Merge "[Elevation] Remove tonal elevation animations as this interferes with ripple opacities" into androidx-main
diff --git a/annotation/annotation-experimental-lint/integration-tests/lint-baseline.xml b/annotation/annotation-experimental-lint/integration-tests/lint-baseline.xml
index ac48471..7155089 100644
--- a/annotation/annotation-experimental-lint/integration-tests/lint-baseline.xml
+++ b/annotation/annotation-experimental-lint/integration-tests/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.0.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (8.0.0-alpha05)" variant="all" version="8.0.0-alpha05">
+<issues format="6" by="lint 8.2.0-beta01" type="baseline" client="gradle" dependencies="false" name="AGP (8.2.0-beta01)" variant="all" version="8.2.0-beta01">
 
     <issue
         id="ExperimentalAnnotationRetention"
@@ -327,6 +327,15 @@
 
     <issue
         id="UnsafeOptInUsageError"
+        message="This declaration is opt-in and its usage should be marked with `@sample.optin.ExperimentalJavaAnnotation` or `@OptIn(markerClass = sample.optin.ExperimentalJavaAnnotation.class)`"
+        errorLine1="        player.accessor"
+        errorLine2="               ~~~~~~~~">
+        <location
+            file="src/main/java/sample/optin/RegressionTestKotlin298322402.kt"/>
+    </issue>
+
+    <issue
+        id="UnsafeOptInUsageError"
         message="This declaration is opt-in and its usage should be marked with `@sample.kotlin.ExperimentalJavaAnnotation` or `@OptIn(markerClass = sample.kotlin.ExperimentalJavaAnnotation.class)`"
         errorLine1="        AnnotatedJavaClass experimentalObject = new AnnotatedJavaClass();"
         errorLine2="                                                ~~~~~~~~~~~~~~~~~~~~~~~~">
diff --git a/annotation/annotation-experimental-lint/integration-tests/src/main/java/sample/optin/AnnotatedJavaMembers.java b/annotation/annotation-experimental-lint/integration-tests/src/main/java/sample/optin/AnnotatedJavaMembers.java
index 82955e3..88faa0f 100644
--- a/annotation/annotation-experimental-lint/integration-tests/src/main/java/sample/optin/AnnotatedJavaMembers.java
+++ b/annotation/annotation-experimental-lint/integration-tests/src/main/java/sample/optin/AnnotatedJavaMembers.java
@@ -38,6 +38,11 @@
         return -1;
     }
 
+    @ExperimentalJavaAnnotation
+    public int getAccessor() {
+        return -1;
+    }
+
     public int getFieldWithSetMarker() {
         return mFieldWithSetMarker;
     }
diff --git a/camera/camera-effects/src/main/java/androidx/camera/effects/Portrait.java b/annotation/annotation-experimental-lint/integration-tests/src/main/java/sample/optin/RegressionTestKotlin298322402.kt
similarity index 66%
rename from camera/camera-effects/src/main/java/androidx/camera/effects/Portrait.java
rename to annotation/annotation-experimental-lint/integration-tests/src/main/java/sample/optin/RegressionTestKotlin298322402.kt
index 7a355f8..5a8eb40 100644
--- a/camera/camera-effects/src/main/java/androidx/camera/effects/Portrait.java
+++ b/annotation/annotation-experimental-lint/integration-tests/src/main/java/sample/optin/RegressionTestKotlin298322402.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2022 The Android Open Source Project
+ * Copyright 2023 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.
@@ -13,16 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+@file:Suppress("unused")
 
-package androidx.camera.effects;
+package sample.optin
 
-import androidx.annotation.RestrictTo;
-
-/**
- * Provides a portrait post-processing effect.
- *
- */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public class Portrait {
-    // TODO: implement this
+internal class RegressionTestKotlin298322402 {
+    fun testMethod(player: AnnotatedJavaMembers) {
+        player.accessor
+    }
 }
diff --git a/annotation/annotation-experimental-lint/src/main/java/androidx/annotation/experimental/lint/ExperimentalDetector.kt b/annotation/annotation-experimental-lint/src/main/java/androidx/annotation/experimental/lint/ExperimentalDetector.kt
index ef20bed..54cb668 100644
--- a/annotation/annotation-experimental-lint/src/main/java/androidx/annotation/experimental/lint/ExperimentalDetector.kt
+++ b/annotation/annotation-experimental-lint/src/main/java/androidx/annotation/experimental/lint/ExperimentalDetector.kt
@@ -35,12 +35,14 @@
 import com.intellij.psi.PsiAnnotation
 import com.intellij.psi.PsiClass
 import com.intellij.psi.PsiClassType
+import com.intellij.psi.PsiComment
 import com.intellij.psi.PsiElement
 import com.intellij.psi.PsiField
 import com.intellij.psi.PsiMethod
 import com.intellij.psi.PsiModifier
 import com.intellij.psi.PsiModifierListOwner
 import com.intellij.psi.PsiPackage
+import com.intellij.psi.PsiWhiteSpace
 import com.intellij.psi.impl.source.PsiClassReferenceType
 import com.intellij.psi.search.GlobalSearchScope
 import com.intellij.psi.util.PsiTreeUtil
@@ -643,24 +645,38 @@
             else -> throw IllegalArgumentException("Unsupported element type")
         }
 
-        // If the element has a modifier list, e.g. not an anonymous class or lambda, then place the
-        // insertion point at the beginning of the modifiers list. This ensures that we don't insert
-        // the annotation in an invalid position, such as after the "public" or "fun" keywords. We
-        // also don't want to place it on the element range itself, since that would place it before
-        // the comments.
-        val elementLocation = context.getLocation(element.modifierList ?: element as UElement)
+        // If the element can include modifiers, e.g. not an anonymous class or lambda, find the
+        // where the list should start. This ensures that we don't insert the annotation in an
+        // invalid position, such as after the `public` or `fun` keywords. We also don't want to
+        // place it on the element range itself, since that would place it before the comments.
+        val elementSourcePsi = element.sourcePsi
+        val elementForInsert = if (elementSourcePsi is PsiModifierListOwner) {
+            elementSourcePsi.asIterable().firstOrNull { child ->
+                child !is PsiWhiteSpace && child !is PsiComment
+            } ?: throw IllegalArgumentException("Failed to locate element declaration")
+        } else {
+            element
+        }
 
         return fix()
-            .replace()
             .name("Add '$annotation' annotation to $elementLabel")
-            .range(elementLocation)
-            .beginning()
-            .shortenNames()
-            .with("$annotation ")
+            .annotate(annotation, true)
+            .range(context.getLocation(elementForInsert))
             .build()
     }
 
     /**
+     * Returns an iterable of child elements.
+     */
+    private fun PsiElement.asIterable(): Iterable<PsiElement> = object : Iterable<PsiElement> {
+        override fun iterator(): Iterator<PsiElement> = object : Iterator<PsiElement> {
+            private var current = firstChild
+            override fun hasNext(): Boolean = current != null
+            override fun next(): PsiElement = current.apply { current = nextSibling }
+        }
+    }
+
+    /**
      * Reports an issue and trims indentation on the [message].
      */
     private fun report(
diff --git a/annotation/annotation-experimental-lint/src/test/kotlin/androidx/annotation/experimental/lint/ExperimentalDetectorTest.kt b/annotation/annotation-experimental-lint/src/test/kotlin/androidx/annotation/experimental/lint/ExperimentalDetectorTest.kt
index 25567ce..21e170e 100644
--- a/annotation/annotation-experimental-lint/src/test/kotlin/androidx/annotation/experimental/lint/ExperimentalDetectorTest.kt
+++ b/annotation/annotation-experimental-lint/src/test/kotlin/androidx/annotation/experimental/lint/ExperimentalDetectorTest.kt
@@ -72,52 +72,40 @@
         val expectedFix = """
 Fix for src/sample/experimental/UseJavaExperimentalFromJava.java line 25: Add '@androidx.annotation.OptIn(markerClass = sample.experimental.ExperimentalDateTime.class)' annotation to 'getDateUnsafe':
 @@ -24 +24
--     int getDateUnsafe() {
-+     @androidx.annotation.OptIn(markerClass = ExperimentalDateTime.class) int getDateUnsafe() {
++     @androidx.annotation.OptIn(markerClass = ExperimentalDateTime.class)
 Fix for src/sample/experimental/UseJavaExperimentalFromJava.java line 25: Add '@sample.experimental.ExperimentalDateTime' annotation to 'getDateUnsafe':
 @@ -24 +24
--     int getDateUnsafe() {
-+     @ExperimentalDateTime int getDateUnsafe() {
++     @ExperimentalDateTime
 Fix for src/sample/experimental/UseJavaExperimentalFromJava.java line 25: Add '@sample.experimental.ExperimentalDateTime' annotation to containing class 'UseJavaExperimentalFromJava':
 @@ -19 +19
-- @SuppressWarnings({"unused", "WeakerAccess", "deprecation"})
-+ @ExperimentalDateTime @SuppressWarnings({"unused", "WeakerAccess", "deprecation"})
++ @ExperimentalDateTime
 Fix for src/sample/experimental/UseJavaExperimentalFromJava.java line 26: Add '@androidx.annotation.OptIn(markerClass = sample.experimental.ExperimentalDateTime.class)' annotation to 'getDateUnsafe':
 @@ -24 +24
--     int getDateUnsafe() {
-+     @androidx.annotation.OptIn(markerClass = ExperimentalDateTime.class) int getDateUnsafe() {
++     @androidx.annotation.OptIn(markerClass = ExperimentalDateTime.class)
 Fix for src/sample/experimental/UseJavaExperimentalFromJava.java line 26: Add '@sample.experimental.ExperimentalDateTime' annotation to 'getDateUnsafe':
 @@ -24 +24
--     int getDateUnsafe() {
-+     @ExperimentalDateTime int getDateUnsafe() {
++     @ExperimentalDateTime
 Fix for src/sample/experimental/UseJavaExperimentalFromJava.java line 26: Add '@sample.experimental.ExperimentalDateTime' annotation to containing class 'UseJavaExperimentalFromJava':
 @@ -19 +19
-- @SuppressWarnings({"unused", "WeakerAccess", "deprecation"})
-+ @ExperimentalDateTime @SuppressWarnings({"unused", "WeakerAccess", "deprecation"})
++ @ExperimentalDateTime
 Fix for src/sample/experimental/UseJavaExperimentalFromJava.java line 53: Add '@androidx.annotation.OptIn(markerClass = sample.experimental.ExperimentalLocation.class)' annotation to 'getDateExperimentalLocationUnsafe':
 @@ -50 +50
--     @ExperimentalDateTime
-+     @androidx.annotation.OptIn(markerClass = ExperimentalLocation.class) @ExperimentalDateTime
++     @androidx.annotation.OptIn(markerClass = ExperimentalLocation.class)
 Fix for src/sample/experimental/UseJavaExperimentalFromJava.java line 53: Add '@sample.experimental.ExperimentalLocation' annotation to 'getDateExperimentalLocationUnsafe':
 @@ -50 +50
--     @ExperimentalDateTime
-+     @ExperimentalLocation @ExperimentalDateTime
++     @ExperimentalLocation
 Fix for src/sample/experimental/UseJavaExperimentalFromJava.java line 53: Add '@sample.experimental.ExperimentalLocation' annotation to containing class 'UseJavaExperimentalFromJava':
 @@ -19 +19
-- @SuppressWarnings({"unused", "WeakerAccess", "deprecation"})
-+ @ExperimentalLocation @SuppressWarnings({"unused", "WeakerAccess", "deprecation"})
++ @ExperimentalLocation
 Fix for src/sample/experimental/UseJavaExperimentalFromJava.java line 54: Add '@androidx.annotation.OptIn(markerClass = sample.experimental.ExperimentalLocation.class)' annotation to 'getDateExperimentalLocationUnsafe':
 @@ -50 +50
--     @ExperimentalDateTime
-+     @androidx.annotation.OptIn(markerClass = ExperimentalLocation.class) @ExperimentalDateTime
++     @androidx.annotation.OptIn(markerClass = ExperimentalLocation.class)
 Fix for src/sample/experimental/UseJavaExperimentalFromJava.java line 54: Add '@sample.experimental.ExperimentalLocation' annotation to 'getDateExperimentalLocationUnsafe':
 @@ -50 +50
--     @ExperimentalDateTime
-+     @ExperimentalLocation @ExperimentalDateTime
++     @ExperimentalLocation
 Fix for src/sample/experimental/UseJavaExperimentalFromJava.java line 54: Add '@sample.experimental.ExperimentalLocation' annotation to containing class 'UseJavaExperimentalFromJava':
 @@ -19 +19
-- @SuppressWarnings({"unused", "WeakerAccess", "deprecation"})
-+ @ExperimentalLocation @SuppressWarnings({"unused", "WeakerAccess", "deprecation"})
++ @ExperimentalLocation
         """.trimIndent()
         /* ktlint-enable max-line-length */
 
@@ -189,53 +177,41 @@
 
         val expectedFix = """
 Fix for src/sample/experimental/UseJavaExperimentalFromKt.kt line 29: Add '@androidx.annotation.OptIn(sample.experimental.ExperimentalDateTime::class)' annotation to 'getDateUnsafe':
-@@ -1 +1
-- /*
-+ @androidx.annotation.OptIn(ExperimentalDateTime::class) /*
+@@ -25 +25
++     @androidx.annotation.OptIn(ExperimentalDateTime::class)
 Fix for src/sample/experimental/UseJavaExperimentalFromKt.kt line 29: Add '@sample.experimental.ExperimentalDateTime' annotation to 'getDateUnsafe':
-@@ -1 +1
-- /*
-+ @ExperimentalDateTime /*
+@@ -25 +25
++     @ExperimentalDateTime
 Fix for src/sample/experimental/UseJavaExperimentalFromKt.kt line 29: Add '@sample.experimental.ExperimentalDateTime' annotation to containing class 'UseJavaExperimentalFromKt':
-@@ -23 +23
-- @Suppress("unused", "MemberVisibilityCanBePrivate")
-+ @ExperimentalDateTime @Suppress("unused", "MemberVisibilityCanBePrivate")
+@@ -1 +1
++ @ExperimentalDateTime
 Fix for src/sample/experimental/UseJavaExperimentalFromKt.kt line 30: Add '@androidx.annotation.OptIn(sample.experimental.ExperimentalDateTime::class)' annotation to 'getDateUnsafe':
-@@ -1 +1
-- /*
-+ @androidx.annotation.OptIn(ExperimentalDateTime::class) /*
+@@ -25 +25
++     @androidx.annotation.OptIn(ExperimentalDateTime::class)
 Fix for src/sample/experimental/UseJavaExperimentalFromKt.kt line 30: Add '@sample.experimental.ExperimentalDateTime' annotation to 'getDateUnsafe':
-@@ -1 +1
-- /*
-+ @ExperimentalDateTime /*
+@@ -25 +25
++     @ExperimentalDateTime
 Fix for src/sample/experimental/UseJavaExperimentalFromKt.kt line 30: Add '@sample.experimental.ExperimentalDateTime' annotation to containing class 'UseJavaExperimentalFromKt':
-@@ -23 +23
-- @Suppress("unused", "MemberVisibilityCanBePrivate")
-+ @ExperimentalDateTime @Suppress("unused", "MemberVisibilityCanBePrivate")
+@@ -1 +1
++ @ExperimentalDateTime
 Fix for src/sample/experimental/UseJavaExperimentalFromKt.kt line 57: Add '@androidx.annotation.OptIn(sample.experimental.ExperimentalLocation::class)' annotation to 'getDateExperimentalLocationUnsafe':
-@@ -54 +54
--     @ExperimentalDateTime
-+     @androidx.annotation.OptIn(ExperimentalLocation::class) @ExperimentalDateTime
+@@ -51 +51
++     @androidx.annotation.OptIn(ExperimentalLocation::class)
 Fix for src/sample/experimental/UseJavaExperimentalFromKt.kt line 57: Add '@sample.experimental.ExperimentalLocation' annotation to 'getDateExperimentalLocationUnsafe':
-@@ -54 +54
--     @ExperimentalDateTime
-+     @ExperimentalLocation @ExperimentalDateTime
+@@ -51 +51
++     @ExperimentalLocation
 Fix for src/sample/experimental/UseJavaExperimentalFromKt.kt line 57: Add '@sample.experimental.ExperimentalLocation' annotation to containing class 'UseJavaExperimentalFromKt':
-@@ -23 +23
-- @Suppress("unused", "MemberVisibilityCanBePrivate")
-+ @ExperimentalLocation @Suppress("unused", "MemberVisibilityCanBePrivate")
+@@ -1 +1
++ @ExperimentalLocation
 Fix for src/sample/experimental/UseJavaExperimentalFromKt.kt line 58: Add '@androidx.annotation.OptIn(sample.experimental.ExperimentalLocation::class)' annotation to 'getDateExperimentalLocationUnsafe':
-@@ -54 +54
--     @ExperimentalDateTime
-+     @androidx.annotation.OptIn(ExperimentalLocation::class) @ExperimentalDateTime
+@@ -51 +51
++     @androidx.annotation.OptIn(ExperimentalLocation::class)
 Fix for src/sample/experimental/UseJavaExperimentalFromKt.kt line 58: Add '@sample.experimental.ExperimentalLocation' annotation to 'getDateExperimentalLocationUnsafe':
-@@ -54 +54
--     @ExperimentalDateTime
-+     @ExperimentalLocation @ExperimentalDateTime
+@@ -51 +51
++     @ExperimentalLocation
 Fix for src/sample/experimental/UseJavaExperimentalFromKt.kt line 58: Add '@sample.experimental.ExperimentalLocation' annotation to containing class 'UseJavaExperimentalFromKt':
-@@ -23 +23
-- @Suppress("unused", "MemberVisibilityCanBePrivate")
-+ @ExperimentalLocation @Suppress("unused", "MemberVisibilityCanBePrivate")
+@@ -1 +1
++ @ExperimentalLocation
         """.trimIndent()
         /* ktlint-enable max-line-length */
 
@@ -286,100 +262,76 @@
         val expectedFix = """
 Fix for src/sample/experimental/UseKtExperimentalFromJava.java line 25: Add '@androidx.annotation.OptIn(markerClass = sample.experimental.ExperimentalDateTimeKt.class)' annotation to 'getDateUnsafe':
 @@ -24 +24
--     int getDateUnsafe() {
-+     @androidx.annotation.OptIn(markerClass = ExperimentalDateTimeKt.class) int getDateUnsafe() {
++     @androidx.annotation.OptIn(markerClass = ExperimentalDateTimeKt.class)
 Fix for src/sample/experimental/UseKtExperimentalFromJava.java line 25: Add '@sample.experimental.ExperimentalDateTimeKt' annotation to 'getDateUnsafe':
 @@ -24 +24
--     int getDateUnsafe() {
-+     @ExperimentalDateTimeKt int getDateUnsafe() {
++     @ExperimentalDateTimeKt
 Fix for src/sample/experimental/UseKtExperimentalFromJava.java line 25: Add '@sample.experimental.ExperimentalDateTimeKt' annotation to containing class 'UseKtExperimentalFromJava':
 @@ -19 +19
-- @SuppressWarnings({"unused", "WeakerAccess"})
-+ @ExperimentalDateTimeKt @SuppressWarnings({"unused", "WeakerAccess"})
++ @ExperimentalDateTimeKt
 Fix for src/sample/experimental/UseKtExperimentalFromJava.java line 26: Add '@androidx.annotation.OptIn(markerClass = sample.experimental.ExperimentalDateTimeKt.class)' annotation to 'getDateUnsafe':
 @@ -24 +24
--     int getDateUnsafe() {
-+     @androidx.annotation.OptIn(markerClass = ExperimentalDateTimeKt.class) int getDateUnsafe() {
++     @androidx.annotation.OptIn(markerClass = ExperimentalDateTimeKt.class)
 Fix for src/sample/experimental/UseKtExperimentalFromJava.java line 26: Add '@sample.experimental.ExperimentalDateTimeKt' annotation to 'getDateUnsafe':
 @@ -24 +24
--     int getDateUnsafe() {
-+     @ExperimentalDateTimeKt int getDateUnsafe() {
++     @ExperimentalDateTimeKt
 Fix for src/sample/experimental/UseKtExperimentalFromJava.java line 26: Add '@sample.experimental.ExperimentalDateTimeKt' annotation to containing class 'UseKtExperimentalFromJava':
 @@ -19 +19
-- @SuppressWarnings({"unused", "WeakerAccess"})
-+ @ExperimentalDateTimeKt @SuppressWarnings({"unused", "WeakerAccess"})
++ @ExperimentalDateTimeKt
 Fix for src/sample/experimental/UseKtExperimentalFromJava.java line 54: Add '@androidx.annotation.OptIn(markerClass = sample.experimental.ExperimentalLocationKt.class)' annotation to 'getDateExperimentalLocationUnsafe':
 @@ -51 +51
--     @ExperimentalDateTimeKt
-+     @androidx.annotation.OptIn(markerClass = ExperimentalLocationKt.class) @ExperimentalDateTimeKt
++     @androidx.annotation.OptIn(markerClass = ExperimentalLocationKt.class)
 Fix for src/sample/experimental/UseKtExperimentalFromJava.java line 54: Add '@sample.experimental.ExperimentalLocationKt' annotation to 'getDateExperimentalLocationUnsafe':
 @@ -51 +51
--     @ExperimentalDateTimeKt
-+     @ExperimentalLocationKt @ExperimentalDateTimeKt
++     @ExperimentalLocationKt
 Fix for src/sample/experimental/UseKtExperimentalFromJava.java line 54: Add '@sample.experimental.ExperimentalLocationKt' annotation to containing class 'UseKtExperimentalFromJava':
 @@ -19 +19
-- @SuppressWarnings({"unused", "WeakerAccess"})
-+ @ExperimentalLocationKt @SuppressWarnings({"unused", "WeakerAccess"})
++ @ExperimentalLocationKt
 Fix for src/sample/experimental/UseKtExperimentalFromJava.java line 55: Add '@androidx.annotation.OptIn(markerClass = sample.experimental.ExperimentalLocationKt.class)' annotation to 'getDateExperimentalLocationUnsafe':
 @@ -51 +51
--     @ExperimentalDateTimeKt
-+     @androidx.annotation.OptIn(markerClass = ExperimentalLocationKt.class) @ExperimentalDateTimeKt
++     @androidx.annotation.OptIn(markerClass = ExperimentalLocationKt.class)
 Fix for src/sample/experimental/UseKtExperimentalFromJava.java line 55: Add '@sample.experimental.ExperimentalLocationKt' annotation to 'getDateExperimentalLocationUnsafe':
 @@ -51 +51
--     @ExperimentalDateTimeKt
-+     @ExperimentalLocationKt @ExperimentalDateTimeKt
++     @ExperimentalLocationKt
 Fix for src/sample/experimental/UseKtExperimentalFromJava.java line 55: Add '@sample.experimental.ExperimentalLocationKt' annotation to containing class 'UseKtExperimentalFromJava':
 @@ -19 +19
-- @SuppressWarnings({"unused", "WeakerAccess"})
-+ @ExperimentalLocationKt @SuppressWarnings({"unused", "WeakerAccess"})
++ @ExperimentalLocationKt
 Fix for src/sample/experimental/UseKtExperimentalFromJava.java line 88: Add '@androidx.annotation.OptIn(markerClass = sample.experimental.ExperimentalDateTimeKt.class)' annotation to 'regressionTestStaticUsage':
 @@ -87 +87
--     void regressionTestStaticUsage() {
-+     @androidx.annotation.OptIn(markerClass = ExperimentalDateTimeKt.class) void regressionTestStaticUsage() {
++     @androidx.annotation.OptIn(markerClass = ExperimentalDateTimeKt.class)
 Fix for src/sample/experimental/UseKtExperimentalFromJava.java line 88: Add '@sample.experimental.ExperimentalDateTimeKt' annotation to 'regressionTestStaticUsage':
 @@ -87 +87
--     void regressionTestStaticUsage() {
-+     @ExperimentalDateTimeKt void regressionTestStaticUsage() {
++     @ExperimentalDateTimeKt
 Fix for src/sample/experimental/UseKtExperimentalFromJava.java line 88: Add '@sample.experimental.ExperimentalDateTimeKt' annotation to containing class 'UseKtExperimentalFromJava':
 @@ -19 +19
-- @SuppressWarnings({"unused", "WeakerAccess"})
-+ @ExperimentalDateTimeKt @SuppressWarnings({"unused", "WeakerAccess"})
++ @ExperimentalDateTimeKt
 Fix for src/sample/experimental/UseKtExperimentalFromJava.java line 89: Add '@androidx.annotation.OptIn(markerClass = sample.experimental.ExperimentalDateTimeKt.class)' annotation to 'regressionTestStaticUsage':
 @@ -87 +87
--     void regressionTestStaticUsage() {
-+     @androidx.annotation.OptIn(markerClass = ExperimentalDateTimeKt.class) void regressionTestStaticUsage() {
++     @androidx.annotation.OptIn(markerClass = ExperimentalDateTimeKt.class)
 Fix for src/sample/experimental/UseKtExperimentalFromJava.java line 89: Add '@sample.experimental.ExperimentalDateTimeKt' annotation to 'regressionTestStaticUsage':
 @@ -87 +87
--     void regressionTestStaticUsage() {
-+     @ExperimentalDateTimeKt void regressionTestStaticUsage() {
++     @ExperimentalDateTimeKt
 Fix for src/sample/experimental/UseKtExperimentalFromJava.java line 89: Add '@sample.experimental.ExperimentalDateTimeKt' annotation to containing class 'UseKtExperimentalFromJava':
 @@ -19 +19
-- @SuppressWarnings({"unused", "WeakerAccess"})
-+ @ExperimentalDateTimeKt @SuppressWarnings({"unused", "WeakerAccess"})
++ @ExperimentalDateTimeKt
 Fix for src/sample/experimental/UseKtExperimentalFromJava.java line 96: Add '@androidx.annotation.OptIn(markerClass = sample.experimental.ExperimentalDateTimeKt.class)' annotation to 'regressionTestInlineUsage':
 @@ -95 +95
--     void regressionTestInlineUsage() {
-+     @androidx.annotation.OptIn(markerClass = ExperimentalDateTimeKt.class) void regressionTestInlineUsage() {
++     @androidx.annotation.OptIn(markerClass = ExperimentalDateTimeKt.class)
 Fix for src/sample/experimental/UseKtExperimentalFromJava.java line 96: Add '@sample.experimental.ExperimentalDateTimeKt' annotation to 'regressionTestInlineUsage':
 @@ -95 +95
--     void regressionTestInlineUsage() {
-+     @ExperimentalDateTimeKt void regressionTestInlineUsage() {
++     @ExperimentalDateTimeKt
 Fix for src/sample/experimental/UseKtExperimentalFromJava.java line 96: Add '@sample.experimental.ExperimentalDateTimeKt' annotation to containing class 'UseKtExperimentalFromJava':
 @@ -19 +19
-- @SuppressWarnings({"unused", "WeakerAccess"})
-+ @ExperimentalDateTimeKt @SuppressWarnings({"unused", "WeakerAccess"})
++ @ExperimentalDateTimeKt
 Fix for src/sample/experimental/UseKtExperimentalFromJava.java line 97: Add '@androidx.annotation.OptIn(markerClass = sample.experimental.ExperimentalDateTime.class)' annotation to 'regressionTestInlineUsage':
 @@ -95 +95
--     void regressionTestInlineUsage() {
-+     @androidx.annotation.OptIn(markerClass = ExperimentalDateTime.class) void regressionTestInlineUsage() {
++     @androidx.annotation.OptIn(markerClass = ExperimentalDateTime.class)
 Fix for src/sample/experimental/UseKtExperimentalFromJava.java line 97: Add '@sample.experimental.ExperimentalDateTime' annotation to 'regressionTestInlineUsage':
 @@ -95 +95
--     void regressionTestInlineUsage() {
-+     @ExperimentalDateTime void regressionTestInlineUsage() {
++     @ExperimentalDateTime
 Fix for src/sample/experimental/UseKtExperimentalFromJava.java line 97: Add '@sample.experimental.ExperimentalDateTime' annotation to containing class 'UseKtExperimentalFromJava':
 @@ -19 +19
-- @SuppressWarnings({"unused", "WeakerAccess"})
-+ @ExperimentalDateTime @SuppressWarnings({"unused", "WeakerAccess"})
++ @ExperimentalDateTime
         """.trimIndent()
         /* ktlint-enable max-line-length */
 
diff --git a/annotation/annotation-experimental-lint/src/test/kotlin/androidx/annotation/experimental/lint/RequiresOptInDetectorTest.kt b/annotation/annotation-experimental-lint/src/test/kotlin/androidx/annotation/experimental/lint/RequiresOptInDetectorTest.kt
index 99ca8e3..f26e382 100644
--- a/annotation/annotation-experimental-lint/src/test/kotlin/androidx/annotation/experimental/lint/RequiresOptInDetectorTest.kt
+++ b/annotation/annotation-experimental-lint/src/test/kotlin/androidx/annotation/experimental/lint/RequiresOptInDetectorTest.kt
@@ -23,7 +23,6 @@
 import com.android.tools.lint.checks.infrastructure.TestFiles.kotlin
 import com.android.tools.lint.checks.infrastructure.TestLintResult
 import com.android.tools.lint.checks.infrastructure.TestLintTask.lint
-import com.android.tools.lint.checks.infrastructure.TestMode
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
@@ -39,7 +38,6 @@
                 *testFiles
             )
             .issues(*ExperimentalDetector.ISSUES.toTypedArray())
-            .testModes(TestMode.PARTIAL)
             .run()
     }
 
@@ -444,6 +442,38 @@
         check(*input).expect(expected)
     }
 
+    @Test
+    fun regressionTestKotlin298322402() {
+        val input = arrayOf(
+            javaSample("sample.optin.ExperimentalJavaAnnotation"),
+            javaSample("sample.optin.AnnotatedJavaMembers"),
+            ktSample("sample.optin.RegressionTestKotlin298322402")
+        )
+
+        /* ktlint-disable max-line-length */
+        val expected = """
+src/sample/optin/RegressionTestKotlin298322402.kt:22: Error: This declaration is opt-in and its usage should be marked with @sample.optin.ExperimentalJavaAnnotation or @OptIn(markerClass = sample.optin.ExperimentalJavaAnnotation.class) [UnsafeOptInUsageError]
+        player.accessor
+               ~~~~~~~~
+1 errors, 0 warnings
+        """.trimIndent()
+
+        val expectedFix = """
+Fix for src/sample/optin/RegressionTestKotlin298322402.kt line 22: Add '@androidx.annotation.OptIn(sample.optin.ExperimentalJavaAnnotation::class)' annotation to 'testMethod':
+@@ -21 +21
++     @androidx.annotation.OptIn(ExperimentalJavaAnnotation::class)
+Fix for src/sample/optin/RegressionTestKotlin298322402.kt line 22: Add '@sample.optin.ExperimentalJavaAnnotation' annotation to 'testMethod':
+@@ -21 +21
++     @ExperimentalJavaAnnotation
+Fix for src/sample/optin/RegressionTestKotlin298322402.kt line 22: Add '@sample.optin.ExperimentalJavaAnnotation' annotation to containing class 'RegressionTestKotlin298322402':
+@@ -1 +1
++ @ExperimentalJavaAnnotation
+        """.trimIndent()
+        /* ktlint-enable max-line-length */
+
+        check(*input).expectFixDiffs(expectedFix).expect(expected)
+    }
+
     /* ktlint-disable max-line-length */
     companion object {
         /**
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/GenericDocumentInternalTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/GenericDocumentInternalTest.java
index b514854..8161c1c 100644
--- a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/GenericDocumentInternalTest.java
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/GenericDocumentInternalTest.java
@@ -18,8 +18,6 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.junit.Assert.assertThrows;
-
 import android.os.Bundle;
 import android.os.Parcel;
 
@@ -107,48 +105,4 @@
         assertThat(outDoc.getPropertyDocument("propDocument").getPropertyBytesArray("propBytes"))
                 .isEqualTo(new byte[][]{{3, 4}});
     }
-
-    @Test
-    public void testPropertyParcel_onePropertySet_success() {
-        String[] stringValues = {"a", "b"};
-        long[] longValues = {1L, 2L};
-        double[] doubleValues = {1.0, 2.0};
-        boolean[] booleanValues = {true, false};
-        byte[][] bytesValues = {new byte[1]};
-        Bundle[] bundleValues = {new Bundle()};
-
-        assertThat(new PropertyParcel.Builder("name").setStringValues(
-                stringValues).build().getStringValues()).isEqualTo(
-                Arrays.copyOf(stringValues, stringValues.length));
-        assertThat(new PropertyParcel.Builder("name").setLongValues(
-                longValues).build().getLongValues()).isEqualTo(
-                Arrays.copyOf(longValues, longValues.length));
-        assertThat(new PropertyParcel.Builder("name").setDoubleValues(
-                doubleValues).build().getDoubleValues()).isEqualTo(
-                Arrays.copyOf(doubleValues, doubleValues.length));
-        assertThat(new PropertyParcel.Builder("name").setBooleanValues(
-                booleanValues).build().getBooleanValues()).isEqualTo(
-                Arrays.copyOf(booleanValues, booleanValues.length));
-        assertThat(new PropertyParcel.Builder("name").setBytesValues(
-                bytesValues).build().getBytesValues()).isEqualTo(
-                Arrays.copyOf(bytesValues, bytesValues.length));
-        assertThat(new PropertyParcel.Builder("name").setDocumentValues(
-                bundleValues).build().getDocumentValues()).isEqualTo(
-                Arrays.copyOf(bundleValues, bundleValues.length));
-    }
-
-    @Test
-    public void testPropertyParcel_moreThanOnePropertySet_exceptionThrown() {
-        String[] stringValues = {"a", "b"};
-        long[] longValues = {1L, 2L};
-        PropertyParcel.Builder propertyParcelBuilder =
-                new PropertyParcel.Builder("name")
-                        .setStringValues(stringValues)
-                        .setLongValues(longValues);
-
-        IllegalArgumentException exception = assertThrows(IllegalArgumentException.class,
-                () -> propertyParcelBuilder.build());
-
-        assertThat(exception.getMessage()).contains("One and only one type array");
-    }
 }
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/safeparcel/GenericDocumentParcelTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/safeparcel/GenericDocumentParcelTest.java
new file mode 100644
index 0000000..47df245
--- /dev/null
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/safeparcel/GenericDocumentParcelTest.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.app.safeparcel;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.Map;
+
+/** Tests for {@link androidx.appsearch.app.GenericDocument} related SafeParcels. */
+public class GenericDocumentParcelTest {
+    @Test
+    public void testPropertyParcel_onePropertySet_success() {
+        String[] stringValues = {"a", "b"};
+        long[] longValues = {1L, 2L};
+        double[] doubleValues = {1.0, 2.0};
+        boolean[] booleanValues = {true, false};
+        byte[][] bytesValues = {new byte[1]};
+        GenericDocumentParcel[] docValues = {(new GenericDocumentParcel.Builder(
+                "namespace", "id", "schemaType")).build()};
+
+        assertThat(new PropertyParcel.Builder("name").setStringValues(
+                stringValues).build().getStringValues()).isEqualTo(
+                Arrays.copyOf(stringValues, stringValues.length));
+        assertThat(new PropertyParcel.Builder("name").setLongValues(
+                longValues).build().getLongValues()).isEqualTo(
+                Arrays.copyOf(longValues, longValues.length));
+        assertThat(new PropertyParcel.Builder("name").setDoubleValues(
+                doubleValues).build().getDoubleValues()).isEqualTo(
+                Arrays.copyOf(doubleValues, doubleValues.length));
+        assertThat(new PropertyParcel.Builder("name").setBooleanValues(
+                booleanValues).build().getBooleanValues()).isEqualTo(
+                Arrays.copyOf(booleanValues, booleanValues.length));
+        assertThat(new PropertyParcel.Builder("name").setBytesValues(
+                bytesValues).build().getBytesValues()).isEqualTo(
+                Arrays.copyOf(bytesValues, bytesValues.length));
+        assertThat(new PropertyParcel.Builder("name").setDocumentValues(
+                docValues).build().getDocumentValues()).isEqualTo(
+                Arrays.copyOf(docValues, docValues.length));
+    }
+
+    @Test
+    public void testPropertyParcel_moreThanOnePropertySet_exceptionThrown() {
+        String[] stringValues = {"a", "b"};
+        long[] longValues = {1L, 2L};
+        PropertyParcel.Builder propertyParcelBuilder =
+                new PropertyParcel.Builder("name")
+                        .setStringValues(stringValues)
+                        .setLongValues(longValues);
+
+        IllegalArgumentException exception = assertThrows(IllegalArgumentException.class,
+                () -> propertyParcelBuilder.build());
+
+        assertThat(exception.getMessage()).contains("One and only one type array");
+    }
+
+    @Test
+    public void testGenericDocumentParcel_propertiesGeneratedCorrectly() {
+        GenericDocumentParcel.Builder builder =
+                new GenericDocumentParcel.Builder(
+                        /*namespace=*/ "namespace",
+                        /*id=*/ "id",
+                        /*schemaType=*/ "schemaType");
+        long[] longArray = new long[]{1L, 2L, 3L};
+        String[] stringArray = new String[]{"hello", "world", "!"};
+        builder.putInPropertyMap(/*name=*/ "longArray", /*values=*/ longArray);
+        builder.putInPropertyMap(/*name=*/ "stringArray", /*values=*/ stringArray);
+        GenericDocumentParcel genericDocumentParcel = builder.build();
+
+        PropertyParcel[] properties = genericDocumentParcel.getProperties();
+        Map<String, PropertyParcel> propertyMap = genericDocumentParcel.getPropertyMap();
+        PropertyParcel longArrayProperty = new PropertyParcel.Builder(
+                /*name=*/ "longArray").setLongValues(longArray).build();
+        PropertyParcel stringArrayProperty = new PropertyParcel.Builder(
+                /*name=*/ "stringArray").setStringValues(stringArray).build();
+
+        assertThat(properties).asList().containsExactly(longArrayProperty, stringArrayProperty);
+        assertThat(propertyMap).containsExactly("longArray", longArrayProperty,
+                "stringArray", stringArrayProperty);
+    }
+
+    @Test
+    public void testGenericDocumentParcel_buildFromAnotherDocumentParcelCorrectly() {
+        GenericDocumentParcel.Builder builder =
+                new GenericDocumentParcel.Builder(
+                        /*namespace=*/ "namespace",
+                        /*id=*/ "id",
+                        /*schemaType=*/ "schemaType");
+        long[] longArray = new long[]{1L, 2L, 3L};
+        String[] stringArray = new String[]{"hello", "world", "!"};
+        builder.putInPropertyMap(/*name=*/ "longArray", /*values=*/ longArray);
+        builder.putInPropertyMap(/*name=*/ "stringArray", /*values=*/ stringArray);
+        GenericDocumentParcel genericDocumentParcel = builder.build();
+
+        GenericDocumentParcel genericDocumentParcelCopy =
+                new GenericDocumentParcel.Builder(genericDocumentParcel).build();
+
+        assertThat(genericDocumentParcelCopy.getNamespace()).isEqualTo(
+                genericDocumentParcel.getNamespace());
+        assertThat(genericDocumentParcelCopy.getId()).isEqualTo(genericDocumentParcel.getId());
+        assertThat(genericDocumentParcelCopy.getSchemaType()).isEqualTo(
+                genericDocumentParcel.getSchemaType());
+        assertThat(genericDocumentParcelCopy.getCreationTimestampMillis()).isEqualTo(
+                genericDocumentParcel.getCreationTimestampMillis());
+        assertThat(genericDocumentParcelCopy.getTtlMillis()).isEqualTo(
+                genericDocumentParcel.getTtlMillis());
+        assertThat(genericDocumentParcelCopy.getScore()).isEqualTo(
+                genericDocumentParcel.getScore());
+        // Check it is a copy.
+        assertThat(genericDocumentParcelCopy).isNotSameInstanceAs(genericDocumentParcel);
+        assertThat(genericDocumentParcelCopy.getProperties()).isEqualTo(
+                genericDocumentParcel.getProperties());
+    }
+}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/safeparcel/GenericDocumentParcel.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/safeparcel/GenericDocumentParcel.java
new file mode 100644
index 0000000..3d92c02
--- /dev/null
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/safeparcel/GenericDocumentParcel.java
@@ -0,0 +1,494 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.app.safeparcel;
+
+import android.os.Parcel;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RestrictTo;
+import androidx.appsearch.annotation.CanIgnoreReturnValue;
+import androidx.appsearch.app.AppSearchSchema;
+import androidx.appsearch.app.AppSearchSession;
+import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.safeparcel.AbstractSafeParcelable;
+import androidx.appsearch.safeparcel.SafeParcelable;
+import androidx.appsearch.safeparcel.stub.StubCreators.GenericDocumentParcelCreator;
+import androidx.collection.ArrayMap;
+
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Holds data for a {@link GenericDocument}.
+ *
+ * @exportToFramework:hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+@SafeParcelable.Class(creator = "GenericDocumentParcelCreator")
+public final class GenericDocumentParcel extends AbstractSafeParcelable {
+    @NonNull
+    public static final GenericDocumentParcelCreator CREATOR =
+            new GenericDocumentParcelCreator();
+
+    /** The default score of document. */
+    private static final int DEFAULT_SCORE = 0;
+
+    /** The default time-to-live in millisecond of a document, which is infinity. */
+    private static final long DEFAULT_TTL_MILLIS = 0L;
+
+    /** Default but invalid value for {@code mCreationTimestampMillis}. */
+    private static final long INVALID_CREATION_TIMESTAMP_MILLIS = -1L;
+
+    @Field(id = 1, getter = "getNamespace")
+    @NonNull
+    private final String mNamespace;
+
+    @Field(id = 2, getter = "getId")
+    @NonNull
+    private final String mId;
+
+    @Field(id = 3, getter = "getSchemaType")
+    @NonNull
+    private final String mSchemaType;
+
+    @Field(id = 4, getter = "getCreationTimestampMillis")
+    private final long mCreationTimestampMillis;
+
+    @Field(id = 5, getter = "getTtlMillis")
+    private final long mTtlMillis;
+
+    @Field(id = 6, getter = "getScore")
+    private final int mScore;
+
+    /**
+     * Contains all properties in {@link GenericDocument} in a list.
+     *
+     * <p>Unfortunately SafeParcelable doesn't support map type so we have to use a list here.
+     */
+    @Field(id = 7, getter = "getProperties")
+    @NonNull
+    private final PropertyParcel[] mProperties;
+
+    /**
+     * Contains all properties in {@link GenericDocument} to support getting properties via name
+     *
+     * <p>This map is created for quick looking up property by name.
+     */
+    @NonNull
+    private final Map<String, PropertyParcel> mPropertyMap;
+
+    @Nullable
+    private Integer mHashCode;
+
+    /**
+     * The constructor taking the property list, and create map internally from this list.
+     *
+     * <p> This will be used in createFromParcel, so creating the property map can not be avoided
+     * in this constructor.
+     */
+    @Constructor
+    GenericDocumentParcel(
+            @Param(id = 1) @NonNull String namespace,
+            @Param(id = 2) @NonNull String id,
+            @Param(id = 3) @NonNull String schemaType,
+            @Param(id = 4) long creationTimestampMillis,
+            @Param(id = 5) long ttlMillis,
+            @Param(id = 6) int score,
+            @Param(id = 7) @NonNull PropertyParcel[] properties) {
+        this(namespace, id, schemaType, creationTimestampMillis, ttlMillis, score,
+                properties, createPropertyMapFromPropertyArray(properties));
+    }
+
+    /**
+     * A constructor taking both property list and property map.
+     *
+     * <p>Caller needs to make sure property list and property map
+     * matches(map is generated from list, or list generated from map).
+     */
+    GenericDocumentParcel(
+            @NonNull String namespace,
+            @NonNull String id,
+            @NonNull String schemaType,
+            long creationTimestampMillis,
+            long ttlMillis,
+            int score,
+            @NonNull PropertyParcel[] properties,
+            @NonNull Map<String, PropertyParcel> propertyMap) {
+        mNamespace = Objects.requireNonNull(namespace);
+        mId = Objects.requireNonNull(id);
+        mSchemaType = Objects.requireNonNull(schemaType);
+        mCreationTimestampMillis = creationTimestampMillis;
+        mTtlMillis = ttlMillis;
+        mScore = score;
+        mProperties = Objects.requireNonNull(properties);
+        mPropertyMap = Objects.requireNonNull(propertyMap);
+    }
+
+    private static Map<String, PropertyParcel> createPropertyMapFromPropertyArray(
+            @NonNull PropertyParcel[] properties) {
+        Objects.requireNonNull(properties);
+        Map<String, PropertyParcel> propertyMap = new ArrayMap<>(properties.length);
+        for (int i = 0; i < properties.length; ++i) {
+            PropertyParcel property = properties[i];
+            propertyMap.put(property.getPropertyName(), property);
+        }
+        return propertyMap;
+    }
+
+    /** Returns the unique identifier of the {@link GenericDocument}. */
+    @NonNull
+    public String getId() {
+        return mId;
+    }
+
+    /** Returns the namespace of the {@link GenericDocument}. */
+    @NonNull
+    public String getNamespace() {
+        return mNamespace;
+    }
+
+    /** Returns the {@link AppSearchSchema} type of the {@link GenericDocument}. */
+    @NonNull
+    public String getSchemaType() {
+        return mSchemaType;
+    }
+
+    /** Returns the creation timestamp of the {@link GenericDocument}, in milliseconds. */
+    /*@exportToFramework:CurrentTimeMillisLong*/
+    public long getCreationTimestampMillis() {
+        return mCreationTimestampMillis;
+    }
+
+    /** Returns the TTL (time-to-live) of the {@link GenericDocument}, in milliseconds. */
+    public long getTtlMillis() {
+        return mTtlMillis;
+    }
+
+    /** Returns the score of the {@link GenericDocument}. */
+    public int getScore() {
+        return mScore;
+    }
+
+    /** Returns the names of all properties defined in this document. */
+    @NonNull
+    public Set<String> getPropertyNames() {
+        return mPropertyMap.keySet();
+    }
+
+    /** Returns all the properties the document has. */
+    @NonNull
+    public PropertyParcel[] getProperties() {
+        return mProperties;
+    }
+
+    /** Returns the property map the document has. */
+    @NonNull
+    public Map<String, PropertyParcel> getPropertyMap() {
+        return mPropertyMap;
+    }
+
+    @Override
+    public boolean equals(@Nullable Object other) {
+        if (this == other) {
+            return true;
+        }
+        if (!(other instanceof GenericDocumentParcel)) {
+            return false;
+        }
+        GenericDocumentParcel otherDocument = (GenericDocumentParcel) other;
+        return mNamespace.equals(otherDocument.mNamespace)
+                && mId.equals(otherDocument.mId)
+                && mSchemaType.equals(otherDocument.mSchemaType)
+                && mTtlMillis == otherDocument.mTtlMillis
+                && mCreationTimestampMillis == otherDocument.mCreationTimestampMillis
+                && mScore == otherDocument.mScore
+                && Arrays.equals(mProperties, otherDocument.mProperties)
+                && Objects.equals(mPropertyMap, otherDocument.mPropertyMap);
+    }
+
+    @Override
+    public int hashCode() {
+        if (mHashCode == null) {
+            mHashCode = Objects.hash(
+                    mNamespace,
+                    mId,
+                    mSchemaType,
+                    mTtlMillis,
+                    mScore,
+                    mCreationTimestampMillis,
+                    Arrays.hashCode(mProperties),
+                    mPropertyMap.hashCode());
+        }
+        return mHashCode;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        GenericDocumentParcelCreator.writeToParcel(this, dest, flags);
+    }
+
+    /** The builder class for {@link GenericDocumentParcel}. */
+    public static final class Builder {
+        private String mNamespace;
+        private String mId;
+        private String mSchemaType;
+        private long mCreationTimestampMillis;
+        private long mTtlMillis;
+        private int mScore;
+        private Map<String, PropertyParcel> mPropertyMap;
+        private boolean mBuilt = false;
+
+        /**
+         * Creates a new {@link GenericDocument.Builder}.
+         *
+         * <p>Document IDs are unique within a namespace.
+         *
+         * <p>The number of namespaces per app should be kept small for efficiency reasons.
+         */
+        public Builder(@NonNull String namespace, @NonNull String id, @NonNull String schemaType) {
+            mNamespace = Objects.requireNonNull(namespace);
+            mId = Objects.requireNonNull(id);
+            mSchemaType = Objects.requireNonNull(schemaType);
+            mCreationTimestampMillis = INVALID_CREATION_TIMESTAMP_MILLIS;
+            mTtlMillis = DEFAULT_TTL_MILLIS;
+            mScore = DEFAULT_SCORE;
+            mPropertyMap = new ArrayMap<>();
+        }
+
+        /**
+         * Creates a new {@link GenericDocumentParcel.Builder} from the given
+         * {@link GenericDocumentParcel}.
+         */
+        Builder(@NonNull GenericDocumentParcel documentSafeParcel) {
+            Objects.requireNonNull(documentSafeParcel);
+
+            mNamespace = documentSafeParcel.mNamespace;
+            mId = documentSafeParcel.mId;
+            mSchemaType = documentSafeParcel.mSchemaType;
+            mCreationTimestampMillis = documentSafeParcel.mCreationTimestampMillis;
+            mTtlMillis = documentSafeParcel.mTtlMillis;
+            mScore = documentSafeParcel.mScore;
+
+            // Create a shallow copy of the map so we won't change the original one.
+            Map<String, PropertyParcel> propertyMap = documentSafeParcel.mPropertyMap;
+            mPropertyMap = new ArrayMap<>(propertyMap.size());
+            for (PropertyParcel value : propertyMap.values()) {
+                mPropertyMap.put(value.getPropertyName(), value);
+            }
+        }
+
+        /**
+         * Sets the app-defined namespace this document resides in, changing the value provided in
+         * the constructor. No special values are reserved or understood by the infrastructure.
+         *
+         * <p>Document IDs are unique within a namespace.
+         *
+         * <p>The number of namespaces per app should be kept small for efficiency reasons.
+         */
+        @CanIgnoreReturnValue
+        @NonNull
+        public Builder setNamespace(@NonNull String namespace) {
+            Objects.requireNonNull(namespace);
+            resetIfBuilt();
+            mNamespace = namespace;
+            return this;
+        }
+
+        /**
+         * Sets the ID of this document, changing the value provided in the constructor. No special
+         * values are reserved or understood by the infrastructure.
+         *
+         * <p>Document IDs are unique within a namespace.
+         */
+        @CanIgnoreReturnValue
+        @NonNull
+        public Builder setId(@NonNull String id) {
+            Objects.requireNonNull(id);
+            resetIfBuilt();
+            mId = id;
+            return this;
+        }
+
+        /**
+         * Sets the schema type of this document, changing the value provided in the constructor.
+         *
+         * <p>To successfully index a document, the schema type must match the name of an {@link
+         * AppSearchSchema} object previously provided to {@link AppSearchSession#setSchema}.
+         */
+        @CanIgnoreReturnValue
+        @NonNull
+        public Builder setSchemaType(@NonNull String schemaType) {
+            Objects.requireNonNull(schemaType);
+            resetIfBuilt();
+            mSchemaType = schemaType;
+            return this;
+        }
+
+        /** Sets the score of the parent {@link GenericDocument}. */
+        @CanIgnoreReturnValue
+        @NonNull
+        public Builder setScore(int score) {
+            resetIfBuilt();
+            mScore = score;
+            return this;
+        }
+
+        /**
+         * Sets the creation timestamp of the {@link GenericDocument}, in milliseconds.
+         *
+         * <p>This should be set using a value obtained from the {@link System#currentTimeMillis}
+         * time base.
+         *
+         * <p>If this method is not called, this will be set to the time the object is built.
+         *
+         * @param creationTimestampMillis a creation timestamp in milliseconds.
+         */
+        @CanIgnoreReturnValue
+        @NonNull
+        public Builder setCreationTimestampMillis(
+                /*@exportToFramework:CurrentTimeMillisLong*/ long creationTimestampMillis) {
+            resetIfBuilt();
+            mCreationTimestampMillis = creationTimestampMillis;
+            return this;
+        }
+
+        /**
+         * Sets the TTL (time-to-live) of the {@link GenericDocument}, in milliseconds.
+         *
+         * <p>The TTL is measured against {@link #getCreationTimestampMillis}. At the timestamp of
+         * {@code creationTimestampMillis + ttlMillis}, measured in the {@link
+         * System#currentTimeMillis} time base, the document will be auto-deleted.
+         *
+         * <p>The default value is 0, which means the document is permanent and won't be
+         * auto-deleted until the app is uninstalled or {@link AppSearchSession#remove} is called.
+         *
+         * @param ttlMillis a non-negative duration in milliseconds.
+         * @throws IllegalArgumentException if ttlMillis is negative.
+         */
+        @CanIgnoreReturnValue
+        @NonNull
+        public Builder setTtlMillis(long ttlMillis) {
+            if (ttlMillis < 0) {
+                throw new IllegalArgumentException("Document ttlMillis cannot be negative.");
+            }
+            resetIfBuilt();
+            mTtlMillis = ttlMillis;
+            return this;
+        }
+
+        /**
+         * Clears the value for the property with the given name.
+         *
+         * <p>Note that this method does not support property paths.
+         *
+         * @param name The name of the property to clear.
+         */
+        @CanIgnoreReturnValue
+        @NonNull
+        public Builder clearProperty(@NonNull String name) {
+            Objects.requireNonNull(name);
+            resetIfBuilt();
+            mPropertyMap.remove(name);
+            return this;
+        }
+
+        /** puts an array of {@link String} in property map. */
+        @NonNull
+        public Builder putInPropertyMap(@NonNull String name, @NonNull String[] values)
+                throws IllegalArgumentException {
+            mPropertyMap.put(name,
+                    new PropertyParcel.Builder(name).setStringValues(values).build());
+            return this;
+        }
+
+        /** puts an array of boolean in property map. */
+        @NonNull
+        public Builder putInPropertyMap(@NonNull String name, @NonNull boolean[] values) {
+            mPropertyMap.put(name,
+                    new PropertyParcel.Builder(name).setBooleanValues(values).build());
+            return this;
+        }
+
+        /** puts an array of double in property map. */
+        @NonNull
+        public Builder putInPropertyMap(@NonNull String name, @NonNull double[] values) {
+            mPropertyMap.put(name,
+                    new PropertyParcel.Builder(name).setDoubleValues(values).build());
+            return this;
+        }
+
+        /** puts an array of long in property map. */
+        @NonNull
+        public Builder putInPropertyMap(@NonNull String name, @NonNull long[] values) {
+            mPropertyMap.put(name,
+                    new PropertyParcel.Builder(name).setLongValues(values).build());
+            return this;
+        }
+
+        /**
+         * Converts and saves a byte[][] into {@link #mProperties}.
+         */
+        @NonNull
+        public Builder putInPropertyMap(@NonNull String name, @NonNull byte[][] values) {
+            mPropertyMap.put(name,
+                    new PropertyParcel.Builder(name).setBytesValues(values).build());
+            return this;
+        }
+
+        /** puts an array of {@link GenericDocumentParcel} in property map. */
+        @NonNull
+        public Builder putInPropertyMap(@NonNull String name,
+                @NonNull GenericDocumentParcel[] values) {
+            mPropertyMap.put(name,
+                    new PropertyParcel.Builder(name).setDocumentValues(values).build());
+            return this;
+        }
+
+        /** Builds the {@link GenericDocument} object. */
+        @NonNull
+        public GenericDocumentParcel build() {
+            mBuilt = true;
+            // Set current timestamp for creation timestamp by default.
+            if (mCreationTimestampMillis == INVALID_CREATION_TIMESTAMP_MILLIS) {
+                mCreationTimestampMillis = System.currentTimeMillis();
+            }
+            return new GenericDocumentParcel(
+                    mNamespace,
+                    mId,
+                    mSchemaType,
+                    mCreationTimestampMillis,
+                    mTtlMillis,
+                    mScore,
+                    mPropertyMap.values().toArray(new PropertyParcel[0]));
+        }
+
+        void resetIfBuilt() {
+            if (mBuilt) {
+                Map<String, PropertyParcel> propertyMap = mPropertyMap;
+                mPropertyMap = new ArrayMap<>(propertyMap.size());
+                for (PropertyParcel value : propertyMap.values()) {
+                    // PropertyParcel is not deep copied since it is not mutable.
+                    mPropertyMap.put(value.getPropertyName(), value);
+                }
+                mBuilt = false;
+            }
+        }
+    }
+}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/PropertyParcel.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/safeparcel/PropertyParcel.java
similarity index 88%
rename from appsearch/appsearch/src/main/java/androidx/appsearch/app/PropertyParcel.java
rename to appsearch/appsearch/src/main/java/androidx/appsearch/app/safeparcel/PropertyParcel.java
index 7e6fa88..f9034a9 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/PropertyParcel.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/safeparcel/PropertyParcel.java
@@ -14,10 +14,9 @@
  * limitations under the License.
  */
 
-package androidx.appsearch.app;
+package androidx.appsearch.app.safeparcel;
 
 
-import android.os.Bundle;
 import android.os.Parcel;
 
 import androidx.annotation.NonNull;
@@ -26,7 +25,6 @@
 import androidx.appsearch.safeparcel.AbstractSafeParcelable;
 import androidx.appsearch.safeparcel.SafeParcelable;
 import androidx.appsearch.safeparcel.stub.StubCreators.PropertyParcelCreator;
-import androidx.appsearch.util.BundleUtil;
 
 import java.util.Arrays;
 import java.util.Objects;
@@ -67,10 +65,9 @@
     @Field(id = 6, getter = "getBytesValues")
     private final byte[][] mBytesValues;
 
-    // TODO(b/24205844) Change it to GenericDocumentParcel once it is added.
     @Nullable
     @Field(id = 7, getter = "getDocumentValues")
-    private final Bundle[] mDocumentValues;
+    private final GenericDocumentParcel[] mDocumentValues;
 
     @Nullable private Integer mHashCode;
 
@@ -82,7 +79,7 @@
             @Param(id = 4) @Nullable double[] doubleValues,
             @Param(id = 5) @Nullable boolean[] booleanValues,
             @Param(id = 6) @Nullable byte[][] bytesValues,
-            @Param(id = 7) @Nullable Bundle[] documentValues) {
+            @Param(id = 7) @Nullable GenericDocumentParcel[] documentValues) {
         mPropertyName = Objects.requireNonNull(propertyName);
         mStringValues = stringValues;
         mLongValues = longValues;
@@ -129,9 +126,9 @@
         return mBytesValues;
     }
 
-    /** Returns {@link Bundle} in an array. */
+    /** Returns {@link GenericDocumentParcel}s in an array. */
     @Nullable
-    public Bundle[] getDocumentValues() {
+    public GenericDocumentParcel[] getDocumentValues() {
         return mDocumentValues;
     }
 
@@ -209,13 +206,7 @@
             } else if (mBytesValues != null) {
                 hashCode = Arrays.deepHashCode(mBytesValues);
             } else if (mDocumentValues != null) {
-                // TODO(b/24205844) change those to Arrays.hashCode() as well once we replace
-                //  this Bundle[] with GenericDocumentParcel[].
-                int[] innerHashCodes = new int[mDocumentValues.length];
-                for (int i = 0; i < mDocumentValues.length; ++i) {
-                    innerHashCodes[i] = BundleUtil.deepHashCode(mDocumentValues[i]);
-                }
-                hashCode = Arrays.hashCode(innerHashCodes);
+                hashCode = Arrays.hashCode(mDocumentValues);
             }
             mHashCode = Objects.hash(mPropertyName, hashCode);
         }
@@ -239,9 +230,7 @@
                 && Arrays.equals(mDoubleValues, otherPropertyParcel.mDoubleValues)
                 && Arrays.equals(mBooleanValues, otherPropertyParcel.mBooleanValues)
                 && Arrays.deepEquals(mBytesValues, otherPropertyParcel.mBytesValues)
-                // TODO(b/24205844) Change it to Arrays.equals once GenericDocumentParcel is added.
-                && BundleUtil.bundleValueEquals(
-                mDocumentValues, otherPropertyParcel.mDocumentValues);
+                && Arrays.equals(mDocumentValues, otherPropertyParcel.mDocumentValues);
     }
 
     /** Builder for {@link PropertyParcel}. */
@@ -252,7 +241,7 @@
         private double[] mDoubleValues;
         private boolean[] mBooleanValues;
         private byte[][] mBytesValues;
-        private Bundle[] mDocumentValues;
+        private GenericDocumentParcel[] mDocumentValues;
 
         public Builder(@NonNull String propertyName) {
             mPropertyName = Objects.requireNonNull(propertyName);
@@ -295,7 +284,7 @@
 
         /** Sets document values. */
         @NonNull
-        public Builder setDocumentValues(@NonNull Bundle[] documentValues) {
+        public Builder setDocumentValues(@NonNull GenericDocumentParcel[] documentValues) {
             mDocumentValues = Objects.requireNonNull(documentValues);
             return this;
         }
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/safeparcel/stub/StubCreators.java b/appsearch/appsearch/src/main/java/androidx/appsearch/safeparcel/stub/StubCreators.java
index 5b36ecd..c4f9241 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/safeparcel/stub/StubCreators.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/safeparcel/stub/StubCreators.java
@@ -16,7 +16,9 @@
 package androidx.appsearch.safeparcel.stub;
 
 import androidx.annotation.RestrictTo;
+import androidx.appsearch.app.safeparcel.GenericDocumentParcel;
 import androidx.appsearch.app.safeparcel.PropertyConfigParcel;
+import androidx.appsearch.app.safeparcel.PropertyParcel;
 
 /**
  * Stub creators for any classes extending
@@ -33,7 +35,7 @@
     public static class StorageInfoCreator extends AbstractCreator {
     }
 
-    /** Stub creator for {@link androidx.appsearch.app.PropertyParcel}. */
+    /** Stub creator for {@link PropertyParcel}. */
     public static class PropertyParcelCreator extends AbstractCreator {
     }
 
@@ -68,4 +70,8 @@
      */
     public static class DocumentIndexingConfigParcelCreator extends AbstractCreator {
     }
+
+    /** Stub creator for {@link GenericDocumentParcel}. */
+    public static class GenericDocumentParcelCreator extends AbstractCreator {
+    }
 }
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/InstrumentationResults.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/InstrumentationResults.kt
index d778a9f..bae0b4c 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/InstrumentationResults.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/InstrumentationResults.kt
@@ -298,6 +298,9 @@
         absoluteFilePath: String,
         reportOnRunEndOnly: Boolean = false
     ) {
+        require(!key.contains('=')) {
+            "Key must not contain '=', which breaks instrumentation result string parsing"
+        }
         if (reportOnRunEndOnly) {
             InstrumentationResultScope(runEndResultBundle).fileRecord(key, absoluteFilePath)
         } else {
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/Outputs.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/Outputs.kt
index 53c59e4..44262c6 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/Outputs.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/Outputs.kt
@@ -117,7 +117,6 @@
      */
     fun writeFile(
         fileName: String,
-        reportKey: String,
         reportOnRunEndOnly: Boolean = false,
         block: (file: File) -> Unit,
     ): String {
@@ -143,7 +142,7 @@
         }
 
         InstrumentationResults.reportAdditionalFileToCopy(
-            key = reportKey,
+            key = sanitizedName,
             absoluteFilePath = destination.absolutePath,
             reportOnRunEndOnly = reportOnRunEndOnly
         )
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/Profiler.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/Profiler.kt
index 19d47fc..1a7b9308 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/Profiler.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/Profiler.kt
@@ -293,8 +293,7 @@
     override fun stop() {
         session!!.stopRecording()
         Outputs.writeFile(
-            fileName = outputRelativePath!!,
-            reportKey = "simpleperf_trace"
+            fileName = outputRelativePath!!
         ) {
             session!!.convertSimpleperfOutputToProto("simpleperf.data", it.absolutePath)
         }
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/ResultWriter.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/ResultWriter.kt
index 873ead3..03c8c81 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/ResultWriter.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/ResultWriter.kt
@@ -43,7 +43,6 @@
 
             Outputs.writeFile(
                 fileName = "$packageName-benchmarkData.json",
-                reportKey = "results_json",
                 reportOnRunEndOnly = true
             ) {
                 Log.d(
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoCaptureWrapper.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoCaptureWrapper.kt
index 5eaa17c..22529eb 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoCaptureWrapper.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoCaptureWrapper.kt
@@ -76,8 +76,7 @@
     @RequiresApi(23)
     private fun stop(traceLabel: String): String {
         return Outputs.writeFile(
-            fileName = "${traceLabel}_${dateToFileName()}.perfetto-trace",
-            reportKey = "perfetto_trace_$traceLabel"
+            fileName = "${traceLabel}_${dateToFileName()}.perfetto-trace"
         ) {
             capture!!.stop(it.absolutePath)
             if (Outputs.forceFilesForShellAccessible) {
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoHelper.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoHelper.kt
index b4fdbc1..6c67eab 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoHelper.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoHelper.kt
@@ -421,8 +421,6 @@
                     // supported by a device. That is why we need to search from most specific to
                     // least specific. For e.g. emulators claim to support aarch64, when in reality
                     // they can only support x86 or x86_64.
-                    // Note: Cuttlefish is x86 but claims support for x86_64
-                    Build.MODEL.contains("Cuttlefish") -> "x86" // TODO(204892353): handle properly
                     Build.SUPPORTED_64_BIT_ABIS.any { it.startsWith("x86_64") } -> "x86_64"
                     Build.SUPPORTED_32_BIT_ABIS.any { it.startsWith("x86") } -> "x86"
                     Build.SUPPORTED_64_BIT_ABIS.any { it.startsWith("arm64") } -> "aarch64"
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/BaselineProfiles.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/BaselineProfiles.kt
index bb55014..1514db6 100644
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/BaselineProfiles.kt
+++ b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/BaselineProfiles.kt
@@ -190,23 +190,21 @@
     // Write a file with a timestamp to be able to disambiguate between runs with the same
     // unique name.
 
-    val (fileName, reportKey, tsFileName) =
+    val (fileName, tsFileName) =
         if (includeInStartupProfile && Arguments.enableStartupProfiles) {
             arrayOf(
                 "$uniqueFilePrefix-startup-prof.txt",
-                "startup-profile",
                 "$uniqueFilePrefix-startup-prof-${Outputs.dateToFileName()}.txt"
             )
         } else {
             arrayOf(
                 "$uniqueFilePrefix-baseline-prof.txt",
-                "baseline-profile",
                 "$uniqueFilePrefix-baseline-prof-${Outputs.dateToFileName()}.txt"
             )
         }
 
-    val absolutePath = Outputs.writeFile(fileName, reportKey) { it.writeText(profile) }
-    val tsAbsolutePath = Outputs.writeFile(tsFileName, "baseline-profile-ts") {
+    val absolutePath = Outputs.writeFile(fileName) { it.writeText(profile) }
+    val tsAbsolutePath = Outputs.writeFile(tsFileName) {
         Log.d(TAG, "Pull Baseline Profile with: `adb pull \"${it.absolutePath}\" .`")
         it.writeText(profile)
     }
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/MacrobenchmarkScope.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/MacrobenchmarkScope.kt
index 9b141c6..5990a47 100644
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/MacrobenchmarkScope.kt
+++ b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/MacrobenchmarkScope.kt
@@ -332,7 +332,7 @@
         // Staging location before we write it again using Outputs.writeFile(...)
         Shell.executeScriptSilent("cp '$tracePath' '$stagingFile'")
         // Report(
-        val outputPath = Outputs.writeFile(fileName, fileName) {
+        val outputPath = Outputs.writeFile(fileName) {
             Log.d(TAG, "Writing method traces to ${it.absolutePath}")
             stagingFile.copyTo(it, overwrite = true)
             // Cleanup
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/MethodTracing.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/MethodTracing.kt
index f77efc40e..790413a 100644
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/MethodTracing.kt
+++ b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/MethodTracing.kt
@@ -60,7 +60,7 @@
         val stagingPath = "${Outputs.dirUsableByAppAndShell}/_$fileName"
         Shell.executeScriptSilent("cp '$sourcePath' '$stagingPath'")
         // Report
-        Outputs.writeFile(fileName, fileName) {
+        Outputs.writeFile(fileName) {
             val staging = File(stagingPath)
             // No need to clean up, here because the clean up happens automatically on subsequent
             // test runs.
diff --git a/bluetooth/bluetooth-testing/src/test/kotlin/androidx/bluetooth/testing/RobolectricAdvertiseTest.kt b/bluetooth/bluetooth-testing/src/test/kotlin/androidx/bluetooth/testing/RobolectricAdvertiseTest.kt
index 8c6a2e1..f27a1e5 100644
--- a/bluetooth/bluetooth-testing/src/test/kotlin/androidx/bluetooth/testing/RobolectricAdvertiseTest.kt
+++ b/bluetooth/bluetooth-testing/src/test/kotlin/androidx/bluetooth/testing/RobolectricAdvertiseTest.kt
@@ -34,7 +34,7 @@
 @OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
 class RobolectricAdvertiseTest {
     private val context: Context = RuntimeEnvironment.getApplication()
-    private var bluetoothLe = BluetoothLe(context)
+    private var bluetoothLe = BluetoothLe.getInstance(context)
 
     @Test
     fun advertiseSuccess() = runTest {
diff --git a/bluetooth/bluetooth-testing/src/test/kotlin/androidx/bluetooth/testing/RobolectricGattClientTest.kt b/bluetooth/bluetooth-testing/src/test/kotlin/androidx/bluetooth/testing/RobolectricGattClientTest.kt
index ac2372c..ab35eda 100644
--- a/bluetooth/bluetooth-testing/src/test/kotlin/androidx/bluetooth/testing/RobolectricGattClientTest.kt
+++ b/bluetooth/bluetooth-testing/src/test/kotlin/androidx/bluetooth/testing/RobolectricGattClientTest.kt
@@ -39,6 +39,7 @@
 import kotlinx.coroutines.flow.first
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.test.runTest
+import org.junit.After
 import org.junit.Assert
 import org.junit.Assert.assertTrue
 import org.junit.Before
@@ -98,11 +99,16 @@
 
     @Before
     fun setUp() {
-        bluetoothLe = BluetoothLe(context)
+        bluetoothLe = BluetoothLe.getInstance(context)
         clientAdapter = StubClientFrameworkAdapter(bluetoothLe.client.fwkAdapter)
         bluetoothLe.client.fwkAdapter = clientAdapter
     }
 
+    @After
+    fun tearDown() {
+        bluetoothLe.client.fwkAdapter = clientAdapter.baseAdapter
+    }
+
     @Test
     fun connectGatt() = runTest {
         val device = createDevice("00:11:22:33:44:55")
@@ -366,7 +372,7 @@
     }
 
     class StubClientFrameworkAdapter(
-        private val baseAdapter: GattClient.FrameworkAdapter
+        internal val baseAdapter: GattClient.FrameworkAdapter
     ) : GattClient.FrameworkAdapter {
         var gattServices: List<FwkService> = listOf()
         var callback: BluetoothGattCallback? = null
diff --git a/bluetooth/bluetooth-testing/src/test/kotlin/androidx/bluetooth/testing/RobolectricGattServerTest.kt b/bluetooth/bluetooth-testing/src/test/kotlin/androidx/bluetooth/testing/RobolectricGattServerTest.kt
index 741377c..07e8583 100644
--- a/bluetooth/bluetooth-testing/src/test/kotlin/androidx/bluetooth/testing/RobolectricGattServerTest.kt
+++ b/bluetooth/bluetooth-testing/src/test/kotlin/androidx/bluetooth/testing/RobolectricGattServerTest.kt
@@ -41,6 +41,7 @@
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.runBlocking
 import kotlinx.coroutines.test.runTest
+import org.junit.After
 import org.junit.Assert
 import org.junit.Before
 import org.junit.Test
@@ -90,11 +91,16 @@
 
     @Before
     fun setUp() {
-        bluetoothLe = BluetoothLe(context)
+        bluetoothLe = BluetoothLe.getInstance(context)
         serverAdapter = StubServerFrameworkAdapter(bluetoothLe.server.fwkAdapter)
         bluetoothLe.server.fwkAdapter = serverAdapter
     }
 
+    @After
+    fun tearDown() {
+        bluetoothLe.server.fwkAdapter = serverAdapter.baseAdapter
+    }
+
     @Test
     fun openGattServer() = runTest {
         val device = createDevice("00:11:22:33:44:55")
@@ -498,7 +504,7 @@
     }
 
     class StubServerFrameworkAdapter(
-        private val baseAdapter: GattServer.FrameworkAdapter
+        val baseAdapter: GattServer.FrameworkAdapter
     ) : GattServer.FrameworkAdapter {
         val shadowGattServer: ShadowBluetoothGattServer
             get() = shadowOf(gattServer)
diff --git a/bluetooth/bluetooth-testing/src/test/kotlin/androidx/bluetooth/testing/RobolectricScanTest.kt b/bluetooth/bluetooth-testing/src/test/kotlin/androidx/bluetooth/testing/RobolectricScanTest.kt
index 189873a..a983408 100644
--- a/bluetooth/bluetooth-testing/src/test/kotlin/androidx/bluetooth/testing/RobolectricScanTest.kt
+++ b/bluetooth/bluetooth-testing/src/test/kotlin/androidx/bluetooth/testing/RobolectricScanTest.kt
@@ -39,7 +39,7 @@
 @OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
 class RobolectricScanTest {
     private val context: Context = RuntimeEnvironment.getApplication()
-    private var bluetoothLe = BluetoothLe(context)
+    private var bluetoothLe = BluetoothLe.getInstance(context)
     private companion object {
         private const val TIMEOUT_MS: Long = 2_000
     }
diff --git a/bluetooth/bluetooth/api/current.txt b/bluetooth/bluetooth/api/current.txt
index 004a624..2618c72 100644
--- a/bluetooth/bluetooth/api/current.txt
+++ b/bluetooth/bluetooth/api/current.txt
@@ -61,11 +61,16 @@
   }
 
   public final class BluetoothLe {
-    ctor public BluetoothLe(android.content.Context context);
     method @RequiresPermission("android.permission.BLUETOOTH_ADVERTISE") public suspend Object? advertise(androidx.bluetooth.AdvertiseParams advertiseParams, optional kotlin.jvm.functions.Function2<? super java.lang.Integer,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?>? block, optional kotlin.coroutines.Continuation<? super kotlin.Unit>);
     method @RequiresPermission("android.permission.BLUETOOTH_CONNECT") public suspend <R> Object? connectGatt(androidx.bluetooth.BluetoothDevice device, kotlin.jvm.functions.Function2<? super androidx.bluetooth.BluetoothLe.GattClientScope,? super kotlin.coroutines.Continuation<? super R>,?> block, kotlin.coroutines.Continuation<? super R>);
+    method public static androidx.bluetooth.BluetoothLe getInstance(android.content.Context context);
     method public suspend <R> Object? openGattServer(java.util.List<androidx.bluetooth.GattService> services, kotlin.jvm.functions.Function2<? super androidx.bluetooth.BluetoothLe.GattServerConnectScope,? super kotlin.coroutines.Continuation<? super R>,?> block, kotlin.coroutines.Continuation<? super R>);
     method @RequiresPermission("android.permission.BLUETOOTH_SCAN") public kotlinx.coroutines.flow.Flow<androidx.bluetooth.ScanResult> scan(optional java.util.List<androidx.bluetooth.ScanFilter> filters);
+    field public static final androidx.bluetooth.BluetoothLe.Companion Companion;
+  }
+
+  public static final class BluetoothLe.Companion {
+    method public androidx.bluetooth.BluetoothLe getInstance(android.content.Context context);
   }
 
   public static interface BluetoothLe.GattClientScope {
diff --git a/bluetooth/bluetooth/api/restricted_current.txt b/bluetooth/bluetooth/api/restricted_current.txt
index 004a624..2618c72 100644
--- a/bluetooth/bluetooth/api/restricted_current.txt
+++ b/bluetooth/bluetooth/api/restricted_current.txt
@@ -61,11 +61,16 @@
   }
 
   public final class BluetoothLe {
-    ctor public BluetoothLe(android.content.Context context);
     method @RequiresPermission("android.permission.BLUETOOTH_ADVERTISE") public suspend Object? advertise(androidx.bluetooth.AdvertiseParams advertiseParams, optional kotlin.jvm.functions.Function2<? super java.lang.Integer,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?>? block, optional kotlin.coroutines.Continuation<? super kotlin.Unit>);
     method @RequiresPermission("android.permission.BLUETOOTH_CONNECT") public suspend <R> Object? connectGatt(androidx.bluetooth.BluetoothDevice device, kotlin.jvm.functions.Function2<? super androidx.bluetooth.BluetoothLe.GattClientScope,? super kotlin.coroutines.Continuation<? super R>,?> block, kotlin.coroutines.Continuation<? super R>);
+    method public static androidx.bluetooth.BluetoothLe getInstance(android.content.Context context);
     method public suspend <R> Object? openGattServer(java.util.List<androidx.bluetooth.GattService> services, kotlin.jvm.functions.Function2<? super androidx.bluetooth.BluetoothLe.GattServerConnectScope,? super kotlin.coroutines.Continuation<? super R>,?> block, kotlin.coroutines.Continuation<? super R>);
     method @RequiresPermission("android.permission.BLUETOOTH_SCAN") public kotlinx.coroutines.flow.Flow<androidx.bluetooth.ScanResult> scan(optional java.util.List<androidx.bluetooth.ScanFilter> filters);
+    field public static final androidx.bluetooth.BluetoothLe.Companion Companion;
+  }
+
+  public static final class BluetoothLe.Companion {
+    method public androidx.bluetooth.BluetoothLe getInstance(android.content.Context context);
   }
 
   public static interface BluetoothLe.GattClientScope {
diff --git a/bluetooth/bluetooth/src/androidTest/java/androidx/bluetooth/BluetoothLeTest.kt b/bluetooth/bluetooth/src/androidTest/java/androidx/bluetooth/BluetoothLeTest.kt
index 822fd61..8e1f074 100644
--- a/bluetooth/bluetooth/src/androidTest/java/androidx/bluetooth/BluetoothLeTest.kt
+++ b/bluetooth/bluetooth/src/androidTest/java/androidx/bluetooth/BluetoothLeTest.kt
@@ -59,7 +59,7 @@
         context = ApplicationProvider.getApplicationContext()
         bluetoothManager = context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
         bluetoothAdapter = bluetoothManager.adapter
-        bluetoothLe = BluetoothLe(context)
+        bluetoothLe = BluetoothLe.getInstance(context)
 
         Assume.assumeNotNull(bluetoothAdapter)
         Assume.assumeTrue(bluetoothAdapter.isEnabled)
diff --git a/bluetooth/bluetooth/src/main/java/androidx/bluetooth/BluetoothLe.kt b/bluetooth/bluetooth/src/main/java/androidx/bluetooth/BluetoothLe.kt
index 24d6dd1..5b34edc 100644
--- a/bluetooth/bluetooth/src/main/java/androidx/bluetooth/BluetoothLe.kt
+++ b/bluetooth/bluetooth/src/main/java/androidx/bluetooth/BluetoothLe.kt
@@ -49,10 +49,20 @@
  * Entry point for BLE related operations. This class provides a way to perform Bluetooth LE
  * operations such as scanning, advertising, and connection with a respective [BluetoothDevice].
  */
-class BluetoothLe constructor(private val context: Context) {
+class BluetoothLe private constructor(private val context: Context) {
 
-    private companion object {
+    companion object {
         private const val TAG = "BluetoothLe"
+        @Volatile
+        @JvmStatic
+        private var instance: BluetoothLe? = null
+
+        @Suppress("VisiblySynchronized")
+        @JvmStatic
+        fun getInstance(context: Context) =
+            instance ?: synchronized(this) {
+                instance ?: BluetoothLe(context.applicationContext).also { instance = it }
+            }
     }
 
     @RequiresApi(34)
diff --git a/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/advertiser/AdvertiserFragment.kt b/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/advertiser/AdvertiserFragment.kt
index 3e1623b..a8b1eb1 100644
--- a/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/advertiser/AdvertiserFragment.kt
+++ b/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/advertiser/AdvertiserFragment.kt
@@ -136,7 +136,7 @@
         container: ViewGroup?,
         savedInstanceState: Bundle?
     ): View {
-        bluetoothLe = BluetoothLe(requireContext())
+        bluetoothLe = BluetoothLe.getInstance(requireContext())
 
         _binding = FragmentAdvertiserBinding.inflate(inflater, container, false)
 
diff --git a/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/scanner/ScannerFragment.kt b/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/scanner/ScannerFragment.kt
index acdb648..b65bbde 100644
--- a/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/scanner/ScannerFragment.kt
+++ b/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/scanner/ScannerFragment.kt
@@ -140,7 +140,7 @@
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
         super.onViewCreated(view, savedInstanceState)
 
-        bluetoothLe = BluetoothLe(requireContext())
+        bluetoothLe = BluetoothLe.getInstance(requireContext())
 
         binding.tabLayout.addOnTabSelectedListener(onTabSelectedListener)
 
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt
index 73b8580..c49ae6d 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt
@@ -792,14 +792,20 @@
             File(project.buildDir, "../nativeBuildStaging")
     }
 
+    @Suppress("UnstableApiUsage") // finalizeDsl, minCompileSdkExtension
     private fun LibraryExtension.configureAndroidLibraryOptions(
         project: Project,
         androidXExtension: AndroidXExtension
     ) {
-        // Note, this should really match COMPILE_SDK_VERSION, however
-        // this API takes an integer and we are unable to set it to a
-        // pre-release SDK.
-        defaultConfig.aarMetadata.minCompileSdk = project.defaultAndroidConfig.targetSdk
+        // Propagate the compileSdk value into minCompileSdk. Don't propagate compileSdkExtension,
+        // since only one library actually depends on the extension APIs and they can explicitly
+        // declare that in their build.gradle. Note that when we're using a preview SDK, the value
+        // for compileSdk will be null and the resulting AAR metadata won't have a minCompileSdk --
+        // this is okay because AGP automatically embeds forceCompileSdkPreview in the AAR metadata
+        // and uses it instead of minCompileSdk.
+        project.extensions.findByType<LibraryAndroidComponentsExtension>()!!.finalizeDsl {
+            it.defaultConfig.aarMetadata.minCompileSdk = it.compileSdk
+        }
 
         // The full Guava artifact is very large, so they split off a special artifact containing a
         // standalone version of the commonly-used ListenableFuture interface. However, they also
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/LintConfiguration.kt b/buildSrc/private/src/main/kotlin/androidx/build/LintConfiguration.kt
index 5a881a2..a307c9d 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/LintConfiguration.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/LintConfiguration.kt
@@ -345,6 +345,9 @@
             disable.add("LintError")
         }
 
+        // Disable a check that's only relevant for apps that ship to Play Store. (b/299278101)
+        disable.add("ExpiredTargetSdkVersion")
+
         // Reenable after b/238892319 is resolved
         disable.add("NotificationPermission")
 
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/MavenUploadHelper.kt b/buildSrc/private/src/main/kotlin/androidx/build/MavenUploadHelper.kt
index cd60cc3..9380bb9 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/MavenUploadHelper.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/MavenUploadHelper.kt
@@ -443,6 +443,9 @@
         scm.url.set("https://cs.android.com/androidx/platform/frameworks/support")
         scm.connection.set(ANDROID_GIT_URL)
     }
+    pom.organization { org ->
+        org.name.set("The Android Open Source Project")
+    }
     pom.developers { devs ->
         devs.developer { dev -> dev.name.set("The Android Open Source Project") }
     }
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 c7006f8..144ed14 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/dackka/DackkaTask.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/dackka/DackkaTask.kt
@@ -34,6 +34,7 @@
 import org.gradle.api.tasks.Input
 import org.gradle.api.tasks.InputFile
 import org.gradle.api.tasks.InputFiles
+import org.gradle.api.tasks.Internal
 import org.gradle.api.tasks.OutputDirectory
 import org.gradle.api.tasks.PathSensitive
 import org.gradle.api.tasks.PathSensitivity
@@ -49,6 +50,8 @@
 constructor(private val workerExecutor: WorkerExecutor, private val objects: ObjectFactory) :
     DefaultTask() {
 
+    @Internal lateinit var argsJsonFile: File
+
     @get:[InputFiles PathSensitive(PathSensitivity.RELATIVE)]
     abstract val projectStructureMetadataFile: RegularFileProperty
 
@@ -220,10 +223,8 @@
             )
 
         val json = gson.toJson(jsonMap)
-        val outputFile = File.createTempFile("dackkaArgs", ".json")
-        outputFile.deleteOnExit()
-        outputFile.writeText(json)
-        return outputFile
+        argsJsonFile.writeText(json)
+        return argsJsonFile
     }
 
     /**
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/docs/AndroidXDocsImplPlugin.kt b/buildSrc/private/src/main/kotlin/androidx/build/docs/AndroidXDocsImplPlugin.kt
index e39904c2..e6ccb06 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/docs/AndroidXDocsImplPlugin.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/docs/AndroidXDocsImplPlugin.kt
@@ -487,6 +487,10 @@
         val dackkaTask =
             project.tasks.register("docs", DackkaTask::class.java) { task ->
                 var taskStartTime: LocalDateTime? = null
+                task.argsJsonFile = File(
+                    project.rootProject.getDistributionDirectory(),
+                    "dackkaArgs-${project.name}.json"
+                )
                 task.apply {
                     dependsOn(unzipJvmSourcesTask)
                     dependsOn(unzipSamplesTask)
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraSurfaceAdapter.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraSurfaceAdapter.kt
index e8b59257..72d3930 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraSurfaceAdapter.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraSurfaceAdapter.kt
@@ -122,6 +122,7 @@
      * @param newUseCaseConfigsSupportedSizeMap map of configurations of the use cases to the
      *                                          supported sizes list that will be given a
      *                                          suggested stream specification
+     * @param isPreviewStabilizationOn          whether the preview stabilization is enabled.
      * @return map of suggested stream specifications for given use cases
      * @throws IllegalArgumentException if {@code newUseCaseConfigs} is an empty list, if
      *                                  there isn't a supported combination of surfaces
@@ -132,7 +133,8 @@
         cameraMode: Int,
         cameraId: String,
         existingSurfaces: List<AttachedSurfaceInfo>,
-        newUseCaseConfigsSupportedSizeMap: Map<UseCaseConfig<*>, List<Size>>
+        newUseCaseConfigsSupportedSizeMap: Map<UseCaseConfig<*>, List<Size>>,
+        isPreviewStabilizationOn: Boolean
     ): Pair<Map<UseCaseConfig<*>, StreamSpec>, Map<AttachedSurfaceInfo, StreamSpec>> {
 
         if (!checkIfSupportedCombinationExist(cameraId)) {
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2CameraMetadata.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2CameraMetadata.kt
index ec0be0e..7274b3b 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2CameraMetadata.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2CameraMetadata.kt
@@ -36,8 +36,7 @@
  * This allows all fields to be accessed and return reasonable values on all OS versions.
  */
 @RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
-internal class Camera2CameraMetadata
-constructor(
+internal class Camera2CameraMetadata(
     override val camera: CameraId,
     override val isRedacted: Boolean,
     private val characteristics: CameraCharacteristics,
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2MetadataCache.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2MetadataCache.kt
index e7187fe..ba3953d7 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2MetadataCache.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2MetadataCache.kt
@@ -17,7 +17,9 @@
 package androidx.camera.camera2.pipe.compat
 
 import android.content.Context
+import android.hardware.camera2.CameraCharacteristics
 import android.hardware.camera2.CameraManager
+import android.os.Build
 import android.util.ArrayMap
 import androidx.annotation.GuardedBy
 import androidx.annotation.RequiresApi
@@ -105,7 +107,13 @@
 
                 // Merge the camera specific and global cache blocklists together.
                 // this will prevent these values from being cached after first access.
-                val cameraBlocklist = cameraMetadataConfig.cameraCacheBlocklist[cameraId]
+                val cameraBlocklist =
+                    if (shouldBlockSensorOrientationCache(characteristics)) {
+                        (cameraMetadataConfig.cameraCacheBlocklist[cameraId] ?: emptySet()) +
+                            CameraCharacteristics.SENSOR_ORIENTATION
+                    } else {
+                        cameraMetadataConfig.cameraCacheBlocklist[cameraId]
+                    }
                 val cacheBlocklist =
                     if (cameraBlocklist == null) {
                         cameraMetadataConfig.cacheBlocklist
@@ -146,4 +154,9 @@
     }
 
     private fun isMetadataRedacted(): Boolean = !permissions.hasCameraPermission
+
+    private fun shouldBlockSensorOrientationCache(characteristics: CameraCharacteristics): Boolean {
+        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.S_V2 &&
+            characteristics[CameraCharacteristics.INFO_DEVICE_STATE_SENSOR_ORIENTATION_MAP] != null
+    }
 }
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraImpl.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraImpl.java
index 78ff31d..5422996 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraImpl.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraImpl.java
@@ -1122,7 +1122,7 @@
 
         try {
             mSupportedSurfaceCombination.getSuggestedStreamSpecifications(cameraMode,
-                    attachedSurfaces, useCaseConfigToSizeMap);
+                    attachedSurfaces, useCaseConfigToSizeMap, false);
         } catch (IllegalArgumentException e) {
             debugLog("Surface combination with metering repeating  not supported!", e);
             return false;
@@ -1480,7 +1480,11 @@
                 }
 
                 Logger.e(TAG, "Unable to configure camera " + Camera2CameraImpl.this, t);
-                resetCaptureSession(/*abortInFlightCaptures=*/false);
+
+                // Reset capture session if the latest capture session fails to open.
+                if (mCaptureSession == captureSession) {
+                    resetCaptureSession(/*abortInFlightCaptures=*/false);
+                }
             }
         }, mExecutor);
     }
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraInfoImpl.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraInfoImpl.java
index 3729cf8..e6da980 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraInfoImpl.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraInfoImpl.java
@@ -16,10 +16,12 @@
 
 package androidx.camera.camera2.internal;
 
+import static android.hardware.camera2.CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES;
+import static android.hardware.camera2.CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_ON;
+import static android.hardware.camera2.CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION;
 import static android.hardware.camera2.CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING;
 import static android.hardware.camera2.CameraMetadata.SENSOR_INFO_TIMESTAMP_SOURCE_REALTIME;
 import static android.hardware.camera2.CameraMetadata.SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN;
-
 import static androidx.camera.camera2.internal.ZslUtil.isCapabilitySupported;
 
 import android.hardware.camera2.CameraCharacteristics;
@@ -505,6 +507,36 @@
         }
     }
 
+    @Override
+    public boolean isVideoStabilizationSupported() {
+        int[] availableVideoStabilizationModes =
+                mCameraCharacteristicsCompat.get(
+                        CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES);
+        if (availableVideoStabilizationModes != null) {
+            for (int mode : availableVideoStabilizationModes) {
+                if (mode == CONTROL_VIDEO_STABILIZATION_MODE_ON) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public boolean isPreviewStabilizationSupported() {
+        int[] availableVideoStabilizationModes =
+                mCameraCharacteristicsCompat.get(
+                        CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES);
+        if (availableVideoStabilizationModes != null) {
+            for (int mode : availableVideoStabilizationModes) {
+                if (mode == CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
     /**
      * Gets the implementation of {@link Camera2CameraInfo}.
      */
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2DeviceSurfaceManager.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2DeviceSurfaceManager.java
index 7c1d95e..1322af7 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2DeviceSurfaceManager.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2DeviceSurfaceManager.java
@@ -171,7 +171,8 @@
             @CameraMode.Mode int cameraMode,
             @NonNull String cameraId,
             @NonNull List<AttachedSurfaceInfo> existingSurfaces,
-            @NonNull Map<UseCaseConfig<?>, List<Size>> newUseCaseConfigsSupportedSizeMap) {
+            @NonNull Map<UseCaseConfig<?>, List<Size>> newUseCaseConfigsSupportedSizeMap,
+            boolean isPreviewStabilizationOn) {
         Preconditions.checkArgument(!newUseCaseConfigsSupportedSizeMap.isEmpty(),
                 "No new use cases to be bound.");
 
@@ -186,6 +187,7 @@
         return supportedSurfaceCombination.getSuggestedStreamSpecifications(
                 cameraMode,
                 existingSurfaces,
-                newUseCaseConfigsSupportedSizeMap);
+                newUseCaseConfigsSupportedSizeMap,
+                isPreviewStabilizationOn);
     }
 }
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/GuaranteedConfigurationsUtil.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/GuaranteedConfigurationsUtil.java
index d18bd1b..5a4413f 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/GuaranteedConfigurationsUtil.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/GuaranteedConfigurationsUtil.java
@@ -833,6 +833,93 @@
     }
 
     /**
+     * Returns the supported stream combinations for preview stabilization.
+     */
+    @RequiresApi(api = Build.VERSION_CODES.TIRAMISU)
+    @NonNull
+    public static List<SurfaceCombination> getPreviewStabilizationSupportedCombinationList() {
+        List<SurfaceCombination> combinationList = new ArrayList<>();
+
+        // (PRIV, s1440p)
+        SurfaceCombination surfaceCombination1 = new SurfaceCombination();
+        surfaceCombination1.addSurfaceConfig(
+                SurfaceConfig.create(ConfigType.PRIV, ConfigSize.s1440p));
+        combinationList.add(surfaceCombination1);
+
+        // (YUV, s1440p)
+        SurfaceCombination surfaceCombination2 = new SurfaceCombination();
+        surfaceCombination2.addSurfaceConfig(
+                SurfaceConfig.create(ConfigType.YUV, ConfigSize.s1440p));
+        combinationList.add(surfaceCombination2);
+
+        // (PRIV, s1440p) + (JPEG, MAXIMUM)
+        SurfaceCombination surfaceCombination3 = new SurfaceCombination();
+        surfaceCombination3.addSurfaceConfig(
+                SurfaceConfig.create(ConfigType.PRIV, ConfigSize.s1440p));
+        surfaceCombination3.addSurfaceConfig(
+                SurfaceConfig.create(ConfigType.JPEG, ConfigSize.MAXIMUM));
+        combinationList.add(surfaceCombination3);
+
+        // (YUV, s1440p) + (JPEG, MAXIMUM)
+        SurfaceCombination surfaceCombination4 = new SurfaceCombination();
+        surfaceCombination4.addSurfaceConfig(
+                SurfaceConfig.create(ConfigType.YUV, ConfigSize.s1440p));
+        surfaceCombination4.addSurfaceConfig(
+                SurfaceConfig.create(ConfigType.JPEG, ConfigSize.MAXIMUM));
+        combinationList.add(surfaceCombination4);
+
+        // (PRIV, s1440p) + (YUV, MAXIMUM)
+        SurfaceCombination surfaceCombination5 = new SurfaceCombination();
+        surfaceCombination5.addSurfaceConfig(
+                SurfaceConfig.create(ConfigType.PRIV, ConfigSize.s1440p));
+        surfaceCombination5.addSurfaceConfig(
+                SurfaceConfig.create(ConfigType.YUV, ConfigSize.MAXIMUM));
+        combinationList.add(surfaceCombination5);
+
+        // (YUV, s1440p) + (YUV, MAXIMUM)
+        SurfaceCombination surfaceCombination6 = new SurfaceCombination();
+        surfaceCombination6.addSurfaceConfig(
+                SurfaceConfig.create(ConfigType.YUV, ConfigSize.s1440p));
+        surfaceCombination6.addSurfaceConfig(
+                SurfaceConfig.create(ConfigType.YUV, ConfigSize.MAXIMUM));
+        combinationList.add(surfaceCombination6);
+
+        // (PRIV, PREVIEW) + (PRIV, s1440)
+        SurfaceCombination surfaceCombination7 = new SurfaceCombination();
+        surfaceCombination7.addSurfaceConfig(
+                SurfaceConfig.create(ConfigType.PRIV, ConfigSize.PREVIEW));
+        surfaceCombination7.addSurfaceConfig(
+                SurfaceConfig.create(ConfigType.PRIV, ConfigSize.s1440p));
+        combinationList.add(surfaceCombination7);
+
+        // (YUV, PREVIEW) + (PRIV, s1440)
+        SurfaceCombination surfaceCombination8 = new SurfaceCombination();
+        surfaceCombination8.addSurfaceConfig(
+                SurfaceConfig.create(ConfigType.YUV, ConfigSize.PREVIEW));
+        surfaceCombination8.addSurfaceConfig(
+                SurfaceConfig.create(ConfigType.PRIV, ConfigSize.s1440p));
+        combinationList.add(surfaceCombination8);
+
+        // (PRIV, PREVIEW) + (YUV, s1440)
+        SurfaceCombination surfaceCombination9 = new SurfaceCombination();
+        surfaceCombination9.addSurfaceConfig(
+                SurfaceConfig.create(ConfigType.PRIV, ConfigSize.PREVIEW));
+        surfaceCombination9.addSurfaceConfig(
+                SurfaceConfig.create(ConfigType.YUV, ConfigSize.s1440p));
+        combinationList.add(surfaceCombination9);
+
+        // (YUV, PREVIEW) + (YUV, s1440)
+        SurfaceCombination surfaceCombination10 = new SurfaceCombination();
+        surfaceCombination10.addSurfaceConfig(
+                SurfaceConfig.create(ConfigType.YUV, ConfigSize.PREVIEW));
+        surfaceCombination10.addSurfaceConfig(
+                SurfaceConfig.create(ConfigType.YUV, ConfigSize.s1440p));
+        combinationList.add(surfaceCombination10);
+
+        return combinationList;
+    }
+
+    /**
      * Returns the supported stream combinations based on the hardware level and capabilities of
      * the device.
      */
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/ProcessingCaptureSession.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/ProcessingCaptureSession.java
index 9b14123..e89c415 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/ProcessingCaptureSession.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/ProcessingCaptureSession.java
@@ -452,7 +452,12 @@
         switch (mProcessorState) {
             case ON_CAPTURE_SESSION_ENDED:
             case SESSION_INITIALIZED:
-                future.addListener(() -> mSessionProcessor.deInitSession(), mExecutor);
+                future.addListener(() -> {
+                    Logger.d(TAG, "== deInitSession (id=" + mInstanceId + ")");
+                    mSessionProcessor.deInitSession();
+                    // Use direct executor to ensure deInitSession is invoked as soon as session is
+                    // closed.
+                }, CameraXExecutors.directExecutor());
                 break;
             default:
                 break;
@@ -478,6 +483,7 @@
         }
         mRequestProcessor = new Camera2RequestProcessor(captureSession,
                 getSessionProcessorSurfaceList(mProcessorSessionConfig.getSurfaces()));
+        Logger.d(TAG, "== onCaptureSessinStarted (id = " + mInstanceId + ")");
         mSessionProcessor.onCaptureSessionStart(mRequestProcessor);
         mProcessorState = ProcessorState.ON_CAPTURE_SESSION_STARTED;
 
@@ -534,6 +540,7 @@
         Logger.d(TAG, "close (id=" + mInstanceId + ") state=" + mProcessorState);
 
         if (mProcessorState == ProcessorState.ON_CAPTURE_SESSION_STARTED) {
+            Logger.d(TAG, "== onCaptureSessionEnd (id = " + mInstanceId + ")");
             mSessionProcessor.onCaptureSessionEnd();
             if (mRequestProcessor != null) {
                 mRequestProcessor.close();
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/SupportedSurfaceCombination.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/SupportedSurfaceCombination.java
index cd453ff..a6d9b50 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/SupportedSurfaceCombination.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/SupportedSurfaceCombination.java
@@ -18,7 +18,6 @@
 
 import static android.content.pm.PackageManager.FEATURE_CAMERA_CONCURRENT;
 import static android.hardware.camera2.CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES;
-
 import static androidx.camera.core.internal.utils.SizeUtil.RESOLUTION_1080P;
 import static androidx.camera.core.internal.utils.SizeUtil.RESOLUTION_480P;
 import static androidx.camera.core.internal.utils.SizeUtil.RESOLUTION_VGA;
@@ -95,6 +94,8 @@
     private final List<SurfaceCombination> mSurfaceCombinations = new ArrayList<>();
     private final List<SurfaceCombination> mUltraHighSurfaceCombinations = new ArrayList<>();
     private final List<SurfaceCombination> mConcurrentSurfaceCombinations = new ArrayList<>();
+    private final List<SurfaceCombination> mPreviewStabilizationSurfaceCombinations =
+            new ArrayList<>();
     private final Map<FeatureSettings, List<SurfaceCombination>>
             mFeatureSettingsToSupportedCombinationsMap = new HashMap<>();
     private final List<SurfaceCombination> mSurfaceCombinations10Bit = new ArrayList<>();
@@ -110,6 +111,7 @@
     private boolean mIsConcurrentCameraModeSupported = false;
     private boolean mIsStreamUseCaseSupported = false;
     private boolean mIsUltraHighResolutionSensorSupported = false;
+    private boolean mIsPreviewStabilizationSupported = false;
     @VisibleForTesting
     SurfaceSizeDefinition mSurfaceSizeDefinition;
     List<Integer> mSurfaceSizeDefinitionFormats = new ArrayList<>();
@@ -184,6 +186,12 @@
             generateStreamUseCaseSupportedCombinationList();
         }
 
+        mIsPreviewStabilizationSupported =
+                VideoStabilizationUtil.isPreviewStabilizationSupported(mCharacteristics);
+        if (mIsPreviewStabilizationSupported) {
+            generatePreviewStabilizationSupportedCombinationList();
+        }
+
         generateSurfaceSizeDefinition();
         checkCustomization();
     }
@@ -267,7 +275,8 @@
                     supportedSurfaceCombinations.addAll(mSurfaceCombinations);
                     break;
                 default:
-                    supportedSurfaceCombinations.addAll(mSurfaceCombinations);
+                    supportedSurfaceCombinations.addAll(featureSettings.isPreviewStabilizationOn()
+                            ? mPreviewStabilizationSurfaceCombinations : mSurfaceCombinations);
                     break;
             }
         } else if (featureSettings.getRequiredMaxBitDepth() == DynamicRange.BIT_DEPTH_10_BIT) {
@@ -521,6 +530,7 @@
      * @param attachedSurfaces                  the existing surfaces.
      * @param newUseCaseConfigsSupportedSizeMap newly added UseCaseConfig to supported output
      *                                          sizes map.
+     * @param isPreviewStabilizationOn          whether the preview stabilization is enabled.
      * @return the suggested stream specifications, which is a pair of mappings. The first
      * mapping is from UseCaseConfig to the suggested stream specification representing new
      * UseCases. The second mapping is from attachedSurfaceInfo to the suggested stream
@@ -536,7 +546,8 @@
             getSuggestedStreamSpecifications(
             @CameraMode.Mode int cameraMode,
             @NonNull List<AttachedSurfaceInfo> attachedSurfaces,
-            @NonNull Map<UseCaseConfig<?>, List<Size>> newUseCaseConfigsSupportedSizeMap) {
+            @NonNull Map<UseCaseConfig<?>, List<Size>> newUseCaseConfigsSupportedSizeMap,
+            boolean isPreviewStabilizationOn) {
         // Refresh Preview Size based on current display configurations.
         refreshPreviewSize();
         List<SurfaceConfig> surfaceConfigs = new ArrayList<>();
@@ -553,7 +564,8 @@
                 mDynamicRangeResolver.resolveAndValidateDynamicRanges(attachedSurfaces,
                         newUseCaseConfigs, useCasesPriorityOrder);
         int requiredMaxBitDepth = getRequiredMaxBitDepth(resolvedDynamicRanges);
-        FeatureSettings featureSettings = FeatureSettings.of(cameraMode, requiredMaxBitDepth);
+        FeatureSettings featureSettings = FeatureSettings.of(cameraMode, requiredMaxBitDepth,
+                isPreviewStabilizationOn);
         if (cameraMode != CameraMode.DEFAULT
                 && requiredMaxBitDepth == DynamicRange.BIT_DEPTH_10_BIT) {
             throw new IllegalArgumentException(String.format("No supported surface combination is "
@@ -1104,6 +1116,13 @@
         }
     }
 
+    private void generatePreviewStabilizationSupportedCombinationList() {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+            mPreviewStabilizationSurfaceCombinations.addAll(
+                    GuaranteedConfigurationsUtil.getPreviewStabilizationSupportedCombinationList());
+        }
+    }
+
     private void checkCustomization() {
         // TODO(b/119466260): Integrate found feasible stream combinations into supported list
     }
@@ -1334,9 +1353,10 @@
     abstract static class FeatureSettings {
         @NonNull
         static FeatureSettings of(@CameraMode.Mode int cameraMode,
-                @RequiredMaxBitDepth int requiredMaxBitDepth) {
+                @RequiredMaxBitDepth int requiredMaxBitDepth,
+                boolean isPreviewStabilizationOn) {
             return new AutoValue_SupportedSurfaceCombination_FeatureSettings(
-                    cameraMode, requiredMaxBitDepth);
+                    cameraMode, requiredMaxBitDepth, isPreviewStabilizationOn);
         }
 
         /**
@@ -1364,5 +1384,10 @@
          * {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT}.
          */
         abstract @RequiredMaxBitDepth int getRequiredMaxBitDepth();
+
+        /**
+         * Whether the preview stabilization is enabled.
+         */
+        abstract boolean isPreviewStabilizationOn();
     }
 }
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/VideoStabilizationUtil.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/VideoStabilizationUtil.java
new file mode 100644
index 0000000..b9f5eeb
--- /dev/null
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/VideoStabilizationUtil.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.camera2.internal;
+
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureRequest;
+import android.os.Build;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+import androidx.camera.camera2.internal.compat.CameraCharacteristicsCompat;
+
+/**
+ * A class that contains utility methods for video stabilization.
+ */
+@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
+public final class VideoStabilizationUtil {
+
+    private VideoStabilizationUtil() {
+    }
+
+    /**
+     * Return true if the given camera characteristics support preview stabilization.
+     */
+    public static boolean isPreviewStabilizationSupported(
+            @NonNull CameraCharacteristicsCompat characteristicsCompat) {
+        if (Build.VERSION.SDK_INT < 33) {
+            return false;
+        }
+        int[] availableVideoStabilizationModes = characteristicsCompat.get(
+                CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES);
+        if (availableVideoStabilizationModes == null
+                || availableVideoStabilizationModes.length == 0) {
+            return false;
+        }
+        for (int mode : availableVideoStabilizationModes) {
+            if (mode == CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/Camera2CameraInfoImplTest.java b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/Camera2CameraInfoImplTest.java
index a0447b4..5908b96 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/Camera2CameraInfoImplTest.java
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/Camera2CameraInfoImplTest.java
@@ -17,12 +17,12 @@
 package androidx.camera.camera2.internal;
 
 import static android.hardware.camera2.CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES;
-
+import static android.hardware.camera2.CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_OFF;
+import static android.hardware.camera2.CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_ON;
+import static android.hardware.camera2.CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION;
 import static androidx.camera.core.DynamicRange.HLG_10_BIT;
 import static androidx.camera.core.DynamicRange.SDR;
-
 import static com.google.common.truth.Truth.assertThat;
-
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -678,6 +678,40 @@
         assertThat(resultFpsRanges1).isEmpty();
     }
 
+    /**
+     * Test for preview stabilization.
+     */
+    @Test
+    public void cameraInfo_isPreviewStabilizationSupported()
+            throws CameraAccessExceptionCompat {
+        init(/* hasAvailableCapabilities = */ false);
+
+        // Camera0
+        CameraInfo cameraInfo0 = new Camera2CameraInfoImpl(CAMERA0_ID,
+                mCameraManagerCompat);
+
+
+        if (Build.VERSION.SDK_INT >= 33) {
+            assertThat(cameraInfo0.isPreviewStabilizationSupported()).isTrue();
+        } else {
+            assertThat(cameraInfo0.isPreviewStabilizationSupported()).isFalse();
+        }
+        assertThat(cameraInfo0.isVideoStabilizationSupported()).isTrue();
+
+        // Camera1
+        CameraInfo cameraInfo1 = new Camera2CameraInfoImpl(CAMERA1_ID,
+                mCameraManagerCompat);
+
+        assertThat(cameraInfo1.isPreviewStabilizationSupported()).isFalse();
+        assertThat(cameraInfo0.isVideoStabilizationSupported()).isTrue();
+
+        // Camera2
+        CameraInfo cameraInfo2 = new Camera2CameraInfoImpl(CAMERA2_ID,
+                mCameraManagerCompat);
+        assertThat(cameraInfo2.isPreviewStabilizationSupported()).isFalse();
+        assertThat(cameraInfo2.isVideoStabilizationSupported()).isFalse();
+    }
+
     @Test
     public void cameraInfo_checkDefaultCameraIntrinsicZoomRatio()
             throws CameraAccessExceptionCompat {
@@ -804,6 +838,24 @@
                     CAMERA0_DYNAMIC_RANGE_PROFILES);
         }
 
+        // Add video stabilization modes
+        if (Build.VERSION.SDK_INT >= 33) {
+            shadowCharacteristics0.set(
+                    CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,
+                    new int[] {
+                            CONTROL_VIDEO_STABILIZATION_MODE_OFF,
+                            CONTROL_VIDEO_STABILIZATION_MODE_ON,
+                            CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION
+                    });
+        } else {
+            shadowCharacteristics0.set(
+                    CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,
+                    new int[] {
+                            CONTROL_VIDEO_STABILIZATION_MODE_OFF,
+                            CONTROL_VIDEO_STABILIZATION_MODE_ON
+                    });
+        }
+
         // Mock the request capability
         if (hasAvailableCapabilities) {
             shadowCharacteristics0.set(REQUEST_AVAILABLE_CAPABILITIES,
@@ -837,6 +889,14 @@
         shadowCharacteristics1.set(
                 CameraCharacteristics.FLASH_INFO_AVAILABLE, CAMERA1_FLASH_INFO_BOOLEAN);
 
+        // Add video stabilization modes
+        shadowCharacteristics1.set(
+                CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,
+                new int[] {
+                        CONTROL_VIDEO_STABILIZATION_MODE_OFF,
+                        CONTROL_VIDEO_STABILIZATION_MODE_ON
+                });
+
         // Mock the supported resolutions
         {
             int formatPrivate = ImageFormatConstants.INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE;
@@ -887,6 +947,13 @@
                 CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,
                 CAMERA2_AE_FPS_RANGES);
 
+        // Add video stabilization modes
+        shadowCharacteristics2.set(
+                CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,
+                new int[] {
+                        CONTROL_VIDEO_STABILIZATION_MODE_OFF
+                });
+
         // Add the camera to the camera service
         ((ShadowCameraManager)
                 Shadow.extract(
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/StreamUseCaseTest.java b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/StreamUseCaseTest.java
index 1c83442..496663c 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/StreamUseCaseTest.java
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/StreamUseCaseTest.java
@@ -17,12 +17,10 @@
 package androidx.camera.camera2.internal;
 
 import static android.os.Build.VERSION.SDK_INT;
-
 import static androidx.camera.camera2.internal.StreamUseCaseUtil.STREAM_USE_CASE_STREAM_SPEC_OPTION;
 import static androidx.camera.core.DynamicRange.BIT_DEPTH_10_BIT;
 import static androidx.camera.core.ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY;
 import static androidx.camera.core.ImageCapture.CAPTURE_MODE_ZERO_SHUTTER_LAG;
-
 import static junit.framework.TestCase.assertFalse;
 import static junit.framework.TestCase.assertTrue;
 
@@ -198,14 +196,16 @@
     public void shouldUseStreamUseCase_cameraModeNotSupported() {
         assertFalse(StreamUseCaseUtil.shouldUseStreamUseCase(
                 SupportedSurfaceCombination.FeatureSettings.of(CameraMode.CONCURRENT_CAMERA,
-                        DynamicRange.BIT_DEPTH_8_BIT)));
+                        DynamicRange.BIT_DEPTH_8_BIT,
+                        false)));
     }
 
     @Test
     public void shouldUseStreamUseCase_bitDepthNotSupported() {
         assertFalse(StreamUseCaseUtil.shouldUseStreamUseCase(
                 SupportedSurfaceCombination.FeatureSettings.of(CameraMode.DEFAULT,
-                        BIT_DEPTH_10_BIT)));
+                        BIT_DEPTH_10_BIT,
+                        false)));
     }
 
     @Test
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/SupportedSurfaceCombinationTest.kt b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/SupportedSurfaceCombinationTest.kt
index c5d0844..2db0d98 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/SupportedSurfaceCombinationTest.kt
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/SupportedSurfaceCombinationTest.kt
@@ -212,7 +212,7 @@
         GuaranteedConfigurationsUtil.getLegacySupportedCombinationList().forEach {
             assertThat(
                 supportedSurfaceCombination.checkSupported(
-                    FeatureSettings.of(CameraMode.DEFAULT, BIT_DEPTH_8_BIT),
+                    FeatureSettings.of(CameraMode.DEFAULT, BIT_DEPTH_8_BIT, false),
                     it.surfaceConfigList
                 )
             ).isTrue()
@@ -228,7 +228,7 @@
         GuaranteedConfigurationsUtil.getLimitedSupportedCombinationList().forEach {
             assertThat(
                 supportedSurfaceCombination.checkSupported(
-                    FeatureSettings.of(CameraMode.DEFAULT, BIT_DEPTH_8_BIT),
+                    FeatureSettings.of(CameraMode.DEFAULT, BIT_DEPTH_8_BIT, false),
                     it.surfaceConfigList
                 )
             ).isFalse()
@@ -244,7 +244,7 @@
         GuaranteedConfigurationsUtil.getFullSupportedCombinationList().forEach {
             assertThat(
                 supportedSurfaceCombination.checkSupported(
-                    FeatureSettings.of(CameraMode.DEFAULT, BIT_DEPTH_8_BIT),
+                    FeatureSettings.of(CameraMode.DEFAULT, BIT_DEPTH_8_BIT, false),
                     it.surfaceConfigList
                 )
             ).isFalse()
@@ -260,7 +260,7 @@
         GuaranteedConfigurationsUtil.getLevel3SupportedCombinationList().forEach {
             assertThat(
                 supportedSurfaceCombination.checkSupported(
-                    FeatureSettings.of(CameraMode.DEFAULT, BIT_DEPTH_8_BIT),
+                    FeatureSettings.of(CameraMode.DEFAULT, BIT_DEPTH_8_BIT, false),
                     it.surfaceConfigList
                 )
             ).isFalse()
@@ -278,7 +278,7 @@
         GuaranteedConfigurationsUtil.getLimitedSupportedCombinationList().forEach {
             assertThat(
                 supportedSurfaceCombination.checkSupported(
-                    FeatureSettings.of(CameraMode.DEFAULT, BIT_DEPTH_8_BIT),
+                    FeatureSettings.of(CameraMode.DEFAULT, BIT_DEPTH_8_BIT, false),
                     it.surfaceConfigList
                 )
             ).isTrue()
@@ -296,7 +296,7 @@
         GuaranteedConfigurationsUtil.getFullSupportedCombinationList().forEach {
             assertThat(
                 supportedSurfaceCombination.checkSupported(
-                    FeatureSettings.of(CameraMode.DEFAULT, BIT_DEPTH_8_BIT),
+                    FeatureSettings.of(CameraMode.DEFAULT, BIT_DEPTH_8_BIT, false),
                     it.surfaceConfigList
                 )
             ).isFalse()
@@ -314,7 +314,7 @@
         GuaranteedConfigurationsUtil.getLevel3SupportedCombinationList().forEach {
             assertThat(
                 supportedSurfaceCombination.checkSupported(
-                    FeatureSettings.of(CameraMode.DEFAULT, BIT_DEPTH_8_BIT),
+                    FeatureSettings.of(CameraMode.DEFAULT, BIT_DEPTH_8_BIT, false),
                     it.surfaceConfigList
                 )
             ).isFalse()
@@ -332,7 +332,7 @@
         GuaranteedConfigurationsUtil.getFullSupportedCombinationList().forEach {
             assertThat(
                 supportedSurfaceCombination.checkSupported(
-                    FeatureSettings.of(CameraMode.DEFAULT, BIT_DEPTH_8_BIT),
+                    FeatureSettings.of(CameraMode.DEFAULT, BIT_DEPTH_8_BIT, false),
                     it.surfaceConfigList
                 )
             ).isTrue()
@@ -350,7 +350,7 @@
         GuaranteedConfigurationsUtil.getLevel3SupportedCombinationList().forEach {
             assertThat(
                 supportedSurfaceCombination.checkSupported(
-                    FeatureSettings.of(CameraMode.DEFAULT, BIT_DEPTH_8_BIT),
+                    FeatureSettings.of(CameraMode.DEFAULT, BIT_DEPTH_8_BIT, false),
                     it.surfaceConfigList
                 )
             ).isFalse()
@@ -369,7 +369,7 @@
         GuaranteedConfigurationsUtil.getLimitedSupportedCombinationList().forEach {
             assertThat(
                 supportedSurfaceCombination.checkSupported(
-                    FeatureSettings.of(CameraMode.DEFAULT, BIT_DEPTH_8_BIT),
+                    FeatureSettings.of(CameraMode.DEFAULT, BIT_DEPTH_8_BIT, false),
                     it.surfaceConfigList
                 )
             ).isTrue()
@@ -388,7 +388,7 @@
         GuaranteedConfigurationsUtil.getLegacySupportedCombinationList().forEach {
             assertThat(
                 supportedSurfaceCombination.checkSupported(
-                    FeatureSettings.of(CameraMode.DEFAULT, BIT_DEPTH_8_BIT),
+                    FeatureSettings.of(CameraMode.DEFAULT, BIT_DEPTH_8_BIT, false),
                     it.surfaceConfigList
                 )
             ).isTrue()
@@ -407,7 +407,7 @@
         GuaranteedConfigurationsUtil.getFullSupportedCombinationList().forEach {
             assertThat(
                 supportedSurfaceCombination.checkSupported(
-                    FeatureSettings.of(CameraMode.DEFAULT, BIT_DEPTH_8_BIT),
+                    FeatureSettings.of(CameraMode.DEFAULT, BIT_DEPTH_8_BIT, false),
                     it.surfaceConfigList
                 )
             ).isTrue()
@@ -426,7 +426,7 @@
         GuaranteedConfigurationsUtil.getRAWSupportedCombinationList().forEach {
             assertThat(
                 supportedSurfaceCombination.checkSupported(
-                    FeatureSettings.of(CameraMode.DEFAULT, BIT_DEPTH_8_BIT),
+                    FeatureSettings.of(CameraMode.DEFAULT, BIT_DEPTH_8_BIT, false),
                     it.surfaceConfigList
                 )
             ).isTrue()
@@ -444,7 +444,7 @@
         GuaranteedConfigurationsUtil.getLevel3SupportedCombinationList().forEach {
             assertThat(
                 supportedSurfaceCombination.checkSupported(
-                    FeatureSettings.of(CameraMode.DEFAULT, BIT_DEPTH_8_BIT),
+                    FeatureSettings.of(CameraMode.DEFAULT, BIT_DEPTH_8_BIT, false),
                     it.surfaceConfigList
                 )
             ).isTrue()
@@ -465,7 +465,7 @@
         GuaranteedConfigurationsUtil.getConcurrentSupportedCombinationList().forEach {
             assertThat(
                 supportedSurfaceCombination.checkSupported(
-                    FeatureSettings.of(CameraMode.CONCURRENT_CAMERA, BIT_DEPTH_8_BIT),
+                    FeatureSettings.of(CameraMode.CONCURRENT_CAMERA, BIT_DEPTH_8_BIT, false),
                     it.surfaceConfigList
                 )
             ).isTrue()
@@ -490,7 +490,7 @@
             assertThat(
                 supportedSurfaceCombination.checkSupported(
                     FeatureSettings.of(
-                        CameraMode.ULTRA_HIGH_RESOLUTION_CAMERA, BIT_DEPTH_8_BIT
+                        CameraMode.ULTRA_HIGH_RESOLUTION_CAMERA, BIT_DEPTH_8_BIT, false
                     ),
                     it.surfaceConfigList
                 )
@@ -498,6 +498,25 @@
         }
     }
 
+    @Test
+    @Config(minSdk = Build.VERSION_CODES.TIRAMISU)
+    fun checkPreviewStabilizationSurfaceCombinationSupportedWhenEnabled() {
+        setupCameraAndInitCameraX(
+            hardwareLevel = CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_3
+        )
+        val supportedSurfaceCombination = SupportedSurfaceCombination(
+            context, DEFAULT_CAMERA_ID, cameraManagerCompat!!, mockCamcorderProfileHelper
+        )
+        GuaranteedConfigurationsUtil.getPreviewStabilizationSupportedCombinationList().forEach {
+            assertThat(
+                supportedSurfaceCombination.checkSupported(
+                    FeatureSettings.of(CameraMode.DEFAULT, BIT_DEPTH_8_BIT, true),
+                    it.surfaceConfigList
+                )
+            ).isTrue()
+        }
+    }
+
     // //////////////////////////////////////////////////////////////////////////////////////////
     //
     // Surface config transformation tests
@@ -1451,7 +1470,8 @@
         val resultPair = supportedSurfaceCombination.getSuggestedStreamSpecifications(
             cameraMode,
             attachedSurfaceInfoList,
-            useCaseConfigToOutputSizesMap
+            useCaseConfigToOutputSizesMap,
+            false
         )
         val suggestedStreamSpecsForNewUseCases = resultPair.first
         val suggestedStreamSpecsForOldSurfaces = resultPair.second
@@ -1564,7 +1584,7 @@
         GuaranteedConfigurationsUtil.get10BitSupportedCombinationList().forEach {
             assertThat(
                 supportedSurfaceCombination.checkSupported(
-                    FeatureSettings.of(CameraMode.DEFAULT, BIT_DEPTH_10_BIT),
+                    FeatureSettings.of(CameraMode.DEFAULT, BIT_DEPTH_10_BIT, false),
                     it.surfaceConfigList
                 )
             ).isTrue()
@@ -3327,6 +3347,19 @@
                 set(CameraCharacteristics.SCALER_AVAILABLE_STREAM_USE_CASES, uc)
             }
 
+            val vs: IntArray
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+                vs = intArrayOf(
+                    CameraCharacteristics.CONTROL_VIDEO_STABILIZATION_MODE_OFF,
+                    CameraCharacteristics.CONTROL_VIDEO_STABILIZATION_MODE_ON,
+                    CameraCharacteristics.CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION)
+            } else {
+                vs = intArrayOf(
+                    CameraCharacteristics.CONTROL_VIDEO_STABILIZATION_MODE_OFF,
+                    CameraCharacteristics.CONTROL_VIDEO_STABILIZATION_MODE_ON)
+            }
+            set(CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES, vs)
+
             capabilities?.let {
                 set(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES, it)
             }
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/CameraInfo.java b/camera/camera-core/src/main/java/androidx/camera/core/CameraInfo.java
index 105bde1..8c0750e 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/CameraInfo.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/CameraInfo.java
@@ -298,6 +298,26 @@
     }
 
     /**
+     * Returns if video stabilization is supported on the device.
+     *
+     * @return true if supported, otherwise false.
+     */
+    @RestrictTo(Scope.LIBRARY_GROUP)
+    default boolean isVideoStabilizationSupported() {
+        return false;
+    }
+
+    /**
+     * Returns if preview stabilization is supported on the device.
+     *
+     * @return true if supported, otherwise false.
+     */
+    @RestrictTo(Scope.LIBRARY_GROUP)
+    default boolean isPreviewStabilizationSupported() {
+        return false;
+    }
+
+    /**
      * Returns if {@link ImageFormat#PRIVATE} reprocessing is supported on the device.
      *
      * @return true if supported, otherwise false.
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/impl/CameraDeviceSurfaceManager.java b/camera/camera-core/src/main/java/androidx/camera/core/impl/CameraDeviceSurfaceManager.java
index 9abb314..540f454 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/impl/CameraDeviceSurfaceManager.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/impl/CameraDeviceSurfaceManager.java
@@ -83,6 +83,7 @@
      * @param newUseCaseConfigsSupportedSizeMap map of configurations of the use cases to the
      *                                          supported output sizes list that will be given a
      *                                          suggested stream specification
+     * @param isPreviewStabilizationOn          whether the preview stabilization is enabled.
      * @return map of suggested stream specifications for given use cases
      * @throws IllegalStateException    if not initialized
      * @throws IllegalArgumentException if {@code newUseCaseConfigs} is an empty list, if
@@ -96,5 +97,6 @@
             @CameraMode.Mode int cameraMode,
             @NonNull String cameraId,
             @NonNull List<AttachedSurfaceInfo> existingSurfaces,
-            @NonNull Map<UseCaseConfig<?>, List<Size>> newUseCaseConfigsSupportedSizeMap);
+            @NonNull Map<UseCaseConfig<?>, List<Size>> newUseCaseConfigsSupportedSizeMap,
+            boolean isPreviewStabilizationOn);
 }
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/impl/Config.java b/camera/camera-core/src/main/java/androidx/camera/core/impl/Config.java
index ab1314e..be3b3b8 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/impl/Config.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/impl/Config.java
@@ -46,8 +46,8 @@
      * Returns whether this configuration contains the supplied option.
      *
      * @param id The {@link Option} to search for in this configuration.
-     * @return <code>true</code> if this configuration contains the supplied option; <code>false
-     * </code> otherwise.
+     * @return {@code true} if this configuration contains the supplied option; {@code false}
+     * otherwise.
      */
     boolean containsOption(@NonNull Option<?> id);
 
@@ -77,7 +77,7 @@
      * @param valueIfMissing The value to return if the specified {@link Option} does not exist in
      *                       this configuration.
      * @param <ValueT>       The type for the value associated with the supplied {@link Option}.
-     * @return The value stored in this configuration, or <code>valueIfMissing</code> if it does
+     * @return The value stored in this configuration, or {@code valueIfMissing} if it does
      * not exist.
      */
     @Nullable
@@ -116,12 +116,10 @@
      *                       option such as \"<code>
      *                       camerax.core.example</code>\".
      * @param matcher        A callback used to receive results of the search. Results will be
-     *                       sent to
-     *                       {@link OptionMatcher#onOptionMatched(Option)} in the order in which
-     *                       they are found inside
-     *                       this configuration. Subsequent results will continue to be sent as
-     *                       long as {@link
-     *                       OptionMatcher#onOptionMatched(Option)} returns <code>true</code>.
+     *                       sent to {@link OptionMatcher#onOptionMatched(Option)} in the order
+     *                       in which they are found inside this configuration. Subsequent
+     *                       results will continue to be sent as long as {@link
+     *                       OptionMatcher#onOptionMatched(Option)} returns {@code true}.
      */
     void findOptions(@NonNull String idSearchString, @NonNull OptionMatcher matcher);
 
@@ -199,8 +197,7 @@
          * @param valueClass The class of the value stored by this option.
          * @param <T>        The type of the value stored by this option.
          * @param token      An optional, type-erased object for storing more context for this
-         *                   specific
-         *                   option. Generally this object should have static scope and be
+         *                   specific option. Generally this object should have static scope and be
          *                   immutable.
          * @return An {@link Option} object which can be used to store/retrieve values from a {@link
          * Config}.
@@ -250,11 +247,14 @@
      */
     enum OptionPriority {
         /**
-         * Should only be used externally by apps. It takes precedence over any other option
-         * values at the risk of causing unexpected behavior.
+         * It takes precedence over any other option values at the risk of causing unexpected
+         * behavior.
          *
-         * <p>This should not used internally in CameraX. It conflicts when merging different
-         * values set to ALWAY_OVERRIDE.
+         * <p>If the same option is already set, the option with this priority will overwrite the
+         * value.
+         *
+         * <p>This priority should only be used to explicitly specify an option, such as used by
+         * {@code Camera2Interop} or {@code Camera2CameraControl}, and should be used with caution.
          */
         ALWAYS_OVERRIDE,
 
@@ -262,15 +262,17 @@
          * It's a required option value in order to achieve expected CameraX behavior. It takes
          * precedence over {@link #OPTIONAL} option values.
          *
-         * <p>If apps set ALWAYS_OVERRIDE options, it'll override REQUIRED option values and can
-         * potentially cause unexpected behaviors. It conflicts when merging different values set
-         * to REQUIRED.
+         * <p>If two values are set to the same option, the value with {@link #ALWAYS_OVERRIDE}
+         * priority will overwrite this priority and can potentially cause unexpected behaviors.
+         *
+         * <p>If two values are set to the same option with this priority, it might indicate a
+         * programming error internally and an exception will be thrown when merging the configs.
          */
         REQUIRED,
 
         /**
          * The lowest priority, it can be overridden by any other option value. When two option
-         * values are set as OPTIONAL, the newer value takes precedence over the old one.
+         * values are set with this priority, the newer value takes precedence over the old one.
          */
         OPTIONAL
     }
@@ -278,35 +280,25 @@
     /**
      * Returns if values with these {@link OptionPriority} conflict or not.
      *
-     * Currently it is not allowed to have different values with same ALWAYS_OVERRIDE
-     * priority or to have different values with same REQUIRED priority.
+     * <p>Currently it is not allowed the same option to have different values with priority
+     * {@link OptionPriority#REQUIRED}.
      */
     static boolean hasConflict(@NonNull OptionPriority priority1,
             @NonNull OptionPriority priority2) {
-        if (priority1 == OptionPriority.ALWAYS_OVERRIDE
-                && priority2 == OptionPriority.ALWAYS_OVERRIDE) {
-            return true;
-        }
-
-        if (priority1 == OptionPriority.REQUIRED
-                && priority2 == OptionPriority.REQUIRED) {
-            return true;
-        }
-
-        return false;
+        return priority1 == OptionPriority.REQUIRED
+                && priority2 == OptionPriority.REQUIRED;
     }
 
     /**
-     * Merges two configs
+     * Merges two configs.
      *
      * @param extendedConfig the extended config. The options in the extendedConfig will be applied
      *                       on top of the baseConfig based on the option priorities.
-     * @param baseConfig the base config
-     * @return a {@link MutableOptionsBundle} of the merged config
+     * @param baseConfig the base config.
+     * @return a {@link MutableOptionsBundle} of the merged config.
      */
     @NonNull
-    static Config mergeConfigs(@Nullable Config extendedConfig,
-            @Nullable Config baseConfig) {
+    static Config mergeConfigs(@Nullable Config extendedConfig, @Nullable Config baseConfig) {
         if (extendedConfig == null && baseConfig == null) {
             return OptionsBundle.emptyBundle();
         }
@@ -333,12 +325,12 @@
     /**
      * Merges a specific option value from two configs.
      *
-     * @param mergedConfig   the final output config
+     * @param mergedConfig   the final output config.
      * @param baseConfig     the base config contains the option value which might be overridden by
      *                       the corresponding option value in the extend config.
      * @param extendedConfig the extended config contains the option value which might override
      *                       the corresponding option value in the base config.
-     * @param opt            the option to merge
+     * @param opt            the option to merge.
      */
     static void mergeOptionValue(@NonNull MutableOptionsBundle mergedConfig,
             @NonNull Config baseConfig,
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/internal/CameraUseCaseAdapter.java b/camera/camera-core/src/main/java/androidx/camera/core/internal/CameraUseCaseAdapter.java
index eff1afc..e998934 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/internal/CameraUseCaseAdapter.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/internal/CameraUseCaseAdapter.java
@@ -25,7 +25,6 @@
 import static androidx.camera.core.streamsharing.StreamSharing.isStreamSharing;
 import static androidx.core.util.Preconditions.checkArgument;
 import static androidx.core.util.Preconditions.checkState;
-
 import static java.util.Collections.emptyList;
 import static java.util.Objects.requireNonNull;
 
@@ -677,6 +676,7 @@
             SupportedOutputSizesSorter supportedOutputSizesSorter = new SupportedOutputSizesSorter(
                     cameraInfoInternal,
                     sensorRect != null ? rectToSize(sensorRect) : null);
+            boolean isPreviewStabilizationOn = false;
             for (UseCase useCase : newUseCases) {
                 ConfigPair configPair = configPairMap.get(useCase);
                 // Combine with default configuration.
@@ -687,6 +687,9 @@
                 configToSupportedSizesMap.put(combinedUseCaseConfig,
                         supportedOutputSizesSorter.getSortedSupportedOutputSizes(
                                 combinedUseCaseConfig));
+
+                // TODO(kailianc): extract the use case's video stabilization settings  and set
+                //  to isPreviewStabilizationOn
             }
 
             // Get suggested stream specifications and update the use case session configuration
@@ -695,7 +698,8 @@
                     mCameraDeviceSurfaceManager.getSuggestedStreamSpecs(
                             cameraMode,
                             cameraId, existingSurfaces,
-                            configToSupportedSizesMap);
+                            configToSupportedSizesMap,
+                            isPreviewStabilizationOn);
 
             for (Map.Entry<UseCaseConfig<?>, UseCase> entry : configToUseCaseMap.entrySet()) {
                 suggestedStreamSpecs.put(entry.getValue(),
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/internal/compat/quirk/LargeJpegImageQuirk.java b/camera/camera-core/src/main/java/androidx/camera/core/internal/compat/quirk/LargeJpegImageQuirk.java
index c6ad529..471095e 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/internal/compat/quirk/LargeJpegImageQuirk.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/internal/compat/quirk/LargeJpegImageQuirk.java
@@ -28,16 +28,16 @@
 
 /**
  * <p>QuirkSummary
- *     Bug Id: 288828159
+ *     Bug Id: 288828159, 299069235
  *     Description: Quirk required to check whether the captured JPEG image contains redundant
  *                  0's padding data. For example, Samsung A5 (2017) series devices have the
  *                  problem and result in the output JPEG image to be extremely large (about 32 MB).
- *     Device(s): Samsung Galaxy A5 (2017), A52, A70, A72 and S7 series devices
+ *     Device(s): Samsung Galaxy A5 (2017), A52, A70, A72, S7 series devices and Vivo S16 device
  */
 @RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
 public final class LargeJpegImageQuirk implements Quirk {
 
-    private static final Set<String> DEVICE_MODELS = new HashSet<>(Arrays.asList(
+    private static final Set<String> SAMSUNG_DEVICE_MODELS = new HashSet<>(Arrays.asList(
             // Samsung Galaxy A5 series devices
             "SM-A520F",
             "SM-A520L",
@@ -70,7 +70,22 @@
             "SM-S906B"
     ));
 
+    private static final Set<String> VIVO_DEVICE_MODELS = new HashSet<>(Arrays.asList(
+            // Vivo S16
+            "V2244A"
+    ));
+
     static boolean load() {
-        return DEVICE_MODELS.contains(Build.MODEL.toUpperCase(Locale.US));
+        return isSamsungProblematicDevice() || isVivoProblematicDevice();
+    }
+
+    private static boolean isSamsungProblematicDevice() {
+        return "Samsung".equalsIgnoreCase(Build.BRAND) && SAMSUNG_DEVICE_MODELS.contains(
+                Build.MODEL.toUpperCase(Locale.US));
+    }
+
+    private static boolean isVivoProblematicDevice() {
+        return "Vivo".equalsIgnoreCase(Build.BRAND) && VIVO_DEVICE_MODELS.contains(
+                Build.MODEL.toUpperCase(Locale.US));
     }
 }
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/internal/compat/workaround/InvalidJpegDataParser.java b/camera/camera-core/src/main/java/androidx/camera/core/internal/compat/workaround/InvalidJpegDataParser.java
index a9b122a..4a0d527 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/internal/compat/workaround/InvalidJpegDataParser.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/internal/compat/workaround/InvalidJpegDataParser.java
@@ -18,6 +18,7 @@
 
 import androidx.annotation.NonNull;
 import androidx.annotation.RequiresApi;
+import androidx.annotation.VisibleForTesting;
 import androidx.camera.core.internal.compat.quirk.DeviceQuirks;
 import androidx.camera.core.internal.compat.quirk.LargeJpegImageQuirk;
 
@@ -41,12 +42,23 @@
             return bytes.length;
         }
 
+        int jfifEoiMarkEndPosition = getJfifEoiMarkEndPosition(bytes);
+
+        return jfifEoiMarkEndPosition != -1 ? jfifEoiMarkEndPosition : bytes.length;
+    }
+
+    /**
+     * Returns the end position of JFIF EOI mark. Returns -1 while JFIF EOI mark can't be found
+     * in the provided byte array.
+     */
+    @VisibleForTesting
+    public static int getJfifEoiMarkEndPosition(@NonNull byte[] bytes) {
         // Parses the JFIF segments from the start of the JPEG image data
         int markPosition = 0x2;
         while (true) {
             // Breaks the while-loop and return null if the mark byte can't be correctly found.
             if (markPosition + 4 > bytes.length || bytes[markPosition] != ((byte) 0xff)) {
-                return bytes.length;
+                return -1;
             }
 
             int segmentLength =
@@ -65,7 +77,7 @@
         while (true) {
             // Breaks the while-loop and return null if EOI mark can't be found
             if (eoiPosition + 2 > bytes.length) {
-                return bytes.length;
+                return -1;
             }
 
             if (bytes[eoiPosition] == ((byte) 0xff) && bytes[eoiPosition + 1] == ((byte) 0xd9)) {
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/impl/ConfigTest.java b/camera/camera-core/src/test/java/androidx/camera/core/impl/ConfigTest.java
index 96b086a..e78d689f 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/impl/ConfigTest.java
+++ b/camera/camera-core/src/test/java/androidx/camera/core/impl/ConfigTest.java
@@ -89,8 +89,8 @@
     }
 
     @Test
-    public void hasConflict_whenTwoValueAreALWAYSOVERRIDE() {
-        assertThat(Config.hasConflict(ALWAYS_OVERRIDE, ALWAYS_OVERRIDE)).isTrue();
+    public void noConflict_whenTwoValueAreALWAYSOVERRIDE() {
+        assertThat(Config.hasConflict(ALWAYS_OVERRIDE, ALWAYS_OVERRIDE)).isFalse();
     }
 
     @Test
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/impl/MutableOptionsBundleTest.java b/camera/camera-core/src/test/java/androidx/camera/core/impl/MutableOptionsBundleTest.java
index 1db4883..be0e91c 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/impl/MutableOptionsBundleTest.java
+++ b/camera/camera-core/src/test/java/androidx/camera/core/impl/MutableOptionsBundleTest.java
@@ -108,13 +108,18 @@
         assertThat(config2.retrieveOptionWithPriority(OPTION_2, OPTIONAL)).isEqualTo(VALUE_1);
     }
 
-    @Test(expected = IllegalArgumentException.class)
+    @Test
     public void insertOption_ALWAYSOVERRIDE_ALWAYSOVERRIDE() {
         MutableOptionsBundle mutOpts = MutableOptionsBundle.create();
 
         mutOpts.insertOption(OPTION_1, ALWAYS_OVERRIDE, VALUE_1);
-        // should throw an Error
         mutOpts.insertOption(OPTION_1, ALWAYS_OVERRIDE, VALUE_2);
+
+        assertThat(mutOpts.retrieveOption(OPTION_1)).isEqualTo(VALUE_2);
+        Config.OptionPriority highestPriority = Collections.min(mutOpts.getPriorities(OPTION_1));
+        assertThat(highestPriority).isEqualTo(ALWAYS_OVERRIDE);
+        assertThat(mutOpts.retrieveOptionWithPriority(OPTION_1, highestPriority))
+                .isEqualTo(VALUE_2);
     }
 
     @Test
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/internal/compat/workaround/InvalidJpegDataParserTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/internal/compat/workaround/InvalidJpegDataParserTest.kt
index cdd2576..127b136 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/internal/compat/workaround/InvalidJpegDataParserTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/internal/compat/workaround/InvalidJpegDataParserTest.kt
@@ -73,31 +73,34 @@
 @DoNotInstrument
 @Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
 class InvalidJpegDataParserTest(
+    private val brand: String,
     private val model: String,
     private val data: ByteArray,
     private val validDataLength: Int,
-    ) {
+) {
 
     companion object {
         @JvmStatic
-        @ParameterizedRobolectricTestRunner.Parameters(name = "model={0}, data={1}, length={2}")
+        @ParameterizedRobolectricTestRunner.Parameters(
+            name = "brand={0}, model={1}, data={2}, length={3}")
         fun data() = mutableListOf<Array<Any?>>().apply {
-            add(arrayOf("SM-A520F", problematicJpegByteArray, 18))
-            add(arrayOf("SM-A520F", problematicJpegByteArray2, 18))
-            add(arrayOf("SM-A520F", correctJpegByteArray1, 18))
-            add(arrayOf("SM-A520F", correctJpegByteArray2, 18))
-            add(arrayOf("SM-A520F", invalidVeryShortData, 2))
-            add(arrayOf("SM-A520F", invalidNoSosData, 28))
-            add(arrayOf("SM-A520F", invalidNoEoiData, 28))
-            add(arrayOf("fake-model", problematicJpegByteArray, 42))
-            add(arrayOf("fake-model", problematicJpegByteArray2, 64))
-            add(arrayOf("fake-model", correctJpegByteArray1, 28))
-            add(arrayOf("fake-model", correctJpegByteArray2, 18))
+            add(arrayOf("SAMSUNG", "SM-A520F", problematicJpegByteArray, 18))
+            add(arrayOf("SAMSUNG", "SM-A520F", problematicJpegByteArray2, 18))
+            add(arrayOf("SAMSUNG", "SM-A520F", correctJpegByteArray1, 18))
+            add(arrayOf("SAMSUNG", "SM-A520F", correctJpegByteArray2, 18))
+            add(arrayOf("SAMSUNG", "SM-A520F", invalidVeryShortData, 2))
+            add(arrayOf("SAMSUNG", "SM-A520F", invalidNoSosData, 28))
+            add(arrayOf("SAMSUNG", "SM-A520F", invalidNoEoiData, 28))
+            add(arrayOf("fake-brand", "fake-model", problematicJpegByteArray, 42))
+            add(arrayOf("fake-brand", "fake-model", problematicJpegByteArray2, 64))
+            add(arrayOf("fake-brand", "fake-model", correctJpegByteArray1, 28))
+            add(arrayOf("fake-brand", "fake-model", correctJpegByteArray2, 18))
         }
     }
 
     @Test
     fun canGetValidJpegDataLength() {
+        ReflectionHelpers.setStaticField(Build::class.java, "BRAND", brand)
         ReflectionHelpers.setStaticField(Build::class.java, "MODEL", model)
         assertThat(InvalidJpegDataParser().getValidDataLength(data)).isEqualTo(validDataLength)
     }
diff --git a/camera/camera-effects/src/androidTest/java/androidx/camera/effects/internal/SurfaceProcessorImplDeviceTest.kt b/camera/camera-effects/src/androidTest/java/androidx/camera/effects/internal/SurfaceProcessorImplDeviceTest.kt
index 5360c0e..e1c03b6 100644
--- a/camera/camera-effects/src/androidTest/java/androidx/camera/effects/internal/SurfaceProcessorImplDeviceTest.kt
+++ b/camera/camera-effects/src/androidTest/java/androidx/camera/effects/internal/SurfaceProcessorImplDeviceTest.kt
@@ -16,6 +16,9 @@
 
 package androidx.camera.effects.internal
 
+import android.graphics.Color
+import android.graphics.Matrix
+import android.graphics.Rect
 import android.graphics.SurfaceTexture
 import android.util.Size
 import android.view.Surface
@@ -23,7 +26,11 @@
 import androidx.camera.core.CameraEffect.VIDEO_CAPTURE
 import androidx.camera.core.SurfaceOutput
 import androidx.camera.core.SurfaceRequest
+import androidx.camera.core.SurfaceRequest.TransformationInfo
+import androidx.camera.core.impl.utils.TransformUtils.sizeToRect
+import androidx.camera.effects.Frame
 import androidx.camera.testing.fakes.FakeCamera
+import androidx.camera.testing.impl.TestImageUtil.getAverageDiff
 import androidx.core.util.Consumer
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SdkSuppress
@@ -49,12 +56,19 @@
 class SurfaceProcessorImplDeviceTest {
 
     companion object {
-        private val SIZE = Size(640, 480)
+        private const val ROTATION_DEGREES = 90
+        private val TRANSFORM = Matrix().apply {
+            postRotate(90F)
+        }
+        private const val INPUT_COLOR = Color.GREEN
+        private const val OVERLAY_COLOR = Color.RED
 
         // The timeout is set to 200ms to qualify for @SmallTest.
         private const val TIMEOUT_MILLIS = 200L
     }
 
+    private val size = Size(640, 480)
+    private val cropRect = sizeToRect(size)
     private lateinit var surfaceRequest: SurfaceRequest
     private lateinit var outputTexture: SurfaceTexture
     private lateinit var outputSurface: Surface
@@ -63,18 +77,28 @@
     private lateinit var surfaceOutput: SurfaceOutput
     private lateinit var surfaceOutput2: SurfaceOutput
     private lateinit var processor: SurfaceProcessorImpl
+    private lateinit var transformationInfo: TransformationInfo
 
     @Before
     fun setUp() {
-        surfaceRequest = SurfaceRequest(SIZE, FakeCamera()) {}
+        transformationInfo = TransformationInfo.of(
+            cropRect,
+            ROTATION_DEGREES,
+            Surface.ROTATION_90,
+            true,
+            TRANSFORM,
+            true
+        )
+        surfaceRequest = SurfaceRequest(size, FakeCamera()) {}
+        surfaceRequest.updateTransformationInfo(transformationInfo)
         outputTexture = SurfaceTexture(0)
         outputTexture.detachFromGLContext()
         outputSurface = Surface(outputTexture)
         outputTexture2 = SurfaceTexture(1)
         outputTexture2.detachFromGLContext()
         outputSurface2 = Surface(outputTexture2)
-        surfaceOutput = SurfaceOutputImpl(outputSurface)
-        surfaceOutput2 = SurfaceOutputImpl(outputSurface2)
+        surfaceOutput = SurfaceOutputImpl(outputSurface, size)
+        surfaceOutput2 = SurfaceOutputImpl(outputSurface2, size)
     }
 
     @After
@@ -89,6 +113,65 @@
     }
 
     @Test
+    fun onDrawListenerReturnsFalse_notDrawnToOutput() = runBlocking {
+        // Act: return false in the on draw listener.
+        val latch = fillFramesAndWaitForOutput(0, 1) {
+            it.setOnDrawListener { false }
+        }
+        // Assert: output is not drawn.
+        assertThat(latch.await(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isFalse()
+    }
+
+    @Test
+    fun onDrawListener_receivesTransformationInfo() = runBlocking {
+        // Arrange.
+        var frameReceived: Frame? = null
+        // Act: fill frames and wait draw frame listener.
+        val latch = fillFramesAndWaitForOutput(0, 1) { processor ->
+            processor.setOnDrawListener { frame ->
+                frameReceived = frame
+                true
+            }
+        }
+        // Assert: draw frame listener receives correct transformation info.
+        assertThat(latch.await(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue()
+        assertThat(frameReceived!!.size).isEqualTo(size)
+        assertThat(frameReceived!!.cropRect).isEqualTo(transformationInfo.cropRect)
+        assertThat(frameReceived!!.getMirroring()).isEqualTo(transformationInfo.mirroring)
+        assertThat(frameReceived!!.sensorToBufferTransform)
+            .isEqualTo(transformationInfo.sensorToBufferTransform)
+        assertThat(frameReceived!!.rotationDegrees).isEqualTo(ROTATION_DEGREES)
+    }
+
+    @Test
+    fun canvasInvalidated_overlayDrawnToOutput(): Unit = runBlocking {
+        val latch = fillFramesAndWaitForOutput(0, 1) { processor ->
+            processor.setOnDrawListener { frame ->
+                // Act: invalidate overlay canvas and draw color.
+                frame.invalidateOverlayCanvas().drawColor(OVERLAY_COLOR)
+                true
+            }
+        }
+        // Assert: output receives frame with overlay color.
+        assertThat(latch.await(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue()
+        assertOutputColor(OVERLAY_COLOR)
+    }
+
+    @Test
+    fun canvasNotInvalidated_overlayNotDrawnToOutput() = runBlocking {
+        val latch = fillFramesAndWaitForOutput(0, 1) { processor ->
+            processor.setOnDrawListener { frame ->
+                // Act: draw color on overlay canvas without invalidating.
+                frame.overlayCanvas.drawColor(OVERLAY_COLOR)
+                true
+            }
+        }
+        // Assert: output receives frame with input color
+        assertThat(latch.await(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue()
+        assertOutputColor(INPUT_COLOR)
+    }
+
+    @Test
     fun zeroQueueDepth_inputDrawnToOutput() = runBlocking {
         // Assert: output receives frame when queue depth == 0.
         val latch = fillFramesAndWaitForOutput(0, 1)
@@ -122,10 +205,7 @@
 
         // Act: replace output surface so the cached frame is no longer valid. The cached frame
         // should be marked empty and not blocking the pipeline.
-        val countDownLatch = CountDownLatch(1)
-        outputTexture2.setOnFrameAvailableListener {
-            countDownLatch.countDown()
-        }
+        val countDownLatch = getTextureUpdateLatch(outputTexture2)
         withContext(processor.glExecutor.asCoroutineDispatcher()) {
             processor.onOutputSurface(surfaceOutput2)
         }
@@ -138,6 +218,25 @@
     }
 
     /**
+     * Renders the input surface to a bitmap and asserts that the color of the bitmap.
+     */
+    private suspend fun assertOutputColor(color: Int) {
+        val matrix = FloatArray(16)
+        android.opengl.Matrix.setIdentityM(matrix, 0)
+        withContext(processor.glExecutor.asCoroutineDispatcher()) {
+            val bitmap = processor.glRendererForTesting
+                .renderInputToBitmap(size.width, size.height, matrix)
+            assertThat(
+                getAverageDiff(
+                    bitmap,
+                    Rect(0, 0, size.width, size.height),
+                    color
+                )
+            ).isEqualTo(0)
+        }
+    }
+
+    /**
      * Creates a processor and draws frames to the input surface.
      *
      * @param queueDepth The queue depth of the processor.
@@ -146,18 +245,17 @@
      */
     private suspend fun fillFramesAndWaitForOutput(
         queueDepth: Int,
-        frameCount: Int
+        frameCount: Int,
+        configureProcessor: (SurfaceProcessorImpl) -> Unit = {},
     ): CountDownLatch {
         // Arrange: Create a processor.
         processor = SurfaceProcessorImpl(queueDepth)
+        configureProcessor(processor)
         withContext(processor.glExecutor.asCoroutineDispatcher()) {
             processor.onInputSurface(surfaceRequest)
             processor.onOutputSurface(surfaceOutput)
         }
-        val countDownLatch = CountDownLatch(1)
-        outputTexture.setOnFrameAvailableListener {
-            countDownLatch.countDown()
-        }
+        val countDownLatch = getTextureUpdateLatch(outputTexture)
 
         // Act: Draw frames to the input surface.
         val inputSurface = surfaceRequest.deferrableSurface.surface.get()
@@ -174,6 +272,7 @@
      */
     private suspend fun drawSurface(surface: Surface) {
         val canvas = surface.lockCanvas(null)
+        canvas.drawColor(INPUT_COLOR)
         surface.unlockCanvasAndPost(canvas)
         // Drain the GL thread to ensure the processor caches or draws the frame. Otherwise, the
         // input SurfaceTexture's onSurfaceAvailable callback may only get called once for
@@ -182,7 +281,16 @@
         }
     }
 
-    private class SurfaceOutputImpl(private val surface: Surface) : SurfaceOutput {
+    private fun getTextureUpdateLatch(surfaceTexture: SurfaceTexture): CountDownLatch {
+        val countDownLatch = CountDownLatch(1)
+        surfaceTexture.setOnFrameAvailableListener {
+            countDownLatch.countDown()
+        }
+        return countDownLatch
+    }
+
+    private class SurfaceOutputImpl(private val surface: Surface, val surfaceSize: Size) :
+        SurfaceOutput {
 
         override fun close() {
         }
@@ -199,7 +307,7 @@
         }
 
         override fun getSize(): Size {
-            return SIZE
+            return surfaceSize
         }
 
         override fun updateTransformMatrix(updated: FloatArray, original: FloatArray) {
diff --git a/camera/camera-effects/src/main/java/androidx/camera/effects/Frame.java b/camera/camera-effects/src/main/java/androidx/camera/effects/Frame.java
new file mode 100644
index 0000000..ee6b8a9
--- /dev/null
+++ b/camera/camera-effects/src/main/java/androidx/camera/effects/Frame.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2023 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.effects;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Rect;
+import android.graphics.SurfaceTexture;
+import android.hardware.camera2.CameraCharacteristics;
+import android.util.Size;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+import androidx.annotation.RestrictTo;
+import androidx.camera.core.ImageInfo;
+import androidx.camera.core.SurfaceRequest;
+
+import com.google.auto.value.AutoValue;
+
+/**
+ * Represents a frame that will be rendered next.
+ *
+ * <p>This class can be used to overlay graphics or data on camera output. It contains
+ * information for drawing an overlay, including sensor-to-buffer transform, size, crop rect,
+ * rotation, mirroring, and timestamp. It also provides a {@link Canvas} for the drawing.
+ *
+ * TODO(b/297509601): Make it public API in 1.4.
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+@RequiresApi(21)
+@AutoValue
+public abstract class Frame {
+
+    private boolean mIsOverlayDirty = false;
+
+    /**
+     * Internal API to create a frame.
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    @NonNull
+    public static Frame of(
+            @NonNull Canvas overlayCanvas,
+            long timestampNs,
+            @NonNull Size size,
+            @NonNull SurfaceRequest.TransformationInfo transformationInfo) {
+        return new AutoValue_Frame(transformationInfo.getSensorToBufferTransform(), size,
+                transformationInfo.getCropRect(), transformationInfo.getRotationDegrees(),
+                transformationInfo.getMirroring(), timestampNs, overlayCanvas);
+    }
+
+    /**
+     * Returns the sensor to image buffer transform matrix.
+     *
+     * <p>The value is a mapping from sensor coordinates to buffer coordinates, which is,
+     * from the rect of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE} to the
+     * rect defined by {@code (0, 0, #getSize()#getWidth(), #getSize()#getHeight())}.
+     *
+     * <p>The value can be set on the {@link Canvas} using {@link Canvas#setMatrix} API. This
+     * transforms the {@link Canvas} to the sensor coordinate system.
+     *
+     * @see SurfaceRequest.TransformationInfo#getSensorToBufferTransform()
+     */
+    @NonNull
+    public abstract Matrix getSensorToBufferTransform();
+
+    /**
+     * Returns the resolution of the frame.
+     *
+     * @see SurfaceRequest#getResolution()
+     */
+    @NonNull
+    public abstract Size getSize();
+
+    /**
+     * Returns the crop rect rectangle.
+     *
+     * <p>The value represents how the frame will be cropped by the CameraX pipeline. The crop
+     * rectangle specifies the region of valid pixels in the frame, using coordinates from (0, 0)
+     * to the (width, height) of {@link #getSize()}. Only the overlay drawn within the bound of
+     * the crop rect will be visible to the end users.
+     *
+     * <p>The crop rect is applied before the rotating and mirroring. The order of the operations
+     * is as follows: 1) cropping, 2) rotating and 3) mirroring.
+     *
+     * @see SurfaceRequest.TransformationInfo#getCropRect()
+     */
+    @NonNull
+    public abstract Rect getCropRect();
+
+    /**
+     * Returns the rotation degrees of the frame.
+     *
+     * <p>This is a clockwise rotation in degrees that needs to be applied to the frame. The
+     * rotation will be determined by {@link CameraCharacteristics} and UseCase configuration.
+     * The app must draw the overlay according to the rotation degrees to ensure it is
+     * displayed correctly to the end users.
+     *
+     * <p>The rotation is applied after the cropping but before the mirroring. The order of the
+     * operations is as follows: 1) cropping, 2) rotating and 3) mirroring.
+     *
+     * @see SurfaceRequest.TransformationInfo#getRotationDegrees()
+     */
+    public abstract int getRotationDegrees();
+
+    /**
+     * Returns whether the buffer will be mirrored.
+     *
+     * <p>This flag indicates whether the buffer will be mirrored by the pipeline vertically. For
+     * example, for front camera preview, the buffer is usually mirrored before displayed to end
+     * users.
+     *
+     * <p>The mirroring is applied after the cropping and the rotating. The order of the
+     * operations is as follows: 1) cropping, 2) rotating and 3) mirroring.
+     *
+     * @see SurfaceRequest.TransformationInfo#getMirroring()
+     */
+    public abstract boolean getMirroring();
+
+    /**
+     * Returns the timestamp of the frame in nanoseconds.
+     *
+     * @see SurfaceTexture#getTimestamp()
+     * @see ImageInfo#getTimestamp()
+     */
+    public abstract long getTimestampNs();
+
+    /**
+     * Invalidates and returns the overlay canvas.
+     *
+     * <p>Call this method to get the {@link Canvas} for drawing an overlay on top of the frame.
+     * The {@link Canvas} is backed by a {@link Bitmap} with the sizes equals {@link #getSize()} and
+     * the format equals {@link Bitmap.Config#ARGB_8888}. To draw object in camera sensor
+     * coordinates, apply {@link #getSensorToBufferTransform()} via
+     * {@link Canvas#setMatrix(Matrix)} before drawing.
+     *
+     * <p>Only call this method if the caller needs to draw overlay on the frame. Calling this
+     * method will upload the {@link Bitmap} to GPU for blending.
+     */
+    @NonNull
+    public Canvas invalidateOverlayCanvas() {
+        mIsOverlayDirty = true;
+        return getOverlayCanvas();
+    }
+
+    /**
+     * Internal API to check whether the overlay canvas is dirty.
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    public boolean isOverlayDirty() {
+        return mIsOverlayDirty;
+    }
+
+
+    /**
+     * Internal API to get the overlay canvas without invalidating it.
+     */
+    @NonNull
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    public abstract Canvas getOverlayCanvas();
+}
diff --git a/camera/camera-effects/src/main/java/androidx/camera/effects/internal/SurfaceProcessorImpl.java b/camera/camera-effects/src/main/java/androidx/camera/effects/internal/SurfaceProcessorImpl.java
index aaaaec1..2c8ec15 100644
--- a/camera/camera-effects/src/main/java/androidx/camera/effects/internal/SurfaceProcessorImpl.java
+++ b/camera/camera-effects/src/main/java/androidx/camera/effects/internal/SurfaceProcessorImpl.java
@@ -33,10 +33,13 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
+import androidx.annotation.VisibleForTesting;
+import androidx.arch.core.util.Function;
 import androidx.camera.core.SurfaceOutput;
 import androidx.camera.core.SurfaceProcessor;
 import androidx.camera.core.SurfaceRequest;
 import androidx.camera.core.impl.utils.executor.CameraXExecutors;
+import androidx.camera.effects.Frame;
 import androidx.camera.effects.opengl.GlRenderer;
 import androidx.core.util.Pair;
 
@@ -77,6 +80,10 @@
     private Canvas mOverlayCanvas;
     @Nullable
     private Pair<SurfaceOutput, Surface> mOutputSurfacePair = null;
+    @Nullable
+    private SurfaceRequest.TransformationInfo mTransformationInfo = null;
+    @Nullable
+    private Function<Frame, Boolean> mOnDrawListener;
 
     private boolean mIsReleased = false;
 
@@ -110,6 +117,11 @@
         });
         surfaceTexture.setOnFrameAvailableListener(this, mGlHandler);
 
+        // Listen for transformation updates.
+        mTransformationInfo = null;
+        surfaceRequest.setTransformationInfoListener(mGlExecutor, transformationInfo ->
+                mTransformationInfo = transformationInfo);
+
         // Configure buffers based on the input size.
         createBufferAndOverlay(surfaceRequest.getResolution());
     }
@@ -209,6 +221,20 @@
         return mGlExecutor;
     }
 
+    /**
+     * Sets the listener that listens to frame updates and draws overlay.
+     *
+     * <p>CameraX invokes this {@link Function} on the GL thread each time a frame is drawn. The
+     * caller can use implement the {@link Function} to draw overlay on the frame.
+     *
+     * <p>The {@link Function} accepts a {@link Frame} object which provides information on how to
+     * draw the overlay. The return value of the {@link Function} indicates whether the frame
+     * should be drawn. If false, the frame will be dropped.
+     */
+    public void setOnDrawListener(@Nullable Function<Frame, Boolean> onDrawListener) {
+        runOnGlThread(() -> mOnDrawListener = onDrawListener);
+    }
+
     // *** Private methods ***
 
     private void runOnGlThread(@NonNull Runnable runnable) {
@@ -264,7 +290,22 @@
      */
     @SuppressWarnings("unused")
     private boolean drawOverlay(long timestampNs) {
-        // TODO(b/297509601) implement this method. See: aosp/2676397.
+        checkGlThread();
+        if (mTransformationInfo == null || mOnDrawListener == null) {
+            return true;
+        }
+        Frame frame = Frame.of(
+                requireNonNull(mOverlayCanvas),
+                timestampNs,
+                requireNonNull(mInputSize),
+                mTransformationInfo);
+        if (!mOnDrawListener.apply(frame)) {
+            // The caller wants to drop the frame.
+            return false;
+        }
+        if (frame.isOverlayDirty()) {
+            mGlRenderer.uploadOverlay(requireNonNull(mOverlayBitmap));
+        }
         return true;
     }
 
@@ -275,4 +316,9 @@
     private boolean isGlThread() {
         return Thread.currentThread() == mGlThread;
     }
+
+    @VisibleForTesting
+    GlRenderer getGlRendererForTesting() {
+        return mGlRenderer;
+    }
 }
diff --git a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/compat/workaround/OnEnableDisableSessionDurationCheckTest.kt b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/compat/workaround/OnEnableDisableSessionDurationCheckTest.kt
index abd3bda..9bc767e 100644
--- a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/compat/workaround/OnEnableDisableSessionDurationCheckTest.kt
+++ b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/compat/workaround/OnEnableDisableSessionDurationCheckTest.kt
@@ -17,6 +17,7 @@
 package androidx.camera.extensions.internal.compat.workaround
 
 import androidx.camera.extensions.internal.compat.workaround.OnEnableDisableSessionDurationCheck.MIN_DURATION_FOR_ENABLE_DISABLE_SESSION
+import androidx.camera.testing.impl.AndroidUtil
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SdkSuppress
 import androidx.test.filters.SmallTest
@@ -24,6 +25,8 @@
 import kotlin.system.measureTimeMillis
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.runBlocking
+import org.junit.Assume.assumeFalse
+import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
 
@@ -35,6 +38,11 @@
         const val TOLERANCE = 60L
     }
 
+    @Before
+    fun setUp() {
+        assumeFalse(AndroidUtil.isEmulatorAndAPI21())
+    }
+
     @Test
     fun enabled_ensureMinimalDuration() = runBlocking {
         // Arrange
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/impl/E2ETestUtil.kt b/camera/camera-testing/src/main/java/androidx/camera/testing/impl/FileUtil.kt
similarity index 60%
rename from camera/camera-testing/src/main/java/androidx/camera/testing/impl/E2ETestUtil.kt
rename to camera/camera-testing/src/main/java/androidx/camera/testing/impl/FileUtil.kt
index e454f702..b482047 100644
--- a/camera/camera-testing/src/main/java/androidx/camera/testing/impl/E2ETestUtil.kt
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/impl/FileUtil.kt
@@ -18,10 +18,12 @@
 
 import android.content.ContentResolver
 import android.content.ContentValues
+import android.net.Uri
 import android.os.Environment.DIRECTORY_DOCUMENTS
 import android.os.Environment.DIRECTORY_MOVIES
 import android.os.Environment.getExternalStoragePublicDirectory
 import android.provider.MediaStore
+import android.util.Log
 import androidx.annotation.RequiresApi
 import androidx.camera.core.Logger
 import androidx.camera.video.FileOutputOptions
@@ -32,12 +34,12 @@
 import java.io.FileOutputStream
 import java.io.OutputStreamWriter
 
-private const val TAG = "E2ETestUtil"
+private const val TAG = "FileUtil"
 private const val EXTENSION_MP4 = "mp4"
 private const val EXTENSION_TEXT = "txt"
 
 @RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
-object E2ETestUtil {
+object FileUtil {
 
     /**
      * Write the given text to the external storage.
@@ -101,7 +103,7 @@
     ): FileOutputOptions {
         val fileNameWithExtension = "$fileName.$extension"
         val folder = getExternalStoragePublicDirectory(DIRECTORY_MOVIES)
-        if (!folder.exists() && !folder.mkdirs()) {
+        if (!createFolder(folder)) {
             Logger.e(TAG, "Failed to create directory: $folder")
         }
         return FileOutputOptions.Builder(File(folder, fileNameWithExtension)).build()
@@ -119,14 +121,10 @@
     fun generateVideoMediaStoreOptions(
         contentResolver: ContentResolver,
         fileName: String
-    ): MediaStoreOutputOptions {
-        val contentValues = generateVideoContentValues(fileName)
-
-        return MediaStoreOutputOptions.Builder(
-            contentResolver,
-            MediaStore.Video.Media.EXTERNAL_CONTENT_URI
-        ).setContentValues(contentValues).build()
-    }
+    ): MediaStoreOutputOptions = MediaStoreOutputOptions.Builder(
+        contentResolver,
+        MediaStore.Video.Media.EXTERNAL_CONTENT_URI
+    ).setContentValues(generateVideoContentValues(fileName)).build()
 
     /**
      * Check if the given file name string is valid.
@@ -145,14 +143,79 @@
         return !fileName.isNullOrBlank()
     }
 
-    private fun generateVideoContentValues(fileName: String): ContentValues {
-        val res = ContentValues()
-        res.put(MediaStore.MediaColumns.MIME_TYPE, "video/mp4")
-        res.put(MediaStore.Video.Media.TITLE, fileName)
-        res.put(MediaStore.Video.Media.DISPLAY_NAME, fileName)
-        res.put(MediaStore.Video.Media.DATE_ADDED, System.currentTimeMillis() / 1000)
-        res.put(MediaStore.Video.Media.DATE_TAKEN, System.currentTimeMillis())
+    /**
+     * Creates parent folder for the input file path.
+     *
+     * @param filePath the input file path to create its parent folder.
+     * @return `true` if the parent folder already exists or is created successfully.
+     * `false` if the existing parent folder path is not a folder or failed to create.
+     */
+    @JvmStatic
+    fun createParentFolder(filePath: String): Boolean {
+        return createParentFolder(File(filePath))
+    }
 
-        return res
+    /**
+     * Creates parent folder for the input file.
+     *
+     * @param file the input file to create its parent folder
+     * @return `true` if the parent folder already exists or is created successfully.
+     * `false` if the existing parent folder path is not a folder or failed to create.
+     */
+    @JvmStatic
+    fun createParentFolder(file: File): Boolean = file.parentFile?.let {
+        createFolder(it)
+    } ?: false
+
+    /**
+     * Creates folder for the input file.
+     *
+     * @param file the input file to create folder
+     * @return `true` if the folder already exists or is created successfully.
+     * `false` if the existing folder path is not a folder or failed to create.
+     */
+    @JvmStatic
+    fun createFolder(file: File): Boolean = if (file.exists()) {
+        file.isDirectory
+    } else {
+        file.mkdirs()
+    }
+
+    /**
+     * Gets the absolute path from a Uri.
+     *
+     * @param resolver   the content resolver.
+     * @param contentUri the content uri.
+     * @return the file path of the content uri or null if not found.
+     */
+    @JvmStatic
+    fun getAbsolutePathFromUri(resolver: ContentResolver, contentUri: Uri): String? {
+        // MediaStore.Video.Media.DATA was deprecated in API level 29.
+        val column = MediaStore.Video.Media.DATA
+        try {
+            resolver.query(contentUri, arrayOf(column), null, null, null)!!.use { cursor ->
+                val columnIndex = cursor.getColumnIndexOrThrow(column)
+                cursor.moveToFirst()
+                return cursor.getString(columnIndex)
+            }
+        } catch (e: RuntimeException) {
+            Log.e(
+                TAG,
+                String.format(
+                    "Failed in getting absolute path for Uri %s with Exception %s",
+                    contentUri, e
+                ), e
+            )
+            return null
+        }
+    }
+
+    private fun generateVideoContentValues(fileName: String) = ContentValues().apply {
+        put(MediaStore.MediaColumns.MIME_TYPE, "video/mp4")
+        put(MediaStore.Video.Media.TITLE, fileName)
+        put(MediaStore.Video.Media.DISPLAY_NAME, fileName)
+        val currentTimeMs = System.currentTimeMillis()
+        put(MediaStore.Video.Media.DATE_ADDED, currentTimeMs / 1000)
+        put(MediaStore.Video.Media.DATE_TAKEN, currentTimeMs)
     }
 }
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/impl/fakes/FakeCameraDeviceSurfaceManager.java b/camera/camera-testing/src/main/java/androidx/camera/testing/impl/fakes/FakeCameraDeviceSurfaceManager.java
index c0a5fe5..4813cdc 100644
--- a/camera/camera-testing/src/main/java/androidx/camera/testing/impl/fakes/FakeCameraDeviceSurfaceManager.java
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/impl/fakes/FakeCameraDeviceSurfaceManager.java
@@ -18,9 +18,7 @@
 
 import static android.graphics.ImageFormat.JPEG;
 import static android.graphics.ImageFormat.YUV_420_888;
-
 import static androidx.camera.core.impl.ImageFormatConstants.INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE;
-
 import static com.google.common.primitives.Ints.asList;
 
 import android.util.Pair;
@@ -90,7 +88,8 @@
             @CameraMode.Mode int cameraMode,
             @NonNull String cameraId,
             @NonNull List<AttachedSurfaceInfo> existingSurfaces,
-            @NonNull Map<UseCaseConfig<?>, List<Size>> newUseCaseConfigsSupportedSizeMap) {
+            @NonNull Map<UseCaseConfig<?>, List<Size>> newUseCaseConfigsSupportedSizeMap,
+            boolean isPreviewStabilizationOn) {
         List<UseCaseConfig<?>> newUseCaseConfigs =
                 new ArrayList<>(newUseCaseConfigsSupportedSizeMap.keySet());
         checkSurfaceCombo(existingSurfaces, newUseCaseConfigs);
diff --git a/camera/camera-testing/src/test/java/androidx/camera/testing/fakes/FakeCameraDeviceSurfaceManagerTest.java b/camera/camera-testing/src/test/java/androidx/camera/testing/fakes/FakeCameraDeviceSurfaceManagerTest.java
index 453a9af..1ac4332 100644
--- a/camera/camera-testing/src/test/java/androidx/camera/testing/fakes/FakeCameraDeviceSurfaceManagerTest.java
+++ b/camera/camera-testing/src/test/java/androidx/camera/testing/fakes/FakeCameraDeviceSurfaceManagerTest.java
@@ -17,12 +17,9 @@
 package androidx.camera.testing.fakes;
 
 import static android.graphics.ImageFormat.YUV_420_888;
-
 import static androidx.camera.core.impl.SurfaceConfig.ConfigSize.PREVIEW;
 import static androidx.camera.core.impl.SurfaceConfig.ConfigType.YUV;
-
 import static com.google.common.truth.Truth.assertThat;
-
 import static java.util.Collections.emptyList;
 import static java.util.Collections.singletonList;
 
@@ -96,7 +93,8 @@
                 CameraMode.DEFAULT,
                 FAKE_CAMERA_ID0,
                 emptyList(),
-                createConfigOutputSizesMap(preview, analysis));
+                createConfigOutputSizesMap(preview, analysis),
+                false);
     }
 
     @Test(expected = IllegalArgumentException.class)
@@ -114,7 +112,8 @@
         mFakeCameraDeviceSurfaceManager.getSuggestedStreamSpecs(
                 CameraMode.DEFAULT,
                 FAKE_CAMERA_ID0,
-                singletonList(analysis), createConfigOutputSizesMap(preview, video));
+                singletonList(analysis), createConfigOutputSizesMap(preview, video),
+                false);
     }
 
     @Test(expected = IllegalArgumentException.class)
@@ -125,7 +124,8 @@
         mFakeCameraDeviceSurfaceManager.getSuggestedStreamSpecs(
                 CameraMode.DEFAULT,
                 FAKE_CAMERA_ID0,
-                Collections.emptyList(), createConfigOutputSizesMap(preview, video, analysis));
+                Collections.emptyList(), createConfigOutputSizesMap(preview, video, analysis),
+                false);
     }
 
     @Test
@@ -134,12 +134,14 @@
                 mFakeCameraDeviceSurfaceManager.getSuggestedStreamSpecs(
                         CameraMode.DEFAULT,
                         FAKE_CAMERA_ID0,
-                        emptyList(), createConfigOutputSizesMap(mFakeUseCaseConfig)).first;
+                        emptyList(), createConfigOutputSizesMap(mFakeUseCaseConfig),
+                        false).first;
         Map<UseCaseConfig<?>, StreamSpec> suggestedStreamSpecCamera1 =
                 mFakeCameraDeviceSurfaceManager.getSuggestedStreamSpecs(
                         CameraMode.DEFAULT,
                         FAKE_CAMERA_ID1,
-                        emptyList(), createConfigOutputSizesMap(mFakeUseCaseConfig)).first;
+                        emptyList(), createConfigOutputSizesMap(mFakeUseCaseConfig),
+                        false).first;
 
         assertThat(suggestedStreamSpecsCamera0.get(mFakeUseCaseConfig)).isEqualTo(
                 StreamSpec.builder(new Size(FAKE_WIDTH0, FAKE_HEIGHT0)).build());
diff --git a/camera/camera-video/api/current.txt b/camera/camera-video/api/current.txt
index b9cc77a..7f1314e 100644
--- a/camera/camera-video/api/current.txt
+++ b/camera/camera-video/api/current.txt
@@ -2,10 +2,12 @@
 package androidx.camera.video {
 
   @RequiresApi(21) @com.google.auto.value.AutoValue public abstract class AudioStats {
+    method public double getAudioAmplitude();
     method public abstract int getAudioState();
     method public abstract Throwable? getErrorCause();
     method public boolean hasAudio();
     method public boolean hasError();
+    field public static final double AUDIO_AMPLITUDE_NONE = 0.0;
     field public static final int AUDIO_STATE_ACTIVE = 0; // 0x0
     field public static final int AUDIO_STATE_DISABLED = 1; // 0x1
     field public static final int AUDIO_STATE_ENCODER_ERROR = 3; // 0x3
@@ -14,6 +16,9 @@
     field public static final int AUDIO_STATE_SOURCE_SILENCED = 2; // 0x2
   }
 
+  @SuppressCompatibility @RequiresOptIn @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ExperimentalAudioApi {
+  }
+
   @SuppressCompatibility @RequiresOptIn @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ExperimentalPersistentRecording {
   }
 
diff --git a/camera/camera-video/api/restricted_current.txt b/camera/camera-video/api/restricted_current.txt
index b9cc77a..7f1314e 100644
--- a/camera/camera-video/api/restricted_current.txt
+++ b/camera/camera-video/api/restricted_current.txt
@@ -2,10 +2,12 @@
 package androidx.camera.video {
 
   @RequiresApi(21) @com.google.auto.value.AutoValue public abstract class AudioStats {
+    method public double getAudioAmplitude();
     method public abstract int getAudioState();
     method public abstract Throwable? getErrorCause();
     method public boolean hasAudio();
     method public boolean hasError();
+    field public static final double AUDIO_AMPLITUDE_NONE = 0.0;
     field public static final int AUDIO_STATE_ACTIVE = 0; // 0x0
     field public static final int AUDIO_STATE_DISABLED = 1; // 0x1
     field public static final int AUDIO_STATE_ENCODER_ERROR = 3; // 0x3
@@ -14,6 +16,9 @@
     field public static final int AUDIO_STATE_SOURCE_SILENCED = 2; // 0x2
   }
 
+  @SuppressCompatibility @RequiresOptIn @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ExperimentalAudioApi {
+  }
+
   @SuppressCompatibility @RequiresOptIn @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ExperimentalPersistentRecording {
   }
 
diff --git a/camera/camera-video/src/main/java/androidx/camera/video/AudioStats.java b/camera/camera-video/src/main/java/androidx/camera/video/AudioStats.java
index 7f171f5..dde69be 100644
--- a/camera/camera-video/src/main/java/androidx/camera/video/AudioStats.java
+++ b/camera/camera-video/src/main/java/androidx/camera/video/AudioStats.java
@@ -104,7 +104,6 @@
      * Should audio recording be disabled, any attempts to retrieve the amplitude will
      * return this value.
      */
-    @RestrictTo(RestrictTo.Scope.LIBRARY)
     public static final double AUDIO_AMPLITUDE_NONE = 0;
 
     @IntDef({AUDIO_STATE_ACTIVE, AUDIO_STATE_DISABLED, AUDIO_STATE_SOURCE_SILENCED,
@@ -168,8 +167,8 @@
     public abstract Throwable getErrorCause();
 
     /**
-     * Returns the maximum absolute amplitude of the audio most recently sampled. Returns
-     * {@link #AUDIO_AMPLITUDE_NONE} if audio is disabled.
+     * Returns the maximum absolute amplitude of the audio most recently sampled in the past 2
+     * nanoseconds
      *
      * <p>The amplitude is the maximum absolute value over all channels which the audio was
      * most recently sampled from.
@@ -177,10 +176,11 @@
      * <p>Amplitude is a relative measure of the maximum sound pressure/voltage range of the device
      * microphone.
      *
+     * <p>Returns {@link #AUDIO_AMPLITUDE_NONE} if audio is disabled.
      * <p>The amplitude value returned will be a double between {@code 0} and {@code 1}.
+     *
      */
     @OptIn(markerClass = ExperimentalAudioApi.class)
-    @RestrictTo(RestrictTo.Scope.LIBRARY)
     public double getAudioAmplitude() {
         if (getAudioState() == AUDIO_STATE_DISABLED) {
             return AUDIO_AMPLITUDE_NONE;
diff --git a/camera/camera-video/src/main/java/androidx/camera/video/ExperimentalAudioApi.java b/camera/camera-video/src/main/java/androidx/camera/video/ExperimentalAudioApi.java
index bf07a6e..99de642 100644
--- a/camera/camera-video/src/main/java/androidx/camera/video/ExperimentalAudioApi.java
+++ b/camera/camera-video/src/main/java/androidx/camera/video/ExperimentalAudioApi.java
@@ -19,16 +19,14 @@
 import static java.lang.annotation.RetentionPolicy.CLASS;
 
 import androidx.annotation.RequiresOptIn;
-import androidx.annotation.RestrictTo;
 
 import java.lang.annotation.Retention;
 
 /**
- * Denotes that the methods on retrieving audio amplitude data are experimental and may
+ * Denotes that the annotated element relates to an experimental audio feature and may
  * change in a future release.
  */
 @Retention(CLASS)
 @RequiresOptIn
-@RestrictTo(RestrictTo.Scope.LIBRARY)
 public @interface ExperimentalAudioApi {
 }
diff --git a/camera/camera-video/src/main/java/androidx/camera/video/VideoCapture.java b/camera/camera-video/src/main/java/androidx/camera/video/VideoCapture.java
index d39f6dc..8e8bbd6 100644
--- a/camera/camera-video/src/main/java/androidx/camera/video/VideoCapture.java
+++ b/camera/camera-video/src/main/java/androidx/camera/video/VideoCapture.java
@@ -905,7 +905,7 @@
 
         sessionConfigBuilder.clearSurfaces();
         DynamicRange dynamicRange = streamSpec.getDynamicRange();
-        if (!isStreamError) {
+        if (!isStreamError && mDeferrableSurface != null) {
             if (isStreamActive) {
                 sessionConfigBuilder.addSurface(mDeferrableSurface, dynamicRange);
             } else {
diff --git a/camera/camera-video/src/main/java/androidx/camera/video/internal/compat/quirk/PreviewDelayWhenVideoCaptureIsBoundQuirk.java b/camera/camera-video/src/main/java/androidx/camera/video/internal/compat/quirk/PreviewDelayWhenVideoCaptureIsBoundQuirk.java
index efffa0c..558d22d 100644
--- a/camera/camera-video/src/main/java/androidx/camera/video/internal/compat/quirk/PreviewDelayWhenVideoCaptureIsBoundQuirk.java
+++ b/camera/camera-video/src/main/java/androidx/camera/video/internal/compat/quirk/PreviewDelayWhenVideoCaptureIsBoundQuirk.java
@@ -21,22 +21,20 @@
 import androidx.annotation.RequiresApi;
 import androidx.camera.core.impl.Quirk;
 
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Locale;
-import java.util.Set;
-
 /**
  * <p>QuirkSummary
  *     Bug Id: b/223643510
  *     Description: Quirk indicates Preview is delayed on some Huawei devices when the Preview uses
- *                  certain resolutions and VideoCapture is bound.
+ *                  certain resolutions and VideoCapture is bound. The quirk applies on all
+ *                  Huawei devices since there is a certain number of unknown devices with this
+ *                  issue.
  *     Device(s): Some Huawei devices.
  */
 @RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
 public class PreviewDelayWhenVideoCaptureIsBoundQuirk implements Quirk {
 
-    private static final Set<String> HUAWEI_DEVICE_LIST = new HashSet<>(Arrays.asList(
+    /*
+    Known devices:
             "HWELE",  // P30
             "HW-02L", // P30 Pro
             "HWVOG",  // P30 Pro
@@ -44,15 +42,16 @@
             "HWLYA",  // Mate 20 Pro
             "HWCOL",  // Honor 10
             "HWPAR"   // Nova 3
-    ));
 
-    private static final Set<String> HUAWEI_MODEL_LIST = new HashSet<>(Arrays.asList(
+    Known models:
             "ELS-AN00", "ELS-TN00", "ELS-NX9", "ELS-N04"  // P40 Pro
-    ));
+
+    Known others:
+            mate40
+            honor v2
+     */
 
     static boolean load() {
-        return "Huawei".equalsIgnoreCase(Build.MANUFACTURER)
-                && (HUAWEI_DEVICE_LIST.contains(Build.DEVICE.toUpperCase(Locale.US))
-                || HUAWEI_MODEL_LIST.contains(Build.MODEL.toUpperCase(Locale.US)));
+        return "Huawei".equalsIgnoreCase(Build.MANUFACTURER);
     }
 }
diff --git a/camera/camera-view/src/main/java/androidx/camera/view/CameraController.java b/camera/camera-view/src/main/java/androidx/camera/view/CameraController.java
index d92bad2..b76e3c6 100644
--- a/camera/camera-view/src/main/java/androidx/camera/view/CameraController.java
+++ b/camera/camera-view/src/main/java/androidx/camera/view/CameraController.java
@@ -655,13 +655,17 @@
     /**
      * Captures a new still image and saves to a file along with application specified metadata.
      *
-     * <p> The callback will be called only once for every invocation of this method.
+     * <p>The callback will be called only once for every invocation of this method.
      *
-     * <p> By default, the saved image is mirrored to match the output of the preview if front
+     * <p>By default, the saved image is mirrored to match the output of the preview if front
      * camera is used. To override this behavior, the app needs to explicitly set the flag to
      * {@code false} using {@link ImageCapture.Metadata#setReversedHorizontal} and
      * {@link ImageCapture.OutputFileOptions.Builder#setMetadata}.
      *
+     * <p>The saved image is cropped to match the aspect ratio of the {@link PreviewView}. To
+     * take a picture with the maximum available resolution, make sure that the
+     * {@link PreviewView}'s aspect ratio is 4:3.
+     *
      * @param outputFileOptions  Options to store the newly captured image.
      * @param executor           The executor in which the callback methods will be run.
      * @param imageSavedCallback Callback to be called for the newly captured image.
@@ -1773,8 +1777,8 @@
      * <p>Valid zoom values range from {@link ZoomState#getMinZoomRatio()} to
      * {@link ZoomState#getMaxZoomRatio()}.
      *
-     * <p> No-ops if the camera is not ready. The {@link ListenableFuture} completes successfully
-     * in this case.
+     * <p>If the value is set before the camera is ready, {@link CameraController} waits for the
+     * camera to be ready and then sets the zoom ratio.
      *
      * @param zoomRatio The requested zoom ratio.
      * @return a {@link ListenableFuture} which is finished when camera is set to the given ratio.
@@ -1797,13 +1801,13 @@
     /**
      * Sets current zoom by a linear zoom value ranging from 0f to 1.0f.
      *
-     * <p> LinearZoom 0f represents the minimum zoom while linearZoom 1.0f represents the maximum
+     * <p>LinearZoom 0f represents the minimum zoom while linearZoom 1.0f represents the maximum
      * zoom. The advantage of linearZoom is that it ensures the field of view (FOV) varies
      * linearly with the linearZoom value, for use with slider UI elements (while
      * {@link #setZoomRatio(float)} works well for pinch-zoom gestures).
      *
-     * <p> No-ops if the camera is not ready. The {@link ListenableFuture} completes successfully
-     * in this case.
+     * <p>If the value is set before the camera is ready, {@link CameraController} waits for the
+     * camera to be ready and then sets the linear zoom.
      *
      * @return a {@link ListenableFuture} which is finished when camera is set to the given ratio.
      * It fails with {@link CameraControl.OperationCanceledException} if there is newer value
@@ -1840,8 +1844,8 @@
     /**
      * Enable the torch or disable the torch.
      *
-     * <p> No-ops if the camera is not ready. The {@link ListenableFuture} completes successfully
-     * in this case.
+     * <p>If the value is set before the camera is ready, {@link CameraController} waits for the
+     * camera to be ready and then enables the torch.
      *
      * @param torchEnabled true to turn on the torch, false to turn it off.
      * @return A {@link ListenableFuture} which is successful when the torch was changed to the
diff --git a/camera/integration-tests/coretestapp/lint-baseline.xml b/camera/integration-tests/coretestapp/lint-baseline.xml
index 4cbca68..78ea985 100644
--- a/camera/integration-tests/coretestapp/lint-baseline.xml
+++ b/camera/integration-tests/coretestapp/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.2.0-alpha15" type="baseline" client="gradle" dependencies="false" name="AGP (8.2.0-alpha15)" variant="all" version="8.2.0-alpha15">
+<issues format="6" by="lint 8.2.0-beta01" type="baseline" client="gradle" dependencies="false" name="AGP (8.2.0-beta01)" variant="all" version="8.2.0-beta01">
 
     <issue
         id="BanThreadSleep"
@@ -12,108 +12,90 @@
 
     <issue
         id="RestrictedApiAndroidX"
-        message="CameraInfoInternal can only be accessed from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
-        errorLine1="                if (cameraInfo instanceof CameraInfoInternal) {"
-        errorLine2="                                          ~~~~~~~~~~~~~~~~~~">
+        message="FileUtil.canDeviceWriteToMediaStore can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
+        errorLine1="                    if (!canDeviceWriteToMediaStore()) {"
+        errorLine2="                         ~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="src/main/java/androidx/camera/integration/core/CameraXActivity.java"/>
     </issue>
 
     <issue
         id="RestrictedApiAndroidX"
-        message="DeviceQuirks.getAll can only be called from within the same library (androidx.camera:camera-video)"
-        errorLine1="                    Quirks deviceQuirks = DeviceQuirks.getAll();"
-        errorLine2="                                                       ~~~~~~">
+        message="FileUtil.generateVideoFileOutputOptions can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
+        errorLine1="                                this, generateVideoFileOutputOptions(fileName, extension));"
+        errorLine2="                                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="src/main/java/androidx/camera/integration/core/CameraXActivity.java"/>
     </issue>
 
     <issue
         id="RestrictedApiAndroidX"
-        message="CameraInfoInternal can only be accessed from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
-        errorLine1="                    Quirks cameraQuirks = ((CameraInfoInternal) cameraInfo).getCameraQuirks();"
-        errorLine2="                                            ~~~~~~~~~~~~~~~~~~">
+        message="FileUtil.generateVideoFileOutputOptions can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
+        errorLine1="                                this, generateVideoFileOutputOptions(fileName, extension));"
+        errorLine2="                                                                     ~~~~~~~~">
         <location
             file="src/main/java/androidx/camera/integration/core/CameraXActivity.java"/>
     </issue>
 
     <issue
         id="RestrictedApiAndroidX"
-        message="CameraInfoInternal.getCameraQuirks can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
-        errorLine1="                    Quirks cameraQuirks = ((CameraInfoInternal) cameraInfo).getCameraQuirks();"
-        errorLine2="                                                                            ~~~~~~~~~~~~~~~">
+        message="FileUtil.generateVideoFileOutputOptions can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
+        errorLine1="                                this, generateVideoFileOutputOptions(fileName, extension));"
+        errorLine2="                                                                               ~~~~~~~~~">
         <location
             file="src/main/java/androidx/camera/integration/core/CameraXActivity.java"/>
     </issue>
 
     <issue
         id="RestrictedApiAndroidX"
-        message="Quirks.contains can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
-        errorLine1="                    if (deviceQuirks.contains(CrashWhenTakingPhotoWithAutoFlashAEModeQuirk.class)"
-        errorLine2="                                     ~~~~~~~~">
+        message="FileUtil.generateVideoMediaStoreOptions can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
+        errorLine1="                                generateVideoMediaStoreOptions(getContentResolver(), fileName));"
+        errorLine2="                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="src/main/java/androidx/camera/integration/core/CameraXActivity.java"/>
     </issue>
 
     <issue
         id="RestrictedApiAndroidX"
-        message="Quirks.contains can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
-        errorLine1="                    if (deviceQuirks.contains(CrashWhenTakingPhotoWithAutoFlashAEModeQuirk.class)"
-        errorLine2="                                              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        message="FileUtil.generateVideoMediaStoreOptions can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
+        errorLine1="                                generateVideoMediaStoreOptions(getContentResolver(), fileName));"
+        errorLine2="                                                               ~~~~~~~~~~~~~~~~~~">
         <location
             file="src/main/java/androidx/camera/integration/core/CameraXActivity.java"/>
     </issue>
 
     <issue
         id="RestrictedApiAndroidX"
-        message="Quirks.contains can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
-        errorLine1="                            || cameraQuirks.contains(ImageCaptureFailWithAutoFlashQuirk.class)"
-        errorLine2="                                            ~~~~~~~~">
+        message="FileUtil.generateVideoMediaStoreOptions can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
+        errorLine1="                                generateVideoMediaStoreOptions(getContentResolver(), fileName));"
+        errorLine2="                                                                                     ~~~~~~~~">
         <location
             file="src/main/java/androidx/camera/integration/core/CameraXActivity.java"/>
     </issue>
 
     <issue
         id="RestrictedApiAndroidX"
-        message="Quirks.contains can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
-        errorLine1="                            || cameraQuirks.contains(ImageCaptureFailWithAutoFlashQuirk.class)"
-        errorLine2="                                                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        message="FileUtil.getAbsolutePathFromUri can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
+        errorLine1="                        videoFilePath = getAbsolutePathFromUri("
+        errorLine2="                                        ~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="src/main/java/androidx/camera/integration/core/CameraXActivity.java"/>
     </issue>
 
     <issue
         id="RestrictedApiAndroidX"
-        message="Quirks.contains can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
-        errorLine1="                            || cameraQuirks.contains(ImageCaptureFlashNotFireQuirk.class)) {"
-        errorLine2="                                            ~~~~~~~~">
+        message="FileUtil.getAbsolutePathFromUri can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
+        errorLine1="                                getApplicationContext().getContentResolver(),"
+        errorLine2="                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="src/main/java/androidx/camera/integration/core/CameraXActivity.java"/>
     </issue>
 
     <issue
         id="RestrictedApiAndroidX"
-        message="Quirks.contains can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
-        errorLine1="                            || cameraQuirks.contains(ImageCaptureFlashNotFireQuirk.class)) {"
-        errorLine2="                                                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/integration/core/CameraXActivity.java"/>
-    </issue>
-
-    <issue
-        id="RestrictedApiAndroidX"
-        message="DeviceQuirks.get can only be called from within the same library (androidx.camera:camera-video)"
-        errorLine1="                    if (DeviceQuirks.get(MediaStoreVideoCannotWrite.class) != null) {"
-        errorLine2="                                     ~~~">
-        <location
-            file="src/main/java/androidx/camera/integration/core/CameraXActivity.java"/>
-    </issue>
-
-    <issue
-        id="RestrictedApiAndroidX"
-        message="DeviceQuirks.get can only be called from within the same library (androidx.camera:camera-video)"
-        errorLine1="                    if (DeviceQuirks.get(MediaStoreVideoCannotWrite.class) != null) {"
-        errorLine2="                                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        message="FileUtil.getAbsolutePathFromUri can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
+        errorLine1="                                uri"
+        errorLine2="                                ~~~">
         <location
             file="src/main/java/androidx/camera/integration/core/CameraXActivity.java"/>
     </issue>
@@ -183,6 +165,69 @@
 
     <issue
         id="RestrictedApiAndroidX"
+        message="FileUtil.createParentFolder can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
+        errorLine1="        if (createParentFolder(pictureFolder)) {"
+        errorLine2="            ~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/camera/integration/core/CameraXActivity.java"/>
+    </issue>
+
+    <issue
+        id="RestrictedApiAndroidX"
+        message="FileUtil.createParentFolder can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
+        errorLine1="        if (createParentFolder(pictureFolder)) {"
+        errorLine2="                               ~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/camera/integration/core/CameraXActivity.java"/>
+    </issue>
+
+    <issue
+        id="RestrictedApiAndroidX"
+        message="FileUtil.getAbsolutePathFromUri can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
+        errorLine1="                getAbsolutePathFromUri(getApplicationContext().getContentResolver(),"
+        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/camera/integration/core/CameraXActivity.java"/>
+    </issue>
+
+    <issue
+        id="RestrictedApiAndroidX"
+        message="FileUtil.getAbsolutePathFromUri can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
+        errorLine1="                getAbsolutePathFromUri(getApplicationContext().getContentResolver(),"
+        errorLine2="                                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/camera/integration/core/CameraXActivity.java"/>
+    </issue>
+
+    <issue
+        id="RestrictedApiAndroidX"
+        message="FileUtil.getAbsolutePathFromUri can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
+        errorLine1="                        MediaStore.Video.Media.EXTERNAL_CONTENT_URI);"
+        errorLine2="                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/camera/integration/core/CameraXActivity.java"/>
+    </issue>
+
+    <issue
+        id="RestrictedApiAndroidX"
+        message="FileUtil.createParentFolder can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
+        errorLine1="        if (videoFilePath == null || !createParentFolder(videoFilePath)) {"
+        errorLine2="                                      ~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/camera/integration/core/CameraXActivity.java"/>
+    </issue>
+
+    <issue
+        id="RestrictedApiAndroidX"
+        message="FileUtil.createParentFolder can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
+        errorLine1="        if (videoFilePath == null || !createParentFolder(videoFilePath)) {"
+        errorLine2="                                                         ~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/camera/integration/core/CameraXActivity.java"/>
+    </issue>
+
+    <issue
+        id="RestrictedApiAndroidX"
         message="CameraXExecutors.mainThreadExecutor can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
         errorLine1="                            CameraXExecutors.mainThreadExecutor());"
         errorLine2="                                             ~~~~~~~~~~~~~~~~~~">
@@ -192,6 +237,24 @@
 
     <issue
         id="RestrictedApiAndroidX"
+        message="FileUtil.createParentFolder can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
+        errorLine1="        if (createParentFolder(pictureFolder)) {"
+        errorLine2="            ~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/camera/integration/core/CameraXService.java"/>
+    </issue>
+
+    <issue
+        id="RestrictedApiAndroidX"
+        message="FileUtil.createParentFolder can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
+        errorLine1="        if (createParentFolder(pictureFolder)) {"
+        errorLine2="                               ~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/camera/integration/core/CameraXService.java"/>
+    </issue>
+
+    <issue
+        id="RestrictedApiAndroidX"
         message="TransformationInfo.hasCameraTransform can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
         errorLine1="                                    mHasCameraTransform = transformationInfo.hasCameraTransform();"
         errorLine2="                                                                             ~~~~~~~~~~~~~~~~~~">
@@ -264,34 +327,34 @@
 
     <issue
         id="RestrictedApiAndroidX"
-        message="E2ETestUtil.canDeviceWriteToMediaStore can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
-        errorLine1="        if (E2ETestUtil.canDeviceWriteToMediaStore()) {"
-        errorLine2="                        ~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        message="FileUtil.canDeviceWriteToMediaStore can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
+        errorLine1="        if (FileUtil.canDeviceWriteToMediaStore()) {"
+        errorLine2="                     ~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="src/main/java/androidx/camera/integration/core/VideoCameraSwitchingActivity.java"/>
     </issue>
 
     <issue
         id="RestrictedApiAndroidX"
-        message="E2ETestUtil.generateVideoMediaStoreOptions can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
-        errorLine1="                    E2ETestUtil.generateVideoMediaStoreOptions(this.getContentResolver(),"
-        errorLine2="                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        message="FileUtil.generateVideoMediaStoreOptions can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
+        errorLine1="                    FileUtil.generateVideoMediaStoreOptions(this.getContentResolver(),"
+        errorLine2="                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="src/main/java/androidx/camera/integration/core/VideoCameraSwitchingActivity.java"/>
     </issue>
 
     <issue
         id="RestrictedApiAndroidX"
-        message="E2ETestUtil.generateVideoMediaStoreOptions can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
-        errorLine1="                    E2ETestUtil.generateVideoMediaStoreOptions(this.getContentResolver(),"
-        errorLine2="                                                               ~~~~~~~~~~~~~~~~~~~~~~~~~">
+        message="FileUtil.generateVideoMediaStoreOptions can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
+        errorLine1="                    FileUtil.generateVideoMediaStoreOptions(this.getContentResolver(),"
+        errorLine2="                                                            ~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="src/main/java/androidx/camera/integration/core/VideoCameraSwitchingActivity.java"/>
     </issue>
 
     <issue
         id="RestrictedApiAndroidX"
-        message="E2ETestUtil.generateVideoMediaStoreOptions can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
+        message="FileUtil.generateVideoMediaStoreOptions can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
         errorLine1="                            videoFileName));"
         errorLine2="                            ~~~~~~~~~~~~~">
         <location
@@ -300,52 +363,52 @@
 
     <issue
         id="RestrictedApiAndroidX"
-        message="E2ETestUtil.generateVideoFileOutputOptions can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
-        errorLine1="                    E2ETestUtil.generateVideoFileOutputOptions(videoFileName, &quot;mp4&quot;));"
-        errorLine2="                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        message="FileUtil.generateVideoFileOutputOptions can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
+        errorLine1="                    FileUtil.generateVideoFileOutputOptions(videoFileName, &quot;mp4&quot;));"
+        errorLine2="                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="src/main/java/androidx/camera/integration/core/VideoCameraSwitchingActivity.java"/>
     </issue>
 
     <issue
         id="RestrictedApiAndroidX"
-        message="E2ETestUtil.generateVideoFileOutputOptions can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
-        errorLine1="                    E2ETestUtil.generateVideoFileOutputOptions(videoFileName, &quot;mp4&quot;));"
-        errorLine2="                                                               ~~~~~~~~~~~~~">
+        message="FileUtil.generateVideoFileOutputOptions can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
+        errorLine1="                    FileUtil.generateVideoFileOutputOptions(videoFileName, &quot;mp4&quot;));"
+        errorLine2="                                                            ~~~~~~~~~~~~~">
         <location
             file="src/main/java/androidx/camera/integration/core/VideoCameraSwitchingActivity.java"/>
     </issue>
 
     <issue
         id="RestrictedApiAndroidX"
-        message="E2ETestUtil.generateVideoFileOutputOptions can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
-        errorLine1="                    E2ETestUtil.generateVideoFileOutputOptions(videoFileName, &quot;mp4&quot;));"
-        errorLine2="                                                                              ~~~~~">
+        message="FileUtil.generateVideoFileOutputOptions can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
+        errorLine1="                    FileUtil.generateVideoFileOutputOptions(videoFileName, &quot;mp4&quot;));"
+        errorLine2="                                                                           ~~~~~">
         <location
             file="src/main/java/androidx/camera/integration/core/VideoCameraSwitchingActivity.java"/>
     </issue>
 
     <issue
         id="RestrictedApiAndroidX"
-        message="E2ETestUtil.writeTextToExternalFile can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
-        errorLine1="        E2ETestUtil.writeTextToExternalFile(information,"
-        errorLine2="                    ~~~~~~~~~~~~~~~~~~~~~~~">
+        message="FileUtil.writeTextToExternalFile can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
+        errorLine1="        FileUtil.writeTextToExternalFile(information,"
+        errorLine2="                 ~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="src/main/java/androidx/camera/integration/core/VideoCameraSwitchingActivity.java"/>
     </issue>
 
     <issue
         id="RestrictedApiAndroidX"
-        message="E2ETestUtil.writeTextToExternalFile can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
-        errorLine1="        E2ETestUtil.writeTextToExternalFile(information,"
-        errorLine2="                                            ~~~~~~~~~~~">
+        message="FileUtil.writeTextToExternalFile can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
+        errorLine1="        FileUtil.writeTextToExternalFile(information,"
+        errorLine2="                                         ~~~~~~~~~~~">
         <location
             file="src/main/java/androidx/camera/integration/core/VideoCameraSwitchingActivity.java"/>
     </issue>
 
     <issue
         id="RestrictedApiAndroidX"
-        message="E2ETestUtil.writeTextToExternalFile can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
+        message="FileUtil.writeTextToExternalFile can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
         errorLine1="                generateFileName(INFO_FILE_PREFIX, false), &quot;txt&quot;);"
         errorLine2="                ~~~~~~~~~~~~~~~~">
         <location
@@ -354,7 +417,7 @@
 
     <issue
         id="RestrictedApiAndroidX"
-        message="E2ETestUtil.writeTextToExternalFile can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
+        message="FileUtil.writeTextToExternalFile can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
         errorLine1="                generateFileName(INFO_FILE_PREFIX, false), &quot;txt&quot;);"
         errorLine2="                                                           ~~~~~">
         <location
@@ -363,36 +426,36 @@
 
     <issue
         id="RestrictedApiAndroidX"
-        message="E2ETestUtil.isFileNameValid can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
-        errorLine1="        if (!isUnique &amp;&amp; !E2ETestUtil.isFileNameValid(prefix)) {"
-        errorLine2="                                      ~~~~~~~~~~~~~~~">
+        message="FileUtil.isFileNameValid can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
+        errorLine1="        if (!isUnique &amp;&amp; !FileUtil.isFileNameValid(prefix)) {"
+        errorLine2="                                   ~~~~~~~~~~~~~~~">
         <location
             file="src/main/java/androidx/camera/integration/core/VideoCameraSwitchingActivity.java"/>
     </issue>
 
     <issue
         id="RestrictedApiAndroidX"
-        message="E2ETestUtil.isFileNameValid can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
-        errorLine1="        if (!isUnique &amp;&amp; !E2ETestUtil.isFileNameValid(prefix)) {"
-        errorLine2="                                                      ~~~~~~">
+        message="FileUtil.isFileNameValid can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
+        errorLine1="        if (!isUnique &amp;&amp; !FileUtil.isFileNameValid(prefix)) {"
+        errorLine2="                                                   ~~~~~~">
         <location
             file="src/main/java/androidx/camera/integration/core/VideoCameraSwitchingActivity.java"/>
     </issue>
 
     <issue
         id="RestrictedApiAndroidX"
-        message="E2ETestUtil.isFileNameValid can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
-        errorLine1="        if (E2ETestUtil.isFileNameValid(prefix)) {"
-        errorLine2="                        ~~~~~~~~~~~~~~~">
+        message="FileUtil.isFileNameValid can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
+        errorLine1="        if (FileUtil.isFileNameValid(prefix)) {"
+        errorLine2="                     ~~~~~~~~~~~~~~~">
         <location
             file="src/main/java/androidx/camera/integration/core/VideoCameraSwitchingActivity.java"/>
     </issue>
 
     <issue
         id="RestrictedApiAndroidX"
-        message="E2ETestUtil.isFileNameValid can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
-        errorLine1="        if (E2ETestUtil.isFileNameValid(prefix)) {"
-        errorLine2="                                        ~~~~~~">
+        message="FileUtil.isFileNameValid can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
+        errorLine1="        if (FileUtil.isFileNameValid(prefix)) {"
+        errorLine2="                                     ~~~~~~">
         <location
             file="src/main/java/androidx/camera/integration/core/VideoCameraSwitchingActivity.java"/>
     </issue>
diff --git a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/CameraXServiceTest.kt b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/CameraXServiceTest.kt
index 0810339..df79650 100644
--- a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/CameraXServiceTest.kt
+++ b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/CameraXServiceTest.kt
@@ -16,6 +16,7 @@
 
 package androidx.camera.integration.core
 
+import android.Manifest
 import android.app.ActivityManager
 import android.app.Service
 import android.content.ComponentName
@@ -32,6 +33,7 @@
 import androidx.camera.core.ImageCapture
 import androidx.camera.core.UseCase
 import androidx.camera.integration.core.CameraXService.ACTION_BIND_USE_CASES
+import androidx.camera.integration.core.CameraXService.ACTION_TAKE_PICTURE
 import androidx.camera.integration.core.CameraXService.EXTRA_IMAGE_ANALYSIS_ENABLED
 import androidx.camera.integration.core.CameraXService.EXTRA_IMAGE_CAPTURE_ENABLED
 import androidx.camera.integration.core.CameraXService.EXTRA_VIDEO_CAPTURE_ENABLED
@@ -45,6 +47,7 @@
 import androidx.lifecycle.Lifecycle
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.filters.LargeTest
+import androidx.test.rule.GrantPermissionRule
 import androidx.testutils.LifecycleOwnerUtils
 import com.google.common.truth.Truth.assertThat
 import java.util.concurrent.TimeUnit
@@ -72,6 +75,12 @@
     )
 
     @get:Rule
+    val permissionRule: GrantPermissionRule =
+        GrantPermissionRule.grant(
+            Manifest.permission.WRITE_EXTERNAL_STORAGE,
+        )
+
+    @get:Rule
     val cameraPipeConfigTestRule = CameraPipeConfigTestRule(
         active = implName == CameraPipeConfig::class.simpleName,
     )
@@ -105,6 +114,7 @@
     @After
     fun tearDown() {
         if (this::service.isInitialized) {
+            service.deleteSavedMediaFiles()
             context.unbindService(serviceConnection)
             context.stopService(createServiceIntent())
 
@@ -165,6 +175,21 @@
         assertThat(latch.await(15, TimeUnit.SECONDS)).isTrue()
     }
 
+    @Test
+    fun canTakePicture() = runBlocking {
+        // Arrange.
+        context.startService(createServiceIntent(ACTION_BIND_USE_CASES).apply {
+            putExtra(EXTRA_IMAGE_CAPTURE_ENABLED, true)
+        })
+
+        // Act.
+        val latch = service.acquireTakePictureCountDownLatch()
+        context.startService(createServiceIntent(ACTION_TAKE_PICTURE))
+
+        // Assert.
+        assertThat(latch.await(15, TimeUnit.SECONDS)).isTrue()
+    }
+
     private fun createServiceIntent(action: String? = null) =
         Intent(context, CameraXService::class.java).apply {
             action?.let { setAction(it) }
diff --git a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageCaptureTest.kt b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageCaptureTest.kt
index abb5eaed..e10ff38 100644
--- a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageCaptureTest.kt
+++ b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageCaptureTest.kt
@@ -64,6 +64,7 @@
 import androidx.camera.core.impl.utils.CameraOrientationUtil
 import androidx.camera.core.impl.utils.Exif
 import androidx.camera.core.internal.compat.workaround.ExifRotationAvailability
+import androidx.camera.core.internal.compat.workaround.InvalidJpegDataParser
 import androidx.camera.core.resolutionselector.AspectRatioStrategy
 import androidx.camera.core.resolutionselector.ResolutionFilter
 import androidx.camera.core.resolutionselector.ResolutionSelector
@@ -1802,6 +1803,89 @@
         assertThat(imageProperties.size).isEqualTo(maxHighResolutionOutputSize)
     }
 
+    /**
+     * See b/288828159 for the detailed info of the issue
+     */
+    @Test
+    fun jpegImageZeroPaddingDataDetectionTest(): Unit = runBlocking {
+        val imageCapture = ImageCapture.Builder().build()
+
+        withContext(Dispatchers.Main) {
+            cameraProvider.bindToLifecycle(fakeLifecycleOwner, BACK_SELECTOR, imageCapture)
+        }
+
+        val latch = CountdownDeferred(1)
+        var errors: Exception? = null
+
+        val callback = object : ImageCapture.OnImageCapturedCallback() {
+            override fun onCaptureSuccess(image: ImageProxy) {
+                val planes = image.planes
+                val buffer = planes[0].buffer
+                val data = ByteArray(buffer.capacity())
+                buffer.rewind()
+                buffer[data]
+
+                image.close()
+
+                val invalidJpegDataParser = InvalidJpegDataParser()
+
+                // Only checks the unnecessary zero padding data when the device is not included in
+                // the LargeJpegImageQuirk device list. InvalidJpegDataParser#getValidDataLength()
+                // should have returned the valid data length to avoid the extremely large JPEG
+                // file issue.
+                if (invalidJpegDataParser.getValidDataLength(data) == data.size &&
+                    containsZeroPaddingDataAfterEoi(data)
+                ) {
+                    errors = Exception("UNNECESSARY_JPEG_ZERO_PADDING_DATA_DETECTED!")
+                }
+
+                latch.countDown()
+            }
+
+            override fun onError(exception: ImageCaptureException) {
+                errors = exception
+                latch.countDown()
+            }
+        }
+
+        imageCapture.takePicture(mainExecutor, callback)
+
+        // Wait for the signal that the image has been captured.
+        assertThat(withTimeoutOrNull(CAPTURE_TIMEOUT) {
+            latch.await()
+        }).isNotNull()
+        assertThat(errors).isNull()
+    }
+
+    /**
+     * This util function is only used to detect the unnecessary zero padding data after EOI. It
+     * will directly return false when it fails to parse the JPEG byte array data.
+     */
+    private fun containsZeroPaddingDataAfterEoi(bytes: ByteArray): Boolean {
+        val jfifEoiMarkEndPosition = InvalidJpegDataParser.getJfifEoiMarkEndPosition(bytes)
+
+        // Directly returns false when EOI mark can't be found.
+        if (jfifEoiMarkEndPosition == -1) {
+            return false
+        }
+
+        // Will check 1mb data to know whether unnecessary zero padding data exists or not.
+        // Directly returns false when the data length is long enough
+        val dataLengthToDetect = 1_000_000
+        if (jfifEoiMarkEndPosition + dataLengthToDetect > bytes.size) {
+            return false
+        }
+
+        // Checks that there are at least continuous 1mb of unnecessary zero padding data after EOI
+        for (position in jfifEoiMarkEndPosition..jfifEoiMarkEndPosition + dataLengthToDetect) {
+            if (bytes[position] != 0x00.toByte()) {
+                return false
+            }
+        }
+
+        return true
+    }
+
     private fun createNonRotatedConfiguration(): ImageCaptureConfig {
         // Create a configuration with target rotation that matches the sensor rotation.
         // This assumes a back-facing camera (facing away from screen)
diff --git a/camera/integration-tests/coretestapp/src/main/AndroidManifest.xml b/camera/integration-tests/coretestapp/src/main/AndroidManifest.xml
index 4954bfb..3fd027e 100644
--- a/camera/integration-tests/coretestapp/src/main/AndroidManifest.xml
+++ b/camera/integration-tests/coretestapp/src/main/AndroidManifest.xml
@@ -83,6 +83,7 @@
             android:label="CameraX Service">
             <intent-filter>
                 <action android:name="androidx.camera.integration.core.intent.action.BIND_USE_CASES" />
+                <action android:name="androidx.camera.integration.core.intent.action.TAKE_PICTURE" />
             </intent-filter>
         </service>
     </application>
diff --git a/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/CameraXActivity.java b/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/CameraXActivity.java
index f89839e..b304a9a 100644
--- a/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/CameraXActivity.java
+++ b/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/CameraXActivity.java
@@ -25,21 +25,25 @@
 import static androidx.camera.core.ImageCapture.FLASH_MODE_OFF;
 import static androidx.camera.core.ImageCapture.FLASH_MODE_ON;
 import static androidx.camera.core.MirrorMode.MIRROR_MODE_ON_FRONT_ONLY;
+import static androidx.camera.testing.impl.FileUtil.canDeviceWriteToMediaStore;
+import static androidx.camera.testing.impl.FileUtil.createParentFolder;
+import static androidx.camera.testing.impl.FileUtil.generateVideoFileOutputOptions;
+import static androidx.camera.testing.impl.FileUtil.generateVideoMediaStoreOptions;
+import static androidx.camera.testing.impl.FileUtil.getAbsolutePathFromUri;
 import static androidx.camera.video.VideoRecordEvent.Finalize.ERROR_DURATION_LIMIT_REACHED;
 import static androidx.camera.video.VideoRecordEvent.Finalize.ERROR_FILE_SIZE_LIMIT_REACHED;
 import static androidx.camera.video.VideoRecordEvent.Finalize.ERROR_INSUFFICIENT_STORAGE;
 import static androidx.camera.video.VideoRecordEvent.Finalize.ERROR_NONE;
 import static androidx.camera.video.VideoRecordEvent.Finalize.ERROR_SOURCE_INACTIVE;
 
+import static java.util.Objects.requireNonNull;
+
 import android.Manifest;
 import android.annotation.SuppressLint;
-import android.content.ContentResolver;
 import android.content.ContentValues;
-import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
-import android.database.Cursor;
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.display.DisplayManager;
 import android.media.MediaScannerConnection;
@@ -126,8 +130,6 @@
 import androidx.camera.video.VideoCapabilities;
 import androidx.camera.video.VideoCapture;
 import androidx.camera.video.VideoRecordEvent;
-import androidx.camera.video.internal.compat.quirk.DeviceQuirks;
-import androidx.camera.video.internal.compat.quirk.MediaStoreVideoCannotWrite;
 import androidx.core.content.ContextCompat;
 import androidx.core.math.MathUtils;
 import androidx.core.util.Consumer;
@@ -357,6 +359,9 @@
 
         @Override
         public void onSuccess(@Nullable Integer result) {
+            if (result == null) {
+                return;
+            }
             CameraInfo cameraInfo = getCameraInfo();
             if (cameraInfo != null) {
                 ExposureState exposureState = cameraInfo.getExposureState();
@@ -478,7 +483,7 @@
     @VisibleForTesting
     public void resetViewIdlingResource() {
         mPreviewFrameCount.set(0);
-        // Make the view idling resource non-idle, until required framecount achieved.
+        // Make the view idling resource non-idle, until required frame count achieved.
         if (mViewIdlingResource.isIdleNow()) {
             mViewIdlingResource.increment();
         }
@@ -596,14 +601,17 @@
                 case IDLE:
                     createDefaultVideoFolderIfNotExist();
                     final PendingRecording pendingRecording;
-                    if (DeviceQuirks.get(MediaStoreVideoCannotWrite.class) != null) {
-                        // Use FileOutputOption for devices in MediaStoreVideoCannotWrite Quirk.
-                        pendingRecording = getVideoCapture().getOutput().prepareRecording(
-                                this, getNewVideoFileOutputOptions());
-                    } else {
+                    String fileName = "video_" + System.currentTimeMillis();
+                    String extension = "mp4";
+                    if (canDeviceWriteToMediaStore()) {
                         // Use MediaStoreOutputOptions for public share media storage.
                         pendingRecording = getVideoCapture().getOutput().prepareRecording(
-                                this, getNewVideoOutputMediaStoreOptions());
+                                this,
+                                generateVideoMediaStoreOptions(getContentResolver(), fileName));
+                    } else {
+                        // Use FileOutputOption for devices in MediaStoreVideoCannotWrite Quirk.
+                        pendingRecording = getVideoCapture().getOutput().prepareRecording(
+                                this, generateVideoFileOutputOptions(fileName, extension));
                     }
 
                     resetVideoSavedIdlingResource();
@@ -806,32 +814,6 @@
         }
     }
 
-    @NonNull
-    private MediaStoreOutputOptions getNewVideoOutputMediaStoreOptions() {
-        String videoFileName = "video_" + System.currentTimeMillis();
-        ContentValues contentValues = new ContentValues();
-        contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "video/mp4");
-        contentValues.put(MediaStore.Video.Media.TITLE, videoFileName);
-        contentValues.put(MediaStore.Video.Media.DISPLAY_NAME, videoFileName);
-        contentValues.put(MediaStore.Video.Media.DATE_ADDED, System.currentTimeMillis() / 1000);
-        contentValues.put(MediaStore.Video.Media.DATE_TAKEN, System.currentTimeMillis());
-        return new MediaStoreOutputOptions.Builder(getContentResolver(),
-                MediaStore.Video.Media.EXTERNAL_CONTENT_URI)
-                .setContentValues(contentValues)
-                .build();
-    }
-
-    @NonNull
-    private FileOutputOptions getNewVideoFileOutputOptions() {
-        String videoFileName = "video_" + System.currentTimeMillis() + ".mp4";
-        File videoFolder = Environment.getExternalStoragePublicDirectory(
-                Environment.DIRECTORY_MOVIES);
-        if (!videoFolder.exists() && !videoFolder.mkdirs()) {
-            Log.e(TAG, "Failed to create directory: " + videoFolder);
-        }
-        return new FileOutputOptions.Builder(new File(videoFolder, videoFileName)).build();
-    }
-
     private void updateRecordingStats(@NonNull RecordingStats stats) {
         double durationMs = TimeUnit.NANOSECONDS.toMillis(stats.getRecordedDurationNanos());
         // Show megabytes in International System of Units (SI)
@@ -890,7 +872,7 @@
                                                 Toast.LENGTH_SHORT).show());
                                         if (mSessionImagesUriSet != null) {
                                             mSessionImagesUriSet.add(
-                                                    Objects.requireNonNull(
+                                                    requireNonNull(
                                                             outputFileResults.getSavedUri()));
                                         }
                                     }
@@ -956,7 +938,7 @@
                     Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
                 }
             } catch (IllegalArgumentException e) {
-                Toast.makeText(this, "Failed to swich Camera. Error:" + e.getMessage(),
+                Toast.makeText(this, "Failed to switch Camera. Error:" + e.getMessage(),
                         Toast.LENGTH_SHORT).show();
             }
         });
@@ -1008,8 +990,8 @@
 
     private void setUpTorchButton() {
         mTorchButton.setOnClickListener(v -> {
-            Objects.requireNonNull(getCameraInfo());
-            Objects.requireNonNull(getCameraControl());
+            requireNonNull(getCameraInfo());
+            requireNonNull(getCameraControl());
             Integer torchState = getCameraInfo().getTorchState().getValue();
             boolean toggledState = !Objects.equals(torchState, TorchState.ON);
             Log.d(TAG, "Set camera torch: " + toggledState);
@@ -1029,8 +1011,8 @@
 
     private void setUpEVButton() {
         mPlusEV.setOnClickListener(v -> {
-            Objects.requireNonNull(getCameraInfo());
-            Objects.requireNonNull(getCameraControl());
+            requireNonNull(getCameraInfo());
+            requireNonNull(getCameraControl());
 
             ExposureState exposureState = getCameraInfo().getExposureState();
             Range<Integer> range = exposureState.getExposureCompensationRange();
@@ -1048,8 +1030,8 @@
         });
 
         mDecEV.setOnClickListener(v -> {
-            Objects.requireNonNull(getCameraInfo());
-            Objects.requireNonNull(getCameraControl());
+            requireNonNull(getCameraInfo());
+            requireNonNull(getCameraControl());
 
             ExposureState exposureState = getCameraInfo().getExposureState();
             Range<Integer> range = exposureState.getExposureCompensationRange();
@@ -1120,12 +1102,12 @@
                 ViewGroup.LayoutParams lp = viewFinderStub.getLayoutParams();
                 if (orientation == Configuration.ORIENTATION_PORTRAIT) {
                     lp.width = displayMetrics.widthPixels;
-                    lp.height = (int) (displayMetrics.widthPixels / ratio.getDenominator()
-                            * ratio.getNumerator());
+                    lp.height = displayMetrics.widthPixels / ratio.getDenominator()
+                            * ratio.getNumerator();
                 } else {
                     lp.height = displayMetrics.heightPixels;
-                    lp.width = (int) (displayMetrics.heightPixels / ratio.getDenominator()
-                            * ratio.getNumerator());
+                    lp.width = displayMetrics.heightPixels / ratio.getDenominator()
+                            * ratio.getNumerator();
                 }
                 viewFinderStub.setLayoutParams(lp);
             }
@@ -1329,7 +1311,7 @@
         };
 
         DisplayManager dpyMgr =
-                Objects.requireNonNull((DisplayManager) getSystemService(Context.DISPLAY_SERVICE));
+                requireNonNull(ContextCompat.getSystemService(this, DisplayManager.class));
         dpyMgr.registerDisplayListener(mDisplayListener, new Handler(Looper.getMainLooper()));
 
         StrictMode.VmPolicy vmPolicy =
@@ -1446,7 +1428,7 @@
     public void onDestroy() {
         super.onDestroy();
         DisplayManager dpyMgr =
-                Objects.requireNonNull((DisplayManager) getSystemService(Context.DISPLAY_SERVICE));
+                requireNonNull(ContextCompat.getSystemService(this, DisplayManager.class));
         dpyMgr.unregisterDisplayListener(mDisplayListener);
         mPreviewRenderer.shutdown();
         mImageCaptureExecutorService.shutdown();
@@ -1577,12 +1559,9 @@
         // Remove ImageAnalysis to check whether the new use cases combination can be supported.
         if (mAnalysisToggle.isChecked()) {
             mAnalysisToggle.setChecked(false);
-            if (isCheckedUseCasesCombinationSupported()) {
-                return;
-            }
+            // No need to do further use case combination check since Preview + ImageCapture
+            // should be always supported.
         }
-
-        // Preview + ImageCapture should be always supported.
     }
 
     /**
@@ -1687,7 +1666,7 @@
                             new ActivityResultContracts.RequestMultiplePermissions(),
                             result -> {
                                 for (String permission : REQUIRED_PERMISSIONS) {
-                                    if (!Objects.requireNonNull(result.get(permission))) {
+                                    if (!requireNonNull(result.get(permission))) {
                                         Toast.makeText(getApplicationContext(),
                                                         "Camera permission denied.",
                                                         Toast.LENGTH_SHORT)
@@ -1720,10 +1699,8 @@
     void createDefaultPictureFolderIfNotExist() {
         File pictureFolder = Environment.getExternalStoragePublicDirectory(
                 Environment.DIRECTORY_PICTURES);
-        if (!pictureFolder.exists()) {
-            if (!pictureFolder.mkdir()) {
-                Log.e(TAG, "Failed to create directory: " + pictureFolder);
-            }
+        if (createParentFolder(pictureFolder)) {
+            Log.e(TAG, "Failed to create directory: " + pictureFolder);
         }
     }
 
@@ -1732,17 +1709,8 @@
         String videoFilePath =
                 getAbsolutePathFromUri(getApplicationContext().getContentResolver(),
                         MediaStore.Video.Media.EXTERNAL_CONTENT_URI);
-
-        // If cannot get the video path, just skip checking and create folder.
-        if (videoFilePath == null) {
-            return;
-        }
-        File videoFile = new File(videoFilePath);
-
-        if (videoFile.getParentFile() != null && !videoFile.getParentFile().exists()) {
-            if (!videoFile.getParentFile().mkdir()) {
-                Log.e(TAG, "Failed to create directory: " + videoFile);
-            }
+        if (videoFilePath == null || !createParentFolder(videoFilePath)) {
+            Log.e(TAG, "Failed to create parent directory for: " + videoFilePath);
         }
     }
 
@@ -1778,13 +1746,14 @@
     ScaleGestureDetector.SimpleOnScaleGestureListener mScaleGestureListener =
             new ScaleGestureDetector.SimpleOnScaleGestureListener() {
                 @Override
-                public boolean onScale(ScaleGestureDetector detector) {
+                public boolean onScale(@NonNull ScaleGestureDetector detector) {
                     if (mCamera == null) {
                         return true;
                     }
 
                     CameraInfo cameraInfo = mCamera.getCameraInfo();
-                    float newZoom = cameraInfo.getZoomState().getValue().getZoomRatio()
+                    float newZoom =
+                            requireNonNull(cameraInfo.getZoomState().getValue()).getZoomRatio()
                             * detector.getScaleFactor();
                     setZoomRatio(newZoom);
                     return true;
@@ -1794,7 +1763,7 @@
     GestureDetector.OnGestureListener onTapGestureListener =
             new GestureDetector.SimpleOnGestureListener() {
                 @Override
-                public boolean onSingleTapUp(MotionEvent e) {
+                public boolean onSingleTapUp(@NonNull MotionEvent e) {
                     if (mCamera == null) {
                         return false;
                     }
@@ -1834,7 +1803,8 @@
 
         mZoomSeekBar.setMax(MAX_SEEKBAR_VALUE);
         mZoomSeekBar.setProgress(
-                (int) (cameraInfo.getZoomState().getValue().getLinearZoom() * MAX_SEEKBAR_VALUE));
+                (int) (requireNonNull(cameraInfo.getZoomState().getValue()).getLinearZoom()
+                        * MAX_SEEKBAR_VALUE));
         mZoomSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
             @Override
             public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
@@ -1884,7 +1854,7 @@
     private boolean is2XZoomSupported() {
         CameraInfo cameraInfo = getCameraInfo();
         return cameraInfo != null
-                && cameraInfo.getZoomState().getValue().getMaxZoomRatio() >= 2.0f;
+                && requireNonNull(cameraInfo.getZoomState().getValue()).getMaxZoomRatio() >= 2.0f;
     }
 
     private void setUpZoomButton() {
@@ -1901,7 +1871,7 @@
         CameraInfo cameraInfo = mCamera.getCameraInfo();
         CameraControl cameraControl = mCamera.getCameraControl();
         float clampedNewZoom = MathUtils.clamp(newZoom,
-                cameraInfo.getZoomState().getValue().getMinZoomRatio(),
+                requireNonNull(cameraInfo.getZoomState().getValue()).getMinZoomRatio(),
                 cameraInfo.getZoomState().getValue().getMaxZoomRatio());
 
         Log.d(TAG, "setZoomRatio ratio: " + clampedNewZoom);
@@ -1932,34 +1902,6 @@
         });
     }
 
-    /** Gets the absolute path from a Uri. */
-    @Nullable
-    public String getAbsolutePathFromUri(@NonNull ContentResolver resolver,
-            @NonNull Uri contentUri) {
-        Cursor cursor = null;
-        try {
-            // We should include in any Media collections.
-            String[] proj;
-            int columnIndex;
-            // MediaStore.Video.Media.DATA was deprecated in API level 29.
-            proj = new String[]{MediaStore.Video.Media.DATA};
-            cursor = resolver.query(contentUri, proj, null, null, null);
-            columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA);
-
-            cursor.moveToFirst();
-            return cursor.getString(columnIndex);
-        } catch (RuntimeException e) {
-            Log.e(TAG, String.format(
-                    "Failed in getting absolute path for Uri %s with Exception %s",
-                    contentUri, e));
-            return "";
-        } finally {
-            if (cursor != null) {
-                cursor.close();
-            }
-        }
-    }
-
     private class SessionMediaUriSet {
         private final Set<Uri> mSessionMediaUris;
 
diff --git a/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/CameraXService.java b/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/CameraXService.java
index 45f7201..4e5333c 100644
--- a/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/CameraXService.java
+++ b/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/CameraXService.java
@@ -17,15 +17,21 @@
 package androidx.camera.integration.core;
 
 import static androidx.camera.core.CameraSelector.DEFAULT_BACK_CAMERA;
+import static androidx.camera.testing.impl.FileUtil.createParentFolder;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
 import android.app.NotificationChannel;
 import android.app.NotificationManager;
+import android.content.ContentValues;
 import android.content.Intent;
+import android.net.Uri;
 import android.os.Binder;
 import android.os.Build;
+import android.os.Environment;
 import android.os.IBinder;
+import android.os.SystemClock;
+import android.provider.MediaStore;
 import android.util.Log;
 
 import androidx.annotation.DoNotInline;
@@ -35,6 +41,7 @@
 import androidx.annotation.VisibleForTesting;
 import androidx.camera.core.ImageAnalysis;
 import androidx.camera.core.ImageCapture;
+import androidx.camera.core.ImageCaptureException;
 import androidx.camera.core.UseCase;
 import androidx.camera.core.UseCaseGroup;
 import androidx.camera.lifecycle.ProcessCameraProvider;
@@ -47,9 +54,18 @@
 
 import com.google.common.util.concurrent.ListenableFuture;
 
+import java.io.File;
+import java.text.Format;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutionException;
 
@@ -64,6 +80,8 @@
     // Actions
     public static final String ACTION_BIND_USE_CASES =
             "androidx.camera.integration.core.intent.action.BIND_USE_CASES";
+    public static final String ACTION_TAKE_PICTURE =
+            "androidx.camera.integration.core.intent.action.TAKE_PICTURE";
 
     // Extras
     public static final String EXTRA_VIDEO_CAPTURE_ENABLED = "EXTRA_VIDEO_CAPTURE_ENABLED";
@@ -73,12 +91,22 @@
     private final IBinder mBinder = new CameraXServiceBinder();
 
     ////////////////////////////////////////////////////////////////////////////////////////////////
+    //                          Members only accessed on main thread                              //
+    ////////////////////////////////////////////////////////////////////////////////////////////////
+    private final Map<Class<?>, UseCase> mBoundUseCases = new HashMap<>();
+    //--------------------------------------------------------------------------------------------//
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////
     //                                   Members for testing                                      //
     ////////////////////////////////////////////////////////////////////////////////////////////////
+    private final Set<Uri> mSavedImageUri = new HashSet<>();
+
     @Nullable
     private Consumer<Collection<UseCase>> mOnUseCaseBoundCallback;
     @Nullable
     private CountDownLatch mAnalysisFrameLatch;
+    @Nullable
+    private CountDownLatch mTakePictureLatch;
     //--------------------------------------------------------------------------------------------//
 
     @Override
@@ -101,6 +129,8 @@
             Log.d(TAG, "onStartCommand: action = " + action + ", extras = " + intent.getExtras());
             if (ACTION_BIND_USE_CASES.equals(action)) {
                 bindToLifecycle(intent);
+            } else if (ACTION_TAKE_PICTURE.equals(action)) {
+                takePicture();
             }
         }
         return super.onStartCommand(intent, flags, startId);
@@ -125,6 +155,7 @@
             throw new IllegalStateException(e);
         }
         cameraProvider.unbindAll();
+        mBoundUseCases.clear();
         UseCaseGroup useCaseGroup = resolveUseCaseGroup(intent);
         List<UseCase> boundUseCases = Collections.emptyList();
         if (useCaseGroup != null) {
@@ -136,6 +167,9 @@
             }
         }
         Log.d(TAG, "Bound UseCases: " + boundUseCases);
+        for (UseCase boundUseCase : boundUseCases) {
+            mBoundUseCases.put(boundUseCase.getClass(), boundUseCase);
+        }
         if (mOnUseCaseBoundCallback != null) {
             mOnUseCaseBoundCallback.accept(boundUseCases);
         }
@@ -183,6 +217,61 @@
         return checkNotNull(ContextCompat.getSystemService(this, NotificationManager.class));
     }
 
+    @Nullable
+    private ImageCapture getImageCapture() {
+        return (ImageCapture) mBoundUseCases.get(ImageCapture.class);
+    }
+
+    private void takePicture() {
+        ImageCapture imageCapture = getImageCapture();
+        if (imageCapture == null) {
+            Log.w(TAG, "ImageCapture is not bound.");
+            return;
+        }
+        createDefaultPictureFolderIfNotExist();
+        Format formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss-SSS", Locale.US);
+        String fileName = "ServiceTestApp-" + formatter.format(Calendar.getInstance().getTime())
+                + ".jpg";
+        ContentValues contentValues = new ContentValues();
+        contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, fileName);
+        contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg");
+        ImageCapture.OutputFileOptions outputFileOptions =
+                new ImageCapture.OutputFileOptions.Builder(
+                        getContentResolver(),
+                        MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
+                        contentValues).build();
+        long startTimeMs = SystemClock.elapsedRealtime();
+        imageCapture.takePicture(outputFileOptions,
+                ContextCompat.getMainExecutor(this),
+                new ImageCapture.OnImageSavedCallback() {
+                    @Override
+                    public void onImageSaved(
+                            @NonNull ImageCapture.OutputFileResults outputFileResults) {
+                        long durationMs = SystemClock.elapsedRealtime() - startTimeMs;
+                        Log.d(TAG, "Saved image " + outputFileResults.getSavedUri()
+                                + "  (" + durationMs + " ms)");
+                        mSavedImageUri.add(outputFileResults.getSavedUri());
+                        if (mTakePictureLatch != null) {
+                            mTakePictureLatch.countDown();
+                        }
+                    }
+
+                    @Override
+                    public void onError(@NonNull ImageCaptureException exception) {
+                        Log.e(TAG, "Failed to save image by " + exception.getImageCaptureError(),
+                                exception);
+                    }
+                });
+    }
+
+    private void createDefaultPictureFolderIfNotExist() {
+        File pictureFolder = Environment.getExternalStoragePublicDirectory(
+                Environment.DIRECTORY_PICTURES);
+        if (!createParentFolder(pictureFolder)) {
+            Log.e(TAG, "Failed to create directory: " + pictureFolder);
+        }
+    }
+
     private final ImageAnalysis.Analyzer mAnalyzer = image -> {
         if (mAnalysisFrameLatch != null) {
             mAnalysisFrameLatch.countDown();
@@ -217,11 +306,34 @@
     }
 
     @VisibleForTesting
+    @NonNull
     CountDownLatch acquireAnalysisFrameCountDownLatch() {
         mAnalysisFrameLatch = new CountDownLatch(3);
         return mAnalysisFrameLatch;
     }
 
+    @VisibleForTesting
+    @NonNull
+    CountDownLatch acquireTakePictureCountDownLatch() {
+        mTakePictureLatch = new CountDownLatch(1);
+        return mTakePictureLatch;
+    }
+
+    @VisibleForTesting
+    void deleteSavedMediaFiles() {
+        deleteUriSet(mSavedImageUri);
+    }
+
+    private void deleteUriSet(@NonNull Set<Uri> uriSet) {
+        for (Uri uri : uriSet) {
+            try {
+                getContentResolver().delete(uri, null, null);
+            } catch (RuntimeException e) {
+                Log.w(TAG, "Unable to delete uri: " + uri, e);
+            }
+        }
+    }
+
     class CameraXServiceBinder extends Binder {
         @NonNull
         CameraXService getService() {
diff --git a/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/CameraXViewModel.java b/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/CameraXViewModel.java
index 61a1f09..620f7e0 100644
--- a/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/CameraXViewModel.java
+++ b/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/CameraXViewModel.java
@@ -107,7 +107,7 @@
     @OptIn(markerClass = ExperimentalCameraProviderConfiguration.class)
     @MainThread
     public static boolean isCameraProviderUnInitializedOrSameAsParameter(
-            @NonNull String cameraImplementation) {
+            @Nullable String cameraImplementation) {
 
         if (sConfiguredCameraXCameraImplementation == null) {
             return true;
@@ -116,11 +116,7 @@
                 sConfiguredCameraXCameraImplementation);
         cameraImplementation = getCameraProviderName(cameraImplementation);
 
-        if (currentCameraProvider.equals(cameraImplementation)) {
-            return true;
-        }
-
-        return false;
+        return currentCameraProvider.equals(cameraImplementation);
     }
 
     /**
@@ -129,7 +125,7 @@
      */
     @OptIn(markerClass = ExperimentalCameraProviderConfiguration.class)
     @MainThread
-    private static String getCameraProviderName(String mCameraProvider) {
+    private static String getCameraProviderName(@Nullable String mCameraProvider) {
         if (mCameraProvider == null) {
             mCameraProvider = CAMERA2_IMPLEMENTATION_OPTION;
         }
diff --git a/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/VideoCameraSwitchingActivity.java b/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/VideoCameraSwitchingActivity.java
index c775b3d..976b5f3 100644
--- a/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/VideoCameraSwitchingActivity.java
+++ b/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/VideoCameraSwitchingActivity.java
@@ -33,7 +33,7 @@
 import androidx.camera.core.Logger;
 import androidx.camera.core.Preview;
 import androidx.camera.lifecycle.ProcessCameraProvider;
-import androidx.camera.testing.impl.E2ETestUtil;
+import androidx.camera.testing.impl.FileUtil;
 import androidx.camera.video.ExperimentalPersistentRecording;
 import androidx.camera.video.PendingRecording;
 import androidx.camera.video.Recorder;
@@ -232,14 +232,14 @@
 
         final String videoFileName = generateFileName(VIDEO_FILE_PREFIX, true);
         final PendingRecording pendingRecording;
-        if (E2ETestUtil.canDeviceWriteToMediaStore()) {
+        if (FileUtil.canDeviceWriteToMediaStore()) {
             // Use MediaStoreOutputOptions for public share media storage.
             pendingRecording = mVideoCapture.getOutput().prepareRecording(this,
-                    E2ETestUtil.generateVideoMediaStoreOptions(this.getContentResolver(),
+                    FileUtil.generateVideoMediaStoreOptions(this.getContentResolver(),
                             videoFileName));
         } else {
             pendingRecording = mVideoCapture.getOutput().prepareRecording(this,
-                    E2ETestUtil.generateVideoFileOutputOptions(videoFileName, "mp4"));
+                    FileUtil.generateVideoFileOutputOptions(videoFileName, "mp4"));
         }
         mRecording = pendingRecording
                 .asPersistentRecording() // Perform the recording as a persistent recording.
@@ -274,17 +274,17 @@
 
     private void exportTestInformation() {
         String information = KEY_DEVICE_ORIENTATION + ": " + mDeviceOrientation;
-        E2ETestUtil.writeTextToExternalFile(information,
+        FileUtil.writeTextToExternalFile(information,
                 generateFileName(INFO_FILE_PREFIX, false), "txt");
     }
 
     @NonNull
     private String generateFileName(@Nullable String prefix, boolean isUnique) {
-        if (!isUnique && !E2ETestUtil.isFileNameValid(prefix)) {
+        if (!isUnique && !FileUtil.isFileNameValid(prefix)) {
             throw new IllegalArgumentException("Invalid arguments for generating file name.");
         }
         StringBuilder fileName = new StringBuilder();
-        if (E2ETestUtil.isFileNameValid(prefix)) {
+        if (FileUtil.isFileNameValid(prefix)) {
             fileName.append(prefix);
             if (isUnique) {
                 fileName.append("_");
diff --git a/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/viewpager/ViewPagerActivityTest.kt b/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/viewpager/ViewPagerActivityTest.kt
index e3dc0e9..49a518d 100644
--- a/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/viewpager/ViewPagerActivityTest.kt
+++ b/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/viewpager/ViewPagerActivityTest.kt
@@ -39,7 +39,6 @@
 import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
 import androidx.test.espresso.matcher.ViewMatchers.withId
 import androidx.test.espresso.matcher.ViewMatchers.withText
-import androidx.test.filters.FlakyTest
 import androidx.test.filters.LargeTest
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
@@ -146,7 +145,6 @@
     }
 
     // The test makes sure the TextureView surface texture keeps the same after switch.
-    @FlakyTest(bugId = 230873000)
     @Test
     fun testPreviewViewUpdateAfterSwitch() {
         launchActivity(lensFacing, cameraXConfig).use { scenario ->
diff --git a/camera/integration-tests/viewtestapp/lint-baseline.xml b/camera/integration-tests/viewtestapp/lint-baseline.xml
index acea7110..cfacbf5 100644
--- a/camera/integration-tests/viewtestapp/lint-baseline.xml
+++ b/camera/integration-tests/viewtestapp/lint-baseline.xml
@@ -264,7 +264,7 @@
 
     <issue
         id="RestrictedApiAndroidX"
-        message="E2ETestUtil.canDeviceWriteToMediaStore can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
+        message="FileUtil.canDeviceWriteToMediaStore can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
         errorLine1="        return if (canDeviceWriteToMediaStore()) {"
         errorLine2="                   ~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
@@ -273,7 +273,7 @@
 
     <issue
         id="RestrictedApiAndroidX"
-        message="E2ETestUtil.generateVideoMediaStoreOptions can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
+        message="FileUtil.generateVideoMediaStoreOptions can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
         errorLine1="                generateVideoMediaStoreOptions(context.contentResolver, fileName)"
         errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
@@ -282,7 +282,7 @@
 
     <issue
         id="RestrictedApiAndroidX"
-        message="E2ETestUtil.generateVideoMediaStoreOptions can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
+        message="FileUtil.generateVideoMediaStoreOptions can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
         errorLine1="                generateVideoMediaStoreOptions(context.contentResolver, fileName)"
         errorLine2="                                               ~~~~~~~~~~~~~~~~~~~~~~~">
         <location
@@ -291,7 +291,7 @@
 
     <issue
         id="RestrictedApiAndroidX"
-        message="E2ETestUtil.generateVideoMediaStoreOptions can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
+        message="FileUtil.generateVideoMediaStoreOptions can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
         errorLine1="                generateVideoMediaStoreOptions(context.contentResolver, fileName)"
         errorLine2="                                                                        ~~~~~~~~">
         <location
@@ -300,7 +300,7 @@
 
     <issue
         id="RestrictedApiAndroidX"
-        message="E2ETestUtil.generateVideoFileOutputOptions can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
+        message="FileUtil.generateVideoFileOutputOptions can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
         errorLine1="            recorder.prepareRecording(context, generateVideoFileOutputOptions(fileName))"
         errorLine2="                                               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
@@ -309,7 +309,7 @@
 
     <issue
         id="RestrictedApiAndroidX"
-        message="E2ETestUtil.generateVideoFileOutputOptions can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
+        message="FileUtil.generateVideoFileOutputOptions can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
         errorLine1="            recorder.prepareRecording(context, generateVideoFileOutputOptions(fileName))"
         errorLine2="                                                                              ~~~~~~~~">
         <location
@@ -318,7 +318,7 @@
 
     <issue
         id="RestrictedApiAndroidX"
-        message="E2ETestUtil.writeTextToExternalFile can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
+        message="FileUtil.writeTextToExternalFile can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
         errorLine1="        writeTextToExternalFile(information, fileName)"
         errorLine2="        ~~~~~~~~~~~~~~~~~~~~~~~">
         <location
@@ -327,7 +327,7 @@
 
     <issue
         id="RestrictedApiAndroidX"
-        message="E2ETestUtil.writeTextToExternalFile can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
+        message="FileUtil.writeTextToExternalFile can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
         errorLine1="        writeTextToExternalFile(information, fileName)"
         errorLine2="                                ~~~~~~~~~~~">
         <location
@@ -336,7 +336,7 @@
 
     <issue
         id="RestrictedApiAndroidX"
-        message="E2ETestUtil.writeTextToExternalFile can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
+        message="FileUtil.writeTextToExternalFile can only be called from within the same library group (referenced groupId=`androidx.camera` from groupId=`androidx.camera.integration-tests`)"
         errorLine1="        writeTextToExternalFile(information, fileName)"
         errorLine2="                                             ~~~~~~~~">
         <location
diff --git a/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/StreamSharingActivity.kt b/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/StreamSharingActivity.kt
index a593ec0..6577ce6 100644
--- a/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/StreamSharingActivity.kt
+++ b/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/StreamSharingActivity.kt
@@ -33,10 +33,10 @@
 import androidx.camera.core.UseCase
 import androidx.camera.core.impl.utils.executor.CameraXExecutors
 import androidx.camera.lifecycle.ProcessCameraProvider
-import androidx.camera.testing.impl.E2ETestUtil.canDeviceWriteToMediaStore
-import androidx.camera.testing.impl.E2ETestUtil.generateVideoFileOutputOptions
-import androidx.camera.testing.impl.E2ETestUtil.generateVideoMediaStoreOptions
-import androidx.camera.testing.impl.E2ETestUtil.writeTextToExternalFile
+import androidx.camera.testing.impl.FileUtil.canDeviceWriteToMediaStore
+import androidx.camera.testing.impl.FileUtil.generateVideoFileOutputOptions
+import androidx.camera.testing.impl.FileUtil.generateVideoMediaStoreOptions
+import androidx.camera.testing.impl.FileUtil.writeTextToExternalFile
 import androidx.camera.video.PendingRecording
 import androidx.camera.video.Recorder
 import androidx.camera.video.Recording
diff --git a/collection/collection/api/current.txt b/collection/collection/api/current.txt
index 5bcab89..313ca38 100644
--- a/collection/collection/api/current.txt
+++ b/collection/collection/api/current.txt
@@ -563,6 +563,58 @@
     method @IntRange(from=0L) public int trim();
   }
 
+  public final class MutableObjectList<E> extends androidx.collection.ObjectList<E> {
+    ctor public MutableObjectList(optional int initialCapacity);
+    method public boolean add(E element);
+    method public void add(@IntRange(from=0L) int index, E element);
+    method public boolean addAll(androidx.collection.ObjectList<E> elements);
+    method public boolean addAll(androidx.collection.ScatterSet<E> elements);
+    method public boolean addAll(E![] elements);
+    method public boolean addAll(@IntRange(from=0L) int index, androidx.collection.ObjectList<E> elements);
+    method public boolean addAll(@IntRange(from=0L) int index, E![] elements);
+    method public boolean addAll(@IntRange(from=0L) int index, java.util.Collection<? extends E> elements);
+    method public boolean addAll(Iterable<? extends E> elements);
+    method public boolean addAll(java.util.List<? extends E> elements);
+    method public boolean addAll(kotlin.sequences.Sequence<? extends E> elements);
+    method public java.util.List<E> asList();
+    method public java.util.List<E> asMutableList();
+    method public void clear();
+    method public void ensureCapacity(int capacity);
+    method public inline int getCapacity();
+    method public operator void minusAssign(androidx.collection.ObjectList<E> elements);
+    method public operator void minusAssign(androidx.collection.ScatterSet<E> elements);
+    method public inline operator void minusAssign(E element);
+    method public operator void minusAssign(E![] elements);
+    method public operator void minusAssign(Iterable<? extends E> elements);
+    method public operator void minusAssign(java.util.List<? extends E> elements);
+    method public operator void minusAssign(kotlin.sequences.Sequence<? extends E> elements);
+    method public operator void plusAssign(androidx.collection.ObjectList<E> elements);
+    method public operator void plusAssign(androidx.collection.ScatterSet<E> elements);
+    method public inline operator void plusAssign(E element);
+    method public operator void plusAssign(E![] elements);
+    method public operator void plusAssign(Iterable<? extends E> elements);
+    method public operator void plusAssign(java.util.List<? extends E> elements);
+    method public operator void plusAssign(kotlin.sequences.Sequence<? extends E> elements);
+    method public boolean remove(E element);
+    method public boolean removeAll(androidx.collection.ObjectList<E> elements);
+    method public boolean removeAll(androidx.collection.ScatterSet<E> elements);
+    method public boolean removeAll(E![] elements);
+    method public boolean removeAll(Iterable<? extends E> elements);
+    method public boolean removeAll(java.util.List<? extends E> elements);
+    method public boolean removeAll(kotlin.sequences.Sequence<? extends E> elements);
+    method public E removeAt(@IntRange(from=0L) int index);
+    method public inline void removeIf(kotlin.jvm.functions.Function1<? super E,java.lang.Boolean> predicate);
+    method public void removeRange(@IntRange(from=0L) int start, @IntRange(from=0L) int end);
+    method public boolean retainAll(androidx.collection.ObjectList<E> elements);
+    method public boolean retainAll(E![] elements);
+    method public boolean retainAll(Iterable<? extends E> elements);
+    method public boolean retainAll(java.util.Collection<? extends E> elements);
+    method public boolean retainAll(kotlin.sequences.Sequence<? extends E> elements);
+    method public operator E set(@IntRange(from=0L) int index, E element);
+    method public void trim(optional int minCapacity);
+    property public final inline int capacity;
+  }
+
   public final class MutableScatterMap<K, V> extends androidx.collection.ScatterMap<K,V> {
     ctor public MutableScatterMap(optional int initialCapacity);
     method public java.util.Map<K,V> asMutableMap();
@@ -619,6 +671,66 @@
     method @IntRange(from=0L) public int trim();
   }
 
+  public abstract sealed class ObjectList<E> {
+    method public final boolean any();
+    method public final inline boolean any(kotlin.jvm.functions.Function1<? super E,java.lang.Boolean> predicate);
+    method public abstract java.util.List<E> asList();
+    method public final operator boolean contains(E element);
+    method public final boolean containsAll(androidx.collection.ObjectList<E> elements);
+    method public final boolean containsAll(E![] elements);
+    method public final boolean containsAll(Iterable<? extends E> elements);
+    method public final boolean containsAll(java.util.List<? extends E> elements);
+    method public final int count();
+    method public final inline int count(kotlin.jvm.functions.Function1<? super E,java.lang.Boolean> predicate);
+    method public final E elementAt(@IntRange(from=0L) int index);
+    method public final inline E elementAtOrElse(@IntRange(from=0L) int index, kotlin.jvm.functions.Function1<? super java.lang.Integer,? extends E> defaultValue);
+    method public final E first();
+    method public final inline E first(kotlin.jvm.functions.Function1<? super E,java.lang.Boolean> predicate);
+    method public final inline E? firstOrNull();
+    method public final inline E? firstOrNull(kotlin.jvm.functions.Function1<? super E,java.lang.Boolean> predicate);
+    method public final inline <R> R fold(R initial, kotlin.jvm.functions.Function2<? super R,? super E,? extends R> operation);
+    method public final inline <R> R foldIndexed(R initial, kotlin.jvm.functions.Function3<? super java.lang.Integer,? super R,? super E,? extends R> operation);
+    method public final inline <R> R foldRight(R initial, kotlin.jvm.functions.Function2<? super E,? super R,? extends R> operation);
+    method public final inline <R> R foldRightIndexed(R initial, kotlin.jvm.functions.Function3<? super java.lang.Integer,? super E,? super R,? extends R> operation);
+    method public final inline void forEach(kotlin.jvm.functions.Function1<? super E,kotlin.Unit> block);
+    method public final inline void forEachIndexed(kotlin.jvm.functions.Function2<? super java.lang.Integer,? super E,kotlin.Unit> block);
+    method public final inline void forEachReversed(kotlin.jvm.functions.Function1<? super E,kotlin.Unit> block);
+    method public final inline void forEachReversedIndexed(kotlin.jvm.functions.Function2<? super java.lang.Integer,? super E,kotlin.Unit> block);
+    method public final operator E get(@IntRange(from=0L) int index);
+    method public final inline kotlin.ranges.IntRange getIndices();
+    method @IntRange(from=-1L) public final inline int getLastIndex();
+    method @IntRange(from=0L) public final int getSize();
+    method public final int indexOf(E element);
+    method public final inline int indexOfFirst(kotlin.jvm.functions.Function1<? super E,java.lang.Boolean> predicate);
+    method public final inline int indexOfLast(kotlin.jvm.functions.Function1<? super E,java.lang.Boolean> predicate);
+    method public final boolean isEmpty();
+    method public final boolean isNotEmpty();
+    method public final E last();
+    method public final inline E last(kotlin.jvm.functions.Function1<? super E,java.lang.Boolean> predicate);
+    method public final int lastIndexOf(E element);
+    method public final inline E? lastOrNull();
+    method public final inline E? lastOrNull(kotlin.jvm.functions.Function1<? super E,java.lang.Boolean> predicate);
+    method public final boolean none();
+    method public final inline boolean reversedAny(kotlin.jvm.functions.Function1<? super E,java.lang.Boolean> predicate);
+    property public final inline kotlin.ranges.IntRange indices;
+    property @IntRange(from=-1L) public final inline int lastIndex;
+    property @IntRange(from=0L) public final int size;
+  }
+
+  public final class ObjectListKt {
+    method public static <E> androidx.collection.ObjectList<E> emptyObjectList();
+    method public static inline <E> androidx.collection.MutableObjectList<E> mutableObjectListOf();
+    method public static <E> androidx.collection.MutableObjectList<E> mutableObjectListOf(E element1);
+    method public static <E> androidx.collection.MutableObjectList<E> mutableObjectListOf(E element1, E element2);
+    method public static <E> androidx.collection.MutableObjectList<E> mutableObjectListOf(E element1, E element2, E element3);
+    method public static inline <E> androidx.collection.MutableObjectList<E> mutableObjectListOf(E?... elements);
+    method public static <E> androidx.collection.ObjectList<E> objectListOf();
+    method public static <E> androidx.collection.ObjectList<E> objectListOf(E element1);
+    method public static <E> androidx.collection.ObjectList<E> objectListOf(E element1, E element2);
+    method public static <E> androidx.collection.ObjectList<E> objectListOf(E element1, E element2, E element3);
+    method public static <E> androidx.collection.ObjectList<E> objectListOf(E?... elements);
+  }
+
   @kotlin.jvm.JvmInline public final value class PairFloatFloat {
     ctor public PairFloatFloat(float first, float second);
     method public inline operator float component1();
diff --git a/collection/collection/api/restricted_current.txt b/collection/collection/api/restricted_current.txt
index a46df5c..9847883 100644
--- a/collection/collection/api/restricted_current.txt
+++ b/collection/collection/api/restricted_current.txt
@@ -578,6 +578,58 @@
     method @IntRange(from=0L) public int trim();
   }
 
+  public final class MutableObjectList<E> extends androidx.collection.ObjectList<E> {
+    ctor public MutableObjectList(optional int initialCapacity);
+    method public boolean add(E element);
+    method public void add(@IntRange(from=0L) int index, E element);
+    method public boolean addAll(androidx.collection.ObjectList<E> elements);
+    method public boolean addAll(androidx.collection.ScatterSet<E> elements);
+    method public boolean addAll(E![] elements);
+    method public boolean addAll(@IntRange(from=0L) int index, androidx.collection.ObjectList<E> elements);
+    method public boolean addAll(@IntRange(from=0L) int index, E![] elements);
+    method public boolean addAll(@IntRange(from=0L) int index, java.util.Collection<? extends E> elements);
+    method public boolean addAll(Iterable<? extends E> elements);
+    method public boolean addAll(java.util.List<? extends E> elements);
+    method public boolean addAll(kotlin.sequences.Sequence<? extends E> elements);
+    method public java.util.List<E> asList();
+    method public java.util.List<E> asMutableList();
+    method public void clear();
+    method public void ensureCapacity(int capacity);
+    method public inline int getCapacity();
+    method public operator void minusAssign(androidx.collection.ObjectList<E> elements);
+    method public operator void minusAssign(androidx.collection.ScatterSet<E> elements);
+    method public inline operator void minusAssign(E element);
+    method public operator void minusAssign(E![] elements);
+    method public operator void minusAssign(Iterable<? extends E> elements);
+    method public operator void minusAssign(java.util.List<? extends E> elements);
+    method public operator void minusAssign(kotlin.sequences.Sequence<? extends E> elements);
+    method public operator void plusAssign(androidx.collection.ObjectList<E> elements);
+    method public operator void plusAssign(androidx.collection.ScatterSet<E> elements);
+    method public inline operator void plusAssign(E element);
+    method public operator void plusAssign(E![] elements);
+    method public operator void plusAssign(Iterable<? extends E> elements);
+    method public operator void plusAssign(java.util.List<? extends E> elements);
+    method public operator void plusAssign(kotlin.sequences.Sequence<? extends E> elements);
+    method public boolean remove(E element);
+    method public boolean removeAll(androidx.collection.ObjectList<E> elements);
+    method public boolean removeAll(androidx.collection.ScatterSet<E> elements);
+    method public boolean removeAll(E![] elements);
+    method public boolean removeAll(Iterable<? extends E> elements);
+    method public boolean removeAll(java.util.List<? extends E> elements);
+    method public boolean removeAll(kotlin.sequences.Sequence<? extends E> elements);
+    method public E removeAt(@IntRange(from=0L) int index);
+    method public inline void removeIf(kotlin.jvm.functions.Function1<? super E,java.lang.Boolean> predicate);
+    method public void removeRange(@IntRange(from=0L) int start, @IntRange(from=0L) int end);
+    method public boolean retainAll(androidx.collection.ObjectList<E> elements);
+    method public boolean retainAll(E![] elements);
+    method public boolean retainAll(Iterable<? extends E> elements);
+    method public boolean retainAll(java.util.Collection<? extends E> elements);
+    method public boolean retainAll(kotlin.sequences.Sequence<? extends E> elements);
+    method public operator E set(@IntRange(from=0L) int index, E element);
+    method public void trim(optional int minCapacity);
+    property public final inline int capacity;
+  }
+
   public final class MutableScatterMap<K, V> extends androidx.collection.ScatterMap<K,V> {
     ctor public MutableScatterMap(optional int initialCapacity);
     method public java.util.Map<K,V> asMutableMap();
@@ -635,6 +687,68 @@
     method @IntRange(from=0L) public int trim();
   }
 
+  public abstract sealed class ObjectList<E> {
+    method public final boolean any();
+    method public final inline boolean any(kotlin.jvm.functions.Function1<? super E,java.lang.Boolean> predicate);
+    method public abstract java.util.List<E> asList();
+    method public final operator boolean contains(E element);
+    method public final boolean containsAll(androidx.collection.ObjectList<E> elements);
+    method public final boolean containsAll(E![] elements);
+    method public final boolean containsAll(Iterable<? extends E> elements);
+    method public final boolean containsAll(java.util.List<? extends E> elements);
+    method public final int count();
+    method public final inline int count(kotlin.jvm.functions.Function1<? super E,java.lang.Boolean> predicate);
+    method public final E elementAt(@IntRange(from=0L) int index);
+    method public final inline E elementAtOrElse(@IntRange(from=0L) int index, kotlin.jvm.functions.Function1<? super java.lang.Integer,? extends E> defaultValue);
+    method public final E first();
+    method public final inline E first(kotlin.jvm.functions.Function1<? super E,java.lang.Boolean> predicate);
+    method public final inline E? firstOrNull();
+    method public final inline E? firstOrNull(kotlin.jvm.functions.Function1<? super E,java.lang.Boolean> predicate);
+    method public final inline <R> R fold(R initial, kotlin.jvm.functions.Function2<? super R,? super E,? extends R> operation);
+    method public final inline <R> R foldIndexed(R initial, kotlin.jvm.functions.Function3<? super java.lang.Integer,? super R,? super E,? extends R> operation);
+    method public final inline <R> R foldRight(R initial, kotlin.jvm.functions.Function2<? super E,? super R,? extends R> operation);
+    method public final inline <R> R foldRightIndexed(R initial, kotlin.jvm.functions.Function3<? super java.lang.Integer,? super E,? super R,? extends R> operation);
+    method public final inline void forEach(kotlin.jvm.functions.Function1<? super E,kotlin.Unit> block);
+    method public final inline void forEachIndexed(kotlin.jvm.functions.Function2<? super java.lang.Integer,? super E,kotlin.Unit> block);
+    method public final inline void forEachReversed(kotlin.jvm.functions.Function1<? super E,kotlin.Unit> block);
+    method public final inline void forEachReversedIndexed(kotlin.jvm.functions.Function2<? super java.lang.Integer,? super E,kotlin.Unit> block);
+    method public final operator E get(@IntRange(from=0L) int index);
+    method public final inline kotlin.ranges.IntRange getIndices();
+    method @IntRange(from=-1L) public final inline int getLastIndex();
+    method @IntRange(from=0L) public final int getSize();
+    method public final int indexOf(E element);
+    method public final inline int indexOfFirst(kotlin.jvm.functions.Function1<? super E,java.lang.Boolean> predicate);
+    method public final inline int indexOfLast(kotlin.jvm.functions.Function1<? super E,java.lang.Boolean> predicate);
+    method public final boolean isEmpty();
+    method public final boolean isNotEmpty();
+    method public final E last();
+    method public final inline E last(kotlin.jvm.functions.Function1<? super E,java.lang.Boolean> predicate);
+    method public final int lastIndexOf(E element);
+    method public final inline E? lastOrNull();
+    method public final inline E? lastOrNull(kotlin.jvm.functions.Function1<? super E,java.lang.Boolean> predicate);
+    method public final boolean none();
+    method public final inline boolean reversedAny(kotlin.jvm.functions.Function1<? super E,java.lang.Boolean> predicate);
+    property public final inline kotlin.ranges.IntRange indices;
+    property @IntRange(from=-1L) public final inline int lastIndex;
+    property @IntRange(from=0L) public final int size;
+    field @kotlin.PublishedApi internal int _size;
+    field @kotlin.PublishedApi internal Object![] content;
+  }
+
+  public final class ObjectListKt {
+    method public static <E> androidx.collection.ObjectList<E> emptyObjectList();
+    method public static inline <E> androidx.collection.MutableObjectList<E> mutableObjectListOf();
+    method public static <E> androidx.collection.MutableObjectList<E> mutableObjectListOf(E element1);
+    method public static <E> androidx.collection.MutableObjectList<E> mutableObjectListOf(E element1, E element2);
+    method public static <E> androidx.collection.MutableObjectList<E> mutableObjectListOf(E element1, E element2, E element3);
+    method public static inline <E> androidx.collection.MutableObjectList<E> mutableObjectListOf(E?... elements);
+    method public static <E> androidx.collection.ObjectList<E> objectListOf();
+    method public static <E> androidx.collection.ObjectList<E> objectListOf(E element1);
+    method public static <E> androidx.collection.ObjectList<E> objectListOf(E element1, E element2);
+    method public static <E> androidx.collection.ObjectList<E> objectListOf(E element1, E element2, E element3);
+    method public static <E> androidx.collection.ObjectList<E> objectListOf(E?... elements);
+  }
+
   @kotlin.jvm.JvmInline public final value class PairFloatFloat {
     ctor public PairFloatFloat(float first, float second);
     method public inline operator float component1();
diff --git a/collection/collection/src/commonMain/kotlin/androidx/collection/ObjectList.kt b/collection/collection/src/commonMain/kotlin/androidx/collection/ObjectList.kt
new file mode 100644
index 0000000..105ebaf
--- /dev/null
+++ b/collection/collection/src/commonMain/kotlin/androidx/collection/ObjectList.kt
@@ -0,0 +1,1560 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+@file:Suppress("NOTHING_TO_INLINE", "RedundantVisibilityModifier", "UNCHECKED_CAST")
+@file:OptIn(ExperimentalContracts::class)
+
+package androidx.collection
+
+import kotlin.contracts.ExperimentalContracts
+import kotlin.contracts.contract
+import kotlin.jvm.JvmField
+
+/**
+ * [ObjectList] is a [List]-like collection for reference types. It is optimized for fast
+ * access, avoiding virtual and interface method access. Methods avoid allocation whenever
+ * possible. For example [forEach] does not need allocate an [Iterator].
+ *
+ * This implementation is not thread-safe: if multiple threads access this
+ * container concurrently, and one or more threads modify the structure of
+ * the list (insertion or removal for instance), the calling code must provide
+ * the appropriate synchronization. It is also not safe to mutate during reentrancy --
+ * in the middle of a [forEach], for example. However, concurrent reads are safe.
+ *
+ * **Note** [List] access is available through [asList] when developers need access to the
+ * common API.
+ *
+ * @see MutableObjectList
+ * @see FloatList
+ * @see IntList
+ * @eee LongList
+ */
+public sealed class ObjectList<E>(initialCapacity: Int) {
+    @JvmField
+    @PublishedApi
+    internal var content: Array<Any?> = if (initialCapacity == 0) {
+        EmptyArray
+    } else {
+        arrayOfNulls(initialCapacity)
+    }
+
+    @Suppress("PropertyName")
+    @JvmField
+    @PublishedApi
+    internal var _size: Int = 0
+
+    /**
+     * The number of elements in the [ObjectList].
+     */
+    @get:androidx.annotation.IntRange(from = 0)
+    public val size: Int
+        get() = _size
+
+    /**
+     * Returns the last valid index in the [ObjectList]. This can be `-1` when the list is empty.
+     */
+    @get:androidx.annotation.IntRange(from = -1)
+    public inline val lastIndex: Int get() = _size - 1
+
+    /**
+     * Returns an [IntRange] of the valid indices for this [ObjectList].
+     */
+    public inline val indices: IntRange get() = 0 until _size
+
+    /**
+     * Returns `true` if the collection has no elements in it.
+     */
+    public fun none(): Boolean {
+        return isEmpty()
+    }
+
+    /**
+     * Returns `true` if there's at least one element in the collection.
+     */
+    public fun any(): Boolean {
+        return isNotEmpty()
+    }
+
+    /**
+     * Returns `true` if any of the elements give a `true` return value for [predicate].
+     */
+    public inline fun any(predicate: (element: E) -> Boolean): Boolean {
+        contract { callsInPlace(predicate) }
+        forEach {
+            if (predicate(it)) {
+                return true
+            }
+        }
+        return false
+    }
+
+    /**
+     * Returns `true` if any of the elements give a `true` return value for [predicate] while
+     * iterating in the reverse order.
+     */
+    public inline fun reversedAny(predicate: (element: E) -> Boolean): Boolean {
+        contract { callsInPlace(predicate) }
+        forEachReversed {
+            if (predicate(it)) {
+                return true
+            }
+        }
+        return false
+    }
+
+    /**
+     * Returns `true` if the [ObjectList] contains [element] or `false` otherwise.
+     */
+    public operator fun contains(element: E): Boolean {
+        forEach {
+            if (it == element) {
+                return true
+            }
+        }
+        return false
+    }
+
+    /**
+     * Returns `true` if the [ObjectList] contains all elements in [elements] or `false` if
+     * one or more are missing.
+     */
+    public fun containsAll(@Suppress("ArrayReturn") elements: Array<E>): Boolean {
+        for (i in elements.indices) {
+            if (!contains(elements[i])) return false
+        }
+        return true
+    }
+
+    /**
+     * Returns `true` if the [ObjectList] contains all elements in [elements] or `false` if
+     * one or more are missing.
+     */
+    public fun containsAll(elements: List<E>): Boolean {
+        for (i in elements.indices) {
+            if (!contains(elements[i])) return false
+        }
+        return true
+    }
+
+    /**
+     * Returns `true` if the [ObjectList] contains all elements in [elements] or `false` if
+     * one or more are missing.
+     */
+    public fun containsAll(elements: Iterable<E>): Boolean {
+        elements.forEach { element ->
+            if (!contains(element)) return false
+        }
+        return true
+    }
+
+    /**
+     * Returns `true` if the [ObjectList] contains all elements in [elements] or `false` if
+     * one or more are missing.
+     */
+    public fun containsAll(elements: ObjectList<E>): Boolean {
+        elements.forEach { element ->
+            if (!contains(element)) return false
+        }
+        return true
+    }
+
+    /**
+     * Returns the number of elements in this list.
+     */
+    public fun count(): Int = _size
+
+    /**
+     * Counts the number of elements matching [predicate].
+     * @return The number of elements in this list for which [predicate] returns true.
+     */
+    public inline fun count(predicate: (element: E) -> Boolean): Int {
+        contract { callsInPlace(predicate) }
+        var count = 0
+        forEach { if (predicate(it)) count++ }
+        return count
+    }
+
+    /**
+     * Returns the first element in the [ObjectList] or throws a [NoSuchElementException] if
+     * it [isEmpty].
+     */
+    public fun first(): E {
+        if (isEmpty()) {
+            throw NoSuchElementException("ObjectList is empty.")
+        }
+        return content[0] as E
+    }
+
+    /**
+     * Returns the first element in the [ObjectList] for which [predicate] returns `true` or
+     * throws [NoSuchElementException] if nothing matches.
+     * @see indexOfFirst
+     * @see firstOrNull
+     */
+    public inline fun first(predicate: (element: E) -> Boolean): E {
+        contract { callsInPlace(predicate) }
+        forEach { element ->
+            if (predicate(element)) return element
+        }
+        throw NoSuchElementException("ObjectList contains no element matching the predicate.")
+    }
+
+    /**
+     * Returns the first element in the [ObjectList] or `null` if it [isEmpty].
+     */
+    public inline fun firstOrNull(): E? = if (isEmpty()) null else get(0)
+
+    /**
+     * Returns the first element in the [ObjectList] for which [predicate] returns `true` or
+     * `null` if nothing matches.
+     * @see indexOfFirst
+     */
+    public inline fun firstOrNull(predicate: (element: E) -> Boolean): E? {
+        contract { callsInPlace(predicate) }
+        forEach { element ->
+            if (predicate(element)) return element
+        }
+        return null
+    }
+
+    /**
+     * Accumulates values, starting with [initial], and applying [operation] to each element
+     * in the [ObjectList] in order.
+     * @param initial The value of `acc` for the first call to [operation] or return value if
+     * there are no elements in this list.
+     * @param operation function that takes current accumulator value and an element, and
+     * calculates the next accumulator value.
+     */
+    public inline fun <R> fold(initial: R, operation: (acc: R, element: E) -> R): R {
+        contract { callsInPlace(operation) }
+        var acc = initial
+        forEach { element ->
+            acc = operation(acc, element)
+        }
+        return acc
+    }
+
+    /**
+     * Accumulates values, starting with [initial], and applying [operation] to each element
+     * in the [ObjectList] in order.
+     */
+    public inline fun <R> foldIndexed(
+        initial: R,
+        operation: (index: Int, acc: R, element: E) -> R
+    ): R {
+        contract { callsInPlace(operation) }
+        var acc = initial
+        forEachIndexed { i, element ->
+            acc = operation(i, acc, element)
+        }
+        return acc
+    }
+
+    /**
+     * Accumulates values, starting with [initial], and applying [operation] to each element
+     * in the [ObjectList] in reverse order.
+     * @param initial The value of `acc` for the first call to [operation] or return value if
+     * there are no elements in this list.
+     * @param operation function that takes an element and the current accumulator value, and
+     * calculates the next accumulator value.
+     */
+    public inline fun <R> foldRight(initial: R, operation: (element: E, acc: R) -> R): R {
+        contract { callsInPlace(operation) }
+        var acc = initial
+        forEachReversed { element ->
+            acc = operation(element, acc)
+        }
+        return acc
+    }
+
+    /**
+     * Accumulates values, starting with [initial], and applying [operation] to each element
+     * in the [ObjectList] in reverse order.
+     */
+    public inline fun <R> foldRightIndexed(
+        initial: R,
+        operation: (index: Int, element: E, acc: R) -> R
+    ): R {
+        contract { callsInPlace(operation) }
+        var acc = initial
+        forEachReversedIndexed { i, element ->
+            acc = operation(i, element, acc)
+        }
+        return acc
+    }
+
+    /**
+     * Calls [block] for each element in the [ObjectList], in order.
+     * @param block will be executed for every element in the list, accepting an element from
+     * the list
+     */
+    public inline fun forEach(block: (element: E) -> Unit) {
+        contract { callsInPlace(block) }
+        val content = content
+        for (i in 0 until _size) {
+            block(content[i] as E)
+        }
+    }
+
+    /**
+     * Calls [block] for each element in the [ObjectList] along with its index, in order.
+     * @param block will be executed for every element in the list, accepting the index and
+     * the element at that index.
+     */
+    public inline fun forEachIndexed(block: (index: Int, element: E) -> Unit) {
+        contract { callsInPlace(block) }
+        val content = content
+        for (i in 0 until _size) {
+            block(i, content[i] as E)
+        }
+    }
+
+    /**
+     * Calls [block] for each element in the [ObjectList] in reverse order.
+     * @param block will be executed for every element in the list, accepting an element from
+     * the list
+     */
+    public inline fun forEachReversed(block: (element: E) -> Unit) {
+        contract { callsInPlace(block) }
+        val content = content
+        for (i in _size - 1 downTo 0) {
+            block(content[i] as E)
+        }
+    }
+
+    /**
+     * Calls [block] for each element in the [ObjectList] along with its index, in reverse
+     * order.
+     * @param block will be executed for every element in the list, accepting the index and
+     * the element at that index.
+     */
+    public inline fun forEachReversedIndexed(block: (index: Int, element: E) -> Unit) {
+        contract { callsInPlace(block) }
+        val content = content
+        for (i in _size - 1 downTo 0) {
+            block(i, content[i] as E)
+        }
+    }
+
+    /**
+     * Returns the element at the given [index] or throws [IndexOutOfBoundsException] if
+     * the [index] is out of bounds of this collection.
+     */
+    public operator fun get(@androidx.annotation.IntRange(from = 0) index: Int): E {
+        if (index !in 0 until _size) {
+            throw IndexOutOfBoundsException("Index $index must be in 0..$lastIndex")
+        }
+        return content[index] as E
+    }
+
+    /**
+     * Returns the element at the given [index] or throws [IndexOutOfBoundsException] if
+     * the [index] is out of bounds of this collection.
+     */
+    public fun elementAt(@androidx.annotation.IntRange(from = 0) index: Int): E {
+        if (index !in 0 until _size) {
+            throw IndexOutOfBoundsException("Index $index must be in 0..$lastIndex")
+        }
+        return content[index] as E
+    }
+
+    /**
+     * Returns the element at the given [index] or [defaultValue] if [index] is out of bounds
+     * of the collection.
+     * @param index The index of the element whose value should be returned
+     * @param defaultValue A lambda to call with [index] as a parameter to return a value at
+     * an index not in the list.
+     */
+    public inline fun elementAtOrElse(
+        @androidx.annotation.IntRange(from = 0) index: Int,
+        defaultValue: (index: Int) -> E
+    ): E {
+        if (index !in 0 until _size) {
+            return defaultValue(index)
+        }
+        return content[index] as E
+    }
+
+    /**
+     * Returns the index of [element] in the [ObjectList] or `-1` if [element] is not there.
+     */
+    public fun indexOf(element: E): Int {
+        forEachIndexed { i, item ->
+            if (element == item) {
+                return i
+            }
+        }
+        return -1
+    }
+
+    /**
+     * Returns the index if the first element in the [ObjectList] for which [predicate]
+     * returns `true` or -1 if there was no element for which predicate returned `true`.
+     */
+    public inline fun indexOfFirst(predicate: (element: E) -> Boolean): Int {
+        contract { callsInPlace(predicate) }
+        forEachIndexed { i, element ->
+            if (predicate(element)) {
+                return i
+            }
+        }
+        return -1
+    }
+
+    /**
+     * Returns the index if the last element in the [ObjectList] for which [predicate]
+     * returns `true` or -1 if there was no element for which predicate returned `true`.
+     */
+    public inline fun indexOfLast(predicate: (element: E) -> Boolean): Int {
+        contract { callsInPlace(predicate) }
+        forEachReversedIndexed { i, element ->
+            if (predicate(element)) {
+                return i
+            }
+        }
+        return -1
+    }
+
+    /**
+     * Returns `true` if the [ObjectList] has no elements in it or `false` otherwise.
+     */
+    public fun isEmpty(): Boolean = _size == 0
+
+    /**
+     * Returns `true` if there are elements in the [ObjectList] or `false` if it is empty.
+     */
+    public fun isNotEmpty(): Boolean = _size != 0
+
+    /**
+     * Returns the last element in the [ObjectList] or throws a [NoSuchElementException] if
+     * it [isEmpty].
+     */
+    public fun last(): E {
+        if (isEmpty()) {
+            throw NoSuchElementException("ObjectList is empty.")
+        }
+        return content[lastIndex] as E
+    }
+
+    /**
+     * Returns the last element in the [ObjectList] for which [predicate] returns `true` or
+     * throws [NoSuchElementException] if nothing matches.
+     * @see indexOfLast
+     * @see lastOrNull
+     */
+    public inline fun last(predicate: (element: E) -> Boolean): E {
+        contract { callsInPlace(predicate) }
+        forEachReversed { element ->
+            if (predicate(element)) {
+                return element
+            }
+        }
+        throw NoSuchElementException("ObjectList contains no element matching the predicate.")
+    }
+
+    /**
+     * Returns the last element in the [ObjectList] or `null` if it [isEmpty].
+     */
+    public inline fun lastOrNull(): E? = if (isEmpty()) null else content[lastIndex] as E
+
+    /**
+     * Returns the last element in the [ObjectList] for which [predicate] returns `true` or
+     * `null` if nothing matches.
+     * @see indexOfLast
+     */
+    public inline fun lastOrNull(predicate: (element: E) -> Boolean): E? {
+        contract { callsInPlace(predicate) }
+        forEachReversed { element ->
+            if (predicate(element)) {
+                return element
+            }
+        }
+        return null
+    }
+
+    /**
+     * Returns the index of the last element in the [ObjectList] that is the same as
+     * [element] or `-1` if no elements match.
+     */
+    public fun lastIndexOf(element: E): Int {
+        forEachReversedIndexed { i, item ->
+            if (element == item) {
+                return i
+            }
+        }
+        return -1
+    }
+
+    /**
+     * Returns a [List] view into the [ObjectList]. All access to the collection will be
+     * less efficient and abides by the allocation requirements of the [List]. For example,
+     * [List.forEach] will allocate an iterator. All access will go through the more expensive
+     * interface calls. Critical performance areas should use the [ObjectList] API rather than
+     * [List] API, when possible.
+     */
+    public abstract fun asList(): List<E>
+
+    /**
+     * Returns a hash code based on the contents of the [ObjectList].
+     */
+    override fun hashCode(): Int {
+        var hashCode = 0
+        forEach { element ->
+            hashCode += 31 * element.hashCode()
+        }
+        return hashCode
+    }
+
+    /**
+     * Returns `true` if [other] is a [ObjectList] and the contents of this and [other] are the
+     * same.
+     */
+    override fun equals(other: Any?): Boolean {
+        if (other !is ObjectList<*> || other._size != _size) {
+            return false
+        }
+        val content = content
+        val otherContent = other.content
+        for (i in indices) {
+            if (content[i] != otherContent[i]) {
+                return false
+            }
+        }
+        return true
+    }
+
+    /**
+     * Returns a String representation of the list, surrounded by "[]" and each element
+     * separated by ", ".
+     */
+    override fun toString(): String {
+        if (isEmpty()) {
+            return "[]"
+        }
+        val last = lastIndex
+        return buildString {
+            append('[')
+            val content = content
+            for (i in 0 until last) {
+                append(content[i])
+                append(',')
+                append(' ')
+            }
+            append(content[last])
+            append(']')
+        }
+    }
+}
+
+/**
+ * [MutableObjectList] is a [MutableList]-like collection for reference types. It is optimized
+ * for fast access, avoiding virtual and interface method access. Methods avoid allocation
+ * whenever possible. For example [forEach] does not need allocate an [Iterator].
+ *
+ * This implementation is not thread-safe: if multiple threads access this
+ * container concurrently, and one or more threads modify the structure of
+ * the list (insertion or removal for instance), the calling code must provide
+ * the appropriate synchronization. It is also not safe to mutate during reentrancy --
+ * in the middle of a [forEach], for example. However, concurrent reads are safe.
+ *
+ * **Note** [List] access is available through [asList] when developers need access to the
+ * common API.
+
+ * **Note** [MutableList] access is available through [asMutableList] when developers need
+ * access to the common API.
+ *
+ * @see ObjectList
+ * @see MutableFloatList
+ * @see MutableIntList
+ * @eee MutableLongList
+ */
+public class MutableObjectList<E>(
+    initialCapacity: Int = 16
+) : ObjectList<E>(initialCapacity) {
+    private var list: ObjectListMutableList<E>? = null
+
+    /**
+     * Returns the total number of elements that can be held before the [MutableObjectList] must
+     * grow.
+     *
+     * @see ensureCapacity
+     */
+    public inline val capacity: Int
+        get() = content.size
+
+    /**
+     * Adds [element] to the [MutableObjectList] and returns `true`.
+     */
+    public fun add(element: E): Boolean {
+        ensureCapacity(_size + 1)
+        content[_size] = element
+        _size++
+        return true
+    }
+
+    /**
+     * Adds [element] to the [MutableObjectList] at the given [index], shifting over any
+     * elements at [index] and after, if any.
+     * @throws IndexOutOfBoundsException if [index] isn't between 0 and [size], inclusive
+     */
+    public fun add(@androidx.annotation.IntRange(from = 0) index: Int, element: E) {
+        if (index !in 0.._size) {
+            throw IndexOutOfBoundsException("Index $index must be in 0..$_size")
+        }
+        ensureCapacity(_size + 1)
+        val content = content
+        if (index != _size) {
+            content.copyInto(
+                destination = content,
+                destinationOffset = index + 1,
+                startIndex = index,
+                endIndex = _size
+            )
+        }
+        content[index] = element
+        _size++
+    }
+
+    /**
+     * Adds all [elements] to the [MutableObjectList] at the given [index], shifting over any
+     * elements at [index] and after, if any.
+     * @return `true` if the [MutableObjectList] was changed or `false` if [elements] was empty
+     * @throws IndexOutOfBoundsException if [index] isn't between 0 and [size], inclusive.
+     */
+    public fun addAll(
+        @androidx.annotation.IntRange(from = 0) index: Int,
+        @Suppress("ArrayReturn") elements: Array<E>
+    ): Boolean {
+        if (index !in 0.._size) {
+            throw IndexOutOfBoundsException("Index $index must be in 0..$_size")
+        }
+        if (elements.isEmpty()) return false
+        ensureCapacity(_size + elements.size)
+        val content = content
+        if (index != _size) {
+            content.copyInto(
+                destination = content,
+                destinationOffset = index + elements.size,
+                startIndex = index,
+                endIndex = _size
+            )
+        }
+        elements.copyInto(content, index)
+        _size += elements.size
+        return true
+    }
+
+    /**
+     * Adds all [elements] to the [MutableObjectList] at the given [index], shifting over any
+     * elements at [index] and after, if any.
+     * @return `true` if the [MutableObjectList] was changed or `false` if [elements] was empty
+     * @throws IndexOutOfBoundsException if [index] isn't between 0 and [size], inclusive.
+     */
+    public fun addAll(
+        @androidx.annotation.IntRange(from = 0) index: Int,
+        elements: Collection<E>
+    ): Boolean {
+        if (index !in 0.._size) {
+            throw IndexOutOfBoundsException("Index $index must be in 0..$_size")
+        }
+        if (elements.isEmpty()) return false
+        ensureCapacity(_size + elements.size)
+        val content = content
+        if (index != _size) {
+            content.copyInto(
+                destination = content,
+                destinationOffset = index + elements.size,
+                startIndex = index,
+                endIndex = _size
+            )
+        }
+        elements.forEachIndexed { i, element ->
+            content[index + i] = element
+        }
+        _size += elements.size
+        return true
+    }
+
+    /**
+     * Adds all [elements] to the [MutableObjectList] at the given [index], shifting over any
+     * elements at [index] and after, if any.
+     * @return `true` if the [MutableObjectList] was changed or `false` if [elements] was empty
+     * @throws IndexOutOfBoundsException if [index] isn't between 0 and [size], inclusive
+     */
+    public fun addAll(
+        @androidx.annotation.IntRange(from = 0) index: Int,
+        elements: ObjectList<E>
+    ): Boolean {
+        if (index !in 0.._size) {
+            throw IndexOutOfBoundsException("Index $index must be in 0..$_size")
+        }
+        if (elements.isEmpty()) return false
+        ensureCapacity(_size + elements._size)
+        val content = content
+        if (index != _size) {
+            content.copyInto(
+                destination = content,
+                destinationOffset = index + elements._size,
+                startIndex = index,
+                endIndex = _size
+            )
+        }
+        elements.content.copyInto(
+            destination = content,
+            destinationOffset = index,
+            startIndex = 0,
+            endIndex = elements._size
+        )
+        _size += elements._size
+        return true
+    }
+
+    /**
+     * Adds all [elements] to the end of the [MutableObjectList] and returns `true` if the
+     * [MutableObjectList] was changed or `false` if [elements] was empty.
+     */
+    public fun addAll(elements: ObjectList<E>): Boolean {
+        val oldSize = _size
+        plusAssign(elements)
+        return oldSize != _size
+    }
+
+    /**
+     * Adds all [elements] to the end of the [MutableObjectList] and returns `true` if the
+     * [MutableObjectList] was changed or `false` if [elements] was empty.
+     */
+    public fun addAll(elements: ScatterSet<E>): Boolean {
+        val oldSize = _size
+        plusAssign(elements)
+        return oldSize != _size
+    }
+
+    /**
+     * Adds all [elements] to the end of the [MutableObjectList] and returns `true` if the
+     * [MutableObjectList] was changed or `false` if [elements] was empty.
+     */
+    public fun addAll(@Suppress("ArrayReturn") elements: Array<E>): Boolean {
+        val oldSize = _size
+        plusAssign(elements)
+        return oldSize != _size
+    }
+
+    /**
+     * Adds all [elements] to the end of the [MutableObjectList] and returns `true` if the
+     * [MutableObjectList] was changed or `false` if [elements] was empty.
+     */
+    public fun addAll(elements: List<E>): Boolean {
+        val oldSize = _size
+        plusAssign(elements)
+        return oldSize != _size
+    }
+
+    /**
+     * Adds all [elements] to the end of the [MutableObjectList] and returns `true` if the
+     * [MutableObjectList] was changed or `false` if [elements] was empty.
+     */
+    public fun addAll(elements: Iterable<E>): Boolean {
+        val oldSize = _size
+        plusAssign(elements)
+        return oldSize != _size
+    }
+
+    /**
+     * Adds all [elements] to the end of the [MutableObjectList] and returns `true` if the
+     * [MutableObjectList] was changed or `false` if [elements] was empty.
+     */
+    public fun addAll(elements: Sequence<E>): Boolean {
+        val oldSize = _size
+        plusAssign(elements)
+        return oldSize != _size
+    }
+
+    /**
+     * Adds all [elements] to the end of the [MutableObjectList].
+     */
+    public operator fun plusAssign(elements: ObjectList<E>) {
+        if (elements.isEmpty()) return
+        ensureCapacity(_size + elements._size)
+        val content = content
+        elements.content.copyInto(
+            destination = content,
+            destinationOffset = _size,
+            startIndex = 0,
+            endIndex = elements._size
+        )
+        _size += elements._size
+    }
+
+    /**
+     * Adds all [elements] to the end of the [MutableObjectList].
+     */
+    public operator fun plusAssign(elements: ScatterSet<E>) {
+        if (elements.isEmpty()) return
+        ensureCapacity(_size + elements.size)
+        elements.forEach { element ->
+            plusAssign(element)
+        }
+    }
+
+    /**
+     * Adds all [elements] to the end of the [MutableObjectList].
+     */
+    public operator fun plusAssign(@Suppress("ArrayReturn") elements: Array<E>) {
+        if (elements.isEmpty()) return
+        ensureCapacity(_size + elements.size)
+        val content = content
+        elements.copyInto(content, _size)
+        _size += elements.size
+    }
+
+    /**
+     * Adds all [elements] to the end of the [MutableObjectList].
+     */
+    public operator fun plusAssign(elements: List<E>) {
+        if (elements.isEmpty()) return
+        val size = _size
+        ensureCapacity(size + elements.size)
+        val content = content
+        for (i in elements.indices) {
+            content[i + size] = elements[i]
+        }
+        _size += elements.size
+    }
+
+    /**
+     * Adds all [elements] to the end of the [MutableObjectList].
+     */
+    public operator fun plusAssign(elements: Iterable<E>) {
+        elements.forEach { element ->
+            plusAssign(element)
+        }
+    }
+
+    /**
+     * Adds all [elements] to the end of the [MutableObjectList].
+     */
+    public operator fun plusAssign(elements: Sequence<E>) {
+        elements.forEach { element ->
+            plusAssign(element)
+        }
+    }
+
+    /**
+     * Removes all elements in the [MutableObjectList]. The storage isn't released.
+     * @see trim
+     */
+    public fun clear() {
+        content.fill(null, fromIndex = 0, toIndex = _size)
+        _size = 0
+    }
+
+    /**
+     * Reduces the internal storage. If [capacity] is greater than [minCapacity] and [size], the
+     * internal storage is reduced to the maximum of [size] and [minCapacity].
+     * @see ensureCapacity
+     */
+    public fun trim(minCapacity: Int = _size) {
+        val minSize = maxOf(minCapacity, _size)
+        if (capacity > minSize) {
+            content = content.copyOf(minSize)
+        }
+    }
+
+    /**
+     * Ensures that there is enough space to store [capacity] elements in the [MutableObjectList].
+     * @see trim
+     */
+    public fun ensureCapacity(capacity: Int) {
+        val oldContent = content
+        if (oldContent.size < capacity) {
+            val newSize = maxOf(capacity, oldContent.size * 3 / 2)
+            content = oldContent.copyOf(newSize)
+        }
+    }
+
+    /**
+     * [add] [element] to the [MutableObjectList].
+     */
+    public inline operator fun plusAssign(element: E) {
+        add(element)
+    }
+
+    /**
+     * [remove] [element] from the [MutableObjectList]
+     */
+    public inline operator fun minusAssign(element: E) {
+        remove(element)
+    }
+
+    /**
+     * Removes [element] from the [MutableObjectList]. If [element] was in the [MutableObjectList]
+     * and was removed, `true` will be returned, or `false` will be returned if the element
+     * was not found.
+     */
+    public fun remove(element: E): Boolean {
+        val index = indexOf(element)
+        if (index >= 0) {
+            removeAt(index)
+            return true
+        }
+        return false
+    }
+
+    /**
+     * Removes all elements in this list for which [predicate] returns `true`.
+     */
+    public inline fun removeIf(predicate: (element: E) -> Boolean) {
+        var gap = 0
+        val size = _size
+        val content = content
+        for (i in indices) {
+            content[i - gap] = content[i]
+            if (predicate(content[i] as E)) {
+                gap++
+            }
+        }
+        content.fill(null, fromIndex = size - gap, toIndex = size)
+        _size -= gap
+    }
+
+    /**
+     * Removes all [elements] from the [MutableObjectList] and returns `true` if anything was removed.
+     */
+    public fun removeAll(@Suppress("ArrayReturn") elements: Array<E>): Boolean {
+        val initialSize = _size
+        for (i in elements.indices) {
+            remove(elements[i])
+        }
+        return initialSize != _size
+    }
+
+    /**
+     * Removes all [elements] from the [MutableObjectList] and returns `true` if anything was removed.
+     */
+    public fun removeAll(elements: ObjectList<E>): Boolean {
+        val initialSize = _size
+        minusAssign(elements)
+        return initialSize != _size
+    }
+
+    /**
+     * Removes all [elements] from the [MutableObjectList] and returns `true` if anything was removed.
+     */
+    public fun removeAll(elements: ScatterSet<E>): Boolean {
+        val initialSize = _size
+        minusAssign(elements)
+        return initialSize != _size
+    }
+
+    /**
+     * Removes all [elements] from the [MutableObjectList] and returns `true` if anything was removed.
+     */
+    public fun removeAll(elements: List<E>): Boolean {
+        val initialSize = _size
+        minusAssign(elements)
+        return initialSize != _size
+    }
+
+    /**
+     * Removes all [elements] from the [MutableObjectList] and returns `true` if anything was removed.
+     */
+    public fun removeAll(elements: Iterable<E>): Boolean {
+        val initialSize = _size
+        minusAssign(elements)
+        return initialSize != _size
+    }
+
+    /**
+     * Removes all [elements] from the [MutableObjectList] and returns `true` if anything was removed.
+     */
+    public fun removeAll(elements: Sequence<E>): Boolean {
+        val initialSize = _size
+        minusAssign(elements)
+        return initialSize != _size
+    }
+
+    /**
+     * Removes all [elements] from the [MutableObjectList].
+     */
+    public operator fun minusAssign(@Suppress("ArrayReturn") elements: Array<E>) {
+        elements.forEach { element ->
+            minusAssign(element)
+        }
+    }
+
+    /**
+     * Removes all [elements] from the [MutableObjectList].
+     */
+    public operator fun minusAssign(elements: ObjectList<E>) {
+        elements.forEach { element ->
+            minusAssign(element)
+        }
+    }
+
+    /**
+     * Removes all [elements] from the [MutableObjectList].
+     */
+    public operator fun minusAssign(elements: ScatterSet<E>) {
+        elements.forEach { element ->
+            minusAssign(element)
+        }
+    }
+
+    /**
+     * Removes all [elements] from the [MutableObjectList].
+     */
+    public operator fun minusAssign(elements: List<E>) {
+        for (i in elements.indices) {
+            minusAssign(elements[i])
+        }
+    }
+
+    /**
+     * Removes all [elements] from the [MutableObjectList].
+     */
+    public operator fun minusAssign(elements: Iterable<E>) {
+        elements.forEach { element ->
+            minusAssign(element)
+        }
+    }
+
+    /**
+     * Removes all [elements] from the [MutableObjectList].
+     */
+    public operator fun minusAssign(elements: Sequence<E>) {
+        elements.forEach { element ->
+            minusAssign(element)
+        }
+    }
+
+    /**
+     * Removes the element at the given [index] and returns it.
+     * @throws IndexOutOfBoundsException if [index] isn't between 0 and [lastIndex], inclusive
+     */
+    public fun removeAt(@androidx.annotation.IntRange(from = 0) index: Int): E {
+        if (index !in 0 until _size) {
+            throw IndexOutOfBoundsException("Index $index must be in 0..$lastIndex")
+        }
+        val content = content
+        val element = content[index]
+        if (index != lastIndex) {
+            content.copyInto(
+                destination = content,
+                destinationOffset = index,
+                startIndex = index + 1,
+                endIndex = _size
+            )
+        }
+        _size--
+        content[_size] = null
+        return element as E
+    }
+
+    /**
+     * Removes elements from index [start] (inclusive) to [end] (exclusive).
+     * @throws IndexOutOfBoundsException if [start] or [end] isn't between 0 and [size], inclusive
+     * @throws IllegalArgumentException if [start] is greater than [end]
+     */
+    public fun removeRange(
+        @androidx.annotation.IntRange(from = 0) start: Int,
+        @androidx.annotation.IntRange(from = 0) end: Int
+    ) {
+        if (start !in 0.._size || end !in 0.._size) {
+            throw IndexOutOfBoundsException("Start ($start) and end ($end) must be in 0..$_size")
+        }
+        if (end < start) {
+            throw IllegalArgumentException("Start ($start) is more than end ($end)")
+        }
+        if (end != start) {
+            if (end < _size) {
+                content.copyInto(
+                    destination = content,
+                    destinationOffset = start,
+                    startIndex = end,
+                    endIndex = _size
+                )
+            }
+            val newSize = _size - (end - start)
+            content.fill(null, fromIndex = newSize, toIndex = _size)
+            _size = newSize
+        }
+    }
+
+    /**
+     * Keeps only [elements] in the [MutableObjectList] and removes all other values.
+     * @return `true` if the [MutableObjectList] has changed.
+     */
+    public fun retainAll(@Suppress("ArrayReturn") elements: Array<E>): Boolean {
+        val initialSize = _size
+        val content = content
+        for (i in lastIndex downTo 0) {
+            val element = content[i]
+            if (elements.indexOfFirst { it == element } < 0) {
+                removeAt(i)
+            }
+        }
+        return initialSize != _size
+    }
+
+    /**
+     * Keeps only [elements] in the [MutableObjectList] and removes all other values.
+     * @return `true` if the [MutableObjectList] has changed.
+     */
+    public fun retainAll(elements: ObjectList<E>): Boolean {
+        val initialSize = _size
+        val content = content
+        for (i in lastIndex downTo 0) {
+            val element = content[i] as E
+            if (element !in elements) {
+                removeAt(i)
+            }
+        }
+        return initialSize != _size
+    }
+
+    /**
+     * Keeps only [elements] in the [MutableObjectList] and removes all other values.
+     * @return `true` if the [MutableObjectList] has changed.
+     */
+    public fun retainAll(elements: Collection<E>): Boolean {
+        val initialSize = _size
+        val content = content
+        for (i in lastIndex downTo 0) {
+            val element = content[i] as E
+            if (element !in elements) {
+                removeAt(i)
+            }
+        }
+        return initialSize != _size
+    }
+
+    /**
+     * Keeps only [elements] in the [MutableObjectList] and removes all other values.
+     * @return `true` if the [MutableObjectList] has changed.
+     */
+    public fun retainAll(elements: Iterable<E>): Boolean {
+        val initialSize = _size
+        val content = content
+        for (i in lastIndex downTo 0) {
+            val element = content[i] as E
+            if (element !in elements) {
+                removeAt(i)
+            }
+        }
+        return initialSize != _size
+    }
+
+    /**
+     * Keeps only [elements] in the [MutableObjectList] and removes all other values.
+     * @return `true` if the [MutableObjectList] has changed.
+     */
+    public fun retainAll(elements: Sequence<E>): Boolean {
+        val initialSize = _size
+        val content = content
+        for (i in lastIndex downTo 0) {
+            val element = content[i] as E
+            if (element !in elements) {
+                removeAt(i)
+            }
+        }
+        return initialSize != _size
+    }
+
+    /**
+     * Sets the value at [index] to [element].
+     * @return the previous value set at [index]
+     * @throws IndexOutOfBoundsException if [index] isn't between 0 and [lastIndex], inclusive
+     */
+    public operator fun set(
+        @androidx.annotation.IntRange(from = 0) index: Int,
+        element: E
+    ): E {
+        if (index !in 0 until _size) {
+            throw IndexOutOfBoundsException("set index $index must be between 0 .. $lastIndex")
+        }
+        val content = content
+        val old = content[index]
+        content[index] = element
+        return old as E
+    }
+
+    override fun asList(): List<E> = asMutableList()
+
+    /**
+     * Returns a [MutableList] view into the [MutableObjectList]. All access to the collection
+     * will be less efficient and abides by the allocation requirements of the
+     * [MutableList]. For example, [MutableList.forEach] will allocate an iterator.
+     * All access will go through the more expensive interface calls. Critical performance
+     * areas should use the [MutableObjectList] API rather than [MutableList] API, when possible.
+     */
+    public fun asMutableList(): MutableList<E> = list ?: ObjectListMutableList(this).also {
+        list = it
+    }
+
+    private class MutableObjectListIterator<T>(
+        private val list: MutableList<T>,
+        private var index: Int
+    ) : MutableListIterator<T> {
+        override fun hasNext(): Boolean {
+            return index < list.size
+        }
+
+        override fun next(): T {
+            return list[index++]
+        }
+
+        override fun remove() {
+            index--
+            list.removeAt(index)
+        }
+
+        override fun hasPrevious(): Boolean {
+            return index > 0
+        }
+
+        override fun nextIndex(): Int {
+            return index
+        }
+
+        override fun previous(): T {
+            index--
+            return list[index]
+        }
+
+        override fun previousIndex(): Int {
+            return index - 1
+        }
+
+        override fun add(element: T) {
+            list.add(index, element)
+            index++
+        }
+
+        override fun set(element: T) {
+            list[index] = element
+        }
+    }
+
+    /**
+     * [MutableList] implementation for a [MutableObjectList], used in [asMutableList].
+     */
+    private class ObjectListMutableList<T>(
+        private val objectList: MutableObjectList<T>
+    ) : MutableList<T> {
+        override val size: Int
+            get() = objectList.size
+
+        override fun contains(element: T): Boolean = objectList.contains(element)
+
+        override fun containsAll(elements: Collection<T>): Boolean =
+            objectList.containsAll(elements)
+
+        override fun get(index: Int): T {
+            checkIndex(index)
+            return objectList[index]
+        }
+
+        override fun indexOf(element: T): Int = objectList.indexOf(element)
+
+        override fun isEmpty(): Boolean = objectList.isEmpty()
+
+        override fun iterator(): MutableIterator<T> = MutableObjectListIterator(this, 0)
+
+        override fun lastIndexOf(element: T): Int = objectList.lastIndexOf(element)
+
+        override fun add(element: T): Boolean = objectList.add(element)
+
+        override fun add(index: Int, element: T) = objectList.add(index, element)
+
+        override fun addAll(index: Int, elements: Collection<T>): Boolean =
+            objectList.addAll(index, elements)
+
+        override fun addAll(elements: Collection<T>): Boolean = objectList.addAll(elements)
+
+        override fun clear() = objectList.clear()
+
+        override fun listIterator(): MutableListIterator<T> = MutableObjectListIterator(this, 0)
+
+        override fun listIterator(index: Int): MutableListIterator<T> =
+            MutableObjectListIterator(this, index)
+
+        override fun remove(element: T): Boolean = objectList.remove(element)
+
+        override fun removeAll(elements: Collection<T>): Boolean = objectList.removeAll(elements)
+
+        override fun removeAt(index: Int): T {
+            checkIndex(index)
+            return objectList.removeAt(index)
+        }
+
+        override fun retainAll(elements: Collection<T>): Boolean = objectList.retainAll(elements)
+
+        override fun set(index: Int, element: T): T {
+            checkIndex(index)
+            return objectList.set(index, element)
+        }
+
+        override fun subList(fromIndex: Int, toIndex: Int): MutableList<T> {
+            checkSubIndex(fromIndex, toIndex)
+            return SubList(this, fromIndex, toIndex)
+        }
+    }
+
+    /**
+     * A view into an underlying [MutableList] that directly accesses the underlying [MutableList].
+     * This is important for the implementation of [List.subList]. A change to the [SubList]
+     * also changes the referenced [MutableList].
+     */
+    private class SubList<T>(
+        private val list: MutableList<T>,
+        private val start: Int,
+        private var end: Int
+    ) : MutableList<T> {
+        override val size: Int
+            get() = end - start
+
+        override fun contains(element: T): Boolean {
+            for (i in start until end) {
+                if (list[i] == element) {
+                    return true
+                }
+            }
+            return false
+        }
+
+        override fun containsAll(elements: Collection<T>): Boolean {
+            elements.forEach {
+                if (!contains(it)) {
+                    return false
+                }
+            }
+            return true
+        }
+
+        override fun get(index: Int): T {
+            checkIndex(index)
+            return list[index + start]
+        }
+
+        override fun indexOf(element: T): Int {
+            for (i in start until end) {
+                if (list[i] == element) {
+                    return i - start
+                }
+            }
+            return -1
+        }
+
+        override fun isEmpty(): Boolean = end == start
+
+        override fun iterator(): MutableIterator<T> = MutableObjectListIterator(this, 0)
+
+        override fun lastIndexOf(element: T): Int {
+            for (i in end - 1 downTo start) {
+                if (list[i] == element) {
+                    return i - start
+                }
+            }
+            return -1
+        }
+
+        override fun add(element: T): Boolean {
+            list.add(end++, element)
+            return true
+        }
+
+        override fun add(index: Int, element: T) {
+            list.add(index + start, element)
+            end++
+        }
+
+        override fun addAll(index: Int, elements: Collection<T>): Boolean {
+            list.addAll(index + start, elements)
+            end += elements.size
+            return elements.size > 0
+        }
+
+        override fun addAll(elements: Collection<T>): Boolean {
+            list.addAll(end, elements)
+            end += elements.size
+            return elements.size > 0
+        }
+
+        override fun clear() {
+            for (i in end - 1 downTo start) {
+                list.removeAt(i)
+            }
+            end = start
+        }
+
+        override fun listIterator(): MutableListIterator<T> = MutableObjectListIterator(this, 0)
+
+        override fun listIterator(index: Int): MutableListIterator<T> =
+            MutableObjectListIterator(this, index)
+
+        override fun remove(element: T): Boolean {
+            for (i in start until end) {
+                if (list[i] == element) {
+                    list.removeAt(i)
+                    end--
+                    return true
+                }
+            }
+            return false
+        }
+
+        override fun removeAll(elements: Collection<T>): Boolean {
+            val originalEnd = end
+            elements.forEach {
+                remove(it)
+            }
+            return originalEnd != end
+        }
+
+        override fun removeAt(index: Int): T {
+            checkIndex(index)
+            val element = list.removeAt(index + start)
+            end--
+            return element
+        }
+
+        override fun retainAll(elements: Collection<T>): Boolean {
+            val originalEnd = end
+            for (i in end - 1 downTo start) {
+                val element = list[i]
+                if (element !in elements) {
+                    list.removeAt(i)
+                    end--
+                }
+            }
+            return originalEnd != end
+        }
+
+        override fun set(index: Int, element: T): T {
+            checkIndex(index)
+            return list.set(index + start, element)
+        }
+
+        override fun subList(fromIndex: Int, toIndex: Int): MutableList<T> {
+            checkSubIndex(fromIndex, toIndex)
+            return SubList(this, fromIndex, toIndex)
+        }
+    }
+}
+
+private fun List<*>.checkIndex(index: Int) {
+    val size = size
+    if (index < 0 || index >= size) {
+        throw IndexOutOfBoundsException("Index $index is out of bounds. " +
+            "The list has $size elements.")
+    }
+}
+
+private fun List<*>.checkSubIndex(fromIndex: Int, toIndex: Int) {
+    val size = size
+    if (fromIndex > toIndex) {
+        throw IllegalArgumentException("Indices are out of order. fromIndex ($fromIndex) is " +
+            "greater than toIndex ($toIndex).")
+    }
+    if (fromIndex < 0) {
+        throw IndexOutOfBoundsException("fromIndex ($fromIndex) is less than 0.")
+    }
+    if (toIndex > size) {
+        throw IndexOutOfBoundsException(
+            "toIndex ($toIndex) is more than than the list size ($size)"
+        )
+    }
+}
+
+// Empty array used when nothing is allocated
+private val EmptyArray = arrayOfNulls<Any>(0)
+
+private val EmptyObjectList: ObjectList<Any?> = MutableObjectList(0)
+
+/**
+ * @return a read-only [ObjectList] with nothing in it.
+ */
+public fun <E> emptyObjectList(): ObjectList<E> = EmptyObjectList as ObjectList<E>
+
+/**
+ * @return a read-only [ObjectList] with nothing in it.
+ */
+public fun <E> objectListOf(): ObjectList<E> = EmptyObjectList as ObjectList<E>
+
+/**
+ * @return a new read-only [ObjectList] with [element1] as the only element in the list.
+ */
+public fun <E> objectListOf(element1: E): ObjectList<E> = mutableObjectListOf(element1)
+
+/**
+ * @return a new read-only [ObjectList] with 2 elements, [element1] and [element2], in order.
+ */
+public fun <E> objectListOf(element1: E, element2: E): ObjectList<E> =
+    mutableObjectListOf(element1, element2)
+
+/**
+ * @return a new read-only [ObjectList] with 3 elements, [element1], [element2], and [element3],
+ * in order.
+ */
+public fun <E> objectListOf(element1: E, element2: E, element3: E): ObjectList<E> =
+    mutableObjectListOf(element1, element2, element3)
+
+/**
+ * @return a new read-only [ObjectList] with [elements] in order.
+ */
+public fun <E> objectListOf(vararg elements: E): ObjectList<E> =
+    MutableObjectList<E>(elements.size).apply { plusAssign(elements as Array<E>) }
+
+/**
+ * @return a new empty [MutableObjectList] with the default capacity.
+ */
+public inline fun <E> mutableObjectListOf(): MutableObjectList<E> = MutableObjectList()
+
+/**
+ * @return a new [MutableObjectList] with [element1] as the only element in the list.
+ */
+public fun <E> mutableObjectListOf(element1: E): MutableObjectList<E> {
+    val list = MutableObjectList<E>(1)
+    list += element1
+    return list
+}
+
+/**
+ * @return a new [MutableObjectList] with 2 elements, [element1] and [element2], in order.
+ */
+public fun <E> mutableObjectListOf(element1: E, element2: E): MutableObjectList<E> {
+    val list = MutableObjectList<E>(2)
+    list += element1
+    list += element2
+    return list
+}
+
+/**
+ * @return a new [MutableObjectList] with 3 elements, [element1], [element2], and [element3],
+ * in order.
+ */
+public fun <E> mutableObjectListOf(element1: E, element2: E, element3: E): MutableObjectList<E> {
+    val list = MutableObjectList<E>(3)
+    list += element1
+    list += element2
+    list += element3
+    return list
+}
+
+/**
+ * @return a new [MutableObjectList] with the given elements, in order.
+ */
+public inline fun <E> mutableObjectListOf(vararg elements: E): MutableObjectList<E> =
+    MutableObjectList<E>(elements.size).apply { plusAssign(elements as Array<E>) }
diff --git a/collection/collection/src/commonTest/kotlin/androidx/collection/ObjectListTest.kt b/collection/collection/src/commonTest/kotlin/androidx/collection/ObjectListTest.kt
new file mode 100644
index 0000000..d524dcf
--- /dev/null
+++ b/collection/collection/src/commonTest/kotlin/androidx/collection/ObjectListTest.kt
@@ -0,0 +1,1312 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.collection
+
+import kotlin.test.Test
+import kotlin.test.assertEquals
+import kotlin.test.assertFailsWith
+import kotlin.test.assertFalse
+import kotlin.test.assertNotEquals
+import kotlin.test.assertNull
+import kotlin.test.assertTrue
+
+class ObjectListTest {
+    private val list: MutableObjectList<Int> = mutableObjectListOf(1, 2, 3, 4, 5)
+
+    @Test
+    fun emptyConstruction() {
+        val l = mutableObjectListOf<Int>()
+        assertEquals(0, l.size)
+        assertEquals(16, l.capacity)
+    }
+
+    @Test
+    fun sizeConstruction() {
+        val l = MutableObjectList<Int>(4)
+        assertEquals(4, l.capacity)
+    }
+
+    @Test
+    fun contentConstruction() {
+        val l = mutableObjectListOf(1, 2, 3)
+        assertEquals(3, l.size)
+        assertEquals(1, l[0])
+        assertEquals(2, l[1])
+        assertEquals(3, l[2])
+        assertEquals(3, l.capacity)
+        repeat(2) {
+            val l2 = mutableObjectListOf(1, 2, 3, 4, 5)
+            assertEquals(list, l2)
+            l2.removeAt(0)
+        }
+    }
+
+    @Test
+    fun hashCodeTest() {
+        val l2 = mutableObjectListOf(1, 2, 3, 4, 5)
+        assertEquals(list.hashCode(), l2.hashCode())
+        l2.removeAt(4)
+        assertNotEquals(list.hashCode(), l2.hashCode())
+        l2.add(5)
+        assertEquals(list.hashCode(), l2.hashCode())
+        l2.clear()
+        assertNotEquals(list.hashCode(), l2.hashCode())
+    }
+
+    @Test
+    fun equalsTest() {
+        val l2 = mutableObjectListOf(1, 2, 3, 4, 5)
+        assertEquals(list, l2)
+        assertNotEquals(list, mutableObjectListOf())
+        l2.removeAt(4)
+        assertNotEquals(list, l2)
+        l2.add(5)
+        assertEquals(list, l2)
+        l2.clear()
+        assertNotEquals(list, l2)
+    }
+
+    @Test
+    fun string() {
+        assertEquals("[1, 2, 3, 4, 5]", list.toString())
+        assertEquals("[]", mutableObjectListOf<Int>().toString())
+    }
+
+    @Test
+    fun size() {
+        assertEquals(5, list.size)
+        assertEquals(5, list.count())
+        val l2 = mutableObjectListOf<Int>()
+        assertEquals(0, l2.size)
+        assertEquals(0, l2.count())
+        l2 += 1
+        assertEquals(1, l2.size)
+        assertEquals(1, l2.count())
+    }
+
+    @Test
+    fun get() {
+        assertEquals(1, list[0])
+        assertEquals(5, list[4])
+        assertEquals(1, list.elementAt(0))
+        assertEquals(5, list.elementAt(4))
+    }
+
+    @Test
+    fun getOutOfBounds() {
+        assertFailsWith(IndexOutOfBoundsException::class) {
+            list[5]
+        }
+    }
+
+    @Test
+    fun getOutOfBoundsNegative() {
+        assertFailsWith(IndexOutOfBoundsException::class) {
+            list[-1]
+        }
+    }
+
+    @Test
+    fun elementAtOfBounds() {
+        assertFailsWith(IndexOutOfBoundsException::class) {
+            list.elementAt(5)
+        }
+    }
+
+    @Test
+    fun elementAtOfBoundsNegative() {
+        assertFailsWith(IndexOutOfBoundsException::class) {
+            list.elementAt(-1)
+        }
+    }
+
+    @Test
+    fun elementAtOrElse() {
+        assertEquals(1, list.elementAtOrElse(0) {
+            assertEquals(0, it)
+            0
+        })
+        assertEquals(0, list.elementAtOrElse(-1) {
+            assertEquals(-1, it)
+            0
+        })
+        assertEquals(0, list.elementAtOrElse(5) {
+            assertEquals(5, it)
+            0
+        })
+    }
+
+    @Test
+    fun count() {
+        assertEquals(1, list.count { it < 2 })
+        assertEquals(0, list.count { it < 0 })
+        assertEquals(5, list.count { it < 10 })
+    }
+
+    @Test
+    fun isEmpty() {
+        assertFalse(list.isEmpty())
+        assertFalse(list.none())
+        assertTrue(mutableObjectListOf<Int>().isEmpty())
+        assertTrue(mutableObjectListOf<Int>().none())
+    }
+
+    @Test
+    fun isNotEmpty() {
+        assertTrue(list.isNotEmpty())
+        assertTrue(list.any())
+        assertFalse(mutableObjectListOf<Int>().isNotEmpty())
+    }
+
+    @Test
+    fun indices() {
+        assertEquals(IntRange(0, 4), list.indices)
+        assertEquals(IntRange(0, -1), mutableObjectListOf<Int>().indices)
+    }
+
+    @Test
+    fun any() {
+        assertTrue(list.any { it == 5 })
+        assertTrue(list.any { it == 1 })
+        assertFalse(list.any { it == 0 })
+    }
+
+    @Test
+    fun reversedAny() {
+        val reversedList = mutableObjectListOf<Int>()
+        assertFalse(
+            list.reversedAny {
+                reversedList.add(it)
+                false
+            }
+        )
+        val reversedContent = mutableObjectListOf(5, 4, 3, 2, 1)
+        assertEquals(reversedContent, reversedList)
+
+        val reversedSublist = mutableObjectListOf<Int>()
+        assertTrue(
+            list.reversedAny {
+                reversedSublist.add(it)
+                reversedSublist.size == 2
+            }
+        )
+        assertEquals(reversedSublist, mutableObjectListOf(5, 4))
+    }
+
+    @Test
+    fun forEach() {
+        val copy = mutableObjectListOf<Int>()
+        list.forEach { copy += it }
+        assertEquals(list, copy)
+    }
+
+    @Test
+    fun forEachReversed() {
+        val copy = mutableObjectListOf<Int>()
+        list.forEachReversed { copy += it }
+        assertEquals(copy, mutableObjectListOf(5, 4, 3, 2, 1))
+    }
+
+    @Test
+    fun forEachIndexed() {
+        val copy = mutableObjectListOf<Int>()
+        val indices = mutableObjectListOf<Int>()
+        list.forEachIndexed { index, open ->
+            copy += open
+            indices += index
+        }
+        assertEquals(list, copy)
+        assertEquals(indices, mutableObjectListOf(0, 1, 2, 3, 4))
+    }
+
+    @Test
+    fun forEachReversedIndexed() {
+        val copy = mutableObjectListOf<Int>()
+        val indices = mutableObjectListOf<Int>()
+        list.forEachReversedIndexed { index, open ->
+            copy += open
+            indices += index
+        }
+        assertEquals(copy, mutableObjectListOf(5, 4, 3, 2, 1))
+        assertEquals(indices, mutableObjectListOf(4, 3, 2, 1, 0))
+    }
+
+    @Test
+    fun indexOfFirst() {
+        assertEquals(0, list.indexOfFirst { it < 2 })
+        assertEquals(4, list.indexOfFirst { it > 4 })
+        assertEquals(-1, list.indexOfFirst { it < 0 })
+        assertEquals(0, mutableObjectListOf(8, 8).indexOfFirst { it > 7 })
+    }
+
+    @Test
+    fun firstOrNullNoParam() {
+        assertEquals(1, list.firstOrNull())
+        assertNull(emptyObjectList<Int>().firstOrNull())
+    }
+
+    @Test
+    fun firstOrNull() {
+        assertEquals(1, list.firstOrNull { it < 5 })
+        assertEquals(3, list.firstOrNull { it > 2 })
+        assertEquals(5, list.firstOrNull { it > 4 })
+        assertNull(list.firstOrNull { it > 5 })
+    }
+
+    @Test
+    fun lastOrNullNoParam() {
+        assertEquals(5, list.lastOrNull())
+        assertNull(emptyObjectList<Int>().lastOrNull())
+    }
+
+    @Test
+    fun lastOrNull() {
+        assertEquals(4, list.lastOrNull { it < 5 })
+        assertEquals(5, list.lastOrNull { it > 2 })
+        assertEquals(1, list.lastOrNull { it < 2 })
+        assertNull(list.firstOrNull { it > 5 })
+    }
+
+    @Test
+    fun indexOfLast() {
+        assertEquals(0, list.indexOfLast { it < 2 })
+        assertEquals(4, list.indexOfLast { it > 4 })
+        assertEquals(-1, list.indexOfLast { it < 0 })
+        assertEquals(1, objectListOf(8, 8).indexOfLast { it > 7 })
+    }
+
+    @Test
+    fun contains() {
+        assertTrue(list.contains(5))
+        assertTrue(list.contains(1))
+        assertFalse(list.contains(0))
+    }
+
+    @Test
+    fun containsAllList() {
+        assertTrue(list.containsAll(mutableObjectListOf(2, 3, 1)))
+        assertFalse(list.containsAll(mutableObjectListOf(2, 3, 6)))
+    }
+
+    @Test
+    fun lastIndexOf() {
+        assertEquals(4, list.lastIndexOf(5))
+        assertEquals(1, list.lastIndexOf(2))
+        val copy = mutableObjectListOf<Int>()
+        copy.addAll(list)
+        copy.addAll(list)
+        assertEquals(5, copy.lastIndexOf(1))
+    }
+
+    @Test
+    fun first() {
+        assertEquals(1, list.first())
+    }
+
+    @Test
+    fun firstException() {
+        assertFailsWith(NoSuchElementException::class) {
+            mutableObjectListOf<Int>().first()
+        }
+    }
+
+    @Test
+    fun firstWithPredicate() {
+        assertEquals(5, list.first { it > 4 })
+        assertEquals(1, mutableObjectListOf(1, 5).first { it > 0 })
+    }
+
+    @Test
+    fun firstWithPredicateException() {
+        assertFailsWith(NoSuchElementException::class) {
+            mutableObjectListOf<Int>().first { it > 8 }
+        }
+    }
+
+    @Test
+    fun last() {
+        assertEquals(5, list.last())
+    }
+
+    @Test
+    fun lastException() {
+        assertFailsWith(NoSuchElementException::class) {
+            mutableObjectListOf<Int>().last()
+        }
+    }
+
+    @Test
+    fun lastWithPredicate() {
+        assertEquals(1, list.last { it < 2 })
+        assertEquals(5, objectListOf(1, 5).last { it > 0 })
+    }
+
+    @Test
+    fun lastWithPredicateException() {
+        assertFailsWith<NoSuchElementException> {
+            objectListOf(2).last { it > 2 }
+        }
+    }
+
+    @Test
+    fun fold() {
+        assertEquals("12345", list.fold("") { acc, i -> acc + i.toString() })
+    }
+
+    @Test
+    fun foldIndexed() {
+        assertEquals(
+            "01-12-23-34-45-",
+            list.foldIndexed("") { index, acc, i ->
+                "$acc$index$i-"
+            }
+        )
+    }
+
+    @Test
+    fun foldRight() {
+        assertEquals("54321", list.foldRight("") { i, acc -> acc + i.toString() })
+    }
+
+    @Test
+    fun foldRightIndexed() {
+        assertEquals(
+            "45-34-23-12-01-",
+            list.foldRightIndexed("") { index, i, acc ->
+                "$acc$index$i-"
+            }
+        )
+    }
+
+    @Test
+    fun add() {
+        val l = mutableObjectListOf(1, 2, 3)
+        l += 4
+        l.add(5)
+        assertEquals(list, l)
+    }
+
+    @Test
+    fun addAtIndex() {
+        val l = mutableObjectListOf(2, 4)
+        l.add(2, 5)
+        l.add(0, 1)
+        l.add(2, 3)
+        assertEquals(list, l)
+        assertFailsWith(IndexOutOfBoundsException::class) {
+            l.add(-1, 2)
+        }
+        assertFailsWith(IndexOutOfBoundsException::class) {
+            l.add(6, 2)
+        }
+    }
+
+    @Test
+    fun addAllListAtIndex() {
+        val l = mutableObjectListOf(4)
+        val l2 = mutableObjectListOf(1, 2)
+        val l3 = mutableObjectListOf(5)
+        val l4 = mutableObjectListOf(3)
+        assertTrue(l4.addAll(1, l3))
+        assertTrue(l4.addAll(0, l2))
+        assertTrue(l4.addAll(3, l))
+        assertFalse(l4.addAll(0, mutableObjectListOf()))
+        assertEquals(list, l4)
+        assertFailsWith(IndexOutOfBoundsException::class) {
+            l4.addAll(6, mutableObjectListOf())
+        }
+        assertFailsWith(IndexOutOfBoundsException::class) {
+            l4.addAll(-1, mutableObjectListOf())
+        }
+    }
+
+    @Test
+    fun addAllObjectList() {
+        val l = MutableObjectList<Int>()
+        l.add(3)
+        l.add(4)
+        l.add(5)
+        val l2 = mutableObjectListOf(1, 2)
+        assertTrue(l2.addAll(l))
+        assertEquals(list, l2)
+        assertFalse(l2.addAll(mutableObjectListOf()))
+    }
+
+    @Test
+    fun addAllList() {
+        val l = listOf(3, 4, 5)
+        val l2 = mutableObjectListOf(1, 2)
+        assertTrue(l2.addAll(l))
+        assertEquals(list, l2)
+        assertFalse(l2.addAll(mutableObjectListOf()))
+    }
+
+    @Test
+    fun addAllIterable() {
+        val l = listOf(3, 4, 5) as Iterable<Int>
+        val l2 = mutableObjectListOf(1, 2)
+        assertTrue(l2.addAll(l))
+        assertEquals(list, l2)
+        assertFalse(l2.addAll(mutableObjectListOf()))
+    }
+
+    @Test
+    fun addAllSequence() {
+        val l = listOf(3, 4, 5).asSequence()
+        val l2 = mutableObjectListOf(1, 2)
+        assertTrue(l2.addAll(l))
+        assertEquals(list, l2)
+        assertFalse(l2.addAll(mutableObjectListOf()))
+    }
+
+    @Test
+    fun plusAssignObjectList() {
+        val l = objectListOf(3, 4, 5)
+        val l2 = mutableObjectListOf(1, 2)
+        l2 += l
+        assertEquals(list, l2)
+    }
+
+    @Test
+    fun plusAssignIterable() {
+        val l = listOf(3, 4, 5) as Iterable<Int>
+        val l2 = mutableObjectListOf(1, 2)
+        l2 += l
+        assertEquals(list, l2)
+    }
+
+    @Test
+    fun plusAssignSequence() {
+        val l = arrayOf(3, 4, 5).asSequence()
+        val l2 = mutableObjectListOf(1, 2)
+        l2 += l
+        assertEquals(list, l2)
+    }
+
+    @Test
+    fun addAllArrayAtIndex() {
+        val a1 = arrayOf(4)
+        val a2 = arrayOf(1, 2)
+        val a3 = arrayOf(5)
+        val l = mutableObjectListOf(3)
+        assertTrue(l.addAll(1, a3))
+        assertTrue(l.addAll(0, a2))
+        assertTrue(l.addAll(3, a1))
+        assertFalse(l.addAll(0, arrayOf()))
+        assertEquals(list, l)
+        assertFailsWith(IndexOutOfBoundsException::class) {
+            l.addAll(6, arrayOf())
+        }
+        assertFailsWith(IndexOutOfBoundsException::class) {
+            l.addAll(-1, arrayOf())
+        }
+    }
+
+    @Test
+    fun addAllArray() {
+        val a = arrayOf(3, 4, 5)
+        val v = mutableObjectListOf(1, 2)
+        v.addAll(a)
+        assertEquals(5, v.size)
+        assertEquals(3, v[2])
+        assertEquals(4, v[3])
+        assertEquals(5, v[4])
+    }
+
+    @Test
+    fun plusAssignArray() {
+        val a = arrayOf(3, 4, 5)
+        val v = mutableObjectListOf(1, 2)
+        v += a
+        assertEquals(list, v)
+    }
+
+    @Test
+    fun clear() {
+        val l = mutableObjectListOf<Int>()
+        l.addAll(list)
+        assertTrue(l.isNotEmpty())
+        l.clear()
+        assertTrue(l.isEmpty())
+        repeat(5) { index ->
+            assertNull(l.content[index])
+        }
+    }
+
+    @Test
+    fun trim() {
+        val l = mutableObjectListOf(1)
+        l.trim()
+        assertEquals(1, l.capacity)
+        l += arrayOf(1, 2, 3, 4, 5)
+        l.trim()
+        assertEquals(6, l.capacity)
+        assertEquals(6, l.size)
+        l.clear()
+        l.trim()
+        assertEquals(0, l.capacity)
+        l.trim(100)
+        assertEquals(0, l.capacity)
+        l += arrayOf(1, 2, 3, 4, 5)
+        l -= 5
+        l.trim(5)
+        assertEquals(5, l.capacity)
+        l.trim(4)
+        assertEquals(4, l.capacity)
+        l.trim(3)
+        assertEquals(4, l.capacity)
+    }
+
+    @Test
+    fun remove() {
+        val l = mutableObjectListOf(1, 2, 3, 4, 5)
+        l.remove(3)
+        assertEquals(mutableObjectListOf(1, 2, 4, 5), l)
+    }
+
+    @Test
+    fun removeIf() {
+        val l = mutableObjectListOf(1, 2, 3, 4, 5, 6)
+        l.removeIf { it == 100 }
+        assertEquals(objectListOf(1, 2, 3, 4, 5, 6), l)
+        l.removeIf { it % 2 == 0 }
+        assertEquals(objectListOf(1, 3, 5), l)
+        repeat(3) {
+            assertNull(l.content[3 + it])
+        }
+        l.removeIf { it != 3 }
+        assertEquals(objectListOf(3), l)
+    }
+
+    @Test
+    fun removeAt() {
+        val l = mutableObjectListOf(1, 2, 3, 4, 5)
+        l.removeAt(2)
+        assertNull(l.content[4])
+        assertEquals(mutableObjectListOf(1, 2, 4, 5), l)
+        assertFailsWith(IndexOutOfBoundsException::class) {
+            l.removeAt(6)
+        }
+        assertFailsWith(IndexOutOfBoundsException::class) {
+            l.removeAt(-1)
+        }
+    }
+
+    @Test
+    fun set() {
+        val l = mutableObjectListOf(0, 0, 0, 0, 0)
+        l[0] = 1
+        l[4] = 5
+        l[2] = 3
+        l[1] = 2
+        l[3] = 4
+        assertEquals(list, l)
+        assertFailsWith<IndexOutOfBoundsException> {
+            l[-1] = 1
+        }
+        assertFailsWith<IndexOutOfBoundsException> {
+            l[6] = 1
+        }
+        assertEquals(4, l.set(3, 1));
+    }
+
+    @Test
+    fun ensureCapacity() {
+        val l = mutableObjectListOf(1)
+        assertEquals(1, l.capacity)
+        l.ensureCapacity(5)
+        assertEquals(5, l.capacity)
+    }
+
+    @Test
+    fun removeAllObjectList() {
+        assertFalse(list.removeAll(mutableObjectListOf(0, 10, 15)))
+        val l = mutableObjectListOf(0, 1, 15, 10, 2, 3, 4, 5, 20, 5)
+        assertTrue(l.removeAll(mutableObjectListOf(20, 0, 15, 10, 5)))
+        assertEquals(list, l)
+    }
+
+    @Test
+    fun removeAllScatterSet() {
+        assertFalse(list.removeAll(scatterSetOf(0, 10, 15)))
+        val l = mutableObjectListOf(0, 1, 15, 10, 2, 3, 4, 5, 20, 5)
+        assertTrue(l.removeAll(scatterSetOf(20, 0, 15, 10, 5)))
+        assertEquals(list, l)
+    }
+
+    @Test
+    fun removeAllArray() {
+        assertFalse(list.removeAll(arrayOf(0, 10, 15)))
+        val l = mutableObjectListOf(0, 1, 15, 10, 2, 3, 4, 5, 20, 5)
+        assertTrue(l.removeAll(arrayOf(20, 0, 15, 10, 5)))
+        assertEquals(list, l)
+    }
+
+    @Test
+    fun removeAllList() {
+        assertFalse(list.removeAll(listOf(0, 10, 15)))
+        val l = mutableObjectListOf(0, 1, 15, 10, 2, 3, 4, 5, 20, 5)
+        assertTrue(l.removeAll(listOf(20, 0, 15, 10, 5)))
+        assertEquals(list, l)
+    }
+
+    @Test
+    fun removeAllIterable() {
+        assertFalse(list.removeAll(listOf(0, 10, 15) as Iterable<Int>))
+        val l = mutableObjectListOf(0, 1, 15, 10, 2, 3, 4, 5, 20, 5)
+        assertTrue(l.removeAll(listOf(20, 0, 15, 10, 5) as Iterable<Int>))
+        assertEquals(list, l)
+    }
+
+    @Test
+    fun removeAllSequence() {
+        assertFalse(list.removeAll(listOf(0, 10, 15).asSequence()))
+        val l = mutableObjectListOf(0, 1, 15, 10, 2, 3, 4, 5, 20, 5)
+        assertTrue(l.removeAll(listOf(20, 0, 15, 10, 5).asSequence()))
+        assertEquals(list, l)
+    }
+
+    @Test
+    fun minusAssignObjectList() {
+        val l = mutableObjectListOf<Int>().also { it += list }
+        l -= mutableObjectListOf(0, 10, 15)
+        assertEquals(list, l)
+        val l2 = mutableObjectListOf(0, 1, 15, 10, 2, 3, 4, 5, 20, 5)
+        l2 -= mutableObjectListOf(20, 0, 15, 10, 5)
+        assertEquals(list, l2)
+    }
+
+    @Test
+    fun minusAssignScatterSet() {
+        val l = mutableObjectListOf<Int>().also { it += list }
+        l -= scatterSetOf(0, 10, 15)
+        assertEquals(list, l)
+        val l2 = mutableObjectListOf(0, 1, 15, 10, 2, 3, 4, 5, 20, 5)
+        l2 -= scatterSetOf(20, 0, 15, 10, 5)
+        assertEquals(list, l2)
+    }
+
+    @Test
+    fun minusAssignArray() {
+        val l = mutableObjectListOf<Int>().also { it += list }
+        l -= arrayOf(0, 10, 15)
+        assertEquals(list, l)
+        val l2 = mutableObjectListOf(0, 1, 15, 10, 2, 3, 4, 5, 20, 5)
+        l2 -= arrayOf(20, 0, 15, 10, 5)
+        assertEquals(list, l2)
+    }
+
+    @Test
+    fun minusAssignList() {
+        val l = mutableObjectListOf<Int>().also { it += list }
+        l -= listOf(0, 10, 15)
+        assertEquals(list, l)
+        val l2 = mutableObjectListOf(0, 1, 15, 10, 2, 3, 4, 5, 20, 5)
+        l2 -= listOf(20, 0, 15, 10, 5)
+        assertEquals(list, l2)
+    }
+
+    @Test
+    fun minusAssignIterable() {
+        val l = mutableObjectListOf<Int>().also { it += list }
+        l -= listOf(0, 10, 15) as Iterable<Int>
+        assertEquals(list, l)
+        val l2 = mutableObjectListOf(0, 1, 15, 10, 2, 3, 4, 5, 20, 5)
+        l2 -= listOf(20, 0, 15, 10, 5) as Iterable<Int>
+        assertEquals(list, l2)
+    }
+
+    @Test
+    fun minusAssignSequence() {
+        val l = mutableObjectListOf<Int>().also { it += list }
+        l -= listOf(0, 10, 15).asSequence()
+        assertEquals(list, l)
+        val l2 = mutableObjectListOf(0, 1, 15, 10, 2, 3, 4, 5, 20, 5)
+        l2 -= listOf(20, 0, 15, 10, 5).asSequence()
+        assertEquals(list, l2)
+    }
+
+    @Test
+    fun retainAll() {
+        assertFalse(list.retainAll(mutableObjectListOf(1, 2, 3, 4, 5, 6)))
+        val l = mutableObjectListOf(0, 1, 15, 10, 2, 3, 4, 5, 20)
+        assertTrue(l.retainAll(mutableObjectListOf(1, 2, 3, 4, 5, 6)))
+        assertEquals(list, l)
+    }
+
+    @Test
+    fun retainAllArray() {
+        assertFalse(list.retainAll(arrayOf(1, 2, 3, 4, 5, 6)))
+        val l = mutableObjectListOf(0, 1, 15, 10, 2, 3, 4, 5, 20)
+        assertTrue(l.retainAll(arrayOf(1, 2, 3, 4, 5, 6)))
+        assertEquals(list, l)
+    }
+
+    @Test
+    fun retainAllCollection() {
+        assertFalse(list.retainAll(listOf(1, 2, 3, 4, 5, 6)))
+        val l = mutableObjectListOf(0, 1, 15, 10, 2, 3, 4, 5, 20)
+        assertTrue(l.retainAll(listOf(1, 2, 3, 4, 5, 6)))
+        assertEquals(list, l)
+    }
+
+    @Test
+    fun retainAllIterable() {
+        assertFalse(list.retainAll(listOf(1, 2, 3, 4, 5, 6) as Iterable<Int>))
+        val l = mutableObjectListOf(0, 1, 15, 10, 2, 3, 4, 5, 20)
+        assertTrue(l.retainAll(listOf(1, 2, 3, 4, 5, 6) as Iterable<Int>))
+        assertEquals(list, l)
+    }
+
+    @Test
+    fun retainAllSequence() {
+        assertFalse(list.retainAll(arrayOf(1, 2, 3, 4, 5, 6).asSequence()))
+        val l = mutableObjectListOf(0, 1, 15, 10, 2, 3, 4, 5, 20)
+        assertTrue(l.retainAll(arrayOf(1, 2, 3, 4, 5, 6).asSequence()))
+        assertEquals(list, l)
+    }
+
+    @Test
+    fun removeRange() {
+        val l = mutableObjectListOf(1, 9, 7, 6, 2, 3, 4, 5)
+        l.removeRange(1, 4)
+        assertNull(l.content[5])
+        assertNull(l.content[6])
+        assertNull(l.content[7])
+        assertEquals(list, l)
+        assertFailsWith<IndexOutOfBoundsException> {
+            l.removeRange(6, 6)
+        }
+        assertFailsWith<IndexOutOfBoundsException> {
+            l.removeRange(100, 200)
+        }
+        assertFailsWith<IndexOutOfBoundsException> {
+            l.removeRange(-1, 0)
+        }
+        assertFailsWith<IllegalArgumentException> {
+            l.removeRange(3, 2)
+        }
+    }
+
+    @Test
+    fun testEmptyObjectList() {
+        val l = emptyObjectList<Int>()
+        assertEquals(0, l.size)
+    }
+
+    @Test
+    fun objectListOfEmpty() {
+        val l = objectListOf<Int>()
+        assertEquals(0, l.size)
+    }
+
+    @Test
+    fun objectListOfOneValue() {
+        val l = objectListOf(2)
+        assertEquals(1, l.size)
+        assertEquals(2, l[0])
+    }
+
+    @Test
+    fun objectListOfTwoValues() {
+        val l = objectListOf(2, 1)
+        assertEquals(2, l.size)
+        assertEquals(2, l[0])
+        assertEquals(1, l[1])
+    }
+
+    @Test
+    fun objectListOfThreeValues() {
+        val l = objectListOf(2, 10, -1)
+        assertEquals(3, l.size)
+        assertEquals(2, l[0])
+        assertEquals(10, l[1])
+        assertEquals(-1, l[2])
+    }
+
+    @Test
+    fun objectListOfFourValues() {
+        val l = objectListOf(2, 10, -1, 10)
+        assertEquals(4, l.size)
+        assertEquals(2, l[0])
+        assertEquals(10, l[1])
+        assertEquals(-1, l[2])
+        assertEquals(10, l[3])
+    }
+
+    @Test
+    fun mutableObjectListOfOneValue() {
+        val l = mutableObjectListOf(2)
+        assertEquals(1, l.size)
+        assertEquals(1, l.capacity)
+        assertEquals(2, l[0])
+    }
+
+    @Test
+    fun mutableObjectListOfTwoValues() {
+        val l = mutableObjectListOf(2, 1)
+        assertEquals(2, l.size)
+        assertEquals(2, l.capacity)
+        assertEquals(2, l[0])
+        assertEquals(1, l[1])
+    }
+
+    @Test
+    fun mutableObjectListOfThreeValues() {
+        val l = mutableObjectListOf(2, 10, -1)
+        assertEquals(3, l.size)
+        assertEquals(3, l.capacity)
+        assertEquals(2, l[0])
+        assertEquals(10, l[1])
+        assertEquals(-1, l[2])
+    }
+
+    @Test
+    fun mutableObjectListOfFourValues() {
+        val l = mutableObjectListOf(2, 10, -1, 10)
+        assertEquals(4, l.size)
+        assertEquals(4, l.capacity)
+        assertEquals(2, l[0])
+        assertEquals(10, l[1])
+        assertEquals(-1, l[2])
+        assertEquals(10, l[3])
+    }
+
+    @Test
+    fun iterator() {
+        val l = mutableObjectListOf(1, 2, 3, 4, 5)
+        val iterator = l.asMutableList().iterator()
+        assertTrue(iterator.hasNext())
+        assertEquals(1, iterator.next())
+        assertTrue(iterator.hasNext())
+        assertEquals(2, iterator.next())
+        assertTrue(iterator.hasNext())
+        assertEquals(3, iterator.next())
+        assertTrue(iterator.hasNext())
+        iterator.remove()
+        assertTrue(iterator.hasNext())
+        assertEquals(l, mutableObjectListOf(1, 2, 4, 5))
+
+        assertEquals(4, iterator.next())
+        assertTrue(iterator.hasNext())
+        assertEquals(5, iterator.next())
+        assertFalse(iterator.hasNext())
+        iterator.remove()
+        assertEquals(l, mutableObjectListOf(1, 2, 4))
+    }
+
+    @Test
+    fun listIterator() {
+        val l = mutableObjectListOf(1, 2, 3, 4, 5)
+        val iterator = l.asMutableList().listIterator()
+        assertEquals(1, iterator.next())
+        assertEquals(1, iterator.previous())
+        assertEquals(0, iterator.nextIndex())
+        iterator.add(6)
+        assertEquals(1, iterator.nextIndex())
+        assertEquals(0, iterator.previousIndex())
+        assertEquals(6, iterator.previous())
+        assertEquals(l, mutableObjectListOf(6, 1, 2, 3, 4, 5))
+    }
+
+    @Test
+    fun listIteratorInitialIndex() {
+        val iterator = list.asMutableList().listIterator(2)
+        assertEquals(2, iterator.nextIndex())
+    }
+
+    @Test
+    fun subList() {
+        val l = list.asMutableList().subList(1, 4)
+        assertEquals(3, l.size)
+        assertEquals(2, l[0])
+        assertEquals(3, l[1])
+        assertEquals(4, l[2])
+    }
+
+    @Test
+    fun subListContains() {
+        val l = list.asMutableList().subList(1, 4)
+        assertTrue(l.contains(2))
+        assertTrue(l.contains(3))
+        assertTrue(l.contains(4))
+        assertFalse(l.contains(5))
+        assertFalse(l.contains(1))
+    }
+
+    @Test
+    fun subListContainsAll() {
+        val l = list.asMutableList().subList(1, 4)
+        val smallList = listOf(2, 3, 4)
+        assertTrue(l.containsAll(smallList))
+        val largeList = listOf(3, 4, 5)
+        assertFalse(l.containsAll(largeList))
+    }
+
+    @Test
+    fun subListIndexOf() {
+        val l = list.asMutableList().subList(1, 4)
+        assertEquals(0, l.indexOf(2))
+        assertEquals(2, l.indexOf(4))
+        assertEquals(-1, l.indexOf(1))
+        val l2 = mutableObjectListOf(2, 1, 1, 3).asMutableList().subList(1, 2)
+        assertEquals(0, l2.indexOf(1))
+    }
+
+    @Test
+    fun subListIsEmpty() {
+        val l = list.asMutableList().subList(1, 4)
+        assertFalse(l.isEmpty())
+        assertTrue(list.asMutableList().subList(4, 4).isEmpty())
+    }
+
+    @Test
+    fun subListIterator() {
+        val l = list.asMutableList().subList(1, 4)
+        val l2 = mutableListOf<Int>()
+        l.forEach { l2 += it }
+        assertEquals(3, l2.size)
+        assertEquals(2, l2[0])
+        assertEquals(3, l2[1])
+        assertEquals(4, l2[2])
+    }
+
+    @Test
+    fun subListLastIndexOf() {
+        val l = list.asMutableList().subList(1, 4)
+        assertEquals(0, l.lastIndexOf(2))
+        assertEquals(2, l.lastIndexOf(4))
+        assertEquals(-1, l.lastIndexOf(1))
+        val l2 = mutableObjectListOf(2, 1, 1, 3).asMutableList().subList(1, 3)
+        assertEquals(1, l2.lastIndexOf(1))
+    }
+
+    @Test
+    fun subListAdd() {
+        val v = mutableObjectListOf(1, 2, 3)
+        val l = v.asMutableList().subList(1, 2)
+        assertTrue(l.add(4))
+        assertEquals(2, l.size)
+        assertEquals(4, v.size)
+        assertEquals(2, l[0])
+        assertEquals(4, l[1])
+        assertEquals(2, v[1])
+        assertEquals(4, v[2])
+        assertEquals(3, v[3])
+    }
+
+    @Test
+    fun subListAddIndex() {
+        val v = mutableObjectListOf(6, 1, 2, 3)
+        val l = v.asMutableList().subList(1, 3)
+        l.add(1, 4)
+        assertEquals(3, l.size)
+        assertEquals(5, v.size)
+        assertEquals(1, l[0])
+        assertEquals(4, l[1])
+        assertEquals(2, l[2])
+        assertEquals(1, v[1])
+        assertEquals(4, v[2])
+        assertEquals(2, v[3])
+    }
+
+    @Test
+    fun subListAddAllAtIndex() {
+        val v = mutableObjectListOf(6, 1, 2, 3)
+        val l = v.asMutableList().subList(1, 3)
+        l.addAll(1, listOf(4, 5))
+        assertEquals(4, l.size)
+        assertEquals(6, v.size)
+        assertEquals(1, l[0])
+        assertEquals(4, l[1])
+        assertEquals(5, l[2])
+        assertEquals(2, l[3])
+        assertEquals(1, v[1])
+        assertEquals(4, v[2])
+        assertEquals(5, v[3])
+        assertEquals(2, v[4])
+    }
+
+    @Test
+    fun subListAddAll() {
+        val v = mutableObjectListOf(6, 1, 2, 3)
+        val l = v.asMutableList().subList(1, 3)
+        l.addAll(listOf(4, 5))
+        assertEquals(4, l.size)
+        assertEquals(6, v.size)
+        assertEquals(1, l[0])
+        assertEquals(2, l[1])
+        assertEquals(4, l[2])
+        assertEquals(5, l[3])
+        assertEquals(1, v[1])
+        assertEquals(2, v[2])
+        assertEquals(4, v[3])
+        assertEquals(5, v[4])
+        assertEquals(3, v[5])
+    }
+
+    @Test
+    fun subListClear() {
+        val v = mutableObjectListOf(1, 2, 3, 4, 5)
+        val l = v.asMutableList().subList(1, 4)
+        l.clear()
+        assertEquals(0, l.size)
+        assertEquals(2, v.size)
+        assertEquals(1, v[0])
+        assertEquals(5, v[1])
+        kotlin.test.assertNull(v.content[2])
+        kotlin.test.assertNull(v.content[3])
+        kotlin.test.assertNull(v.content[4])
+    }
+
+    @Test
+    fun subListListIterator() {
+        val l = list.asMutableList().subList(1, 4)
+        val listIterator = l.listIterator()
+        assertTrue(listIterator.hasNext())
+        assertFalse(listIterator.hasPrevious())
+        assertEquals(0, listIterator.nextIndex())
+        assertEquals(2, listIterator.next())
+    }
+
+    @Test
+    fun subListListIteratorWithIndex() {
+        val l = list.asMutableList().subList(1, 4)
+        val listIterator = l.listIterator(1)
+        assertTrue(listIterator.hasNext())
+        assertTrue(listIterator.hasPrevious())
+        assertEquals(1, listIterator.nextIndex())
+        assertEquals(3, listIterator.next())
+    }
+
+    @Test
+    fun subListRemove() {
+        val l = mutableObjectListOf(1, 2, 3, 4, 5)
+        val l2 = l.asMutableList().subList(1, 4)
+        assertTrue(l2.remove(3))
+        assertEquals(l, mutableObjectListOf(1, 2, 4, 5))
+        assertEquals(2, l2.size)
+        assertEquals(2, l2[0])
+        assertEquals(4, l2[1])
+        assertFalse(l2.remove(3))
+        assertEquals(l, mutableObjectListOf(1, 2, 4, 5))
+        assertEquals(2, l2.size)
+    }
+
+    @Test
+    fun subListRemoveAll() {
+        val l = mutableObjectListOf(1, 2, 3, 4, 5)
+        val l2 = l.asMutableList().subList(1, 4)
+        assertFalse(l2.removeAll(listOf(1, 5, -1)))
+        assertEquals(5, l.size)
+        assertEquals(3, l2.size)
+        assertTrue(l2.removeAll(listOf(3, 4, 5)))
+        assertEquals(3, l.size)
+        assertEquals(1, l2.size)
+    }
+
+    @Test
+    fun subListRemoveAt() {
+        val l = mutableObjectListOf(1, 2, 3, 4, 5)
+        val l2 = l.asMutableList().subList(1, 4)
+        assertEquals(3, l2.removeAt(1))
+        assertEquals(4, l.size)
+        assertEquals(2, l2.size)
+        assertEquals(4, l2.removeAt(1))
+        assertEquals(1, l2.size)
+    }
+
+    @Test
+    fun subListRetainAll() {
+        val l = mutableObjectListOf(1, 2, 3, 4, 5)
+        val l2 = l.asMutableList().subList(1, 4)
+        val l3 = objectListOf(1, 2, 3, 4, 5)
+        assertFalse(l2.retainAll(l3.asList()))
+        assertFalse(l2.retainAll(listOf(2, 3, 4)))
+        assertEquals(3, l2.size)
+        assertEquals(5, l.size)
+        assertTrue(l2.retainAll(setOf(1, 2, 4)))
+        assertEquals(4, l.size)
+        assertEquals(2, l2.size)
+        assertEquals(l, objectListOf(1, 2, 4, 5))
+    }
+
+    @Test
+    fun subListSet() {
+        val l = mutableObjectListOf(1, 2, 3, 4, 5)
+        val l2 = l.asMutableList().subList(1, 4)
+        l2[1] = 10
+        assertEquals(10, l2[1])
+        assertEquals(3, l2.size)
+        assertEquals(10, l[2])
+    }
+
+    @Test
+    fun subListSubList() {
+        val l = objectListOf(1, 2, 3, 4, 5).asList().subList(1, 5)
+        val l2 = l.subList(1, 3)
+        assertEquals(2, l2.size)
+        assertEquals(3, l2[0])
+    }
+
+    @Suppress("KotlinConstantConditions")
+    @Test
+    fun list_outOfBounds_Get_Below() {
+        assertFailsWith(IndexOutOfBoundsException::class) {
+            val l = mutableObjectListOf(1, 2, 3, 4).asMutableList()
+            l[-1]
+        }
+    }
+
+    @Suppress("KotlinConstantConditions")
+    @Test
+    fun sublist_outOfBounds_Get_Below() {
+        assertFailsWith(IndexOutOfBoundsException::class) {
+            val l = mutableObjectListOf(1, 2, 3, 4).asMutableList().subList(1, 2)
+            l[-1]
+        }
+    }
+
+    @Test
+    fun list_outOfBounds_Get_Above() {
+        assertFailsWith(IndexOutOfBoundsException::class) {
+            val l = mutableObjectListOf(1, 2, 3, 4).asMutableList()
+            l[4]
+        }
+    }
+
+    @Test
+    fun sublist_outOfBounds_Get_Above() {
+        assertFailsWith(IndexOutOfBoundsException::class) {
+            val l = mutableObjectListOf(1, 2, 3, 4).asMutableList().subList(1, 2)
+            l[1]
+        }
+    }
+
+    @Test
+    fun list_outOfBounds_RemoveAt_Below() {
+        assertFailsWith(IndexOutOfBoundsException::class) {
+            val l = mutableObjectListOf(0, 1, 2, 3).asMutableList()
+            l.removeAt(-1)
+        }
+    }
+
+    @Test
+    fun sublist_outOfBounds_RemoveAt_Below() {
+        assertFailsWith(IndexOutOfBoundsException::class) {
+            val l = mutableObjectListOf(0, 1, 2, 3).asMutableList().subList(1, 2)
+            l.removeAt(-1)
+        }
+    }
+
+    @Test
+    fun list_outOfBounds_RemoveAt_Above() {
+        assertFailsWith(IndexOutOfBoundsException::class) {
+            val l = mutableObjectListOf(0, 1, 2, 3).asMutableList()
+            l.removeAt(4)
+        }
+    }
+
+    @Test
+    fun sublist_outOfBounds_RemoveAt_Above() {
+        assertFailsWith(IndexOutOfBoundsException::class) {
+            val l = mutableObjectListOf(0, 1, 2, 3).asMutableList().subList(1, 2)
+            l.removeAt(1)
+        }
+    }
+
+    @Suppress("KotlinConstantConditions")
+    @Test
+    fun list_outOfBounds_Set_Below() {
+        assertFailsWith(IndexOutOfBoundsException::class) {
+            val l = mutableObjectListOf(0, 1, 2, 3).asMutableList()
+            l[-1] = 1
+        }
+    }
+
+    @Suppress("KotlinConstantConditions")
+    @Test
+    fun sublist_outOfBounds_Set_Below() {
+        assertFailsWith(IndexOutOfBoundsException::class) {
+            val l = mutableObjectListOf(0, 1, 2, 3).asMutableList().subList(1, 2)
+            l[-1] = 1
+        }
+    }
+
+    @Test
+    fun list_outOfBounds_Set_Above() {
+        assertFailsWith(IndexOutOfBoundsException::class) {
+            val l = mutableObjectListOf(0, 1, 2, 3).asMutableList()
+            l[4] = 1
+        }
+    }
+
+    @Test
+    fun sublist_outOfBounds_Set_Above() {
+        assertFailsWith(IndexOutOfBoundsException::class) {
+            val l = mutableObjectListOf(0, 1, 2, 3).asMutableList().subList(1, 2)
+            l[1] = 1
+        }
+    }
+
+    @Test
+    fun list_outOfBounds_SubList_Below() {
+        assertFailsWith(IndexOutOfBoundsException::class) {
+            val l = mutableObjectListOf(0, 1, 2, 3).asMutableList()
+            l.subList(-1, 1)
+        }
+    }
+
+    @Test
+    fun sublist_outOfBounds_SubList_Below() {
+        assertFailsWith(IndexOutOfBoundsException::class) {
+            val l = mutableObjectListOf(0, 1, 2, 3).asMutableList().subList(1, 2)
+            l.subList(-1, 1)
+        }
+    }
+
+    @Test
+    fun list_outOfBounds_SubList_Above() {
+        assertFailsWith(IndexOutOfBoundsException::class) {
+            val l = mutableObjectListOf(0, 1, 2, 3).asMutableList()
+            l.subList(5, 5)
+        }
+    }
+
+    @Test
+    fun sublist_outOfBounds_SubList_Above() {
+        assertFailsWith(IndexOutOfBoundsException::class) {
+            val l = mutableObjectListOf(0, 1, 2, 3).asMutableList().subList(1, 2)
+            l.subList(1, 2)
+        }
+    }
+
+    @Test
+    fun list_outOfBounds_SubList_Order() {
+        assertFailsWith(IllegalArgumentException::class) {
+            val l = mutableObjectListOf(0, 1, 2, 3).asMutableList()
+            l.subList(3, 2)
+        }
+    }
+
+    @Test
+    fun sublist_outOfBounds_SubList_Order() {
+        assertFailsWith(IllegalArgumentException::class) {
+            val l = mutableObjectListOf(0, 1, 2, 3).asMutableList().subList(1, 2)
+            l.subList(1, 0)
+        }
+    }
+}
diff --git a/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/AnimatedContentTest.kt b/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/AnimatedContentTest.kt
index 2767e5aa..67921dc 100644
--- a/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/AnimatedContentTest.kt
+++ b/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/AnimatedContentTest.kt
@@ -28,11 +28,13 @@
 import androidx.compose.animation.core.updateTransition
 import androidx.compose.foundation.background
 import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Spacer
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.requiredSize
 import androidx.compose.foundation.layout.size
 import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.layout.wrapContentSize
 import androidx.compose.material3.Scaffold
 import androidx.compose.material3.Surface
 import androidx.compose.material3.TabRow
@@ -1115,6 +1117,77 @@
     }
 
     @Test
+    fun testRightEnterExitTransitionIsChosenDuringInterruption() {
+        var flag by mutableStateOf(false)
+        var fixedPosition: Offset? = null
+        var slidePosition: Offset? = null
+        rule.setContent {
+            AnimatedContent(
+                targetState = flag,
+                label = "",
+                transitionSpec = {
+                    if (false isTransitioningTo true) {
+                        ContentTransform(
+                            targetContentEnter = EnterTransition.None,
+                            initialContentExit = slideOutOfContainer(
+                                AnimatedContentTransitionScope.SlideDirection.Start,
+                                animationSpec = tween(durationMillis = 500)
+                            ),
+                            targetContentZIndex = -1.0f,
+                            sizeTransform = SizeTransform(clip = false)
+                        )
+                    } else {
+                        ContentTransform(
+                            targetContentEnter = slideIntoContainer(
+                                AnimatedContentTransitionScope.SlideDirection.End
+                            ),
+                            initialContentExit = ExitTransition.Hold,
+                            targetContentZIndex = 0.0f,
+                            sizeTransform = SizeTransform(clip = false)
+                        )
+                    }
+                },
+                modifier = Modifier.fillMaxSize()
+            ) { flag ->
+                Spacer(
+                    modifier = Modifier
+                        .wrapContentSize(Alignment.Center)
+                        .size(256.dp)
+                        .onGloballyPositioned {
+                            if (flag) {
+                                fixedPosition = it.positionInRoot()
+                            } else {
+                                slidePosition = it.positionInRoot()
+                            }
+                        }
+                )
+            }
+        }
+
+        rule.runOnIdle {
+            flag = true
+        }
+        rule.waitUntil { fixedPosition != null }
+        val initialFixedPosition = fixedPosition
+        // Advance 10 frames
+        repeat(10) {
+            val lastSlidePos = slidePosition
+            rule.waitUntil { slidePosition != lastSlidePos }
+            assertEquals(initialFixedPosition, fixedPosition)
+        }
+
+        // Change the target state amid transition, creating an interruption
+        flag = false
+        // Advance 10 frames
+        repeat(10) {
+            val lastSlidePos = slidePosition
+            rule.waitUntil { slidePosition != lastSlidePos }
+            assertEquals(initialFixedPosition, fixedPosition)
+        }
+        rule.waitForIdle()
+    }
+
+    @Test
     fun testScaleToFitWithFitHeight() {
         var target by mutableStateOf(true)
         var box1Coords: LayoutCoordinates? = null
diff --git a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedContent.kt b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedContent.kt
index b82c044..e557851 100644
--- a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedContent.kt
+++ b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedContent.kt
@@ -820,13 +820,14 @@
         }
         if (!contentMap.containsKey(targetState) || !contentMap.containsKey(currentState)) {
             contentMap.clear()
-            val enter = transitionSpec(rootScope).targetContentEnter
-            val exit = rootScope.transitionSpec().initialContentExit
-            val zIndex = transitionSpec(rootScope).targetContentZIndex
             currentlyVisible.fastForEach { stateForContent ->
                 contentMap[stateForContent] = {
+                    // Only update content transform when enter/exit _direction_ changes.
+                    val contentTransform = remember(stateForContent == targetState) {
+                        rootScope.transitionSpec()
+                    }
                     PopulateContentFor(
-                        stateForContent, rootScope, enter, exit, zIndex, currentlyVisible, content
+                        stateForContent, rootScope, contentTransform, currentlyVisible, content
                     )
                 }
             }
@@ -871,33 +872,32 @@
 private inline fun <S> Transition<S>.PopulateContentFor(
     stateForContent: S,
     rootScope: AnimatedContentRootScope<S>,
-    enter: EnterTransition,
-    exit: ExitTransition,
-    zIndex: Float,
+    contentTransform: ContentTransform,
     currentlyVisible: SnapshotStateList<S>,
     crossinline content: @Composable() AnimatedContentScope.(targetState: S) -> Unit
 ) {
-    var activeEnter by remember { mutableStateOf(enter) }
+    var activeEnter by remember { mutableStateOf(contentTransform.targetContentEnter) }
     var activeExit by remember { mutableStateOf(ExitTransition.None) }
-    val targetZIndex = remember { zIndex }
+    val targetZIndex = remember { contentTransform.targetContentZIndex }
 
     val isEntering = targetState == stateForContent
     if (targetState == currentState) {
         // Transition finished, reset active enter & exit.
-        activeEnter = androidx.compose.animation.EnterTransition.None
-        activeExit = androidx.compose.animation.ExitTransition.None
+        activeEnter = EnterTransition.None
+        activeExit = ExitTransition.None
     } else if (isEntering) {
         // If the previous enter transition never finishes when multiple
         // interruptions happen, avoid adding new enter transitions for simplicity.
-        if (activeEnter == androidx.compose.animation.EnterTransition.None)
-            activeEnter += enter
+        if (activeEnter == EnterTransition.None)
+            activeEnter += contentTransform.targetContentEnter
     } else {
         // If the previous exit transition never finishes when multiple
         // interruptions happen, avoid adding new enter transitions for simplicity.
-        if (activeExit == androidx.compose.animation.ExitTransition.None) {
-            activeExit += exit
+        if (activeExit == ExitTransition.None) {
+            activeExit += contentTransform.initialContentExit
         }
     }
+
     val childData = remember { AnimatedContentRootScope.ChildData(stateForContent) }
     AnimatedEnterExitImpl(
         this,
@@ -915,16 +915,15 @@
             .then(
                 if (isEntering) {
                     activeEnter[ScaleToFitTransitionKey]
-                        ?: activeExit[ScaleToFitTransitionKey] ?: androidx.compose.ui.Modifier
+                        ?: activeExit[ScaleToFitTransitionKey] ?: Modifier
                 } else {
                     activeExit[ScaleToFitTransitionKey]
-                        ?: activeEnter[ScaleToFitTransitionKey] ?: androidx.compose.ui.Modifier
+                        ?: activeEnter[ScaleToFitTransitionKey] ?: Modifier
                 }
             ),
         shouldDisposeBlock = { currentState, targetState ->
-            currentState == androidx.compose.animation.EnterExitState.PostExit &&
-                targetState == androidx.compose.animation.EnterExitState.PostExit &&
-                !activeExit.data.hold
+            currentState == EnterExitState.PostExit &&
+                targetState == EnterExitState.PostExit && !activeExit.data.hold
         },
         onLookaheadMeasured = {
             if (isEntering) rootScope.targetSizeMap.getOrPut(targetState) {
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 d428ebd..2eaec85 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
@@ -302,7 +302,8 @@
                 }
                 A(%composer, 0)
                 M3({ %composer: Composer?, %changed: Int ->
-                  sourceInformationMarkerStart(%composer, <>, "C<A()>,<A()>:Test.kt")
+                  %composer.startReplaceableGroup(<>)
+                  sourceInformation(%composer, "C<A()>,<A()>:Test.kt")
                   A(%composer, 0)
                   if (condition) {
                     %composer.endToMarker(tmp0_marker)
@@ -315,7 +316,7 @@
                     return
                   }
                   A(%composer, 0)
-                  sourceInformationMarkerEnd(%composer)
+                  %composer.endReplaceableGroup()
                 }, %composer, 0)
                 A(%composer, 0)
                 if (isTraceInProgress()) {
@@ -374,7 +375,8 @@
                 }
                 A(%composer, 0)
                 M3({ %composer: Composer?, %changed: Int ->
-                  sourceInformationMarkerStart(%composer, <>, "C<A()>,<A()>:Test.kt")
+                  %composer.startReplaceableGroup(<>)
+                  sourceInformation(%composer, "C<A()>,<A()>:Test.kt")
                   A(%composer, 0)
                   if (a) {
                     %composer.endToMarker(tmp0_marker)
@@ -387,10 +389,11 @@
                     return
                   }
                   A(%composer, 0)
-                  sourceInformationMarkerEnd(%composer)
+                  %composer.endReplaceableGroup()
                 }, %composer, 0)
                 M3({ %composer: Composer?, %changed: Int ->
-                  sourceInformationMarkerStart(%composer, <>, "C<A()>,<A()>:Test.kt")
+                  %composer.startReplaceableGroup(<>)
+                  sourceInformation(%composer, "C<A()>,<A()>:Test.kt")
                   A(%composer, 0)
                   if (b) {
                     %composer.endToMarker(tmp0_marker)
@@ -403,7 +406,7 @@
                     return
                   }
                   A(%composer, 0)
-                  sourceInformationMarkerEnd(%composer)
+                  %composer.endReplaceableGroup()
                 }, %composer, 0)
                 A(%composer, 0)
                 if (isTraceInProgress()) {
@@ -451,14 +454,15 @@
                 }
                 A(%composer, 0)
                 M3({ %composer: Composer?, %changed: Int ->
-                  sourceInformationMarkerStart(%composer, <>, "C<A()>,<A()>:Test.kt")
+                  %composer.startReplaceableGroup(<>)
+                  sourceInformation(%composer, "C<A()>,<A()>:Test.kt")
                   A(%composer, 0)
                   if (condition) {
-                    sourceInformationMarkerEnd(%composer)
+                    %composer.endReplaceableGroup()
                     return@M3
                   }
                   A(%composer, 0)
-                  sourceInformationMarkerEnd(%composer)
+                  %composer.endReplaceableGroup()
                 }, %composer, 0)
                 A(%composer, 0)
                 if (isTraceInProgress()) {
@@ -498,7 +502,8 @@
                       traceEventStart(<>, %changed, -1, <>)
                     }
                     M1({ %composer: Composer?, %changed: Int ->
-                      sourceInformationMarkerStart(%composer, <>, "C:Test.kt")
+                      %composer.startReplaceableGroup(<>)
+                      sourceInformation(%composer, "C:Test.kt")
                       if (condition) {
                         %composer.endToMarker(tmp0_marker)
                         if (isTraceInProgress()) {
@@ -506,7 +511,7 @@
                         }
                         return@composableLambdaInstance
                       }
-                      sourceInformationMarkerEnd(%composer)
+                      %composer.endReplaceableGroup()
                     }, %composer, 0)
                     if (isTraceInProgress()) {
                       traceEventEnd()
@@ -572,12 +577,13 @@
                   sourceInformationMarkerStart(%composer, <>, "C<A()>,<M1>,<A()>:Test.kt")
                   A(%composer, 0)
                   M1({ %composer: Composer?, %changed: Int ->
-                    sourceInformationMarkerStart(%composer, <>, "C:Test.kt")
+                    %composer.startReplaceableGroup(<>)
+                    sourceInformation(%composer, "C:Test.kt")
                     if (condition) {
-                      sourceInformationMarkerEnd(%composer)
+                      %composer.endReplaceableGroup()
                       return@M1
                     }
-                    sourceInformationMarkerEnd(%composer)
+                    %composer.endReplaceableGroup()
                   }, %composer, 0)
                   A(%composer, 0)
                   sourceInformationMarkerEnd(%composer)
@@ -630,18 +636,20 @@
                 A(%composer, 0)
                 M3({ %composer: Composer?, %changed: Int ->
                   val tmp0_marker = %composer.currentMarker
-                  sourceInformationMarkerStart(%composer, <>, "C<A()>,<M1>,<A()>:Test.kt")
+                  %composer.startReplaceableGroup(<>)
+                  sourceInformation(%composer, "C<A()>,<M1>,<A()>:Test.kt")
                   A(%composer, 0)
                   M1({ %composer: Composer?, %changed: Int ->
-                    sourceInformationMarkerStart(%composer, <>, "C:Test.kt")
+                    %composer.startReplaceableGroup(<>)
+                    sourceInformation(%composer, "C:Test.kt")
                     if (condition) {
                       %composer.endToMarker(tmp0_marker)
                       return@M3
                     }
-                    sourceInformationMarkerEnd(%composer)
+                    %composer.endReplaceableGroup()
                   }, %composer, 0)
                   A(%composer, 0)
-                  sourceInformationMarkerEnd(%composer)
+                  %composer.endReplaceableGroup()
                 }, %composer, 0)
                 A(%composer, 0)
                 if (isTraceInProgress()) {
@@ -694,7 +702,8 @@
                 }
                 A(%composer, 0)
                 M1({ %composer: Composer?, %changed: Int ->
-                  sourceInformationMarkerStart(%composer, <>, "C<A()>,<A()>:Test.kt")
+                  %composer.startReplaceableGroup(<>)
+                  sourceInformation(%composer, "C<A()>,<A()>:Test.kt")
                   A(%composer, 0)
                   %composer.startReplaceableGroup(<>)
                   sourceInformation(%composer, "*<A()>,<A()>")
@@ -714,7 +723,7 @@
                   }
                   %composer.endReplaceableGroup()
                   A(%composer, 0)
-                  sourceInformationMarkerEnd(%composer)
+                  %composer.endReplaceableGroup()
                 }, %composer, 0)
                 A(%composer, 0)
                 if (isTraceInProgress()) {
@@ -769,24 +778,26 @@
                 }
                 A(%composer, 0)
                 M3({ %composer: Composer?, %changed: Int ->
-                  sourceInformationMarkerStart(%composer, <>, "C<A()>,<A()>:Test.kt")
+                  %composer.startReplaceableGroup(<>)
+                  sourceInformation(%composer, "C<A()>,<A()>:Test.kt")
                   A(%composer, 0)
                   if (condition) {
-                    sourceInformationMarkerEnd(%composer)
+                    %composer.endReplaceableGroup()
                     return@M3
                   }
                   A(%composer, 0)
-                  sourceInformationMarkerEnd(%composer)
+                  %composer.endReplaceableGroup()
                 }, %composer, 0)
                 M3({ %composer: Composer?, %changed: Int ->
-                  sourceInformationMarkerStart(%composer, <>, "C<A()>,<A()>:Test.kt")
+                  %composer.startReplaceableGroup(<>)
+                  sourceInformation(%composer, "C<A()>,<A()>:Test.kt")
                   A(%composer, 0)
                   if (condition) {
-                    sourceInformationMarkerEnd(%composer)
+                    %composer.endReplaceableGroup()
                     return@M3
                   }
                   A(%composer, 0)
-                  sourceInformationMarkerEnd(%composer)
+                  %composer.endReplaceableGroup()
                 }, %composer, 0)
                 A(%composer, 0)
                 if (isTraceInProgress()) {
@@ -839,14 +850,16 @@
                 }
                 Text("Root - before", %composer, 0b0110)
                 M1({ %composer: Composer?, %changed: Int ->
-                  sourceInformationMarkerStart(%composer, <>, "C<Text("...>,<Text("...>:Test.kt")
+                  %composer.startReplaceableGroup(<>)
+                  sourceInformation(%composer, "C<Text("...>,<Text("...>:Test.kt")
                   Text("M1 - begin", %composer, 0b0110)
                   %composer.startReplaceableGroup(<>)
                   sourceInformation(%composer, "<Text("...>,<M1>")
                   if (condition) {
                     Text("if - begin", %composer, 0b0110)
                     M1({ %composer: Composer?, %changed: Int ->
-                      sourceInformationMarkerStart(%composer, <>, "C<Text("...>:Test.kt")
+                      %composer.startReplaceableGroup(<>)
+                      sourceInformation(%composer, "C<Text("...>:Test.kt")
                       Text("In CCM1", %composer, 0b0110)
                       %composer.endToMarker(tmp0_marker)
                       if (isTraceInProgress()) {
@@ -856,12 +869,12 @@
                         test_CM1_CCM1_RetFun(condition, %composer, updateChangedFlags(%changed or 0b0001))
                       }
                       return
-                      sourceInformationMarkerEnd(%composer)
+                      %composer.endReplaceableGroup()
                     }, %composer, 0)
                   }
                   %composer.endReplaceableGroup()
                   Text("M1 - end", %composer, 0b0110)
-                  sourceInformationMarkerEnd(%composer)
+                  %composer.endReplaceableGroup()
                 }, %composer, 0)
                 Text("Root - end", %composer, 0b0110)
                 if (isTraceInProgress()) {
@@ -905,13 +918,14 @@
                 traceEventStart(<>, %changed, -1, <>)
               }
               FakeBox({ %composer: Composer?, %changed: Int ->
-                sourceInformationMarkerStart(%composer, <>, "C<A()>:Test.kt")
+                %composer.startReplaceableGroup(<>)
+                sourceInformation(%composer, "C<A()>:Test.kt")
                 if (condition) {
-                  sourceInformationMarkerEnd(%composer)
+                  %composer.endReplaceableGroup()
                   return@FakeBox
                 }
                 A(%composer, 0)
-                sourceInformationMarkerEnd(%composer)
+                %composer.endReplaceableGroup()
               }, %composer, 0)
               if (isTraceInProgress()) {
                 traceEventEnd()
@@ -1087,13 +1101,14 @@
                   traceEventStart(<>, %dirty, -1, <>)
                 }
                 IW({ %composer: Composer?, %changed: Int ->
-                  sourceInformationMarkerStart(%composer, <>, "C<A()>:Test.kt")
+                  %composer.startReplaceableGroup(<>)
+                  sourceInformation(%composer, "C<A()>:Test.kt")
                   if (condition) {
-                    sourceInformationMarkerEnd(%composer)
+                    %composer.endReplaceableGroup()
                     return@IW
                   }
                   A(%composer, 0)
-                  sourceInformationMarkerEnd(%composer)
+                  %composer.endReplaceableGroup()
                 }, %composer, 0)
                 if (isTraceInProgress()) {
                   traceEventEnd()
@@ -1189,7 +1204,8 @@
                 }
                 Text("Some text", %composer, 0b0110)
                 M1({ %composer: Composer?, %changed: Int ->
-                  sourceInformationMarkerStart(%composer, <>, "C:Test.kt")
+                  %composer.startReplaceableGroup(<>)
+                  sourceInformation(%composer, "C:Test.kt")
                   Identity {
                     if (condition) {
                       %composer.endToMarker(tmp0_marker)
@@ -1202,7 +1218,7 @@
                       return
                     }
                   }
-                  sourceInformationMarkerEnd(%composer)
+                  %composer.endReplaceableGroup()
                 }, %composer, 0)
                 Text("Some more text", %composer, 0b0110)
                 if (isTraceInProgress()) {
@@ -1247,14 +1263,15 @@
                 }
                 Text("Some text", %composer, 0b0110)
                 M1({ %composer: Composer?, %changed: Int ->
-                  sourceInformationMarkerStart(%composer, <>, "C:Test.kt")
+                  %composer.startReplaceableGroup(<>)
+                  sourceInformation(%composer, "C:Test.kt")
                   Identity {
                     if (condition) {
-                      sourceInformationMarkerEnd(%composer)
+                      %composer.endReplaceableGroup()
                       return@M1
                     }
                   }
-                  sourceInformationMarkerEnd(%composer)
+                  %composer.endReplaceableGroup()
                 }, %composer, 0)
                 Text("Some more text", %composer, 0b0110)
                 if (isTraceInProgress()) {
@@ -1271,6 +1288,154 @@
     )
 
     @Test
+    fun verifyEarlyExitFromNestedInlineFunction() = verifyComposeIrTransform(
+        source = """
+            import androidx.compose.runtime.*
+
+            @Composable
+            @NonRestartableComposable
+            fun Test(condition: Boolean) {
+                Text("Before outer")
+                InlineLinearA {
+                    Text("Before inner")
+                    InlineLinearB inner@{
+                        Text("Before return")
+                        if (condition) return@inner
+                        Text("After return")
+                    }
+                    Text("After inner")
+                }
+                Text("Before outer")
+            }
+        """,
+        expectedTransformed = """
+            @Composable
+            @NonRestartableComposable
+            fun Test(condition: Boolean, %composer: Composer?, %changed: Int) {
+              %composer.startReplaceableGroup(<>)
+              sourceInformation(%composer, "C(Test)<Text("...>,<Inline...>,<Text("...>:Test.kt")
+              if (isTraceInProgress()) {
+                traceEventStart(<>, %changed, -1, <>)
+              }
+              Text("Before outer", %composer, 0b0110)
+              InlineLinearA({ %composer: Composer?, %changed: Int ->
+                sourceInformationMarkerStart(%composer, <>, "C<Text("...>,<Inline...>,<Text("...>:Test.kt")
+                Text("Before inner", %composer, 0b0110)
+                InlineLinearB({ %composer: Composer?, %changed: Int ->
+                  %composer.startReplaceableGroup(<>)
+                  sourceInformation(%composer, "C<Text("...>,<Text("...>:Test.kt")
+                  Text("Before return", %composer, 0b0110)
+                  if (condition) {
+                    %composer.endReplaceableGroup()
+                    return@InlineLinearB
+                  }
+                  Text("After return", %composer, 0b0110)
+                  %composer.endReplaceableGroup()
+                }, %composer, 0)
+                Text("After inner", %composer, 0b0110)
+                sourceInformationMarkerEnd(%composer)
+              }, %composer, 0)
+              Text("Before outer", %composer, 0b0110)
+              if (isTraceInProgress()) {
+                traceEventEnd()
+              }
+              %composer.endReplaceableGroup()
+            }
+        """,
+        extra = """
+            import androidx.compose.runtime.*
+
+            @Composable
+            fun Text(value: String) { }
+
+            @Composable
+            inline fun InlineLinearA(content: @Composable () -> Unit) {
+                content()
+            }
+
+            @Composable
+            inline fun InlineLinearB(content: @Composable () -> Unit) {
+                content()
+            }
+        """
+    )
+
+    @Test
+    fun verifyEarlyExitFromMultiLevelNestedInlineFunction() = verifyComposeIrTransform(
+        source = """
+            import androidx.compose.runtime.*
+
+            @Composable
+            @NonRestartableComposable
+            fun Test(condition: Boolean) {
+                Text("Before outer")
+                InlineLinearA outer@{
+                    Text("Before inner")
+                    InlineLinearB {
+                        Text("Before return")
+                        if (condition) return@outer
+                        Text("After return")
+                    }
+                    Text("After inner")
+                }
+                Text("Before outer")
+            }
+        """,
+        expectedTransformed = """
+            @Composable
+            @NonRestartableComposable
+            fun Test(condition: Boolean, %composer: Composer?, %changed: Int) {
+              %composer.startReplaceableGroup(<>)
+              sourceInformation(%composer, "C(Test)<Text("...>,<Inline...>,<Text("...>:Test.kt")
+              if (isTraceInProgress()) {
+                traceEventStart(<>, %changed, -1, <>)
+              }
+              Text("Before outer", %composer, 0b0110)
+              InlineLinearA({ %composer: Composer?, %changed: Int ->
+                val tmp0_marker = %composer.currentMarker
+                %composer.startReplaceableGroup(<>)
+                sourceInformation(%composer, "C<Text("...>,<Inline...>,<Text("...>:Test.kt")
+                Text("Before inner", %composer, 0b0110)
+                InlineLinearB({ %composer: Composer?, %changed: Int ->
+                  %composer.startReplaceableGroup(<>)
+                  sourceInformation(%composer, "C<Text("...>,<Text("...>:Test.kt")
+                  Text("Before return", %composer, 0b0110)
+                  if (condition) {
+                    %composer.endToMarker(tmp0_marker)
+                    return@InlineLinearA
+                  }
+                  Text("After return", %composer, 0b0110)
+                  %composer.endReplaceableGroup()
+                }, %composer, 0)
+                Text("After inner", %composer, 0b0110)
+                %composer.endReplaceableGroup()
+              }, %composer, 0)
+              Text("Before outer", %composer, 0b0110)
+              if (isTraceInProgress()) {
+                traceEventEnd()
+              }
+              %composer.endReplaceableGroup()
+            }
+        """,
+        extra = """
+            import androidx.compose.runtime.*
+
+            @Composable
+            fun Text(value: String) { }
+
+            @Composable
+            inline fun InlineLinearA(content: @Composable () -> Unit) {
+                content()
+            }
+
+            @Composable
+            inline fun InlineLinearB(content: @Composable () -> Unit) {
+                content()
+            }
+        """
+    )
+
+    @Test
     fun testEnsureRuntimeTestWillCompile_CL() {
         classLoader(
             """
@@ -1332,7 +1497,8 @@
                 }
                 Text("Root - before", %composer, 0b0110)
                 M1({ %composer: Composer?, %changed: Int ->
-                  sourceInformationMarkerStart(%composer, <>, "C<Text("...>,<Text("...>:Test.kt")
+                  %composer.startReplaceableGroup(<>)
+                  sourceInformation(%composer, "C<Text("...>,<Text("...>:Test.kt")
                   Text("M1 - before", %composer, 0b0110)
                   if (condition) {
                     %composer.endToMarker(tmp0_marker)
@@ -1345,7 +1511,7 @@
                     return
                   }
                   Text("M1 - after", %composer, 0b0110)
-                  sourceInformationMarkerEnd(%composer)
+                  %composer.endReplaceableGroup()
                 }, %composer, 0)
                 Text("Root - after", %composer, 0b0110)
                 if (isTraceInProgress()) {
@@ -6182,16 +6348,18 @@
                 }
                 Inline1({ %composer: Composer?, %changed: Int ->
                   val tmp0_marker = %composer.currentMarker
-                  sourceInformationMarkerStart(%composer, <>, "C<Inline...>:Test.kt")
+                  %composer.startReplaceableGroup(<>)
+                  sourceInformation(%composer, "C<Inline...>:Test.kt")
                   Inline2({ %composer: Composer?, %changed: Int ->
-                    sourceInformationMarkerStart(%composer, <>, "C:Test.kt")
+                    %composer.startReplaceableGroup(<>)
+                    sourceInformation(%composer, "C:Test.kt")
                     if (true) {
                       %composer.endToMarker(tmp0_marker)
                       return@Inline1
                     }
-                    sourceInformationMarkerEnd(%composer)
+                    %composer.endReplaceableGroup()
                   }, %composer, 0)
-                  sourceInformationMarkerEnd(%composer)
+                  %composer.endReplaceableGroup()
                 }, %composer, 0)
                 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 4fb99f6..a3a2934 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
@@ -174,4 +174,77 @@
             }
         """
     )
+
+    @Test
+    fun verifyEarlyExitFromMultiLevelNestedInlineFunction() = verifyComposeIrTransform(
+        source = """
+            import androidx.compose.runtime.*
+
+            @Composable
+            @NonRestartableComposable
+            fun Test(condition: Boolean) {
+                Text("Before outer")
+                InlineLinearA outer@{
+                    Text("Before inner")
+                    InlineLinearB {
+                        Text("Before return")
+                        if (condition) return@outer
+                        Text("After return")
+                    }
+                    Text("After inner")
+                }
+                Text("Before outer")
+            }
+        """,
+        expectedTransformed = """
+            @Composable
+            @NonRestartableComposable
+            fun Test(condition: Boolean, %composer: Composer?, %changed: Int) {
+              %composer.startReplaceableGroup(<>)
+              sourceInformation(%composer, "C(Test)")
+              if (isTraceInProgress()) {
+                traceEventStart(<>, %changed, -1, <>)
+              }
+              Text("Before outer", %composer, 0b0110)
+              InlineLinearA({ %composer: Composer?, %changed: Int ->
+                val tmp0_marker = %composer.currentMarker
+                %composer.startReplaceableGroup(<>)
+                Text("Before inner", %composer, 0b0110)
+                InlineLinearB({ %composer: Composer?, %changed: Int ->
+                  %composer.startReplaceableGroup(<>)
+                  Text("Before return", %composer, 0b0110)
+                  if (condition) {
+                    %composer.endToMarker(tmp0_marker)
+                    return@InlineLinearA
+                  }
+                  Text("After return", %composer, 0b0110)
+                  %composer.endReplaceableGroup()
+                }, %composer, 0)
+                Text("After inner", %composer, 0b0110)
+                %composer.endReplaceableGroup()
+              }, %composer, 0)
+              Text("Before outer", %composer, 0b0110)
+              if (isTraceInProgress()) {
+                traceEventEnd()
+              }
+              %composer.endReplaceableGroup()
+            }
+        """,
+        extra = """
+            import androidx.compose.runtime.*
+
+            @Composable
+            fun Text(value: String) { }
+
+            @Composable
+            inline fun InlineLinearA(content: @Composable () -> Unit) {
+                content()
+            }
+
+            @Composable
+            inline fun InlineLinearB(content: @Composable () -> Unit) {
+                content()
+            }
+        """
+    )
 }
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 2aa05c6..aaaba3b2 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
@@ -175,7 +175,8 @@
                 }
                 A(%composer, 0)
                 Wrapper({ %composer: Composer?, %changed: Int ->
-                  sourceInformationMarkerStart(%composer, <>, "C<A()>,<A()>:Test.kt")
+                  %composer.startReplaceableGroup(<>)
+                  sourceInformation(%composer, "C<A()>,<A()>:Test.kt")
                   A(%composer, 0)
                   if (!condition) {
                     %composer.endToMarker(tmp0_marker)
@@ -188,7 +189,7 @@
                     return
                   }
                   A(%composer, 0)
-                  sourceInformationMarkerEnd(%composer)
+                  %composer.endReplaceableGroup()
                 }, %composer, 0)
                 A(%composer, 0)
                 if (isTraceInProgress()) {
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 b1b54c0..1b4c6c2f 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
@@ -978,17 +978,10 @@
         val bodyPreamble = mutableStatementContainer()
         val bodyEpilogue = mutableStatementContainer()
 
-        // First generate the source information call
         val isInlineLambda = scope.isInlinedLambda
-        if (collectSourceInformation) {
-            if (isInlineLambda) {
-                sourceInformationPreamble.statements.add(
-                    irSourceInformationMarkerStart(body, scope)
-                )
-                bodyEpilogue.statements.add(irSourceInformationMarkerEnd(body, scope))
-            } else {
-                sourceInformationPreamble.statements.add(irSourceInformation(scope))
-            }
+
+        if (collectSourceInformation && !isInlineLambda) {
+            sourceInformationPreamble.statements.add(irSourceInformation(scope))
         }
 
         // we start off assuming that we *can* skip execution of the function
@@ -1028,7 +1021,12 @@
         // are using the dispatchReceiverParameter or the extensionReceiverParameter
         val transformed = nonReturningBody.apply {
             transformChildrenVoid()
+        }.let {
+            if (isInlineLambda) {
+                it.asSourceOrEarlyExitGroup(scope)
+            } else it
         }
+
         canSkipExecution = buildPreambleStatementsAndReturnIfSkippingPossible(
             body,
             skipPreamble,
@@ -1058,12 +1056,6 @@
             }
         }
 
-        if (collectSourceInformation && isInlineLambda) {
-            scope.realizeEndCalls {
-                irSourceInformationMarkerEnd(body, scope)
-            }
-        }
-
         if (canSkipExecution) {
             // We CANNOT skip if any of the following conditions are met
             // 1. if any of the stable parameters have *differences* from last execution.
@@ -1290,7 +1282,6 @@
                 returnVar?.let { irReturnVar(declaration.symbol, it) }
             )
         )
-
         scope.metrics.recordFunction(
             composable = true,
             restartable = true,
@@ -2290,7 +2281,7 @@
         }
     }
 
-    fun irTemporary(
+    private fun irTemporary(
         value: IrExpression,
         nameHint: String? = null,
         irType: IrType = value.type,
@@ -2307,7 +2298,9 @@
             name,
             irType,
             isVar
-        )
+        ).also {
+            it.parent = currentFunctionScope.function.parent
+        }
     }
 
     private fun IrBlock.withReplaceableGroupStatements(scope: Scope.BlockScope): IrExpression {
@@ -2404,7 +2397,7 @@
     private fun IrExpression.wrap(
         before: List<IrExpression> = emptyList(),
         after: List<IrExpression> = emptyList()
-    ): IrExpression {
+    ): IrContainerExpression {
         return if (after.isEmpty() || type.isNothing() || type.isUnit()) {
             wrap(startOffset, endOffset, type, before, after)
         } else {
@@ -2425,7 +2418,7 @@
         type: IrType,
         before: List<IrExpression> = emptyList(),
         after: List<IrExpression> = emptyList()
-    ): IrExpression {
+    ): IrContainerExpression {
         return IrBlockImpl(
             startOffset,
             endOffset,
@@ -2462,6 +2455,58 @@
         )
     }
 
+    private fun IrContainerExpression.asSourceOrEarlyExitGroup(
+        scope: Scope.FunctionScope
+    ): IrContainerExpression {
+        if (scope.hasEarlyReturn) {
+            currentFunctionScope.metrics.recordGroup()
+        } else if (!collectSourceInformation) {
+            // If we are not generating source information and the lambda does not contain an
+            // early exit this we don't need a group or source markers.
+            return this
+        }
+        // if the scope has no composable calls, then the only important thing is that a
+        // start/end call gets executed. as a result, we can just put them both at the top of
+        // the group, and we don't have to deal with any of the complicated jump logic that
+        // could be inside of the block
+        val makeStart = {
+            if (scope.hasEarlyReturn) irStartReplaceableGroup(
+                this,
+                scope,
+                startOffset = startOffset,
+                endOffset = endOffset
+            )
+            else irSourceInformationMarkerStart(this, scope)
+        }
+        val makeEnd = {
+            if (scope.hasEarlyReturn) irEndReplaceableGroup(scope = scope)
+            else irSourceInformationMarkerEnd(this, scope)
+        }
+        if (!scope.hasComposableCalls && !scope.hasReturn && !scope.hasJump) {
+            return wrap(
+                before = listOf(makeStart()),
+                after = listOf(makeEnd()),
+            )
+        }
+        scope.realizeGroup(makeEnd)
+        return when {
+            // if the scope ends with a return call, then it will get properly ended if we
+            // just push the end call on the scope because of the way returns get transformed in
+            // this class. As a result, here we can safely just "prepend" the start call
+            endsWithReturnOrJump() -> {
+                wrap(before = listOf(makeStart()))
+            }
+            // otherwise, we want to push an end call for any early returns/jumps, but also add
+            // an end call to the end of the group
+            else -> {
+                wrap(
+                    before = listOf(makeStart()),
+                    after = listOf(makeEnd()),
+                )
+            }
+        }
+    }
+
     private fun mutableStatementContainer() = mutableStatementContainer(context)
 
     private fun encounteredComposableCall(withGroups: Boolean, isCached: Boolean) {
@@ -2574,12 +2619,16 @@
                                 it.markReturn(extraEndLocation)
                             }
                             scope.markReturn(extraEndLocation)
+                            if (scope.isInlinedLambda && scope.inComposableCall) {
+                                scope.hasEarlyReturn = true
+                            }
                         } else {
                             val functionScope = scope
                             val targetScope = currentScope as? Scope.BlockScope ?: functionScope
                             if (functionScope.isInlinedLambda) {
                                 val marker = irGet(functionScope.allocateMarker())
                                 extraEndLocation(irEndToMarker(marker, targetScope))
+                                scope.hasEarlyReturn = true
                             } else {
                                 val marker = functionScope.allocateMarker()
                                 functionScope.markReturn {
@@ -2591,8 +2640,10 @@
                         scope.updateIntrinsiceRememberSafety(false)
                         break@loop
                     }
-                    if (scope.isInlinedLambda && scope.inComposableCall)
+                    if (scope.isInlinedLambda && scope.inComposableCall) {
                         leavingInlinedLambda = true
+                        scope.hasEarlyReturn = true
+                    }
                 }
                 is Scope.BlockScope -> {
                     blockScopeMarks.add(scope)
@@ -3708,6 +3759,8 @@
 
             val metrics: FunctionMetrics = transformer.metricsFor(function)
 
+            var hasEarlyReturn: Boolean = false
+
             private var lastTemporaryIndex: Int = 0
 
             private fun nextTemporaryIndex(): Int = lastTemporaryIndex++
@@ -4038,13 +4091,12 @@
                 makeEnd: () -> IrExpression
             ) {
                 addProvisionalSourceLocations(scope.sourceLocations)
-                coalescableChilds.add(
-                    CoalescableGroupInfo(
-                        scope,
-                        realizeGroup,
-                        makeEnd
-                    )
+                val groupInfo = CoalescableGroupInfo(
+                    scope,
+                    realizeGroup,
+                    makeEnd
                 )
+                coalescableChilds.add(groupInfo)
             }
 
             open fun calculateHasSourceInformation(sourceInformationEnabled: Boolean): Boolean =
@@ -4442,6 +4494,7 @@
                     isConst = false,
                     isLateinit = false
                 ).apply {
+                    parent = currentFunctionScope.function.parent
                     initializer = irGet(param)
                 }
             }
diff --git a/compose/foundation/foundation/api/current.txt b/compose/foundation/foundation/api/current.txt
index 66ef5ba..166ecd1 100644
--- a/compose/foundation/foundation/api/current.txt
+++ b/compose/foundation/foundation/api/current.txt
@@ -111,6 +111,30 @@
     method @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.ui.Modifier onFocusedBoundsChanged(androidx.compose.ui.Modifier, kotlin.jvm.functions.Function1<? super androidx.compose.ui.layout.LayoutCoordinates,kotlin.Unit> onPositioned);
   }
 
+  public final class GraphicsSurfaceKt {
+    method @androidx.compose.runtime.Composable public static void EmbeddedGraphicsSurface(optional androidx.compose.ui.Modifier modifier, optional boolean isOpaque, optional long surfaceSize, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.GraphicsSurfaceScope,kotlin.Unit> onInit);
+    method @androidx.compose.runtime.Composable public static void GraphicsSurface(optional androidx.compose.ui.Modifier modifier, optional boolean isOpaque, optional int zOrder, optional long surfaceSize, optional boolean isSecure, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.GraphicsSurfaceScope,kotlin.Unit> onInit);
+  }
+
+  public interface GraphicsSurfaceScope {
+    method public void onSurface(kotlin.jvm.functions.Function5<? super androidx.compose.foundation.SurfaceCoroutineScope,? super android.view.Surface,? super java.lang.Integer,? super java.lang.Integer,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> onSurface);
+  }
+
+  @kotlin.jvm.JvmInline public final value class GraphicsSurfaceZOrder {
+    method public int getZOrder();
+    property public final int zOrder;
+    field public static final androidx.compose.foundation.GraphicsSurfaceZOrder.Companion Companion;
+  }
+
+  public static final class GraphicsSurfaceZOrder.Companion {
+    method public int getBehind();
+    method public int getMediaOverlay();
+    method public int getOnTop();
+    property public final int Behind;
+    property public final int MediaOverlay;
+    property public final int OnTop;
+  }
+
   public final class HoverableKt {
     method public static androidx.compose.ui.Modifier hoverable(androidx.compose.ui.Modifier, androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional boolean enabled);
   }
@@ -246,6 +270,14 @@
     property public final androidx.compose.runtime.saveable.Saver<androidx.compose.foundation.ScrollState,?> Saver;
   }
 
+  public interface SurfaceCoroutineScope extends androidx.compose.foundation.SurfaceScope kotlinx.coroutines.CoroutineScope {
+  }
+
+  public interface SurfaceScope {
+    method public void onChanged(android.view.Surface, kotlin.jvm.functions.Function3<? super android.view.Surface,? super java.lang.Integer,? super java.lang.Integer,kotlin.Unit> onChanged);
+    method public void onDestroyed(android.view.Surface, kotlin.jvm.functions.Function1<? super android.view.Surface,kotlin.Unit> onDestroyed);
+  }
+
   public final class SystemGestureExclusionKt {
     method public static androidx.compose.ui.Modifier systemGestureExclusion(androidx.compose.ui.Modifier);
     method public static androidx.compose.ui.Modifier systemGestureExclusion(androidx.compose.ui.Modifier, kotlin.jvm.functions.Function1<? super androidx.compose.ui.layout.LayoutCoordinates,androidx.compose.ui.geometry.Rect> exclusion);
diff --git a/compose/foundation/foundation/api/restricted_current.txt b/compose/foundation/foundation/api/restricted_current.txt
index 3118943..5c2e81b 100644
--- a/compose/foundation/foundation/api/restricted_current.txt
+++ b/compose/foundation/foundation/api/restricted_current.txt
@@ -111,6 +111,30 @@
     method @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.ui.Modifier onFocusedBoundsChanged(androidx.compose.ui.Modifier, kotlin.jvm.functions.Function1<? super androidx.compose.ui.layout.LayoutCoordinates,kotlin.Unit> onPositioned);
   }
 
+  public final class GraphicsSurfaceKt {
+    method @androidx.compose.runtime.Composable public static void EmbeddedGraphicsSurface(optional androidx.compose.ui.Modifier modifier, optional boolean isOpaque, optional long surfaceSize, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.GraphicsSurfaceScope,kotlin.Unit> onInit);
+    method @androidx.compose.runtime.Composable public static void GraphicsSurface(optional androidx.compose.ui.Modifier modifier, optional boolean isOpaque, optional int zOrder, optional long surfaceSize, optional boolean isSecure, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.GraphicsSurfaceScope,kotlin.Unit> onInit);
+  }
+
+  public interface GraphicsSurfaceScope {
+    method public void onSurface(kotlin.jvm.functions.Function5<? super androidx.compose.foundation.SurfaceCoroutineScope,? super android.view.Surface,? super java.lang.Integer,? super java.lang.Integer,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> onSurface);
+  }
+
+  @kotlin.jvm.JvmInline public final value class GraphicsSurfaceZOrder {
+    method public int getZOrder();
+    property public final int zOrder;
+    field public static final androidx.compose.foundation.GraphicsSurfaceZOrder.Companion Companion;
+  }
+
+  public static final class GraphicsSurfaceZOrder.Companion {
+    method public int getBehind();
+    method public int getMediaOverlay();
+    method public int getOnTop();
+    property public final int Behind;
+    property public final int MediaOverlay;
+    property public final int OnTop;
+  }
+
   public final class HoverableKt {
     method public static androidx.compose.ui.Modifier hoverable(androidx.compose.ui.Modifier, androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional boolean enabled);
   }
@@ -248,6 +272,14 @@
     property public final androidx.compose.runtime.saveable.Saver<androidx.compose.foundation.ScrollState,?> Saver;
   }
 
+  public interface SurfaceCoroutineScope extends androidx.compose.foundation.SurfaceScope kotlinx.coroutines.CoroutineScope {
+  }
+
+  public interface SurfaceScope {
+    method public void onChanged(android.view.Surface, kotlin.jvm.functions.Function3<? super android.view.Surface,? super java.lang.Integer,? super java.lang.Integer,kotlin.Unit> onChanged);
+    method public void onDestroyed(android.view.Surface, kotlin.jvm.functions.Function1<? super android.view.Surface,kotlin.Unit> onDestroyed);
+  }
+
   public final class SystemGestureExclusionKt {
     method public static androidx.compose.ui.Modifier systemGestureExclusion(androidx.compose.ui.Modifier);
     method public static androidx.compose.ui.Modifier systemGestureExclusion(androidx.compose.ui.Modifier, kotlin.jvm.functions.Function1<? super androidx.compose.ui.layout.LayoutCoordinates,androidx.compose.ui.geometry.Rect> exclusion);
diff --git a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/FoundationDemos.kt b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/FoundationDemos.kt
index b50584f..4a07721 100644
--- a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/FoundationDemos.kt
+++ b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/FoundationDemos.kt
@@ -66,6 +66,7 @@
         ComposableDemo("Vertical scroll") { VerticalScrollExample() },
         ComposableDemo("Controlled Scrollable Row") { ControlledScrollableRowSample() },
         ComposableDemo("Draw Modifiers") { DrawModifiersDemo() },
+        ComposableDemo("Graphics Surfaces") { GraphicsSurfaceDemo() },
         DemoCategory("Lazy lists", LazyListDemos),
         DemoCategory("Snapping", SnappingDemos),
         DemoCategory("Pagers", PagerDemos),
diff --git a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/GraphicsSurfaceDemo.kt b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/GraphicsSurfaceDemo.kt
new file mode 100644
index 0000000..4cc8c77
--- /dev/null
+++ b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/GraphicsSurfaceDemo.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.foundation.demos
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.samples.EmbeddedGraphicsSurfaceColors
+import androidx.compose.foundation.samples.GraphicsSurfaceColors
+import androidx.compose.foundation.verticalScroll
+import androidx.compose.material.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+
+@Composable
+fun GraphicsSurfaceDemo() {
+    Column(Modifier.verticalScroll(rememberScrollState())) {
+        Text("GraphicsSurface:")
+        GraphicsSurfaceColors()
+        Spacer(Modifier.height(50.dp))
+        Text("EmbeddedGraphicsSurface:")
+        EmbeddedGraphicsSurfaceColors()
+    }
+}
diff --git a/compose/foundation/foundation/samples/src/main/java/androidx/compose/foundation/samples/GraphicsSurfaceSamples.kt b/compose/foundation/foundation/samples/src/main/java/androidx/compose/foundation/samples/GraphicsSurfaceSamples.kt
new file mode 100644
index 0000000..dc63c5f
--- /dev/null
+++ b/compose/foundation/foundation/samples/src/main/java/androidx/compose/foundation/samples/GraphicsSurfaceSamples.kt
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2023 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.samples
+
+import android.graphics.Rect
+import androidx.annotation.Sampled
+import androidx.compose.foundation.EmbeddedGraphicsSurface
+import androidx.compose.foundation.GraphicsSurface
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.withFrameNanos
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.lerp
+import androidx.compose.ui.graphics.toArgb
+import androidx.compose.ui.unit.dp
+import kotlin.math.sin
+
+@Sampled
+@Composable
+fun GraphicsSurfaceColors() {
+    GraphicsSurface(
+        modifier = Modifier.fillMaxWidth().height(400.dp)
+    ) {
+        // Resources can be initialized/cached here
+
+        // A surface is available, we can start rendering
+        onSurface { surface, width, height ->
+            var w = width
+            var h = height
+
+            // Initial draw to avoid a black frame
+            surface.lockCanvas(Rect(0, 0, w, h)).apply {
+                drawColor(Color.Blue.toArgb())
+                surface.unlockCanvasAndPost(this)
+            }
+
+            // React to surface dimension changes
+            surface.onChanged { newWidth, newHeight ->
+                w = newWidth
+                h = newHeight
+            }
+
+            // Cleanup if needed
+            surface.onDestroyed {
+            }
+
+            // Render loop, automatically cancelled by GraphicsSurface
+            // on surface destruction
+            while (true) {
+                withFrameNanos { time ->
+                    surface.lockCanvas(Rect(0, 0, w, h)).apply {
+                        val timeMs = time / 1_000_000L
+                        val t = 0.5f + 0.5f * sin(timeMs / 1_000.0f)
+                        drawColor(lerp(Color.Blue, Color.Green, t).toArgb())
+                        surface.unlockCanvasAndPost(this)
+                    }
+                }
+            }
+        }
+    }
+}
+
+@Sampled
+@Composable
+fun EmbeddedGraphicsSurfaceColors() {
+    EmbeddedGraphicsSurface(
+        modifier = Modifier.fillMaxWidth().height(400.dp)
+    ) {
+        // Resources can be initialized/cached here
+
+        // A surface is available, we can start rendering
+        onSurface { surface, width, height ->
+            var w = width
+            var h = height
+
+            // Initial draw to avoid a black frame
+            surface.lockCanvas(Rect(0, 0, w, h)).apply {
+                drawColor(Color.Yellow.toArgb())
+                surface.unlockCanvasAndPost(this)
+            }
+
+            // React to surface dimension changes
+            surface.onChanged { newWidth, newHeight ->
+                w = newWidth
+                h = newHeight
+            }
+
+            // Cleanup if needed
+            surface.onDestroyed {
+            }
+
+            // Render loop, automatically cancelled by EmbeddedGraphicsSurface
+            // on surface destruction
+            while (true) {
+                withFrameNanos { time ->
+                    surface.lockCanvas(Rect(0, 0, w, h)).apply {
+                        val timeMs = time / 1_000_000L
+                        val t = 0.5f + 0.5f * sin(timeMs / 1_000.0f)
+                        drawColor(lerp(Color.Yellow, Color.Red, t).toArgb())
+                        surface.unlockCanvasAndPost(this)
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/EmbeddedGraphicsSurfaceTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/EmbeddedGraphicsSurfaceTest.kt
new file mode 100644
index 0000000..6a10cd1
--- /dev/null
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/EmbeddedGraphicsSurfaceTest.kt
@@ -0,0 +1,306 @@
+/*
+ * 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
+
+import android.graphics.PorterDuff
+import android.os.Build
+import android.view.Surface
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.size
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import androidx.compose.testutils.assertPixels
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.toArgb
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.test.assertHeightIsEqualTo
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.assertWidthIsEqualTo
+import androidx.compose.ui.test.captureToImage
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.onRoot
+import androidx.compose.ui.unit.dp
+import androidx.core.graphics.ColorUtils
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
+import androidx.test.filters.SdkSuppress
+import kotlin.math.roundToInt
+import kotlin.test.assertEquals
+import kotlin.test.assertNotEquals
+import kotlin.test.assertNotNull
+import kotlin.test.assertNull
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@LargeTest
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+@RunWith(AndroidJUnit4::class)
+class EmbeddedGraphicsSurfaceTest {
+    @get:Rule
+    val rule = createComposeRule()
+
+    val size = 48.dp
+
+    @Test
+    fun testOnSurface() {
+        var surfaceRef: Surface? = null
+        var surfaceWidth = 0
+        var surfaceHeight = 0
+        var expectedSize = 0
+
+        rule.setContent {
+            expectedSize = with(LocalDensity.current) {
+                size.toPx().roundToInt()
+            }
+
+            EmbeddedGraphicsSurface(modifier = Modifier.size(size)) {
+                onSurface { surface, width, height ->
+                    surfaceRef = surface
+                    surfaceWidth = width
+                    surfaceHeight = height
+                }
+            }
+        }
+
+        rule.onRoot()
+            .assertWidthIsEqualTo(size)
+            .assertHeightIsEqualTo(size)
+            .assertIsDisplayed()
+
+        rule.runOnIdle {
+            assertNotNull(surfaceRef)
+            assertEquals(expectedSize, surfaceWidth)
+            assertEquals(expectedSize, surfaceHeight)
+        }
+    }
+
+    @Test
+    fun testOnSurfaceChanged() {
+        var surfaceWidth = 0
+        var surfaceHeight = 0
+        var expectedSize = 0
+
+        var desiredSize by mutableStateOf(size)
+
+        rule.setContent {
+            expectedSize = with(LocalDensity.current) {
+                desiredSize.toPx().roundToInt()
+            }
+
+            EmbeddedGraphicsSurface(modifier = Modifier.size(desiredSize)) {
+                onSurface { surface, initWidth, initHeight ->
+                    surfaceWidth = initWidth
+                    surfaceHeight = initHeight
+
+                    surface.onChanged { newWidth, newHeight ->
+                        surfaceWidth = newWidth
+                        surfaceHeight = newHeight
+                    }
+                }
+            }
+        }
+
+        rule.onRoot()
+            .assertWidthIsEqualTo(desiredSize)
+            .assertHeightIsEqualTo(desiredSize)
+
+        rule.runOnIdle {
+            assertEquals(expectedSize, surfaceWidth)
+            assertEquals(expectedSize, surfaceHeight)
+        }
+
+        desiredSize = size * 2
+        val prevSurfaceWidth = surfaceWidth
+        val prevSurfaceHeight = surfaceHeight
+
+        rule.onRoot()
+            .assertWidthIsEqualTo(desiredSize)
+            .assertHeightIsEqualTo(desiredSize)
+
+        rule.runOnIdle {
+            assertNotEquals(prevSurfaceWidth, surfaceWidth)
+            assertNotEquals(prevSurfaceHeight, surfaceHeight)
+            assertEquals(expectedSize, surfaceWidth)
+            assertEquals(expectedSize, surfaceHeight)
+        }
+    }
+
+    @Test
+    fun testOnSurfaceDestroyed() {
+        var surfaceRef: Surface? = null
+        var visible by mutableStateOf(true)
+
+        rule.setContent {
+            if (visible) {
+                EmbeddedGraphicsSurface(modifier = Modifier.size(size)) {
+                    onSurface { surface, _, _ ->
+                        surfaceRef = surface
+
+                        surface.onDestroyed {
+                            surfaceRef = null
+                        }
+                    }
+                }
+            }
+        }
+
+        rule.runOnIdle {
+            assertNotNull(surfaceRef)
+        }
+
+        visible = false
+
+        rule.runOnIdle {
+            assertNull(surfaceRef)
+        }
+    }
+
+    @Test
+    fun testOnSurfaceRecreated() {
+        var surfaceCreatedCount = 0
+        var surfaceDestroyedCount = 0
+        var visible by mutableStateOf(true)
+
+        // NOTE: TextureView only destroys the surface when TextureView is detached from
+        // the window, and only creates when it gets attached to the window
+        rule.setContent {
+            if (visible) {
+                EmbeddedGraphicsSurface(modifier = Modifier.size(size)) {
+                    onSurface { surface, _, _ ->
+                        surfaceCreatedCount++
+                        surface.onDestroyed {
+                            surfaceDestroyedCount++
+                        }
+                    }
+                }
+            }
+        }
+
+        rule.runOnIdle {
+            assertEquals(1, surfaceCreatedCount)
+            assertEquals(0, surfaceDestroyedCount)
+            visible = false
+        }
+
+        rule.runOnIdle {
+            assertEquals(1, surfaceCreatedCount)
+            assertEquals(1, surfaceDestroyedCount)
+            visible = true
+        }
+
+        rule.runOnIdle {
+            assertEquals(2, surfaceCreatedCount)
+            assertEquals(1, surfaceDestroyedCount)
+        }
+    }
+
+    @Test
+    fun testRender() {
+        var surfaceRef: Surface? = null
+        var expectedSize = 0
+
+        rule.setContent {
+            expectedSize = with(LocalDensity.current) {
+                size.toPx().roundToInt()
+            }
+            EmbeddedGraphicsSurface(modifier = Modifier.size(size)) {
+                onSurface { surface, _, _ ->
+                    surfaceRef = surface
+                    surface.lockHardwareCanvas().apply {
+                        drawColor(Color.Blue.toArgb())
+                        surface.unlockCanvasAndPost(this)
+                    }
+                }
+            }
+        }
+
+        rule.runOnIdle {
+            assertNotNull(surfaceRef)
+        }
+
+        surfaceRef!!
+            .captureToImage(expectedSize, expectedSize)
+            .assertPixels { Color.Blue }
+    }
+
+    @Test
+    fun testNotOpaque() {
+        val translucentRed = Color(1.0f, 0.0f, 0.0f, 0.5f).toArgb()
+
+        rule.setContent {
+            Box(modifier = Modifier.size(size)) {
+                Canvas(modifier = Modifier.size(size)) {
+                    drawRect(Color.White)
+                }
+                EmbeddedGraphicsSurface(
+                    modifier = Modifier
+                        .size(size)
+                        .testTag("EmbeddedGraphicSurface"),
+                    isOpaque = false
+                ) {
+                    onSurface { surface, _, _ ->
+                        surface.lockHardwareCanvas().apply {
+                            drawColor(0x00000000, PorterDuff.Mode.CLEAR)
+                            drawColor(translucentRed)
+                            surface.unlockCanvasAndPost(this)
+                        }
+                    }
+                }
+            }
+        }
+
+        val expectedColor = Color(ColorUtils.compositeColors(translucentRed, Color.White.toArgb()))
+
+        rule
+            .onNodeWithTag("EmbeddedGraphicSurface")
+            .captureToImage()
+            .assertPixels { expectedColor }
+    }
+
+    @Test
+    fun testOpaque() {
+        rule.setContent {
+            Box(modifier = Modifier.size(size)) {
+                Canvas(modifier = Modifier.size(size)) {
+                    drawRect(Color.Green)
+                }
+                EmbeddedGraphicsSurface(
+                    modifier = Modifier
+                        .size(size)
+                        .testTag("EmbeddedGraphicSurface")
+                ) {
+                    onSurface { surface, _, _ ->
+                        surface.lockHardwareCanvas().apply {
+                            drawColor(Color.Red.toArgb())
+                            surface.unlockCanvasAndPost(this)
+                        }
+                    }
+                }
+            }
+        }
+
+        rule
+            .onNodeWithTag("EmbeddedGraphicSurface")
+            .captureToImage()
+            .assertPixels { Color.Red }
+    }
+}
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/GraphicsSurfaceTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/GraphicsSurfaceTest.kt
new file mode 100644
index 0000000..a850dd8
--- /dev/null
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/GraphicsSurfaceTest.kt
@@ -0,0 +1,554 @@
+/*
+ * 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
+
+import android.graphics.Bitmap
+import android.graphics.PorterDuff
+import android.graphics.Rect
+import android.os.Build
+import android.os.Handler
+import android.os.Looper
+import android.view.PixelCopy
+import android.view.Surface
+import android.view.View
+import androidx.annotation.RequiresApi
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.size
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import androidx.compose.runtime.withFrameNanos
+import androidx.compose.testutils.assertPixels
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.ImageBitmap
+import androidx.compose.ui.graphics.asImageBitmap
+import androidx.compose.ui.graphics.toArgb
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.platform.LocalView
+import androidx.compose.ui.platform.ViewRootForTest
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.test.SemanticsNodeInteraction
+import androidx.compose.ui.test.assertHeightIsEqualTo
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.assertWidthIsEqualTo
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.onRoot
+import androidx.compose.ui.unit.dp
+import androidx.core.graphics.ColorUtils
+import androidx.core.graphics.createBitmap
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
+import androidx.test.filters.SdkSuppress
+import androidx.test.platform.app.InstrumentationRegistry
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.TimeUnit
+import kotlin.math.roundToInt
+import kotlin.test.assertEquals
+import kotlin.test.assertNotEquals
+import kotlin.test.assertNotNull
+import kotlin.test.assertNull
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@LargeTest
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+@RunWith(AndroidJUnit4::class)
+class GraphicsSurfaceTest {
+    @get:Rule
+    val rule = createComposeRule()
+
+    val size = 48.dp
+
+    @Test
+    fun testOnSurface() {
+        var surfaceRef: Surface? = null
+        var surfaceWidth = 0
+        var surfaceHeight = 0
+        var expectedSize = 0
+
+        rule.setContent {
+            expectedSize = with(LocalDensity.current) {
+                size.toPx().roundToInt()
+            }
+
+            GraphicsSurface(modifier = Modifier.size(size)) {
+                onSurface { surface, width, height ->
+                    surfaceRef = surface
+                    surfaceWidth = width
+                    surfaceHeight = height
+                }
+            }
+        }
+
+        rule.onRoot()
+            .assertWidthIsEqualTo(size)
+            .assertHeightIsEqualTo(size)
+            .assertIsDisplayed()
+
+        rule.runOnIdle {
+            assertNotNull(surfaceRef)
+            assertEquals(expectedSize, surfaceWidth)
+            assertEquals(expectedSize, surfaceHeight)
+        }
+    }
+
+    @Test
+    fun testOnSurfaceChanged() {
+        var surfaceWidth = 0
+        var surfaceHeight = 0
+        var expectedSize = 0
+
+        var desiredSize by mutableStateOf(size)
+
+        rule.setContent {
+            expectedSize = with(LocalDensity.current) {
+                desiredSize.toPx().roundToInt()
+            }
+
+            GraphicsSurface(modifier = Modifier.size(desiredSize)) {
+                onSurface { surface, _, _ ->
+                    surface.onChanged { newWidth, newHeight ->
+                        surfaceWidth = newWidth
+                        surfaceHeight = newHeight
+                    }
+                }
+            }
+        }
+
+        rule.onRoot()
+            .assertWidthIsEqualTo(desiredSize)
+            .assertHeightIsEqualTo(desiredSize)
+
+        // onChanged() hasn't been called yet
+        rule.runOnIdle {
+            assertEquals(0, surfaceWidth)
+            assertEquals(0, surfaceHeight)
+        }
+
+        desiredSize = size * 2
+        val prevSurfaceWidth = surfaceWidth
+        val prevSurfaceHeight = surfaceHeight
+
+        rule.onRoot()
+            .assertWidthIsEqualTo(desiredSize)
+            .assertHeightIsEqualTo(desiredSize)
+
+        rule.runOnIdle {
+            assertNotEquals(prevSurfaceWidth, surfaceWidth)
+            assertNotEquals(prevSurfaceHeight, surfaceHeight)
+            assertEquals(expectedSize, surfaceWidth)
+            assertEquals(expectedSize, surfaceHeight)
+        }
+    }
+
+    @Test
+    fun testOnSurfaceDestroyed() {
+        var surfaceRef: Surface? = null
+        var visible by mutableStateOf(true)
+
+        rule.setContent {
+            if (visible) {
+                GraphicsSurface(modifier = Modifier.size(size)) {
+                    onSurface { surface, _, _ ->
+                        surfaceRef = surface
+
+                        surface.onDestroyed {
+                            surfaceRef = null
+                        }
+                    }
+                }
+            }
+        }
+
+        rule.runOnIdle {
+            assertNotNull(surfaceRef)
+        }
+
+        visible = false
+
+        rule.runOnIdle {
+            assertNull(surfaceRef)
+        }
+    }
+
+    @Test
+    fun testOnSurfaceRecreated() {
+        var surfaceCreatedCount = 0
+        var surfaceDestroyedCount = 0
+
+        var view: View? = null
+
+        rule.setContent {
+            view = LocalView.current
+            GraphicsSurface(modifier = Modifier.size(size)) {
+                onSurface { surface, _, _ ->
+                    surfaceCreatedCount++
+                    surface.onDestroyed {
+                        surfaceDestroyedCount++
+                    }
+                }
+            }
+        }
+
+        // NOTE: SurfaceView only triggers a Surface destroy/create cycle on visibility
+        // change if its *own* visibility or the visibility of the window changes. Here
+        // we change the visibility of the window by setting the visibility of the root
+        // view (the host view in ViewRootImpl).
+        rule.runOnIdle {
+            assertEquals(1, surfaceCreatedCount)
+            assertEquals(0, surfaceDestroyedCount)
+            view?.rootView?.visibility = View.INVISIBLE
+        }
+
+        rule.runOnIdle {
+            assertEquals(1, surfaceCreatedCount)
+            assertEquals(1, surfaceDestroyedCount)
+            view?.rootView?.visibility = View.VISIBLE
+        }
+
+        rule.runOnIdle {
+            assertEquals(2, surfaceCreatedCount)
+            assertEquals(1, surfaceDestroyedCount)
+        }
+    }
+
+    @Test
+    fun testRender() {
+        var surfaceRef: Surface? = null
+        var expectedSize = 0
+
+        rule.setContent {
+            expectedSize = with(LocalDensity.current) {
+                size.toPx().roundToInt()
+            }
+            GraphicsSurface(modifier = Modifier.size(size)) {
+                onSurface { surface, _, _ ->
+                    surfaceRef = surface
+                    surface.lockHardwareCanvas().apply {
+                        drawColor(Color.Blue.toArgb())
+                        surface.unlockCanvasAndPost(this)
+                    }
+                }
+            }
+        }
+
+        rule.runOnIdle {
+            assertNotNull(surfaceRef)
+        }
+
+        surfaceRef!!
+            .captureToImage(expectedSize, expectedSize)
+            .assertPixels { Color.Blue }
+    }
+
+    @Test
+    fun testZOrderDefault() {
+        val frameCount = 4
+        val latch = CountDownLatch(frameCount)
+
+        rule.setContent {
+            Box(modifier = Modifier.size(size)) {
+                GraphicsSurface(
+                    modifier = Modifier
+                        .size(size)
+                        .testTag("GraphicSurface")
+                ) {
+                    onSurface { surface, _, _ ->
+                        // Draw > 3 frames to make sure the screenshot copy will pick up
+                        // a SurfaceFlinger composition that includes our Surface
+                        repeat(frameCount) {
+                            withFrameNanos {
+                                surface.lockHardwareCanvas().apply {
+                                    drawColor(Color.Blue.toArgb())
+                                    surface.unlockCanvasAndPost(this)
+                                }
+                                latch.countDown()
+                            }
+                        }
+                    }
+                }
+                Canvas(modifier = Modifier.size(size)) {
+                    drawRect(Color.Green)
+                }
+            }
+        }
+
+        if (!latch.await(5, TimeUnit.SECONDS)) {
+            throw AssertionError("Failed waiting for render")
+        }
+
+        rule
+            .onNodeWithTag("GraphicSurface")
+            .screenshotToImage()!!
+            .assertPixels { Color.Green }
+    }
+
+    @Test
+    fun testZOrderMediaOverlay() {
+        val frameCount = 6
+        val latch = CountDownLatch(frameCount)
+
+        rule.setContent {
+            Box(modifier = Modifier.size(size)) {
+                GraphicsSurface(
+                    modifier = Modifier.size(size),
+                    zOrder = GraphicsSurfaceZOrder.Behind
+                ) {
+                    onSurface { surface, _, _ ->
+                        // Draw > 3 frames to make sure the screenshot copy will pick up
+                        // a SurfaceFlinger composition that includes our Surface
+                        repeat(frameCount) {
+                            withFrameNanos {
+                                surface.lockHardwareCanvas().apply {
+                                    drawColor(Color.Blue.toArgb())
+                                    surface.unlockCanvasAndPost(this)
+                                }
+                                latch.countDown()
+                            }
+                        }
+                    }
+                }
+                GraphicsSurface(
+                    modifier = Modifier
+                        .size(size)
+                        .testTag("GraphicSurface"),
+                    zOrder = GraphicsSurfaceZOrder.MediaOverlay
+                ) {
+                    onSurface { surface, _, _ ->
+                        surface.lockHardwareCanvas().apply {
+                            drawColor(Color.Red.toArgb())
+                            surface.unlockCanvasAndPost(this)
+                        }
+                        latch.countDown()
+                    }
+                }
+            }
+        }
+
+        if (!latch.await(5, TimeUnit.SECONDS)) {
+            throw AssertionError("Failed waiting for render")
+        }
+
+        rule
+            .onNodeWithTag("GraphicSurface")
+            .screenshotToImage()!!
+            .assertPixels { Color.Red }
+    }
+
+    @Test
+    fun testZOrderOnTop() {
+        val frameCount = 4
+        val latch = CountDownLatch(frameCount)
+
+        rule.setContent {
+            Box(modifier = Modifier.size(size)) {
+                GraphicsSurface(
+                    modifier = Modifier
+                        .size(size)
+                        .testTag("GraphicSurface"),
+                    zOrder = GraphicsSurfaceZOrder.OnTop
+                ) {
+                    onSurface { surface, _, _ ->
+                        // Draw > 3 frames to make sure the screenshot copy will pick up
+                        // a SurfaceFlinger composition that includes our Surface
+                        repeat(frameCount) {
+                            withFrameNanos {
+                                surface.lockHardwareCanvas().apply {
+                                    drawColor(Color.Blue.toArgb())
+                                    surface.unlockCanvasAndPost(this)
+                                }
+                                latch.countDown()
+                            }
+                        }
+                    }
+                }
+                Canvas(modifier = Modifier.size(size)) {
+                    drawRect(Color.Green)
+                }
+            }
+        }
+
+        if (!latch.await(5, TimeUnit.SECONDS)) {
+            throw AssertionError("Failed waiting for render")
+        }
+
+        rule
+            .onNodeWithTag("GraphicSurface")
+            .screenshotToImage()!!
+            .assertPixels { Color.Blue }
+    }
+
+    @Test
+    fun testNotOpaque() {
+        val frameCount = 4
+        val latch = CountDownLatch(frameCount)
+        val translucentRed = Color(1.0f, 0.0f, 0.0f, 0.5f).toArgb()
+
+        rule.setContent {
+            Box(modifier = Modifier.size(size)) {
+                GraphicsSurface(
+                    modifier = Modifier
+                        .size(size)
+                        .testTag("GraphicSurface"),
+                    isOpaque = false,
+                    zOrder = GraphicsSurfaceZOrder.OnTop
+                ) {
+                    onSurface { surface, _, _ ->
+                        // Draw > 3 frames to make sure the screenshot copy will pick up
+                        // a SurfaceFlinger composition that includes our Surface
+                        repeat(frameCount) {
+                            withFrameNanos {
+                                surface.lockHardwareCanvas().apply {
+                                    // Since we are drawing a translucent color we need to
+                                    // clear first
+                                    drawColor(0x00000000, PorterDuff.Mode.CLEAR)
+                                    drawColor(translucentRed)
+                                    surface.unlockCanvasAndPost(this)
+                                }
+                                latch.countDown()
+                            }
+                        }
+                    }
+                }
+                Canvas(modifier = Modifier.size(size)) {
+                    drawRect(Color.White)
+                }
+            }
+        }
+
+        if (!latch.await(5, TimeUnit.SECONDS)) {
+            throw AssertionError("Failed waiting for render")
+        }
+
+        val expectedColor = Color(ColorUtils.compositeColors(translucentRed, Color.White.toArgb()))
+
+        rule
+            .onNodeWithTag("GraphicSurface")
+            .screenshotToImage()!!
+            .assertPixels { expectedColor }
+    }
+
+    @Test
+    fun testSecure() {
+        val frameCount = 4
+        val latch = CountDownLatch(frameCount)
+
+        rule.setContent {
+            GraphicsSurface(
+                modifier = Modifier
+                    .size(size)
+                    .testTag("GraphicSurface"),
+                isSecure = true
+            ) {
+                onSurface { surface, _, _ ->
+                    // Draw > 3 frames to make sure the screenshot copy will pick up
+                    // a SurfaceFlinger composition that includes our Surface
+                    repeat(frameCount) {
+                        withFrameNanos {
+                            surface.lockHardwareCanvas().apply {
+                                drawColor(Color.Blue.toArgb())
+                                surface.unlockCanvasAndPost(this)
+                            }
+                            latch.countDown()
+                        }
+                    }
+                }
+            }
+        }
+
+        if (!latch.await(5, TimeUnit.SECONDS)) {
+            throw AssertionError("Failed waiting for render")
+        }
+
+        val screen = rule
+            .onNodeWithTag("GraphicSurface")
+            .screenshotToImage()
+
+        // Before API 33 taking a screenshot with a secure surface returns null
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
+            assertNull(screen)
+        } else {
+            screen?.assertPixels { Color.Black }
+        }
+    }
+}
+
+/**
+ * Returns an ImageBitmap containing a screenshot of the device. On API < 33,
+ * a secure surface present on screen can cause this function to return null.
+ */
+private fun SemanticsNodeInteraction.screenshotToImage(): ImageBitmap? {
+    val node = fetchSemanticsNode()
+    val view = (node.root as ViewRootForTest).view
+
+    val location = IntArray(2)
+    view.getLocationOnScreen(location)
+
+    val bounds = node.boundsInRoot.translate(
+        location[0].toFloat(),
+        location[1].toFloat()
+    )
+
+    // TODO: On API 34+ we should use takeScreenshot(Window) instead
+    //       It would be faster and less flaky than capturing the entire screen
+    val screen = InstrumentationRegistry
+        .getInstrumentation()
+        .uiAutomation
+        .takeScreenshot() ?: return null
+
+    return Bitmap.createBitmap(
+        screen,
+        bounds.left.toInt(),
+        bounds.top.toInt(),
+        bounds.width.roundToInt(),
+        bounds.height.roundToInt()
+    ).asImageBitmap()
+}
+
+@RequiresApi(Build.VERSION_CODES.O)
+internal fun Surface.captureToImage(width: Int, height: Int): ImageBitmap {
+    val bitmap = createBitmap(width, height)
+
+    val latch = CountDownLatch(1)
+    var copyResult = 0
+    val onCopyFinished = PixelCopy.OnPixelCopyFinishedListener { result ->
+        copyResult = result
+        latch.countDown()
+        android.util.Log.d("Test", Thread.currentThread().toString())
+    }
+
+    PixelCopy.request(
+        this,
+        Rect(0, 0, width, height),
+        bitmap,
+        onCopyFinished,
+        Handler(Looper.getMainLooper())
+    )
+
+    if (!latch.await(1, TimeUnit.SECONDS)) {
+        throw AssertionError("Failed waiting for PixelCopy!")
+    }
+
+    if (copyResult != PixelCopy.SUCCESS) {
+        throw AssertionError("PixelCopy failed!")
+    }
+
+    return bitmap.asImageBitmap()
+}
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/GraphicsSurface.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/GraphicsSurface.kt
new file mode 100644
index 0000000..17a6823
--- /dev/null
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/GraphicsSurface.kt
@@ -0,0 +1,438 @@
+/*
+ * Copyright 2023 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
+
+import android.graphics.PixelFormat
+import android.graphics.SurfaceTexture
+import android.view.Surface
+import android.view.SurfaceHolder
+import android.view.SurfaceView
+import android.view.TextureView
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.IntSize
+import androidx.compose.ui.viewinterop.AndroidView
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.CoroutineStart
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.cancelAndJoin
+import kotlinx.coroutines.launch
+
+/**
+ * [SurfaceScope] is a scoped environment provided by [GraphicsSurface] and
+ * [EmbeddedGraphicsSurface] to handle [Surface] lifecycle events.
+ *
+ * @sample androidx.compose.foundation.samples.GraphicsSurfaceColors
+ */
+interface SurfaceScope {
+    /**
+     * Invokes [onChanged] when the surface's geometry (width and height) changes.
+     * Always invoked on the main thread.
+     */
+    @Suppress("PrimitiveInLambda")
+    fun Surface.onChanged(onChanged: Surface.(width: Int, height: Int) -> Unit)
+
+    /**
+     * Invokes [onDestroyed] when the surface is destroyed. All rendering into
+     * the surface should stop immediately after [onDestroyed] is invoked.
+     * Always invoked on the main thread.
+     */
+    fun Surface.onDestroyed(onDestroyed: Surface.() -> Unit)
+}
+
+/**
+ * [SurfaceCoroutineScope] is a scoped environment provided by
+ * [GraphicsSurface] and [EmbeddedGraphicsSurface] when a new [Surface] is
+ * created. This environment is a coroutine scope that also provides access to
+ * a [SurfaceScope] environment which can itself be used to handle other [Surface]
+ * lifecycle events.
+ *
+ * @see SurfaceScope
+ * @see GraphicsSurfaceScope
+ *
+ * @sample androidx.compose.foundation.samples.GraphicsSurfaceColors
+ */
+interface SurfaceCoroutineScope : SurfaceScope, CoroutineScope
+
+/**
+ * [GraphicsSurfaceScope] is a scoped environment provided when a [GraphicsSurface]
+ * or [EmbeddedGraphicsSurface] is first initialized. This environment can be
+ * used to register a lambda to invoke when a new [Surface] associated with the
+ * [GraphicsSurface]/[EmbeddedGraphicsSurface] is created.
+ */
+interface GraphicsSurfaceScope {
+    /**
+     * Invokes [onSurface] when a new [Surface] is created. The [onSurface] lambda
+     * is invoked on the main thread as part of a [SurfaceCoroutineScope] to provide
+     * a coroutine context.
+     *
+     * @param onSurface Callback invoked when a new [Surface] is created. The initial
+     *                  dimensions of the surface are provided.
+     */
+    @Suppress("PrimitiveInLambda")
+    fun onSurface(
+        onSurface: suspend SurfaceCoroutineScope.(surface: Surface, width: Int, height: Int) -> Unit
+    )
+}
+
+/**
+ * Base class for [GraphicsSurface] and [EmbeddedGraphicsSurface] state. This class
+ * provides methods to properly dispatch lifecycle events on [Surface] creation,
+ * change, and destruction. Surface creation is treated as a coroutine launch,
+ * using the specified [scope] as the parent. This scope must be the main thread scope.
+ */
+private abstract class BaseGraphicsSurfaceState(val scope: CoroutineScope) :
+    GraphicsSurfaceScope, SurfaceScope {
+
+    private var onSurface:
+        (suspend SurfaceCoroutineScope.(surface: Surface, width: Int, height: Int) -> Unit)? = null
+    private var onSurfaceChanged: (Surface.(width: Int, height: Int) -> Unit)? = null
+    private var onSurfaceDestroyed: (Surface.() -> Unit)? = null
+
+    private var job: Job? = null
+
+    override fun onSurface(
+        onSurface: suspend SurfaceCoroutineScope.(surface: Surface, width: Int, height: Int) -> Unit
+    ) {
+        this.onSurface = onSurface
+    }
+
+    override fun Surface.onChanged(onChanged: Surface.(width: Int, height: Int) -> Unit) {
+        onSurfaceChanged = onChanged
+    }
+
+    override fun Surface.onDestroyed(onDestroyed: Surface.() -> Unit) {
+        onSurfaceDestroyed = onDestroyed
+    }
+
+    /**
+     * Dispatch a surface creation event by launching a new coroutine in [scope].
+     * Any previous job from a previous surface creation dispatch is cancelled.
+     */
+    fun dispatchSurfaceCreated(surface: Surface, width: Int, height: Int) {
+        if (onSurface != null) {
+            job = scope.launch(start = CoroutineStart.UNDISPATCHED) {
+                job?.cancelAndJoin()
+                val receiver =
+                    object : SurfaceCoroutineScope, SurfaceScope by this@BaseGraphicsSurfaceState,
+                        CoroutineScope by this {}
+                onSurface?.invoke(receiver, surface, width, height)
+            }
+        }
+    }
+
+    /**
+     * Dispatch a surface change event, providing the surface's new width and height.
+     * Must be invoked from the main thread.
+     */
+    fun dispatchSurfaceChanged(surface: Surface, width: Int, height: Int) {
+        onSurfaceChanged?.invoke(surface, width, height)
+    }
+
+    /**
+     * Dispatch a surface destruction event. Any pending job from [dispatchSurfaceCreated]
+     * is cancelled before dispatching the event. Must be invoked from the main thread.
+     */
+    fun dispatchSurfaceDestroyed(surface: Surface) {
+        onSurfaceDestroyed?.invoke(surface)
+        job?.cancel()
+        job = null
+    }
+}
+
+private class GraphicsSurfaceState(scope: CoroutineScope) : BaseGraphicsSurfaceState(scope),
+    SurfaceHolder.Callback {
+
+    var lastWidth = -1
+    var lastHeight = -1
+
+    override fun surfaceCreated(holder: SurfaceHolder) {
+        val frame = holder.surfaceFrame
+        lastWidth = frame.width()
+        lastHeight = frame.height()
+
+        dispatchSurfaceCreated(holder.surface, lastWidth, lastHeight)
+    }
+
+    override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
+        if (lastWidth != width || lastHeight != height) {
+            lastWidth = width
+            lastHeight = height
+
+            dispatchSurfaceChanged(holder.surface, width, height)
+        }
+    }
+
+    override fun surfaceDestroyed(holder: SurfaceHolder) {
+        dispatchSurfaceDestroyed(holder.surface)
+    }
+}
+
+@Composable
+private fun rememberGraphicsSurfaceState(): GraphicsSurfaceState {
+    val scope = rememberCoroutineScope()
+    return remember { GraphicsSurfaceState(scope) }
+}
+
+@JvmInline
+value class GraphicsSurfaceZOrder private constructor(val zOrder: Int) {
+    companion object {
+        val Behind = GraphicsSurfaceZOrder(0)
+        val MediaOverlay = GraphicsSurfaceZOrder(1)
+        val OnTop = GraphicsSurfaceZOrder(2)
+    }
+}
+
+/**
+ * Provides a dedicated drawing [Surface] as a separate layer positioned by default behind
+ * the window holding the [GraphicsSurface] composable. Because [GraphicsSurface] uses
+ * a separate window layer, graphics composition is handled by the system compositor which
+ * can bypass the GPU and provide better performance and power usage characteristics compared
+ * to [EmbeddedGraphicsSurface]. It is therefore recommended to use [GraphicsSurface]
+ * whenever possible.
+ *
+ * The z-ordering of the surface can be controlled using the [zOrder] parameter:
+ *
+ * - [GraphicsSurfaceZOrder.Behind]: positions the surface behind the window
+ * - [GraphicsSurfaceZOrder.MediaOverlay]: positions the surface behind the window but
+ *   above other [GraphicsSurfaceZOrder.Behind] surfaces
+ * - [GraphicsSurfaceZOrder.OnTop]: positions the surface above the window
+ *
+ * The drawing surface is opaque by default, which can be controlled with the [isOpaque]
+ * parameter. When the surface is transparent, you may need to change the z-order to
+ * see something behind the surface.
+ *
+ * To start rendering, the caller must first acquire the [Surface] when it's created.
+ * This is achieved by providing the [onInit] lambda, which allows the caller to
+ * register an appropriate [GraphicsSurfaceScope.onSurface] callback. The [onInit]
+ * lambda can also be used to initialize/cache resources needed once a surface is
+ * available.
+ *
+ * After acquiring a surface, the caller can start rendering into it. Rendering into a
+ * surface can be done from any thread.
+ *
+ * It is recommended to register the [SurfaceScope.onChanged] and [SurfaceScope.onDestroyed]
+ * callbacks to properly handle the lifecycle of the surface and react to dimension
+ * changes. You must ensure that the rendering thread stops interacting with the surface
+ * when the [SurfaceScope.onDestroyed] callback is invoked.
+ *
+ * If a [surfaceSize] is specified (set to non-[IntSize.Zero]), the surface will use
+ * the specified size instead of the layout size of this composable. The surface will
+ * be stretched at render time to fit the layout size. This can be used for instance to
+ * render at a lower resolution for performance reasons.
+ *
+ * @param modifier Modifier to be applied to the [GraphicsSurface]
+ * @param isOpaque Whether the managed surface should be opaque or transparent.
+ * @param zOrder Sets the z-order of the surface relative to its parent window.
+ * @param surfaceSize Sets the surface size independently of the layout size of
+ *                    this [GraphicsSurface]. If set to [IntSize.Zero], the surface
+ *                    size will be equal to the [GraphicsSurface] layout size.
+ * @param isSecure Control whether the surface view's content should be treated as
+ *                 secure, preventing it from appearing in screenshots or from being
+ *                 viewed on non-secure displays.
+ * @param onInit Lambda invoked on first composition. This lambda can be used to
+ *               declare a [GraphicsSurfaceScope.onSurface] callback that will be
+ *               invoked when a surface is available.
+ *
+ * @sample androidx.compose.foundation.samples.GraphicsSurfaceColors
+ */
+@Composable
+fun GraphicsSurface(
+    modifier: Modifier = Modifier,
+    isOpaque: Boolean = true,
+    zOrder: GraphicsSurfaceZOrder = GraphicsSurfaceZOrder.Behind,
+    surfaceSize: IntSize = IntSize.Zero,
+    isSecure: Boolean = false,
+    onInit: GraphicsSurfaceScope.() -> Unit
+) {
+    val state = rememberGraphicsSurfaceState()
+
+    AndroidView(
+        factory = { context ->
+            SurfaceView(context).apply {
+                state.onInit()
+                holder.addCallback(state)
+            }
+        },
+        modifier = modifier,
+        onReset = { },
+        update = { view ->
+            if (surfaceSize != IntSize.Zero) {
+                view.holder.setFixedSize(surfaceSize.width, surfaceSize.height)
+            } else {
+                view.holder.setSizeFromLayout()
+            }
+
+            view.holder.setFormat(
+                if (isOpaque) {
+                    PixelFormat.OPAQUE
+                } else {
+                    PixelFormat.TRANSLUCENT
+                }
+            )
+
+            when (zOrder) {
+                GraphicsSurfaceZOrder.Behind -> view.setZOrderOnTop(false)
+                GraphicsSurfaceZOrder.MediaOverlay -> view.setZOrderMediaOverlay(true)
+                GraphicsSurfaceZOrder.OnTop -> view.setZOrderOnTop(true)
+            }
+
+            view.setSecure(isSecure)
+        }
+    )
+}
+
+private class EmbeddedGraphicsSurfaceState(scope: CoroutineScope) : BaseGraphicsSurfaceState(scope),
+    TextureView.SurfaceTextureListener {
+
+    var surfaceSize = IntSize.Zero
+
+    private var surfaceTextureSurface: Surface? = null
+
+    override fun onSurfaceTextureAvailable(
+        surfaceTexture: SurfaceTexture,
+        width: Int,
+        height: Int
+    ) {
+        var w = width
+        var h = height
+
+        if (surfaceSize != IntSize.Zero) {
+            w = surfaceSize.width
+            h = surfaceSize.height
+            surfaceTexture.setDefaultBufferSize(w, h)
+        }
+
+        val surface = Surface(surfaceTexture)
+        surfaceTextureSurface = surface
+
+        dispatchSurfaceCreated(surface, w, h)
+    }
+
+    override fun onSurfaceTextureSizeChanged(
+        surfaceTexture: SurfaceTexture,
+        width: Int,
+        height: Int
+    ) {
+        var w = width
+        var h = height
+
+        if (surfaceSize != IntSize.Zero) {
+            w = surfaceSize.width
+            h = surfaceSize.height
+            surfaceTexture.setDefaultBufferSize(w, h)
+        }
+
+        dispatchSurfaceChanged(surfaceTextureSurface!!, w, h)
+    }
+
+    override fun onSurfaceTextureDestroyed(surfaceTexture: SurfaceTexture): Boolean {
+        dispatchSurfaceDestroyed(surfaceTextureSurface!!)
+        surfaceTextureSurface = null
+        return true
+    }
+
+    override fun onSurfaceTextureUpdated(surface: SurfaceTexture) {
+        // onSurfaceTextureUpdated is called when the content of the SurfaceTexture
+        // has changed, which is not relevant to us since we are the producer here
+    }
+}
+
+@Composable
+private fun rememberEmbeddedGraphicsSurfaceState(): EmbeddedGraphicsSurfaceState {
+    val scope = rememberCoroutineScope()
+    return remember { EmbeddedGraphicsSurfaceState(scope) }
+}
+
+/**
+ * Provides a dedicated drawing [Surface] embedded directly in the UI hierarchy.
+ * Unlike [GraphicsSurface], [EmbeddedGraphicsSurface] positions its surface as a
+ * regular element inside the composable hierarchy. This means that graphics
+ * composition is handled like any other UI widget, using the GPU. This can lead
+ * to increased power and memory bandwidth usage compared to [GraphicsSurface]. It
+ * is therefore recommended to use [GraphicsSurface] when possible.
+ *
+ * [EmbeddedGraphicsSurface] can however be useful when interactions with other widgets
+ * is necessary, for instance if the surface needs to be "sandwiched" between two
+ * other widgets, or if it must participate in visual effects driven by
+ * a `Modifier.graphicsLayer{}`.
+ *
+ * The drawing surface is opaque by default, which can be controlled with the [isOpaque]
+ * parameter.
+ *
+ * To start rendering, the caller must first acquire the [Surface] when it's created.
+ * This is achieved by providing the [onInit] lambda, which allows the caller to
+ * register an appropriate [GraphicsSurfaceScope.onSurface] callback. The [onInit]
+ * lambda can also be used to initialize/cache resources needed once a surface is
+ * available.
+ *
+ * After acquiring a surface, the caller can start rendering into it. Rendering into a
+ * surface can be done from any thread.
+ *
+ * It is recommended to register the [SurfaceScope.onChanged] and [SurfaceScope.onDestroyed]
+ * callbacks to properly handle the lifecycle of the surface and react to dimension
+ * changes. You must ensure that the rendering thread stops interacting with the surface
+ * when the [SurfaceScope.onDestroyed] callback is invoked.
+ *
+ * If a [surfaceSize] is specified (set to non-[IntSize.Zero]), the surface will use
+ * the specified size instead of the layout size of this composable. The surface will
+ * be stretched at render time to fit the layout size. This can be used for instance to
+ * render at a lower resolution for performance reasons.
+ *
+ * @param modifier Modifier to be applied to the [GraphicsSurface]
+ * @param isOpaque Whether the managed surface should be opaque or transparent. If
+ *                 transparent and [isMediaOverlay] is `false`, the surface will
+ *                 be positioned above the parent window.
+ * @param surfaceSize Sets the surface size independently of the layout size of
+ *                    this [GraphicsSurface]. If set to [IntSize.Zero], the surface
+ *                    size will be equal to the [GraphicsSurface] layout size.
+ * @param onInit Lambda invoked on first composition. This lambda can be used to
+ *               declare a [GraphicsSurfaceScope.onSurface] callback that will be
+ *               invoked when a surface is available.
+ *
+ * @sample androidx.compose.foundation.samples.EmbeddedGraphicsSurfaceColors
+ */
+@Composable
+fun EmbeddedGraphicsSurface(
+    modifier: Modifier = Modifier,
+    isOpaque: Boolean = true,
+    surfaceSize: IntSize = IntSize.Zero,
+    onInit: GraphicsSurfaceScope.() -> Unit
+) {
+    val state = rememberEmbeddedGraphicsSurfaceState()
+
+    AndroidView(
+        factory = { context ->
+            TextureView(context).apply {
+                state.surfaceSize = surfaceSize
+                state.onInit()
+                surfaceTextureListener = state
+            }
+        },
+        modifier = modifier,
+        onReset = { },
+        update = { view ->
+            if (surfaceSize != IntSize.Zero) {
+                view.surfaceTexture?.setDefaultBufferSize(surfaceSize.width, surfaceSize.height)
+            }
+            state.surfaceSize = surfaceSize
+            view.isOpaque = isOpaque
+        }
+    )
+}
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/relocation/BringIntoViewRequester.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/relocation/BringIntoViewRequester.kt
index 8041415..8001053 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/relocation/BringIntoViewRequester.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/relocation/BringIntoViewRequester.kt
@@ -38,6 +38,9 @@
  *
  * Here is a sample where part of a composable is brought into view:
  * @sample androidx.compose.foundation.samples.BringPartOfComposableIntoViewSample
+ *
+ * Note: this API is experimental while we optimise the performance and find the right API shape
+ * for it
  */
 @ExperimentalFoundationApi
 sealed interface BringIntoViewRequester {
@@ -73,6 +76,9 @@
  *
  * Here is a sample where a part of a composable is brought into view:
  * @sample androidx.compose.foundation.samples.BringPartOfComposableIntoViewSample
+ *
+ * Note: this API is experimental while we optimise the performance and find the right API shape
+ * for it
  */
 @ExperimentalFoundationApi
 fun BringIntoViewRequester(): BringIntoViewRequester {
@@ -94,6 +100,9 @@
  *     hoisted object can be used to send
  *     [bringIntoView][BringIntoViewRequester.bringIntoView] requests to parents
  *     of the current composable.
+ *
+ * Note: this API is experimental while we optimise the performance and find the right API shape
+ * for it
  */
 @Suppress("ModifierInspectorInfo")
 @ExperimentalFoundationApi
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/relocation/BringIntoViewResponder.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/relocation/BringIntoViewResponder.kt
index 71820cc..770c8a06 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/relocation/BringIntoViewResponder.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/relocation/BringIntoViewResponder.kt
@@ -48,6 +48,9 @@
  * @sample androidx.compose.foundation.samples.BringPartOfComposableIntoViewSample
  *
  * @see BringIntoViewRequester
+ *
+ * Note: this API is experimental while we optimise the performance and find the right API shape
+ * for it
  */
 @ExperimentalFoundationApi
 interface BringIntoViewResponder {
@@ -94,6 +97,9 @@
  * @sample androidx.compose.foundation.samples.BringIntoViewSample
  *
  * @see BringIntoViewRequester
+ *
+ * Note: this API is experimental while we optimise the performance and find the right API shape
+ * for it
  */
 @Suppress("ModifierInspectorInfo")
 @ExperimentalFoundationApi
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text2/input/TextFieldBuffer.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text2/input/TextFieldBuffer.kt
index 10ac37e..a332068 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text2/input/TextFieldBuffer.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text2/input/TextFieldBuffer.kt
@@ -150,7 +150,7 @@
     ) {
         require(start <= end) { "Expected start=$start <= end=$end" }
         require(textStart <= textEnd) { "Expected textStart=$textStart <= textEnd=$textEnd" }
-        onTextWillChange(TextRange(start, end), textEnd - textStart)
+        onTextWillChange(start, end, textEnd - textStart)
         buffer.replace(start, end, text, textStart, textEnd)
     }
 
@@ -168,7 +168,7 @@
     // This append overload should be first so it ends up being the target of links to this method.
     override fun append(text: CharSequence?): Appendable = apply {
         if (text != null) {
-            onTextWillChange(TextRange(length), text.length)
+            onTextWillChange(length, length, text.length)
             buffer.replace(buffer.length, buffer.length, text)
         }
     }
@@ -176,30 +176,31 @@
     // Doc inherited from Appendable.
     override fun append(text: CharSequence?, start: Int, end: Int): Appendable = apply {
         if (text != null) {
-            onTextWillChange(TextRange(length), end - start)
+            onTextWillChange(length, length, end - start)
             buffer.replace(buffer.length, buffer.length, text.subSequence(start, end))
         }
     }
 
     // Doc inherited from Appendable.
     override fun append(char: Char): Appendable = apply {
-        onTextWillChange(TextRange(length), 1)
+        onTextWillChange(length, length, 1)
         buffer.replace(buffer.length, buffer.length, char.toString())
     }
 
     /**
      * Called just before the text contents are about to change.
      *
-     * @param rangeToBeReplaced The range in the current text that's about to be replaced.
+     * @param replaceStart The first offset to be replaced (inclusive).
+     * @param replaceEnd The last offset to be replaced (exclusive).
      * @param newLength The length of the replacement.
      */
-    private fun onTextWillChange(rangeToBeReplaced: TextRange, newLength: Int) {
+    private fun onTextWillChange(replaceStart: Int, replaceEnd: Int, newLength: Int) {
         (changeTracker ?: ChangeTracker().also { changeTracker = it })
-            .trackChange(rangeToBeReplaced, newLength)
+            .trackChange(replaceStart, replaceEnd, newLength)
 
         // Adjust selection.
-        val start = rangeToBeReplaced.min
-        val end = rangeToBeReplaced.max
+        val start = minOf(replaceStart, replaceEnd)
+        val end = maxOf(replaceStart, replaceEnd)
         var selStart = selectionInChars.min
         var selEnd = selectionInChars.max
 
@@ -448,7 +449,7 @@
     /**
      * The ordered list of non-overlapping and discontinuous changes performed on a
      * [TextFieldBuffer] during the current [edit][TextFieldState.edit] or
-     * [filter][TextEditFilter.filter] operation. Changes are listed in the order they appear in the
+     * [filter][InputTransformation.transformInput] operation. Changes are listed in the order they appear in the
      * text, not the order in which they were made. Overlapping changes are represented as a single
      * change.
      */
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text2/input/internal/ChangeTracker.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text2/input/internal/ChangeTracker.kt
index a3f31a5..ad73c39 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text2/input/internal/ChangeTracker.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text2/input/internal/ChangeTracker.kt
@@ -64,15 +64,17 @@
      *     for the new text.
      *  3. Offset all remaining changes are to account for the new text.
      */
-    fun trackChange(preRange: TextRange, postLength: Int) {
-        if (preRange.collapsed && postLength == 0) {
+    fun trackChange(preStart: Int, preEnd: Int, postLength: Int) {
+        if (preStart == preEnd && postLength == 0) {
             // Ignore noop changes.
             return
         }
+        val preMin = minOf(preStart, preEnd)
+        val preMax = maxOf(preStart, preEnd)
 
         var i = 0
         var recordedNewChange = false
-        val postDelta = postLength - preRange.length
+        val postDelta = postLength - (preMax - preStart)
 
         var mergedOverlappingChange: Change? = null
         while (i < _changes.size) {
@@ -80,8 +82,8 @@
 
             // Merge adjacent and overlapping changes as we go.
             if (
-                change.preStart in preRange.min..preRange.max ||
-                change.preEnd in preRange.min..preRange.max
+                change.preStart in preMin..preMax ||
+                change.preEnd in preMin..preMax
             ) {
                 if (mergedOverlappingChange == null) {
                     mergedOverlappingChange = change
@@ -94,10 +96,10 @@
                 continue
             }
 
-            if (change.preStart > preRange.max && !recordedNewChange) {
+            if (change.preStart > preMax && !recordedNewChange) {
                 // First non-overlapping change after the new one – record the change before
                 // proceeding.
-                appendNewChange(mergedOverlappingChange, preRange, postDelta)
+                appendNewChange(mergedOverlappingChange, preMin, preMax, postDelta)
                 recordedNewChange = true
             }
 
@@ -112,7 +114,7 @@
         if (!recordedNewChange) {
             // The new change is after or overlapping all previous changes so it hasn't been
             // appended yet.
-            appendNewChange(mergedOverlappingChange, preRange, postDelta)
+            appendNewChange(mergedOverlappingChange, preMin, preMax, postDelta)
         }
 
         // Swap the lists.
@@ -146,7 +148,8 @@
 
     private fun appendNewChange(
         mergedOverlappingChange: Change?,
-        preRange: TextRange,
+        preMin: Int,
+        preMax: Int,
         postDelta: Int
     ) {
         var originalDelta = if (_changesTemp.isEmpty()) 0 else {
@@ -155,11 +158,11 @@
         val newChange: Change
         if (mergedOverlappingChange == null) {
             // There were no overlapping changes, so allocate a new one.
-            val originalStart = preRange.min - originalDelta
-            val originalEnd = originalStart + preRange.length
+            val originalStart = preMin - originalDelta
+            val originalEnd = originalStart + (preMax - preMin)
             newChange = Change(
-                preStart = preRange.min,
-                preEnd = preRange.max + postDelta,
+                preStart = preMin,
+                preEnd = preMax + postDelta,
                 originalStart = originalStart,
                 originalEnd = originalEnd
             )
@@ -167,16 +170,16 @@
             newChange = mergedOverlappingChange
             // Convert the merged overlapping changes to the `post` space.
             // Merge the new changed with the merged overlapping changes.
-            if (newChange.preStart > preRange.min) {
+            if (newChange.preStart > preMin) {
                 // The new change starts before the merged overlapping set.
-                newChange.preStart = preRange.min
-                newChange.originalStart = preRange.min
+                newChange.preStart = preMin
+                newChange.originalStart = preMin
             }
-            if (preRange.max > newChange.preEnd) {
+            if (preMax > newChange.preEnd) {
                 // The new change ends after the merged overlapping set.
                 originalDelta = newChange.preEnd - newChange.originalEnd
-                newChange.preEnd = preRange.max
-                newChange.originalEnd = preRange.max - originalDelta
+                newChange.preEnd = preMax
+                newChange.originalEnd = preMax - originalDelta
             }
             newChange.preEnd += postDelta
         }
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text2/input/internal/EditingBuffer.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text2/input/internal/EditingBuffer.kt
index 75ef12a..d869ec5 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text2/input/internal/EditingBuffer.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text2/input/internal/EditingBuffer.kt
@@ -151,7 +151,7 @@
         val min = minOf(start, end)
         val max = maxOf(start, end)
 
-        changeTracker.trackChange(TextRange(start, end), text.length)
+        changeTracker.trackChange(start, end, text.length)
 
         gapBuffer.replace(min, max, text)
 
@@ -180,7 +180,7 @@
         checkRange(start, end)
         val deleteRange = TextRange(start, end)
 
-        changeTracker.trackChange(deleteRange, 0)
+        changeTracker.trackChange(start, end, 0)
 
         gapBuffer.replace(deleteRange.min, deleteRange.max, "")
 
diff --git a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/internal/ChangeTrackerTest.kt b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/internal/ChangeTrackerTest.kt
index 5c08053..3029a8e 100644
--- a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/internal/ChangeTrackerTest.kt
+++ b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/internal/ChangeTrackerTest.kt
@@ -190,7 +190,7 @@
         val changes = ChangeTracker()
 
         fun append(text: String) {
-            changes.trackChange(TextRange(builder.length), text.length)
+            changes.trackChange(builder.length, builder.length, text.length)
             builder.append(text)
         }
 
@@ -198,7 +198,7 @@
             val start = builder.indexOf(substring)
             if (start != -1) {
                 val end = start + substring.length
-                changes.trackChange(TextRange(start, end), text.length)
+                changes.trackChange(start, end, text.length)
                 builder.replace(start, end, text)
             }
         }
diff --git a/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/PagerAsCarouselBenchmark.kt b/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/PagerAsCarouselBenchmark.kt
index becf364..f6b8b9c 100644
--- a/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/PagerAsCarouselBenchmark.kt
+++ b/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/PagerAsCarouselBenchmark.kt
@@ -29,6 +29,7 @@
 import androidx.test.uiautomator.Until
 import androidx.testutils.createCompilationParams
 import org.junit.Before
+import org.junit.Ignore
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -51,6 +52,7 @@
     }
 
     @Test
+    @Ignore("b/299155975")
     fun scroll() {
         val carousel = device.findObject(By.desc(ContentDescription))
         benchmarkRule.performRepeatedScroll(PackageName, compilationMode, Action, carousel) {
diff --git a/compose/lint/internal-lint-checks/build.gradle b/compose/lint/internal-lint-checks/build.gradle
index 3039214..f2132be 100644
--- a/compose/lint/internal-lint-checks/build.gradle
+++ b/compose/lint/internal-lint-checks/build.gradle
@@ -26,6 +26,7 @@
     compileOnly(libs.androidLintApi)
     compileOnly(libs.kotlinStdlib)
     implementation(project(":compose:lint:common"))
+    implementation(project(":collection:collection"))
 
     testImplementation(project(":compose:lint:common-test"))
     testImplementation(libs.kotlinStdlib)
diff --git a/compose/lint/internal-lint-checks/src/main/java/androidx/compose/lint/AsCollectionDetector.kt b/compose/lint/internal-lint-checks/src/main/java/androidx/compose/lint/AsCollectionDetector.kt
new file mode 100644
index 0000000..2d470e0
--- /dev/null
+++ b/compose/lint/internal-lint-checks/src/main/java/androidx/compose/lint/AsCollectionDetector.kt
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:Suppress("UnstableApiUsage")
+
+package androidx.compose.lint
+
+import androidx.collection.MutableObjectList
+import androidx.collection.MutableScatterMap
+import androidx.collection.MutableScatterSet
+import androidx.collection.ObjectList
+import androidx.collection.ScatterMap
+import androidx.collection.ScatterSet
+import androidx.collection.scatterSetOf
+import com.android.tools.lint.client.api.UElementHandler
+import com.android.tools.lint.detector.api.Category
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Implementation
+import com.android.tools.lint.detector.api.Issue
+import com.android.tools.lint.detector.api.JavaContext
+import com.android.tools.lint.detector.api.Scope
+import com.android.tools.lint.detector.api.Severity
+import com.android.tools.lint.detector.api.SourceCodeScanner
+import com.intellij.psi.impl.source.PsiClassReferenceType
+import java.util.EnumSet
+import org.jetbrains.uast.UCallExpression
+import org.jetbrains.uast.UElement
+
+/**
+ * Using [ScatterMap.asMap], [ScatterSet.asSet], [ObjectList.asList], or their mutable
+ * counterparts indicates that the developer may be using the collection incorrectly.
+ * Using the interfaces is slower access. It is best to use those only for when it touches
+ * public API.
+ */
+class AsCollectionDetector : Detector(), SourceCodeScanner {
+    override fun getApplicableUastTypes() = listOf<Class<out UElement>>(
+        UCallExpression::class.java
+    )
+
+    override fun createUastHandler(context: JavaContext) = object : UElementHandler() {
+        override fun visitCallExpression(node: UCallExpression) {
+            val methodName = node.methodName ?: return
+            if (methodName in MethodNames) {
+                val receiverType = node.receiverType as? PsiClassReferenceType ?: return
+                val qualifiedName = receiverType.reference.qualifiedName ?: return
+                val indexOfAngleBracket = qualifiedName.indexOf('<')
+                if (indexOfAngleBracket > 0 &&
+                    qualifiedName.substring(0, indexOfAngleBracket) in CollectionClasses
+                ) {
+                    context.report(
+                        ISSUE,
+                        node,
+                        context.getLocation(node),
+                        "Use method $methodName() only for public API usage"
+                    )
+                }
+            }
+        }
+    }
+
+    companion object {
+        private val MethodNames = scatterSetOf(
+            "asMap",
+            "asMutableMap",
+            "asSet",
+            "asMutableSet",
+            "asList",
+            "asMutableList"
+        )
+        private val CollectionClasses = scatterSetOf(
+            ScatterMap::class.qualifiedName,
+            MutableScatterMap::class.qualifiedName,
+            ScatterSet::class.qualifiedName,
+            MutableScatterSet::class.qualifiedName,
+            ObjectList::class.qualifiedName,
+            MutableObjectList::class.qualifiedName,
+        )
+
+        private val AsCollectionDetectorId = "AsCollectionCall"
+
+        val ISSUE = Issue.create(
+            id = AsCollectionDetectorId,
+            briefDescription = "High performance collections don't implement standard collection " +
+                "interfaces so that they can remain high performance. Converting to standard " +
+                "collections wraps the classes with another object. Use these interface " +
+                "wrappers only for exposing to public API.",
+            explanation = "ScatterMap, ScatterSet, and AnyList are written for high " +
+                "performance access. Using the standard collection interfaces for these classes " +
+                "forces slower performance access to these collections. The methods returning " +
+                "these interfaces should be limited to public API, where standard collection " +
+                "interfaces are expected.",
+            category = Category.PERFORMANCE, priority = 3, severity = Severity.ERROR,
+            implementation = Implementation(
+                AsCollectionDetector::class.java,
+                EnumSet.of(Scope.JAVA_FILE)
+            )
+        )
+    }
+}
diff --git a/compose/lint/internal-lint-checks/src/main/java/androidx/compose/lint/ComposeIssueRegistry.kt b/compose/lint/internal-lint-checks/src/main/java/androidx/compose/lint/ComposeIssueRegistry.kt
index 7e43f93..f13628f 100644
--- a/compose/lint/internal-lint-checks/src/main/java/androidx/compose/lint/ComposeIssueRegistry.kt
+++ b/compose/lint/internal-lint-checks/src/main/java/androidx/compose/lint/ComposeIssueRegistry.kt
@@ -28,6 +28,7 @@
     override val api = 14
     override val issues get(): List<Issue> {
         return listOf(
+            AsCollectionDetector.ISSUE,
             ExceptionMessageDetector.ISSUE,
             ListIteratorDetector.ISSUE,
             SteppedForLoopDetector.ISSUE,
diff --git a/compose/lint/internal-lint-checks/src/test/java/androidx/compose/lint/AsCollectionDetectorTest.kt b/compose/lint/internal-lint-checks/src/test/java/androidx/compose/lint/AsCollectionDetectorTest.kt
new file mode 100644
index 0000000..39ce2a1
--- /dev/null
+++ b/compose/lint/internal-lint-checks/src/test/java/androidx/compose/lint/AsCollectionDetectorTest.kt
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2023 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.lint
+
+import com.android.tools.lint.checks.infrastructure.LintDetectorTest
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Issue
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+/* ktlint-disable max-line-length */
+@RunWith(Parameterized::class)
+class AsCollectionDetectorTest(
+    val types: CollectionType
+) : LintDetectorTest() {
+
+    override fun getDetector(): Detector = AsCollectionDetector()
+
+    override fun getIssues(): MutableList<Issue> =
+        mutableListOf(AsCollectionDetector.ISSUE)
+
+    private val collectionTilde = "~".repeat(types.collection.length)
+
+    @Test
+    fun immutableAsImmutable() {
+        lint().files(
+            ScatterMapClass,
+            ScatterSetClass,
+            ObjectListClass,
+            kotlin(
+                """
+                        package androidx.compose.lint
+
+                        import androidx.collection.${types.immutable}
+
+                        fun foo(collection: ${types.immutable}${types.params}): ${types.collection}${types.params} =
+                            collection.as${types.collection}()
+                        """
+            )
+        ).run().expect(
+            """
+src/androidx/compose/lint/test.kt:7: Error: Use method as${types.collection}() only for public API usage [AsCollectionCall]
+                            collection.as${types.collection}()
+                            ~~~~~~~~~~~~~$collectionTilde~~
+1 errors, 0 warnings
+            """
+        )
+    }
+
+    @Test
+    fun mutableAsImmutable() {
+        lint().files(
+            ScatterMapClass,
+            ScatterSetClass,
+            ObjectListClass,
+            kotlin(
+                """
+                        package androidx.compose.lint
+
+                        import androidx.collection.Mutable${types.immutable}
+
+                        fun foo(collection: Mutable${types.immutable}${types.params}): ${types.collection}${types.params} =
+                            collection.as${types.collection}()
+                        """
+            )
+        ).run().expect(
+            """
+src/androidx/compose/lint/test.kt:7: Error: Use method as${types.collection}() only for public API usage [AsCollectionCall]
+                            collection.as${types.collection}()
+                            ~~~~~~~~~~~~~$collectionTilde~~
+1 errors, 0 warnings
+            """
+        )
+    }
+
+    @Test
+    fun mutableAsMutable() {
+        lint().files(
+            ScatterMapClass,
+            ScatterSetClass,
+            ObjectListClass,
+            kotlin(
+                """
+                        package androidx.compose.lint
+
+                        import androidx.collection.Mutable${types.immutable}
+
+                        fun foo(collection: Mutable${types.immutable}${types.params}): Mutable${types.collection}${types.params} =
+                            collection.asMutable${types.collection}()
+                        """
+            )
+        ).run().expect(
+            """
+src/androidx/compose/lint/test.kt:7: Error: Use method asMutable${types.collection}() only for public API usage [AsCollectionCall]
+                            collection.asMutable${types.collection}()
+                            ~~~~~~~~~~~~~~~~~~~~$collectionTilde~~
+1 errors, 0 warnings
+            """
+        )
+    }
+
+    @Test
+    fun nonCollectionAs() {
+        lint().files(
+            kotlin(
+                """
+                        package androidx.compose.lint
+
+                        fun foo(): ${types.collection}${types.params} =
+                            WeirdCollection().as${types.collection}()
+
+                        class WeirdCollection {
+                            fun asList(): List<String>? = null
+                            fun asSet(): Set<String>? = null
+                            fun asMap(): Map<String, String>? = null
+                        }
+                        """
+            )
+        ).run().expectClean()
+    }
+
+    class CollectionType(
+        val immutable: String,
+        val collection: String,
+        val params: String
+    )
+
+    companion object {
+        @JvmStatic
+        @Parameterized.Parameters(name = "{0}")
+        fun initParameters() = listOf(
+            CollectionType("ScatterMap", "Map", "<String, String>"),
+            CollectionType("ScatterSet", "Set", "<String>"),
+            CollectionType("ObjectList", "List", "<String>")
+        )
+
+        val ScatterMapClass = kotlin(
+            """
+            package androidx.collection
+            sealed class ScatterMap<K, V> {
+                fun asMap(): Map<K, V> = mapOf()
+            }
+
+            class MutableScatterMap<K, V> : ScatterMap<K, V>() {
+                fun asMutableMap(): MutableMap<K, V> = mutableMapOf()
+            }
+            """.trimIndent()
+        )
+
+        val ScatterSetClass = kotlin(
+            """
+            package androidx.collection
+            sealed class ScatterSet<E> {
+                fun asSet(): Set<E> = setOf()
+            }
+
+            class MutableScatterSet<E> : ScatterSet<E>() {
+                fun asMutableSet(): MutableSet<E> = mutableSetOf()
+            }
+            """.trimIndent()
+        )
+
+        val ObjectListClass = kotlin(
+            """
+            package androidx.collection
+            sealed class ObjectList<E> {
+                fun asList(): List<E> = listOf()
+            }
+
+            class MutableObjectList<E> : ObjectList<E>() {
+                fun asMutableList(): MutableList<E> = mutableListOf()
+            }
+            """.trimIndent()
+        )
+    }
+}
diff --git a/compose/material3/material3/api/current.txt b/compose/material3/material3/api/current.txt
index d665b1b..2e69826 100644
--- a/compose/material3/material3/api/current.txt
+++ b/compose/material3/material3/api/current.txt
@@ -29,13 +29,17 @@
   }
 
   public final class AppBarKt {
+    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void BottomAppBar(optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional float tonalElevation, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.BottomAppBarScrollBehavior? scrollBehavior, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
     method @androidx.compose.runtime.Composable public static void BottomAppBar(optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional float tonalElevation, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.layout.WindowInsets windowInsets, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
     method @androidx.compose.runtime.Composable public static void BottomAppBar(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> actions, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? floatingActionButton, optional long containerColor, optional long contentColor, optional float tonalElevation, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.layout.WindowInsets windowInsets);
+    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void BottomAppBar(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> actions, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? floatingActionButton, optional long containerColor, optional long contentColor, optional float tonalElevation, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.BottomAppBarScrollBehavior? scrollBehavior);
+    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public static androidx.compose.material3.BottomAppBarState BottomAppBarState(float initialHeightOffsetLimit, float initialHeightOffset, float initialContentOffset);
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void CenterAlignedTopAppBar(kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit> navigationIcon, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> actions, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.TopAppBarColors colors, optional androidx.compose.material3.TopAppBarScrollBehavior? scrollBehavior);
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void LargeTopAppBar(kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit> navigationIcon, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> actions, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.TopAppBarColors colors, optional androidx.compose.material3.TopAppBarScrollBehavior? scrollBehavior);
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void MediumTopAppBar(kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit> navigationIcon, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> actions, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.TopAppBarColors colors, optional androidx.compose.material3.TopAppBarScrollBehavior? scrollBehavior);
     method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SmallTopAppBar(kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit> navigationIcon, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> actions, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.TopAppBarColors colors, optional androidx.compose.material3.TopAppBarScrollBehavior? scrollBehavior);
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void TopAppBar(kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit> navigationIcon, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> actions, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.TopAppBarColors colors, optional androidx.compose.material3.TopAppBarScrollBehavior? scrollBehavior);
+    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.BottomAppBarState rememberBottomAppBarState(optional float initialHeightOffsetLimit, optional float initialHeightOffset, optional float initialContentOffset);
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.TopAppBarState rememberTopAppBarState(optional float initialHeightOffsetLimit, optional float initialHeightOffset, optional float initialContentOffset);
   }
 
@@ -66,6 +70,7 @@
   }
 
   public final class BottomAppBarDefaults {
+    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public androidx.compose.material3.BottomAppBarScrollBehavior exitAlwaysScrollBehavior(optional androidx.compose.material3.BottomAppBarState state, optional kotlin.jvm.functions.Function0<java.lang.Boolean> canScroll, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float>? snapAnimationSpec, optional androidx.compose.animation.core.DecayAnimationSpec<java.lang.Float>? flingAnimationSpec);
     method @androidx.compose.runtime.Composable public long getBottomAppBarFabColor();
     method @androidx.compose.runtime.Composable public long getContainerColor();
     method public float getContainerElevation();
@@ -79,6 +84,39 @@
     field public static final androidx.compose.material3.BottomAppBarDefaults INSTANCE;
   }
 
+  @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public interface BottomAppBarScrollBehavior {
+    method public androidx.compose.animation.core.DecayAnimationSpec<java.lang.Float>? getFlingAnimationSpec();
+    method public androidx.compose.ui.input.nestedscroll.NestedScrollConnection getNestedScrollConnection();
+    method public androidx.compose.animation.core.AnimationSpec<java.lang.Float>? getSnapAnimationSpec();
+    method public androidx.compose.material3.BottomAppBarState getState();
+    method public boolean isPinned();
+    property public abstract androidx.compose.animation.core.DecayAnimationSpec<java.lang.Float>? flingAnimationSpec;
+    property public abstract boolean isPinned;
+    property public abstract androidx.compose.ui.input.nestedscroll.NestedScrollConnection nestedScrollConnection;
+    property public abstract androidx.compose.animation.core.AnimationSpec<java.lang.Float>? snapAnimationSpec;
+    property public abstract androidx.compose.material3.BottomAppBarState state;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public interface BottomAppBarState {
+    method public float getCollapsedFraction();
+    method public float getContentOffset();
+    method public float getHeightOffset();
+    method public float getHeightOffsetLimit();
+    method public void setContentOffset(float);
+    method public void setHeightOffset(float);
+    method public void setHeightOffsetLimit(float);
+    property public abstract float collapsedFraction;
+    property public abstract float contentOffset;
+    property public abstract float heightOffset;
+    property public abstract float heightOffsetLimit;
+    field public static final androidx.compose.material3.BottomAppBarState.Companion Companion;
+  }
+
+  public static final class BottomAppBarState.Companion {
+    method public androidx.compose.runtime.saveable.Saver<androidx.compose.material3.BottomAppBarState,?> getSaver();
+    property public final androidx.compose.runtime.saveable.Saver<androidx.compose.material3.BottomAppBarState,?> Saver;
+  }
+
   @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public final class BottomSheetDefaults {
     method @androidx.compose.runtime.Composable public void DragHandle(optional androidx.compose.ui.Modifier modifier, optional float width, optional float height, optional androidx.compose.ui.graphics.Shape shape, optional long color);
     method @androidx.compose.runtime.Composable public long getContainerColor();
@@ -677,9 +715,11 @@
   public static final class FabPosition.Companion {
     method public int getCenter();
     method public int getEnd();
+    method public int getEndOverlay();
     method public int getStart();
     property public final int Center;
     property public final int End;
+    property public final int EndOverlay;
     property public final int Start;
   }
 
@@ -829,6 +869,10 @@
     property @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public static final androidx.compose.runtime.ProvidableCompositionLocal<java.lang.Boolean> LocalMinimumTouchTargetEnforcement;
   }
 
+  public final class LabelKt {
+    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void Label(kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional boolean isPersistent, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+  }
+
   @androidx.compose.runtime.Immutable public final class ListItemColors {
     ctor public ListItemColors(long containerColor, long headlineColor, long leadingIconColor, long overlineColor, long supportingTextColor, long trailingIconColor, long disabledHeadlineColor, long disabledLeadingIconColor, long disabledTrailingIconColor);
     method public long getContainerColor();
diff --git a/compose/material3/material3/api/restricted_current.txt b/compose/material3/material3/api/restricted_current.txt
index d665b1b..2e69826 100644
--- a/compose/material3/material3/api/restricted_current.txt
+++ b/compose/material3/material3/api/restricted_current.txt
@@ -29,13 +29,17 @@
   }
 
   public final class AppBarKt {
+    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void BottomAppBar(optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional float tonalElevation, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.BottomAppBarScrollBehavior? scrollBehavior, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
     method @androidx.compose.runtime.Composable public static void BottomAppBar(optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional float tonalElevation, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.layout.WindowInsets windowInsets, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
     method @androidx.compose.runtime.Composable public static void BottomAppBar(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> actions, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? floatingActionButton, optional long containerColor, optional long contentColor, optional float tonalElevation, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.layout.WindowInsets windowInsets);
+    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void BottomAppBar(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> actions, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? floatingActionButton, optional long containerColor, optional long contentColor, optional float tonalElevation, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.BottomAppBarScrollBehavior? scrollBehavior);
+    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public static androidx.compose.material3.BottomAppBarState BottomAppBarState(float initialHeightOffsetLimit, float initialHeightOffset, float initialContentOffset);
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void CenterAlignedTopAppBar(kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit> navigationIcon, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> actions, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.TopAppBarColors colors, optional androidx.compose.material3.TopAppBarScrollBehavior? scrollBehavior);
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void LargeTopAppBar(kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit> navigationIcon, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> actions, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.TopAppBarColors colors, optional androidx.compose.material3.TopAppBarScrollBehavior? scrollBehavior);
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void MediumTopAppBar(kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit> navigationIcon, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> actions, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.TopAppBarColors colors, optional androidx.compose.material3.TopAppBarScrollBehavior? scrollBehavior);
     method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SmallTopAppBar(kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit> navigationIcon, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> actions, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.TopAppBarColors colors, optional androidx.compose.material3.TopAppBarScrollBehavior? scrollBehavior);
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void TopAppBar(kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit> navigationIcon, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> actions, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.TopAppBarColors colors, optional androidx.compose.material3.TopAppBarScrollBehavior? scrollBehavior);
+    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.BottomAppBarState rememberBottomAppBarState(optional float initialHeightOffsetLimit, optional float initialHeightOffset, optional float initialContentOffset);
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.TopAppBarState rememberTopAppBarState(optional float initialHeightOffsetLimit, optional float initialHeightOffset, optional float initialContentOffset);
   }
 
@@ -66,6 +70,7 @@
   }
 
   public final class BottomAppBarDefaults {
+    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public androidx.compose.material3.BottomAppBarScrollBehavior exitAlwaysScrollBehavior(optional androidx.compose.material3.BottomAppBarState state, optional kotlin.jvm.functions.Function0<java.lang.Boolean> canScroll, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float>? snapAnimationSpec, optional androidx.compose.animation.core.DecayAnimationSpec<java.lang.Float>? flingAnimationSpec);
     method @androidx.compose.runtime.Composable public long getBottomAppBarFabColor();
     method @androidx.compose.runtime.Composable public long getContainerColor();
     method public float getContainerElevation();
@@ -79,6 +84,39 @@
     field public static final androidx.compose.material3.BottomAppBarDefaults INSTANCE;
   }
 
+  @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public interface BottomAppBarScrollBehavior {
+    method public androidx.compose.animation.core.DecayAnimationSpec<java.lang.Float>? getFlingAnimationSpec();
+    method public androidx.compose.ui.input.nestedscroll.NestedScrollConnection getNestedScrollConnection();
+    method public androidx.compose.animation.core.AnimationSpec<java.lang.Float>? getSnapAnimationSpec();
+    method public androidx.compose.material3.BottomAppBarState getState();
+    method public boolean isPinned();
+    property public abstract androidx.compose.animation.core.DecayAnimationSpec<java.lang.Float>? flingAnimationSpec;
+    property public abstract boolean isPinned;
+    property public abstract androidx.compose.ui.input.nestedscroll.NestedScrollConnection nestedScrollConnection;
+    property public abstract androidx.compose.animation.core.AnimationSpec<java.lang.Float>? snapAnimationSpec;
+    property public abstract androidx.compose.material3.BottomAppBarState state;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public interface BottomAppBarState {
+    method public float getCollapsedFraction();
+    method public float getContentOffset();
+    method public float getHeightOffset();
+    method public float getHeightOffsetLimit();
+    method public void setContentOffset(float);
+    method public void setHeightOffset(float);
+    method public void setHeightOffsetLimit(float);
+    property public abstract float collapsedFraction;
+    property public abstract float contentOffset;
+    property public abstract float heightOffset;
+    property public abstract float heightOffsetLimit;
+    field public static final androidx.compose.material3.BottomAppBarState.Companion Companion;
+  }
+
+  public static final class BottomAppBarState.Companion {
+    method public androidx.compose.runtime.saveable.Saver<androidx.compose.material3.BottomAppBarState,?> getSaver();
+    property public final androidx.compose.runtime.saveable.Saver<androidx.compose.material3.BottomAppBarState,?> Saver;
+  }
+
   @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public final class BottomSheetDefaults {
     method @androidx.compose.runtime.Composable public void DragHandle(optional androidx.compose.ui.Modifier modifier, optional float width, optional float height, optional androidx.compose.ui.graphics.Shape shape, optional long color);
     method @androidx.compose.runtime.Composable public long getContainerColor();
@@ -677,9 +715,11 @@
   public static final class FabPosition.Companion {
     method public int getCenter();
     method public int getEnd();
+    method public int getEndOverlay();
     method public int getStart();
     property public final int Center;
     property public final int End;
+    property public final int EndOverlay;
     property public final int Start;
   }
 
@@ -829,6 +869,10 @@
     property @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public static final androidx.compose.runtime.ProvidableCompositionLocal<java.lang.Boolean> LocalMinimumTouchTargetEnforcement;
   }
 
+  public final class LabelKt {
+    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void Label(kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional boolean isPersistent, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+  }
+
   @androidx.compose.runtime.Immutable public final class ListItemColors {
     ctor public ListItemColors(long containerColor, long headlineColor, long leadingIconColor, long overlineColor, long supportingTextColor, long trailingIconColor, long disabledHeadlineColor, long disabledLeadingIconColor, long disabledTrailingIconColor);
     method public long getContainerColor();
diff --git a/compose/material3/material3/integration-tests/material3-catalog/src/main/java/androidx/compose/material3/catalog/library/model/Examples.kt b/compose/material3/material3/integration-tests/material3-catalog/src/main/java/androidx/compose/material3/catalog/library/model/Examples.kt
index c6d720e..2e8c6a2 100644
--- a/compose/material3/material3/integration-tests/material3-catalog/src/main/java/androidx/compose/material3/catalog/library/model/Examples.kt
+++ b/compose/material3/material3/integration-tests/material3-catalog/src/main/java/androidx/compose/material3/catalog/library/model/Examples.kt
@@ -57,6 +57,7 @@
 import androidx.compose.material3.samples.ElevatedFilterChipSample
 import androidx.compose.material3.samples.ElevatedSuggestionChipSample
 import androidx.compose.material3.samples.EnterAlwaysTopAppBar
+import androidx.compose.material3.samples.ExitAlwaysBottomAppBar
 import androidx.compose.material3.samples.ExitUntilCollapsedLargeTopAppBar
 import androidx.compose.material3.samples.ExitUntilCollapsedMediumTopAppBar
 import androidx.compose.material3.samples.ExposedDropdownMenuSample
@@ -465,7 +466,12 @@
         name = ::BottomAppBarWithFAB.name,
         description = BottomAppBarsExampleDescription,
         sourceUrl = BottomAppBarsExampleSourceUrl,
-    ) { BottomAppBarWithFAB() }
+    ) { BottomAppBarWithFAB() },
+    Example(
+        name = ::ExitAlwaysBottomAppBar.name,
+        description = BottomAppBarsExampleDescription,
+        sourceUrl = BottomAppBarsExampleSourceUrl,
+    ) { ExitAlwaysBottomAppBar() }
 )
 
 private const val TopAppBarExampleDescription = "Top app bar examples"
diff --git a/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/AppBarSamples.kt b/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/AppBarSamples.kt
index 6cbc0aa..a6538f0 100644
--- a/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/AppBarSamples.kt
+++ b/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/AppBarSamples.kt
@@ -19,6 +19,7 @@
 import androidx.annotation.Sampled
 import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.offset
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.lazy.LazyColumn
 import androidx.compose.material.icons.Icons
@@ -31,6 +32,7 @@
 import androidx.compose.material3.BottomAppBarDefaults
 import androidx.compose.material3.CenterAlignedTopAppBar
 import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.FabPosition
 import androidx.compose.material3.FloatingActionButton
 import androidx.compose.material3.FloatingActionButtonDefaults
 import androidx.compose.material3.Icon
@@ -418,11 +420,13 @@
 @Sampled
 @Composable
 fun SimpleBottomAppBar() {
-    BottomAppBar {
-        IconButton(onClick = { /* doSomething() */ }) {
-            Icon(Icons.Filled.Menu, contentDescription = "Localized description")
+    BottomAppBar(
+        actions = {
+            IconButton(onClick = { /* doSomething() */ }) {
+                Icon(Icons.Filled.Menu, contentDescription = "Localized description")
+            }
         }
-    }
+    )
 }
 
 @Preview
@@ -452,3 +456,59 @@
         }
     )
 }
+
+/**
+ * A sample for a [BottomAppBar] that collapses when the content is scrolled up, and
+ * appears when the content scrolled down.
+ */
+@OptIn(ExperimentalMaterial3Api::class)
+@Preview
+@Sampled
+@Composable
+fun ExitAlwaysBottomAppBar() {
+    val scrollBehavior = BottomAppBarDefaults.exitAlwaysScrollBehavior()
+    Scaffold(
+        modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
+        bottomBar = {
+            BottomAppBar(
+                actions = {
+                    IconButton(onClick = { /* doSomething() */ }) {
+                        Icon(Icons.Filled.Check, contentDescription = "Localized description")
+                    }
+                    IconButton(onClick = { /* doSomething() */ }) {
+                        Icon(Icons.Filled.Edit, contentDescription = "Localized description")
+                    }
+                },
+                scrollBehavior = scrollBehavior
+            )
+        },
+        floatingActionButton = {
+            FloatingActionButton(
+                modifier = Modifier.offset(y = 4.dp),
+                onClick = { /* do something */ },
+                containerColor = BottomAppBarDefaults.bottomAppBarFabColor,
+                elevation = FloatingActionButtonDefaults.bottomAppBarFabElevation()
+            ) {
+                Icon(Icons.Filled.Add, "Localized description")
+            }
+        },
+        floatingActionButtonPosition = FabPosition.EndOverlay,
+        content = { innerPadding ->
+            LazyColumn(
+                contentPadding = innerPadding,
+                verticalArrangement = Arrangement.spacedBy(8.dp)
+            ) {
+                val list = (0..75).map { it.toString() }
+                items(count = list.size) {
+                    Text(
+                        text = list[it],
+                        style = MaterialTheme.typography.bodyLarge,
+                        modifier = Modifier
+                            .fillMaxWidth()
+                            .padding(horizontal = 16.dp)
+                    )
+                }
+            }
+        }
+    )
+}
diff --git a/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/SliderSamples.kt b/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/SliderSamples.kt
index 77929ef..2528da4 100644
--- a/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/SliderSamples.kt
+++ b/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/SliderSamples.kt
@@ -19,12 +19,16 @@
 import androidx.annotation.Sampled
 import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.requiredSize
 import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.wrapContentWidth
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.filled.Favorite
 import androidx.compose.material3.ButtonDefaults
 import androidx.compose.material3.ExperimentalMaterial3Api
 import androidx.compose.material3.Icon
+import androidx.compose.material3.Label
+import androidx.compose.material3.PlainTooltip
 import androidx.compose.material3.RangeSlider
 import androidx.compose.material3.RangeSliderState
 import androidx.compose.material3.Slider
@@ -41,6 +45,8 @@
 import androidx.compose.ui.semantics.contentDescription
 import androidx.compose.ui.semantics.semantics
 import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import kotlin.math.roundToInt
 
 @Preview
 @Sampled
@@ -56,7 +62,6 @@
     }
 }
 
-@OptIn(ExperimentalMaterial3Api::class)
 @Preview
 @Sampled
 @Composable
@@ -84,25 +89,40 @@
 @Composable
 fun SliderWithCustomThumbSample() {
     var sliderPosition by remember { mutableStateOf(0f) }
+    val interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }
     Column {
-        Text(text = sliderPosition.toString())
         Slider(
             modifier = Modifier.semantics { contentDescription = "Localized Description" },
             value = sliderPosition,
             onValueChange = { sliderPosition = it },
-            valueRange = 0f..5f,
-            steps = 10,
+            valueRange = 0f..100f,
+            interactionSource = interactionSource,
             onValueChangeFinished = {
                 // launch some business logic update with the state you hold
                 // viewModel.updateSelectedSliderValue(sliderPosition)
             },
             thumb = {
-                Icon(
-                    imageVector = Icons.Filled.Favorite,
-                    contentDescription = null,
-                    modifier = Modifier.size(ButtonDefaults.IconSize),
-                    tint = Color.Red
-                )
+                Label(
+                    label = {
+                        PlainTooltip(
+                            modifier = Modifier
+                                .requiredSize(45.dp, 25.dp)
+                                .wrapContentWidth()
+                        ) {
+                            val roundedEnd =
+                                (sliderPosition * 100.0).roundToInt() / 100.0
+                            Text(roundedEnd.toString())
+                        }
+                    },
+                    interactionSource = interactionSource
+                ) {
+                    Icon(
+                        imageVector = Icons.Filled.Favorite,
+                        contentDescription = null,
+                        modifier = Modifier.size(ButtonDefaults.IconSize),
+                        tint = Color.Red
+                    )
+                }
             }
         )
     }
@@ -221,23 +241,52 @@
     )
     val endThumbColors = SliderDefaults.colors(thumbColor = Color.Green)
     Column {
-        Text(text = (rangeSliderState.activeRangeStart..rangeSliderState.activeRangeEnd).toString())
         RangeSlider(
             state = rangeSliderState,
             modifier = Modifier.semantics { contentDescription = "Localized Description" },
             startInteractionSource = startInteractionSource,
             endInteractionSource = endInteractionSource,
             startThumb = {
-                SliderDefaults.Thumb(
-                    interactionSource = startInteractionSource,
-                    colors = startThumbAndTrackColors
-                )
+                Label(
+                    label = {
+                        PlainTooltip(
+                            modifier = Modifier
+                                .requiredSize(45.dp, 25.dp)
+                                .wrapContentWidth()
+                        ) {
+                            val roundedStart =
+                                (rangeSliderState.activeRangeStart * 100.0).roundToInt() / 100.0
+                            Text(roundedStart.toString())
+                        }
+                    },
+                    interactionSource = startInteractionSource
+                ) {
+                    SliderDefaults.Thumb(
+                        interactionSource = startInteractionSource,
+                        colors = startThumbAndTrackColors
+                    )
+                }
             },
             endThumb = {
-                SliderDefaults.Thumb(
-                    interactionSource = endInteractionSource,
-                    colors = endThumbColors
-                )
+                Label(
+                    label = {
+                        PlainTooltip(
+                            modifier = Modifier
+                                .requiredSize(45.dp, 25.dp)
+                                .wrapContentWidth()
+                        ) {
+                            val roundedEnd =
+                                (rangeSliderState.activeRangeEnd * 100.0).roundToInt() / 100.0
+                            Text(roundedEnd.toString())
+                        }
+                    },
+                    interactionSource = endInteractionSource
+                ) {
+                    SliderDefaults.Thumb(
+                        interactionSource = endInteractionSource,
+                        colors = endThumbColors
+                    )
+                }
             },
             track = { rangeSliderState ->
                 SliderDefaults.Track(
diff --git a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/AppBarScreenshotTest.kt b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/AppBarScreenshotTest.kt
index ddbb438..7b8d1a5 100644
--- a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/AppBarScreenshotTest.kt
+++ b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/AppBarScreenshotTest.kt
@@ -24,6 +24,7 @@
 import androidx.compose.material.icons.filled.Add
 import androidx.compose.material.icons.filled.Favorite
 import androidx.compose.material.icons.filled.Menu
+import androidx.compose.material3.BottomAppBarDefaults.bottomAppBarFabColor
 import androidx.compose.material3.TopAppBarDefaults.enterAlwaysScrollBehavior
 import androidx.compose.material3.tokens.TopAppBarSmallTokens
 import androidx.compose.testutils.assertAgainstGolden
@@ -361,7 +362,7 @@
                     floatingActionButton = {
                         FloatingActionButton(
                             onClick = { /* do something */ },
-                            containerColor = BottomAppBarDefaults.bottomAppBarFabColor,
+                            containerColor = bottomAppBarFabColor,
                             elevation = FloatingActionButtonDefaults.bottomAppBarFabElevation()
                         ) {
                             Icon(Icons.Filled.Add, "Localized description")
@@ -393,7 +394,7 @@
                     floatingActionButton = {
                         FloatingActionButton(
                             onClick = { /* do something */ },
-                            containerColor = BottomAppBarDefaults.bottomAppBarFabColor,
+                            containerColor = bottomAppBarFabColor,
                             elevation = FloatingActionButtonDefaults.bottomAppBarFabElevation()
                         ) {
                             Icon(Icons.Filled.Add, "Localized description")
diff --git a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/AppBarTest.kt b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/AppBarTest.kt
index ef6ffe4..a913ceb 100644
--- a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/AppBarTest.kt
+++ b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/AppBarTest.kt
@@ -23,6 +23,7 @@
 import androidx.compose.foundation.layout.WindowInsets
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.offset
 import androidx.compose.foundation.layout.wrapContentHeight
 import androidx.compose.foundation.lazy.LazyColumn
 import androidx.compose.foundation.lazy.LazyListState
@@ -1183,6 +1184,105 @@
             .assertTopPositionInRootIsEqualTo(12.dp)
     }
 
+    @Test
+    fun bottomAppBar_exitAlways_scaffoldWithFAB_default_positioning() {
+        rule.setMaterialContent(lightColorScheme()) {
+            val scrollBehavior = BottomAppBarDefaults.exitAlwaysScrollBehavior()
+            Scaffold(
+                modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
+                bottomBar = {
+                    BottomAppBar(
+                        modifier = Modifier.testTag(BottomAppBarTestTag),
+                        scrollBehavior = scrollBehavior
+                    ) {}
+                },
+                floatingActionButton = {
+                    FloatingActionButton(
+                        modifier = Modifier
+                            .testTag("FAB")
+                            .offset(y = 4.dp),
+                        onClick = { /* do something */ },
+                    ) {}
+                },
+                floatingActionButtonPosition = FabPosition.EndOverlay
+            ) {}
+        }
+
+        val appBarBounds = rule.onNodeWithTag(BottomAppBarTestTag).getUnclippedBoundsInRoot()
+        val fabBounds = rule.onNodeWithTag("FAB").getUnclippedBoundsInRoot()
+        rule.onNodeWithTag("FAB")
+            // FAB should be 16.dp from the end
+            .assertLeftPositionInRootIsEqualTo(appBarBounds.width - 16.dp - fabBounds.width)
+            // FAB should be 12.dp from the bottom
+            .assertTopPositionInRootIsEqualTo(rule.rootHeight() - 12.dp - fabBounds.height)
+    }
+
+    @Test
+    fun bottomAppBar_exitAlways_scaffoldWithFAB_scrolled_positioning() {
+        lateinit var scrollBehavior: BottomAppBarScrollBehavior
+        val scrollHeightOffsetDp = 20.dp
+        var scrollHeightOffsetPx = 0f
+
+        rule.setMaterialContent(lightColorScheme()) {
+            scrollBehavior = BottomAppBarDefaults.exitAlwaysScrollBehavior()
+            scrollHeightOffsetPx = with(LocalDensity.current) { scrollHeightOffsetDp.toPx() }
+            Scaffold(
+                modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
+                bottomBar = {
+                    BottomAppBar(
+                        modifier = Modifier.testTag(BottomAppBarTestTag),
+                        scrollBehavior = scrollBehavior
+                    ) {}
+                },
+                floatingActionButton = {
+                    FloatingActionButton(
+                        modifier = Modifier
+                            .testTag("FAB")
+                            .offset(y = 4.dp),
+                        onClick = { /* do something */ },
+                    ) {}
+                },
+                floatingActionButtonPosition = FabPosition.EndOverlay
+            ) {}
+        }
+
+        // Simulate scrolled content.
+        rule.runOnIdle {
+            scrollBehavior.state.heightOffset = -scrollHeightOffsetPx
+            scrollBehavior.state.contentOffset = -scrollHeightOffsetPx
+        }
+        rule.waitForIdle()
+        rule.onNodeWithTag(BottomAppBarTestTag)
+            .assertHeightIsEqualTo(BottomAppBarTokens.ContainerHeight - scrollHeightOffsetDp)
+
+        val appBarBounds = rule.onNodeWithTag(BottomAppBarTestTag).getUnclippedBoundsInRoot()
+        val fabBounds = rule.onNodeWithTag("FAB").getUnclippedBoundsInRoot()
+        rule.onNodeWithTag("FAB")
+            // FAB should be 16.dp from the end
+            .assertLeftPositionInRootIsEqualTo(appBarBounds.width - 16.dp - fabBounds.width)
+            // FAB should be 12.dp from the bottom
+            .assertTopPositionInRootIsEqualTo(rule.rootHeight() - 12.dp - fabBounds.height)
+    }
+
+    @Test
+    fun bottomAppBar_exitAlways_allowHorizontalScroll() {
+        lateinit var state: LazyListState
+        rule.setMaterialContent(lightColorScheme()) {
+            state = rememberLazyListState()
+            MultiPageContent(BottomAppBarDefaults.exitAlwaysScrollBehavior(), state)
+        }
+
+        rule.onNodeWithTag(LazyListTag).performTouchInput { swipeLeft() }
+        rule.runOnIdle {
+            assertThat(state.firstVisibleItemIndex).isEqualTo(1)
+        }
+
+        rule.onNodeWithTag(LazyListTag).performTouchInput { swipeRight() }
+        rule.runOnIdle {
+            assertThat(state.firstVisibleItemIndex).isEqualTo(0)
+        }
+    }
+
     @OptIn(ExperimentalMaterial3Api::class)
     @Composable
     private fun MultiPageContent(scrollBehavior: TopAppBarScrollBehavior, state: LazyListState) {
@@ -1218,6 +1318,39 @@
         }
     }
 
+    @Composable
+    private fun MultiPageContent(scrollBehavior: BottomAppBarScrollBehavior, state: LazyListState) {
+        Scaffold(
+            modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
+            bottomBar = {
+                BottomAppBar(
+                    modifier = Modifier.testTag(BottomAppBarTestTag),
+                    scrollBehavior = scrollBehavior
+                ) {}
+            }
+        ) { contentPadding ->
+            LazyRow(
+                Modifier
+                    .fillMaxSize()
+                    .testTag(LazyListTag), state
+            ) {
+                items(2) { page ->
+                    LazyColumn(
+                        modifier = Modifier.fillParentMaxSize(),
+                        contentPadding = contentPadding
+                    ) {
+                        items(50) {
+                            Text(
+                                modifier = Modifier.fillParentMaxWidth(),
+                                text = "Item #$page x $it"
+                            )
+                        }
+                    }
+                }
+            }
+        }
+    }
+
     /**
      * Checks the app bar's components positioning when it's a [TopAppBar], a
      * [CenterAlignedTopAppBar], or a larger app bar that is scrolled up and collapsed into a small
@@ -1583,7 +1716,8 @@
         (TopAppBarSmallTokens.ContainerHeight - FakeIconSize) / 2
 
     private val LazyListTag = "lazyList"
-    private val TopAppBarTestTag = "bar"
+    private val TopAppBarTestTag = "topAppBar"
+    private val BottomAppBarTestTag = "bottomAppBar"
     private val NavigationIconTestTag = "navigationIcon"
     private val TitleTestTag = "title"
     private val ActionsTestTag = "actions"
diff --git a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/ModalBottomSheetTest.kt b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/ModalBottomSheetTest.kt
index 85a2ddc..6d2d0b7 100644
--- a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/ModalBottomSheetTest.kt
+++ b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/ModalBottomSheetTest.kt
@@ -144,6 +144,42 @@
     }
 
     @Test
+    fun modalBottomSheet_isDismissedOnSwipeDown() {
+        var showBottomSheet by mutableStateOf(true)
+        val sheetState = SheetState(skipPartiallyExpanded = false, density = rule.density)
+
+        rule.setContent {
+            val windowInsets = if (edgeToEdgeWrapper.edgeToEdgeEnabled)
+                WindowInsets(0) else BottomSheetDefaults.windowInsets
+
+            if (showBottomSheet) {
+                ModalBottomSheet(
+                    sheetState = sheetState,
+                    onDismissRequest = { showBottomSheet = false },
+                    windowInsets = windowInsets
+                ) {
+                    Box(
+                        Modifier
+                            .size(sheetHeight)
+                            .testTag(sheetTag)
+                    )
+                }
+            }
+        }
+
+        assertThat(sheetState.isVisible).isTrue()
+
+        // Swipe Down
+        rule.onNodeWithTag(sheetTag).performTouchInput {
+            swipeDown()
+        }
+        rule.waitForIdle()
+
+        // Bottom sheet should not exist
+        rule.onNodeWithTag(sheetTag).assertDoesNotExist()
+    }
+
+    @Test
     fun modalBottomSheet_fillsScreenWidth() {
         var boxWidth = 0
         var screenWidth by mutableStateOf(0)
diff --git a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/SliderScreenshotTest.kt b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/SliderScreenshotTest.kt
index 36514dd..883e39b 100644
--- a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/SliderScreenshotTest.kt
+++ b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/SliderScreenshotTest.kt
@@ -216,8 +216,8 @@
         assertSliderAgainstGolden("slider_customColors_disabled")
     }
 
+    @OptIn(ExperimentalMaterial3Api::class)
     @Test
-    @ExperimentalMaterial3Api
     fun rangeSliderTest_middle_steps_disabled() {
         rule.setMaterialContent(lightColorScheme()) {
             Box(wrap.testTag(wrapperTestTag)) {
@@ -232,8 +232,8 @@
         assertSliderAgainstGolden("rangeSlider_middle_steps_disabled")
     }
 
+    @OptIn(ExperimentalMaterial3Api::class)
     @Test
-    @ExperimentalMaterial3Api
     fun rangeSliderTest_middle_steps_enabled() {
         rule.setMaterialContent(lightColorScheme()) {
             Box(wrap.testTag(wrapperTestTag)) {
@@ -251,8 +251,8 @@
         assertSliderAgainstGolden("rangeSlider_middle_steps_enabled")
     }
 
+    @OptIn(ExperimentalMaterial3Api::class)
     @Test
-    @ExperimentalMaterial3Api
     fun rangeSliderTest_middle_steps_dark_enabled() {
         rule.setMaterialContent(darkColorScheme()) {
             Box(wrap.testTag(wrapperTestTag)) {
@@ -270,8 +270,8 @@
         assertSliderAgainstGolden("rangeSlider_middle_steps_dark_enabled")
     }
 
+    @OptIn(ExperimentalMaterial3Api::class)
     @Test
-    @ExperimentalMaterial3Api
     fun rangeSliderTest_middle_steps_dark_disabled() {
         rule.setMaterialContent(darkColorScheme()) {
             Box(wrap.testTag(wrapperTestTag)) {
@@ -286,8 +286,8 @@
         assertSliderAgainstGolden("rangeSlider_middle_steps_dark_disabled")
     }
 
+    @OptIn(ExperimentalMaterial3Api::class)
     @Test
-    @ExperimentalMaterial3Api
     fun rangeSliderTest_overlapingThumbs() {
         rule.setMaterialContent(lightColorScheme()) {
             Box(wrap.testTag(wrapperTestTag)) {
@@ -301,8 +301,8 @@
         assertSliderAgainstGolden("rangeSlider_overlapingThumbs")
     }
 
+    @OptIn(ExperimentalMaterial3Api::class)
     @Test
-    @ExperimentalMaterial3Api
     fun rangeSliderTest_fullRange() {
         rule.setMaterialContent(lightColorScheme()) {
             Box(wrap.testTag(wrapperTestTag)) {
@@ -316,8 +316,8 @@
         assertSliderAgainstGolden("rangeSlider_fullRange")
     }
 
+    @OptIn(ExperimentalMaterial3Api::class)
     @Test
-    @ExperimentalMaterial3Api
     fun rangeSliderTest_steps_customColors() {
         rule.setMaterialContent(lightColorScheme()) {
             Box(wrap.testTag(wrapperTestTag)) {
diff --git a/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/ModalBottomSheet.android.kt b/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/ModalBottomSheet.android.kt
index 85e41b3..771d739 100644
--- a/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/ModalBottomSheet.android.kt
+++ b/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/ModalBottomSheet.android.kt
@@ -28,6 +28,7 @@
 import androidx.compose.foundation.Canvas
 import androidx.compose.foundation.gestures.Orientation
 import androidx.compose.foundation.gestures.detectTapGestures
+import androidx.compose.foundation.gestures.draggable
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.BoxWithConstraints
 import androidx.compose.foundation.layout.Column
@@ -198,10 +199,12 @@
                             )
                         }
                     )
-                    .anchoredDraggable(
-                        state = sheetState.anchoredDraggableState,
+                    .draggable(
+                        state = sheetState.anchoredDraggableState.draggableState,
                         orientation = Orientation.Vertical,
-                        enabled = sheetState.isVisible
+                        enabled = sheetState.isVisible,
+                        startDragImmediately = sheetState.anchoredDraggableState.isAnimationRunning,
+                        onDragStopped = { settleToDismiss(it) }
                     )
                     .modalBottomSheetAnchors(
                         sheetState = sheetState,
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/AppBar.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/AppBar.kt
index cd79a42..7d8c9f6 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/AppBar.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/AppBar.kt
@@ -73,6 +73,7 @@
 import androidx.compose.ui.layout.AlignmentLine
 import androidx.compose.ui.layout.LastBaseline
 import androidx.compose.ui.layout.Layout
+import androidx.compose.ui.layout.layout
 import androidx.compose.ui.layout.layoutId
 import androidx.compose.ui.platform.LocalDensity
 import androidx.compose.ui.semantics.clearAndSetSemantics
@@ -391,6 +392,7 @@
  * @param contentPadding the padding applied to the content of this BottomAppBar
  * @param windowInsets a window insets that app bar will respect.
  */
+@OptIn(ExperimentalMaterial3Api::class)
 @Composable
 fun BottomAppBar(
     actions: @Composable RowScope.() -> Unit,
@@ -402,12 +404,76 @@
     contentPadding: PaddingValues = BottomAppBarDefaults.ContentPadding,
     windowInsets: WindowInsets = BottomAppBarDefaults.windowInsets,
 ) = BottomAppBar(
+    actions = actions,
+    modifier = modifier,
+    floatingActionButton = floatingActionButton,
+    containerColor = containerColor,
+    contentColor = contentColor,
+    tonalElevation = tonalElevation,
+    contentPadding = contentPadding,
+    windowInsets = windowInsets,
+    scrollBehavior = null
+)
+
+/**
+ * <a href="https://m3.material.io/components/bottom-app-bar/overview" class="external" target="_blank">Material Design bottom app bar</a>.
+ *
+ * A bottom app bar displays navigation and key actions at the bottom of mobile screens.
+ *
+ * ![Bottom app bar image](https://developer.android.com/images/reference/androidx/compose/material3/bottom-app-bar.png)
+ *
+ * @sample androidx.compose.material3.samples.SimpleBottomAppBar
+ *
+ * It can optionally display a [FloatingActionButton] embedded at the end of the BottomAppBar.
+ *
+ * @sample androidx.compose.material3.samples.BottomAppBarWithFAB
+ *
+ * A bottom app bar that uses a [scrollBehavior] to customize its nested scrolling behavior when
+ * working in conjunction with a scrolling content looks like:
+ *
+ * @sample androidx.compose.material3.samples.ExitAlwaysBottomAppBar
+ *
+ * Also see [NavigationBar].
+ *
+ * @param actions the icon content of this BottomAppBar. The default layout here is a [Row],
+ * so content inside will be placed horizontally.
+ * @param modifier the [Modifier] to be applied to this BottomAppBar
+ * @param floatingActionButton optional floating action button at the end of this BottomAppBar
+ * @param containerColor the color used for the background of this BottomAppBar. Use
+ * [Color.Transparent] to have no color.
+ * @param contentColor the preferred color for content inside this BottomAppBar. Defaults to either
+ * the matching content color for [containerColor], or to the current [LocalContentColor] if
+ * [containerColor] is not a color from the theme.
+ * @param tonalElevation when [containerColor] is [ColorScheme.surface], a translucent primary color
+ * overlay is applied on top of the container. A higher tonal elevation value will result in a
+ * darker color in light theme and lighter color in dark theme. See also: [Surface].
+ * @param contentPadding the padding applied to the content of this BottomAppBar
+ * @param windowInsets a window insets that app bar will respect.
+ * @param scrollBehavior a [BottomAppBarScrollBehavior] which holds various offset values that will
+ * be applied by this bottom app bar to set up its height. A scroll behavior is designed to
+ * work in conjunction with a scrolled content to change the bottom app bar appearance as the
+ * content scrolls. See [BottomAppBarScrollBehavior.nestedScrollConnection].
+ */
+@ExperimentalMaterial3Api
+@Composable
+fun BottomAppBar(
+    actions: @Composable RowScope.() -> Unit,
+    modifier: Modifier = Modifier,
+    floatingActionButton: @Composable (() -> Unit)? = null,
+    containerColor: Color = BottomAppBarDefaults.containerColor,
+    contentColor: Color = contentColorFor(containerColor),
+    tonalElevation: Dp = BottomAppBarDefaults.ContainerElevation,
+    contentPadding: PaddingValues = BottomAppBarDefaults.ContentPadding,
+    windowInsets: WindowInsets = BottomAppBarDefaults.windowInsets,
+    scrollBehavior: BottomAppBarScrollBehavior? = null,
+) = BottomAppBar(
     modifier = modifier,
     containerColor = containerColor,
     contentColor = contentColor,
     tonalElevation = tonalElevation,
     windowInsets = windowInsets,
-    contentPadding = contentPadding
+    contentPadding = contentPadding,
+    scrollBehavior = scrollBehavior
 ) {
     Row(
         modifier = Modifier.weight(1f),
@@ -455,6 +521,7 @@
  * @param content the content of this BottomAppBar. The default layout here is a [Row],
  * so content inside will be placed horizontally.
  */
+@OptIn(ExperimentalMaterial3Api::class)
 @Composable
 fun BottomAppBar(
     modifier: Modifier = Modifier,
@@ -464,7 +531,81 @@
     contentPadding: PaddingValues = BottomAppBarDefaults.ContentPadding,
     windowInsets: WindowInsets = BottomAppBarDefaults.windowInsets,
     content: @Composable RowScope.() -> Unit
+) = BottomAppBar(
+    modifier = modifier,
+    containerColor = containerColor,
+    contentColor = contentColor,
+    tonalElevation = tonalElevation,
+    contentPadding = contentPadding,
+    windowInsets = windowInsets,
+    scrollBehavior = null,
+    content = content
+)
+
+/**
+ * <a href="https://m3.material.io/components/bottom-app-bar/overview" class="external" target="_blank">Material Design bottom app bar</a>.
+ *
+ * A bottom app bar displays navigation and key actions at the bottom of mobile screens.
+ *
+ * ![Bottom app bar image](https://developer.android.com/images/reference/androidx/compose/material3/bottom-app-bar.png)
+ *
+ * If you are interested in displaying a [FloatingActionButton], consider using another overload.
+ *
+ * Also see [NavigationBar].
+ *
+ * @param modifier the [Modifier] to be applied to this BottomAppBar
+ * @param containerColor the color used for the background of this BottomAppBar. Use
+ * [Color.Transparent] to have no color.
+ * @param contentColor the preferred color for content inside this BottomAppBar. Defaults to either
+ * the matching content color for [containerColor], or to the current [LocalContentColor] if
+ * [containerColor] is not a color from the theme.
+ * @param tonalElevation when [containerColor] is [ColorScheme.surface], a translucent primary color
+ * overlay is applied on top of the container. A higher tonal elevation value will result in a
+ * darker color in light theme and lighter color in dark theme. See also: [Surface].
+ * @param contentPadding the padding applied to the content of this BottomAppBar
+ * @param windowInsets a window insets that app bar will respect.
+ * @param scrollBehavior a [BottomAppBarScrollBehavior] which holds various offset values that will
+ * be applied by this bottom app bar to set up its height. A scroll behavior is designed to
+ * work in conjunction with a scrolled content to change the bottom app bar appearance as the
+ * content scrolls. See [BottomAppBarScrollBehavior.nestedScrollConnection].
+ * @param content the content of this BottomAppBar. The default layout here is a [Row],
+ * so content inside will be placed horizontally.
+ */
+@ExperimentalMaterial3Api
+@Composable
+fun BottomAppBar(
+    modifier: Modifier = Modifier,
+    containerColor: Color = BottomAppBarDefaults.containerColor,
+    contentColor: Color = contentColorFor(containerColor),
+    tonalElevation: Dp = BottomAppBarDefaults.ContainerElevation,
+    contentPadding: PaddingValues = BottomAppBarDefaults.ContentPadding,
+    windowInsets: WindowInsets = BottomAppBarDefaults.windowInsets,
+    scrollBehavior: BottomAppBarScrollBehavior? = null,
+    content: @Composable RowScope.() -> Unit
 ) {
+    // Set up support for resizing the bottom app bar when vertically dragging the bar itself.
+    val appBarDragModifier = if (scrollBehavior != null && !scrollBehavior.isPinned) {
+        Modifier.draggable(
+            orientation = Orientation.Vertical,
+            state = rememberDraggableState { delta ->
+                scrollBehavior.state.heightOffset -= delta
+            },
+            onDragStopped = { velocity ->
+                settleAppBarBottom(
+                    scrollBehavior.state,
+                    velocity,
+                    scrollBehavior.flingAnimationSpec,
+                    scrollBehavior.snapAnimationSpec
+                )
+            }
+        )
+    } else {
+        Modifier
+    }
+
+    // Compose a Surface with a Row content.
+    // The height of the app bar is determined by subtracting the bar's height offset from the
+    // app bar's defined constant height value (i.e. the ContainerHeight token).
     Surface(
         color = containerColor,
         contentColor = contentColor,
@@ -472,6 +613,19 @@
         // TODO(b/209583788): Consider adding a shape parameter if updated design guidance allows
         shape = BottomAppBarTokens.ContainerShape.value,
         modifier = modifier
+            .layout { measurable, constraints ->
+                // Sets the app bar's height offset to collapse the entire bar's height when content
+                // is scrolled.
+                scrollBehavior?.state?.heightOffsetLimit =
+                    -BottomAppBarTokens.ContainerHeight.toPx()
+
+                val placeable = measurable.measure(constraints)
+                val height = placeable.height + (scrollBehavior?.state?.heightOffset ?: 0f)
+                layout(placeable.width, height.roundToInt()) {
+                    placeable.place(0, 0)
+                }
+            }
+            .then(appBarDragModifier)
     ) {
         Row(
             Modifier
@@ -979,6 +1133,50 @@
     }
 }
 
+/**
+ * A BottomAppBarScrollBehavior defines how a bottom app bar should behave when the content under
+ * it is scrolled.
+ *
+ * @see [BottomAppBarDefaults.exitAlwaysScrollBehavior]
+ */
+@ExperimentalMaterial3Api
+@Stable
+interface BottomAppBarScrollBehavior {
+
+    /**
+     * A [BottomAppBarState] that is attached to this behavior and is read and updated when
+     * scrolling happens.
+     */
+    val state: BottomAppBarState
+
+    /**
+     * Indicates whether the bottom app bar is pinned.
+     *
+     * A pinned app bar will stay fixed in place when content is scrolled and will not react to any
+     * drag gestures.
+     */
+    val isPinned: Boolean
+
+    /**
+     * An optional [AnimationSpec] that defines how the bottom app bar snaps to either fully
+     * collapsed or fully extended state when a fling or a drag scrolled it into an intermediate
+     * position.
+     */
+    val snapAnimationSpec: AnimationSpec<Float>?
+
+    /**
+     * An optional [DecayAnimationSpec] that defined how to fling the bottom app bar when the user
+     * flings the app bar itself, or the content below it.
+     */
+    val flingAnimationSpec: DecayAnimationSpec<Float>?
+
+    /**
+     * A [NestedScrollConnection] that should be attached to a [Modifier.nestedScroll] in order to
+     * keep track of the scroll events.
+     */
+    val nestedScrollConnection: NestedScrollConnection
+}
+
 /** Contains default values used for the bottom app bar implementations. */
 object BottomAppBarDefaults {
 
@@ -1012,6 +1210,287 @@
     val bottomAppBarFabColor: Color
         @Composable get() =
             FabSecondaryTokens.ContainerColor.value
+
+    /**
+     * Returns a [BottomAppBarScrollBehavior]. A bottom app bar that is set up with this
+     * [BottomAppBarScrollBehavior] will immediately collapse when the content is pulled up, and
+     * will immediately appear when the content is pulled down.
+     *
+     * @param state the state object to be used to control or observe the bottom app bar's scroll
+     * state. See [rememberBottomAppBarState] for a state that is remembered across compositions.
+     * @param canScroll a callback used to determine whether scroll events are to be
+     * handled by this [ExitAlwaysScrollBehavior]
+     * @param snapAnimationSpec an optional [AnimationSpec] that defines how the bottom app bar
+     * snaps to either fully collapsed or fully extended state when a fling or a drag scrolled it
+     * into an intermediate position
+     * @param flingAnimationSpec an optional [DecayAnimationSpec] that defined how to fling the
+     * bottom app bar when the user flings the app bar itself, or the content below it
+     */
+    @ExperimentalMaterial3Api
+    @Composable
+    fun exitAlwaysScrollBehavior(
+        state: BottomAppBarState = rememberBottomAppBarState(),
+        canScroll: () -> Boolean = { true },
+        snapAnimationSpec: AnimationSpec<Float>? = spring(stiffness = Spring.StiffnessMediumLow),
+        flingAnimationSpec: DecayAnimationSpec<Float>? = rememberSplineBasedDecay()
+    ): BottomAppBarScrollBehavior =
+        ExitAlwaysScrollBehavior(
+            state = state,
+            snapAnimationSpec = snapAnimationSpec,
+            flingAnimationSpec = flingAnimationSpec,
+            canScroll = canScroll
+        )
+}
+
+/**
+ * Creates a [BottomAppBarState] that is remembered across compositions.
+ *
+ * @param initialHeightOffsetLimit the initial value for [BottomAppBarState.heightOffsetLimit],
+ * which represents the pixel limit that a bottom app bar is allowed to collapse when the scrollable
+ * content is scrolled
+ * @param initialHeightOffset the initial value for [BottomAppBarState.heightOffset]. The initial
+ * offset height offset should be between zero and [initialHeightOffsetLimit].
+ * @param initialContentOffset the initial value for [BottomAppBarState.contentOffset]
+ */
+@ExperimentalMaterial3Api
+@Composable
+fun rememberBottomAppBarState(
+    initialHeightOffsetLimit: Float = -Float.MAX_VALUE,
+    initialHeightOffset: Float = 0f,
+    initialContentOffset: Float = 0f
+): BottomAppBarState {
+    return rememberSaveable(saver = BottomAppBarState.Saver) {
+        BottomAppBarState(
+            initialHeightOffsetLimit,
+            initialHeightOffset,
+            initialContentOffset
+        )
+    }
+}
+
+/**
+ * A state object that can be hoisted to control and observe the bottom app bar state. The state is
+ * read and updated by a [BottomAppBarScrollBehavior] implementation.
+ *
+ * In most cases, this state will be created via [rememberBottomAppBarState].
+ */
+@ExperimentalMaterial3Api
+interface BottomAppBarState {
+
+    /**
+     * The bottom app bar's height offset limit in pixels, which represents the limit that a bottom
+     * app bar is allowed to collapse to.
+     *
+     * Use this limit to coerce the [heightOffset] value when it's updated.
+     */
+    var heightOffsetLimit: Float
+
+    /**
+     * The bottom app bar's current height offset in pixels. This height offset is applied to the
+     * fixed height of the app bar to control the displayed height when content is being scrolled.
+     *
+     * Updates to the [heightOffset] value are coerced between zero and [heightOffsetLimit].
+     */
+    var heightOffset: Float
+
+    /**
+     * The total offset of the content scrolled under the bottom app bar.
+     *
+     * This value is updated by a [BottomAppBarScrollBehavior] whenever a nested scroll connection
+     * consumes scroll events. A common implementation would update the value to be the sum of all
+     * [NestedScrollConnection.onPostScroll] `consumed.y` values.
+     */
+    var contentOffset: Float
+
+    /**
+     * A value that represents the collapsed height percentage of the app bar.
+     *
+     * A `0.0` represents a fully expanded bar, and `1.0` represents a fully collapsed bar (computed
+     * as [heightOffset] / [heightOffsetLimit]).
+     */
+    val collapsedFraction: Float
+
+    companion object {
+        /**
+         * The default [Saver] implementation for [BottomAppBarState].
+         */
+        val Saver: Saver<BottomAppBarState, *> = listSaver(
+            save = { listOf(it.heightOffsetLimit, it.heightOffset, it.contentOffset) },
+            restore = {
+                BottomAppBarState(
+                    initialHeightOffsetLimit = it[0],
+                    initialHeightOffset = it[1],
+                    initialContentOffset = it[2]
+                )
+            }
+        )
+    }
+}
+
+/**
+ * Creates a [BottomAppBarState].
+ *
+ * @param initialHeightOffsetLimit the initial value for [BottomAppBarState.heightOffsetLimit],
+ * which represents the pixel limit that a bottom app bar is allowed to collapse when the scrollable
+ * content is scrolled
+ * @param initialHeightOffset the initial value for [BottomAppBarState.heightOffset]. The initial
+ * offset height offset should be between zero and [initialHeightOffsetLimit].
+ * @param initialContentOffset the initial value for [BottomAppBarState.contentOffset]
+ */
+@ExperimentalMaterial3Api
+fun BottomAppBarState(
+    initialHeightOffsetLimit: Float,
+    initialHeightOffset: Float,
+    initialContentOffset: Float
+): BottomAppBarState = BottomAppBarStateImpl(
+    initialHeightOffsetLimit,
+    initialHeightOffset,
+    initialContentOffset
+)
+
+@ExperimentalMaterial3Api
+@Stable
+private class BottomAppBarStateImpl(
+    initialHeightOffsetLimit: Float,
+    initialHeightOffset: Float,
+    initialContentOffset: Float
+) : BottomAppBarState {
+
+    override var heightOffsetLimit by mutableFloatStateOf(initialHeightOffsetLimit)
+
+    override var heightOffset: Float
+        get() = _heightOffset.floatValue
+        set(newOffset) {
+            _heightOffset.floatValue = newOffset.coerceIn(
+                minimumValue = heightOffsetLimit,
+                maximumValue = 0f
+            )
+        }
+
+    override var contentOffset by mutableFloatStateOf(initialContentOffset)
+
+    override val collapsedFraction: Float
+        get() = if (heightOffsetLimit != 0f) {
+            heightOffset / heightOffsetLimit
+        } else {
+            0f
+        }
+
+    private var _heightOffset = mutableFloatStateOf(initialHeightOffset)
+}
+
+/**
+ * A [BottomAppBarScrollBehavior] that adjusts its properties to affect the colors and height of a
+ * bottom app bar.
+ *
+ * A bottom app bar that is set up with this [BottomAppBarScrollBehavior] will immediately collapse
+ * when the nested content is pulled up, and will immediately appear when the content is pulled
+ * down.
+ *
+ * @param state a [BottomAppBarState]
+ * @param snapAnimationSpec an optional [AnimationSpec] that defines how the bottom app bar snaps to
+ * either fully collapsed or fully extended state when a fling or a drag scrolled it into an
+ * intermediate position
+ * @param flingAnimationSpec an optional [DecayAnimationSpec] that defined how to fling the bottom
+ * app bar when the user flings the app bar itself, or the content below it
+ * @param canScroll a callback used to determine whether scroll events are to be
+ * handled by this [ExitAlwaysScrollBehavior]
+ */
+@ExperimentalMaterial3Api
+private class ExitAlwaysScrollBehavior(
+    override val state: BottomAppBarState,
+    override val snapAnimationSpec: AnimationSpec<Float>?,
+    override val flingAnimationSpec: DecayAnimationSpec<Float>?,
+    val canScroll: () -> Boolean = { true }
+) : BottomAppBarScrollBehavior {
+    override val isPinned: Boolean = false
+    override var nestedScrollConnection =
+        object : NestedScrollConnection {
+            override fun onPostScroll(
+                consumed: Offset,
+                available: Offset,
+                source: NestedScrollSource
+            ): Offset {
+                if (!canScroll()) return Offset.Zero
+                state.contentOffset += consumed.y
+                if (state.heightOffset == 0f || state.heightOffset == state.heightOffsetLimit) {
+                    if (consumed.y == 0f && available.y > 0f) {
+                        // Reset the total content offset to zero when scrolling all the way down.
+                        // This will eliminate some float precision inaccuracies.
+                        state.contentOffset = 0f
+                    }
+                }
+                state.heightOffset = state.heightOffset + consumed.y
+                return Offset.Zero
+            }
+
+            override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity {
+                val superConsumed = super.onPostFling(consumed, available)
+                return superConsumed + settleAppBarBottom(
+                    state,
+                    available.y,
+                    flingAnimationSpec,
+                    snapAnimationSpec
+                )
+            }
+        }
+}
+
+/**
+ * Settles the app bar by flinging, in case the given velocity is greater than zero, and snapping
+ * after the fling settles.
+ */
+@ExperimentalMaterial3Api
+private suspend fun settleAppBarBottom(
+    state: BottomAppBarState,
+    velocity: Float,
+    flingAnimationSpec: DecayAnimationSpec<Float>?,
+    snapAnimationSpec: AnimationSpec<Float>?
+): Velocity {
+    // Check if the app bar is completely collapsed/expanded. If so, no need to settle the app bar,
+    // and just return Zero Velocity.
+    // Note that we don't check for 0f due to float precision with the collapsedFraction
+    // calculation.
+    if (state.collapsedFraction < 0.01f || state.collapsedFraction == 1f) {
+        return Velocity.Zero
+    }
+    var remainingVelocity = velocity
+    // In case there is an initial velocity that was left after a previous user fling, animate to
+    // continue the motion to expand or collapse the app bar.
+    if (flingAnimationSpec != null && abs(velocity) > 1f) {
+        var lastValue = 0f
+        AnimationState(
+            initialValue = 0f,
+            initialVelocity = velocity,
+        )
+            .animateDecay(flingAnimationSpec) {
+                val delta = value - lastValue
+                val initialHeightOffset = state.heightOffset
+                state.heightOffset = initialHeightOffset + delta
+                val consumed = abs(initialHeightOffset - state.heightOffset)
+                lastValue = value
+                remainingVelocity = this.velocity
+                // avoid rounding errors and stop if anything is unconsumed
+                if (abs(delta - consumed) > 0.5f) this.cancelAnimation()
+            }
+    }
+    // Snap if animation specs were provided.
+    if (snapAnimationSpec != null) {
+        if (state.heightOffset < 0 &&
+            state.heightOffset > state.heightOffsetLimit
+        ) {
+            AnimationState(initialValue = state.heightOffset).animateTo(
+                if (state.collapsedFraction < 0.5f) {
+                    0f
+                } else {
+                    state.heightOffsetLimit
+                },
+                animationSpec = snapAnimationSpec
+            ) { state.heightOffset = value }
+        }
+    }
+
+    return Velocity(0f, remainingVelocity)
 }
 
 // Padding minus IconButton's min touch target expansion
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Label.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Label.kt
new file mode 100644
index 0000000..1aedef2
--- /dev/null
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Label.kt
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2023 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.BasicTooltipBox
+import androidx.compose.foundation.BasicTooltipState
+import androidx.compose.foundation.MutatePriority
+import androidx.compose.foundation.MutatorMutex
+import androidx.compose.foundation.interaction.DragInteraction
+import androidx.compose.foundation.interaction.HoverInteraction
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.interaction.PressInteraction
+import androidx.compose.foundation.rememberBasicTooltipState
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import kotlinx.coroutines.flow.collectLatest
+
+/**
+ * Label component that will append a [label] to [content].
+ * The positioning logic uses [TooltipDefaults.rememberPlainTooltipPositionProvider].
+ *
+ * Label appended to thumbs of Slider:
+ *
+ * @sample androidx.compose.material3.samples.SliderWithCustomThumbSample
+ *
+ * Label appended to thumbs of RangeSlider:
+ *
+ * @sample androidx.compose.material3.samples.RangeSliderWithCustomComponents
+ *
+ * @param label composable that will be appended to [content]
+ * @param modifier [Modifier] that will be applied to [content]
+ * @param interactionSource the [MutableInteractionSource] representing the
+ * stream of [Interaction]s for the [content].
+ * @param isPersistent boolean to determine if the label should be persistent.
+ * If true, then the label will always show and be anchored to [content].
+ * if false, then the label will only show when pressing down or hovering over the [content].
+ * @param content the composable that [label] will anchor to.
+ */
+@ExperimentalMaterial3Api
+@Composable
+fun Label(
+    label: @Composable () -> Unit,
+    modifier: Modifier = Modifier,
+    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
+    isPersistent: Boolean = false,
+    content: @Composable () -> Unit
+) {
+    // Has the same positioning logic as PlainTooltips
+    val positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider()
+    val state = if (isPersistent)
+        remember { LabelStateImpl() }
+    else
+        rememberBasicTooltipState(mutatorMutex = MutatorMutex())
+    BasicTooltipBox(
+        positionProvider = positionProvider,
+        tooltip = label,
+        state = state,
+        modifier = modifier,
+        focusable = false,
+        enableUserInput = false,
+        content = content
+    )
+    HandleInteractions(
+        enabled = !isPersistent,
+        state = state,
+        interactionSource = interactionSource
+    )
+}
+
+@Composable
+private fun HandleInteractions(
+    enabled: Boolean,
+    state: BasicTooltipState,
+    interactionSource: MutableInteractionSource
+) {
+    if (enabled) {
+        LaunchedEffect(interactionSource) {
+            interactionSource.interactions.collectLatest { interaction ->
+                when (interaction) {
+                    is PressInteraction.Press,
+                    is DragInteraction.Start,
+                    is HoverInteraction.Enter -> { state.show(MutatePriority.UserInput) }
+                    is PressInteraction.Release,
+                    is DragInteraction.Stop,
+                    is HoverInteraction.Exit -> { state.dismiss() }
+                }
+            }
+        }
+    }
+}
+
+private class LabelStateImpl(
+    override val isVisible: Boolean = true,
+    override val isPersistent: Boolean = true
+) : BasicTooltipState {
+    override suspend fun show(mutatePriority: MutatePriority) {}
+
+    override fun dismiss() {}
+
+    override fun onDispose() {}
+}
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Scaffold.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Scaffold.kt
index b346d44..fea69f4 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Scaffold.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Scaffold.kt
@@ -197,7 +197,7 @@
                         layoutWidth - FabSpacing.roundToPx() - fabWidth
                     }
                 }
-                FabPosition.End -> {
+                FabPosition.End, FabPosition.EndOverlay -> {
                     if (layoutDirection == LayoutDirection.Ltr) {
                         layoutWidth - FabSpacing.roundToPx() - fabWidth
                     } else {
@@ -225,7 +225,7 @@
 
         val bottomBarHeight = bottomBarPlaceables.fastMaxBy { it.height }?.height
         val fabOffsetFromBottom = fabPlacement?.let {
-            if (bottomBarHeight == null) {
+            if (bottomBarHeight == null || fabPosition == FabPosition.EndOverlay) {
                 it.height + FabSpacing.roundToPx() +
                     contentWindowInsets.getBottom(this@SubcomposeLayout)
             } else {
@@ -329,13 +329,20 @@
          * exists)
          */
         val End = FabPosition(2)
+
+        /**
+         * Position FAB at the bottom of the screen at the end, overlaying the [NavigationBar] (if
+         * it exists)
+         */
+        val EndOverlay = FabPosition(3)
     }
 
     override fun toString(): String {
         return when (this) {
             Start -> "FabPosition.Start"
             Center -> "FabPosition.Center"
-            else -> "FabPosition.End"
+            End -> "FabPosition.End"
+            else -> "FabPosition.EndOverlay"
         }
     }
 }
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Tooltip.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Tooltip.kt
index 67bdfb5..21e04e7 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Tooltip.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Tooltip.kt
@@ -89,7 +89,7 @@
  * relative to the anchor content.
  * @param tooltip the composable that will be used to populate the tooltip's content.
  * @param state handles the state of the tooltip's visibility.
- * @param modifier the [Modifier] to be applied to the tooltip.
+ * @param modifier the [Modifier] to be applied to the TooltipBox.
  * @param focusable [Boolean] that determines if the tooltip is focusable. When true,
  * the tooltip will consume touch events while it's shown and will have accessibility
  * focus move to the first element of the component. When false, the tooltip
@@ -142,16 +142,16 @@
     content: @Composable () -> Unit
 ) {
     Surface(
-        modifier = modifier
+        shape = shape,
+        color = containerColor
+    ) {
+        Box(modifier = modifier
             .sizeIn(
                 minWidth = TooltipMinWidth,
                 maxWidth = PlainTooltipMaxWidth,
                 minHeight = TooltipMinHeight
-            ),
-        shape = shape,
-        color = containerColor
-    ) {
-        Box(modifier = Modifier.padding(PlainTooltipContentPadding)) {
+            ).padding(PlainTooltipContentPadding)
+        ) {
             val textStyle =
                 MaterialTheme.typography.fromToken(PlainTooltipTokens.SupportingTextFont)
             CompositionLocalProvider(
diff --git a/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/CompositionTests.kt b/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/CompositionTests.kt
index 8f8615b..d93db8a 100644
--- a/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/CompositionTests.kt
+++ b/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/CompositionTests.kt
@@ -3424,13 +3424,17 @@
     @Test // regression test for 264467571
     fun test_returnConditionally_fromNodeLambda_local_initial_return() = compositionTest {
         var condition by mutableStateOf(true)
+
         compose {
+            currentComposer.disableSourceInformation()
             Text("Before outer")
             InlineLinear {
                 Text("Before inner")
                 InlineLinear inner@{
                     Text("Before return")
-                    if (condition) return@inner
+                    if (condition) {
+                        return@inner
+                    }
                     Text("After return")
                 }
                 Text("After inner")
@@ -3463,6 +3467,7 @@
     fun test_returnConditionally_fromNodeLambda_local_initial_no_return() = compositionTest {
         var condition by mutableStateOf(true)
         compose {
+            currentComposer.disableSourceInformation()
             Text("Before outer")
             InlineLinear {
                 Text("Before inner")
@@ -3501,6 +3506,7 @@
     fun test_returnConditionally_fromNodeLambda_nonLocal_initial_return() = compositionTest {
         var condition by mutableStateOf(true)
         compose {
+            currentComposer.disableSourceInformation()
             Text("Before outer")
             InlineLinear outer@{
                 Text("Before inner")
@@ -3539,6 +3545,7 @@
     fun test_returnConditionally_fromNodeLambda_nonLocal_initial_no_return() = compositionTest {
         var condition by mutableStateOf(true)
         compose {
+            currentComposer.disableSourceInformation()
             Text("Before outer")
             InlineLinear outer@{
                 Text("Before inner")
@@ -3578,6 +3585,7 @@
         compositionTest {
             var condition by mutableStateOf(true)
             compose {
+                currentComposer.disableSourceInformation()
                 Text("Before outer")
                 InlineLinear outer@{
                     Text("Before inner")
diff --git a/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/inspector/LayoutInspectorTree.kt b/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/inspector/LayoutInspectorTree.kt
index 8ba40fa..a36e3d6 100644
--- a/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/inspector/LayoutInspectorTree.kt
+++ b/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/inspector/LayoutInspectorTree.kt
@@ -502,23 +502,26 @@
         val box = context.bounds
         val size = box.size.toSize()
         val coordinates = layoutInfo.coordinates
-        val topLeft = toIntOffset(coordinates.localToWindow(Offset.Zero))
-        val topRight = toIntOffset(coordinates.localToWindow(Offset(size.width, 0f)))
-        val bottomRight = toIntOffset(coordinates.localToWindow(Offset(size.width, size.height)))
-        val bottomLeft = toIntOffset(coordinates.localToWindow(Offset(0f, size.height)))
         var bounds: QuadBounds? = null
+        if (layoutInfo.isAttached) {
+            val topLeft = toIntOffset(coordinates.localToWindow(Offset.Zero))
+            val topRight = toIntOffset(coordinates.localToWindow(Offset(size.width, 0f)))
+            val bottomRight =
+                toIntOffset(coordinates.localToWindow(Offset(size.width, size.height)))
+            val bottomLeft = toIntOffset(coordinates.localToWindow(Offset(0f, size.height)))
 
-        if (topLeft.x != box.left || topLeft.y != box.top ||
-            topRight.x != box.right || topRight.y != box.top ||
-            bottomRight.x != box.right || bottomRight.y != box.bottom ||
-            bottomLeft.x != box.left || bottomLeft.y != box.bottom
-        ) {
-            bounds = QuadBounds(
-                topLeft.x, topLeft.y,
-                topRight.x, topRight.y,
-                bottomRight.x, bottomRight.y,
-                bottomLeft.x, bottomLeft.y,
-            )
+            if (topLeft.x != box.left || topLeft.y != box.top ||
+                topRight.x != box.right || topRight.y != box.top ||
+                bottomRight.x != box.right || bottomRight.y != box.bottom ||
+                bottomLeft.x != box.left || bottomLeft.y != box.bottom
+            ) {
+                bounds = QuadBounds(
+                    topLeft.x, topLeft.y,
+                    topRight.x, topRight.y,
+                    bottomRight.x, bottomRight.y,
+                    bottomLeft.x, bottomLeft.y,
+                )
+            }
         }
         if (!includeNodesOutsizeOfWindow) {
             // Ignore this node if the bounds are completely outside the window
diff --git a/compose/ui/ui-text/benchmark/src/androidTest/java/androidx/compose/ui/text/benchmark/HyphensLineBreakBenchmark.kt b/compose/ui/ui-text/benchmark/src/androidTest/java/androidx/compose/ui/text/benchmark/HyphensLineBreakBenchmark.kt
deleted file mode 100644
index 72f0dbc..0000000
--- a/compose/ui/ui-text/benchmark/src/androidTest/java/androidx/compose/ui/text/benchmark/HyphensLineBreakBenchmark.kt
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Copyright 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.compose.ui.text.benchmark
-
-import android.graphics.Bitmap
-import android.graphics.Canvas
-import android.graphics.text.LineBreakConfig
-import android.graphics.text.LineBreaker
-import android.os.Build
-import android.text.Layout
-import android.text.TextPaint
-import androidx.benchmark.junit4.BenchmarkRule
-import androidx.benchmark.junit4.measureRepeated
-import androidx.compose.ui.text.android.InternalPlatformTextApi
-import androidx.compose.ui.text.android.StaticLayoutFactory
-import androidx.compose.ui.text.style.Hyphens
-import androidx.compose.ui.text.style.LineBreak
-import androidx.test.filters.LargeTest
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.Parameterized
-
-@LargeTest
-@RunWith(Parameterized::class)
-@OptIn(InternalPlatformTextApi::class)
-class HyphensLineBreakBenchmark(
-    private val textLength: Int,
-    private val hyphensString: String,
-    private val lineBreakString: String
-) {
-    companion object {
-        @JvmStatic
-        @Parameterized.Parameters(name = "length={0} hyphens={1} lineBreak={2}")
-        fun initParameters(): List<Array<Any?>> {
-            return cartesian(
-                arrayOf(32, 128, 512),
-                arrayOf(
-                    Hyphens.None.toTestString(),
-                    Hyphens.Auto.toTestString()
-                ),
-                arrayOf(
-                    LineBreak.Paragraph.toTestString(),
-                    LineBreak.Simple.toTestString(),
-                    LineBreak.Heading.toTestString()
-                )
-            )
-        }
-    }
-
-    @get:Rule
-    val benchmarkRule = BenchmarkRule()
-
-    @get:Rule
-    val textBenchmarkRule = TextBenchmarkTestRule()
-
-    private val width = 100
-    private val textSize: Float = 10F
-    private val hyphenationFrequency = toLayoutHyphenationFrequency(hyphensString.toHyphens())
-    private val lineBreakStyle = toLayoutLineBreakStyle(lineBreakString.toLineBreak().strictness)
-    private val breakStrategy = toLayoutBreakStrategy(lineBreakString.toLineBreak().strategy)
-    private val lineBreakWordStyle =
-        toLayoutLineBreakWordStyle(lineBreakString.toLineBreak().wordBreak)
-
-    @Test
-    fun constructLayout() {
-        textBenchmarkRule.generator { textGenerator ->
-            val text = textGenerator.nextParagraph(textLength)
-            val textPaint = TextPaint()
-            textPaint.textSize = textSize
-            benchmarkRule.measureRepeated {
-                StaticLayoutFactory.create(
-                    text = text,
-                    width = width,
-                    paint = textPaint,
-                    hyphenationFrequency = hyphenationFrequency,
-                    lineBreakStyle = lineBreakStyle,
-                    breakStrategy = breakStrategy,
-                    lineBreakWordStyle = lineBreakWordStyle
-                )
-            }
-        }
-    }
-
-    @Test
-    fun constructLayoutDraw() {
-        textBenchmarkRule.generator { textGenerator ->
-            val text = textGenerator.nextParagraph(textLength)
-            val textPaint = TextPaint()
-            textPaint.textSize = textSize
-            val canvas = Canvas(Bitmap.createBitmap(width, 1000, Bitmap.Config.ARGB_8888))
-            benchmarkRule.measureRepeated {
-                val layout = StaticLayoutFactory.create(
-                    text = text,
-                    width = width,
-                    paint = textPaint,
-                    hyphenationFrequency = hyphenationFrequency,
-                    lineBreakStyle = lineBreakStyle,
-                    breakStrategy = breakStrategy,
-                    lineBreakWordStyle = lineBreakWordStyle
-                )
-                layout.draw(canvas)
-            }
-        }
-    }
-
-    private fun toLayoutHyphenationFrequency(hyphens: Hyphens?): Int = when (hyphens) {
-        Hyphens.Auto -> if (Build.VERSION.SDK_INT <= 32) {
-            Layout.HYPHENATION_FREQUENCY_NORMAL
-        } else {
-            Layout.HYPHENATION_FREQUENCY_NORMAL_FAST
-        }
-        Hyphens.None -> Layout.HYPHENATION_FREQUENCY_NONE
-        else -> Layout.HYPHENATION_FREQUENCY_NONE
-    }
-
-    private fun toLayoutBreakStrategy(breakStrategy: LineBreak.Strategy?): Int =
-        when (breakStrategy) {
-            LineBreak.Strategy.Simple -> LineBreaker.BREAK_STRATEGY_SIMPLE
-            LineBreak.Strategy.HighQuality -> LineBreaker.BREAK_STRATEGY_HIGH_QUALITY
-            LineBreak.Strategy.Balanced -> LineBreaker.BREAK_STRATEGY_BALANCED
-            else -> LineBreaker.BREAK_STRATEGY_SIMPLE
-        }
-
-    private fun toLayoutLineBreakStyle(lineBreakStrictness: LineBreak.Strictness?): Int =
-        when (lineBreakStrictness) {
-            LineBreak.Strictness.Default -> LineBreakConfig.LINE_BREAK_STYLE_NONE
-            LineBreak.Strictness.Loose -> LineBreakConfig.LINE_BREAK_STYLE_LOOSE
-            LineBreak.Strictness.Normal -> LineBreakConfig.LINE_BREAK_STYLE_NORMAL
-            LineBreak.Strictness.Strict -> LineBreakConfig.LINE_BREAK_STYLE_STRICT
-            else -> LineBreakConfig.LINE_BREAK_STYLE_NONE
-        }
-
-    private fun toLayoutLineBreakWordStyle(lineBreakWordStyle: LineBreak.WordBreak?): Int =
-        when (lineBreakWordStyle) {
-            LineBreak.WordBreak.Default -> LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE
-            LineBreak.WordBreak.Phrase -> LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE
-            else -> LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE
-        }
-}
-
-/**
- * Required to make this test work due to a bug with value classes and Parameterized JUnit tests.
- * https://youtrack.jetbrains.com/issue/KT-35523
- *
- * However, it's not enough to use a wrapper because wrapper makes the test name unnecessarily
- * long which causes Perfetto to be unable to create output files with a very long name in some
- * file systems.
- *
- * Using a String instead of an Integer gives us a better test naming.
- */
-private fun String.toLineBreak(): LineBreak = when (this) {
-    "Simple" -> LineBreak.Simple
-    "Heading" -> LineBreak.Heading
-    "Paragraph" -> LineBreak.Paragraph
-    else -> throw IllegalArgumentException("Unrecognized LineBreak value for this test")
-}
-
-private fun LineBreak.toTestString(): String = when (this) {
-    LineBreak.Simple -> "Simple"
-    LineBreak.Heading -> "Heading"
-    LineBreak.Paragraph -> "Paragraph"
-    else -> throw IllegalArgumentException("Unrecognized LineBreak value for this test")
-}
-
-private fun String.toHyphens(): Hyphens = when (this) {
-    "None" -> Hyphens.None
-    "Auto" -> Hyphens.Auto
-    else -> throw IllegalArgumentException("Unrecognized Hyphens value for this test")
-}
-
-private fun Hyphens.toTestString(): String = when (this) {
-    Hyphens.None -> "None"
-    Hyphens.Auto -> "Auto"
-    else -> throw IllegalArgumentException("Unrecognized Hyphens value for this test")
-}
diff --git a/compose/ui/ui/api/current.txt b/compose/ui/ui/api/current.txt
index 59a93d9..e5c14c2 100644
--- a/compose/ui/ui/api/current.txt
+++ b/compose/ui/ui/api/current.txt
@@ -609,7 +609,7 @@
   }
 
   public final class FocusRestorerKt {
-    method @SuppressCompatibility @androidx.compose.ui.ExperimentalComposeUiApi public static androidx.compose.ui.Modifier focusRestorer(androidx.compose.ui.Modifier);
+    method @SuppressCompatibility @androidx.compose.ui.ExperimentalComposeUiApi public static androidx.compose.ui.Modifier focusRestorer(androidx.compose.ui.Modifier, optional kotlin.jvm.functions.Function0<androidx.compose.ui.focus.FocusRequester>? onRestoreFailed);
   }
 
   public interface FocusState {
diff --git a/compose/ui/ui/api/restricted_current.txt b/compose/ui/ui/api/restricted_current.txt
index 7608ff3..71da5eb 100644
--- a/compose/ui/ui/api/restricted_current.txt
+++ b/compose/ui/ui/api/restricted_current.txt
@@ -609,7 +609,7 @@
   }
 
   public final class FocusRestorerKt {
-    method @SuppressCompatibility @androidx.compose.ui.ExperimentalComposeUiApi public static androidx.compose.ui.Modifier focusRestorer(androidx.compose.ui.Modifier);
+    method @SuppressCompatibility @androidx.compose.ui.ExperimentalComposeUiApi public static androidx.compose.ui.Modifier focusRestorer(androidx.compose.ui.Modifier, optional kotlin.jvm.functions.Function0<androidx.compose.ui.focus.FocusRequester>? onRestoreFailed);
   }
 
   public interface FocusState {
diff --git a/compose/ui/ui/integration-tests/ui-demos/src/main/java/androidx/compose/ui/demos/viewinterop/ViewInterop.kt b/compose/ui/ui/integration-tests/ui-demos/src/main/java/androidx/compose/ui/demos/viewinterop/ViewInterop.kt
index 2ea6de9..22effa7 100644
--- a/compose/ui/ui/integration-tests/ui-demos/src/main/java/androidx/compose/ui/demos/viewinterop/ViewInterop.kt
+++ b/compose/ui/ui/integration-tests/ui-demos/src/main/java/androidx/compose/ui/demos/viewinterop/ViewInterop.kt
@@ -16,16 +16,27 @@
 
 package androidx.compose.ui.demos.viewinterop
 
+import android.annotation.SuppressLint
 import android.content.Context
 import android.graphics.Canvas
 import android.graphics.Paint
 import android.graphics.Rect
+import android.os.Build
 import android.view.View
 import android.view.ViewGroup
+import android.widget.LinearLayout
 import android.widget.TextView
+import androidx.annotation.DoNotInline
+import androidx.annotation.RequiresApi
 import androidx.compose.foundation.background
 import androidx.compose.foundation.clickable
 import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.verticalScroll
 import androidx.compose.material.Button
 import androidx.compose.material.Text
 import androidx.compose.runtime.Composable
@@ -38,9 +49,11 @@
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.toArgb
 import androidx.compose.ui.node.Ref
+import androidx.compose.ui.unit.dp
 import androidx.compose.ui.viewinterop.AndroidView
 import androidx.compose.ui.viewinterop.AndroidViewBinding
 
+@SuppressLint("ResourceType")
 @Composable
 fun ViewInteropDemo() {
     Column {
@@ -85,6 +98,62 @@
         ) {
             Text("Change color of Android view")
         }
+
+        Column(modifier =
+            Modifier.fillMaxWidth().height(100.dp).verticalScroll(rememberScrollState())
+        ) {
+            AndroidView({ c ->
+                LinearLayout(c).apply {
+                    val text1 = TextView(c).apply { text = "LinearLayout child 1"; id = 11 }
+                    val text2 = TextView(c).apply { text = "LinearLayout child 2"; id = 22 }
+                    val text3 = TextView(c).apply { text = "LinearLayout child 3"; id = 33 }
+                    if (Build.VERSION.SDK_INT >= 26) {
+                        Api26Impl.setAccessibilityTraversalAfter(text3, text2.getId());
+                        Api26Impl.setAccessibilityTraversalAfter(text2, text1.getId());
+                    }
+                    addView(text3)
+                    addView(text2)
+                    addView(text1)
+                }
+            })
+        }
+
+        Spacer(Modifier.height(20.dp))
+
+        LazyColumn(
+            modifier = Modifier.fillMaxWidth().height(50.dp)
+        ) {
+            item {
+                AndroidView(::TextView) { it.text = "TextView in LazyColumn 1A" }
+                AndroidView(::TextView) { it.text = "TextView in LazyColumn 1B" }
+            }
+            item {
+                AndroidView(::TextView) { it.text = "TextView in LazyColumn 2A" }
+                AndroidView(::TextView) { it.text = "TextView in LazyColumn 2B" }
+            }
+            item {
+                AndroidView(::TextView) { it.text = "TextView in LazyColumn 3A" }
+                AndroidView(::TextView) { it.text = "TextView in LazyColumn 3B" }
+            }
+            item {
+                AndroidView(::TextView) { it.text = "TextView in LazyColumn 4A" }
+                AndroidView(::TextView) { it.text = "TextView in LazyColumn 4B" }
+            }
+        }
+        Spacer(Modifier.height(20.dp))
+        Column(
+            modifier = Modifier.fillMaxWidth().height(50.dp).verticalScroll(rememberScrollState())
+        ) {
+            AndroidView(::TextView) { it.text = "TextView in verticalScroll 1" }
+            AndroidView(::TextView) { it.text = "TextView in verticalScroll 2" }
+            AndroidView(::TextView) { it.text = "TextView in verticalScroll 3" }
+            AndroidView(::TextView) { it.text = "TextView in verticalScroll 4" }
+            AndroidView(::TextView) { it.text = "TextView in verticalScroll 5" }
+            AndroidView(::TextView) { it.text = "TextView in verticalScroll 6" }
+            AndroidView(::TextView) { it.text = "TextView in verticalScroll 7" }
+            AndroidView(::TextView) { it.text = "TextView in verticalScroll 8" }
+            AndroidView(::TextView) { it.text = "TextView in verticalScroll 9" }
+        }
     }
 }
 
@@ -120,3 +189,15 @@
         canvas.drawRect(rect, paint)
     }
 }
+
+@RequiresApi(Build.VERSION_CODES.O)
+private object Api26Impl {
+    @DoNotInline
+    @JvmStatic
+    fun setAccessibilityTraversalAfter(
+        view: View,
+        id: Int
+    ) {
+        view.setAccessibilityTraversalAfter(id);
+    }
+}
diff --git a/compose/ui/ui/samples/src/main/java/androidx/compose/ui/samples/FocusSamples.kt b/compose/ui/ui/samples/src/main/java/androidx/compose/ui/samples/FocusSamples.kt
index 69035e5..4041e63 100644
--- a/compose/ui/ui/samples/src/main/java/androidx/compose/ui/samples/FocusSamples.kt
+++ b/compose/ui/ui/samples/src/main/java/androidx/compose/ui/samples/FocusSamples.kt
@@ -134,6 +134,27 @@
     }
 }
 
+@OptIn(ExperimentalComposeUiApi::class)
+@Sampled
+@Composable
+fun FocusRestorerCustomFallbackSample() {
+    val focusRequester = remember { FocusRequester() }
+    LazyRow(
+        // If restoration fails, focus would fallback to the item associated with focusRequester.
+        Modifier.focusRestorer { focusRequester }
+    ) {
+        item {
+            Button(
+                modifier = Modifier.focusRequester(focusRequester),
+                onClick = {}
+            ) { Text("1") }
+        }
+        item { Button(onClick = {}) { Text("2") } }
+        item { Button(onClick = {}) { Text("3") } }
+        item { Button(onClick = {}) { Text("4") } }
+    }
+}
+
 @Sampled
 @Composable
 fun RequestFocusSample() {
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/FocusRestorerTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/FocusRestorerTest.kt
index dbe8b98..469567e 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/FocusRestorerTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/FocusRestorerTest.kt
@@ -177,4 +177,48 @@
             assertThat(grandChildState.isFocused).isFalse()
         }
     }
+
+    @Test
+    fun restorationFailed_fallbackToOnRestoreFailedDestination() {
+        // Arrange.
+        val (parent, child2) = FocusRequester.createRefs()
+        lateinit var child1State: FocusState
+        lateinit var child2State: FocusState
+        rule.setFocusableContent {
+            Box(
+                Modifier
+                    .size(10.dp)
+                    .focusRequester(parent)
+                    .focusRestorer { child2 }
+                    .focusGroup()
+            ) {
+                key(1) {
+                    Box(
+                        Modifier
+                            .size(10.dp)
+                            .onFocusChanged { child1State = it }
+                            .focusTarget()
+                    )
+                }
+                key(2) {
+                    Box(
+                        Modifier
+                            .size(10.dp)
+                            .focusRequester(child2)
+                            .onFocusChanged { child2State = it }
+                            .focusTarget()
+                    )
+                }
+            }
+        }
+
+        // Act.
+        rule.runOnIdle { parent.requestFocus() }
+
+        // Assert.
+        rule.runOnIdle {
+            assertThat(child1State.isFocused).isFalse()
+            assertThat(child2State.isFocused).isTrue()
+        }
+    }
 }
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/viewinterop/AndroidViewTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/viewinterop/AndroidViewTest.kt
index ffe8b60..3225799 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/viewinterop/AndroidViewTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/viewinterop/AndroidViewTest.kt
@@ -237,6 +237,9 @@
                 }
                 val info: AccessibilityNodeInfo = AccessibilityNodeInfo()
                 delegate.onInitializeAccessibilityNodeInfo(view, info)
+                if (info.isVisibleToUser()) {
+                    throw exception
+                }
                 if (!info.isScreenReaderFocusable()) {
                     throw exception
                 }
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.android.kt
index 817bf68..5859ede 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.android.kt
@@ -818,6 +818,10 @@
                     info: AccessibilityNodeInfoCompat
                 ) {
                     super.onInitializeAccessibilityNodeInfo(host, info)
+
+                    // Prevent TalkBack from trying to focus the AndroidViewHolder
+                    info.setVisibleToUser(false)
+
                     var parentId = layoutNode
                         .findClosestParentNode { it.nodes.has(Nodes.Semantics) }
                         ?.semanticsId
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/viewinterop/AndroidViewHolder.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/viewinterop/AndroidViewHolder.android.kt
index bef25e7e..12dd53e 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/viewinterop/AndroidViewHolder.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/viewinterop/AndroidViewHolder.android.kt
@@ -202,6 +202,10 @@
     override val isValidOwnerScope: Boolean
         get() = isAttachedToWindow
 
+    override fun getAccessibilityClassName(): CharSequence {
+        return javaClass.name
+    }
+
     override fun onReuse() {
         // We reset at the same time we remove the view. So if the view was removed, we can just
         // re-add it and it's ready to go. If it's already attached, we didn't reset it and need
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusRestorer.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusRestorer.kt
index c490f79..bfa2812 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusRestorer.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusRestorer.kt
@@ -19,7 +19,6 @@
 import androidx.compose.runtime.saveable.LocalSaveableStateRegistry
 import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.Modifier
-import androidx.compose.ui.focus.FocusRestorerNode.Companion.FocusRestorerElement
 import androidx.compose.ui.node.ModifierNodeElement
 import androidx.compose.ui.node.Nodes
 import androidx.compose.ui.node.currentValueOf
@@ -63,17 +62,25 @@
 
 // TODO: Move focusRestorer to foundation after saveFocusedChild and restoreFocusedChild are stable.
 /**
- * This modifier can be uses to save and restore focus to a focus group.
+ * This modifier can be used to save and restore focus to a focus group.
  * When focus leaves the focus group, it stores a reference to the item that was previously focused.
  * Then when focus re-enters this focus group, it restores focus to the previously focused item.
  *
+ * @param onRestoreFailed callback provides a lambda that is invoked if focus restoration fails.
+ * This lambda can be used to return a custom fallback item by providing a [FocusRequester]
+ * attached to that item. This can be used to customize the initially focused item.
+ *
  * @sample androidx.compose.ui.samples.FocusRestorerSample
+ * @sample androidx.compose.ui.samples.FocusRestorerCustomFallbackSample
  */
 @ExperimentalComposeUiApi
-fun Modifier.focusRestorer(): Modifier = this then FocusRestorerElement
+fun Modifier.focusRestorer(
+    onRestoreFailed: (() -> FocusRequester)? = null
+): Modifier = this then FocusRestorerElement(onRestoreFailed)
 
-internal class FocusRestorerNode :
-    FocusPropertiesModifierNode, FocusRequesterModifierNode, Modifier.Node() {
+internal class FocusRestorerNode(
+    var onRestoreFailed: (() -> FocusRequester)?
+) : FocusPropertiesModifierNode, FocusRequesterModifierNode, Modifier.Node() {
     private val onExit: (FocusDirection) -> FocusRequester = {
         @OptIn(ExperimentalComposeUiApi::class)
         saveFocusedChild()
@@ -83,22 +90,32 @@
     @OptIn(ExperimentalComposeUiApi::class)
     private val onEnter: (FocusDirection) -> FocusRequester = {
         @OptIn(ExperimentalComposeUiApi::class)
-        if (restoreFocusedChild()) FocusRequester.Cancel else FocusRequester.Default
+        if (restoreFocusedChild()) {
+            FocusRequester.Cancel
+        } else {
+            onRestoreFailed?.invoke() ?: FocusRequester.Default
+        }
     }
+
     override fun applyFocusProperties(focusProperties: FocusProperties) {
         @OptIn(ExperimentalComposeUiApi::class)
         focusProperties.enter = onEnter
         @OptIn(ExperimentalComposeUiApi::class)
         focusProperties.exit = onExit
     }
+}
 
-    companion object {
-        val FocusRestorerElement = object : ModifierNodeElement<FocusRestorerNode>() {
-            override fun create() = FocusRestorerNode()
-            override fun update(node: FocusRestorerNode) {}
-            override fun InspectorInfo.inspectableProperties() { name = "focusRestorer" }
-            override fun hashCode(): Int = "focusRestorer".hashCode()
-            override fun equals(other: Any?) = other === this
-        }
+private data class FocusRestorerElement(
+    val onRestoreFailed: (() -> FocusRequester)?
+) : ModifierNodeElement<FocusRestorerNode>() {
+    override fun create() = FocusRestorerNode(onRestoreFailed)
+
+    override fun update(node: FocusRestorerNode) {
+        node.onRestoreFailed = onRestoreFailed
+    }
+
+    override fun InspectorInfo.inspectableProperties() {
+        name = "focusRestorer"
+        properties["onRestoreFailed"] = onRestoreFailed
     }
 }
diff --git a/core/core-performance-play-services/build.gradle b/core/core-performance-play-services/build.gradle
index c7a44dd..5ae6276 100644
--- a/core/core-performance-play-services/build.gradle
+++ b/core/core-performance-play-services/build.gradle
@@ -29,23 +29,13 @@
     implementation(libs.kotlinCoroutinesCore)
     implementation(project(":core:core-performance"))
     implementation("androidx.datastore:datastore-preferences:1.0.0")
-    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4")
 
-    testImplementation(libs.robolectric)
     androidTestImplementation(libs.junit)
     androidTestImplementation(libs.testExtJunit)
     androidTestImplementation(libs.testRunner)
     androidTestImplementation(libs.truth)
-    androidTestImplementation(libs.espressoCore, excludes.espresso)
-    androidTestImplementation(libs.mockitoAndroid)
 
 
-    testImplementation(libs.testCore)
-    testImplementation(libs.kotlinStdlib)
-    testImplementation(libs.kotlinCoroutinesTest)
-    testImplementation(libs.junit)
-    testImplementation(libs.truth)
-
 }
 
 android {
diff --git a/core/core-performance-play-services/src/androidTest/java/androidx/core/performance/play/services/PlayServiceDevicePerformanceAndroidTest.kt b/core/core-performance-play-services/src/androidTest/java/androidx/core/performance/play/services/PlayServiceDevicePerformanceAndroidTest.kt
index 033e68a..26ed265 100644
--- a/core/core-performance-play-services/src/androidTest/java/androidx/core/performance/play/services/PlayServiceDevicePerformanceAndroidTest.kt
+++ b/core/core-performance-play-services/src/androidTest/java/androidx/core/performance/play/services/PlayServiceDevicePerformanceAndroidTest.kt
@@ -28,27 +28,26 @@
 import com.google.android.gms.common.api.internal.ApiKey
 import com.google.android.gms.deviceperformance.DevicePerformanceClient
 import com.google.android.gms.tasks.Task
-import com.google.android.gms.tasks.Tasks
+import com.google.android.gms.tasks.TaskCompletionSource
 import com.google.common.truth.Truth
 import java.util.concurrent.TimeUnit
 import kotlinx.coroutines.runBlocking
 import org.junit.After
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.mockito.Mockito.mock
-import org.mockito.Mockito.`when`
 
 /** Android Unit tests for [PlayServicesDevicePerformance]. */
 @RunWith(AndroidJUnit4::class)
 class PlayServicesDevicePerformanceTest {
-    open class DevicePerformanceClientTest : DevicePerformanceClient {
+    class FakeDevicePerformanceClient() : DevicePerformanceClient {
+        val taskSource: TaskCompletionSource<Int> = TaskCompletionSource()
         override fun getApiKey(): ApiKey<Api.ApiOptions.NoOptions> {
             // method for testing purpose
             return this.apiKey
         }
 
         override fun mediaPerformanceClass(): Task<Int> {
-            return Tasks.forResult(0)
+            return taskSource.task
         }
     }
 
@@ -62,45 +61,26 @@
 
     @Test
     @MediumTest
-    fun basePlayServiceDevicePerformanceClassTest() {
-        val playServicesDevicePerformance = PlayServicesDevicePerformance(
-            context
-        )
-        val pcScore = playServicesDevicePerformance.mediaPerformanceClass
-        Truth.assertThat(pcScore).isEqualTo(defaultMediaPerformanceClass)
-    }
+    fun mediaPerformanceClass_EmptyStore_33Client() {
+        val fakeDevicePerformanceClient = FakeDevicePerformanceClient()
 
-    @Test
-    @MediumTest
-    fun mockPlayServiceDevicePerformanceClassTest() {
-        val mockClient: DevicePerformanceClient = mock(DevicePerformanceClientTest::class.java)
-        val mediaPerformanceClass = 33
-        `when`(mockClient.mediaPerformanceClass()).thenAnswer {
-            Tasks.forResult(mediaPerformanceClass)
-        }
-        val playServicesDevicePerformance = PlayServicesDevicePerformance(
+        val playServicesDevicePerformance = PlayServicesDevicePerformance.create(
             context,
-            mockClient
+            fakeDevicePerformanceClient
         )
+        fakeDevicePerformanceClient.taskSource.setResult(33)
         delayRead()
         val pcScore = playServicesDevicePerformance.mediaPerformanceClass
-        Truth.assertThat(pcScore).isEqualTo(mediaPerformanceClass)
+        Truth.assertThat(pcScore).isEqualTo(33)
     }
 
     @Test
     @MediumTest
-    fun delayMockPlayServiceDevicePerformanceClassTest() {
-        val mockClient: DevicePerformanceClient = mock(DevicePerformanceClientTest::class.java)
-
-        // Delay the response from mockClient.mediaPerformanceClass() so
-        // response will be different that provided.
-        `when`(mockClient.mediaPerformanceClass()).thenAnswer {
-            TimeUnit.SECONDS.sleep(5)
-            Tasks.forResult(defaultMediaPerformanceClass + 100)
-        }
-        val playServicesDevicePerformance = PlayServicesDevicePerformance(
+    fun mediaPerformanceClass_EmptyStore() {
+        val fakeDevicePerformanceClient = FakeDevicePerformanceClient()
+        val playServicesDevicePerformance = PlayServicesDevicePerformance.create(
             context,
-            mockClient
+            fakeDevicePerformanceClient
         )
         val pcScore = playServicesDevicePerformance.mediaPerformanceClass
         Truth.assertThat(pcScore).isEqualTo(defaultMediaPerformanceClass)
@@ -108,32 +88,30 @@
 
     @Test
     @MediumTest
-    fun playServiceCrashPerformanceClassTest() {
-        val mockClient: DevicePerformanceClient = mock(DevicePerformanceClientTest::class.java)
-        `when`(mockClient.mediaPerformanceClass()).thenReturn( // Throw an exception here.
-            Tasks.forException(IllegalStateException())
-        )
-        val pc = PlayServicesDevicePerformance(
+    fun mediaPerformanceClass_EmptyStore_IllegalStateException() {
+        val fakeDevicePerformanceClient = FakeDevicePerformanceClient()
+        fakeDevicePerformanceClient.taskSource.setException(IllegalStateException())
+        val playServicesDevicePerformance = PlayServicesDevicePerformance.create(
             context,
-            mockClient
+            fakeDevicePerformanceClient
         )
         // Since the gms service has crashed, the library should still return default value.
-        Truth.assertThat(pc.mediaPerformanceClass).isEqualTo(defaultMediaPerformanceClass)
+        Truth.assertThat(playServicesDevicePerformance.mediaPerformanceClass)
+            .isEqualTo(defaultMediaPerformanceClass)
     }
 
     @Test
     @MediumTest
-    fun playServiceNotStartPerformanceClassTest() {
-        val mockClient: DevicePerformanceClient = mock(DevicePerformanceClientTest::class.java)
-        `when`(mockClient.mediaPerformanceClass()).thenReturn( // Throw an exception here.
-            Tasks.forException(ApiException(Status.RESULT_TIMEOUT))
-        )
-        val pc = PlayServicesDevicePerformance(
+    fun mediaPerformanceClass_EmptyStore_TimeOut() {
+        val fakeDevicePerformanceClient = FakeDevicePerformanceClient()
+        fakeDevicePerformanceClient.taskSource.setException(ApiException(Status.RESULT_TIMEOUT))
+        val playServicesDevicePerformance = PlayServicesDevicePerformance.create(
             context,
-            mockClient
+            fakeDevicePerformanceClient
         )
         // Since the gms service not started, the library should still return default value.
-        Truth.assertThat(pc.mediaPerformanceClass).isEqualTo(defaultMediaPerformanceClass)
+        Truth.assertThat(playServicesDevicePerformance.mediaPerformanceClass)
+            .isEqualTo(defaultMediaPerformanceClass)
     }
 
     /* Add delay to make sure that value is written in Preference datastore before reading it */
diff --git a/core/core-performance-play-services/src/main/java/androidx/core/performance/play/services/PlayServicesDevicePerformance.kt b/core/core-performance-play-services/src/main/java/androidx/core/performance/play/services/PlayServicesDevicePerformance.kt
index 2fa0a804..03f2d6a 100644
--- a/core/core-performance-play-services/src/main/java/androidx/core/performance/play/services/PlayServicesDevicePerformance.kt
+++ b/core/core-performance-play-services/src/main/java/androidx/core/performance/play/services/PlayServicesDevicePerformance.kt
@@ -39,7 +39,9 @@
  *
  * @param context The application context value to use.
  */
-class PlayServicesDevicePerformance(private val context: Context) : DevicePerformance {
+class PlayServicesDevicePerformance
+private constructor(private val context: Context, client: DevicePerformanceClient) :
+    DevicePerformance {
     private val tag = "PlayServicesDevicePerformance"
 
     private val defaultMpc = DefaultDevicePerformance()
@@ -64,24 +66,32 @@
             "Getting mediaPerformanceClass from " +
                 "com.google.android.gms.deviceperformance.DevicePerformanceClient"
         )
-        updatePerformanceStore(
-            com.google.android.gms.deviceperformance.DevicePerformance.getClient(context)
-        )
+        updatePerformanceStore(client)
     }
 
-    @VisibleForTesting
-    internal constructor(context: Context, client: DevicePerformanceClient) : this(context) {
-        // mock client should wait for the playServices client to finish,
-        // so the test results are determined by the mock client.
-        runBlocking {
-            playServicesValueStoredDeferred.await()
-        }
-        updatePerformanceStore(client)
+    /**
+     * A DevicePerformance that uses Google Play Services to retrieve media performance class data.
+     *
+     * @param context The application context value to use.
+     */
+      constructor(context: Context) : this(
+        context,
+        com.google.android.gms.deviceperformance.DevicePerformance.getClient(context)
+    ) {
     }
 
     private val mpcKey = intPreferencesKey("mpc_value")
 
     internal companion object {
+
+        @VisibleForTesting
+        fun create(
+            context: Context,
+            client: DevicePerformanceClient
+        ): PlayServicesDevicePerformance {
+            return PlayServicesDevicePerformance(context, client)
+        }
+
         // To avoid creating multiple instance of datastore
         private val Context.performanceStore by
         preferencesDataStore(name = "media_performance_class")
@@ -115,16 +125,14 @@
                 launch {
                     savePerformanceClass(storedVal)
                     Log.v(tag, "Saved mediaPerformanceClass $storedVal")
-                    playServicesValueStoredDeferred.complete(true)
                 }
             }
         }.addOnFailureListener { e: Exception ->
             if (e is ApiException) {
-                Log.e(tag, "Error saving mediaPerformanceClass: $e")
+                Log.e(tag, "Error saving mediaPerformanceClass", e)
             } else if (e is IllegalStateException) {
-                Log.e(tag, "Error saving mediaPerformanceClass: $e")
+                Log.e(tag, "Error saving mediaPerformanceClass", e)
             }
-            playServicesValueStoredDeferred.complete(true)
         }
     }
 }
diff --git a/core/core-telecom/src/androidTest/AndroidManifest.xml b/core/core-telecom/src/androidTest/AndroidManifest.xml
index 6e24bd3..4d94ecb2 100644
--- a/core/core-telecom/src/androidTest/AndroidManifest.xml
+++ b/core/core-telecom/src/androidTest/AndroidManifest.xml
@@ -16,6 +16,7 @@
   -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android">
     <uses-permission android:name="android.permission.MANAGE_OWN_CALLS" />
+    <uses-permission android:name="android.permission.READ_PHONE_NUMBERS"/>
 
     <application>
         <service
diff --git a/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/E2ECallExtensionExtrasTests.kt b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/E2ECallExtensionExtrasTests.kt
new file mode 100644
index 0000000..458a920
--- /dev/null
+++ b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/E2ECallExtensionExtrasTests.kt
@@ -0,0 +1,202 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.telecom.test
+
+import android.Manifest
+import android.os.Build
+import android.telecom.Call
+import android.telecom.DisconnectCause
+import androidx.annotation.RequiresApi
+import androidx.core.telecom.CallAttributesCompat
+import androidx.core.telecom.CallsManager
+import androidx.core.telecom.internal.InCallServiceCompat
+import androidx.core.telecom.internal.utils.Utils
+import androidx.core.telecom.test.utils.BaseTelecomTest
+import androidx.core.telecom.test.utils.TestUtils
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
+import androidx.test.filters.SdkSuppress
+import androidx.test.rule.GrantPermissionRule
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
+import org.junit.After
+import org.junit.Assert
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * This test class helps verify the E2E behavior for calls added via Jetpack to ensure that the
+ * call details contain the appropriate extension extras that define the support for capability
+ * exchange between the VOIP app and ICS.
+ *
+ * Note: Currently, this test only verifies the presence of [CallsManager.PROPERTY_IS_TRANSACTIONAL]
+ * (only in V) in the call properties, if the phone account supports transactional ops (U+ devices),
+ * or if the [CallsManager.EXTRA_VOIP_BACKWARDS_COMPATIBILITY_SUPPORTED] key is present in the call
+ * extras (pre-U devices). In the future, this will be expanded to be provide more robust testing
+ * to verify binder functionality as well as supporting the case for auto
+ * ([CallsManager.EXTRA_VOIP_API_VERSION]).
+ */
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+@RequiresApi(Build.VERSION_CODES.O)
+@RunWith(AndroidJUnit4::class)
+class E2ECallExtensionExtrasTests : BaseTelecomTest() {
+    private lateinit var inCallServiceCompat: InCallServiceCompat
+
+    /**
+     * Grant READ_PHONE_NUMBERS permission as part of testing
+     * [InCallServiceCompat#resolveCallExtensionsType].
+     */
+    @get:Rule
+    val readPhoneNumbersRule: GrantPermissionRule =
+        GrantPermissionRule.grant(Manifest.permission.READ_PHONE_NUMBERS)!!
+
+    @Before
+    fun setUp() {
+        Utils.resetUtils()
+        inCallServiceCompat = InCallServiceCompat(mContext)
+    }
+
+    @After
+    fun onDestroy() {
+        Utils.resetUtils()
+    }
+
+    /***********************************************************************************************
+     *                           V2 APIs (Android U and above) tests
+     *********************************************************************************************/
+
+    /**
+     * For U+ devices using the v2 APIs, assert that the incoming call details either support
+     * the [CallsManager.PROPERTY_IS_TRANSACTIONAL] property (V) or the phone account supports
+     * transactional operations (U+).
+     */
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+    @LargeTest
+    @Test(timeout = 10000)
+    fun testCapabilityExchangeIncoming_V2() {
+        setUpV2Test()
+        addAndVerifyCallExtensionTypeE2E(TestUtils.INCOMING_CALL_ATTRIBUTES)
+    }
+
+    /**
+     * For U+ devices using the v2 APIs, assert that the outgoing call details either support
+     * the [CallsManager.PROPERTY_IS_TRANSACTIONAL] property (V) or the phone account supports
+     * transactional operations (U+).
+     */
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+    @LargeTest
+    @Test(timeout = 10000)
+    fun testCapabilityExchangeOutgoing_V2() {
+        setUpV2Test()
+        addAndVerifyCallExtensionTypeE2E(TestUtils.OUTGOING_CALL_ATTRIBUTES)
+    }
+
+    /***********************************************************************************************
+     *                           Backwards Compatibility Layer tests
+     *********************************************************************************************/
+
+    /**
+     * For pre-U devices using the backwards compatibility library, assert that the incoming call
+     * details contain the [CallsManager.EXTRA_VOIP_BACKWARDS_COMPATIBILITY_SUPPORTED] key
+     */
+    @LargeTest
+    @Test(timeout = 10000)
+    fun testCapabilityExchangeIncoming_BackwardsCompat() {
+        setUpBackwardsCompatTest()
+        addAndVerifyCallExtensionTypeE2E(
+            TestUtils.INCOMING_CALL_ATTRIBUTES,
+            waitForCallDetailExtras = true
+        )
+    }
+
+    /**
+     * For pre-U devices using the backwards compatibility library, assert that the outgoing call
+     * details contain the [CallsManager.EXTRA_VOIP_BACKWARDS_COMPATIBILITY_SUPPORTED] key
+     */
+    @LargeTest
+    @Test(timeout = 10000)
+    fun testCapabilityExchangeOutgoing_BackwardsCompat() {
+        setUpBackwardsCompatTest()
+        addAndVerifyCallExtensionTypeE2E(
+            TestUtils.OUTGOING_CALL_ATTRIBUTES,
+            waitForCallDetailExtras = true
+        )
+    }
+
+    /***********************************************************************************************
+     *                           Helpers
+     *********************************************************************************************/
+
+    /**
+     * Helper to add a call via CallsManager#addCall and block (if needed) until the connection
+     * extras are propagated into the call details.
+     *
+     * @param callAttributesCompat for the call.
+     * @param waitForCallDetailExtras used for waiting on the call details extras to be non-empty.
+     */
+    private fun addAndVerifyCallExtensionTypeE2E(
+        callAttributesCompat: CallAttributesCompat,
+        waitForCallDetailExtras: Boolean = false
+    ) {
+        runBlocking {
+            assertWithinTimeout_addCall(callAttributesCompat) {
+                launch {
+                    val call = TestUtils.waitOnInCallServiceToReachXCalls(1)
+                    Assert.assertNotNull("The returned Call object is <NULL>", call!!)
+
+                    // Enforce waiting logic to ensure that the call details extras are populated.
+                    if (waitForCallDetailExtras) {
+                        TestUtils.waitOnCallExtras(call)
+                    }
+
+                    // Assert the call extra or call property from the details
+                    assertCallExtraOrProperty(call)
+                    // Always send disconnect signal if possible.
+                    assertTrue(disconnect(DisconnectCause(DisconnectCause.LOCAL)))
+                }
+            }
+        }
+    }
+
+    /**
+     * Helper to assert the call extra or property set on the call coming from Telecom.
+     */
+    private fun assertCallExtraOrProperty(call: Call) {
+        // Call details should be present at this point
+        val callDetails = call.details!!
+        if (TestUtils.buildIsAtLeastU()) {
+            if (TestUtils.buildIsAtLeastV()) {
+                assertTrue(callDetails.hasProperty(CallsManager.PROPERTY_IS_TRANSACTIONAL))
+            } else if (Utils.hasPlatformV2Apis()) {
+                // We need to check the phone account, which requires accessing TelecomManager.
+                // Directly resolving the extension type via resolveCallExtensionsType() will
+                // provide that functionality so no need to rewrite it here.
+                assertEquals(
+                    inCallServiceCompat.resolveCallExtensionsType(call),
+                    InCallServiceCompat.CAPABILITY_EXCHANGE)
+            }
+        } else {
+            val containsBackwardsCompatKey = callDetails.extras != null && callDetails.extras
+                .containsKey(CallsManager.EXTRA_VOIP_BACKWARDS_COMPATIBILITY_SUPPORTED)
+            assertTrue(containsBackwardsCompatKey)
+        }
+    }
+}
diff --git a/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/InCallServiceCompatTest.kt b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/InCallServiceCompatTest.kt
new file mode 100644
index 0000000..94f3a2e
--- /dev/null
+++ b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/InCallServiceCompatTest.kt
@@ -0,0 +1,224 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.telecom.test
+
+import android.Manifest
+import android.os.Build
+import android.telecom.Call
+import android.telecom.DisconnectCause
+import android.util.Log
+import androidx.annotation.RequiresApi
+import androidx.core.telecom.CallAttributesCompat
+import androidx.core.telecom.CallsManager
+import androidx.core.telecom.internal.InCallServiceCompat
+import androidx.core.telecom.internal.utils.Utils
+import androidx.core.telecom.test.utils.BaseTelecomTest
+import androidx.core.telecom.test.utils.TestUtils
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
+import androidx.test.filters.SdkSuppress
+import androidx.test.rule.GrantPermissionRule
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
+import org.junit.After
+import org.junit.Assert
+import org.junit.Assert.assertEquals
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * This test class verifies the [InCallServiceCompat] functionality around resolving the call
+ * extension type in order to determine the supported extensions between the VOIP app and the
+ * associated InCallServices. This test constructs calls via TelecomManager and modifies the call
+ * details (if required) to test each scenario. This is explained in more detail at the test level
+ * for each of the applicable cases below.
+ *
+ * Note: [Call] is package-private so we still need to leverage Telecom to create calls on our
+ * behalf for testing. The call properties and extras fields aren't mutable so we need to ensure
+ * that we wait for them to become available before accessing them.
+ */
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+@RequiresApi(Build.VERSION_CODES.O)
+@RunWith(AndroidJUnit4::class)
+class InCallServiceCompatTest : BaseTelecomTest() {
+    private lateinit var inCallServiceCompat: InCallServiceCompat
+
+    /**
+     * Grant READ_PHONE_NUMBERS permission as part of testing
+     * [InCallServiceCompat#resolveCallExtensionsType].
+     */
+    @get:Rule
+    val readPhoneNumbersRule: GrantPermissionRule =
+        GrantPermissionRule.grant(Manifest.permission.READ_PHONE_NUMBERS)!!
+
+    companion object {
+        /**
+         * Logging for within the test class.
+         */
+        internal val TAG = InCallServiceCompatTest::class.simpleName
+    }
+
+    @Before
+    fun setUp() {
+        Utils.resetUtils()
+        inCallServiceCompat = InCallServiceCompat(mContext)
+    }
+
+    @After
+    fun onDestroy() {
+        Utils.resetUtils()
+    }
+
+    /**
+     * Assert that EXTRAS is the extension type for calls made using the V1.5 ConnectionService +
+     * Extensions Library (Auto). The call should have the [CallsManager.EXTRA_VOIP_API_VERSION]
+     * defined in the extras.
+     *
+     * The contents of the call detail extras need to be modified to test calls using the V1.5
+     * ConnectionService + Extensions library (until E2E testing can be supported for it). This
+     * requires us to manually insert the [CallsManager.EXTRA_VOIP_API_VERSION] key into the bundle.
+     */
+    @LargeTest
+    @Test(timeout = 10000)
+    fun testResolveCallExtension_Extra() {
+        setUpBackwardsCompatTest()
+        val voipApiExtra = Pair(CallsManager.EXTRA_VOIP_API_VERSION, true)
+        addAndVerifyCallExtensionType(
+            TestUtils.OUTGOING_CALL_ATTRIBUTES,
+            InCallServiceCompat.EXTRAS,
+            extraToInclude = voipApiExtra)
+    }
+
+    /**
+     * Assert that CAPABILITY_EXCHANGE is the extension type for calls that either have the
+     * [CallsManager.PROPERTY_IS_TRANSACTIONAL] (V) defined as a property or the phone account
+     * supports transactional ops (U+). For pre-U devices, the call extras would define the
+     * [CallsManager.EXTRA_VOIP_BACKWARDS_COMPATIBILITY_SUPPORTED] key.
+     *
+     * Note: The version codes for V is not available so we need to enforce a strict manual check
+     * to ensure the V test path is not executed by incompatible devices.
+     */
+    @LargeTest
+    @Test(timeout = 10000)
+    fun testResolveCallExtension_CapabilityExchange() {
+        if (TestUtils.buildIsAtLeastU()) {
+            Log.w(TAG, "Setting up v2 tests for U+ device")
+            setUpV2Test()
+        } else {
+            Log.w(TAG, "Setting up backwards compatibility tests for pre-U device")
+            setUpBackwardsCompatTest()
+        }
+
+        // Add EXTRA_VOIP_BACKWARDS_COMPATIBILITY_SUPPORTED for pre-U testing
+        val backwardsCompatExtra = if (!TestUtils.buildIsAtLeastU())
+            Pair(CallsManager.EXTRA_VOIP_BACKWARDS_COMPATIBILITY_SUPPORTED, true)
+        else null
+        addAndVerifyCallExtensionType(
+            TestUtils.OUTGOING_CALL_ATTRIBUTES,
+            InCallServiceCompat.CAPABILITY_EXCHANGE,
+            // Waiting is not required for U+ testing
+            waitForCallDetailExtras = !TestUtils.buildIsAtLeastU(),
+            extraToInclude = backwardsCompatExtra
+        )
+    }
+
+    /**
+     * Assert that NONE is the extension type for calls with phone accounts that do not support
+     * transactional ops. Note that the caller must have had the read phone numbers permission.
+     *
+     * Note: Ensure that all extras are cleared before asserting extension type so that the phone
+     * account can be checked. For backwards compatibility tests, calls define the
+     * [CallsManager.EXTRA_VOIP_BACKWARDS_COMPATIBILITY_SUPPORTED] key in the details extras so this
+     * needs to be disregarded.
+     *
+     * We need to ensure that all extras/properties are ignored for testing so that the phone
+     * account can be checked to see if it supports transactional ops. In jetpack, this can only be
+     * verified on pre-U devices as those phone accounts are registered in Telecom without
+     * transactional ops. Keep in mind that because these calls are set up for backwards
+     * compatibility, they will have the [CallsManager.EXTRA_VOIP_BACKWARDS_COMPATIBILITY_SUPPORTED]
+     * extra in the details (which will need to be ignored during testing).
+     */
+    @LargeTest
+    @Test(timeout = 10000)
+    fun testResolveCallExtension_TransactionalOpsNotSupported() {
+        // Phone accounts that don't use the v2 APIs don't support transactional ops.
+        setUpBackwardsCompatTest()
+        addAndVerifyCallExtensionType(
+            TestUtils.OUTGOING_CALL_ATTRIBUTES,
+            InCallServiceCompat.NONE,
+            waitForCallDetailExtras = false
+        )
+    }
+
+    /***********************************************************************************************
+     *                           Helpers
+     *********************************************************************************************/
+
+    /**
+     * Helper to add a call via CallsManager#addCall and verify the extension type depending on
+     * the APIs that are leveraged.
+     *
+     * Note: The connection extras are not added into the call until the connection is successfully
+     * created. This is usually the case when the call moves from the CONNECTING state into either
+     * the DIALING/RINGING state. This would be the case for [CallsManager.EXTRA_VOIP_API_VERSION]
+     * (handled by auto) as well as for [CallsManager.EXTRA_VOIP_BACKWARDS_COMPATIBILITY_SUPPORTED]
+     * (see JetpackConnectionService#createSelfManagedConnection). Keep in mind that these extras
+     * would not be available in [InCalLService#onCallAdded], but after
+     * [Call#handleCreateConnectionSuccess] is invoked and the connection service extras are
+     * propagated into the call details via [Call#putConnectionServiceExtras].
+     *
+     * @param callAttributesCompat for the call.
+     * @param expectedType for call extension type.
+     * @param waitForCallDetailExtras used for waiting on the call details extras to be non-null.
+     * @param extraToInclude as part of the call extras.
+     */
+    private fun addAndVerifyCallExtensionType(
+        callAttributesCompat: CallAttributesCompat,
+        @InCallServiceCompat.Companion.CapabilityExchangeType expectedType: Int,
+        waitForCallDetailExtras: Boolean = true,
+        extraToInclude: Pair<String, Boolean>? = null
+    ) {
+        runBlocking {
+            assertWithinTimeout_addCall(callAttributesCompat) {
+                launch {
+                    val call = TestUtils.waitOnInCallServiceToReachXCalls(1)
+                    Assert.assertNotNull("The returned Call object is <NULL>", call!!)
+
+                    // Enforce waiting logic to ensure that the call details extras are populated.
+                    if (waitForCallDetailExtras) {
+                        TestUtils.waitOnCallExtras(call)
+                    }
+
+                    val callDetails = call.details
+                    // Clear out extras to isolate the testing scenarios.
+                    call.details.extras?.clear()
+                    // Add extraToInclude for testing.
+                    if (extraToInclude != null) {
+                        callDetails.extras?.putBoolean(extraToInclude.first, extraToInclude.second)
+                    }
+
+                    // Assert call extension type.
+                    assertEquals(expectedType, inCallServiceCompat.resolveCallExtensionsType(call))
+                    // Always send disconnect signal if possible.
+                    Assert.assertTrue(disconnect(DisconnectCause(DisconnectCause.LOCAL)))
+                }
+            }
+        }
+    }
+}
diff --git a/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/utils/TestUtils.kt b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/utils/TestUtils.kt
index 5aba448..c44414ca 100644
--- a/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/utils/TestUtils.kt
+++ b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/utils/TestUtils.kt
@@ -19,6 +19,7 @@
 import android.content.Context
 import android.media.AudioManager
 import android.net.Uri
+import android.os.Build
 import android.os.Build.VERSION_CODES
 import android.os.UserHandle
 import android.os.UserManager
@@ -310,4 +311,39 @@
             )
         }
     }
+
+    /**
+     * Helper to wait on the call detail extras to be populated from the connection service
+     */
+    suspend fun waitOnCallExtras(call: Call) {
+        try {
+            withTimeout(TestUtils.WAIT_ON_CALL_STATE_TIMEOUT) {
+                while (isActive /* aka  within timeout window */ && call.details?.extras == null) {
+                    yield() // another mechanism to stop the while loop if the coroutine is dead
+                    delay(1) // sleep x millisecond(s) instead of spamming check
+                }
+            }
+        } catch (e: TimeoutCancellationException) {
+            Log.i(TestUtils.LOG_TAG, "waitOnCallExtras: timeout reached")
+            TestUtils.dumpTelecom()
+            MockInCallService.destroyAllCalls()
+            throw AssertionError("Expected call detail extras to be non-null.")
+        }
+    }
+
+    /**
+     * Used for testing in V. The build version is not available for referencing so this helper
+     * performs a manual check instead.
+     */
+    fun buildIsAtLeastV(): Boolean {
+        // V is not referencable as a valid build version yet. Enforce strict manual check instead.
+        return Build.VERSION.SDK_INT > 34
+    }
+
+    /**
+     * Determine if the current build supports at least U.
+     */
+    fun buildIsAtLeastU(): Boolean {
+        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE
+    }
 }
diff --git a/core/core-telecom/src/main/java/androidx/core/telecom/CallsManager.kt b/core/core-telecom/src/main/java/androidx/core/telecom/CallsManager.kt
index fd67da4..27df20c 100644
--- a/core/core-telecom/src/main/java/androidx/core/telecom/CallsManager.kt
+++ b/core/core-telecom/src/main/java/androidx/core/telecom/CallsManager.kt
@@ -82,6 +82,11 @@
         annotation class Capability
 
         /**
+         * Set on Connections that are using ConnectionService+AUTO specific extension layer.
+         */
+        internal const val EXTRA_VOIP_API_VERSION = "android.telecom.extra.VOIP_API_VERSION"
+
+        /**
          * Set on Jetpack Connections that are emulating the transactional APIs using
          * ConnectionService.
          */
@@ -89,6 +94,15 @@
             "android.telecom.extra.VOIP_BACKWARDS_COMPATIBILITY_SUPPORTED"
 
         /**
+         * The connection is using transactional call APIs.
+         *
+         *
+         * The underlying connection was added as a transactional call via the
+         * [TelecomManager.addCall] API.
+         */
+        internal const val PROPERTY_IS_TRANSACTIONAL = 0x00008000
+
+        /**
          * If your VoIP application does not want support any of the capabilities below, then your
          * application can register with [CAPABILITY_BASELINE].
          *
diff --git a/camera/camera-effects/src/main/java/androidx/camera/effects/Portrait.java b/core/core-telecom/src/main/java/androidx/core/telecom/internal/CallCompat.kt
similarity index 63%
copy from camera/camera-effects/src/main/java/androidx/camera/effects/Portrait.java
copy to core/core-telecom/src/main/java/androidx/core/telecom/internal/CallCompat.kt
index 7a355f8..890707d 100644
--- a/camera/camera-effects/src/main/java/androidx/camera/effects/Portrait.java
+++ b/core/core-telecom/src/main/java/androidx/core/telecom/internal/CallCompat.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2022 The Android Open Source Project
+ * Copyright 2023 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,15 +14,12 @@
  * limitations under the License.
  */
 
-package androidx.camera.effects;
+package androidx.core.telecom.internal
 
-import androidx.annotation.RestrictTo;
+import android.telecom.Call
+import kotlinx.coroutines.CoroutineScope
 
-/**
- * Provides a portrait post-processing effect.
- *
- */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public class Portrait {
-    // TODO: implement this
+internal class CallCompat(call: Call, block: CoroutineScope.() -> Unit) {
+    private val mCall: Call = call
+    private val mBlock: CoroutineScope.() -> Unit = block
 }
diff --git a/core/core-telecom/src/main/java/androidx/core/telecom/internal/InCallServiceCompat.kt b/core/core-telecom/src/main/java/androidx/core/telecom/internal/InCallServiceCompat.kt
new file mode 100644
index 0000000..f3063c0
--- /dev/null
+++ b/core/core-telecom/src/main/java/androidx/core/telecom/internal/InCallServiceCompat.kt
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.telecom.internal
+
+import android.Manifest
+import android.content.Context
+import android.content.pm.PackageManager
+import android.os.Build
+import android.os.Bundle
+import android.telecom.Call
+import android.telecom.InCallService
+import android.telecom.PhoneAccount
+import android.telecom.TelecomManager
+import android.util.Log
+import androidx.annotation.IntDef
+import androidx.annotation.RequiresApi
+import androidx.core.content.ContextCompat
+import androidx.core.telecom.CallsManager
+
+/**
+ * This class defines the Jetpack ICS layer which will be leveraged as part of supporting VOIP app
+ * actions.
+ */
+@RequiresApi(Build.VERSION_CODES.M)
+internal class InCallServiceCompat(context: Context) : InCallService() {
+    private val mContext: Context = context
+
+    companion object {
+        /**
+         * Constants used to denote the extension level supported by the VOIP app.
+         */
+        @Retention(AnnotationRetention.SOURCE)
+        @IntDef(NONE, EXTRAS, CAPABILITY_EXCHANGE, UNKNOWN)
+        internal annotation class CapabilityExchangeType
+
+        internal const val NONE = 0
+        internal const val EXTRAS = 1
+        internal const val CAPABILITY_EXCHANGE = 2
+        internal const val UNKNOWN = 3
+
+        private val TAG = InCallServiceCompat::class.simpleName
+    }
+
+    fun onCreateCall(call: Call): CallCompat {
+        Log.d(TAG, "onCreateCall: call = $call")
+        return with(this) {
+            CallCompat(call) {
+            }
+        }
+    }
+
+    fun onRemoveCall(call: CallCompat) {
+        Log.d(TAG, "onRemoveCall: call = $call")
+    }
+
+    /**
+     * Internal helper used by the [InCallService] to help resolve the call extension type. This
+     * is invoked before capability exchange between the [InCallService] and VOIP app starts to
+     * ensure the necessary features are enabled to support it.
+     *
+     * If the call is placed using the V1.5 ConnectionService + Extensions Library (Auto Case), the
+     * call will have the [CallsManager.EXTRA_VOIP_API_VERSION] defined in the extras. The call
+     * extension would be resolved as [InCallServiceCompat.EXTRAS].
+     *
+     * If the call is using the v2 APIs and the phone account associated with the call supports
+     * transactional ops (U+) or the call has the [CallsManager.PROPERTY_IS_TRANSACTIONAL] property
+     * defined (on V devices), then the extension type is [InCallServiceCompat.CAPABILITY_EXCHANGE].
+     *
+     * If the call is added via CallsManager#addCall on pre-U devices and the
+     * [CallsManager.EXTRA_VOIP_BACKWARDS_COMPATIBILITY_SUPPORTED] is present in the call extras,
+     * the extension type also resolves to [InCallServiceCompat.CAPABILITY_EXCHANGE].
+     *
+     * In the case that none of the cases above apply and the phone account is found not to support
+     * transactional ops (assumes that caller has [android.Manifest.permission.READ_PHONE_NUMBERS]
+     * permission), then the extension type is [InCallServiceCompat.NONE].
+     *
+     * If the caller does not have the required permission to retrieve the phone account, then
+     * the extension type will be [InCallServiceCompat.UNKNOWN], until it can be resolved.
+     *
+     * @param call to resolve the extension type for.
+     * @return the extension type [InCallServiceCompat.CapabilityExchangeType] resolved for the
+     * call.
+     */
+    @RequiresApi(Build.VERSION_CODES.O)
+    @CapabilityExchangeType
+    internal fun resolveCallExtensionsType(call: Call): Int {
+        var callDetails = call.details
+        val callExtras = callDetails?.extras ?: Bundle()
+
+        if (callExtras.containsKey(CallsManager.EXTRA_VOIP_API_VERSION)) {
+            return EXTRAS
+        }
+        if (callDetails?.hasProperty(CallsManager.PROPERTY_IS_TRANSACTIONAL) == true || callExtras
+            .containsKey(CallsManager.EXTRA_VOIP_BACKWARDS_COMPATIBILITY_SUPPORTED)) {
+            return CAPABILITY_EXCHANGE
+        }
+        // Verify read phone numbers permission to see if phone account supports transactional ops.
+        if (ContextCompat.checkSelfPermission(mContext, Manifest.permission.READ_PHONE_NUMBERS)
+            == PackageManager.PERMISSION_GRANTED) {
+            var telecomManager = mContext.getSystemService(Context.TELECOM_SERVICE)
+                as TelecomManager
+            var phoneAccount = telecomManager.getPhoneAccount(callDetails?.accountHandle)
+            if (phoneAccount?.hasCapabilities(
+                    PhoneAccount.CAPABILITY_SUPPORTS_TRANSACTIONAL_OPERATIONS) == true) {
+                return CAPABILITY_EXCHANGE
+            } else {
+                return NONE
+            }
+        }
+
+        Log.i(TAG, "Unable to resolve call extension type. Returning $UNKNOWN.")
+        return UNKNOWN
+    }
+}
diff --git a/core/haptics/haptics/api/current.txt b/core/haptics/haptics/api/current.txt
index 87cfe87..b4b7e54 100644
--- a/core/haptics/haptics/api/current.txt
+++ b/core/haptics/haptics/api/current.txt
@@ -3,7 +3,7 @@
 
   public interface HapticManager {
     method public static androidx.core.haptics.HapticManager create(android.content.Context context);
-    method @RequiresPermission(android.Manifest.permission.VIBRATE) public void play(androidx.core.haptics.signal.PredefinedEffect effect);
+    method @RequiresPermission(android.Manifest.permission.VIBRATE) public void play(androidx.core.haptics.signal.HapticSignal signal);
     field public static final androidx.core.haptics.HapticManager.Companion Companion;
   }
 
@@ -15,15 +15,155 @@
 
 package androidx.core.haptics.signal {
 
-  public final class PredefinedEffect {
-    field public static final androidx.core.haptics.signal.PredefinedEffect.Companion Companion;
-    field public static final androidx.core.haptics.signal.PredefinedEffect PredefinedClick;
-    field public static final androidx.core.haptics.signal.PredefinedEffect PredefinedDoubleClick;
-    field public static final androidx.core.haptics.signal.PredefinedEffect PredefinedHeavyClick;
-    field public static final androidx.core.haptics.signal.PredefinedEffect PredefinedTick;
+  public final class CompositionSignal extends androidx.core.haptics.signal.FiniteSignal {
+    ctor public CompositionSignal(java.util.List<? extends androidx.core.haptics.signal.CompositionSignal.Atom> atoms);
+    method public static androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom click();
+    method public static androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom click(optional @FloatRange(from=0.0, to=1.0) float amplitudeScale);
+    method public static androidx.core.haptics.signal.CompositionSignal compositionOf(androidx.core.haptics.signal.CompositionSignal.Atom... atoms);
+    method public java.util.List<androidx.core.haptics.signal.CompositionSignal.Atom> getAtoms();
+    method public static androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom lowTick();
+    method public static androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom lowTick(optional @FloatRange(from=0.0, to=1.0) float amplitudeScale);
+    method @RequiresApi(android.os.Build.VERSION_CODES.O) public static androidx.core.haptics.signal.CompositionSignal.OffAtom off(java.time.Duration duration);
+    method public static androidx.core.haptics.signal.CompositionSignal.OffAtom off(long durationMillis);
+    method public static androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom quickFall();
+    method public static androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom quickFall(optional @FloatRange(from=0.0, to=1.0) float amplitudeScale);
+    method public static androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom quickRise();
+    method public static androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom quickRise(optional @FloatRange(from=0.0, to=1.0) float amplitudeScale);
+    method public static androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom slowRise();
+    method public static androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom slowRise(optional @FloatRange(from=0.0, to=1.0) float amplitudeScale);
+    method public static androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom spin();
+    method public static androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom spin(optional @FloatRange(from=0.0, to=1.0) float amplitudeScale);
+    method public static androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom thud();
+    method public static androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom thud(optional @FloatRange(from=0.0, to=1.0) float amplitudeScale);
+    method public static androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom tick();
+    method public static androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom tick(optional @FloatRange(from=0.0, to=1.0) float amplitudeScale);
+    property public final java.util.List<androidx.core.haptics.signal.CompositionSignal.Atom> atoms;
+    field public static final androidx.core.haptics.signal.CompositionSignal.Companion Companion;
   }
 
-  public static final class PredefinedEffect.Companion {
+  public abstract static class CompositionSignal.Atom {
+  }
+
+  public static final class CompositionSignal.Companion {
+    method public androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom click();
+    method public androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom click(optional @FloatRange(from=0.0, to=1.0) float amplitudeScale);
+    method public androidx.core.haptics.signal.CompositionSignal compositionOf(androidx.core.haptics.signal.CompositionSignal.Atom... atoms);
+    method public androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom lowTick();
+    method public androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom lowTick(optional @FloatRange(from=0.0, to=1.0) float amplitudeScale);
+    method @RequiresApi(android.os.Build.VERSION_CODES.O) public androidx.core.haptics.signal.CompositionSignal.OffAtom off(java.time.Duration duration);
+    method public androidx.core.haptics.signal.CompositionSignal.OffAtom off(long durationMillis);
+    method public androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom quickFall();
+    method public androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom quickFall(optional @FloatRange(from=0.0, to=1.0) float amplitudeScale);
+    method public androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom quickRise();
+    method public androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom quickRise(optional @FloatRange(from=0.0, to=1.0) float amplitudeScale);
+    method public androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom slowRise();
+    method public androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom slowRise(optional @FloatRange(from=0.0, to=1.0) float amplitudeScale);
+    method public androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom spin();
+    method public androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom spin(optional @FloatRange(from=0.0, to=1.0) float amplitudeScale);
+    method public androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom thud();
+    method public androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom thud(optional @FloatRange(from=0.0, to=1.0) float amplitudeScale);
+    method public androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom tick();
+    method public androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom tick(optional @FloatRange(from=0.0, to=1.0) float amplitudeScale);
+  }
+
+  public static final class CompositionSignal.OffAtom extends androidx.core.haptics.signal.CompositionSignal.Atom {
+    method public long getDurationMillis();
+    property public final long durationMillis;
+  }
+
+  public static final class CompositionSignal.PrimitiveAtom extends androidx.core.haptics.signal.CompositionSignal.Atom {
+    method public float getAmplitudeScale();
+    method public int getType();
+    method public androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom withAmplitudeScale(@FloatRange(from=0.0, to=1.0) float newAmplitudeScale);
+    property public final float amplitudeScale;
+    property public final int type;
+    field public static final int CLICK = 1; // 0x1
+    field public static final androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom.Companion Companion;
+    field public static final int LOW_TICK = 8; // 0x8
+    field public static final int QUICK_FALL = 6; // 0x6
+    field public static final int QUICK_RISE = 4; // 0x4
+    field public static final int SLOW_RISE = 5; // 0x5
+    field public static final int SPIN = 3; // 0x3
+    field public static final int THUD = 2; // 0x2
+    field public static final int TICK = 7; // 0x7
+  }
+
+  public static final class CompositionSignal.PrimitiveAtom.Companion {
+  }
+
+  public abstract class FiniteSignal extends androidx.core.haptics.signal.HapticSignal {
+  }
+
+  public abstract class HapticSignal {
+  }
+
+  public abstract class InfiniteSignal extends androidx.core.haptics.signal.HapticSignal {
+  }
+
+  public final class PredefinedEffectSignal extends androidx.core.haptics.signal.FiniteSignal {
+    method public static androidx.core.haptics.signal.PredefinedEffectSignal predefinedClick();
+    method public static androidx.core.haptics.signal.PredefinedEffectSignal predefinedDoubleClick();
+    method public static androidx.core.haptics.signal.PredefinedEffectSignal predefinedHeavyClick();
+    method public static androidx.core.haptics.signal.PredefinedEffectSignal predefinedTick();
+    field public static final androidx.core.haptics.signal.PredefinedEffectSignal.Companion Companion;
+  }
+
+  public static final class PredefinedEffectSignal.Companion {
+    method public androidx.core.haptics.signal.PredefinedEffectSignal predefinedClick();
+    method public androidx.core.haptics.signal.PredefinedEffectSignal predefinedDoubleClick();
+    method public androidx.core.haptics.signal.PredefinedEffectSignal predefinedHeavyClick();
+    method public androidx.core.haptics.signal.PredefinedEffectSignal predefinedTick();
+  }
+
+  public final class RepeatingWaveformSignal extends androidx.core.haptics.signal.InfiniteSignal {
+    method public androidx.core.haptics.signal.WaveformSignal? getInitialWaveform();
+    method public androidx.core.haptics.signal.WaveformSignal getRepeatingWaveform();
+    property public final androidx.core.haptics.signal.WaveformSignal? initialWaveform;
+    property public final androidx.core.haptics.signal.WaveformSignal repeatingWaveform;
+  }
+
+  public final class WaveformSignal extends androidx.core.haptics.signal.FiniteSignal {
+    ctor public WaveformSignal(java.util.List<? extends androidx.core.haptics.signal.WaveformSignal.Atom> atoms);
+    method public java.util.List<androidx.core.haptics.signal.WaveformSignal.Atom> getAtoms();
+    method @RequiresApi(android.os.Build.VERSION_CODES.O) public static androidx.core.haptics.signal.WaveformSignal.ConstantVibrationAtom off(java.time.Duration duration);
+    method public static androidx.core.haptics.signal.WaveformSignal.ConstantVibrationAtom off(long durationMillis);
+    method @RequiresApi(android.os.Build.VERSION_CODES.O) public static androidx.core.haptics.signal.WaveformSignal.ConstantVibrationAtom on(java.time.Duration duration);
+    method @RequiresApi(android.os.Build.VERSION_CODES.O) public static androidx.core.haptics.signal.WaveformSignal.ConstantVibrationAtom on(java.time.Duration duration, @FloatRange(from=0.0, to=1.0) float amplitude);
+    method public static androidx.core.haptics.signal.WaveformSignal.ConstantVibrationAtom on(long durationMillis);
+    method public static androidx.core.haptics.signal.WaveformSignal.ConstantVibrationAtom on(long durationMillis, @FloatRange(from=0.0, to=1.0) float amplitude);
+    method public androidx.core.haptics.signal.RepeatingWaveformSignal repeat();
+    method public static androidx.core.haptics.signal.RepeatingWaveformSignal repeatingWaveformOf(androidx.core.haptics.signal.WaveformSignal.Atom... atoms);
+    method public androidx.core.haptics.signal.RepeatingWaveformSignal thenRepeat(androidx.core.haptics.signal.WaveformSignal waveformToRepeat);
+    method public androidx.core.haptics.signal.RepeatingWaveformSignal thenRepeat(androidx.core.haptics.signal.WaveformSignal.Atom... atoms);
+    method public static androidx.core.haptics.signal.WaveformSignal waveformOf(androidx.core.haptics.signal.WaveformSignal.Atom... atoms);
+    property public final java.util.List<androidx.core.haptics.signal.WaveformSignal.Atom> atoms;
+    field public static final androidx.core.haptics.signal.WaveformSignal.Companion Companion;
+  }
+
+  public abstract static class WaveformSignal.Atom {
+  }
+
+  public static final class WaveformSignal.Companion {
+    method @RequiresApi(android.os.Build.VERSION_CODES.O) public androidx.core.haptics.signal.WaveformSignal.ConstantVibrationAtom off(java.time.Duration duration);
+    method public androidx.core.haptics.signal.WaveformSignal.ConstantVibrationAtom off(long durationMillis);
+    method @RequiresApi(android.os.Build.VERSION_CODES.O) public androidx.core.haptics.signal.WaveformSignal.ConstantVibrationAtom on(java.time.Duration duration);
+    method @RequiresApi(android.os.Build.VERSION_CODES.O) public androidx.core.haptics.signal.WaveformSignal.ConstantVibrationAtom on(java.time.Duration duration, @FloatRange(from=0.0, to=1.0) float amplitude);
+    method public androidx.core.haptics.signal.WaveformSignal.ConstantVibrationAtom on(long durationMillis);
+    method public androidx.core.haptics.signal.WaveformSignal.ConstantVibrationAtom on(long durationMillis, @FloatRange(from=0.0, to=1.0) float amplitude);
+    method public androidx.core.haptics.signal.RepeatingWaveformSignal repeatingWaveformOf(androidx.core.haptics.signal.WaveformSignal.Atom... atoms);
+    method public androidx.core.haptics.signal.WaveformSignal waveformOf(androidx.core.haptics.signal.WaveformSignal.Atom... atoms);
+  }
+
+  public static final class WaveformSignal.ConstantVibrationAtom extends androidx.core.haptics.signal.WaveformSignal.Atom {
+    method public float getAmplitude();
+    method public long getDurationMillis();
+    property public final float amplitude;
+    property public final long durationMillis;
+    field public static final androidx.core.haptics.signal.WaveformSignal.ConstantVibrationAtom.Companion Companion;
+    field public static final float DEFAULT_AMPLITUDE = -1.0f;
+  }
+
+  public static final class WaveformSignal.ConstantVibrationAtom.Companion {
   }
 
 }
diff --git a/core/haptics/haptics/api/restricted_current.txt b/core/haptics/haptics/api/restricted_current.txt
index 87cfe87..b4b7e54 100644
--- a/core/haptics/haptics/api/restricted_current.txt
+++ b/core/haptics/haptics/api/restricted_current.txt
@@ -3,7 +3,7 @@
 
   public interface HapticManager {
     method public static androidx.core.haptics.HapticManager create(android.content.Context context);
-    method @RequiresPermission(android.Manifest.permission.VIBRATE) public void play(androidx.core.haptics.signal.PredefinedEffect effect);
+    method @RequiresPermission(android.Manifest.permission.VIBRATE) public void play(androidx.core.haptics.signal.HapticSignal signal);
     field public static final androidx.core.haptics.HapticManager.Companion Companion;
   }
 
@@ -15,15 +15,155 @@
 
 package androidx.core.haptics.signal {
 
-  public final class PredefinedEffect {
-    field public static final androidx.core.haptics.signal.PredefinedEffect.Companion Companion;
-    field public static final androidx.core.haptics.signal.PredefinedEffect PredefinedClick;
-    field public static final androidx.core.haptics.signal.PredefinedEffect PredefinedDoubleClick;
-    field public static final androidx.core.haptics.signal.PredefinedEffect PredefinedHeavyClick;
-    field public static final androidx.core.haptics.signal.PredefinedEffect PredefinedTick;
+  public final class CompositionSignal extends androidx.core.haptics.signal.FiniteSignal {
+    ctor public CompositionSignal(java.util.List<? extends androidx.core.haptics.signal.CompositionSignal.Atom> atoms);
+    method public static androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom click();
+    method public static androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom click(optional @FloatRange(from=0.0, to=1.0) float amplitudeScale);
+    method public static androidx.core.haptics.signal.CompositionSignal compositionOf(androidx.core.haptics.signal.CompositionSignal.Atom... atoms);
+    method public java.util.List<androidx.core.haptics.signal.CompositionSignal.Atom> getAtoms();
+    method public static androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom lowTick();
+    method public static androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom lowTick(optional @FloatRange(from=0.0, to=1.0) float amplitudeScale);
+    method @RequiresApi(android.os.Build.VERSION_CODES.O) public static androidx.core.haptics.signal.CompositionSignal.OffAtom off(java.time.Duration duration);
+    method public static androidx.core.haptics.signal.CompositionSignal.OffAtom off(long durationMillis);
+    method public static androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom quickFall();
+    method public static androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom quickFall(optional @FloatRange(from=0.0, to=1.0) float amplitudeScale);
+    method public static androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom quickRise();
+    method public static androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom quickRise(optional @FloatRange(from=0.0, to=1.0) float amplitudeScale);
+    method public static androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom slowRise();
+    method public static androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom slowRise(optional @FloatRange(from=0.0, to=1.0) float amplitudeScale);
+    method public static androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom spin();
+    method public static androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom spin(optional @FloatRange(from=0.0, to=1.0) float amplitudeScale);
+    method public static androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom thud();
+    method public static androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom thud(optional @FloatRange(from=0.0, to=1.0) float amplitudeScale);
+    method public static androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom tick();
+    method public static androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom tick(optional @FloatRange(from=0.0, to=1.0) float amplitudeScale);
+    property public final java.util.List<androidx.core.haptics.signal.CompositionSignal.Atom> atoms;
+    field public static final androidx.core.haptics.signal.CompositionSignal.Companion Companion;
   }
 
-  public static final class PredefinedEffect.Companion {
+  public abstract static class CompositionSignal.Atom {
+  }
+
+  public static final class CompositionSignal.Companion {
+    method public androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom click();
+    method public androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom click(optional @FloatRange(from=0.0, to=1.0) float amplitudeScale);
+    method public androidx.core.haptics.signal.CompositionSignal compositionOf(androidx.core.haptics.signal.CompositionSignal.Atom... atoms);
+    method public androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom lowTick();
+    method public androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom lowTick(optional @FloatRange(from=0.0, to=1.0) float amplitudeScale);
+    method @RequiresApi(android.os.Build.VERSION_CODES.O) public androidx.core.haptics.signal.CompositionSignal.OffAtom off(java.time.Duration duration);
+    method public androidx.core.haptics.signal.CompositionSignal.OffAtom off(long durationMillis);
+    method public androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom quickFall();
+    method public androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom quickFall(optional @FloatRange(from=0.0, to=1.0) float amplitudeScale);
+    method public androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom quickRise();
+    method public androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom quickRise(optional @FloatRange(from=0.0, to=1.0) float amplitudeScale);
+    method public androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom slowRise();
+    method public androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom slowRise(optional @FloatRange(from=0.0, to=1.0) float amplitudeScale);
+    method public androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom spin();
+    method public androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom spin(optional @FloatRange(from=0.0, to=1.0) float amplitudeScale);
+    method public androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom thud();
+    method public androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom thud(optional @FloatRange(from=0.0, to=1.0) float amplitudeScale);
+    method public androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom tick();
+    method public androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom tick(optional @FloatRange(from=0.0, to=1.0) float amplitudeScale);
+  }
+
+  public static final class CompositionSignal.OffAtom extends androidx.core.haptics.signal.CompositionSignal.Atom {
+    method public long getDurationMillis();
+    property public final long durationMillis;
+  }
+
+  public static final class CompositionSignal.PrimitiveAtom extends androidx.core.haptics.signal.CompositionSignal.Atom {
+    method public float getAmplitudeScale();
+    method public int getType();
+    method public androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom withAmplitudeScale(@FloatRange(from=0.0, to=1.0) float newAmplitudeScale);
+    property public final float amplitudeScale;
+    property public final int type;
+    field public static final int CLICK = 1; // 0x1
+    field public static final androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom.Companion Companion;
+    field public static final int LOW_TICK = 8; // 0x8
+    field public static final int QUICK_FALL = 6; // 0x6
+    field public static final int QUICK_RISE = 4; // 0x4
+    field public static final int SLOW_RISE = 5; // 0x5
+    field public static final int SPIN = 3; // 0x3
+    field public static final int THUD = 2; // 0x2
+    field public static final int TICK = 7; // 0x7
+  }
+
+  public static final class CompositionSignal.PrimitiveAtom.Companion {
+  }
+
+  public abstract class FiniteSignal extends androidx.core.haptics.signal.HapticSignal {
+  }
+
+  public abstract class HapticSignal {
+  }
+
+  public abstract class InfiniteSignal extends androidx.core.haptics.signal.HapticSignal {
+  }
+
+  public final class PredefinedEffectSignal extends androidx.core.haptics.signal.FiniteSignal {
+    method public static androidx.core.haptics.signal.PredefinedEffectSignal predefinedClick();
+    method public static androidx.core.haptics.signal.PredefinedEffectSignal predefinedDoubleClick();
+    method public static androidx.core.haptics.signal.PredefinedEffectSignal predefinedHeavyClick();
+    method public static androidx.core.haptics.signal.PredefinedEffectSignal predefinedTick();
+    field public static final androidx.core.haptics.signal.PredefinedEffectSignal.Companion Companion;
+  }
+
+  public static final class PredefinedEffectSignal.Companion {
+    method public androidx.core.haptics.signal.PredefinedEffectSignal predefinedClick();
+    method public androidx.core.haptics.signal.PredefinedEffectSignal predefinedDoubleClick();
+    method public androidx.core.haptics.signal.PredefinedEffectSignal predefinedHeavyClick();
+    method public androidx.core.haptics.signal.PredefinedEffectSignal predefinedTick();
+  }
+
+  public final class RepeatingWaveformSignal extends androidx.core.haptics.signal.InfiniteSignal {
+    method public androidx.core.haptics.signal.WaveformSignal? getInitialWaveform();
+    method public androidx.core.haptics.signal.WaveformSignal getRepeatingWaveform();
+    property public final androidx.core.haptics.signal.WaveformSignal? initialWaveform;
+    property public final androidx.core.haptics.signal.WaveformSignal repeatingWaveform;
+  }
+
+  public final class WaveformSignal extends androidx.core.haptics.signal.FiniteSignal {
+    ctor public WaveformSignal(java.util.List<? extends androidx.core.haptics.signal.WaveformSignal.Atom> atoms);
+    method public java.util.List<androidx.core.haptics.signal.WaveformSignal.Atom> getAtoms();
+    method @RequiresApi(android.os.Build.VERSION_CODES.O) public static androidx.core.haptics.signal.WaveformSignal.ConstantVibrationAtom off(java.time.Duration duration);
+    method public static androidx.core.haptics.signal.WaveformSignal.ConstantVibrationAtom off(long durationMillis);
+    method @RequiresApi(android.os.Build.VERSION_CODES.O) public static androidx.core.haptics.signal.WaveformSignal.ConstantVibrationAtom on(java.time.Duration duration);
+    method @RequiresApi(android.os.Build.VERSION_CODES.O) public static androidx.core.haptics.signal.WaveformSignal.ConstantVibrationAtom on(java.time.Duration duration, @FloatRange(from=0.0, to=1.0) float amplitude);
+    method public static androidx.core.haptics.signal.WaveformSignal.ConstantVibrationAtom on(long durationMillis);
+    method public static androidx.core.haptics.signal.WaveformSignal.ConstantVibrationAtom on(long durationMillis, @FloatRange(from=0.0, to=1.0) float amplitude);
+    method public androidx.core.haptics.signal.RepeatingWaveformSignal repeat();
+    method public static androidx.core.haptics.signal.RepeatingWaveformSignal repeatingWaveformOf(androidx.core.haptics.signal.WaveformSignal.Atom... atoms);
+    method public androidx.core.haptics.signal.RepeatingWaveformSignal thenRepeat(androidx.core.haptics.signal.WaveformSignal waveformToRepeat);
+    method public androidx.core.haptics.signal.RepeatingWaveformSignal thenRepeat(androidx.core.haptics.signal.WaveformSignal.Atom... atoms);
+    method public static androidx.core.haptics.signal.WaveformSignal waveformOf(androidx.core.haptics.signal.WaveformSignal.Atom... atoms);
+    property public final java.util.List<androidx.core.haptics.signal.WaveformSignal.Atom> atoms;
+    field public static final androidx.core.haptics.signal.WaveformSignal.Companion Companion;
+  }
+
+  public abstract static class WaveformSignal.Atom {
+  }
+
+  public static final class WaveformSignal.Companion {
+    method @RequiresApi(android.os.Build.VERSION_CODES.O) public androidx.core.haptics.signal.WaveformSignal.ConstantVibrationAtom off(java.time.Duration duration);
+    method public androidx.core.haptics.signal.WaveformSignal.ConstantVibrationAtom off(long durationMillis);
+    method @RequiresApi(android.os.Build.VERSION_CODES.O) public androidx.core.haptics.signal.WaveformSignal.ConstantVibrationAtom on(java.time.Duration duration);
+    method @RequiresApi(android.os.Build.VERSION_CODES.O) public androidx.core.haptics.signal.WaveformSignal.ConstantVibrationAtom on(java.time.Duration duration, @FloatRange(from=0.0, to=1.0) float amplitude);
+    method public androidx.core.haptics.signal.WaveformSignal.ConstantVibrationAtom on(long durationMillis);
+    method public androidx.core.haptics.signal.WaveformSignal.ConstantVibrationAtom on(long durationMillis, @FloatRange(from=0.0, to=1.0) float amplitude);
+    method public androidx.core.haptics.signal.RepeatingWaveformSignal repeatingWaveformOf(androidx.core.haptics.signal.WaveformSignal.Atom... atoms);
+    method public androidx.core.haptics.signal.WaveformSignal waveformOf(androidx.core.haptics.signal.WaveformSignal.Atom... atoms);
+  }
+
+  public static final class WaveformSignal.ConstantVibrationAtom extends androidx.core.haptics.signal.WaveformSignal.Atom {
+    method public float getAmplitude();
+    method public long getDurationMillis();
+    property public final float amplitude;
+    property public final long durationMillis;
+    field public static final androidx.core.haptics.signal.WaveformSignal.ConstantVibrationAtom.Companion Companion;
+    field public static final float DEFAULT_AMPLITUDE = -1.0f;
+  }
+
+  public static final class WaveformSignal.ConstantVibrationAtom.Companion {
   }
 
 }
diff --git a/core/haptics/haptics/build.gradle b/core/haptics/haptics/build.gradle
index 203d4db..7dc493a 100644
--- a/core/haptics/haptics/build.gradle
+++ b/core/haptics/haptics/build.gradle
@@ -15,7 +15,6 @@
  */
 
 import androidx.build.LibraryType
-import androidx.build.RunApiTasks
 
 plugins {
     id("AndroidXPlugin")
@@ -33,8 +32,7 @@
 
     androidTestImplementation(libs.testCore)
     androidTestImplementation(libs.testRunner)
-    androidTestImplementation(libs.mockitoCore4)
-    androidTestImplementation(libs.dexmakerMockitoInline)
+    implementation(libs.truth)
 }
 
 android {
diff --git a/core/haptics/haptics/integration-tests/demos/src/main/AndroidManifest.xml b/core/haptics/haptics/integration-tests/demos/src/main/AndroidManifest.xml
index 4c19b57..ea32d19 100644
--- a/core/haptics/haptics/integration-tests/demos/src/main/AndroidManifest.xml
+++ b/core/haptics/haptics/integration-tests/demos/src/main/AndroidManifest.xml
@@ -22,7 +22,7 @@
         android:theme="@style/AppTheme">
         <activity
             android:allowBackup="false"
-            android:name=".HapticSamplesActivity"
+            android:name=".HapticDemosActivity"
             android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
diff --git a/core/haptics/haptics/integration-tests/demos/src/main/java/androidx/core/haptics/demos/HapticDemosActivity.kt b/core/haptics/haptics/integration-tests/demos/src/main/java/androidx/core/haptics/demos/HapticDemosActivity.kt
new file mode 100644
index 0000000..b147e5c
--- /dev/null
+++ b/core/haptics/haptics/integration-tests/demos/src/main/java/androidx/core/haptics/demos/HapticDemosActivity.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.haptics.demos
+
+import android.os.Bundle
+import android.widget.Button
+import androidx.appcompat.app.AppCompatActivity
+import androidx.core.haptics.HapticManager
+import androidx.core.haptics.signal.CompositionSignal.Companion.click
+import androidx.core.haptics.signal.CompositionSignal.Companion.compositionOf
+import androidx.core.haptics.signal.PredefinedEffectSignal.Companion.predefinedClick
+import androidx.core.haptics.signal.WaveformSignal.Companion.off
+import androidx.core.haptics.signal.WaveformSignal.Companion.on
+import androidx.core.haptics.signal.WaveformSignal.Companion.waveformOf
+
+/**
+ * Demonstrations of multiple haptic signal samples.
+ */
+class HapticDemosActivity : AppCompatActivity() {
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContentView(R.layout.haptics_demos_activity)
+
+        val hapticManager = HapticManager.create(this)
+        findViewById<Button>(R.id.standard_click_btn).setOnClickListener {
+            hapticManager.play(predefinedClick())
+        }
+        findViewById<Button>(R.id.scaled_click_btn).setOnClickListener {
+            hapticManager.play(compositionOf(click().withAmplitudeScale(0.8f)))
+        }
+        findViewById<Button>(R.id.on_off_pattern_btn).setOnClickListener {
+            hapticManager.play(
+                waveformOf(
+                    on(durationMillis = 350),
+                    off(durationMillis = 250),
+                    on(durationMillis = 350),
+                )
+            )
+        }
+        findViewById<Button>(R.id.repeating_waveform_btn).setOnClickListener {
+            hapticManager.play(
+                waveformOf(
+                    on(durationMillis = 20),
+                    off(durationMillis = 50),
+                    on(durationMillis = 20),
+                ).thenRepeat(
+                    // 500ms off
+                    off(durationMillis = 500),
+                    // 600ms ramp up with 50% increments
+                    on(durationMillis = 100, amplitude = 0.1f),
+                    on(durationMillis = 100, amplitude = 0.15f),
+                    on(durationMillis = 100, amplitude = 0.22f),
+                    on(durationMillis = 100, amplitude = 0.34f),
+                    on(durationMillis = 100, amplitude = 0.51f),
+                    on(durationMillis = 100, amplitude = 0.76f),
+                    // 400ms at max amplitude
+                    on(durationMillis = 400, amplitude = 1f),
+                )
+            )
+        }
+    }
+}
diff --git a/core/haptics/haptics/integration-tests/demos/src/main/java/androidx/core/haptics/demos/HapticSamplesActivity.kt b/core/haptics/haptics/integration-tests/demos/src/main/java/androidx/core/haptics/demos/HapticSamplesActivity.kt
deleted file mode 100644
index 5fb1076..0000000
--- a/core/haptics/haptics/integration-tests/demos/src/main/java/androidx/core/haptics/demos/HapticSamplesActivity.kt
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.core.haptics.demos
-
-import android.os.Bundle
-import android.widget.Button
-import androidx.appcompat.app.AppCompatActivity
-import androidx.core.haptics.HapticManager
-import androidx.core.haptics.signal.PredefinedEffect.Companion.PredefinedClick
-
-/**
- * Demo with multiple selection of haptic effect samples.
- */
-class HapticSamplesActivity : AppCompatActivity() {
-
-    override fun onCreate(savedInstanceState: Bundle?) {
-        super.onCreate(savedInstanceState)
-        setContentView(R.layout.haptic_samples_activity)
-
-        val hapticManager = HapticManager.create(this)
-        findViewById<Button>(R.id.standard_click_btn).setOnClickListener {
-            hapticManager.play(PredefinedClick)
-        }
-    }
-}
diff --git a/core/haptics/haptics/integration-tests/demos/src/main/res/layout/haptic_samples_activity.xml b/core/haptics/haptics/integration-tests/demos/src/main/res/layout/haptics_demos_activity.xml
similarity index 64%
rename from core/haptics/haptics/integration-tests/demos/src/main/res/layout/haptic_samples_activity.xml
rename to core/haptics/haptics/integration-tests/demos/src/main/res/layout/haptics_demos_activity.xml
index 24002ee..8b48bab 100644
--- a/core/haptics/haptics/integration-tests/demos/src/main/res/layout/haptic_samples_activity.xml
+++ b/core/haptics/haptics/integration-tests/demos/src/main/res/layout/haptics_demos_activity.xml
@@ -20,7 +20,7 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:gravity="center"
-    tools:context="androidx.core.haptics.demos.HapticSamplesActivity">
+    tools:context=".HapticDemosActivity">
 
     <Button
         android:id="@+id/standard_click_btn"
@@ -28,4 +28,22 @@
         android:layout_height="wrap_content"
         android:text="@string/standard_click" />
 
+    <Button
+        android:id="@+id/scaled_click_btn"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/scaled_click" />
+
+    <Button
+        android:id="@+id/on_off_pattern_btn"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/on_off_pattern" />
+
+    <Button
+        android:id="@+id/repeating_waveform_btn"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/repeating_waveform" />
+
 </LinearLayout>
diff --git a/core/haptics/haptics/integration-tests/demos/src/main/res/values/donottranslate-strings.xml b/core/haptics/haptics/integration-tests/demos/src/main/res/values/donottranslate-strings.xml
index 903a0be..e79e071 100644
--- a/core/haptics/haptics/integration-tests/demos/src/main/res/values/donottranslate-strings.xml
+++ b/core/haptics/haptics/integration-tests/demos/src/main/res/values/donottranslate-strings.xml
@@ -17,4 +17,7 @@
 <resources>
     <string name="app_name">Haptic Demos</string>
     <string name="standard_click">Standard Click</string>
+    <string name="scaled_click">Scaled Click</string>
+    <string name="on_off_pattern">On/Off Pattern</string>
+    <string name="repeating_waveform">Repeating Waveform</string>
 </resources>
diff --git a/core/haptics/haptics/samples/src/main/java/androidx/core/haptics/samples/CompositionSignalSamples.kt b/core/haptics/haptics/samples/src/main/java/androidx/core/haptics/samples/CompositionSignalSamples.kt
new file mode 100644
index 0000000..856b999
--- /dev/null
+++ b/core/haptics/haptics/samples/src/main/java/androidx/core/haptics/samples/CompositionSignalSamples.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.haptics.samples
+
+import androidx.annotation.Sampled
+import androidx.core.haptics.signal.CompositionSignal.Companion.compositionOf
+import androidx.core.haptics.signal.CompositionSignal.Companion.off
+import androidx.core.haptics.signal.CompositionSignal.Companion.quickFall
+import androidx.core.haptics.signal.CompositionSignal.Companion.slowRise
+import androidx.core.haptics.signal.CompositionSignal.Companion.thud
+
+/**
+ * Sample showing how to create a composition signal with scaled effects and off atoms.
+ */
+@Sampled
+fun CompositionSignalOfScaledEffectsAndOff() {
+    compositionOf(
+        slowRise().withAmplitudeScale(0.7f),
+        quickFall().withAmplitudeScale(0.7f),
+        off(durationMillis = 50),
+        thud(),
+    )
+}
diff --git a/core/haptics/haptics/samples/src/main/java/androidx/core/haptics/samples/HapticManagerSamples.kt b/core/haptics/haptics/samples/src/main/java/androidx/core/haptics/samples/HapticManagerSamples.kt
index e1d3df4..83ce76d 100644
--- a/core/haptics/haptics/samples/src/main/java/androidx/core/haptics/samples/HapticManagerSamples.kt
+++ b/core/haptics/haptics/samples/src/main/java/androidx/core/haptics/samples/HapticManagerSamples.kt
@@ -19,7 +19,12 @@
 import android.content.Context
 import androidx.annotation.Sampled
 import androidx.core.haptics.HapticManager
-import androidx.core.haptics.signal.PredefinedEffect.Companion.PredefinedClick
+import androidx.core.haptics.signal.CompositionSignal.Companion.compositionOf
+import androidx.core.haptics.signal.CompositionSignal.Companion.off
+import androidx.core.haptics.signal.CompositionSignal.Companion.quickFall
+import androidx.core.haptics.signal.CompositionSignal.Companion.slowRise
+import androidx.core.haptics.signal.CompositionSignal.Companion.thud
+import androidx.core.haptics.signal.PredefinedEffectSignal.Companion.predefinedClick
 
 /**
  * Sample showing how to play a standard click haptic effect on the system vibrator.
@@ -27,5 +32,20 @@
 @Sampled
 fun PlaySystemStandardClick(context: Context) {
     val hapticManager = HapticManager.create(context)
-    hapticManager.play(PredefinedClick)
+    hapticManager.play(predefinedClick())
+}
+
+/**
+ * Sample showing how to play a haptic signal on a vibrator.
+ */
+@Sampled
+fun PlayHapticSignal(hapticManager: HapticManager) {
+    hapticManager.play(
+        compositionOf(
+            slowRise(),
+            quickFall(),
+            off(durationMillis = 50),
+            thud(),
+        )
+    )
 }
diff --git a/core/haptics/haptics/samples/src/main/java/androidx/core/haptics/samples/WaveformSignalSamples.kt b/core/haptics/haptics/samples/src/main/java/androidx/core/haptics/samples/WaveformSignalSamples.kt
new file mode 100644
index 0000000..3b7b597
--- /dev/null
+++ b/core/haptics/haptics/samples/src/main/java/androidx/core/haptics/samples/WaveformSignalSamples.kt
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.haptics.samples
+
+import androidx.annotation.Sampled
+import androidx.core.haptics.signal.WaveformSignal
+import androidx.core.haptics.signal.WaveformSignal.Companion.off
+import androidx.core.haptics.signal.WaveformSignal.Companion.on
+import androidx.core.haptics.signal.WaveformSignal.Companion.repeatingWaveformOf
+import androidx.core.haptics.signal.WaveformSignal.Companion.waveformOf
+
+/**
+ * Sample showing how to create an on-off pattern.
+ */
+@Sampled
+fun PatternWaveform() {
+    waveformOf(
+        on(durationMillis = 250),
+        off(durationMillis = 350),
+        on(durationMillis = 250),
+    )
+}
+
+/**
+ * Sample showing how to create an infinite haptic signal a repeating step waveform.
+ */
+@Sampled
+fun PatternWaveformRepeat() {
+    waveformOf(
+        on(durationMillis = 100),
+        off(durationMillis = 50),
+        on(durationMillis = 100),
+        off(durationMillis = 50),
+    ).repeat()
+}
+
+/**
+ * Sample showing how to create an amplitude step waveform.
+ */
+@Sampled
+fun AmplitudeWaveform() {
+    waveformOf(
+        on(durationMillis = 10, amplitude = 0.2f),
+        on(durationMillis = 20, amplitude = 0.4f),
+        on(durationMillis = 30, amplitude = 0.8f),
+        on(durationMillis = 40, amplitude = 1f),
+        off(durationMillis = 50),
+        on(durationMillis = 50),
+    )
+}
+
+/**
+ * Sample showing how to create an amplitude step waveform.
+ */
+@Sampled
+fun RepeatingAmplitudeWaveform() {
+    repeatingWaveformOf(
+        on(durationMillis = 100),
+        off(durationMillis = 50),
+    )
+}
+
+/**
+ * Sample showing how to create an infinite haptic signal as repeating step waveform.
+ */
+@Sampled
+fun PatternThenRepeatExistingWaveform(waveformSignal: WaveformSignal) {
+    waveformOf(
+        on(durationMillis = 100),
+        off(durationMillis = 50),
+        on(durationMillis = 100),
+        off(durationMillis = 500),
+    ).thenRepeat(waveformSignal)
+}
+
+/**
+ * Sample showing how to create an infinite haptic signal as repeating step waveform.
+ */
+@Sampled
+fun PatternThenRepeatAmplitudeWaveform() {
+    waveformOf(
+        on(durationMillis = 100),
+        off(durationMillis = 50),
+        on(durationMillis = 100),
+    ).thenRepeat(
+        on(durationMillis = 500, amplitude = 0f),
+        on(durationMillis = 100, amplitude = 0.2f),
+        on(durationMillis = 200, amplitude = 0.4f),
+        on(durationMillis = 300, amplitude = 0.8f),
+        on(durationMillis = 400, amplitude = 1f),
+    )
+}
diff --git a/core/haptics/haptics/src/androidTest/java/androidx/core/haptics/PlayCompositionSignalTest.kt b/core/haptics/haptics/src/androidTest/java/androidx/core/haptics/PlayCompositionSignalTest.kt
new file mode 100644
index 0000000..584ffc637
--- /dev/null
+++ b/core/haptics/haptics/src/androidTest/java/androidx/core/haptics/PlayCompositionSignalTest.kt
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.haptics
+
+import android.os.Build
+import androidx.core.haptics.signal.CompositionSignal.Companion.click
+import androidx.core.haptics.signal.CompositionSignal.Companion.compositionOf
+import androidx.core.haptics.signal.CompositionSignal.Companion.lowTick
+import androidx.core.haptics.signal.CompositionSignal.Companion.off
+import androidx.core.haptics.signal.CompositionSignal.Companion.quickFall
+import androidx.core.haptics.signal.CompositionSignal.Companion.quickRise
+import androidx.core.haptics.signal.CompositionSignal.Companion.slowRise
+import androidx.core.haptics.signal.CompositionSignal.Companion.spin
+import androidx.core.haptics.signal.CompositionSignal.Companion.thud
+import androidx.core.haptics.signal.CompositionSignal.Companion.tick
+import androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom
+import androidx.core.haptics.testing.CompositionPrimitive
+import androidx.core.haptics.testing.FakeVibratorSubject.Companion.assertThat
+import androidx.core.haptics.testing.FullVibrator
+import androidx.core.haptics.testing.vibration
+import androidx.test.filters.SdkSuppress
+import androidx.test.filters.SmallTest
+import kotlin.time.Duration.Companion.milliseconds
+import org.junit.Assert.assertThrows
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.junit.runners.Parameterized
+
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.R)
+@RunWith(Parameterized::class)
+@SmallTest
+class PlayCompositionSignalSdk30AndAboveTest(
+    private val primitive: PrimitiveAtom,
+) {
+    private val fakeVibrator = FullVibrator()
+    private val hapticManager = HapticManager.createForVibrator(fakeVibrator)
+
+    @Test
+    fun play_vibratesWithSupportedPrimitives() {
+        hapticManager.play(
+            compositionOf(
+                primitive,
+                off(durationMillis = 50),
+                primitive.withAmplitudeScale(0.5f),
+                off(durationMillis = 100),
+                primitive.withAmplitudeScale(0.8f),
+                off(durationMillis = 200),
+            )
+        )
+        assertThat(fakeVibrator).vibratedExactly(
+            vibration(
+                CompositionPrimitive(primitive),
+                CompositionPrimitive(primitive, scale = 0.5f, delay = 50.milliseconds),
+                CompositionPrimitive(primitive, scale = 0.8f, delay = 100.milliseconds),
+                // Skips trailing 200ms delay from vibrate call
+            )
+        )
+    }
+
+    companion object {
+
+        @JvmStatic
+        @Parameterized.Parameters(name = "primitive:{0}")
+        fun data(): Collection<Any> {
+            val primitives = mutableListOf(
+                tick(),
+                click(),
+                slowRise(),
+                quickRise(),
+                quickFall(),
+            )
+            if (Build.VERSION.SDK_INT >= 31) {
+                primitives.apply {
+                    add(lowTick())
+                    add(spin())
+                    add(thud())
+                }
+            }
+            return primitives
+        }
+    }
+}
+
+@SdkSuppress(maxSdkVersion = Build.VERSION_CODES.Q)
+@RunWith(Parameterized::class)
+@SmallTest
+class PlayCompositionSignalBelowSdk30Test(
+    private val primitive: PrimitiveAtom,
+) {
+    private val fakeVibrator = FullVibrator()
+    private val hapticManager = HapticManager.createForVibrator(fakeVibrator)
+
+    @Test
+    fun play_doesNotVibrate() {
+        hapticManager.play(compositionOf(primitive))
+        assertThat(fakeVibrator).neverVibrated()
+    }
+
+    companion object {
+
+        @JvmStatic
+        @Parameterized.Parameters(name = "primitive:{0}")
+        fun data(): Collection<Any> = mutableListOf(
+            tick(),
+            click(),
+            slowRise(),
+            quickRise(),
+            quickFall(),
+            lowTick(),
+            spin(),
+            thud(),
+        )
+    }
+}
+
+@RunWith(JUnit4::class)
+@SmallTest
+class PlayCompositionSignalPartialPrimitiveSdkSupportTest {
+    private val fakeVibrator = FullVibrator()
+    private val hapticManager = HapticManager.createForVibrator(fakeVibrator)
+
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.R, maxSdkVersion = Build.VERSION_CODES.R)
+    @Test
+    fun play_api30AndPrimitiveFromApi31AndAbove_doesNotVibrate() {
+        hapticManager.play(compositionOf(lowTick()))
+        hapticManager.play(compositionOf(thud()))
+        hapticManager.play(compositionOf(spin()))
+        // Mix supported/unsupported primitives
+        hapticManager.play(compositionOf(tick(), lowTick()))
+        assertThat(fakeVibrator).neverVibrated()
+    }
+}
+
+@RunWith(JUnit4::class)
+@SmallTest
+class PlayCompositionSignalAllSdksTest {
+
+    @Test
+    fun compositionOf_withNoAtom_throwsException() {
+        assertThrows(IllegalArgumentException::class.java) {
+            compositionOf()
+        }
+    }
+
+    @Test
+    fun off_withNegativeDuration_throwsException() {
+        assertThrows(IllegalArgumentException::class.java) {
+            off(durationMillis = -10)
+        }
+    }
+
+    @Test
+    fun withAmplitudeScale_withAmplitudeLargerThanOne_throwsException() {
+        assertThrows(IllegalArgumentException::class.java) {
+            click().withAmplitudeScale(2f)
+        }
+    }
+
+    @Test
+    fun withAmplitudeScale_withNegativeAmplitude_throwsException() {
+        assertThrows(IllegalArgumentException::class.java) {
+            click().withAmplitudeScale(-1f)
+        }
+    }
+}
diff --git a/core/haptics/haptics/src/androidTest/java/androidx/core/haptics/PlayPredefinedEffectSignalTest.kt b/core/haptics/haptics/src/androidTest/java/androidx/core/haptics/PlayPredefinedEffectSignalTest.kt
new file mode 100644
index 0000000..f5572c1
--- /dev/null
+++ b/core/haptics/haptics/src/androidTest/java/androidx/core/haptics/PlayPredefinedEffectSignalTest.kt
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.haptics
+
+import android.os.Build
+import androidx.core.haptics.signal.PredefinedEffectSignal
+import androidx.core.haptics.signal.PredefinedEffectSignal.Companion.predefinedClick
+import androidx.core.haptics.signal.PredefinedEffectSignal.Companion.predefinedDoubleClick
+import androidx.core.haptics.signal.PredefinedEffectSignal.Companion.predefinedHeavyClick
+import androidx.core.haptics.signal.PredefinedEffectSignal.Companion.predefinedTick
+import androidx.core.haptics.testing.FakeVibratorSubject.Companion.assertThat
+import androidx.core.haptics.testing.PredefinedEffectsAndAmplitudeVibrator
+import androidx.core.haptics.testing.vibration
+import androidx.test.filters.SdkSuppress
+import androidx.test.filters.SmallTest
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+@RunWith(Parameterized::class)
+@SmallTest
+class PlayPredefinedEffectSignalTest(
+    private val effect: PredefinedEffectSignal,
+    private val expectedFallbackPattern: LongArray,
+) {
+    private val fakeVibrator = PredefinedEffectsAndAmplitudeVibrator()
+    private val hapticManager = HapticManager.createForVibrator(fakeVibrator)
+
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.Q)
+    @Test
+    fun play_api29AndAbove_vibratesWithPredefinedEffect() {
+        hapticManager.play(effect)
+        assertThat(fakeVibrator).vibratedExactly(vibration(effect))
+    }
+
+    @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.P)
+    @Test
+    fun play_belowApi29_vibratesWithFallbackPattern() {
+        hapticManager.play(effect)
+        assertThat(fakeVibrator).vibratedExactly(vibration(expectedFallbackPattern))
+    }
+
+    companion object {
+
+        @JvmStatic
+        @Parameterized.Parameters(name = "effect:{0}, expectedFallbackPattern:{1}")
+        fun data(): Collection<Array<Any>> = listOf(
+            arrayOf(predefinedTick(), longArrayOf(0, 10)),
+            arrayOf(predefinedClick(), longArrayOf(0, 20)),
+            arrayOf(predefinedHeavyClick(), longArrayOf(0, 30)),
+            arrayOf(predefinedDoubleClick(), longArrayOf(0, 30, 100, 30)),
+        )
+    }
+}
diff --git a/core/haptics/haptics/src/androidTest/java/androidx/core/haptics/PlayPredefinedEffectTest.kt b/core/haptics/haptics/src/androidTest/java/androidx/core/haptics/PlayPredefinedEffectTest.kt
deleted file mode 100644
index fab916e..0000000
--- a/core/haptics/haptics/src/androidTest/java/androidx/core/haptics/PlayPredefinedEffectTest.kt
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.core.haptics
-
-import android.os.Build
-import android.os.VibrationEffect
-import android.os.Vibrator
-import androidx.core.haptics.signal.PredefinedEffect
-import androidx.core.haptics.signal.PredefinedEffect.Companion.PredefinedClick
-import androidx.core.haptics.signal.PredefinedEffect.Companion.PredefinedDoubleClick
-import androidx.core.haptics.signal.PredefinedEffect.Companion.PredefinedHeavyClick
-import androidx.core.haptics.signal.PredefinedEffect.Companion.PredefinedTick
-import androidx.test.filters.SdkSuppress
-import androidx.test.filters.SmallTest
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.Parameterized
-import org.mockito.Mockito.eq
-import org.mockito.Mockito.mock
-import org.mockito.Mockito.verify
-
-@RunWith(Parameterized::class)
-@SmallTest
-class PlayPredefinedEffectTest(
-    private val effect: PredefinedEffect,
-    private val expectedFallbackPattern: LongArray,
-) {
-    // Vibrator has package-protected constructor and cannot be extended by a FakeVibrator
-    // TODO(b/275084444): replace with a testable interface to allow all SDK levels
-    private val vibrator = mock(Vibrator::class.java)
-    private val hapticManager = HapticManager.createForVibrator(vibrator)
-
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.Q)
-    @Test
-    fun perform_api29AndAbove() {
-        hapticManager.play(effect)
-        verify(vibrator).vibrate(eq(VibrationEffect.createPredefined(effect.effectId)))
-    }
-
-    @Suppress("DEPRECATION") // Verifying deprecated APIs are triggered by this test
-    @SdkSuppress(
-        minSdkVersion = 28, // TODO(b/275084444): remove this once we introduce fake vibrator
-        maxSdkVersion = Build.VERSION_CODES.P
-    )
-    @Test
-    fun perform_belowApi29() {
-        hapticManager.play(effect)
-        verify(vibrator).vibrate(eq(expectedFallbackPattern), eq(-1))
-    }
-
-    companion object {
-
-        @JvmStatic
-        @Parameterized.Parameters(name = "effect:{0}, expectedFallbackPattern:{1}")
-        fun data(): Collection<Array<Any>> = listOf(
-            arrayOf(PredefinedTick, longArrayOf(0, 10)),
-            arrayOf(PredefinedClick, longArrayOf(0, 20)),
-            arrayOf(PredefinedHeavyClick, longArrayOf(0, 30)),
-            arrayOf(PredefinedDoubleClick, longArrayOf(0, 30, 100, 30)),
-        )
-    }
-}
diff --git a/core/haptics/haptics/src/androidTest/java/androidx/core/haptics/PlayWaveformSignalTest.kt b/core/haptics/haptics/src/androidTest/java/androidx/core/haptics/PlayWaveformSignalTest.kt
new file mode 100644
index 0000000..cd7a70d
--- /dev/null
+++ b/core/haptics/haptics/src/androidTest/java/androidx/core/haptics/PlayWaveformSignalTest.kt
@@ -0,0 +1,279 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.haptics
+
+import android.os.Build
+import androidx.core.haptics.signal.WaveformSignal.Companion.off
+import androidx.core.haptics.signal.WaveformSignal.Companion.on
+import androidx.core.haptics.signal.WaveformSignal.Companion.repeatingWaveformOf
+import androidx.core.haptics.signal.WaveformSignal.Companion.waveformOf
+import androidx.core.haptics.testing.AmplitudeVibrator
+import androidx.core.haptics.testing.FakeVibratorSubject.Companion.assertThat
+import androidx.core.haptics.testing.PatternVibrator
+import androidx.core.haptics.testing.vibration
+import androidx.test.filters.SdkSuppress
+import androidx.test.filters.SmallTest
+import org.junit.Assert.assertThrows
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+@RunWith(JUnit4::class)
+@SmallTest
+class PlayWaveformSignalSdk26AndAboveTest {
+    private val fakeVibrator = AmplitudeVibrator()
+    private val hapticManager = HapticManager.createForVibrator(fakeVibrator)
+
+    @Test
+    fun play_withOneShot_vibratesWithOneShotEffect() {
+        hapticManager.play(waveformOf(on(durationMillis = 10)))
+        hapticManager.play(waveformOf(on(durationMillis = 20, amplitude = 0.2f)))
+        assertThat(fakeVibrator).vibratedExactly(
+            vibration(timings = longArrayOf(10), amplitudes = intArrayOf(-1)),
+            vibration(timings = longArrayOf(20), amplitudes = intArrayOf(51)),
+        ).inOrder()
+    }
+
+    @Test
+    fun play_withAmplitudes_vibratesWithAmplitudes() {
+        hapticManager.play(
+            waveformOf(
+                on(durationMillis = 10, amplitude = 0.2f),
+                on(durationMillis = 20, amplitude = 0.8f),
+                on(durationMillis = 30, amplitude = 0f),
+                on(durationMillis = 40, amplitude = 1f),
+            )
+        )
+        assertThat(fakeVibrator).vibratedExactly(
+            vibration(
+                timings = longArrayOf(10, 20, 30, 40),
+                amplitudes = intArrayOf(51, 204, 0, 255),
+            )
+        )
+    }
+
+    @Test
+    fun play_withOnOffPattern_vibratesWithAmplitudes() {
+        hapticManager.play(
+            waveformOf(
+                on(durationMillis = 10),
+                off(durationMillis = 20),
+                on(durationMillis = 30),
+                off(durationMillis = 40),
+            )
+        )
+        assertThat(fakeVibrator).vibratedExactly(
+            vibration(
+                timings = longArrayOf(10, 20, 30, 40),
+                amplitudes = intArrayOf(-1, 0, -1, 0),
+            )
+        )
+    }
+
+    @Test
+    fun play_withRepeatingAmplitudes_vibratesWithRepeatIndex() {
+        hapticManager.play(
+            waveformOf(
+                on(durationMillis = 10, amplitude = 0.2f),
+                on(durationMillis = 20, amplitude = 0.4f),
+            ).thenRepeat(
+                on(durationMillis = 30, amplitude = 0.6f),
+                on(durationMillis = 40, amplitude = 0.8f),
+            )
+        )
+        assertThat(fakeVibrator).vibratedExactly(
+            vibration(
+                timings = longArrayOf(10, 20, 30, 40),
+                amplitudes = intArrayOf(51, 102, 153, 204),
+                repeat = 2,
+            )
+        )
+    }
+}
+
+@SdkSuppress(maxSdkVersion = Build.VERSION_CODES.N_MR1)
+@RunWith(JUnit4::class)
+@SmallTest
+class PlayWaveformSignalBelowSdk26Test {
+    private val fakeVibrator = PatternVibrator()
+    private val hapticManager = HapticManager.createForVibrator(fakeVibrator)
+
+    @Test
+    fun play_withOneShot_vibratesWithPatternForDefaultAndMaxAmplitudes() {
+        hapticManager.play(waveformOf(on(durationMillis = 10)))
+        hapticManager.play(waveformOf(on(durationMillis = 20, amplitude = 1f)))
+        hapticManager.play(waveformOf(on(durationMillis = 30, amplitude = 0.2f)))
+        assertThat(fakeVibrator).vibratedExactly(
+            vibration(pattern = longArrayOf(0, 10)),
+            vibration(pattern = longArrayOf(0, 20)),
+            // Ignores last request with non-default amplitude
+        ).inOrder()
+    }
+
+    @Test
+    fun play_withAmplitudes_doesNotVibrate() {
+        hapticManager.play(
+            waveformOf(
+                on(durationMillis = 10, amplitude = 0.2f),
+                on(durationMillis = 20, amplitude = 0.8f),
+                on(durationMillis = 30, amplitude = 0f),
+                on(durationMillis = 40, amplitude = 1f),
+            )
+        )
+        assertThat(fakeVibrator).neverVibrated()
+    }
+
+    @Test
+    fun play_withOnOffPattern_vibratesWithFallbackPattern() {
+        hapticManager.play(
+            waveformOf(
+                on(durationMillis = 10),
+                off(durationMillis = 20),
+                on(durationMillis = 30),
+                on(durationMillis = 40),
+                off(durationMillis = 50),
+                off(durationMillis = 60),
+            )
+        )
+        assertThat(fakeVibrator).vibratedExactly(
+            // OFF(0ms), ON(10ms), OFF(20ms), ON(30+40ms), OFF(50+60ms)
+            vibration(pattern = longArrayOf(0, 10, 20, 70, 110))
+        )
+    }
+
+    @Test
+    fun play_withOnOffMaxAmplitudePattern_vibratesWithFallbackPattern() {
+        hapticManager.play(
+            waveformOf(
+                on(durationMillis = 10),
+                on(durationMillis = 20, amplitude = 1f),
+                off(durationMillis = 30),
+                on(durationMillis = 40, amplitude = 0f),
+                on(durationMillis = 50),
+            )
+        )
+        assertThat(fakeVibrator).vibratedExactly(
+            // OFF(0ms), ON(10+20ms), OFF(30+40ms), ON(50ms)
+            vibration(pattern = longArrayOf(0, 30, 70, 50))
+        )
+    }
+
+    @Test
+    fun play_withRepeatingPattern_vibratesWithRepeatIndex() {
+        hapticManager.play(
+            repeatingWaveformOf(
+                off(durationMillis = 10),
+                on(durationMillis = 20),
+                off(durationMillis = 30),
+                off(durationMillis = 40),
+                on(durationMillis = 50),
+                on(durationMillis = 60),
+            )
+        )
+        assertThat(fakeVibrator).vibratedExactly(
+            vibration(
+                // OFF(10ms), ON(20ms), OFF(30+40ms), ON(50+60ms)
+                pattern = longArrayOf(10, 20, 70, 110),
+                repeat = 0,
+            )
+        )
+    }
+
+    @Test
+    fun play_withInitialAndRepeatingPattern_doesNotMergeInitialWithRepeatingPattern() {
+        hapticManager.play(
+            waveformOf(
+                on(durationMillis = 10),
+                off(durationMillis = 20),
+                off(durationMillis = 30),
+                on(durationMillis = 40),
+            ).thenRepeat(
+                on(durationMillis = 50),
+                on(durationMillis = 60),
+                off(durationMillis = 70),
+                off(durationMillis = 80),
+            )
+        )
+        assertThat(fakeVibrator).vibratedExactly(
+            vibration(
+                // Does not merge consecutive ON steps 40 and 50 because of repeat index.
+                // OFF(0ms), ON(10ms), OFF(20+30ms), ON(40ms), OFF(+0ms), ON(50+60ms), OFF(70+80ms)
+                pattern = longArrayOf(0, 10, 50, 40, 0, 110, 150),
+                repeat = 4,
+            )
+        )
+    }
+}
+
+@RunWith(JUnit4::class)
+@SmallTest
+class PlayWaveformSignalAllSdksTest {
+    private val fakeVibrator = AmplitudeVibrator()
+    private val hapticManager = HapticManager.createForVibrator(fakeVibrator)
+
+    @Test
+    fun play_withZeroDurationSignal_doesNotVibrate() {
+        hapticManager.play(waveformOf(on(durationMillis = 0)))
+        hapticManager.play(waveformOf(on(durationMillis = 0, amplitude = 0.2f)))
+        hapticManager.play(
+            waveformOf(
+                on(durationMillis = 0, amplitude = 0.2f),
+                on(durationMillis = 0, amplitude = 0.8f),
+                on(durationMillis = 0, amplitude = 0f),
+                on(durationMillis = 0, amplitude = 1f),
+                off(durationMillis = 0),
+            )
+        )
+        assertThat(fakeVibrator).neverVibrated()
+    }
+
+    @Test
+    fun waveformOf_withNoAtom_throwsException() {
+        assertThrows(IllegalArgumentException::class.java) {
+            waveformOf()
+        }
+    }
+
+    @Test
+    fun on_withAmplitudeLargerThanOne_throwsException() {
+        assertThrows(IllegalArgumentException::class.java) {
+            on(durationMillis = 0, amplitude = 1.1f)
+        }
+    }
+
+    @Test
+    fun on_withNegativeAmplitude_throwsException() {
+        assertThrows(IllegalArgumentException::class.java) {
+            on(durationMillis = 0, amplitude = -0.5f)
+        }
+    }
+
+    @Test
+    fun on_withNegativeDuration_throwsException() {
+        assertThrows(IllegalArgumentException::class.java) {
+            on(durationMillis = -10)
+        }
+    }
+
+    @Test
+    fun off_withNegativeDuration_throwsException() {
+        assertThrows(IllegalArgumentException::class.java) {
+            off(durationMillis = -10)
+        }
+    }
+}
diff --git a/core/haptics/haptics/src/androidTest/java/androidx/core/haptics/testing/FakeVibrator.kt b/core/haptics/haptics/src/androidTest/java/androidx/core/haptics/testing/FakeVibrator.kt
new file mode 100644
index 0000000..2ff140a
--- /dev/null
+++ b/core/haptics/haptics/src/androidTest/java/androidx/core/haptics/testing/FakeVibrator.kt
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.haptics.testing
+
+import android.os.Build
+import android.os.VibrationEffect
+import androidx.annotation.RequiresApi
+import androidx.core.haptics.PatternVibrationWrapper
+import androidx.core.haptics.VibrationEffectWrapper
+import androidx.core.haptics.VibrationWrapper
+import androidx.core.haptics.VibratorWrapper
+import androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom
+import androidx.core.haptics.signal.PredefinedEffectSignal
+import kotlin.time.Duration
+
+/**
+ * Fake [VibratorWrapper] implementation for testing.
+ */
+internal sealed class FakeVibrator(
+    private val amplitudeControlSupported: Boolean,
+    private val effectsSupported: IntArray? = null,
+    private val primitivesSupported: IntArray = intArrayOf(),
+) : VibratorWrapper {
+    private val vibrations: MutableList<VibrationWrapper> = mutableListOf()
+
+    override fun hasVibrator(): Boolean = true
+
+    override fun hasAmplitudeControl(): Boolean = amplitudeControlSupported
+
+    override fun areEffectsSupported(
+        effects: IntArray,
+    ): Array<VibratorWrapper.EffectSupport> =
+        effects.map {
+            when {
+                effectsSupported == null -> VibratorWrapper.EffectSupport.UNKNOWN
+                effectsSupported.contains(it) -> VibratorWrapper.EffectSupport.YES
+                else -> VibratorWrapper.EffectSupport.NO
+            }
+        }.toTypedArray()
+
+    override fun arePrimitivesSupported(primitives: IntArray): BooleanArray =
+        primitives.map { primitivesSupported.contains(it) }.toBooleanArray()
+
+    override fun vibrate(vibration: VibrationWrapper) {
+        vibrations.add(vibration)
+    }
+
+    override fun cancel() {
+        // No-op
+    }
+
+    /** Returns all requests sent to the [android.os.Vibrator], in order. */
+    internal fun vibrations(): List<VibrationWrapper> = vibrations
+}
+
+/**
+ * Vibrator that only supports on-off patterns.
+ */
+internal class PatternVibrator : FakeVibrator(
+    amplitudeControlSupported = false,
+)
+
+/**
+ * Vibrator that only supports amplitude control.
+ */
+internal class AmplitudeVibrator : FakeVibrator(
+    amplitudeControlSupported = true,
+)
+
+/**
+ * Vibrator that supports amplitude control and all predefined effects.
+ */
+internal class PredefinedEffectsAndAmplitudeVibrator : FakeVibrator(
+    amplitudeControlSupported = true,
+    effectsSupported = intArrayOf(
+        PredefinedEffectSignal.TICK,
+        PredefinedEffectSignal.CLICK,
+        PredefinedEffectSignal.HEAVY_CLICK,
+        PredefinedEffectSignal.DOUBLE_CLICK,
+    ),
+)
+
+/**
+ * Vibrator that supports amplitude control and all predefined and primitive effects.
+ */
+internal class FullVibrator : FakeVibrator(
+    amplitudeControlSupported = true,
+    effectsSupported = intArrayOf(
+        PredefinedEffectSignal.TICK,
+        PredefinedEffectSignal.CLICK,
+        PredefinedEffectSignal.HEAVY_CLICK,
+        PredefinedEffectSignal.DOUBLE_CLICK,
+    ),
+    primitivesSupported = intArrayOf(
+        PrimitiveAtom.LOW_TICK,
+        PrimitiveAtom.TICK,
+        PrimitiveAtom.CLICK,
+        PrimitiveAtom.SLOW_RISE,
+        PrimitiveAtom.QUICK_RISE,
+        PrimitiveAtom.QUICK_FALL,
+        PrimitiveAtom.SPIN,
+        PrimitiveAtom.THUD,
+    ),
+)
+
+/** Helper to create [android.os.VibrationEffect.Composition] entries. */
+internal data class CompositionPrimitive(
+    val primitiveId: Int,
+    val scale: Float,
+    val delayMs: Int,
+) {
+    constructor(
+        primitive: PrimitiveAtom,
+        scale: Float = primitive.amplitudeScale,
+        delay: Duration = Duration.ZERO,
+    ) : this(primitive.type, scale, delay.inWholeMilliseconds.toInt())
+}
+
+/** Helper to create [VibrationWrapper] request for a on-off pattern. */
+internal fun vibration(
+    pattern: LongArray,
+    repeat: Int = -1,
+): VibrationWrapper =
+    PatternVibrationWrapper(pattern, repeat)
+
+/** Helper to create [VibrationWrapper] request for a predefined effect. */
+@RequiresApi(Build.VERSION_CODES.Q)
+internal fun vibration(effect: PredefinedEffectSignal): VibrationWrapper =
+    VibrationEffectWrapper(VibrationEffect.createPredefined(effect.type))
+
+/** Helper to create [VibrationWrapper] request for a waveform effect. */
+@RequiresApi(Build.VERSION_CODES.O)
+internal fun vibration(
+    timings: LongArray,
+    amplitudes: IntArray,
+    repeat: Int = -1,
+): VibrationWrapper =
+    VibrationEffectWrapper(VibrationEffect.createWaveform(timings, amplitudes, repeat))
+
+/** Helper to create [VibrationWrapper] request for a primitive composition effect. */
+@RequiresApi(Build.VERSION_CODES.R)
+internal fun vibration(vararg primitives: CompositionPrimitive): VibrationWrapper {
+    return VibrationEffectWrapper(
+        VibrationEffect.startComposition().apply {
+            primitives.forEach { addPrimitive(it.primitiveId, it.scale, it.delayMs) }
+        }.compose()
+    )
+}
diff --git a/core/haptics/haptics/src/androidTest/java/androidx/core/haptics/testing/FakeVibratorSubject.kt b/core/haptics/haptics/src/androidTest/java/androidx/core/haptics/testing/FakeVibratorSubject.kt
new file mode 100644
index 0000000..9ab2ca2
--- /dev/null
+++ b/core/haptics/haptics/src/androidTest/java/androidx/core/haptics/testing/FakeVibratorSubject.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.haptics.testing
+
+import androidx.core.haptics.VibrationWrapper
+import com.google.common.truth.FailureMetadata
+import com.google.common.truth.Ordered
+import com.google.common.truth.Subject
+import com.google.common.truth.Subject.Factory
+import com.google.common.truth.Truth.assertAbout
+
+/**
+ * Truth extension for [FakeVibrator].
+ */
+internal class FakeVibratorSubject private constructor(
+    metadata: FailureMetadata?,
+    private val actual: FakeVibrator,
+) : Subject(metadata, actual) {
+
+    companion object {
+        private val SUBJECT_FACTORY: Factory<FakeVibratorSubject?, FakeVibrator> =
+            Factory { failureMetadata, subject -> FakeVibratorSubject(failureMetadata, subject) }
+
+        internal fun assertThat(vibrator: FakeVibrator): FakeVibratorSubject =
+            requireNotNull(assertAbout(SUBJECT_FACTORY).that(vibrator))
+    }
+
+    /**
+     * Checks the subject was requested to vibrate with exactly the provided parameters.
+     *
+     * To also test that the requests appear in the given order, make a call to inOrder() on the
+     * object returned by this method.
+     */
+    fun vibratedExactly(vararg expected: VibrationWrapper): Ordered =
+        check("vibrations()").that(actual.vibrations()).containsExactly(*expected)
+
+    /**
+     * Checks the subject has never requested to vibrate.
+     */
+    fun neverVibrated(): Unit =
+        check("vibrations()").that(actual.vibrations()).isEmpty()
+}
diff --git a/core/haptics/haptics/src/main/java/androidx/core/haptics/HapticManager.kt b/core/haptics/haptics/src/main/java/androidx/core/haptics/HapticManager.kt
index 1ca0bd0..37b74bd 100644
--- a/core/haptics/haptics/src/main/java/androidx/core/haptics/HapticManager.kt
+++ b/core/haptics/haptics/src/main/java/androidx/core/haptics/HapticManager.kt
@@ -19,11 +19,14 @@
 import android.content.Context
 import android.os.Vibrator
 import androidx.annotation.RequiresPermission
+import androidx.annotation.VisibleForTesting
+import androidx.core.content.ContextCompat
 import androidx.core.haptics.impl.HapticManagerImpl
-import androidx.core.haptics.signal.PredefinedEffect
+import androidx.core.haptics.impl.VibratorWrapperImpl
+import androidx.core.haptics.signal.HapticSignal
 
 /**
- * Manager for the vibrators of a device.
+ * Manager for interactions with a device vibrator.
  *
  * <p>If your process exits, any vibration you started will stop.
  */
@@ -32,35 +35,38 @@
     companion object {
 
         /**
-         * Creates haptic manager for the system vibrators.
+         * Creates a haptic manager for the system vibrator.
          *
-         * Sample code:
          * @sample androidx.core.haptics.samples.PlaySystemStandardClick
          *
-         * @param context Context to load the device vibrators.
-         * @return a new instance of HapticManager for the system vibrators.
+         * @param context Context to load the device vibrator.
+         * @return a new instance of HapticManager for the system vibrator.
          */
         @JvmStatic
         fun create(context: Context): HapticManager {
-            return HapticManagerImpl(context)
+            return HapticManagerImpl(
+                VibratorWrapperImpl(
+                    requireNotNull(ContextCompat.getSystemService(context, Vibrator::class.java)) {
+                        "Vibrator service not found"
+                    }
+                )
+            )
         }
 
-        /** Creates haptic manager for given vibrator. */
-        internal fun createForVibrator(vibrator: Vibrator): HapticManager {
+        /** Creates a haptic manager for the given vibrator. */
+        @VisibleForTesting
+        internal fun createForVibrator(vibrator: VibratorWrapper): HapticManager {
             return HapticManagerImpl(vibrator)
         }
     }
 
     /**
-     * Play a [PredefinedEffect].
+     * Play a [HapticSignal].
      *
-     * The app should be in the foreground for the vibration to happen.
+     * @sample androidx.core.haptics.samples.PlayHapticSignal
      *
-     * Sample code:
-     * @sample androidx.core.haptics.samples.PlaySystemStandardClick
-     *
-     * @param effect The predefined haptic effect to be played.
+     * @param signal The haptic signal to be played.
      */
     @RequiresPermission(android.Manifest.permission.VIBRATE)
-    fun play(effect: PredefinedEffect)
+    fun play(signal: HapticSignal)
 }
diff --git a/core/haptics/haptics/src/main/java/androidx/core/haptics/VibratorWrapper.kt b/core/haptics/haptics/src/main/java/androidx/core/haptics/VibratorWrapper.kt
new file mode 100644
index 0000000..683c071
--- /dev/null
+++ b/core/haptics/haptics/src/main/java/androidx/core/haptics/VibratorWrapper.kt
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.haptics
+
+import androidx.annotation.RequiresPermission
+
+/**
+ * Internal wrapper for [android.os.Vibrator] to enable fake implementations for testing.
+ */
+internal interface VibratorWrapper {
+    /** Check whether the hardware has a vibrator. */
+    fun hasVibrator(): Boolean
+
+    /** Check whether the vibrator has amplitude control. */
+    fun hasAmplitudeControl(): Boolean
+
+    /** Check whether the hardware supports each predefined effect type. */
+    fun areEffectsSupported(effects: IntArray): Array<EffectSupport>?
+
+    /** Check whether the hardware supports each primitive effect type. */
+    fun arePrimitivesSupported(primitives: IntArray): BooleanArray?
+
+    /** Vibrate with a given vibration effect or pattern. */
+    @RequiresPermission(android.Manifest.permission.VIBRATE)
+    fun vibrate(vibration: VibrationWrapper)
+
+    /** Cancel any ongoing vibration from this app and turns the vibrator off. */
+    @RequiresPermission(android.Manifest.permission.VIBRATE)
+    fun cancel()
+
+    /** Represents constants from [android.os.Vibrator.VIBRATION_EFFECT_SUPPORT_*]. */
+    enum class EffectSupport {
+        UNKNOWN, YES, NO
+    }
+}
+
+/**
+ * Represents different API levels of support for [android.os.Vibrator.vibrate] parameters.
+ */
+internal sealed interface VibrationWrapper
+
+/**
+ * Represents vibrations defined by on-off patterns.
+ */
+internal data class PatternVibrationWrapper(
+    val timings: LongArray,
+    val repeatIndex: Int,
+) : VibrationWrapper {
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (javaClass != other?.javaClass) return false
+
+        other as PatternVibrationWrapper
+
+        if (!timings.contentEquals(other.timings)) return false
+        if (repeatIndex != other.repeatIndex) return false
+
+        return true
+    }
+
+    override fun hashCode(): Int {
+        var result = timings.contentHashCode()
+        result = 31 * result + repeatIndex.hashCode()
+        return result
+    }
+}
+
+/**
+ * Represents vibrations defined by an instance of [android.os.VibrationEffect].
+ */
+internal data class VibrationEffectWrapper(
+    val vibrationEffect: Any,
+) : VibrationWrapper
diff --git a/core/haptics/haptics/src/main/java/androidx/core/haptics/impl/HapticManagerImpl.kt b/core/haptics/haptics/src/main/java/androidx/core/haptics/impl/HapticManagerImpl.kt
index a5c518c..bd249c9 100644
--- a/core/haptics/haptics/src/main/java/androidx/core/haptics/impl/HapticManagerImpl.kt
+++ b/core/haptics/haptics/src/main/java/androidx/core/haptics/impl/HapticManagerImpl.kt
@@ -16,72 +16,23 @@
 
 package androidx.core.haptics.impl
 
-import android.content.Context
-import android.os.Build.VERSION
-import android.os.VibrationEffect
 import android.os.Vibrator
-import androidx.annotation.DoNotInline
-import androidx.annotation.RequiresApi
 import androidx.annotation.RequiresPermission
-import androidx.core.content.ContextCompat
 import androidx.core.haptics.HapticManager
-import androidx.core.haptics.signal.PredefinedEffect
-import androidx.core.haptics.signal.PredefinedEffect.Companion.PredefinedClick
-import androidx.core.haptics.signal.PredefinedEffect.Companion.PredefinedDoubleClick
-import androidx.core.haptics.signal.PredefinedEffect.Companion.PredefinedHeavyClick
-import androidx.core.haptics.signal.PredefinedEffect.Companion.PredefinedTick
+import androidx.core.haptics.VibratorWrapper
+import androidx.core.haptics.signal.HapticSignal
 
 /**
  * [HapticManager] implementation for the [Vibrator] service.
  */
 internal class HapticManagerImpl internal constructor(
-    private val vibrator: Vibrator
+    private val vibrator: VibratorWrapper
 ) : HapticManager {
 
-    internal constructor(context: Context) : this(
-        requireNotNull(ContextCompat.getSystemService(context, Vibrator::class.java)) {
-            "Vibrator service not found"
-        }
-    )
-
     @RequiresPermission(android.Manifest.permission.VIBRATE)
-    override fun play(effect: PredefinedEffect) {
-        if (VERSION.SDK_INT >= 29) {
-            Api29Impl.play(vibrator, effect)
-        } else {
-            ApiImpl.play(vibrator, effect)
-        }
-    }
-
-    /** Version-specific static inner class. */
-    @RequiresApi(29)
-    private object Api29Impl {
-
-        @JvmStatic
-        @DoNotInline
-        @RequiresPermission(android.Manifest.permission.VIBRATE)
-        fun play(vibrator: Vibrator, effect: PredefinedEffect) {
-            vibrator.vibrate(VibrationEffect.createPredefined(effect.effectId))
-        }
-    }
-
-    /** Version-specific static inner class. */
-    private object ApiImpl {
-
-        private val predefinedEffectFallbackPatterns = mapOf(
-            PredefinedTick to longArrayOf(0, 10),
-            PredefinedClick to longArrayOf(0, 20),
-            PredefinedHeavyClick to longArrayOf(0, 30),
-            PredefinedDoubleClick to longArrayOf(0, 30, 100, 30)
-        )
-
-        @JvmStatic
-        @Suppress("DEPRECATION") // ApkVariant for compatibility
-        @RequiresPermission(android.Manifest.permission.VIBRATE)
-        fun play(vibrator: Vibrator, effect: PredefinedEffect) {
-            predefinedEffectFallbackPatterns[effect]?.let {
-                vibrator.vibrate(/* pattern= */ it, /* repeat= */ -1)
-            }
+    override fun play(signal: HapticSignal) {
+        signal.toVibration()?.let {
+                vibration -> vibrator.vibrate(vibration)
         }
     }
 }
diff --git a/core/haptics/haptics/src/main/java/androidx/core/haptics/impl/HapticSignalConverter.kt b/core/haptics/haptics/src/main/java/androidx/core/haptics/impl/HapticSignalConverter.kt
new file mode 100644
index 0000000..705c6d1
--- /dev/null
+++ b/core/haptics/haptics/src/main/java/androidx/core/haptics/impl/HapticSignalConverter.kt
@@ -0,0 +1,269 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.haptics.impl
+
+import android.os.Build
+import android.os.VibrationEffect
+import androidx.annotation.DoNotInline
+import androidx.annotation.RequiresApi
+import androidx.core.haptics.PatternVibrationWrapper
+import androidx.core.haptics.VibrationEffectWrapper
+import androidx.core.haptics.VibrationWrapper
+import androidx.core.haptics.signal.CompositionSignal
+import androidx.core.haptics.signal.CompositionSignal.OffAtom
+import androidx.core.haptics.signal.CompositionSignal.PrimitiveAtom
+import androidx.core.haptics.signal.PredefinedEffectSignal
+import androidx.core.haptics.signal.WaveformSignal
+import androidx.core.haptics.signal.WaveformSignal.ConstantVibrationAtom
+import androidx.core.haptics.signal.WaveformSignal.ConstantVibrationAtom.Companion.DEFAULT_AMPLITUDE
+import kotlin.math.roundToInt
+
+private const val VIBRATION_DEFAULT_AMPLITUDE: Int = -1 // VibrationEffect.DEFAULT_AMPLITUDE
+private const val VIBRATION_MAX_AMPLITUDE: Int = 255 // VibrationEffect.MAX_AMPLITUDE
+
+/** Returns true if amplitude is 0, 1 or [DEFAULT_AMPLITUDE]. */
+internal fun ConstantVibrationAtom.hasPatternAmplitude(): Boolean =
+    (amplitude == 0f) || (amplitude == 1f) || (amplitude == DEFAULT_AMPLITUDE)
+
+/** Returns the amplitude value in [0,255] or [android.os.VibrationEffect.DEFAULT_AMPLITUDE]. */
+internal fun ConstantVibrationAtom.getAmplitudeInt(): Int =
+    if (amplitude == DEFAULT_AMPLITUDE) {
+        VIBRATION_DEFAULT_AMPLITUDE
+    } else {
+        (amplitude * VIBRATION_MAX_AMPLITUDE).roundToInt()
+    }
+
+/**
+ * Helper class to convert haptic signals to platform types based on SDK support available.
+ */
+internal object HapticSignalConverter {
+
+    internal fun toVibration(effect: PredefinedEffectSignal): VibrationWrapper? =
+        if (Build.VERSION.SDK_INT >= 29) {
+            Api29Impl.toVibrationEffect(effect)
+        } else {
+            ApiImpl.toPatternVibration(effect)
+        }
+
+    internal fun toVibration(
+        initialWaveform: WaveformSignal?,
+        repeatingWaveform: WaveformSignal?
+    ): VibrationWrapper? =
+        if (Build.VERSION.SDK_INT >= 26) {
+            Api26Impl.toVibrationEffect(initialWaveform, repeatingWaveform)
+        } else {
+            ApiImpl.toPatternVibration(initialWaveform, repeatingWaveform)
+        }
+
+    internal fun toVibration(composition: CompositionSignal): VibrationWrapper? =
+        if (Build.VERSION.SDK_INT >= 31) {
+            Api31Impl.toVibrationEffect(composition)
+        } else if (Build.VERSION.SDK_INT >= 30) {
+            Api30Impl.toVibrationEffect(composition)
+        } else {
+            null
+        }
+
+    /** Version-specific static inner class. */
+    @RequiresApi(31)
+    private object Api31Impl {
+        @JvmStatic
+        @DoNotInline
+        fun toVibrationEffect(composition: CompositionSignal): VibrationEffectWrapper? =
+            if (composition.minSdk() <= 31) {
+                // Use same API to create composition from API 30, but allow constants from API 31.
+                Api30Impl.createComposition(composition)
+            } else {
+                null
+            }
+    }
+
+    /** Version-specific static inner class. */
+    @RequiresApi(30)
+    private object Api30Impl {
+        @JvmStatic
+        @DoNotInline
+        fun toVibrationEffect(composition: CompositionSignal): VibrationEffectWrapper? =
+            if (composition.minSdk() <= 30) {
+                createComposition(composition)
+            } else {
+                null
+            }
+
+        @JvmStatic
+        @DoNotInline
+        fun createComposition(composition: CompositionSignal): VibrationEffectWrapper? {
+            val platformComposition = VibrationEffect.startComposition()
+            var delayMs = 0
+
+            composition.atoms.forEach { atom ->
+                when (atom) {
+                    is PrimitiveAtom -> {
+                        platformComposition.addPrimitive(atom.type, atom.amplitudeScale, delayMs)
+                        delayMs = 0
+                    }
+
+                    is OffAtom -> {
+                        delayMs += atom.durationMillis.toInt()
+                    }
+
+                    else -> {
+                        // Unsupported composition atom
+                        return@createComposition null
+                    }
+                }
+            }
+
+            return VibrationEffectWrapper(platformComposition.compose())
+        }
+    }
+
+    /** Version-specific static inner class. */
+    @RequiresApi(29)
+    private object Api29Impl {
+        @JvmStatic
+        @DoNotInline
+        fun toVibrationEffect(effect: PredefinedEffectSignal): VibrationEffectWrapper? =
+            if (effect.minSdk() <= 29) {
+                VibrationEffectWrapper(VibrationEffect.createPredefined(effect.type))
+            } else {
+                null
+            }
+    }
+
+    /** Version-specific static inner class. */
+    @RequiresApi(26)
+    private object Api26Impl {
+
+        @JvmStatic
+        @DoNotInline
+        fun toVibrationEffect(
+            initialWaveform: WaveformSignal? = null,
+            repeatingWaveform: WaveformSignal? = null,
+        ): VibrationEffectWrapper? {
+            if (initialWaveform?.atoms?.any { it !is ConstantVibrationAtom } == true ||
+                repeatingWaveform?.atoms?.any { it !is ConstantVibrationAtom } == true) {
+                // Unsupported waveform atoms
+                return null
+            }
+
+            val initialAtoms =
+                initialWaveform?.atoms?.filterIsInstance<ConstantVibrationAtom>().orEmpty()
+            val repeatingAtoms =
+                repeatingWaveform?.atoms?.filterIsInstance<ConstantVibrationAtom>().orEmpty()
+            val allAtoms = initialAtoms + repeatingAtoms
+
+            val timings = allAtoms.map { it.durationMillis }.toLongArray()
+            val amplitudes = allAtoms.map { it.getAmplitudeInt() }.toIntArray()
+            val repeatIndex = if (repeatingAtoms.isNotEmpty()) initialAtoms.size else -1
+
+            if (timings.isEmpty() || timings.sum() == 0L) {
+                // Empty or zero duration waveforms not supported by VibrationEffect.createWaveform
+                return null
+            }
+
+            return VibrationEffectWrapper(
+                VibrationEffect.createWaveform(timings, amplitudes, repeatIndex)
+            )
+        }
+    }
+
+    /** Version-specific static inner class. */
+    private object ApiImpl {
+
+        @JvmStatic
+        fun toPatternVibration(effect: PredefinedEffectSignal): PatternVibrationWrapper? =
+            // Fallback patterns for predefined effects in SDK < 29.
+            when (effect.type) {
+                PredefinedEffectSignal.TICK ->
+                    PatternVibrationWrapper(longArrayOf(0, 10), repeatIndex = -1)
+                PredefinedEffectSignal.CLICK ->
+                    PatternVibrationWrapper(longArrayOf(0, 20), repeatIndex = -1)
+                PredefinedEffectSignal.HEAVY_CLICK ->
+                    PatternVibrationWrapper(longArrayOf(0, 30), repeatIndex = -1)
+                PredefinedEffectSignal.DOUBLE_CLICK ->
+                    PatternVibrationWrapper(longArrayOf(0, 30, 100, 30), repeatIndex = -1)
+                else ->
+                    null
+            }
+
+        @JvmStatic
+        fun toPatternVibration(
+            initialWaveform: WaveformSignal? = null,
+            repeatingWaveform: WaveformSignal? = null,
+        ): PatternVibrationWrapper? {
+            if (initialWaveform?.atoms?.any { it !is ConstantVibrationAtom } == true ||
+                repeatingWaveform?.atoms?.any { it !is ConstantVibrationAtom } == true) {
+                // Unsupported waveform entries
+                return null
+            }
+
+            val initialAtoms =
+                initialWaveform?.atoms?.filterIsInstance<ConstantVibrationAtom>().orEmpty()
+                    .toMutableList()
+            val repeatingAtoms =
+                repeatingWaveform?.atoms?.filterIsInstance<ConstantVibrationAtom>().orEmpty()
+
+            if (!initialAtoms.all { it.hasPatternAmplitude() } ||
+                !repeatingAtoms.all { it.hasPatternAmplitude() }) {
+                // Not possible to represent all amplitudes by an on-off pattern.
+                return null
+            }
+
+            val allAtoms = initialAtoms + repeatingAtoms
+            val timings = mutableListOf<Long>()
+            var currentIsOff = true // Vibration pattern starts with an off entry.
+            var currentTiming = 0L
+            var repeatIndex = -1
+
+            for ((index, atom) in allAtoms.withIndex()) {
+                if (index == initialAtoms.size) { // This is the first repeating atom.
+                    if (currentTiming > 0) {
+                        // Make sure not to merge the last initial atom to the first repeating one.
+                        timings.add(currentTiming)
+                        currentTiming = 0
+                        currentIsOff = !currentIsOff
+                    }
+                    // Mark the start of the repetition before adding the first repeating atom.
+                    repeatIndex = timings.size
+                }
+                val atomIsOff = atom.amplitude == 0f
+                if (currentIsOff == atomIsOff) {
+                    // Merge timings of same on/off state.
+                    currentTiming += atom.durationMillis
+                } else {
+                    // Start new timing with different on/off state.
+                    timings.add(currentTiming)
+                    currentTiming = atom.durationMillis
+                    currentIsOff = atomIsOff
+                }
+            }
+
+            if (currentTiming > 0) {
+                // Add last timing entry to the pattern.
+                timings.add(currentTiming)
+            }
+
+            if (timings.isEmpty() || timings.sum() == 0L) {
+                // Empty or zero duration waveforms are not supported by pattern vibrations.
+                return null
+            }
+
+            return PatternVibrationWrapper(timings.toLongArray(), repeatIndex)
+        }
+    }
+}
diff --git a/core/haptics/haptics/src/main/java/androidx/core/haptics/impl/VibratorWrapperImpl.kt b/core/haptics/haptics/src/main/java/androidx/core/haptics/impl/VibratorWrapperImpl.kt
new file mode 100644
index 0000000..decc9e0
--- /dev/null
+++ b/core/haptics/haptics/src/main/java/androidx/core/haptics/impl/VibratorWrapperImpl.kt
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.haptics.impl
+
+import android.annotation.SuppressLint
+import android.os.Build
+import android.os.VibrationEffect
+import android.os.Vibrator
+import androidx.annotation.DoNotInline
+import androidx.annotation.RequiresApi
+import androidx.annotation.RequiresPermission
+import androidx.core.haptics.PatternVibrationWrapper
+import androidx.core.haptics.VibrationEffectWrapper
+import androidx.core.haptics.VibrationWrapper
+import androidx.core.haptics.VibratorWrapper
+
+/**
+ * [VibratorWrapper] implementation backed by a real [Vibrator] service.
+ */
+internal class VibratorWrapperImpl(
+    private val vibrator: Vibrator
+) : VibratorWrapper {
+
+    override fun hasVibrator(): Boolean = ApiImpl.hasVibrator(vibrator)
+
+    override fun hasAmplitudeControl(): Boolean =
+        if (Build.VERSION.SDK_INT >= 26) {
+            Api26Impl.hasAmplitudeControl(vibrator)
+        } else {
+            false
+        }
+
+    override fun areEffectsSupported(effects: IntArray): Array<VibratorWrapper.EffectSupport>? =
+        if (Build.VERSION.SDK_INT >= 30) {
+            Api30Impl.areEffectsSupported(vibrator, effects)
+        } else {
+            null
+        }
+
+    override fun arePrimitivesSupported(primitives: IntArray): BooleanArray? =
+        if (Build.VERSION.SDK_INT >= 30) {
+            Api30Impl.arePrimitivesSupported(vibrator, primitives)
+        } else {
+            null
+        }
+
+    @RequiresPermission(android.Manifest.permission.VIBRATE)
+    override fun vibrate(vibration: VibrationWrapper) {
+        when (vibration) {
+            is VibrationEffectWrapper -> {
+                check(Build.VERSION.SDK_INT >= 26) {
+                    "Attempting to vibrate with VibrationEffect before Android O is not supported"
+                }
+                if (Build.VERSION.SDK_INT >= 26) {
+                    Api26Impl.vibrate(vibrator, vibration)
+                }
+            }
+            is PatternVibrationWrapper ->
+                ApiImpl.vibrate(vibrator, vibration)
+        }
+    }
+
+    @RequiresPermission(android.Manifest.permission.VIBRATE)
+    override fun cancel() {
+        ApiImpl.cancel(vibrator)
+    }
+
+    /** Version-specific static inner class. */
+    @RequiresApi(30)
+    private object Api30Impl {
+
+        @SuppressLint("WrongConstant") // custom conversion between jetpack and framework
+        @JvmStatic
+        @DoNotInline
+        fun areEffectsSupported(
+            vibrator: Vibrator,
+            effects: IntArray,
+        ): Array<VibratorWrapper.EffectSupport> {
+            return vibrator.areEffectsSupported(*effects).map {
+                when (it) {
+                    Vibrator.VIBRATION_EFFECT_SUPPORT_YES -> VibratorWrapper.EffectSupport.YES
+                    Vibrator.VIBRATION_EFFECT_SUPPORT_NO -> VibratorWrapper.EffectSupport.NO
+                    else -> VibratorWrapper.EffectSupport.UNKNOWN
+                }
+            }.toTypedArray()
+        }
+
+        @SuppressLint("WrongConstant") // custom conversion between jetpack and framework
+        @JvmStatic
+        @DoNotInline
+        fun arePrimitivesSupported(
+            vibrator: Vibrator,
+            primitives: IntArray,
+        ): BooleanArray {
+            return vibrator.arePrimitivesSupported(*primitives).toTypedArray().toBooleanArray()
+        }
+    }
+
+    /** Version-specific static inner class. */
+    @RequiresApi(26)
+    private object Api26Impl {
+
+        @JvmStatic
+        @DoNotInline
+        fun hasAmplitudeControl(vibrator: Vibrator) = vibrator.hasAmplitudeControl()
+
+        @JvmStatic
+        @DoNotInline
+        @RequiresPermission(android.Manifest.permission.VIBRATE)
+        fun vibrate(vibrator: Vibrator, effect: VibrationEffectWrapper) {
+            check(effect.vibrationEffect is VibrationEffect) {
+                "Attempting to vibrate with unexpected vibration effect ${effect.vibrationEffect}"
+            }
+            vibrator.vibrate(effect.vibrationEffect)
+        }
+    }
+
+    /** Version-specific static inner class. */
+    private object ApiImpl {
+
+        @JvmStatic
+        fun hasVibrator(vibrator: Vibrator) = vibrator.hasVibrator()
+
+        @JvmStatic
+        @Suppress("DEPRECATION") // ApkVariant for compatibility
+        @RequiresPermission(android.Manifest.permission.VIBRATE)
+        fun vibrate(vibrator: Vibrator, pattern: PatternVibrationWrapper) =
+            vibrator.vibrate(pattern.timings, pattern.repeatIndex)
+
+        @JvmStatic
+        @RequiresPermission(android.Manifest.permission.VIBRATE)
+        fun cancel(vibrator: Vibrator) = vibrator.cancel()
+    }
+}
diff --git a/core/haptics/haptics/src/main/java/androidx/core/haptics/signal/CompositionSignal.kt b/core/haptics/haptics/src/main/java/androidx/core/haptics/signal/CompositionSignal.kt
new file mode 100644
index 0000000..0197b93
--- /dev/null
+++ b/core/haptics/haptics/src/main/java/androidx/core/haptics/signal/CompositionSignal.kt
@@ -0,0 +1,444 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.haptics.signal
+
+import android.os.Build
+import androidx.annotation.FloatRange
+import androidx.annotation.IntDef
+import androidx.annotation.RequiresApi
+import androidx.annotation.RestrictTo
+import androidx.core.haptics.VibrationWrapper
+import androidx.core.haptics.impl.HapticSignalConverter
+import java.util.Objects
+import kotlin.time.Duration
+import kotlin.time.Duration.Companion.milliseconds
+import kotlin.time.toKotlinDuration
+
+/**
+ * A composition of haptic elements that can be played as one single haptic effect.
+ *
+ * Composition signals may be defined as a composition of scalable primitive effects, which are
+ * tailored to the device hardware. The composition signal is based on the
+ * [android.os.VibrationEffect.Composition] platform API.
+ *
+ * @sample androidx.core.haptics.samples.CompositionSignalOfScaledEffectsAndOff
+ */
+class CompositionSignal(
+
+    /**
+     * The composition signal atoms that describes the haptic elements to be played in sequence.
+     */
+    val atoms: List<Atom>,
+
+) : FiniteSignal() {
+    init {
+        require(atoms.isNotEmpty()) { "Haptic signals cannot be empty" }
+    }
+
+    companion object {
+
+        /**
+         * Returns a [CompositionSignal] with given atoms.
+         *
+         * @sample androidx.core.haptics.samples.CompositionSignalOfScaledEffectsAndOff
+         *
+         * @param atoms The [CompositionSignal.Atom] instances that define the [CompositionSignal].
+         */
+        @JvmStatic
+        fun compositionOf(vararg atoms: Atom): CompositionSignal =
+            CompositionSignal(atoms.toList())
+
+        /**
+         * Returns a [CompositionSignal.Atom] for a very short low frequency tick effect.
+         *
+         * This effect should produce a light crisp sensation intended to be used repetitively
+         * for dynamic feedback.
+         *
+         * @param amplitudeScale The amplitude scale for the new [PrimitiveAtom]
+         */
+        @JvmOverloads
+        @JvmStatic
+        fun lowTick(@FloatRange(from = 0.0, to = 1.0) amplitudeScale: Float = 1f) =
+            PrimitiveAtom.LowTick.withAmplitudeScale(amplitudeScale)
+
+        /**
+         * Returns a [CompositionSignal.Atom] for a very short light tick effect.
+         *
+         * This effect should produce a light crisp sensation stronger than the [lowTick()], and is
+         * also intended to be used repetitively for dynamic feedback.
+         *
+         * @param amplitudeScale The amplitude scale for the new [PrimitiveAtom]
+         */
+        @JvmOverloads
+        @JvmStatic
+        fun tick(@FloatRange(from = 0.0, to = 1.0) amplitudeScale: Float = 1f) =
+            PrimitiveAtom.Tick.withAmplitudeScale(amplitudeScale)
+
+        /**
+         * Returns a [CompositionSignal.Atom] for a click effect.
+         *
+         * This effect should produce a sharp, crisp click sensation.
+         *
+         * @param amplitudeScale The amplitude scale for the new [PrimitiveAtom]
+         */
+        @JvmOverloads
+        @JvmStatic
+        fun click(@FloatRange(from = 0.0, to = 1.0) amplitudeScale: Float = 1f) =
+            PrimitiveAtom.Click.withAmplitudeScale(amplitudeScale)
+
+        /**
+         * Returns a [CompositionSignal.Atom] for an effect with increasing strength.
+         *
+         * This effect simulates quick upward movement against gravity.
+         *
+         * @param amplitudeScale The amplitude scale for the new [PrimitiveAtom]
+         */
+        @JvmOverloads
+        @JvmStatic
+        fun quickRise(@FloatRange(from = 0.0, to = 1.0) amplitudeScale: Float = 1f) =
+            PrimitiveAtom.QuickRise.withAmplitudeScale(amplitudeScale)
+
+        /**
+         * Returns a [CompositionSignal.Atom] for a longer effect with increasing strength.
+         *
+         * This effect simulates slow upward movement against gravity and is longer than the
+         * [quickRise()].
+         *
+         * @param amplitudeScale The amplitude scale for the new [PrimitiveAtom]
+         */
+        @JvmOverloads
+        @JvmStatic
+        fun slowRise(@FloatRange(from = 0.0, to = 1.0) amplitudeScale: Float = 1f) =
+            PrimitiveAtom.SlowRise.withAmplitudeScale(amplitudeScale)
+
+        /**
+         * Returns a [CompositionSignal.Atom] for an effect with decreasing strength.
+         *
+         * This effect simulates quick downwards movement against gravity.
+         *
+         * @param amplitudeScale The amplitude scale for the new [PrimitiveAtom]
+         */
+        @JvmOverloads
+        @JvmStatic
+        fun quickFall(@FloatRange(from = 0.0, to = 1.0) amplitudeScale: Float = 1f) =
+            PrimitiveAtom.QuickFall.withAmplitudeScale(amplitudeScale)
+
+        /**
+         * Returns a [CompositionSignal.Atom] for a spin effect.
+         *
+         * This effect simulates spinning momentum.
+         *
+         * @param amplitudeScale The amplitude scale for the new [PrimitiveAtom]
+         */
+        @JvmOverloads
+        @JvmStatic
+        fun spin(@FloatRange(from = 0.0, to = 1.0) amplitudeScale: Float = 1f) =
+            PrimitiveAtom.Spin.withAmplitudeScale(amplitudeScale)
+
+        /**
+         * Returns a [CompositionSignal.Atom] for a thud effect.
+         *
+         * This effect simulates downwards movement with gravity, often followed by extra energy
+         * of hitting and reverberation to augment physicality.
+         *
+         * @param amplitudeScale The amplitude scale for the new [PrimitiveAtom]
+         */
+        @JvmOverloads
+        @JvmStatic
+        fun thud(
+            @FloatRange(from = 0.0, to = 1.0) amplitudeScale: Float = 1f,
+        ) =
+            PrimitiveAtom.Thud.withAmplitudeScale(amplitudeScale)
+
+        /**
+         * Returns a [CompositionSignal.Atom] to turn the vibrator off for the specified duration.
+         *
+         * @sample androidx.core.haptics.samples.CompositionSignalOfScaledEffectsAndOff
+         *
+         * @param duration The duration the vibrator should be turned off.
+         */
+        @RequiresApi(Build.VERSION_CODES.O)
+        @JvmStatic
+        fun off(duration: java.time.Duration) =
+            OffAtom(duration.toKotlinDuration())
+
+        /**
+         * Returns a [CompositionSignal.Atom] to turn the vibrator off for the specified duration.
+         *
+         * @sample androidx.core.haptics.samples.CompositionSignalOfScaledEffectsAndOff
+         *
+         * @param durationMillis The duration the vibrator should be turned off, in milliseconds.
+         */
+        @JvmStatic
+        fun off(durationMillis: Long) =
+            OffAtom(durationMillis.milliseconds)
+    }
+
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other !is CompositionSignal) return false
+        if (atoms != other.atoms) return false
+        return true
+    }
+
+    override fun hashCode(): Int {
+        return atoms.hashCode()
+    }
+
+    override fun toString(): String {
+        return "CompositionSignal(${atoms.joinToString()})"
+    }
+
+    /**
+     * Returns the minimum SDK level required by the atoms of this signal.
+     */
+    internal fun minSdk(): Int = atoms.maxOf { it.minSdk() }
+
+    override fun toVibration(): VibrationWrapper? = HapticSignalConverter.toVibration(this)
+
+    /**
+     * A [CompositionSignal.Atom] is a building block for creating a [CompositionSignal].
+     *
+     * Composition signal atoms describe basic haptic elements to be played in sequence as a single
+     * haptic effect. They can describe haptic effects tailored to the device hardware, like click
+     * and tick effects, or then can represent pauses in the effect composition.
+     *
+     * @sample androidx.core.haptics.samples.CompositionSignalOfScaledEffectsAndOff
+     */
+    abstract class Atom internal constructor() {
+
+        /**
+         * The minimum SDK level where this atom is available in the platform.
+         */
+        internal abstract fun minSdk(): Int
+    }
+
+    /**
+     * A [PrimitiveAtom] plays a haptic effect with the specified vibration strength scale.
+     *
+     * Composition primitives are haptic effects tailored to the device hardware with configurable
+     * vibration strength. They can be used as building blocks to create more complex haptic
+     * effects. The primitive atoms are based on the
+     * [android.os.VibrationEffect.Composition.addPrimitive] platform API.
+     *
+     * A primitive effect will always be played with a non-zero vibration amplitude, but the actual
+     * vibration strength can be scaled by values in the range [0f..1f]. Zero [amplitudeScale]
+     * implies the vibrator will play it at the minimum strength required for the effect to be
+     * perceived on the device. The maximum [amplitudeScale] value of 1 implies the vibrator will
+     * play it at the maximum strength that preserves the effect's intended design. For instance, a
+     * [Click] effect with [amplitudeScale] of 1 will usually feel stronger than a [Tick] with same
+     * amplitude scale.
+     *
+     * @sample androidx.core.haptics.samples.CompositionSignalOfScaledEffectsAndOff
+     */
+    class PrimitiveAtom private constructor(
+
+        /**
+         * The type of haptic effect to be played.
+         */
+        @Type val type: Int,
+
+        /**
+         * The minimum SDK level where this effect type is available in the platform.
+         */
+        private val minSdk: Int,
+
+        /**
+         * The scale for the vibration strength.
+         *
+         * A primitive effect will always be played with a non-zero vibration strength. Zero values
+         * here represent minimum effect strength that can still be perceived on the device, and
+         * maximum values represent the maximum strength the effect can be played.
+         */
+        @FloatRange(from = 0.0, to = 1.0) val amplitudeScale: Float = 1f,
+
+    ) : Atom() {
+        init {
+            require(amplitudeScale in 0.0..1.0) {
+                "Primitive amplitude scale must be in [0,1]: $amplitudeScale"
+            }
+        }
+
+        /** Typedef for the [type] attribute. */
+        @RestrictTo(RestrictTo.Scope.LIBRARY)
+        @Retention(AnnotationRetention.SOURCE)
+        @IntDef(
+            LOW_TICK,
+            TICK,
+            CLICK,
+            SLOW_RISE,
+            QUICK_RISE,
+            QUICK_FALL,
+            SPIN,
+            THUD,
+        )
+        annotation class Type
+
+        companion object {
+
+            /**
+             * A very short low frequency tick effect.
+             *
+             * This effect should produce a light crisp sensation intended to be used repetitively
+             * for dynamic feedback.
+             */
+            const val LOW_TICK = 8 // VibrationEffect.Composition.PRIMITIVE_LOW_TICK
+
+            /**
+             * A very short light tick effect.
+             *
+             * This effect should produce a light crisp sensation stronger than the [LowTick], and is
+             * also intended to be used repetitively for dynamic feedback.
+             */
+            const val TICK = 7 // VibrationEffect.Composition.PRIMITIVE_TICK
+
+            /**
+             * A click effect.
+             *
+             * This effect should produce a sharp, crisp click sensation.
+             */
+            const val CLICK = 1 // VibrationEffect.Composition.PRIMITIVE_CLICK
+
+            /**
+             * An effect with increasing strength.
+             *
+             * This effect simulates quick upward movement against gravity.
+             */
+            const val QUICK_RISE = 4 // VibrationEffect.Composition.PRIMITIVE_QUICK_RISE
+
+            /**
+             * A longer effect with increasing strength.
+             *
+             * This effect simulates slow upward movement against gravity and is longer than the
+             * [QuickRise].
+             */
+            const val SLOW_RISE = 5 // VibrationEffect.Composition.PRIMITIVE_SLOW_RISE
+
+            /**
+             * An effect with decreasing strength.
+             *
+             * This effect simulates quick downwards movement against gravity.
+             */
+            const val QUICK_FALL = 6 // VibrationEffect.Composition.PRIMITIVE_QUICK_FALL
+
+            /**
+             * A spin effect.
+             *
+             * This effect simulates spinning momentum.
+             */
+            const val SPIN = 3 // VibrationEffect.Composition.PRIMITIVE_SPIN
+
+            /**
+             * A thud effect.
+             *
+             * This effect simulates downwards movement with gravity, often followed by extra energy
+             * of hitting and reverberation to augment physicality.
+             */
+            const val THUD = 2 // VibrationEffect.Composition.PRIMITIVE_THUD
+
+            internal val LowTick = PrimitiveAtom(LOW_TICK, Build.VERSION_CODES.S)
+            internal val Tick = PrimitiveAtom(TICK, Build.VERSION_CODES.R)
+            internal val Click = PrimitiveAtom(CLICK, Build.VERSION_CODES.R)
+            internal val QuickRise = PrimitiveAtom(QUICK_RISE, Build.VERSION_CODES.R)
+            internal val SlowRise = PrimitiveAtom(SLOW_RISE, Build.VERSION_CODES.R)
+            internal val QuickFall = PrimitiveAtom(QUICK_FALL, Build.VERSION_CODES.R)
+            internal val Spin = PrimitiveAtom(SPIN, Build.VERSION_CODES.S)
+            internal val Thud = PrimitiveAtom(THUD, Build.VERSION_CODES.S)
+        }
+
+        /**
+         * Returns a [PrimitiveAtom] with same effect type and new [amplitudeScale].
+         *
+         * @sample androidx.core.haptics.samples.CompositionSignalOfScaledEffectsAndOff
+         *
+         * @param newAmplitudeScale The amplitude scale for the new [PrimitiveAtom]
+         * @return A new [PrimitiveAtom] with the same effect type and the new amplitude scale.
+         */
+        fun withAmplitudeScale(
+            @FloatRange(from = 0.0, to = 1.0) newAmplitudeScale: Float,
+        ): PrimitiveAtom =
+            if (amplitudeScale == newAmplitudeScale) {
+                this
+            } else {
+                PrimitiveAtom(type, minSdk, newAmplitudeScale)
+            }
+
+        override fun equals(other: Any?): Boolean {
+            if (this === other) return true
+            if (other !is PrimitiveAtom) return false
+            if (type != other.type) return false
+            if (minSdk != other.minSdk) return false
+            if (amplitudeScale != other.amplitudeScale) return false
+            return true
+        }
+
+        override fun hashCode(): Int = Objects.hash(type, amplitudeScale)
+
+        override fun toString(): String {
+            val typeStr = when (type) {
+                LOW_TICK -> "LowTick"
+                TICK -> "Tick"
+                CLICK -> "Click"
+                SLOW_RISE -> "SlowRise"
+                QUICK_RISE -> "QuickRise"
+                QUICK_FALL -> "QuickFall"
+                SPIN -> "Spin"
+                THUD -> "Thud"
+                else -> type.toString()
+            }
+            return "PrimitiveAtom(type=$typeStr, amplitude=$amplitudeScale)"
+        }
+
+        override fun minSdk(): Int = minSdk
+    }
+
+    /**
+     * A [OffAtom] turns off the vibrator for the specified duration.
+     *
+     * @sample androidx.core.haptics.samples.CompositionSignalOfScaledEffectsAndOff
+     */
+    class OffAtom internal constructor(duration: Duration) : Atom() {
+        /**
+         * The duration for the vibrator to be turned off, in milliseconds.
+         */
+        val durationMillis: Long
+
+        init {
+            require(duration.isFinite() && !duration.isNegative()) {
+                "Composition signal off atom duration must be finite and non-negative: $duration"
+            }
+            durationMillis = duration.inWholeMilliseconds
+        }
+
+        override fun equals(other: Any?): Boolean {
+            if (this === other) return true
+            if (other !is OffAtom) return false
+            if (durationMillis != other.durationMillis) return false
+            return true
+        }
+
+        override fun hashCode(): Int {
+            return durationMillis.hashCode()
+        }
+
+        override fun toString(): String {
+            return "OffAtom(durationMillis=$durationMillis)"
+        }
+
+        override fun minSdk(): Int = Build.VERSION_CODES.R
+    }
+}
diff --git a/core/haptics/haptics/src/main/java/androidx/core/haptics/signal/HapticSignal.kt b/core/haptics/haptics/src/main/java/androidx/core/haptics/signal/HapticSignal.kt
new file mode 100644
index 0000000..69ae2c5
--- /dev/null
+++ b/core/haptics/haptics/src/main/java/androidx/core/haptics/signal/HapticSignal.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.haptics.signal
+
+import androidx.core.haptics.VibrationWrapper
+
+/**
+ * A [HapticSignal] describes a generic vibration to be played by a vibrator.
+ *
+ * These signals may represent any number of things, from single shot vibrations to complex
+ * waveforms, device-specific predefined effects or custom vibration patterns.
+ *
+ * A haptic signal can be defined as a [FiniteSignal] or [InfiniteSignal]. Infinite signals will be
+ * played by the vibrator until canceled, while finite signals will stop playing once completed.
+ *
+ * Note: This is a library-restricted representation of a haptic signal that will be mapped to a
+ * platform representation available, like [android.os.VibrationEffect]. This class cannot be
+ * extended or supplemented outside the library, but they can be instantiated from custom extensions
+ * via factory methods.
+ */
+abstract class HapticSignal internal constructor() {
+
+    /**
+     * Returns a [VibrationWrapper] representing this signal, or null if not supported in this SDK
+     * level.
+     */
+    internal abstract fun toVibration(): VibrationWrapper?
+}
+
+/**
+ * A [FiniteSignal] describes a non-infinite haptic signal to be played by a vibrator.
+ */
+abstract class FiniteSignal internal constructor() : HapticSignal()
+
+/**
+ * A [InfiniteSignal] describes a haptic signal that will be played by a vibrator until canceled.
+ */
+abstract class InfiniteSignal internal constructor() : HapticSignal()
diff --git a/core/haptics/haptics/src/main/java/androidx/core/haptics/signal/PredefinedEffect.kt b/core/haptics/haptics/src/main/java/androidx/core/haptics/signal/PredefinedEffect.kt
deleted file mode 100644
index abe1b89..0000000
--- a/core/haptics/haptics/src/main/java/androidx/core/haptics/signal/PredefinedEffect.kt
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.core.haptics.signal
-
-/**
- * A [PredefinedEffect] describes a haptic effect to be played by a vibrator.
- *
- * Predefined effects represent common vibration effects that should be identical, regardless of
- * the app they come from, in order to provide a cohesive experience for users across the entire
- * device.
- *
- * They also may be custom tailored to the device hardware in order to provide a better
- * experience than you could otherwise build using the generic building blocks.
- *
- * This will fallback to a generic pattern if one exists and there is no hardware-specific
- * implementation of the effect available.
- */
-class PredefinedEffect private constructor(
-
-    /** The id of the effect to be played. */
-    internal val effectId: Int
-) {
-
-    companion object {
-
-        /**
-         * A standard tick effect.
-         *
-         * This effect is less strong than the [PredefinedClick].
-         */
-        @JvmField
-        val PredefinedTick = PredefinedEffect(2) // VibrationEffect.EFFECT_TICK
-
-        /**
-         * A standard click effect.
-         *
-         * Use this effect as a baseline, as it's the most common type of click effect.
-         */
-        @JvmField
-        val PredefinedClick = PredefinedEffect(0) // VibrationEffect.EFFECT_CLICK
-
-        /**
-         * A heavy click effect.
-         *
-         * This effect is stronger than the [PredefinedClick].
-         */
-        @JvmField
-        val PredefinedHeavyClick = PredefinedEffect(5) // VibrationEffect.EFFECT_HEAVY_CLICK
-
-        /**
-         * A double-click effect.
-         */
-        @JvmField
-        val PredefinedDoubleClick = PredefinedEffect(1) // VibrationEffect.EFFECT_DOUBLE_CLICK
-    }
-
-    override fun equals(other: Any?): Boolean {
-        if (this === other) return true
-        if (other !is PredefinedEffect) return false
-        if (effectId != other.effectId) return false
-        return true
-    }
-
-    override fun hashCode(): Int {
-        return effectId.hashCode()
-    }
-}
diff --git a/core/haptics/haptics/src/main/java/androidx/core/haptics/signal/PredefinedEffectSignal.kt b/core/haptics/haptics/src/main/java/androidx/core/haptics/signal/PredefinedEffectSignal.kt
new file mode 100644
index 0000000..a81419a
--- /dev/null
+++ b/core/haptics/haptics/src/main/java/androidx/core/haptics/signal/PredefinedEffectSignal.kt
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.haptics.signal
+
+import android.os.Build
+import androidx.annotation.IntDef
+import androidx.annotation.RestrictTo
+import androidx.core.haptics.VibrationWrapper
+import androidx.core.haptics.impl.HapticSignalConverter
+
+/**
+ * A predefined haptic effect that represents common vibration effects, like clicks and ticks.
+ *
+ * Predefined haptic effects should be identical, regardless of the app they come from, in order to
+ * provide a cohesive experience for users across the entire device. The predefined effects are
+ * based on the [android.os.VibrationEffect.createPredefined] platform API.
+ *
+ * @sample androidx.core.haptics.samples.PlaySystemStandardClick
+ */
+class PredefinedEffectSignal private constructor(
+
+    /**
+     * The type of haptic effect to be played.
+     */
+    @Type internal val type: Int,
+
+    /**
+     * The minimum SDK level where this effect type is available in the platform.
+     */
+    private val minSdk: Int,
+
+) : FiniteSignal() {
+
+    /** Typedef for the [type] attribute. */
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    @Retention(AnnotationRetention.SOURCE)
+    @IntDef(
+        TICK,
+        CLICK,
+        HEAVY_CLICK,
+        DOUBLE_CLICK,
+    )
+    annotation class Type
+
+    companion object {
+        internal const val TICK = 2 // VibrationEffect.EFFECT_TICK
+        internal const val CLICK = 0 // VibrationEffect.EFFECT_CLICK
+        internal const val HEAVY_CLICK = 5 // VibrationEffect.EFFECT_HEAVY_CLICK
+        internal const val DOUBLE_CLICK = 1 // VibrationEffect.EFFECT_DOUBLE_CLICK
+
+        private val Tick = PredefinedEffectSignal(TICK, Build.VERSION_CODES.Q)
+        private val Click = PredefinedEffectSignal(CLICK, Build.VERSION_CODES.Q)
+        private val HeavyClick = PredefinedEffectSignal(HEAVY_CLICK, Build.VERSION_CODES.Q)
+        private val DoubleClick = PredefinedEffectSignal(DOUBLE_CLICK, Build.VERSION_CODES.Q)
+
+        /**
+         * A standard tick effect.
+         *
+         * This effect is less strong than the [predefinedClick()].
+         */
+        @JvmStatic
+        fun predefinedTick() = Tick
+
+        /**
+         * A standard click effect.
+         *
+         * Use this effect as a baseline, as it's the most common type of click effect.
+         */
+        @JvmStatic
+        fun predefinedClick() = Click
+
+        /**
+         * A heavy click effect.
+         *
+         * This effect is stronger than the [predefinedClick()].
+         */
+        @JvmStatic
+        fun predefinedHeavyClick() = HeavyClick
+
+        /**
+         * A double-click effect.
+         */
+        @JvmStatic
+        fun predefinedDoubleClick() = DoubleClick
+    }
+
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other !is PredefinedEffectSignal) return false
+        if (type != other.type) return false
+        return true
+    }
+
+    override fun hashCode(): Int {
+        return type.hashCode()
+    }
+
+    override fun toString(): String {
+        val typeStr = when (type) {
+            TICK -> "Tick"
+            CLICK -> "Click"
+            HEAVY_CLICK -> "HeavyClick"
+            DOUBLE_CLICK -> "DoubleClick"
+            else -> type.toString()
+        }
+        return "PredefinedEffectSignal(type=$typeStr)"
+    }
+
+    /**
+     * Returns the minimum SDK level required by the effect type.
+     */
+    internal fun minSdk(): Int = minSdk
+
+    override fun toVibration(): VibrationWrapper? = HapticSignalConverter.toVibration(this)
+}
diff --git a/core/haptics/haptics/src/main/java/androidx/core/haptics/signal/WaveformSignal.kt b/core/haptics/haptics/src/main/java/androidx/core/haptics/signal/WaveformSignal.kt
new file mode 100644
index 0000000..3f1b87f
--- /dev/null
+++ b/core/haptics/haptics/src/main/java/androidx/core/haptics/signal/WaveformSignal.kt
@@ -0,0 +1,333 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.haptics.signal
+
+import android.os.Build
+import androidx.annotation.FloatRange
+import androidx.annotation.RequiresApi
+import androidx.core.haptics.VibrationWrapper
+import androidx.core.haptics.impl.HapticSignalConverter
+import androidx.core.haptics.signal.WaveformSignal.ConstantVibrationAtom.Companion.DEFAULT_AMPLITUDE
+import java.util.Objects
+import kotlin.time.Duration
+import kotlin.time.Duration.Companion.milliseconds
+import kotlin.time.toKotlinDuration
+
+/**
+ * A haptic signal where the vibration parameters change over time.
+ *
+ * Waveform signals may be used to describe step waveforms, defined by a sequence of constant
+ * vibrations played at different strengths. They can also be combined to define a
+ * [RepeatingWaveformSignal], which is an [InfiniteSignal] that repeats a waveform until the
+ * vibration is canceled.
+ *
+ * @sample androidx.core.haptics.samples.AmplitudeWaveform
+ * @sample androidx.core.haptics.samples.PatternThenRepeatAmplitudeWaveform
+ */
+class WaveformSignal(
+
+    /**
+     * The waveform signal atoms that describes the vibration parameters over time.
+     */
+    val atoms: List<Atom>,
+
+) : FiniteSignal() {
+    init {
+        require(atoms.isNotEmpty()) { "Haptic signals cannot be empty" }
+    }
+
+    companion object {
+
+        /**
+         * Returns a [WaveformSignal] created with given waveform atoms.
+         *
+         * Use [on] and [off] to create atoms.
+         *
+         * @sample androidx.core.haptics.samples.AmplitudeWaveform
+         *
+         * @param atoms The [WaveformSignal.Atom] instances that define the [WaveformSignal].
+         */
+        @JvmStatic
+        fun waveformOf(vararg atoms: Atom): WaveformSignal =
+            WaveformSignal(atoms.toList())
+
+        /**
+         * Returns a [RepeatingWaveformSignal] created with given waveform atoms.
+         *
+         * Repeating waveforms should include any desired loop delay as an [off] atom at the end of
+         * the atom list.
+         *
+         * @sample androidx.core.haptics.samples.RepeatingAmplitudeWaveform
+         *
+         * @param atoms The [WaveformSignal.Atom] instances that define the
+         *   [RepeatingWaveformSignal].
+         */
+        @JvmStatic
+        fun repeatingWaveformOf(vararg atoms: Atom): RepeatingWaveformSignal =
+            waveformOf(*atoms).repeat()
+
+        /**
+         * Returns a [WaveformSignal.Atom] that turns off the vibrator for the specified duration.
+         *
+         * @sample androidx.core.haptics.samples.PatternWaveform
+         *
+         * @param duration The duration the vibrator should be turned off.
+         */
+        @RequiresApi(Build.VERSION_CODES.O)
+        @JvmStatic
+        fun off(duration: java.time.Duration) =
+            ConstantVibrationAtom(duration.toKotlinDuration(), amplitude = 0f)
+
+        /**
+         * Returns a [WaveformSignal.Atom] that turns off the vibrator for the specified duration.
+         *
+         * @sample androidx.core.haptics.samples.PatternWaveform
+         *
+         * @param durationMillis The duration the vibrator should be turned off, in milliseconds.
+         */
+        @JvmStatic
+        fun off(durationMillis: Long) =
+            ConstantVibrationAtom(durationMillis.milliseconds, amplitude = 0f)
+
+        /**
+         * Returns a [WaveformSignal.Atom] that turns on the vibrator for the specified duration at
+         * a device-specific default amplitude.
+         *
+         * @sample androidx.core.haptics.samples.PatternWaveform
+         *
+         * @param duration The duration for the vibration.
+         */
+        @RequiresApi(Build.VERSION_CODES.O)
+        @JvmStatic
+        fun on(duration: java.time.Duration) =
+            ConstantVibrationAtom(duration.toKotlinDuration(), DEFAULT_AMPLITUDE)
+
+        /**
+         * Returns a [WaveformSignal.Atom] that turns on the vibrator for the specified duration at
+         * a device-specific default amplitude.
+         *
+         * @sample androidx.core.haptics.samples.PatternWaveform
+         *
+         * @param durationMillis The duration for the vibration, in milliseconds.
+         */
+        @JvmStatic
+        fun on(durationMillis: Long) =
+            ConstantVibrationAtom(durationMillis.milliseconds, DEFAULT_AMPLITUDE)
+
+        /**
+         * Returns a [WaveformSignal.Atom] that turns on the vibrator for the specified duration at
+         * the specified amplitude.
+         *
+         * @sample androidx.core.haptics.samples.AmplitudeWaveform
+         *
+         * @param duration The duration for the vibration.
+         * @param amplitude The vibration strength, with 1 representing maximum amplitude, and 0
+         *   representing off - equivalent to calling [off].
+         */
+        @RequiresApi(Build.VERSION_CODES.O)
+        @JvmStatic
+        fun on(duration: java.time.Duration, @FloatRange(from = 0.0, to = 1.0) amplitude: Float) =
+            ConstantVibrationAtom(duration.toKotlinDuration(), amplitude)
+
+        /**
+         * Returns a [WaveformSignal.Atom] that turns on the vibrator for the specified duration at
+         * the specified amplitude.
+         *
+         * @sample androidx.core.haptics.samples.AmplitudeWaveform
+         *
+         * @param durationMillis The duration for the vibration, in milliseconds.
+         * @param amplitude The vibration strength, with 1 representing maximum amplitude, and 0
+         *   representing off - equivalent to calling [off].
+         */
+        @JvmStatic
+        fun on(durationMillis: Long, @FloatRange(from = 0.0, to = 1.0) amplitude: Float) =
+            ConstantVibrationAtom(durationMillis.milliseconds, amplitude)
+    }
+
+    /**
+     * Returns a [RepeatingWaveformSignal] to play this waveform on repeat until it's canceled.
+     *
+     * @sample androidx.core.haptics.samples.PatternWaveformRepeat
+     */
+    fun repeat(): RepeatingWaveformSignal =
+        RepeatingWaveformSignal(initialWaveform = null, repeatingWaveform = this)
+
+    /**
+     * Returns a [RepeatingWaveformSignal] that starts with this waveform signal then plays the
+     * given waveform signal on repeat until the vibration is canceled.
+     *
+     * @sample androidx.core.haptics.samples.PatternThenRepeatExistingWaveform
+     *
+     * @param waveformToRepeat The waveform to be played on repeat after this waveform.
+     */
+    fun thenRepeat(waveformToRepeat: WaveformSignal): RepeatingWaveformSignal =
+        RepeatingWaveformSignal(initialWaveform = this, repeatingWaveform = waveformToRepeat)
+
+    /**
+     * Returns a [RepeatingWaveformSignal] that starts with this waveform signal then plays the
+     * given waveform atoms on repeat until the vibration is canceled.
+     *
+     * @sample androidx.core.haptics.samples.PatternThenRepeatAmplitudeWaveform
+     *
+     * @param atoms The [WaveformSignal.Atom] instances that define the repeating [WaveformSignal]
+     *   to be played after this waveform.
+     */
+    fun thenRepeat(vararg atoms: Atom): RepeatingWaveformSignal =
+        thenRepeat(waveformOf(*atoms))
+
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other !is WaveformSignal) return false
+        if (atoms != other.atoms) return false
+        return true
+    }
+
+    override fun hashCode(): Int {
+        return atoms.hashCode()
+    }
+
+    override fun toString(): String {
+        return "WaveformSignal(${atoms.joinToString()})"
+    }
+
+    override fun toVibration(): VibrationWrapper? =
+        HapticSignalConverter.toVibration(initialWaveform = this, repeatingWaveform = null)
+
+    /**
+     * A [WaveformSignal.Atom] is a building block for creating a [WaveformSignal].
+     *
+     * Waveform signal atoms describe how vibration parameters change over time. They can describe
+     * a constant vibration sustained for a fixed duration, for example, which can be used to create
+     * a step waveform. They can also be used to describe simpler on-off vibration patterns.
+     *
+     * @sample androidx.core.haptics.samples.PatternWaveform
+     * @sample androidx.core.haptics.samples.AmplitudeWaveform
+     */
+    abstract class Atom internal constructor()
+
+    /**
+     * A [ConstantVibrationAtom] plays a constant vibration for the specified period of time.
+     *
+     * Constant vibrations can be played in sequence to create custom waveform signals.
+     *
+     * The amplitude determines the strength of the vibration, defined as a value in the range
+     * [0f..1f]. Zero amplitude implies the vibrator motor should be off. The amplitude can also be
+     * defined by [DEFAULT_AMPLITUDE], which will vibrate constantly at a hardware-specific default
+     * vibration strength.
+     *
+     * @sample androidx.core.haptics.samples.PatternWaveform
+     * @sample androidx.core.haptics.samples.AmplitudeWaveform
+     */
+    class ConstantVibrationAtom internal constructor(
+
+        duration: Duration,
+
+        /**
+         * The vibration strength.
+         *
+         * Zero amplitude turns the vibrator off for the specified duration, and [DEFAULT_AMPLITUDE]
+         * uses a hardware-specific default vibration strength.
+         */
+        val amplitude: Float,
+
+    ) : Atom() {
+        /**
+         * The duration to sustain the constant vibration, in milliseconds.
+         */
+        val durationMillis: Long
+
+        init {
+            require(duration.isFinite() && !duration.isNegative()) {
+                "Constant vibration duration must be finite and non-negative: $duration"
+            }
+            require(amplitude in (0.0..1.0) || amplitude == DEFAULT_AMPLITUDE) {
+                "Constant vibration amplitude must be in [0,1]: $amplitude"
+            }
+            durationMillis = duration.inWholeMilliseconds
+        }
+
+        companion object {
+            /**
+             * The [amplitude] value that represents a hardware-specific default vibration strength.
+             */
+            const val DEFAULT_AMPLITUDE: Float = -1f
+        }
+
+        override fun equals(other: Any?): Boolean {
+            if (this === other) return true
+            if (other !is ConstantVibrationAtom) return false
+            if (durationMillis != other.durationMillis) return false
+            if (amplitude != other.amplitude) return false
+            return true
+        }
+
+        override fun hashCode(): Int {
+            return Objects.hash(durationMillis, amplitude)
+        }
+
+        override fun toString(): String {
+            return "ConstantVibrationAtom(durationMillis=$durationMillis" +
+                ", amplitude=${if (amplitude == DEFAULT_AMPLITUDE) "default" else amplitude})"
+        }
+    }
+}
+
+/**
+ * A [RepeatingWaveformSignal] describes an infinite haptic signal where a waveform signal is played
+ * on repeat until canceled.
+ *
+ * A repeating waveform signal has an optional initial [WaveformSignal] that plays once before the
+ * repeating waveform signal is played on repeat until the vibration is canceled.
+ *
+ * @sample androidx.core.haptics.samples.RepeatingAmplitudeWaveform
+ */
+class RepeatingWaveformSignal internal constructor(
+
+    /**
+     * The optional initial waveform signal to be played once at the beginning of the vibration.
+     */
+    val initialWaveform: WaveformSignal?,
+
+    /**
+     * The waveform signal to be repeated after the initial waveform.
+     */
+    val repeatingWaveform: WaveformSignal,
+
+) : InfiniteSignal() {
+
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other !is RepeatingWaveformSignal) return false
+        if (initialWaveform != other.initialWaveform) return false
+        if (repeatingWaveform != other.repeatingWaveform) return false
+        return true
+    }
+
+    override fun hashCode(): Int {
+        return Objects.hash(initialWaveform, repeatingWaveform)
+    }
+
+    override fun toString(): String {
+        return "RepeatingWaveformSignal(initial=$initialWaveform, repeating=$repeatingWaveform)"
+    }
+
+    override fun toVibration(): VibrationWrapper? =
+        HapticSignalConverter.toVibration(
+            initialWaveform = initialWaveform,
+            repeatingWaveform = repeatingWaveform,
+        )
+}
diff --git a/credentials/credentials-fido/credentials-fido/api/current.txt b/credentials/credentials-fido/credentials-fido/api/current.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/credentials/credentials-fido/credentials-fido/api/current.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/credentials/credentials-fido/credentials-fido/api/res-current.txt b/credentials/credentials-fido/credentials-fido/api/res-current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/credentials/credentials-fido/credentials-fido/api/res-current.txt
diff --git a/credentials/credentials-fido/credentials-fido/api/restricted_current.txt b/credentials/credentials-fido/credentials-fido/api/restricted_current.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/credentials/credentials-fido/credentials-fido/api/restricted_current.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/credentials/credentials-fido/credentials-fido/build.gradle b/credentials/credentials-fido/credentials-fido/build.gradle
new file mode 100644
index 0000000..400e738
--- /dev/null
+++ b/credentials/credentials-fido/credentials-fido/build.gradle
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import androidx.build.LibraryType
+
+plugins {
+    id("AndroidXPlugin")
+    id("com.android.library")
+    id("org.jetbrains.kotlin.android")
+}
+
+dependencies {
+    api(libs.kotlinStdlib)
+    api project(":credentials:credentials")
+
+    androidTestImplementation(libs.junit)
+    androidTestImplementation(libs.testExtJunit)
+    androidTestImplementation(libs.testCore)
+    androidTestImplementation(libs.testRunner)
+    androidTestImplementation(libs.testRules)
+    androidTestImplementation(libs.mockitoAndroid)
+    androidTestImplementation(libs.truth)
+    androidTestImplementation(libs.multidex)
+    androidTestImplementation(project(":internal-testutils-truth"))
+    androidTestImplementation(libs.kotlinCoroutinesAndroid)
+    androidTestImplementation("androidx.core:core-ktx:1.10.0")
+}
+
+android {
+    namespace "androidx.credentials.fido"
+
+    defaultConfig {
+        minSdkVersion 19
+        multiDexEnabled = true
+    }
+}
+
+androidx {
+    name = "credentials-fido"
+    type = LibraryType.PUBLISHED_LIBRARY
+    inceptionYear = "2023"
+    description = "Util library for apps using FIDO"
+}
diff --git a/credentials/credentials-fido/credentials-fido/proguard-rules.pro b/credentials/credentials-fido/credentials-fido/proguard-rules.pro
new file mode 100644
index 0000000..4cced1e
--- /dev/null
+++ b/credentials/credentials-fido/credentials-fido/proguard-rules.pro
@@ -0,0 +1,4 @@
+-if class androidx.credentials.CredentialManager
+-keep class androidx.credentials.passkeys.** {
+  *;
+}
\ No newline at end of file
diff --git a/credentials/credentials-fido/credentials-fido/src/androidTest/AndroidManifest.xml b/credentials/credentials-fido/credentials-fido/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000..dc727a5
--- /dev/null
+++ b/credentials/credentials-fido/credentials-fido/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<!--
+  Copyright 2023 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <application>
+    </application>
+</manifest>
\ No newline at end of file
diff --git a/credentials/credentials-fido/credentials-fido/src/main/AndroidManifest.xml b/credentials/credentials-fido/credentials-fido/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..d8a4ecd
--- /dev/null
+++ b/credentials/credentials-fido/credentials-fido/src/main/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<!--
+  Copyright 2023 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<manifest xmlns:tools="http://schemas.android.com/tools"
+    xmlns:android="http://schemas.android.com/apk/res/android">
+    <application>
+    </application>
+</manifest>
diff --git a/credentials/credentials-fido/credentials-fido/src/main/androidx/credentials/androidx-credentials-credentials-fido-documentation.md b/credentials/credentials-fido/credentials-fido/src/main/androidx/credentials/androidx-credentials-credentials-fido-documentation.md
new file mode 100644
index 0000000..b0450b7
--- /dev/null
+++ b/credentials/credentials-fido/credentials-fido/src/main/androidx/credentials/androidx-credentials-credentials-fido-documentation.md
@@ -0,0 +1,7 @@
+# Module root
+
+CREDENTIALS CREDENTIALS FIDO
+
+# Package androidx.credentials.fido
+
+This package contains utility functions for FIDO app developers.
\ No newline at end of file
diff --git a/camera/camera-effects/src/main/java/androidx/camera/effects/Portrait.java b/credentials/credentials-fido/credentials-fido/src/main/java/androidx/credentials/fido/EmptyActivity.kt
similarity index 62%
copy from camera/camera-effects/src/main/java/androidx/camera/effects/Portrait.java
copy to credentials/credentials-fido/credentials-fido/src/main/java/androidx/credentials/fido/EmptyActivity.kt
index 7a355f8..20839f9 100644
--- a/camera/camera-effects/src/main/java/androidx/camera/effects/Portrait.java
+++ b/credentials/credentials-fido/credentials-fido/src/main/java/androidx/credentials/fido/EmptyActivity.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2022 The Android Open Source Project
+ * Copyright 2023 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,15 +14,12 @@
  * limitations under the License.
  */
 
-package androidx.camera.effects;
+package androidx.credentials.fido
 
-import androidx.annotation.RestrictTo;
+import android.app.Activity
+import androidx.annotation.RestrictTo
 
-/**
- * Provides a portrait post-processing effect.
- *
- */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public class Portrait {
-    // TODO: implement this
-}
+/** Remove this class when we add the code (b/292103206). */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+@Suppress("Deprecation", "ForbiddenSuperClass")
+open class EmptyActivity : Activity()
diff --git a/credentials/credentials-play-services-auth/src/androidTest/java/androidx/credentials/playservices/TestUtils.kt b/credentials/credentials-play-services-auth/src/androidTest/java/androidx/credentials/playservices/TestUtils.kt
index f1cf823..4c5226d 100644
--- a/credentials/credentials-play-services-auth/src/androidTest/java/androidx/credentials/playservices/TestUtils.kt
+++ b/credentials/credentials-play-services-auth/src/androidTest/java/androidx/credentials/playservices/TestUtils.kt
@@ -75,13 +75,16 @@
                 val superValues = superset.get(key)
 
                 if ((values::class.java != superValues::class.java || values::class.java !=
-                    requiredValues::class.java) && requiredValues !is Boolean
+                        requiredValues::class.java) && requiredValues !is Boolean
                 ) {
                     return false
                 }
                 if (requiredValues is JSONObject) {
-                    if (!isSubsetJson(superValues as JSONObject, values as JSONObject,
-                            requiredValues)) {
+                    if (!isSubsetJson(
+                            superValues as JSONObject, values as JSONObject,
+                            requiredValues
+                        )
+                    ) {
                         return false
                     }
                 } else if (values is JSONArray) {
@@ -147,6 +150,7 @@
             ConnectionResult.SERVICE_INVALID, ConnectionResult.SERVICE_MISSING,
             ConnectionResult.SERVICE_MISSING_PERMISSION, ConnectionResult.SERVICE_UPDATING,
             ConnectionResult.SERVICE_VERSION_UPDATE_REQUIRED, ConnectionResult.SIGN_IN_FAILED,
-            ConnectionResult.SIGN_IN_REQUIRED, ConnectionResult.TIMEOUT)
+            ConnectionResult.SIGN_IN_REQUIRED, ConnectionResult.TIMEOUT
+        )
     }
 }
diff --git a/credentials/credentials-play-services-auth/src/androidTest/java/androidx/credentials/playservices/createpublickeycredential/CreatePublicKeyCredentialControllerTestUtils.kt b/credentials/credentials-play-services-auth/src/androidTest/java/androidx/credentials/playservices/createpublickeycredential/CreatePublicKeyCredentialControllerTestUtils.kt
index de8ef2b..2dbf889 100644
--- a/credentials/credentials-play-services-auth/src/androidTest/java/androidx/credentials/playservices/createpublickeycredential/CreatePublicKeyCredentialControllerTestUtils.kt
+++ b/credentials/credentials-play-services-auth/src/androidTest/java/androidx/credentials/playservices/createpublickeycredential/CreatePublicKeyCredentialControllerTestUtils.kt
@@ -17,6 +17,7 @@
 package androidx.credentials.playservices.createkeycredential
 
 import androidx.credentials.playservices.TestUtils
+import androidx.credentials.playservices.controllers.CreatePublicKeyCredential.PublicKeyCredentialControllerUtility
 import com.google.android.gms.fido.common.Transport
 import com.google.android.gms.fido.fido2.api.common.PublicKeyCredentialCreationOptions
 import org.json.JSONArray
@@ -26,6 +27,8 @@
 class CreatePublicKeyCredentialControllerTestUtils {
     companion object {
 
+        const val TAG = "PasskeyTestUtils"
+
          // optional and not required key 'transports' is missing in the JSONObject that composes
          // up the JSONArray found at key 'excludeCredentials'
          const val OPTIONAL_FIELD_MISSING_OPTIONAL_SUBFIELD = ("{\"rp\": {\"name\": " +
@@ -323,5 +326,122 @@
                 }
             }
         }
+
+        /**
+         * Helps generate a PublicKeyCredential response json format to start tests with, locally
+         * for example.
+         *
+         * Usage details as follows:
+         *
+         *     val byteArrayClientDataJson = byteArrayOf(0x48, 101, 108, 108, 111)
+         *     val byteArrayAuthenticatorData = byteArrayOf(0x48, 101, 108, 108, 112)
+         *     val byteArraySignature = byteArrayOf(0x48, 101, 108, 108, 113)
+         *     val byteArrayUserHandle = byteArrayOf(0x48, 101, 108, 108, 114)
+         *     val publicKeyCredId = "id"
+         *     val publicKeyCredRawId = byteArrayOf(0x48, 101, 108, 108, 115)
+         *     val publicKeyCredType = "type"
+         *     val authenticatorAttachment = "platform"
+         *     val hasClientExtensionOutputs = true
+         *     val isDiscoverableCredential = true
+         *     val expectedClientExtensions = "{\"credProps\":{\"rk\":true}}"
+         *
+         *     val json = PublicKeyCredentialControllerUtility.beginSignInAssertionResponse(
+         *       byteArrayClientDataJson,
+         *       byteArrayAuthenticatorData,
+         *       byteArraySignature,
+         *       byteArrayUserHandle,
+         *       publicKeyCredId,
+         *       publicKeyCredRawId,
+         *       publicKeyCredType,
+         *       authenticatorAttachment,
+         *       hasClientExtensionOutputs,
+         *       isDiscoverableCredential
+         *     )
+         *
+         * The json can be used as necessary, even if only to generate a log with which to pull
+         * the string from (to then further use that string in other test cases).
+         */
+        fun getPublicKeyCredentialResponseGenerator(
+            clientDataJSON: ByteArray,
+            authenticatorData: ByteArray,
+            signature: ByteArray,
+            userHandle: ByteArray?,
+            publicKeyCredId: String,
+            publicKeyCredRawId: ByteArray,
+            publicKeyCredType: String,
+            authenticatorAttachment: String?,
+            hasClientExtensionResults: Boolean,
+            isDiscoverableCredential: Boolean?
+        ): JSONObject {
+            val json = JSONObject()
+            val responseJson = JSONObject()
+            responseJson.put(
+                PublicKeyCredentialControllerUtility.JSON_KEY_CLIENT_DATA,
+                PublicKeyCredentialControllerUtility.b64Encode(clientDataJSON)
+            )
+            responseJson.put(
+                PublicKeyCredentialControllerUtility.JSON_KEY_AUTH_DATA,
+                PublicKeyCredentialControllerUtility.b64Encode(authenticatorData)
+            )
+            responseJson.put(
+                PublicKeyCredentialControllerUtility.JSON_KEY_SIGNATURE,
+                PublicKeyCredentialControllerUtility.b64Encode(signature)
+            )
+            userHandle?.let {
+                responseJson.put(
+                    PublicKeyCredentialControllerUtility.JSON_KEY_USER_HANDLE,
+                    PublicKeyCredentialControllerUtility.b64Encode(userHandle)
+                )
+            }
+            json.put(PublicKeyCredentialControllerUtility.JSON_KEY_RESPONSE, responseJson)
+            json.put(PublicKeyCredentialControllerUtility.JSON_KEY_ID, publicKeyCredId)
+            json.put(
+                PublicKeyCredentialControllerUtility.JSON_KEY_RAW_ID,
+                PublicKeyCredentialControllerUtility.b64Encode(publicKeyCredRawId)
+            )
+            json.put(PublicKeyCredentialControllerUtility.JSON_KEY_TYPE, publicKeyCredType)
+            addOptionalAuthenticatorAttachmentAndRequiredExtensions(
+                authenticatorAttachment,
+                hasClientExtensionResults,
+                isDiscoverableCredential,
+                json
+            )
+            return json;
+        }
+
+        // This can be shared by both get and create flow response parsers, fills 'json'.
+        private fun addOptionalAuthenticatorAttachmentAndRequiredExtensions(
+            authenticatorAttachment: String?,
+            hasClientExtensionResults: Boolean,
+            isDiscoverableCredential: Boolean?,
+            json: JSONObject
+        ) {
+
+            json.putOpt(
+                PublicKeyCredentialControllerUtility.JSON_KEY_AUTH_ATTACHMENT,
+                authenticatorAttachment
+            )
+
+            val clientExtensionsJson = JSONObject()
+
+            if (hasClientExtensionResults) {
+                if (isDiscoverableCredential != null) {
+                    val credPropsObject = JSONObject()
+                    credPropsObject.put(
+                        PublicKeyCredentialControllerUtility.JSON_KEY_RK,
+                        isDiscoverableCredential
+                    )
+                    clientExtensionsJson.put(
+                        PublicKeyCredentialControllerUtility.JSON_KEY_CRED_PROPS,
+                        credPropsObject
+                    )
+                }
+            }
+
+            json.put(
+                PublicKeyCredentialControllerUtility.JSON_KEY_CLIENT_EXTENSION_RESULTS,
+                clientExtensionsJson
+            )
+        }
     }
 }
diff --git a/credentials/credentials-play-services-auth/src/androidTest/java/androidx/credentials/playservices/createpublickeycredential/PublicKeyCredentialControllerUtilityTest.kt b/credentials/credentials-play-services-auth/src/androidTest/java/androidx/credentials/playservices/createpublickeycredential/PublicKeyCredentialControllerUtilityTest.kt
index 80617b9..17af5dc 100644
--- a/credentials/credentials-play-services-auth/src/androidTest/java/androidx/credentials/playservices/createpublickeycredential/PublicKeyCredentialControllerUtilityTest.kt
+++ b/credentials/credentials-play-services-auth/src/androidTest/java/androidx/credentials/playservices/createpublickeycredential/PublicKeyCredentialControllerUtilityTest.kt
@@ -149,226 +149,6 @@
   }
 
   @Test
-  fun toAssertPasskeyResponse_authenticatorAssertionResponse_success() {
-    val byteArrayClientDataJson = byteArrayOf(0x48, 101, 108, 108, 111)
-    val byteArrayAuthenticatorData = byteArrayOf(0x48, 101, 108, 108, 112)
-    val byteArraySignature = byteArrayOf(0x48, 101, 108, 108, 113)
-    val byteArrayUserHandle = byteArrayOf(0x48, 101, 108, 108, 114)
-    val json = JSONObject()
-    val publicKeyCredId = "id"
-    val publicKeyCredRawId = byteArrayOf(0x48, 101, 108, 108, 115)
-    val publicKeyCredType = "type"
-    val authenticatorAttachment = "platform"
-    val hasClientExtensionOutputs = true
-    val isDiscoverableCredential = true
-    val expectedClientExtensions = "{\"credProps\":{\"rk\":true}}"
-
-    PublicKeyCredentialControllerUtility.beginSignInAssertionResponse(
-      byteArrayClientDataJson,
-      byteArrayAuthenticatorData,
-      byteArraySignature,
-      byteArrayUserHandle,
-      json,
-      publicKeyCredId,
-      publicKeyCredRawId,
-      publicKeyCredType,
-      authenticatorAttachment,
-      hasClientExtensionOutputs,
-      isDiscoverableCredential
-    )
-
-    assertThat(json.get(PublicKeyCredentialControllerUtility.JSON_KEY_ID))
-      .isEqualTo(publicKeyCredId)
-    assertThat(json.get(PublicKeyCredentialControllerUtility.JSON_KEY_RAW_ID))
-      .isEqualTo(PublicKeyCredentialControllerUtility.b64Encode(publicKeyCredRawId))
-    assertThat(json.get(PublicKeyCredentialControllerUtility.JSON_KEY_TYPE))
-      .isEqualTo(publicKeyCredType)
-    assertThat(json.get(PublicKeyCredentialControllerUtility.JSON_KEY_AUTH_ATTACHMENT))
-      .isEqualTo(authenticatorAttachment)
-    assertThat(
-        json
-          .getJSONObject(PublicKeyCredentialControllerUtility.JSON_KEY_CLIENT_EXTENSION_RESULTS)
-          .toString()
-      )
-      .isEqualTo(expectedClientExtensions)
-
-    // There is some embedded JSON so we should make sure we test that.
-    var embeddedResponse =
-      json.getJSONObject(PublicKeyCredentialControllerUtility.JSON_KEY_RESPONSE)
-    assertThat(embeddedResponse.get(PublicKeyCredentialControllerUtility.JSON_KEY_CLIENT_DATA))
-      .isEqualTo(PublicKeyCredentialControllerUtility.b64Encode(byteArrayClientDataJson))
-    assertThat(embeddedResponse.get(PublicKeyCredentialControllerUtility.JSON_KEY_AUTH_DATA))
-      .isEqualTo(PublicKeyCredentialControllerUtility.b64Encode(byteArrayAuthenticatorData))
-    assertThat(embeddedResponse.get(PublicKeyCredentialControllerUtility.JSON_KEY_SIGNATURE))
-      .isEqualTo(PublicKeyCredentialControllerUtility.b64Encode(byteArraySignature))
-    assertThat(embeddedResponse.get(PublicKeyCredentialControllerUtility.JSON_KEY_USER_HANDLE))
-      .isEqualTo(PublicKeyCredentialControllerUtility.b64Encode(byteArrayUserHandle))
-
-    // ClientExtensions are another group of embedded JSON
-    var clientExtensions =
-      json.getJSONObject(PublicKeyCredentialControllerUtility.JSON_KEY_CLIENT_EXTENSION_RESULTS)
-    assertThat(clientExtensions.get(PublicKeyCredentialControllerUtility.JSON_KEY_CRED_PROPS))
-      .isNotNull()
-    assertThat(
-        clientExtensions
-          .getJSONObject(PublicKeyCredentialControllerUtility.JSON_KEY_CRED_PROPS)
-          .getBoolean(PublicKeyCredentialControllerUtility.JSON_KEY_RK)
-      )
-      .isTrue()
-  }
-
-  @Test
-  fun toAssertPasskeyResponse_authenticatorAssertionResponse_noUserHandle_success() {
-    val byteArrayClientDataJson = byteArrayOf(0x48, 101, 108, 108, 111)
-    val byteArrayAuthenticatorData = byteArrayOf(0x48, 101, 108, 108, 112)
-    val byteArraySignature = byteArrayOf(0x48, 101, 108, 108, 113)
-    val json = JSONObject()
-    val publicKeyCredId = "id"
-    val publicKeyCredRawId = byteArrayOf(0x48, 101, 108, 108, 115)
-    val publicKeyCredType = "type"
-    val authenticatorAttachment = "platform"
-    val hasClientExtensionOutputs = false
-
-    PublicKeyCredentialControllerUtility.beginSignInAssertionResponse(
-      byteArrayClientDataJson,
-      byteArrayAuthenticatorData,
-      byteArraySignature,
-      null,
-      json,
-      publicKeyCredId,
-      publicKeyCredRawId,
-      publicKeyCredType,
-      authenticatorAttachment,
-      hasClientExtensionOutputs,
-      null
-    )
-
-    assertThat(json.get(PublicKeyCredentialControllerUtility.JSON_KEY_ID))
-      .isEqualTo(publicKeyCredId)
-    assertThat(json.get(PublicKeyCredentialControllerUtility.JSON_KEY_RAW_ID))
-      .isEqualTo(PublicKeyCredentialControllerUtility.b64Encode(publicKeyCredRawId))
-    assertThat(json.get(PublicKeyCredentialControllerUtility.JSON_KEY_TYPE))
-      .isEqualTo(publicKeyCredType)
-    assertThat(json.get(PublicKeyCredentialControllerUtility.JSON_KEY_AUTH_ATTACHMENT))
-      .isEqualTo(authenticatorAttachment)
-    assertThat(
-        json
-          .getJSONObject(PublicKeyCredentialControllerUtility.JSON_KEY_CLIENT_EXTENSION_RESULTS)
-          .toString()
-      )
-      .isEqualTo(JSONObject().toString())
-
-    // There is some embedded JSON so we should make sure we test that.
-    var embeddedResponse =
-      json.getJSONObject(PublicKeyCredentialControllerUtility.JSON_KEY_RESPONSE)
-    assertThat(embeddedResponse.get(PublicKeyCredentialControllerUtility.JSON_KEY_CLIENT_DATA))
-      .isEqualTo(PublicKeyCredentialControllerUtility.b64Encode(byteArrayClientDataJson))
-    assertThat(embeddedResponse.get(PublicKeyCredentialControllerUtility.JSON_KEY_AUTH_DATA))
-      .isEqualTo(PublicKeyCredentialControllerUtility.b64Encode(byteArrayAuthenticatorData))
-    assertThat(embeddedResponse.get(PublicKeyCredentialControllerUtility.JSON_KEY_SIGNATURE))
-      .isEqualTo(PublicKeyCredentialControllerUtility.b64Encode(byteArraySignature))
-    assertThat(embeddedResponse.has(PublicKeyCredentialControllerUtility.JSON_KEY_USER_HANDLE))
-      .isFalse()
-  }
-
-  @Test
-  fun toAssertPasskeyResponse_authenticatorAssertionResponse_noAuthenticatorAttachment_success() {
-    val byteArrayClientDataJson = byteArrayOf(0x48, 101, 108, 108, 111)
-    val byteArrayAuthenticatorData = byteArrayOf(0x48, 101, 108, 108, 112)
-    val byteArraySignature = byteArrayOf(0x48, 101, 108, 108, 113)
-    val json = JSONObject()
-    val publicKeyCredId = "id"
-    val publicKeyCredRawId = byteArrayOf(0x48, 101, 108, 108, 115)
-    val publicKeyCredType = "type"
-    val hasClientExtensionOutputs = false
-
-    PublicKeyCredentialControllerUtility.beginSignInAssertionResponse(
-      byteArrayClientDataJson,
-      byteArrayAuthenticatorData,
-      byteArraySignature,
-      null,
-      json,
-      publicKeyCredId,
-      publicKeyCredRawId,
-      publicKeyCredType,
-      null,
-      hasClientExtensionOutputs,
-      null
-    )
-
-    assertThat(json.get(PublicKeyCredentialControllerUtility.JSON_KEY_ID))
-      .isEqualTo(publicKeyCredId)
-    assertThat(json.get(PublicKeyCredentialControllerUtility.JSON_KEY_RAW_ID))
-      .isEqualTo(PublicKeyCredentialControllerUtility.b64Encode(publicKeyCredRawId))
-    assertThat(json.get(PublicKeyCredentialControllerUtility.JSON_KEY_TYPE))
-      .isEqualTo(publicKeyCredType)
-    assertThat(json.optJSONObject(PublicKeyCredentialControllerUtility.JSON_KEY_AUTH_ATTACHMENT))
-      .isNull()
-    assertThat(
-        json
-          .getJSONObject(PublicKeyCredentialControllerUtility.JSON_KEY_CLIENT_EXTENSION_RESULTS)
-          .toString()
-      )
-      .isEqualTo(JSONObject().toString())
-
-    // There is some embedded JSON so we should make sure we test that.
-    var embeddedResponse =
-      json.getJSONObject(PublicKeyCredentialControllerUtility.JSON_KEY_RESPONSE)
-    assertThat(embeddedResponse.get(PublicKeyCredentialControllerUtility.JSON_KEY_CLIENT_DATA))
-      .isEqualTo(PublicKeyCredentialControllerUtility.b64Encode(byteArrayClientDataJson))
-    assertThat(embeddedResponse.get(PublicKeyCredentialControllerUtility.JSON_KEY_AUTH_DATA))
-      .isEqualTo(PublicKeyCredentialControllerUtility.b64Encode(byteArrayAuthenticatorData))
-    assertThat(embeddedResponse.get(PublicKeyCredentialControllerUtility.JSON_KEY_SIGNATURE))
-      .isEqualTo(PublicKeyCredentialControllerUtility.b64Encode(byteArraySignature))
-    assertThat(embeddedResponse.has(PublicKeyCredentialControllerUtility.JSON_KEY_USER_HANDLE))
-      .isFalse()
-  }
-
-  @Test
-  fun toCreatePasskeyResponseJson_addOptionalAuthenticatorAttachmentAndRequiredExt() {
-    val json = JSONObject()
-
-    PublicKeyCredentialControllerUtility.addOptionalAuthenticatorAttachmentAndRequiredExtensions(
-      "attachment",
-      true,
-      true,
-      json
-    )
-
-    var clientExtensionResults =
-      json.getJSONObject(PublicKeyCredentialControllerUtility.JSON_KEY_CLIENT_EXTENSION_RESULTS)
-    var credPropsObject =
-      clientExtensionResults.getJSONObject(PublicKeyCredentialControllerUtility.JSON_KEY_CRED_PROPS)
-
-    assertThat(json.get(PublicKeyCredentialControllerUtility.JSON_KEY_AUTH_ATTACHMENT))
-      .isEqualTo("attachment")
-    assertThat(credPropsObject.get(PublicKeyCredentialControllerUtility.JSON_KEY_RK))
-      .isEqualTo(true)
-  }
-
-  @Test
-  fun toCreatePasskeyResponseJson_addOptionalAuthenticatorAttachmentAndRequiredExt_noClientExt() {
-    val json = JSONObject()
-
-    PublicKeyCredentialControllerUtility.addOptionalAuthenticatorAttachmentAndRequiredExtensions(
-      "attachment",
-      false,
-      null,
-      json
-    )
-
-    var clientExtensionResults =
-      json.getJSONObject(PublicKeyCredentialControllerUtility.JSON_KEY_CLIENT_EXTENSION_RESULTS)
-
-    assertThat(json.get(PublicKeyCredentialControllerUtility.JSON_KEY_AUTH_ATTACHMENT))
-      .isEqualTo("attachment")
-    assertThat(
-        clientExtensionResults.optJSONObject(PublicKeyCredentialControllerUtility.JSON_KEY_RK)
-      )
-      .isNull()
-  }
-
-  @Test
   fun toCreatePasskeyResponseJson_addAuthenticatorAttestationResponse_success() {
     val json = JSONObject()
     val byteArrayClientDataJson = byteArrayOf(0x48, 101, 108, 108, 111)
@@ -417,16 +197,16 @@
       )
     var output = PublicKeyCredentialControllerUtility.convertJSON(json)
 
-    assertThat(output.getUser().getId()).isNotEmpty()
-    assertThat(output.getUser().getName()).isEqualTo("Name of User")
-    assertThat(output.getUser().getDisplayName()).isEqualTo("Display Name of User")
-    assertThat(output.getUser().getIcon()).isEqualTo("icon.png")
-    assertThat(output.getChallenge()).isNotEmpty()
-    assertThat(output.getRp().getId()).isNotEmpty()
-    assertThat(output.getRp().getName()).isEqualTo("Name of RP")
-    assertThat(output.getRp().getIcon()).isEqualTo("rpicon.png")
-    assertThat(output.getParameters().get(0).getAlgorithmIdAsInteger()).isEqualTo(-7)
-    assertThat(output.getParameters().get(0).getTypeAsString()).isEqualTo("public-key")
+    assertThat(output.user.id).isNotEmpty()
+    assertThat(output.user.name).isEqualTo("Name of User")
+    assertThat(output.user.displayName).isEqualTo("Display Name of User")
+    assertThat(output.user.icon).isEqualTo("icon.png")
+    assertThat(output.challenge).isNotEmpty()
+    assertThat(output.rp.id).isNotEmpty()
+    assertThat(output.rp.name).isEqualTo("Name of RP")
+    assertThat(output.rp.icon).isEqualTo("rpicon.png")
+    assertThat(output.parameters[0].algorithmIdAsInteger).isEqualTo(-7)
+    assertThat(output.parameters[0].typeAsString).isEqualTo("public-key")
   }
 
   @Test
@@ -680,9 +460,8 @@
       )
     var output = PublicKeyCredentialControllerUtility.convertJSON(json)
 
-    assertThat(output.getAuthenticationExtensions()
-        !!.getFidoAppIdExtension()!!.getAppId()).isEqualTo("https://www.android.com/appid1")
-    assertThat(output.getAuthenticationExtensions()
-        !!.getUserVerificationMethodExtension()!!.getUvm()).isTrue()
+    assertThat(output.authenticationExtensions!!.fidoAppIdExtension!!.appId)
+      .isEqualTo("https://www.android.com/appid1")
+    assertThat(output.authenticationExtensions!!.userVerificationMethodExtension!!.uvm).isTrue()
   }
 }
diff --git a/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/CreatePublicKeyCredential/CredentialProviderCreatePublicKeyCredentialController.kt b/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/CreatePublicKeyCredential/CredentialProviderCreatePublicKeyCredentialController.kt
index 1a37158..e86df83 100644
--- a/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/CreatePublicKeyCredential/CredentialProviderCreatePublicKeyCredentialController.kt
+++ b/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/CreatePublicKeyCredential/CredentialProviderCreatePublicKeyCredentialController.kt
@@ -186,9 +186,12 @@
     @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
     public override fun convertResponseToCredentialManager(response: PublicKeyCredential):
         CreateCredentialResponse {
-        return CreatePublicKeyCredentialResponse(
-            PublicKeyCredentialControllerUtility.toCreatePasskeyResponseJson(response)
-        )
+            try {
+                return CreatePublicKeyCredentialResponse(response.toJson())
+            } catch (t: Throwable) {
+                throw CreateCredentialUnknownException("The PublicKeyCredential response json " +
+                    "had an unexpected exception when parsing: ${t.message}")
+            }
     }
 
     private fun JSONExceptionToPKCError(exception: JSONException):
diff --git a/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/CreatePublicKeyCredential/PublicKeyCredentialControllerUtility.kt b/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/CreatePublicKeyCredential/PublicKeyCredentialControllerUtility.kt
index 4b38772..b38500b 100644
--- a/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/CreatePublicKeyCredential/PublicKeyCredentialControllerUtility.kt
+++ b/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/CreatePublicKeyCredential/PublicKeyCredentialControllerUtility.kt
@@ -24,6 +24,7 @@
 import androidx.credentials.exceptions.CreateCredentialException
 import androidx.credentials.exceptions.GetCredentialCancellationException
 import androidx.credentials.exceptions.GetCredentialException
+import androidx.credentials.exceptions.GetCredentialUnknownException
 import androidx.credentials.exceptions.domerrors.AbortError
 import androidx.credentials.exceptions.domerrors.ConstraintError
 import androidx.credentials.exceptions.domerrors.DataError
@@ -45,7 +46,6 @@
 import com.google.android.gms.fido.fido2.api.common.AttestationConveyancePreference
 import com.google.android.gms.fido.fido2.api.common.AuthenticationExtensions
 import com.google.android.gms.fido.fido2.api.common.AuthenticatorAssertionResponse
-import com.google.android.gms.fido.fido2.api.common.AuthenticatorAttestationResponse
 import com.google.android.gms.fido.fido2.api.common.AuthenticatorErrorResponse
 import com.google.android.gms.fido.fido2.api.common.AuthenticatorResponse
 import com.google.android.gms.fido.fido2.api.common.AuthenticatorSelectionCriteria
@@ -136,39 +136,6 @@
       return builder.build()
     }
 
-    /** Converts the response from fido back to json so it can be passed into CredentialManager. */
-    fun toCreatePasskeyResponseJson(cred: PublicKeyCredential): String {
-      val json = JSONObject()
-      val authenticatorResponse = cred.response
-      if (authenticatorResponse is AuthenticatorAttestationResponse) {
-        val transportArray = convertToProperNamingScheme(authenticatorResponse)
-        addAuthenticatorAttestationResponse(
-          authenticatorResponse.clientDataJSON,
-          authenticatorResponse.attestationObject,
-          transportArray,
-          json
-        )
-      } else {
-        Log.e(
-          TAG,
-          "Authenticator response expected registration response but " +
-            "got: ${authenticatorResponse.javaClass.name}"
-        )
-      }
-
-      addOptionalAuthenticatorAttachmentAndRequiredExtensions(
-        cred.authenticatorAttachment,
-        cred.clientExtensionResults != null,
-        cred.clientExtensionResults?.credProps?.isDiscoverableCredential,
-        json
-      )
-
-      json.put(JSON_KEY_ID, cred.id)
-      json.put(JSON_KEY_RAW_ID, b64Encode(cred.rawId))
-      json.put(JSON_KEY_TYPE, cred.type)
-      return json.toString()
-    }
-
     internal fun addAuthenticatorAttestationResponse(
       clientDataJSON: ByteArray,
       attestationObject: ByteArray,
@@ -182,52 +149,6 @@
       json.put(JSON_KEY_RESPONSE, responseJson)
     }
 
-    private fun convertToProperNamingScheme(
-      authenticatorResponse: AuthenticatorAttestationResponse
-    ): Array<out String> {
-      val transportArray = authenticatorResponse.transports
-      var ix = 0
-      for (transport in transportArray) {
-        if (transport == "cable") {
-          transportArray[ix] = "hybrid"
-        }
-        ix += 1
-      }
-      return transportArray
-    }
-
-    // This can be shared by both get and create flow response parsers
-    internal fun addOptionalAuthenticatorAttachmentAndRequiredExtensions(
-      authenticatorAttachment: String?,
-      hasClientExtensionResults: Boolean,
-      isDiscoverableCredential: Boolean?,
-      json: JSONObject
-    ) {
-
-      if (authenticatorAttachment != null) {
-        json.put(JSON_KEY_AUTH_ATTACHMENT, authenticatorAttachment)
-      }
-
-      val clientExtensionsJson = JSONObject()
-
-      if (hasClientExtensionResults) {
-        try {
-          if (isDiscoverableCredential != null) {
-            val credPropsObject = JSONObject()
-            credPropsObject.put(JSON_KEY_RK, isDiscoverableCredential)
-            clientExtensionsJson.put(JSON_KEY_CRED_PROPS, credPropsObject)
-          }
-        } catch (t: Throwable) {
-          Log.e(
-            TAG,
-            "ClientExtensionResults faced possible implementation " +
-              "inconsistency in uvmEntries - $t"
-          )
-        }
-      }
-      json.put(JSON_KEY_CLIENT_EXTENSION_RESULTS, clientExtensionsJson)
-    }
-
     fun toAssertPasskeyResponse(cred: SignInCredential): String {
       var json = JSONObject()
       val publicKeyCred = cred.publicKeyCredential
@@ -240,61 +161,24 @@
           )
         }
         is AuthenticatorAssertionResponse -> {
-          beginSignInAssertionResponse(
-            authenticatorResponse.clientDataJSON,
-            authenticatorResponse.authenticatorData,
-            authenticatorResponse.signature,
-            authenticatorResponse.userHandle,
-            json,
-            publicKeyCred.id,
-            publicKeyCred.rawId,
-            publicKeyCred.type,
-            publicKeyCred.authenticatorAttachment,
-            publicKeyCred.clientExtensionResults != null,
-            publicKeyCred.clientExtensionResults?.credProps?.isDiscoverableCredential
-          )
+          try {
+            return publicKeyCred.toJson()
+          } catch (t: Throwable) {
+            throw GetCredentialUnknownException("The PublicKeyCredential response json had " +
+                "an unexpected exception when parsing: ${t.message}")
+          }
         }
         else -> {
           Log.e(
             TAG,
             "AuthenticatorResponse expected assertion response but " +
-              "got: ${authenticatorResponse.javaClass.name}"
+                "got: ${authenticatorResponse.javaClass.name}"
           )
         }
       }
       return json.toString()
     }
 
-    internal fun beginSignInAssertionResponse(
-      clientDataJSON: ByteArray,
-      authenticatorData: ByteArray,
-      signature: ByteArray,
-      userHandle: ByteArray?,
-      json: JSONObject,
-      publicKeyCredId: String,
-      publicKeyCredRawId: ByteArray,
-      publicKeyCredType: String,
-      authenticatorAttachment: String?,
-      hasClientExtensionResults: Boolean,
-      isDiscoverableCredential: Boolean?
-    ) {
-      val responseJson = JSONObject()
-      responseJson.put(JSON_KEY_CLIENT_DATA, b64Encode(clientDataJSON))
-      responseJson.put(JSON_KEY_AUTH_DATA, b64Encode(authenticatorData))
-      responseJson.put(JSON_KEY_SIGNATURE, b64Encode(signature))
-      userHandle?.let { responseJson.put(JSON_KEY_USER_HANDLE, b64Encode(userHandle)) }
-      json.put(JSON_KEY_RESPONSE, responseJson)
-      json.put(JSON_KEY_ID, publicKeyCredId)
-      json.put(JSON_KEY_RAW_ID, b64Encode(publicKeyCredRawId))
-      json.put(JSON_KEY_TYPE, publicKeyCredType)
-      addOptionalAuthenticatorAttachmentAndRequiredExtensions(
-        authenticatorAttachment,
-        hasClientExtensionResults,
-        isDiscoverableCredential,
-        json
-      )
-    }
-
     /**
      * Converts from the Credential Manager public key credential option to the Play Auth Module
      * passkey json option.
diff --git a/development/build_log_simplifier/messages.ignore b/development/build_log_simplifier/messages.ignore
index 027bd5a..01c1c3e 100644
--- a/development/build_log_simplifier/messages.ignore
+++ b/development/build_log_simplifier/messages.ignore
@@ -436,6 +436,14 @@
 WARN: Missing @param tag for parameter `previousPageKey` of function androidx\.paging\/PageKeyedDataSource\.LoadInitialCallback\/onResult\/#kotlin\.collections\.List\[TypeParam\(bounds=\[kotlin\.Any\?\]\)\]#kotlin\.Int#kotlin\.Int#TypeParam\(bounds=\[kotlin\.Any\?\]\)\?#TypeParam\(bounds=\[kotlin\.Any\?\]\)\?\/PointingToDeclaration\/
 WARN: Missing @param tag for parameter `priority` of function androidx\.camera\.camera2\.interop\/CaptureRequestOptions\/retrieveOptionWithPriority\/#androidx\.camera\.core\.impl\.Config\.Option<ValueT>#androidx\.camera\.core\.impl\.Config\.OptionPriority\/PointingToDeclaration\/
 WARN: Missing @param tag for parameter `priority` of function androidx\.camera\.core\/CameraXConfig\/retrieveOptionWithPriority\/#androidx\.camera\.core\.impl\.Config\.Option<ValueT>#androidx\.camera\.core\.impl\.Config\.OptionPriority\/PointingToDeclaration\/
+WARN: Missing @param tag for parameter `width` of function androidx\.camera\.testing\.impl\.fakes/FakeImageReaderProxy/newInstance/\#int\#int\#int\#int\#long/PointingToDeclaration/
+WARN: Missing @param tag for parameter `height` of function androidx\.camera\.testing\.impl\.fakes/FakeImageReaderProxy/newInstance/\#int\#int\#int\#int\#long/PointingToDeclaration/
+WARN: Missing @param tag for parameter `format` of function androidx\.camera\.testing\.impl\.fakes/FakeImageReaderProxy/newInstance/\#int\#int\#int\#int\#long/PointingToDeclaration/
+WARN: Missing @param tag for parameter `usage` of function androidx\.camera\.testing\.impl\.fakes/FakeImageReaderProxy/newInstance/\#int\#int\#int\#int\#long/PointingToDeclaration/
+WARN: Missing @param tag for parameter `priority` of function androidx\.camera\.testing\.impl\.fakes/FakeUseCaseConfig/retrieveOptionWithPriority/\#androidx\.camera\.core\.impl\.Config\.Option<ValueT>\#androidx\.camera\.core\.impl\.Config\.OptionPriority/PointingToDeclaration/
+WARN: Missing @param tag for parameter `classType` of function androidx\.camera\.testing\.impl\.mocks/MockConsumer/verifyAcceptCall/\#java\.lang\.Class<\?>\#boolean\#androidx\.camera\.testing\.impl\.mocks\.helpers\.CallTimes\#androidx\.camera\.testing\.impl\.mocks\.helpers\.ArgumentCaptor<T>/PointingToDeclaration/
+WARN: Missing @param tag for parameter `inOrder` of function androidx\.camera\.testing\.impl\.mocks/MockConsumer/verifyAcceptCall/\#java\.lang\.Class<\?>\#boolean\#androidx\.camera\.testing\.impl\.mocks\.helpers\.CallTimes\#androidx\.camera\.testing\.impl\.mocks\.helpers\.ArgumentCaptor<T>/PointingToDeclaration/
+WARN: Missing @param tag for parameter `callTimes` of function androidx\.camera\.testing\.impl\.mocks/MockConsumer/verifyAcceptCall/\#java\.lang\.Class<\?>\#boolean\#androidx\.camera\.testing\.impl\.mocks\.helpers\.CallTimes\#androidx\.camera\.testing\.impl\.mocks\.helpers\.ArgumentCaptor<T>/PointingToDeclaration/
 WARN: Missing @param tag for parameter `query` of function androidx\.leanback\.app\/SearchFragment\/createArgs\/#android\.os\.Bundle#java\.lang\.String\/PointingToDeclaration\/
 WARN: Missing @param tag for parameter `query` of function androidx\.leanback\.app\/SearchSupportFragment\/createArgs\/#android\.os\.Bundle#java\.lang\.String\/PointingToDeclaration\/
 WARN: Missing @param tag for parameter `radians` of function androidx\.compose\.ui\.graphics\/\/rotateRad\/androidx\.compose\.ui\.graphics\.Canvas#kotlin\.Float#kotlin\.Float#kotlin\.Float\/PointingToDeclaration\/
diff --git a/development/update-verification-metadata.sh b/development/update-verification-metadata.sh
index 7023439..d0a6593e 100755
--- a/development/update-verification-metadata.sh
+++ b/development/update-verification-metadata.sh
@@ -1,13 +1,38 @@
 #!/bin/bash
 set -e
 
+# This script updates trust entries in gradle/verification-metadata.xml
+
+# Usage: $0 [--no-dry-run] [<task>]
+
+# --no-dry-run
+#   Don't pass --dry-run to Gradle, so Gradle executes the corresponding tasks.
+#   This is not normally necessary but in some cases can be a useful workaround.
+#   When https://github.com/gradle/gradle/issues/26289 is resolved, we should reevaluate this behavior
+#
+# <task>
+#   The task to ask Gradle to run. By default this is 'bOS'
+#   When --no-dry-run is removed, we should reevaluate this behavior
+
+dryrun=true
+task="bOS"
+
+while [ "$1" != "" ]; do
+  arg="$1"
+  shift
+  if [ "$arg" == "--no-dry-run" ]; then
+    dryrun=false
+    continue
+  fi
+  task="$arg"
+done
+
 function runGradle() {
-  kmpArgs="-Pandroidx.enabled.kmp.target.platforms=+native"
-  echo running ./gradlew $kmpArgs "$@"
-  if ./gradlew $kmpArgs "$@"; then
-    echo succeeded: ./gradlew $kmpArgs "$@"
+  echo running ./gradlew "$@"
+  if ./gradlew "$@"; then
+    echo succeeded: ./gradlew "$@"
   else
-    echo failed: ./gradlew $kmpArgs "$@"
+    echo failed: ./gradlew "$@"
     return 1
   fi
 }
@@ -18,20 +43,31 @@
   # regenerate metadata
   # Need to run a clean build, https://github.com/gradle/gradle/issues/19228
   # Resolving Configurations before task execution is expected. b/297394547
-  runGradle --stacktrace --write-verification-metadata pgp,sha256 --export-keys --dry-run --clean -Pandroidx.update.signatures=true -Pandroid.dependencyResolutionAtConfigurationTime.disallow=false bOS
+  dryrunArg=""
+  if [ "$dryrun" == "true" ]; then
+    dryrunArg="--dry-run"
+  fi
+  runGradle --stacktrace --write-verification-metadata pgp,sha256 --export-keys $dryrunArg --clean -Pandroidx.update.signatures=true -Pandroid.dependencyResolutionAtConfigurationTime.disallow=false -Pandroidx.enabled.kmp.target.platforms=+native $task
 
   # update verification metadata file
-  # also remove 'version=' lines, https://github.com/gradle/gradle/issues/20192
-  cat gradle/verification-metadata.dryrun.xml | sed 's/ \(trusted-key.*\)version="[^"]*"/\1/' > gradle/verification-metadata.xml
+
+  # first, make sure the resulting file is named "verification-metadata.xml"
+  if [ "$dryrun" == "true" ]; then
+    mv gradle/verification-metadata.dryrun.xml gradle/verification-metadata.xml
+  fi
+
+  # next, remove 'version=' lines https://github.com/gradle/gradle/issues/20192
+  sed -i 's/ \(trusted-key.*\)version="[^"]*"/\1/' gradle/verification-metadata.xml
 
   # rename keyring
-  mv gradle/verification-keyring-dryrun.keys gradle/verification-keyring.keys
+  mv gradle/verification-keyring-dryrun.keys gradle/verification-keyring.keys 2>/dev/null || true
 
   # remove temporary files
   rm -f gradle/verification-keyring-dryrun.gpg
-  rm -f gradle/verification-metadata.dryrun.xml
+  rm -f gradle/verification-keyring.gpg
 }
 regenerateVerificationMetadata
 
 echo
 echo 'Done. Please check that these changes look correct (`git diff`)'
+echo "If Gradle did not make all expected updates to verification-metadata.xml, you can try '--no-dry-run'. This is slow so you may also want to specify a task. Example: $0 --dry-run exportSboms"
diff --git a/docs-public/build.gradle b/docs-public/build.gradle
index b6b1688..2954cc7 100644
--- a/docs-public/build.gradle
+++ b/docs-public/build.gradle
@@ -1,5 +1,5 @@
 plugins {
-    id("com.android.library")
+id("com.android.library")
     id("AndroidXDocsPlugin")
 }
 
@@ -8,15 +8,15 @@
 }
 
 dependencies {
-    docs("androidx.activity:activity:1.8.0-alpha07")
-    docs("androidx.activity:activity-compose:1.8.0-alpha07")
-    samples("androidx.activity:activity-compose-samples:1.8.0-alpha07")
-    docs("androidx.activity:activity-ktx:1.8.0-alpha07")
+    docs("androidx.activity:activity:1.8.0-beta01")
+    docs("androidx.activity:activity-compose:1.8.0-beta01")
+    samples("androidx.activity:activity-compose-samples:1.8.0-beta01")
+    docs("androidx.activity:activity-ktx:1.8.0-beta01")
     // ads-identifier is deprecated
     docsWithoutApiSince("androidx.ads:ads-identifier:1.0.0-alpha05")
     docsWithoutApiSince("androidx.ads:ads-identifier-common:1.0.0-alpha05")
     docsWithoutApiSince("androidx.ads:ads-identifier-provider:1.0.0-alpha05")
-    kmpDocs("androidx.annotation:annotation:1.7.0-rc01")
+    kmpDocs("androidx.annotation:annotation:1.7.0")
     docs("androidx.annotation:annotation-experimental:1.4.0-alpha01")
     docs("androidx.appcompat:appcompat:1.7.0-alpha03")
     docs("androidx.appcompat:appcompat-resources:1.7.0-alpha03")
@@ -58,57 +58,57 @@
     docs("androidx.car.app:app-projected:1.4.0-beta01")
     docs("androidx.car.app:app-testing:1.4.0-beta01")
     docs("androidx.cardview:cardview:1.0.0")
-    kmpDocs("androidx.collection:collection:1.3.0-beta01")
-    docs("androidx.collection:collection-ktx:1.3.0-beta01")
-    kmpDocs("androidx.compose.animation:animation:1.6.0-alpha04")
-    kmpDocs("androidx.compose.animation:animation-core:1.6.0-alpha04")
-    kmpDocs("androidx.compose.animation:animation-graphics:1.6.0-alpha04")
-    samples("androidx.compose.animation:animation-samples:1.6.0-alpha04")
-    samples("androidx.compose.animation:animation-core-samples:1.6.0-alpha04")
-    samples("androidx.compose.animation:animation-graphics-samples:1.6.0-alpha04")
-    kmpDocs("androidx.compose.foundation:foundation:1.6.0-alpha04")
-    kmpDocs("androidx.compose.foundation:foundation-layout:1.6.0-alpha04")
-    samples("androidx.compose.foundation:foundation-layout-samples:1.6.0-alpha04")
-    samples("androidx.compose.foundation:foundation-samples:1.6.0-alpha04")
-    kmpDocs("androidx.compose.material3:material3:1.2.0-alpha06")
-    samples("androidx.compose.material3:material3-samples:1.2.0-alpha06")
-    kmpDocs("androidx.compose.material3:material3-window-size-class:1.2.0-alpha06")
-    samples("androidx.compose.material3:material3-window-size-class-samples:1.2.0-alpha06")
-    kmpDocs("androidx.compose.material:material:1.6.0-alpha04")
-    kmpDocs("androidx.compose.material:material-icons-core:1.6.0-alpha04")
-    samples("androidx.compose.material:material-icons-core-samples:1.6.0-alpha04")
-    kmpDocs("androidx.compose.material:material-ripple:1.6.0-alpha04")
-    samples("androidx.compose.material:material-samples:1.6.0-alpha04")
-    kmpDocs("androidx.compose.runtime:runtime:1.6.0-alpha04")
-    docs("androidx.compose.runtime:runtime-livedata:1.6.0-alpha04")
-    samples("androidx.compose.runtime:runtime-livedata-samples:1.6.0-alpha04")
-    docs("androidx.compose.runtime:runtime-rxjava2:1.6.0-alpha04")
-    samples("androidx.compose.runtime:runtime-rxjava2-samples:1.6.0-alpha04")
-    docs("androidx.compose.runtime:runtime-rxjava3:1.6.0-alpha04")
-    samples("androidx.compose.runtime:runtime-rxjava3-samples:1.6.0-alpha04")
-    kmpDocs("androidx.compose.runtime:runtime-saveable:1.6.0-alpha04")
-    samples("androidx.compose.runtime:runtime-saveable-samples:1.6.0-alpha04")
-    samples("androidx.compose.runtime:runtime-samples:1.6.0-alpha04")
-    docs("androidx.compose.runtime:runtime-tracing:1.0.0-alpha04")
-    kmpDocs("androidx.compose.ui:ui:1.6.0-alpha04")
-    kmpDocs("androidx.compose.ui:ui-geometry:1.6.0-alpha04")
-    kmpDocs("androidx.compose.ui:ui-graphics:1.6.0-alpha04")
-    samples("androidx.compose.ui:ui-graphics-samples:1.6.0-alpha04")
-    kmpDocs("androidx.compose.ui:ui-test:1.6.0-alpha04")
-    kmpDocs("androidx.compose.ui:ui-test-junit4:1.6.0-alpha04")
-    samples("androidx.compose.ui:ui-test-samples:1.6.0-alpha04")
-    kmpDocs("androidx.compose.ui:ui-text:1.6.0-alpha04")
-    docs("androidx.compose.ui:ui-text-google-fonts:1.6.0-alpha04")
-    samples("androidx.compose.ui:ui-text-samples:1.6.0-alpha04")
-    kmpDocs("androidx.compose.ui:ui-tooling:1.6.0-alpha04")
-    kmpDocs("androidx.compose.ui:ui-tooling-data:1.6.0-alpha04")
-    kmpDocs("androidx.compose.ui:ui-tooling-preview:1.6.0-alpha04")
-    kmpDocs("androidx.compose.ui:ui-unit:1.6.0-alpha04")
-    samples("androidx.compose.ui:ui-unit-samples:1.6.0-alpha04")
-    kmpDocs("androidx.compose.ui:ui-util:1.6.0-alpha04")
-    docs("androidx.compose.ui:ui-viewbinding:1.6.0-alpha04")
-    samples("androidx.compose.ui:ui-viewbinding-samples:1.6.0-alpha04")
-    samples("androidx.compose.ui:ui-samples:1.6.0-alpha04")
+    kmpDocs("androidx.collection:collection:1.3.0-rc01")
+    docs("androidx.collection:collection-ktx:1.3.0-rc01")
+    kmpDocs("androidx.compose.animation:animation:1.6.0-alpha05")
+    kmpDocs("androidx.compose.animation:animation-core:1.6.0-alpha05")
+    kmpDocs("androidx.compose.animation:animation-graphics:1.6.0-alpha05")
+    samples("androidx.compose.animation:animation-samples:1.6.0-alpha05")
+    samples("androidx.compose.animation:animation-core-samples:1.6.0-alpha05")
+    samples("androidx.compose.animation:animation-graphics-samples:1.6.0-alpha05")
+    kmpDocs("androidx.compose.foundation:foundation:1.6.0-alpha05")
+    kmpDocs("androidx.compose.foundation:foundation-layout:1.6.0-alpha05")
+    samples("androidx.compose.foundation:foundation-layout-samples:1.6.0-alpha05")
+    samples("androidx.compose.foundation:foundation-samples:1.6.0-alpha05")
+    kmpDocs("androidx.compose.material3:material3:1.2.0-alpha07")
+    samples("androidx.compose.material3:material3-samples:1.2.0-alpha07")
+    kmpDocs("androidx.compose.material3:material3-window-size-class:1.2.0-alpha07")
+    samples("androidx.compose.material3:material3-window-size-class-samples:1.2.0-alpha07")
+    kmpDocs("androidx.compose.material:material:1.6.0-alpha05")
+    kmpDocs("androidx.compose.material:material-icons-core:1.6.0-alpha05")
+    samples("androidx.compose.material:material-icons-core-samples:1.6.0-alpha05")
+    kmpDocs("androidx.compose.material:material-ripple:1.6.0-alpha05")
+    samples("androidx.compose.material:material-samples:1.6.0-alpha05")
+    kmpDocs("androidx.compose.runtime:runtime:1.6.0-alpha05")
+    docs("androidx.compose.runtime:runtime-livedata:1.6.0-alpha05")
+    samples("androidx.compose.runtime:runtime-livedata-samples:1.6.0-alpha05")
+    docs("androidx.compose.runtime:runtime-rxjava2:1.6.0-alpha05")
+    samples("androidx.compose.runtime:runtime-rxjava2-samples:1.6.0-alpha05")
+    docs("androidx.compose.runtime:runtime-rxjava3:1.6.0-alpha05")
+    samples("androidx.compose.runtime:runtime-rxjava3-samples:1.6.0-alpha05")
+    kmpDocs("androidx.compose.runtime:runtime-saveable:1.6.0-alpha05")
+    samples("androidx.compose.runtime:runtime-saveable-samples:1.6.0-alpha05")
+    samples("androidx.compose.runtime:runtime-samples:1.6.0-alpha05")
+    docs("androidx.compose.runtime:runtime-tracing:1.0.0-alpha05")
+    kmpDocs("androidx.compose.ui:ui:1.6.0-alpha05")
+    kmpDocs("androidx.compose.ui:ui-geometry:1.6.0-alpha05")
+    kmpDocs("androidx.compose.ui:ui-graphics:1.6.0-alpha05")
+    samples("androidx.compose.ui:ui-graphics-samples:1.6.0-alpha05")
+    kmpDocs("androidx.compose.ui:ui-test:1.6.0-alpha05")
+    kmpDocs("androidx.compose.ui:ui-test-junit4:1.6.0-alpha05")
+    samples("androidx.compose.ui:ui-test-samples:1.6.0-alpha05")
+    kmpDocs("androidx.compose.ui:ui-text:1.6.0-alpha05")
+    docs("androidx.compose.ui:ui-text-google-fonts:1.6.0-alpha05")
+    samples("androidx.compose.ui:ui-text-samples:1.6.0-alpha05")
+    kmpDocs("androidx.compose.ui:ui-tooling:1.6.0-alpha05")
+    kmpDocs("androidx.compose.ui:ui-tooling-data:1.6.0-alpha05")
+    kmpDocs("androidx.compose.ui:ui-tooling-preview:1.6.0-alpha05")
+    kmpDocs("androidx.compose.ui:ui-unit:1.6.0-alpha05")
+    samples("androidx.compose.ui:ui-unit-samples:1.6.0-alpha05")
+    kmpDocs("androidx.compose.ui:ui-util:1.6.0-alpha05")
+    docs("androidx.compose.ui:ui-viewbinding:1.6.0-alpha05")
+    samples("androidx.compose.ui:ui-viewbinding-samples:1.6.0-alpha05")
+    samples("androidx.compose.ui:ui-samples:1.6.0-alpha05")
     docs("androidx.concurrent:concurrent-futures:1.2.0-alpha02")
     docs("androidx.concurrent:concurrent-futures-ktx:1.2.0-alpha02")
     docs("androidx.constraintlayout:constraintlayout:2.2.0-alpha12")
@@ -124,13 +124,13 @@
     docs("androidx.core:core-i18n:1.0.0-alpha01")
     docs("androidx.core:core-ktx:1.12.0-rc01")
     docs("androidx.core:core-location-altitude:1.0.0-alpha01")
-    docs("androidx.core:core-performance:1.0.0-alpha03")
-    docs("androidx.core:core-performance-play-services:1.0.0-alpha03")
-    samples("androidx.core:core-performance-samples:1.0.0-alpha03")
-    docs("androidx.core:core-performance-testing:1.0.0-alpha03")
+    docs("androidx.core:core-performance:1.0.0-beta01")
+    docs("androidx.core:core-performance-play-services:1.0.0-beta01")
+    samples("androidx.core:core-performance-samples:1.0.0-beta01")
+    docs("androidx.core:core-performance-testing:1.0.0-beta01")
     docs("androidx.core:core-remoteviews:1.0.0-rc01")
     docs("androidx.core:core-role:1.2.0-alpha01")
-    docs("androidx.core:core-splashscreen:1.1.0-alpha01")
+    docs("androidx.core:core-splashscreen:1.1.0-alpha02")
     docs("androidx.core:core-telecom:1.0.0-alpha01")
     docs("androidx.core:core-testing:1.12.0-rc01")
     docs("androidx.core.uwb:uwb:1.0.0-alpha07")
@@ -142,15 +142,15 @@
     docs("androidx.customview:customview:1.2.0-alpha02")
     // TODO(b/294531403): Turn on apiSince for customview-poolingcontainer when it releases as alpha
     docsWithoutApiSince("androidx.customview:customview-poolingcontainer:1.0.0-rc01")
-    kmpDocs("androidx.datastore:datastore:1.1.0-alpha04")
-    kmpDocs("androidx.datastore:datastore-core:1.1.0-alpha04")
-    kmpDocs("androidx.datastore:datastore-core-okio:1.1.0-alpha04")
-    kmpDocs("androidx.datastore:datastore-preferences:1.1.0-alpha04")
-    kmpDocs("androidx.datastore:datastore-preferences-core:1.1.0-alpha04")
-    docs("androidx.datastore:datastore-preferences-rxjava2:1.1.0-alpha04")
-    docs("androidx.datastore:datastore-preferences-rxjava3:1.1.0-alpha04")
-    docs("androidx.datastore:datastore-rxjava2:1.1.0-alpha04")
-    docs("androidx.datastore:datastore-rxjava3:1.1.0-alpha04")
+    kmpDocs("androidx.datastore:datastore:1.1.0-alpha05")
+    kmpDocs("androidx.datastore:datastore-core:1.1.0-alpha05")
+    kmpDocs("androidx.datastore:datastore-core-okio:1.1.0-alpha05")
+    kmpDocs("androidx.datastore:datastore-preferences:1.1.0-alpha05")
+    kmpDocs("androidx.datastore:datastore-preferences-core:1.1.0-alpha05")
+    docs("androidx.datastore:datastore-preferences-rxjava2:1.1.0-alpha05")
+    docs("androidx.datastore:datastore-preferences-rxjava3:1.1.0-alpha05")
+    docs("androidx.datastore:datastore-rxjava2:1.1.0-alpha05")
+    docs("androidx.datastore:datastore-rxjava3:1.1.0-alpha05")
     docs("androidx.documentfile:documentfile:1.1.0-alpha01")
     docs("androidx.draganddrop:draganddrop:1.0.0")
     docs("androidx.drawerlayout:drawerlayout:1.2.0")
@@ -167,23 +167,24 @@
     docs("androidx.enterprise:enterprise-feedback:1.1.0")
     docs("androidx.enterprise:enterprise-feedback-testing:1.1.0")
     docs("androidx.exifinterface:exifinterface:1.3.6")
-    docs("androidx.fragment:fragment:1.7.0-alpha03")
-    docs("androidx.fragment:fragment-ktx:1.7.0-alpha03")
-    docs("androidx.fragment:fragment-testing:1.7.0-alpha03")
-    docs("androidx.glance:glance:1.0.0-rc01")
-    docs("androidx.glance:glance-appwidget:1.0.0-rc01")
-    samples("androidx.glance:glance-appwidget-samples:1.0.0-rc01")
+    docs("androidx.fragment:fragment:1.7.0-alpha04")
+    docs("androidx.fragment:fragment-ktx:1.7.0-alpha04")
+    docs("androidx.fragment:fragment-testing:1.7.0-alpha04")
+    docs("androidx.glance:glance:1.0.0")
+    docs("androidx.glance:glance-appwidget:1.0.0")
+    samples("androidx.glance:glance-appwidget-samples:1.0.0")
     docs("androidx.glance:glance-appwidget-preview:1.0.0-alpha06")
-    docs("androidx.glance:glance-material:1.0.0-rc01")
-    docs("androidx.glance:glance-material3:1.0.0-rc01")
+    docs("androidx.glance:glance-material:1.0.0")
+    docs("androidx.glance:glance-material3:1.0.0")
     docs("androidx.glance:glance-preview:1.0.0-alpha06")
     docs("androidx.glance:glance-template:1.0.0-alpha06")
     docs("androidx.glance:glance-wear-tiles:1.0.0-alpha06")
     docs("androidx.glance:glance-wear-tiles-preview:1.0.0-alpha06")
-    docs("androidx.graphics:graphics-core:1.0.0-alpha04")
+    docs("androidx.graphics:graphics-core:1.0.0-alpha05")
+    samples("androidx.graphics:graphics-core-samples:1.0.0-alpha05")
     docs("androidx.gridlayout:gridlayout:1.1.0-beta01")
-    docs("androidx.health.connect:connect-client:1.1.0-alpha03")
-    samples("androidx.health.connect:connect-client-samples:1.1.0-alpha03")
+    docs("androidx.health.connect:connect-client:1.1.0-alpha04")
+    samples("androidx.health.connect:connect-client-samples:1.1.0-alpha04")
     docs("androidx.health:health-services-client:1.1.0-alpha01")
     docs("androidx.heifwriter:heifwriter:1.1.0-alpha02")
     docs("androidx.hilt:hilt-common:1.1.0-alpha01")
@@ -195,32 +196,32 @@
     docs("androidx.input:input-motionprediction:1.0.0-beta02")
     docs("androidx.interpolator:interpolator:1.0.0")
     docs("androidx.javascriptengine:javascriptengine:1.0.0-alpha05")
-    docs("androidx.leanback:leanback:1.2.0-alpha02")
-    docs("androidx.leanback:leanback-grid:1.0.0-alpha01")
-    docs("androidx.leanback:leanback-paging:1.1.0-alpha09")
-    docs("androidx.leanback:leanback-preference:1.2.0-alpha02")
+    docs("androidx.leanback:leanback:1.2.0-alpha03")
+    docs("androidx.leanback:leanback-grid:1.0.0-alpha02")
+    docs("androidx.leanback:leanback-paging:1.1.0-alpha10")
+    docs("androidx.leanback:leanback-preference:1.2.0-alpha03")
     docs("androidx.leanback:leanback-tab:1.1.0-beta01")
-    docs("androidx.lifecycle:lifecycle-common:2.7.0-alpha01")
-    docs("androidx.lifecycle:lifecycle-common-java8:2.7.0-alpha01")
+    docs("androidx.lifecycle:lifecycle-common:2.7.0-alpha02")
+    docs("androidx.lifecycle:lifecycle-common-java8:2.7.0-alpha02")
     docs("androidx.lifecycle:lifecycle-extensions:2.2.0")
-    docs("androidx.lifecycle:lifecycle-livedata:2.7.0-alpha01")
-    docs("androidx.lifecycle:lifecycle-livedata-core:2.7.0-alpha01")
-    docs("androidx.lifecycle:lifecycle-livedata-core-ktx:2.7.0-alpha01")
-    docs("androidx.lifecycle:lifecycle-livedata-ktx:2.7.0-alpha01")
-    docs("androidx.lifecycle:lifecycle-process:2.7.0-alpha01")
-    docs("androidx.lifecycle:lifecycle-reactivestreams:2.7.0-alpha01")
-    docs("androidx.lifecycle:lifecycle-reactivestreams-ktx:2.7.0-alpha01")
-    docs("androidx.lifecycle:lifecycle-runtime:2.7.0-alpha01")
-    docs("androidx.lifecycle:lifecycle-runtime-compose:2.7.0-alpha01")
-    samples("androidx.lifecycle:lifecycle-runtime-compose-samples:2.7.0-alpha01")
-    docs("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0-alpha01")
-    docs("androidx.lifecycle:lifecycle-runtime-testing:2.7.0-alpha01")
-    docs("androidx.lifecycle:lifecycle-service:2.7.0-alpha01")
-    docs("androidx.lifecycle:lifecycle-viewmodel:2.7.0-alpha01")
-    docs("androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0-alpha01")
-    samples("androidx.lifecycle:lifecycle-viewmodel-compose-samples:2.7.0-alpha01")
-    docs("androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0-alpha01")
-    docs("androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0-alpha01")
+    docs("androidx.lifecycle:lifecycle-livedata:2.7.0-alpha02")
+    docs("androidx.lifecycle:lifecycle-livedata-core:2.7.0-alpha02")
+    docs("androidx.lifecycle:lifecycle-livedata-core-ktx:2.7.0-alpha02")
+    docs("androidx.lifecycle:lifecycle-livedata-ktx:2.7.0-alpha02")
+    docs("androidx.lifecycle:lifecycle-process:2.7.0-alpha02")
+    docs("androidx.lifecycle:lifecycle-reactivestreams:2.7.0-alpha02")
+    docs("androidx.lifecycle:lifecycle-reactivestreams-ktx:2.7.0-alpha02")
+    docs("androidx.lifecycle:lifecycle-runtime:2.7.0-alpha02")
+    docs("androidx.lifecycle:lifecycle-runtime-compose:2.7.0-alpha02")
+    samples("androidx.lifecycle:lifecycle-runtime-compose-samples:2.7.0-alpha02")
+    docs("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0-alpha02")
+    docs("androidx.lifecycle:lifecycle-runtime-testing:2.7.0-alpha02")
+    docs("androidx.lifecycle:lifecycle-service:2.7.0-alpha02")
+    docs("androidx.lifecycle:lifecycle-viewmodel:2.7.0-alpha02")
+    docs("androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0-alpha02")
+    samples("androidx.lifecycle:lifecycle-viewmodel-compose-samples:2.7.0-alpha02")
+    docs("androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0-alpha02")
+    docs("androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0-alpha02")
     docs("androidx.loader:loader:1.1.0")
     // localbroadcastmanager is deprecated
     docsWithoutApiSince("androidx.localbroadcastmanager:localbroadcastmanager:1.1.0")
@@ -258,31 +259,31 @@
     docs("androidx.mediarouter:mediarouter:1.6.0-rc01")
     docs("androidx.mediarouter:mediarouter-testing:1.6.0-rc01")
     docs("androidx.metrics:metrics-performance:1.0.0-alpha04")
-    docs("androidx.navigation:navigation-common:2.7.1")
-    docs("androidx.navigation:navigation-common-ktx:2.7.1")
-    docs("androidx.navigation:navigation-compose:2.7.1")
-    samples("androidx.navigation:navigation-compose-samples:2.7.1")
-    docs("androidx.navigation:navigation-dynamic-features-fragment:2.7.1")
-    docs("androidx.navigation:navigation-dynamic-features-runtime:2.7.1")
-    docs("androidx.navigation:navigation-fragment:2.7.1")
-    docs("androidx.navigation:navigation-fragment-ktx:2.7.1")
-    docs("androidx.navigation:navigation-runtime:2.7.1")
-    docs("androidx.navigation:navigation-runtime-ktx:2.7.1")
-    docs("androidx.navigation:navigation-testing:2.7.1")
-    docs("androidx.navigation:navigation-ui:2.7.1")
-    docs("androidx.navigation:navigation-ui-ktx:2.7.1")
-    docs("androidx.paging:paging-common:3.2.0")
-    docs("androidx.paging:paging-common-ktx:3.2.0")
-    docs("androidx.paging:paging-compose:3.2.0")
-    samples("androidx.paging:paging-compose-samples:3.2.0")
-    docs("androidx.paging:paging-guava:3.2.0")
-    docs("androidx.paging:paging-runtime:3.2.0")
-    docs("androidx.paging:paging-runtime-ktx:3.2.0")
-    docs("androidx.paging:paging-rxjava2:3.2.0")
-    docs("androidx.paging:paging-rxjava2-ktx:3.2.0")
-    docs("androidx.paging:paging-rxjava3:3.2.0")
-    samples("androidx.paging:paging-samples:3.2.0")
-    docs("androidx.paging:paging-testing:3.2.0")
+    docs("androidx.navigation:navigation-common:2.7.2")
+    docs("androidx.navigation:navigation-common-ktx:2.7.2")
+    docs("androidx.navigation:navigation-compose:2.7.2")
+    samples("androidx.navigation:navigation-compose-samples:2.7.2")
+    docs("androidx.navigation:navigation-dynamic-features-fragment:2.7.2")
+    docs("androidx.navigation:navigation-dynamic-features-runtime:2.7.2")
+    docs("androidx.navigation:navigation-fragment:2.7.2")
+    docs("androidx.navigation:navigation-fragment-ktx:2.7.2")
+    docs("androidx.navigation:navigation-runtime:2.7.2")
+    docs("androidx.navigation:navigation-runtime-ktx:2.7.2")
+    docs("androidx.navigation:navigation-testing:2.7.2")
+    docs("androidx.navigation:navigation-ui:2.7.2")
+    docs("androidx.navigation:navigation-ui-ktx:2.7.2")
+    docsWithoutApiSince("androidx.paging:paging-common:3.2.1")
+    docsWithoutApiSince("androidx.paging:paging-common-ktx:3.2.1")
+    docsWithoutApiSince("androidx.paging:paging-compose:3.2.1")
+    samples("androidx.paging:paging-compose-samples:3.2.1")
+    docsWithoutApiSince("androidx.paging:paging-guava:3.2.1")
+    docsWithoutApiSince("androidx.paging:paging-runtime:3.2.1")
+    docsWithoutApiSince("androidx.paging:paging-runtime-ktx:3.2.1")
+    docsWithoutApiSince("androidx.paging:paging-rxjava2:3.2.1")
+    docsWithoutApiSince("androidx.paging:paging-rxjava2-ktx:3.2.1")
+    docsWithoutApiSince("androidx.paging:paging-rxjava3:3.2.1")
+    samples("androidx.paging:paging-samples:3.2.1")
+    docsWithoutApiSince("androidx.paging:paging-testing:3.2.1")
     docs("androidx.palette:palette:1.0.0")
     docs("androidx.palette:palette-ktx:1.0.0")
     docs("androidx.percentlayout:percentlayout:1.0.1")
@@ -293,7 +294,7 @@
     docs("androidx.privacysandbox.ads:ads-adservices-java:1.1.0-beta01")
     docs("androidx.privacysandbox.sdkruntime:sdkruntime-client:1.0.0-alpha08")
     docs("androidx.privacysandbox.sdkruntime:sdkruntime-core:1.0.0-alpha08")
-    docs("androidx.privacysandbox.tools:tools:1.0.0-alpha05")
+    docs("androidx.privacysandbox.tools:tools:1.0.0-alpha06")
     docs("androidx.privacysandbox.ui:ui-client:1.0.0-alpha05")
     docs("androidx.privacysandbox.ui:ui-core:1.0.0-alpha05")
     docs("androidx.privacysandbox.ui:ui-provider:1.0.0-alpha05")
@@ -362,11 +363,11 @@
     // TODO(243405142) clean-up
     docsWithoutApiSince("androidx.tracing:tracing-perfetto-common:1.0.0-alpha16")
     docs("androidx.tracing:tracing-perfetto-handshake:1.0.0-beta03")
-    docs("androidx.transition:transition:1.5.0-alpha01")
-    docs("androidx.transition:transition-ktx:1.5.0-alpha01")
-    docs("androidx.tv:tv-foundation:1.0.0-alpha08")
-    docs("androidx.tv:tv-material:1.0.0-alpha08")
-    samples("androidx.tv:tv-samples:1.0.0-alpha08")
+    docs("androidx.transition:transition:1.5.0-alpha02")
+    docs("androidx.transition:transition-ktx:1.5.0-alpha02")
+    docs("androidx.tv:tv-foundation:1.0.0-alpha09")
+    docs("androidx.tv:tv-material:1.0.0-alpha09")
+    samples("androidx.tv:tv-samples:1.0.0-alpha09")
     docs("androidx.tvprovider:tvprovider:1.1.0-alpha01")
     docs("androidx.vectordrawable:vectordrawable:1.2.0-beta01")
     docs("androidx.vectordrawable:vectordrawable-animated:1.2.0-alpha01")
@@ -374,16 +375,16 @@
     docs("androidx.versionedparcelable:versionedparcelable:1.1.1")
     docs("androidx.viewpager2:viewpager2:1.1.0-beta02")
     docs("androidx.viewpager:viewpager:1.1.0-alpha01")
-    docs("androidx.wear.compose:compose-foundation:1.3.0-alpha04")
-    samples("androidx.wear.compose:compose-foundation-samples:1.3.0-alpha04")
-    docs("androidx.wear.compose:compose-material:1.3.0-alpha04")
-    docs("androidx.wear.compose:compose-material-core:1.3.0-alpha04")
-    samples("androidx.wear.compose:compose-material-samples:1.3.0-alpha04")
-    docs("androidx.wear.compose:compose-material3:1.0.0-alpha10")
-    samples("androidx.wear.compose:compose-material3-samples:1.3.0-alpha04")
-    docs("androidx.wear.compose:compose-navigation:1.3.0-alpha04")
-    samples("androidx.wear.compose:compose-navigation-samples:1.3.0-alpha04")
-    docs("androidx.wear.compose:compose-ui-tooling:1.3.0-alpha04")
+    docs("androidx.wear.compose:compose-foundation:1.3.0-alpha05")
+    samples("androidx.wear.compose:compose-foundation-samples:1.3.0-alpha05")
+    docs("androidx.wear.compose:compose-material:1.3.0-alpha05")
+    docs("androidx.wear.compose:compose-material-core:1.3.0-alpha05")
+    samples("androidx.wear.compose:compose-material-samples:1.3.0-alpha05")
+    docs("androidx.wear.compose:compose-material3:1.0.0-alpha11")
+    samples("androidx.wear.compose:compose-material3-samples:1.3.0-alpha05")
+    docs("androidx.wear.compose:compose-navigation:1.3.0-alpha05")
+    samples("androidx.wear.compose:compose-navigation-samples:1.3.0-alpha05")
+    docs("androidx.wear.compose:compose-ui-tooling:1.3.0-alpha05")
     docs("androidx.wear.protolayout:protolayout:1.0.0")
     docs("androidx.wear.protolayout:protolayout-expression:1.0.0")
     docs("androidx.wear.protolayout:protolayout-expression-pipeline:1.0.0")
@@ -394,22 +395,22 @@
     docs("androidx.wear.tiles:tiles-renderer:1.2.0")
     docs("androidx.wear.tiles:tiles-testing:1.2.0")
     docs("androidx.wear.tiles:tiles-tooling:1.2.0-alpha07")
-    docs("androidx.wear.watchface:watchface:1.2.0-beta01")
-    docs("androidx.wear.watchface:watchface-client:1.2.0-beta01")
-    docs("androidx.wear.watchface:watchface-client-guava:1.2.0-beta01")
-    docs("androidx.wear.watchface:watchface-complications:1.2.0-beta01")
-    docs("androidx.wear.watchface:watchface-complications-data:1.2.0-beta01")
-    docs("androidx.wear.watchface:watchface-complications-data-source:1.2.0-beta01")
-    docs("androidx.wear.watchface:watchface-complications-data-source-ktx:1.2.0-beta01")
-    samples("androidx.wear.watchface:watchface-complications-permission-dialogs-sample:1.2.0-beta01")
-    docs("androidx.wear.watchface:watchface-complications-rendering:1.2.0-beta01")
-    docs("androidx.wear.watchface:watchface-data:1.2.0-beta01")
-    docs("androidx.wear.watchface:watchface-editor:1.2.0-beta01")
-    docs("androidx.wear.watchface:watchface-editor-guava:1.2.0-beta01")
-    samples("androidx.wear.watchface:watchface-editor-samples:1.2.0-beta01")
-    docs("androidx.wear.watchface:watchface-guava:1.2.0-beta01")
-    samples("androidx.wear.watchface:watchface-samples:1.2.0-beta01")
-    docs("androidx.wear.watchface:watchface-style:1.2.0-beta01")
+    docs("androidx.wear.watchface:watchface:1.2.0-beta02")
+    docs("androidx.wear.watchface:watchface-client:1.2.0-beta02")
+    docs("androidx.wear.watchface:watchface-client-guava:1.2.0-beta02")
+    docs("androidx.wear.watchface:watchface-complications:1.2.0-beta02")
+    docs("androidx.wear.watchface:watchface-complications-data:1.2.0-beta02")
+    docs("androidx.wear.watchface:watchface-complications-data-source:1.2.0-beta02")
+    docs("androidx.wear.watchface:watchface-complications-data-source-ktx:1.2.0-beta02")
+    samples("androidx.wear.watchface:watchface-complications-permission-dialogs-sample:1.2.0-beta02")
+    docs("androidx.wear.watchface:watchface-complications-rendering:1.2.0-beta02")
+    docs("androidx.wear.watchface:watchface-data:1.2.0-beta02")
+    docs("androidx.wear.watchface:watchface-editor:1.2.0-beta02")
+    docs("androidx.wear.watchface:watchface-editor-guava:1.2.0-beta02")
+    samples("androidx.wear.watchface:watchface-editor-samples:1.2.0-beta02")
+    docs("androidx.wear.watchface:watchface-guava:1.2.0-beta02")
+    samples("androidx.wear.watchface:watchface-samples:1.2.0-beta02")
+    docs("androidx.wear.watchface:watchface-style:1.2.0-beta02")
     // TODO(b/294531403): Turn on apiSince for wear when it releases as alpha
     docsWithoutApiSince("androidx.wear:wear:1.3.0-rc01")
     stubs(fileTree(dir: "../wear/wear_stubs/", include: ["com.google.android.wearable-stubs.jar"]))
@@ -420,7 +421,7 @@
     docs("androidx.wear:wear-phone-interactions:1.1.0-alpha03")
     docs("androidx.wear:wear-remote-interactions:1.1.0-alpha01")
     docs("androidx.wear:wear-tooling-preview:1.0.0-alpha01")
-    docs("androidx.webkit:webkit:1.8.0-rc01")
+    docs("androidx.webkit:webkit:1.8.0")
     docs("androidx.window.extensions.core:core:1.0.0")
     docs("androidx.window:window:1.2.0-beta01")
     stubs(fileTree(dir: "../window/stubs/", include: ["window-sidecar-release-0.1.0-alpha01.aar"]))
@@ -431,12 +432,12 @@
     docs("androidx.window:window-rxjava3:1.2.0-beta01")
     samples("androidx.window:window-samples:1.2.0-beta01")
     docs("androidx.window:window-testing:1.2.0-beta01")
-    docs("androidx.work:work-gcm:2.9.0-alpha02")
-    docs("androidx.work:work-multiprocess:2.9.0-alpha02")
-    docs("androidx.work:work-runtime:2.9.0-alpha02")
-    docs("androidx.work:work-runtime-ktx:2.9.0-alpha02")
-    docs("androidx.work:work-rxjava2:2.9.0-alpha02")
-    docs("androidx.work:work-rxjava3:2.9.0-alpha02")
-    docs("androidx.work:work-testing:2.9.0-alpha02")
+    docs("androidx.work:work-gcm:2.9.0-beta01")
+    docs("androidx.work:work-multiprocess:2.9.0-beta01")
+    docs("androidx.work:work-runtime:2.9.0-beta01")
+    docs("androidx.work:work-runtime-ktx:2.9.0-beta01")
+    docs("androidx.work:work-rxjava2:2.9.0-beta01")
+    docs("androidx.work:work-rxjava3:2.9.0-beta01")
+    docs("androidx.work:work-testing:2.9.0-beta01")
 }
 
diff --git a/docs-tip-of-tree/build.gradle b/docs-tip-of-tree/build.gradle
index d65c0f9..2af5022 100644
--- a/docs-tip-of-tree/build.gradle
+++ b/docs-tip-of-tree/build.gradle
@@ -63,6 +63,7 @@
     docs(project(":camera:camera-lifecycle"))
     docs(project(":camera:camera-mlkit-vision"))
     // camera-previewview is not hosted in androidx
+    docsWithoutApiSince(project(":camera:camera-testing"))
     docs(project(":camera:camera-video"))
     docs(project(":camera:camera-view"))
     docs(project(":camera:camera-viewfinder"))
diff --git a/docs/api_guidelines/dependencies.md b/docs/api_guidelines/dependencies.md
index 011fab9..5a43db3 100644
--- a/docs/api_guidelines/dependencies.md
+++ b/docs/api_guidelines/dependencies.md
@@ -107,9 +107,16 @@
 image and are made available to developers through the `<uses-library>` manifest
 tag.
 
-Examples include Wear OS extensions (`com.google.android.wearable`), Camera OEM
-extensions (`androidx.camera.extensions.impl`), and Window OEM extensions
-(`androix.window.extensions`).
+Examples include Camera OEM extensions (`androidx.camera.extensions.impl`) and
+Window OEM extensions (`androidx.window.extensions`).
+
+Extension libraries may be defined in AndroidX library projects (see
+`androidx.window.extensions`) or externally, ex. in AOSP alongside the platform.
+In either case, we recommend that libraries use extensions as pinned, rather
+than project-type, dependencies to facilitate versioning across repositories.
+
+*Do not* ship extension interfaces to Google Maven. Teams may choose to ship
+stub JARs publicly, but that is not covered by AndroidX workflows.
 
 Project dependencies on extension libraries **must** use `compileOnly`:
 
diff --git a/docs/api_guidelines/deprecation.md b/docs/api_guidelines/deprecation.md
index f5dc6d8..2d7069e 100644
--- a/docs/api_guidelines/deprecation.md
+++ b/docs/api_guidelines/deprecation.md
@@ -91,8 +91,9 @@
     artifact as `@Deprecated` and update the API files
     ([example CL](https://android-review.googlesource.com/c/platform/frameworks/support/+/1938773))
 1.  Schedule a release of the artifact as a new minor version. When you populate
-    the release notes, explain that the entire artifact has been deprecated.
-    Include the reason for deprecation and the migration strategy.
+    the release notes, explain that the entire artifact has been deprecated and
+    will no longer receive new features or bug fixes. Include the reason for
+    deprecation and the migration strategy.
 1.  After the artifact has been released, remove the artifact from the source
     tree, versions file, and tip-of-tree docs configuration
     ([example CL](https://android-review.googlesource.com/c/platform/frameworks/support/+/2061731/))
@@ -107,3 +108,58 @@
 
 After an artifact has been released as fully-deprecated, it can be removed from
 the source tree.
+
+#### Long-term support
+
+Artifacts which have been fully deprecated and removed are not required to fix
+any bugs -- including security issues -- which are reported after the library
+has been removed from source control; however, library owners *may* utilize
+release branches to provide long-term support.
+
+When working on long-term support in a release branch, you may encounter the
+following issues:
+
+-   Release metadata produced by the build system is not compatible with the
+    release scheduling tool
+-   Build targets associated with the release branch do not match targets used
+    by the snapped build ID
+-   Delta between last snapped build ID and proposed snap build ID is too large
+    and cannot be processed by the release branch management tool
+
+### Discouraging usage in Play Store
+
+[Google Play SDK Console](https://play.google.com/sdk-console/) allows library
+owners to annotate specific library versions with notes, which are shown to app
+developers in the Play Store Console, or permanently mark them as outdated,
+which shows a warning in Play Store Console asking app developers to upgrade.
+
+In both cases, library owners have the option to prevent app developers from
+releasing apps to Play Store that have been built against specific library
+versions.
+
+Generally, Jetpack discourages the use of either notes or marking versions as
+outdated. There are few cases that warrant pushing notifications to app
+developers, and it is easy to abuse notes as advertising to drive adoption. As a
+rule, upgrades to Jetpack libraries should be driven by the needs of app
+developers.
+
+Cases where notes may be used include:
+
+1.  The library is used directly, rather than transitively, and contains `P0` or
+    `P1` (ship-blocking, from the app's perspective) issues
+    -   Transitively-included libraries should instead urge their dependent
+        libraries to bump their pinned dependency versions
+1.  The library contains ship-blocking security issues. In this case, we
+    recommend preventing app releases since developers may be less aware of
+    security issues.
+1.  The library was built against a pre-release SDK which has been superseded by
+    a finalized SDK. In this case, we recommend preventing app releases since
+    the library may crash or show unexpected behavior.
+
+Cases where marking a version as outdated maybe used:
+
+1.  The library has security implications and the version is no longer receiving
+    security updates, e.g. the release branch has moved to the next version.
+
+In all cases, there must be a newer stable or bugfix release of the library that
+app developers can use to replace the outdated version.
diff --git a/glance/glance-appwidget-testing/api/current.txt b/glance/glance-appwidget-testing/api/current.txt
index 5886053..7dfb9e9 100644
--- a/glance/glance-appwidget-testing/api/current.txt
+++ b/glance/glance-appwidget-testing/api/current.txt
@@ -42,6 +42,9 @@
     method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> hasStartServiceAction(android.content.Intent intent, optional boolean isForegroundService);
     method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> hasStartServiceAction(Class<? extends android.app.Service> serviceClass, optional boolean isForegroundService);
     method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> isChecked();
+    method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> isIndeterminateCircularProgressIndicator();
+    method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> isIndeterminateLinearProgressIndicator();
+    method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> isLinearProgressIndicator(float progress);
     method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> isNotChecked();
   }
 
diff --git a/glance/glance-appwidget-testing/api/restricted_current.txt b/glance/glance-appwidget-testing/api/restricted_current.txt
index 5886053..7dfb9e9 100644
--- a/glance/glance-appwidget-testing/api/restricted_current.txt
+++ b/glance/glance-appwidget-testing/api/restricted_current.txt
@@ -42,6 +42,9 @@
     method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> hasStartServiceAction(android.content.Intent intent, optional boolean isForegroundService);
     method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> hasStartServiceAction(Class<? extends android.app.Service> serviceClass, optional boolean isForegroundService);
     method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> isChecked();
+    method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> isIndeterminateCircularProgressIndicator();
+    method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> isIndeterminateLinearProgressIndicator();
+    method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> isLinearProgressIndicator(float progress);
     method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> isNotChecked();
   }
 
diff --git a/glance/glance-appwidget-testing/src/main/java/androidx/glance/appwidget/testing/unit/GlanceAppWidgetUnitTestEnvironment.kt b/glance/glance-appwidget-testing/src/main/java/androidx/glance/appwidget/testing/unit/GlanceAppWidgetUnitTestEnvironment.kt
index 674c8c5..6826664 100644
--- a/glance/glance-appwidget-testing/src/main/java/androidx/glance/appwidget/testing/unit/GlanceAppWidgetUnitTestEnvironment.kt
+++ b/glance/glance-appwidget-testing/src/main/java/androidx/glance/appwidget/testing/unit/GlanceAppWidgetUnitTestEnvironment.kt
@@ -34,8 +34,10 @@
 import androidx.glance.appwidget.RemoteViewsRoot
 import androidx.glance.session.globalSnapshotMonitor
 import androidx.glance.testing.GlanceNodeAssertion
+import androidx.glance.testing.GlanceNodeAssertionCollection
 import androidx.glance.testing.GlanceNodeMatcher
 import androidx.glance.testing.TestContext
+import androidx.glance.testing.matcherToSelector
 import androidx.glance.testing.unit.GlanceMappedNode
 import androidx.glance.testing.unit.MappedNode
 import kotlin.time.Duration
@@ -154,10 +156,17 @@
     ): GlanceNodeAssertion<MappedNode, GlanceMappedNode> {
         // Always let all the enqueued tasks finish before inspecting the tree.
         testScope.testScheduler.runCurrent()
-        // Calling onNode resets the previously matched nodes and starts a new matching chain.
-        testContext.reset()
         // Delegates matching to the next assertion.
-        return GlanceNodeAssertion(matcher, testContext)
+        return GlanceNodeAssertion(testContext, matcher.matcherToSelector())
+    }
+
+    override fun onAllNodes(
+        matcher: GlanceNodeMatcher<MappedNode>
+    ): GlanceNodeAssertionCollection<MappedNode, GlanceMappedNode> {
+        // Always let all the enqueued tasks finish before inspecting the tree.
+        testScope.testScheduler.runCurrent()
+        // Delegates matching to the next assertion.
+        return GlanceNodeAssertionCollection(testContext, matcher.matcherToSelector())
     }
 
     override fun setAppWidgetSize(size: DpSize) {
diff --git a/glance/glance-appwidget-testing/src/main/java/androidx/glance/appwidget/testing/unit/UnitTestAssertionExtensions.kt b/glance/glance-appwidget-testing/src/main/java/androidx/glance/appwidget/testing/unit/UnitTestAssertionExtensions.kt
index 7bf1b3b..1cddd3a 100644
--- a/glance/glance-appwidget-testing/src/main/java/androidx/glance/appwidget/testing/unit/UnitTestAssertionExtensions.kt
+++ b/glance/glance-appwidget-testing/src/main/java/androidx/glance/appwidget/testing/unit/UnitTestAssertionExtensions.kt
@@ -28,7 +28,8 @@
 import androidx.glance.testing.unit.MappedNode
 
 // This file contains (appWidget-specific) convenience assertion shorthands for unit tests that
-// delegate calls to "assert(matcher)". For assertions common to surfaces, see AssertionExtension
+// delegate calls to "assert(matcher)". For assertions common to surfaces, see equivalent file in
+// base layer testing library.
 
 internal typealias UnitTestAssertion = GlanceNodeAssertion<MappedNode, GlanceMappedNode>
 
@@ -115,7 +116,7 @@
  * Asserts that a given node has a clickable set with action that sends a broadcast.
  *
  * @param receiverClass class of the broadcast receiver that is expected to have been passed in the
- *                      actionSendBroadcast` method call.
+ *                      `actionSendBroadcast` method call.
  * @throws AssertionError if the matcher does not match or the node can no longer be found.
  */
 fun UnitTestAssertion.assertHasSendBroadcastClickAction(
@@ -128,7 +129,7 @@
  * @param intentAction the intent action of the broadcast receiver that is expected to  have been
  *                     passed in the `actionSendBroadcast` method call.
  * @param componentName optional [ComponentName] of the target broadcast receiver that is expected
- *                      to have been passed in the actionSendBroadcast` method call.
+ *                      to have been passed in the `actionSendBroadcast` method call.
  * @throws AssertionError if the matcher does not match or the node can no longer be found.
  */
 fun UnitTestAssertion.assertHasSendBroadcastClickAction(
@@ -140,7 +141,7 @@
  * Asserts that a given node has a clickable set with action that sends a broadcast.
  *
  * @param componentName [ComponentName] of the target broadcast receiver that is expected to have
- *                      been passed in the actionSendBroadcast` method call.
+ *                      been passed in the `actionSendBroadcast` method call.
  * @throws AssertionError if the matcher does not match or the node can no longer be found.
  */
 fun UnitTestAssertion.assertHasSendBroadcastClickAction(
diff --git a/glance/glance-appwidget-testing/src/main/java/androidx/glance/appwidget/testing/unit/UnitTestFilters.kt b/glance/glance-appwidget-testing/src/main/java/androidx/glance/appwidget/testing/unit/UnitTestFilters.kt
index 0f3f231..95f5846 100644
--- a/glance/glance-appwidget-testing/src/main/java/androidx/glance/appwidget/testing/unit/UnitTestFilters.kt
+++ b/glance/glance-appwidget-testing/src/main/java/androidx/glance/appwidget/testing/unit/UnitTestFilters.kt
@@ -25,6 +25,8 @@
 import androidx.glance.action.ActionModifier
 import androidx.glance.action.ActionParameters
 import androidx.glance.action.actionParametersOf
+import androidx.glance.appwidget.EmittableCircularProgressIndicator
+import androidx.glance.appwidget.EmittableLinearProgressIndicator
 import androidx.glance.appwidget.action.SendBroadcastActionAction
 import androidx.glance.appwidget.action.SendBroadcastClassAction
 import androidx.glance.appwidget.action.SendBroadcastComponentAction
@@ -33,6 +35,7 @@
 import androidx.glance.appwidget.action.StartServiceClassAction
 import androidx.glance.appwidget.action.StartServiceComponentAction
 import androidx.glance.appwidget.action.StartServiceIntentAction
+import androidx.glance.testing.GlanceNodeAssertionsProvider
 import androidx.glance.testing.GlanceNodeMatcher
 import androidx.glance.testing.unit.MappedNode
 
@@ -40,7 +43,8 @@
  * Returns a matcher that matches if a node is checkable (e.g. radio button, switch, checkbox)
  * and is checked.
  *
- * This can be passed in "onNode" and "onNodeAll" functions on assertion providers to filter out
+ * This can be passed in [GlanceNodeAssertionsProvider.onNode] and
+ * [GlanceNodeAssertionsProvider.onAllNodes] functions on assertion providers to filter out
  * matching node(s) or in assertions to validate that node(s) satisfy the condition.
  */
 fun isChecked(): GlanceNodeMatcher<MappedNode> = GlanceNodeMatcher(
@@ -54,7 +58,8 @@
  * Returns a matcher that matches if a node is checkable (e.g. radio button, switch, checkbox)
  * but is not checked.
  *
- * This can be passed in "onNode" and "onNodeAll" functions on assertion providers to filter out
+ * This can be passed in [GlanceNodeAssertionsProvider.onNode] and
+ * [GlanceNodeAssertionsProvider.onAllNodes] functions on assertion providers to filter out
  * matching node(s) or in assertions to validate that node(s) satisfy the condition.
  */
 fun isNotChecked(): GlanceNodeMatcher<MappedNode> = GlanceNodeMatcher(
@@ -67,7 +72,8 @@
 /**
  * Returns a matcher that matches if a node has a clickable set with action that starts an activity.
  *
- * This can be passed in "onNode" and "onNodeAll" functions on assertion providers to filter out
+ * This can be passed in [GlanceNodeAssertionsProvider.onNode] and
+ * [GlanceNodeAssertionsProvider.onAllNodes] functions on assertion providers to filter out
  * matching node(s) or in assertions to validate that node(s) satisfy the condition.
  *
  * @param intent the intent for launching an activity that is expected to have been passed in the
@@ -110,7 +116,8 @@
 /**
  * Returns a matcher that matches if a node has a clickable set with action that starts a service.
  *
- * This can be passed in "onNode" and "onNodeAll" functions on assertion providers to filter out
+ * This can be passed in [GlanceNodeAssertionsProvider.onNode] and
+ * [GlanceNodeAssertionsProvider.onAllNodes] functions on assertion providers to filter out
  * matching node(s) or in assertions to validate that node(s) satisfy the condition.
  *
  * @param serviceClass class of the service to launch that is expected to have been passed in the
@@ -143,7 +150,8 @@
 /**
  * Returns a matcher that matches if a node has a clickable set with action that starts a service.
  *
- * This can be passed in "onNode" and "onNodeAll" functions on assertion providers to filter out
+ * This can be passed in [GlanceNodeAssertionsProvider.onNode] and
+ * [GlanceNodeAssertionsProvider.onAllNodes] functions on assertion providers to filter out
  * matching node(s) or in assertions to validate that node(s) satisfy the condition.
  *
  * @param componentName component of the service to launch that is expected to have been passed in
@@ -176,7 +184,8 @@
 /**
  * Returns a matcher that matches if a node has a clickable set with action that starts a service.
  *
- * This can be passed in "onNode" and "onNodeAll" functions on assertion providers to filter out
+ * This can be passed in [GlanceNodeAssertionsProvider.onNode] and
+ * [GlanceNodeAssertionsProvider.onAllNodes] functions on assertion providers to filter out
  * matching node(s) or in assertions to validate that node(s) satisfy the condition.
  *
  * @param intent the intent for launching the service that is expected to have been passed in
@@ -209,7 +218,8 @@
 /**
  * Returns a matcher that matches if a node has a clickable set with action that sends a broadcast.
  *
- * This can be passed in "onNode" and "onNodeAll" functions on assertion providers to filter out
+ * This can be passed in [GlanceNodeAssertionsProvider.onNode] and
+ * [GlanceNodeAssertionsProvider.onAllNodes] functions on assertion providers to filter out
  * matching node(s) or in assertions to validate that node(s) satisfy the condition.
  *
  * @param receiverClass class of the broadcast receiver that is expected to have been passed in the
@@ -234,7 +244,8 @@
 /**
  * Returns a matcher that matches if a node has a clickable set with action that sends a broadcast.
  *
- * This can be passed in "onNode" and "onNodeAll" functions on assertion providers to filter out
+ * This can be passed in [GlanceNodeAssertionsProvider.onNode] and
+ * [GlanceNodeAssertionsProvider.onAllNodes] functions on assertion providers to filter out
  * matching node(s) or in assertions to validate that node(s) satisfy the condition.
  *
  * @param intentAction the intent action of the broadcast receiver that is expected to  have been
@@ -271,7 +282,8 @@
 /**
  * Returns a matcher that matches if a node has a clickable set with action that sends a broadcast.
  *
- * This can be passed in "onNode" and "onNodeAll" functions on assertion providers to filter out
+ * This can be passed in [GlanceNodeAssertionsProvider.onNode] and
+ * [GlanceNodeAssertionsProvider.onAllNodes] functions on assertion providers to filter out
  * matching node(s) or in assertions to validate that node(s) satisfy the condition.
  *
  * @param componentName [ComponentName] of the target broadcast receiver that is expected to have
@@ -296,7 +308,8 @@
 /**
  * Returns a matcher that matches if a node has a clickable set with action that sends a broadcast.
  *
- * This can be passed in "onNode" and "onNodeAll" functions on assertion providers to filter out
+ * This can be passed in [GlanceNodeAssertionsProvider.onNode] and
+ * [GlanceNodeAssertionsProvider.onAllNodes] functions on assertion providers to filter out
  * matching node(s) or in assertions to validate that node(s) satisfy the condition.
  *
  * @param intent the intent for sending broadcast  that is expected to  have been passed in the
@@ -317,3 +330,52 @@
         false
     }
 }
+
+/**
+ * Returns a matcher that matches if a given node is a linear progress indicator with given progress
+ * value.
+ *
+ * This can be passed in [GlanceNodeAssertionsProvider.onNode] and
+ * [GlanceNodeAssertionsProvider.onAllNodes] functions on assertion providers to filter out
+ * matching node(s) or in assertions to validate that node(s) satisfy the condition.
+ *
+ * @param progress the expected value of the current progress
+ */
+fun isLinearProgressIndicator(
+    /*@FloatRange(from = 0.0, to = 1.0)*/
+    progress: Float
+): GlanceNodeMatcher<MappedNode> = GlanceNodeMatcher(
+    description = "is a linear progress indicator with progress value: $progress"
+) { node ->
+    val emittable = node.value.emittable
+    emittable is EmittableLinearProgressIndicator &&
+        !emittable.indeterminate &&
+        emittable.progress == progress
+}
+
+/**
+ * Returns a matcher that matches if a given node is an indeterminate progress bar.
+ *
+ * This can be passed in [GlanceNodeAssertionsProvider.onNode] and
+ * [GlanceNodeAssertionsProvider.onAllNodes] functions on assertion providers to filter out
+ * matching node(s) or in assertions to validate that node(s) satisfy the condition.
+ */
+fun isIndeterminateLinearProgressIndicator(): GlanceNodeMatcher<MappedNode> = GlanceNodeMatcher(
+    description = "is an indeterminate linear progress indicator"
+) { node ->
+    val emittable = node.value.emittable
+    emittable is EmittableLinearProgressIndicator && emittable.indeterminate
+}
+
+/**
+ * Returns a matcher that matches if a given node is an indeterminate circular progress indicator.
+ *
+ * This can be passed in [GlanceNodeAssertionsProvider.onNode] and
+ * [GlanceNodeAssertionsProvider.onAllNodes] functions on assertion providers to filter out
+ * matching node(s) or in assertions to validate that node(s) satisfy the condition.
+ */
+fun isIndeterminateCircularProgressIndicator(): GlanceNodeMatcher<MappedNode> = GlanceNodeMatcher(
+    description = "is an indeterminate circular progress indicator"
+) { node ->
+    node.value.emittable is EmittableCircularProgressIndicator
+}
diff --git a/glance/glance-appwidget-testing/src/test/kotlin/androidx/glance/appwidget/testing/unit/GlanceAppWidgetUnitTestEnvironmentTest.kt b/glance/glance-appwidget-testing/src/test/kotlin/androidx/glance/appwidget/testing/unit/GlanceAppWidgetUnitTestEnvironmentTest.kt
index a1449d8..3c4e2d9 100644
--- a/glance/glance-appwidget-testing/src/test/kotlin/androidx/glance/appwidget/testing/unit/GlanceAppWidgetUnitTestEnvironmentTest.kt
+++ b/glance/glance-appwidget-testing/src/test/kotlin/androidx/glance/appwidget/testing/unit/GlanceAppWidgetUnitTestEnvironmentTest.kt
@@ -32,9 +32,13 @@
 import androidx.glance.ImageProvider
 import androidx.glance.LocalSize
 import androidx.glance.appwidget.ImageProvider
+import androidx.glance.appwidget.lazy.GridCells
+import androidx.glance.appwidget.lazy.LazyColumn
+import androidx.glance.appwidget.lazy.LazyVerticalGrid
 import androidx.glance.appwidget.testing.test.R
 import androidx.glance.currentState
 import androidx.glance.layout.Column
+import androidx.glance.layout.Row
 import androidx.glance.layout.Spacer
 import androidx.glance.semantics.semantics
 import androidx.glance.semantics.testTag
@@ -164,6 +168,58 @@
 
         onNode(hasTestTag("mutable-test")).assert(hasText("initial"))
     }
+
+    @Test
+    fun runTest_onMultipleNodesMatchedAcrossHierarchy() = runGlanceAppWidgetUnitTest {
+        provideComposable {
+            Column {
+                Row {
+                    Text("text-row")
+                }
+                Spacer()
+                Text("text-in-column")
+            }
+        }
+
+        onAllNodes(hasText(text = "text-")).assertCountEquals(2)
+    }
+
+    @Test
+    fun runTest_lazyColumnChildren() = runGlanceAppWidgetUnitTest {
+        provideComposable {
+            LazyColumn(modifier = GlanceModifier.semantics { testTag = "test-list" }) {
+                item { Text("text-1") }
+                item { Text("text-2") }
+            }
+        }
+
+        onNode(hasTestTag("test-list"))
+            .onChildren()
+            .assertCountEquals(2)
+            .filter(hasText("text-1"))
+            .assertCountEquals(1)
+    }
+
+    @Test
+    fun runTest_lazyGridChildren() = runGlanceAppWidgetUnitTest {
+        provideComposable {
+            LazyVerticalGrid(
+                modifier = GlanceModifier.semantics { testTag = "test-list" },
+                gridCells = GridCells.Fixed(2)
+            ) {
+                item { Text("text-1") }
+                item { Text("text-2") }
+                item { Text("text-3") }
+                item { Text("text-4") }
+            }
+        }
+
+        onNode(hasTestTag("test-list"))
+            .onChildren()
+            .assertCountEquals(4)
+            .filter(hasText("text-1"))
+            .assertCountEquals(1)
+    }
 }
 
 private val toggleKey = booleanPreferencesKey("title_toggled_key")
diff --git a/glance/glance-appwidget-testing/src/test/kotlin/androidx/glance/appwidget/testing/unit/UnitTestFiltersTest.kt b/glance/glance-appwidget-testing/src/test/kotlin/androidx/glance/appwidget/testing/unit/UnitTestFiltersTest.kt
new file mode 100644
index 0000000..b444af1
--- /dev/null
+++ b/glance/glance-appwidget-testing/src/test/kotlin/androidx/glance/appwidget/testing/unit/UnitTestFiltersTest.kt
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.glance.appwidget.testing.unit
+
+import androidx.glance.appwidget.EmittableCircularProgressIndicator
+import androidx.glance.appwidget.EmittableLinearProgressIndicator
+import androidx.glance.layout.EmittableColumn
+import androidx.glance.testing.unit.getGlanceNodeAssertionFor
+import com.google.common.truth.ExpectFailure.assertThat
+import org.junit.Assert
+import org.junit.Test
+
+class UnitTestFiltersTest {
+    @Test
+    fun isCircularProgressIndicator_match() {
+        val nodeAssertion = getGlanceNodeAssertionFor(
+            emittable = EmittableColumn().apply {
+                children += EmittableCircularProgressIndicator()
+            },
+            onNodeMatcher = isIndeterminateCircularProgressIndicator()
+        )
+
+        nodeAssertion.assertExists()
+        // no error
+    }
+
+    @Test
+    fun isCircularProgressIndicator_noMatch_assertionError() {
+        val nodeAssertion = getGlanceNodeAssertionFor(
+            emittable = EmittableColumn().apply {
+                children += EmittableLinearProgressIndicator()
+            },
+            onNodeMatcher = isIndeterminateCircularProgressIndicator()
+        )
+
+        val assertionError = Assert.assertThrows(AssertionError::class.java) {
+            nodeAssertion.assertExists()
+        }
+
+        assertThat(assertionError)
+            .hasMessageThat()
+            .contains(
+                "Failed assertExists" +
+                    "\nReason: Expected '1' node(s) matching condition: " +
+                    "is an indeterminate circular progress indicator, but found '0'"
+            )
+    }
+
+    @Test
+    fun isIndeterminateLinearProgressIndicator_match() {
+        val nodeAssertion = getGlanceNodeAssertionFor(
+            emittable = EmittableColumn().apply {
+                children += EmittableLinearProgressIndicator().apply {
+                    indeterminate = true
+                }
+            },
+            onNodeMatcher = isIndeterminateLinearProgressIndicator()
+        )
+
+        nodeAssertion.assertExists()
+        // no error
+    }
+
+    @Test
+    fun isIndeterminateLinearProgressIndicator_noMatch_assertionError() {
+        val nodeAssertion = getGlanceNodeAssertionFor(
+            emittable = EmittableColumn().apply {
+                children += EmittableCircularProgressIndicator()
+            },
+            onNodeMatcher = isIndeterminateLinearProgressIndicator()
+        )
+
+        val assertionError = Assert.assertThrows(AssertionError::class.java) {
+            nodeAssertion.assertExists()
+        }
+
+        assertThat(assertionError)
+            .hasMessageThat()
+            .contains(
+                "Failed assertExists" +
+                    "\nReason: Expected '1' node(s) matching condition: " +
+                    "is an indeterminate linear progress indicator, but found '0'"
+            )
+    }
+
+    @Test
+    fun isLinearProgressIndicator_match() {
+        val nodeAssertion = getGlanceNodeAssertionFor(
+            emittable = EmittableColumn().apply {
+                children += EmittableLinearProgressIndicator().apply {
+                    progress = 10.0f
+                }
+            },
+            onNodeMatcher = isLinearProgressIndicator(10.0f)
+        )
+
+        nodeAssertion.assertExists()
+        // no error
+    }
+
+    @Test
+    fun isLinearProgressIndicator_progressValueNotMatch_assertionError() {
+        val nodeAssertion = getGlanceNodeAssertionFor(
+            emittable = EmittableColumn().apply {
+                children += EmittableLinearProgressIndicator().apply {
+                    indeterminate = false
+                    progress = 10.0f
+                }
+            },
+            onNodeMatcher = isLinearProgressIndicator(11.0f)
+        )
+
+        val assertionError = Assert.assertThrows(AssertionError::class.java) {
+            nodeAssertion.assertExists()
+        }
+
+        assertThat(assertionError)
+            .hasMessageThat()
+            .contains(
+                "Failed assertExists" +
+                    "\nReason: Expected '1' node(s) matching condition: " +
+                    "is a linear progress indicator with progress value: 11.0, but found '0'"
+            )
+    }
+}
diff --git a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/CircularProgressIndicator.kt b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/CircularProgressIndicator.kt
index 9e13d34..bf622db 100644
--- a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/CircularProgressIndicator.kt
+++ b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/CircularProgressIndicator.kt
@@ -16,6 +16,7 @@
 
 package androidx.glance.appwidget
 
+import androidx.annotation.RestrictTo
 import androidx.compose.runtime.Composable
 import androidx.glance.Emittable
 import androidx.glance.GlanceModifier
@@ -42,7 +43,8 @@
     )
 }
 
-internal class EmittableCircularProgressIndicator : Emittable {
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+class EmittableCircularProgressIndicator : Emittable {
     override var modifier: GlanceModifier = GlanceModifier
     var color: ColorProvider = ProgressIndicatorDefaults.IndicatorColorProvider
 
diff --git a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/LinearProgressIndicator.kt b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/LinearProgressIndicator.kt
index e314c1a..a300ca5 100644
--- a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/LinearProgressIndicator.kt
+++ b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/LinearProgressIndicator.kt
@@ -16,6 +16,7 @@
 
 package androidx.glance.appwidget
 
+import androidx.annotation.RestrictTo
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.graphics.Color
 import androidx.glance.Emittable
@@ -76,7 +77,8 @@
     )
 }
 
-internal class EmittableLinearProgressIndicator : Emittable {
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+class EmittableLinearProgressIndicator : Emittable {
     override var modifier: GlanceModifier = GlanceModifier
     var progress: Float = 0.0f
     var indeterminate: Boolean = false
diff --git a/glance/glance-testing/api/current.txt b/glance/glance-testing/api/current.txt
index f12cf50..7524595 100644
--- a/glance/glance-testing/api/current.txt
+++ b/glance/glance-testing/api/current.txt
@@ -12,16 +12,29 @@
     method public androidx.glance.testing.GlanceNodeAssertion<R,T> assert(androidx.glance.testing.GlanceNodeMatcher<R> matcher, optional kotlin.jvm.functions.Function0<java.lang.String>? messagePrefixOnError);
     method public androidx.glance.testing.GlanceNodeAssertion<R,T> assertDoesNotExist();
     method public androidx.glance.testing.GlanceNodeAssertion<R,T> assertExists();
+    method public androidx.glance.testing.GlanceNodeAssertionCollection<R,T> onChildren();
+  }
+
+  public final class GlanceNodeAssertionCollection<R, T extends androidx.glance.testing.GlanceNode<R>> {
+    method public androidx.glance.testing.GlanceNodeAssertionCollection<R,T> assertAll(androidx.glance.testing.GlanceNodeMatcher<R> matcher);
+    method public androidx.glance.testing.GlanceNodeAssertionCollection<R,T> assertAny(androidx.glance.testing.GlanceNodeMatcher<R> matcher);
+    method public androidx.glance.testing.GlanceNodeAssertionCollection<R,T> assertCountEquals(int expectedCount);
+    method public androidx.glance.testing.GlanceNodeAssertionCollection<R,T> filter(androidx.glance.testing.GlanceNodeMatcher<R> matcher);
+    method public operator androidx.glance.testing.GlanceNodeAssertion<R,T> get(int index);
   }
 
   public interface GlanceNodeAssertionsProvider<R, T extends androidx.glance.testing.GlanceNode<R>> {
+    method public androidx.glance.testing.GlanceNodeAssertionCollection<R,T> onAllNodes(androidx.glance.testing.GlanceNodeMatcher<R> matcher);
     method public androidx.glance.testing.GlanceNodeAssertion<R,T> onNode(androidx.glance.testing.GlanceNodeMatcher<R> matcher);
   }
 
   public final class GlanceNodeMatcher<R> {
     ctor public GlanceNodeMatcher(String description, kotlin.jvm.functions.Function1<? super androidx.glance.testing.GlanceNode<R>,java.lang.Boolean> matcher);
+    method public infix androidx.glance.testing.GlanceNodeMatcher<R> and(androidx.glance.testing.GlanceNodeMatcher<R> other);
     method public boolean matches(androidx.glance.testing.GlanceNode<R> node);
     method public boolean matchesAny(Iterable<? extends androidx.glance.testing.GlanceNode<R>> nodes);
+    method public operator androidx.glance.testing.GlanceNodeMatcher<R> not();
+    method public infix androidx.glance.testing.GlanceNodeMatcher<R> or(androidx.glance.testing.GlanceNodeMatcher<R> other);
   }
 
 }
@@ -40,8 +53,9 @@
   public final class UnitTestAssertionExtensionsKt {
     method public static androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode> assertHasClickAction(androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode>);
     method public static androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode> assertHasContentDescription(androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode>, String value);
-    method public static androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode> assertHasContentDescription(androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode>, String value, optional boolean substring);
-    method public static androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode> assertHasContentDescription(androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode>, String value, optional boolean substring, optional boolean ignoreCase);
+    method public static androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode> assertHasContentDescription(androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode>, String value, optional boolean ignoreCase);
+    method public static androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode> assertHasContentDescriptionEqualTo(androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode>, String value);
+    method public static androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode> assertHasContentDescriptionEqualTo(androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode>, String value, optional boolean ignoreCase);
     method public static androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode> assertHasNoClickAction(androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode>);
     method public static androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode> assertHasStartActivityClickAction(androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode>, android.content.ComponentName componentName);
     method public static androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode> assertHasStartActivityClickAction(androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode>, android.content.ComponentName componentName, optional androidx.glance.action.ActionParameters parameters);
@@ -49,13 +63,19 @@
     method public static <T extends android.app.Activity> androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode> assertHasStartActivityClickAction(androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode>, Class<T> activityClass, optional androidx.glance.action.ActionParameters parameters);
     method public static <T extends android.app.Activity> androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode> assertHasStartActivityClickAction(androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode>, Class<T> activityClass, optional androidx.glance.action.ActionParameters parameters, optional android.os.Bundle? activityOptions);
     method public static androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode> assertHasTestTag(androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode>, String testTag);
+    method public static androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode> assertHasText(androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode>, String text);
+    method public static androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode> assertHasText(androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode>, String text, optional boolean ignoreCase);
+    method public static androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode> assertHasTextEqualTo(androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode>, String text);
+    method public static androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode> assertHasTextEqualTo(androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode>, String text, optional boolean ignoreCase);
   }
 
   public final class UnitTestFiltersKt {
+    method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> hasAnyDescendant(androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> matcher);
     method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> hasClickAction();
     method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> hasContentDescription(String value);
-    method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> hasContentDescription(String value, optional boolean substring);
-    method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> hasContentDescription(String value, optional boolean substring, optional boolean ignoreCase);
+    method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> hasContentDescription(String value, optional boolean ignoreCase);
+    method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> hasContentDescriptionEqualTo(String value);
+    method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> hasContentDescriptionEqualTo(String value, optional boolean ignoreCase);
     method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> hasNoClickAction();
     method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> hasStartActivityClickAction(android.content.ComponentName componentName);
     method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> hasStartActivityClickAction(android.content.ComponentName componentName, optional androidx.glance.action.ActionParameters parameters);
@@ -64,8 +84,9 @@
     method public static <T extends android.app.Activity> androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> hasStartActivityClickAction(Class<T> activityClass, optional androidx.glance.action.ActionParameters parameters, optional android.os.Bundle? activityOptions);
     method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> hasTestTag(String testTag);
     method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> hasText(String text);
-    method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> hasText(String text, optional boolean substring);
-    method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> hasText(String text, optional boolean substring, optional boolean ignoreCase);
+    method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> hasText(String text, optional boolean ignoreCase);
+    method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> hasTextEqualTo(String text);
+    method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> hasTextEqualTo(String text, optional boolean ignoreCase);
   }
 
 }
diff --git a/glance/glance-testing/api/restricted_current.txt b/glance/glance-testing/api/restricted_current.txt
index f12cf50..7524595 100644
--- a/glance/glance-testing/api/restricted_current.txt
+++ b/glance/glance-testing/api/restricted_current.txt
@@ -12,16 +12,29 @@
     method public androidx.glance.testing.GlanceNodeAssertion<R,T> assert(androidx.glance.testing.GlanceNodeMatcher<R> matcher, optional kotlin.jvm.functions.Function0<java.lang.String>? messagePrefixOnError);
     method public androidx.glance.testing.GlanceNodeAssertion<R,T> assertDoesNotExist();
     method public androidx.glance.testing.GlanceNodeAssertion<R,T> assertExists();
+    method public androidx.glance.testing.GlanceNodeAssertionCollection<R,T> onChildren();
+  }
+
+  public final class GlanceNodeAssertionCollection<R, T extends androidx.glance.testing.GlanceNode<R>> {
+    method public androidx.glance.testing.GlanceNodeAssertionCollection<R,T> assertAll(androidx.glance.testing.GlanceNodeMatcher<R> matcher);
+    method public androidx.glance.testing.GlanceNodeAssertionCollection<R,T> assertAny(androidx.glance.testing.GlanceNodeMatcher<R> matcher);
+    method public androidx.glance.testing.GlanceNodeAssertionCollection<R,T> assertCountEquals(int expectedCount);
+    method public androidx.glance.testing.GlanceNodeAssertionCollection<R,T> filter(androidx.glance.testing.GlanceNodeMatcher<R> matcher);
+    method public operator androidx.glance.testing.GlanceNodeAssertion<R,T> get(int index);
   }
 
   public interface GlanceNodeAssertionsProvider<R, T extends androidx.glance.testing.GlanceNode<R>> {
+    method public androidx.glance.testing.GlanceNodeAssertionCollection<R,T> onAllNodes(androidx.glance.testing.GlanceNodeMatcher<R> matcher);
     method public androidx.glance.testing.GlanceNodeAssertion<R,T> onNode(androidx.glance.testing.GlanceNodeMatcher<R> matcher);
   }
 
   public final class GlanceNodeMatcher<R> {
     ctor public GlanceNodeMatcher(String description, kotlin.jvm.functions.Function1<? super androidx.glance.testing.GlanceNode<R>,java.lang.Boolean> matcher);
+    method public infix androidx.glance.testing.GlanceNodeMatcher<R> and(androidx.glance.testing.GlanceNodeMatcher<R> other);
     method public boolean matches(androidx.glance.testing.GlanceNode<R> node);
     method public boolean matchesAny(Iterable<? extends androidx.glance.testing.GlanceNode<R>> nodes);
+    method public operator androidx.glance.testing.GlanceNodeMatcher<R> not();
+    method public infix androidx.glance.testing.GlanceNodeMatcher<R> or(androidx.glance.testing.GlanceNodeMatcher<R> other);
   }
 
 }
@@ -40,8 +53,9 @@
   public final class UnitTestAssertionExtensionsKt {
     method public static androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode> assertHasClickAction(androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode>);
     method public static androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode> assertHasContentDescription(androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode>, String value);
-    method public static androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode> assertHasContentDescription(androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode>, String value, optional boolean substring);
-    method public static androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode> assertHasContentDescription(androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode>, String value, optional boolean substring, optional boolean ignoreCase);
+    method public static androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode> assertHasContentDescription(androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode>, String value, optional boolean ignoreCase);
+    method public static androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode> assertHasContentDescriptionEqualTo(androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode>, String value);
+    method public static androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode> assertHasContentDescriptionEqualTo(androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode>, String value, optional boolean ignoreCase);
     method public static androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode> assertHasNoClickAction(androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode>);
     method public static androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode> assertHasStartActivityClickAction(androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode>, android.content.ComponentName componentName);
     method public static androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode> assertHasStartActivityClickAction(androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode>, android.content.ComponentName componentName, optional androidx.glance.action.ActionParameters parameters);
@@ -49,13 +63,19 @@
     method public static <T extends android.app.Activity> androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode> assertHasStartActivityClickAction(androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode>, Class<T> activityClass, optional androidx.glance.action.ActionParameters parameters);
     method public static <T extends android.app.Activity> androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode> assertHasStartActivityClickAction(androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode>, Class<T> activityClass, optional androidx.glance.action.ActionParameters parameters, optional android.os.Bundle? activityOptions);
     method public static androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode> assertHasTestTag(androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode>, String testTag);
+    method public static androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode> assertHasText(androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode>, String text);
+    method public static androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode> assertHasText(androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode>, String text, optional boolean ignoreCase);
+    method public static androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode> assertHasTextEqualTo(androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode>, String text);
+    method public static androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode> assertHasTextEqualTo(androidx.glance.testing.GlanceNodeAssertion<androidx.glance.testing.unit.MappedNode,androidx.glance.testing.unit.GlanceMappedNode>, String text, optional boolean ignoreCase);
   }
 
   public final class UnitTestFiltersKt {
+    method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> hasAnyDescendant(androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> matcher);
     method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> hasClickAction();
     method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> hasContentDescription(String value);
-    method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> hasContentDescription(String value, optional boolean substring);
-    method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> hasContentDescription(String value, optional boolean substring, optional boolean ignoreCase);
+    method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> hasContentDescription(String value, optional boolean ignoreCase);
+    method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> hasContentDescriptionEqualTo(String value);
+    method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> hasContentDescriptionEqualTo(String value, optional boolean ignoreCase);
     method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> hasNoClickAction();
     method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> hasStartActivityClickAction(android.content.ComponentName componentName);
     method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> hasStartActivityClickAction(android.content.ComponentName componentName, optional androidx.glance.action.ActionParameters parameters);
@@ -64,8 +84,9 @@
     method public static <T extends android.app.Activity> androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> hasStartActivityClickAction(Class<T> activityClass, optional androidx.glance.action.ActionParameters parameters, optional android.os.Bundle? activityOptions);
     method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> hasTestTag(String testTag);
     method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> hasText(String text);
-    method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> hasText(String text, optional boolean substring);
-    method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> hasText(String text, optional boolean substring, optional boolean ignoreCase);
+    method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> hasText(String text, optional boolean ignoreCase);
+    method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> hasTextEqualTo(String text);
+    method public static androidx.glance.testing.GlanceNodeMatcher<androidx.glance.testing.unit.MappedNode> hasTextEqualTo(String text, optional boolean ignoreCase);
   }
 
 }
diff --git a/glance/glance-testing/lint-baseline.xml b/glance/glance-testing/lint-baseline.xml
index c7ffb94..bc6854b 100644
--- a/glance/glance-testing/lint-baseline.xml
+++ b/glance/glance-testing/lint-baseline.xml
@@ -1,11 +1,20 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.2.0-alpha15" type="baseline" client="gradle" dependencies="false" name="AGP (8.2.0-alpha15)" variant="all" version="8.2.0-alpha15">
+<issues format="6" by="lint 8.2.0-beta01" type="baseline" client="gradle" dependencies="false" name="AGP (8.2.0-beta01)" variant="all" version="8.2.0-beta01">
 
     <issue
         id="ListIterator"
         message="Creating an unnecessary Iterator to iterate through a List"
-        errorLine1="            return emittable.children.map { child ->"
-        errorLine2="                                      ~~~">
+        errorLine1="    nodes.forEachIndexed { index, glanceNode ->"
+        errorLine2="          ~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/glance/testing/AssertionErrorMessages.kt"/>
+    </issue>
+
+    <issue
+        id="ListIterator"
+        message="Creating an unnecessary Iterator to iterate through a List"
+        errorLine1="        children.forEach { child ->"
+        errorLine2="                 ~~~~~~~">
         <location
             file="src/main/java/androidx/glance/testing/unit/GlanceMappedNode.kt"/>
     </issue>
@@ -13,19 +22,28 @@
     <issue
         id="ListIterator"
         message="Creating an unnecessary Iterator to iterate through a List"
-        errorLine1="        for (child in node.children()) {"
-        errorLine2="                   ~~">
+        errorLine1="        return mappedNodes.toList()"
+        errorLine2="                           ~~~~~~">
         <location
-            file="src/main/java/androidx/glance/testing/GlanceNodeAssertion.kt"/>
+            file="src/main/java/androidx/glance/testing/unit/GlanceMappedNode.kt"/>
     </issue>
 
     <issue
         id="ListIterator"
         message="Creating an unnecessary Iterator to iterate through a List"
-        errorLine1="        return matching.toList()"
-        errorLine2="                        ~~~~~~">
+        errorLine1="        val violations = filteredNodes.filter {"
+        errorLine2="                                       ~~~~~~">
         <location
-            file="src/main/java/androidx/glance/testing/GlanceNodeAssertion.kt"/>
+            file="src/main/java/androidx/glance/testing/GlanceNodeAssertionCollection.kt"/>
+    </issue>
+
+    <issue
+        id="ListIterator"
+        message="Creating an unnecessary Iterator to iterate through a List"
+        errorLine1="            this.allNodes = allNodes.toList()"
+        errorLine2="                                     ~~~~~~">
+        <location
+            file="src/main/java/androidx/glance/testing/TestContext.kt"/>
     </issue>
 
     <issue
@@ -37,4 +55,13 @@
             file="src/main/java/androidx/glance/testing/unit/UnitTestFilters.kt"/>
     </issue>
 
+    <issue
+        id="ListIterator"
+        message="Creating an unnecessary Iterator to iterate through a List"
+        errorLine1="        return node.children().any { checkIfSubtreeMatchesRecursive(matcher, it) }"
+        errorLine2="                               ~~~">
+        <location
+            file="src/main/java/androidx/glance/testing/unit/UnitTestFilters.kt"/>
+    </issue>
+
 </issues>
diff --git a/glance/glance-testing/src/main/java/androidx/glance/testing/AssertionErrorMessages.kt b/glance/glance-testing/src/main/java/androidx/glance/testing/AssertionErrorMessages.kt
index 671a692..16155f6 100644
--- a/glance/glance-testing/src/main/java/androidx/glance/testing/AssertionErrorMessages.kt
+++ b/glance/glance-testing/src/main/java/androidx/glance/testing/AssertionErrorMessages.kt
@@ -19,23 +19,40 @@
 import java.lang.StringBuilder
 
 /**
- * Builds error message for case where expected amount of matching nodes does not match reality.
+ * Builds error message with reason appended.
  *
- * Provide [errorMessage] to explain which operation you were about to perform. This makes it
- * easier for developer to find where the failure happened.
+ * @param errorMessageOnFail message explaining which operation you were about to perform. This
+ *                           makes it easier for developer to find where the failure happened.
+ * @param reason the reason for failure
  */
-internal fun buildErrorMessageForCountMismatch(
-    errorMessage: String,
+internal fun buildErrorMessageWithReason(errorMessageOnFail: String, reason: String): String {
+    return "${errorMessageOnFail}\nReason: $reason"
+}
+
+/**
+ * Builds error reason for case where amount of matching nodes are less than needed to query given
+ * index and perform assertions on (e.g. if getting a node at index 2 but only 2 nodes exist in
+ * the collection).
+ */
+internal fun buildErrorReasonForIndexOutOfMatchedNodeBounds(
+    matcherDescription: String,
+    requestedIndex: Int,
+    actualCount: Int
+): String {
+    return "Not enough node(s) matching condition: ($matcherDescription) " +
+        "to get node at index '$requestedIndex'. Found '$actualCount' matching node(s)"
+}
+
+/**
+ * Builds error reason for case where expected amount of matching nodes does not match reality.
+ */
+internal fun buildErrorReasonForCountMismatch(
     matcherDescription: String,
     expectedCount: Int,
     actualCount: Int
 ): String {
     val sb = StringBuilder()
 
-    sb.append(errorMessage)
-    sb.append("\n")
-
-    sb.append("Reason: ")
     when (expectedCount) {
         0 -> {
             sb.append("Did not expect any node matching condition: $matcherDescription")
@@ -52,20 +69,54 @@
 }
 
 /**
- * Builds error message for general assertion errors.
+ * Builds error reason for assertions where at least one node was expected to be present to make
+ * assertions on (e.g. assertAny).
+ */
+internal fun buildErrorReasonForAtLeastOneNodeExpected(
+    matcherDescription: String
+): String {
+    return "Expected to receive at least 1 node " +
+        "but 0 nodes were found for condition: ($matcherDescription)"
+}
+
+/**
+ * Builds error message for general assertion errors involving a single node.
  *
  * <p>Provide [errorMessage] to explain which operation you were about to perform. This makes it
  * easier for developer to find where the failure happened.
  */
 internal fun <R> buildGeneralErrorMessage(
     errorMessage: String,
-    glanceNode: GlanceNode<R>
+    node: GlanceNode<R>
 ): String {
     val sb = StringBuilder()
     sb.append(errorMessage)
 
     sb.append("\n")
-    sb.append("Glance Node: ${glanceNode.toDebugString()}")
+    sb.append("Glance Node: ${node.toDebugString()}")
+
+    return sb.toString()
+}
+
+/**
+ * Builds error message for general assertion errors for multiple nodes.
+ *
+ * <p>Provide [errorMessage] to explain which operation you were about to perform. This makes it
+ * easier for developer to find where the failure happened.
+ */
+internal fun <R> buildGeneralErrorMessage(
+    errorMessage: String,
+    nodes: List<GlanceNode<R>>
+): String {
+    val sb = StringBuilder()
+    sb.append(errorMessage)
+
+    sb.append("\n")
+    sb.append("Found ${nodes.size} node(s) that don't match.")
+
+    nodes.forEachIndexed { index, glanceNode ->
+        sb.append("\nNon-matching Glance Node #${index + 1}: ${glanceNode.toDebugString()}")
+    }
 
     return sb.toString()
 }
diff --git a/glance/glance-testing/src/main/java/androidx/glance/testing/GlanceNodeAssertion.kt b/glance/glance-testing/src/main/java/androidx/glance/testing/GlanceNodeAssertion.kt
index 31a1c99..4095626 100644
--- a/glance/glance-testing/src/main/java/androidx/glance/testing/GlanceNodeAssertion.kt
+++ b/glance/glance-testing/src/main/java/androidx/glance/testing/GlanceNodeAssertion.kt
@@ -22,12 +22,12 @@
 /**
  * Represents a Glance node from the tree that can be asserted on.
  *
- * An instance of [GlanceNodeAssertion] can be obtained from {@code onNode} and equivalent methods
- * on a GlanceNodeAssertionProvider
+ * An instance of [GlanceNodeAssertion] can be obtained from `onNode` and equivalent methods
+ * on a [GlanceNodeAssertionsProvider]
  */
 class GlanceNodeAssertion<R, T : GlanceNode<R>> @RestrictTo(Scope.LIBRARY_GROUP) constructor(
-    private val matcher: GlanceNodeMatcher<R>,
     private val testContext: TestContext<R, T>,
+    private val selector: GlanceNodeSelector<R>,
 ) {
     /**
      * Asserts that the node was found.
@@ -35,7 +35,7 @@
      * @throws [AssertionError] if the assert fails.
      */
     fun assertExists(): GlanceNodeAssertion<R, T> {
-        findSingleMatchingNode(finalErrorMessageOnFail = "Failed assertExists")
+        findSingleMatchingNode(errorMessageOnFail = "Failed assertExists")
         return this
     }
 
@@ -45,14 +45,17 @@
      * @throws [AssertionError] if the assert fails.
      */
     fun assertDoesNotExist(): GlanceNodeAssertion<R, T> {
-        val matchedNodesCount = findMatchingNodes().size
+        val errorMessageOnFail = "Failed assertDoesNotExist"
+        val matchedNodesCount = testContext.findMatchingNodes(selector, errorMessageOnFail).size
         if (matchedNodesCount != 0) {
             throw AssertionError(
-                buildErrorMessageForCountMismatch(
-                    errorMessage = "Failed assertDoesNotExist",
-                    matcherDescription = matcher.description,
-                    expectedCount = 0,
-                    actualCount = matchedNodesCount
+                buildErrorMessageWithReason(
+                    errorMessageOnFail = errorMessageOnFail,
+                    reason = buildErrorReasonForCountMismatch(
+                        matcherDescription = selector.description,
+                        expectedCount = 0,
+                        actualCount = matchedNodesCount
+                    )
                 )
             )
         }
@@ -93,39 +96,28 @@
         return this
     }
 
-    private fun findSingleMatchingNode(finalErrorMessageOnFail: String): GlanceNode<R> {
-        val matchingNodes = findMatchingNodes()
-        val matchedNodesCount = matchingNodes.size
-        if (matchedNodesCount != 1) {
+    /**
+     * Returns [GlanceNodeAssertionCollection] that allows performing assertions on the children of
+     * the node selected by this [GlanceNodeAssertion].
+     */
+    fun onChildren(): GlanceNodeAssertionCollection<R, T> {
+        return GlanceNodeAssertionCollection(testContext, selector.addChildrenSelector())
+    }
+
+    private fun findSingleMatchingNode(errorMessageOnFail: String): GlanceNode<R> {
+        val matchingNodes = testContext.findMatchingNodes(selector, errorMessageOnFail)
+        if (matchingNodes.size != 1) {
             throw AssertionError(
-                buildErrorMessageForCountMismatch(
-                    finalErrorMessageOnFail,
-                    matcher.description,
-                    expectedCount = 1,
-                    actualCount = matchedNodesCount
+                buildErrorMessageWithReason(
+                    errorMessageOnFail = errorMessageOnFail,
+                    reason = buildErrorReasonForCountMismatch(
+                        matcherDescription = selector.description,
+                        expectedCount = 1,
+                        actualCount = matchingNodes.size
+                    )
                 )
             )
         }
         return matchingNodes.single()
     }
-
-    private fun findMatchingNodes(): List<GlanceNode<R>> {
-        if (testContext.cachedMatchedNodes.isEmpty()) {
-            val rootGlanceNode =
-                checkNotNull(testContext.rootGlanceNode) { "No root GlanceNode found." }
-            testContext.cachedMatchedNodes = findMatchingNodes(rootGlanceNode)
-        }
-        return testContext.cachedMatchedNodes
-    }
-
-    private fun findMatchingNodes(node: GlanceNode<R>): List<GlanceNode<R>> {
-        val matching = mutableListOf<GlanceNode<R>>()
-        if (matcher.matches(node)) {
-            matching.add(node)
-        }
-        for (child in node.children()) {
-            matching.addAll(findMatchingNodes(child))
-        }
-        return matching.toList()
-    }
 }
diff --git a/glance/glance-testing/src/main/java/androidx/glance/testing/GlanceNodeAssertionCollection.kt b/glance/glance-testing/src/main/java/androidx/glance/testing/GlanceNodeAssertionCollection.kt
new file mode 100644
index 0000000..cbe4572
--- /dev/null
+++ b/glance/glance-testing/src/main/java/androidx/glance/testing/GlanceNodeAssertionCollection.kt
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.glance.testing
+
+import androidx.annotation.RestrictTo
+
+/**
+ * Represents a collection of Glance nodes from the tree that can be asserted on.
+ *
+ * An instance of [GlanceNodeAssertionCollection] can be obtained from
+ * [GlanceNodeAssertionsProvider.onAllNodes] and equivalent methods.
+ */
+// Equivalent to SemanticsNodeInteractionCollection in compose.
+class GlanceNodeAssertionCollection<R, T : GlanceNode<R>>
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) constructor(
+    private val testContext: TestContext<R, T>,
+    private val selector: GlanceNodeSelector<R>
+) {
+    /**
+     * Asserts that this collection of nodes is equal to the given [expectedCount].
+     *
+     * @throws AssertionError if the size is not equal to [expectedCount]
+     */
+    fun assertCountEquals(
+        expectedCount: Int
+    ): GlanceNodeAssertionCollection<R, T> {
+        val errorMessageOnFail = "Failed to assert count of nodes"
+
+        val actualCount = testContext.findMatchingNodes(selector, errorMessageOnFail).size
+        if (actualCount != expectedCount) {
+            throw AssertionError(
+                buildErrorMessageWithReason(
+                    errorMessageOnFail = errorMessageOnFail,
+                    reason = buildErrorReasonForCountMismatch(
+                        matcherDescription = selector.description,
+                        expectedCount = expectedCount,
+                        actualCount = actualCount
+                    )
+                )
+            )
+        }
+        return this
+    }
+
+    /**
+     * Asserts that all the nodes in this collection satisfy the given [matcher].
+     *
+     * Doesn't throw error if the collection is empty. Use [assertCountEquals] to assert on expected
+     * size of the collection.
+     *
+     * @param matcher Matcher that has to be satisfied by all the nodes in the collection.
+     * @throws AssertionError if the collection contains at least one element that does not satisfy
+     * the given matcher.
+     */
+    fun assertAll(
+        matcher: GlanceNodeMatcher<R>,
+    ): GlanceNodeAssertionCollection<R, T> {
+        val errorMessageOnFail = "Failed to assertAll(${matcher.description})"
+
+        val filteredNodes = testContext.findMatchingNodes(selector, errorMessageOnFail)
+        val violations = filteredNodes.filter {
+            !matcher.matches(it)
+        }
+        if (violations.isNotEmpty()) {
+            throw AssertionError(buildGeneralErrorMessage(errorMessageOnFail, violations))
+        }
+        return this
+    }
+
+    /**
+     * Asserts that this collection contains at least one element that satisfies the given
+     * [matcher].
+     *
+     * @param matcher Matcher that has to be satisfied by at least one of the nodes in the
+     * collection.
+     * @throws AssertionError if not at least one matching node was found.
+     */
+    fun assertAny(
+        matcher: GlanceNodeMatcher<R>,
+    ): GlanceNodeAssertionCollection<R, T> {
+        val errorMessageOnFail = "Failed to assertAny(${matcher.description})"
+        val filteredNodes = testContext.findMatchingNodes(selector, errorMessageOnFail)
+
+        if (filteredNodes.isEmpty()) {
+            throw AssertionError(
+                buildErrorMessageWithReason(
+                    errorMessageOnFail = errorMessageOnFail,
+                    reason = buildErrorReasonForAtLeastOneNodeExpected(selector.description)
+                )
+            )
+        }
+
+        if (!matcher.matchesAny(filteredNodes)) {
+            throw AssertionError(buildGeneralErrorMessage(errorMessageOnFail, filteredNodes))
+        }
+        return this
+    }
+
+    /**
+     * Returns a [GlanceNodeAssertion] that can assert on the node at the given index of this
+     * collection.
+     *
+     * Any subsequent assertion on its result will throw error if index is out of bounds of the
+     * matching nodes found from previous operations.
+     */
+    operator fun get(index: Int): GlanceNodeAssertion<R, T> {
+        return GlanceNodeAssertion(
+            testContext = testContext,
+            selector = selector.addIndexedSelector(index)
+        )
+    }
+
+    /**
+     * Returns a new collection of nodes by filtering the given nodes using the provided [matcher].
+     */
+    fun filter(matcher: GlanceNodeMatcher<R>): GlanceNodeAssertionCollection<R, T> {
+        return GlanceNodeAssertionCollection(
+            testContext,
+            selector.addMatcherSelector(
+                selectorName = "filter",
+                matcher = matcher
+            )
+        )
+    }
+}
diff --git a/glance/glance-testing/src/main/java/androidx/glance/testing/GlanceNodeAssertionsProvider.kt b/glance/glance-testing/src/main/java/androidx/glance/testing/GlanceNodeAssertionsProvider.kt
index 624b529..8adddc0 100644
--- a/glance/glance-testing/src/main/java/androidx/glance/testing/GlanceNodeAssertionsProvider.kt
+++ b/glance/glance-testing/src/main/java/androidx/glance/testing/GlanceNodeAssertionsProvider.kt
@@ -30,4 +30,11 @@
      * @param matcher Matcher used for filtering
      */
     fun onNode(matcher: GlanceNodeMatcher<R>): GlanceNodeAssertion<R, T>
+
+    /**
+     * Finds all Glance nodes that matches the given condition.
+     *
+     * @param matcher Matcher used for filtering
+     */
+    fun onAllNodes(matcher: GlanceNodeMatcher<R>): GlanceNodeAssertionCollection<R, T>
 }
diff --git a/glance/glance-testing/src/main/java/androidx/glance/testing/GlanceNodeMatcher.kt b/glance/glance-testing/src/main/java/androidx/glance/testing/GlanceNodeMatcher.kt
index 0e9fe2a..6de4dc5 100644
--- a/glance/glance-testing/src/main/java/androidx/glance/testing/GlanceNodeMatcher.kt
+++ b/glance/glance-testing/src/main/java/androidx/glance/testing/GlanceNodeMatcher.kt
@@ -38,4 +38,35 @@
     fun matchesAny(nodes: Iterable<GlanceNode<R>>): Boolean {
         return nodes.any(matcher)
     }
+
+    /**
+     * Returns whether the given node is matched by this and the [other] matcher.
+     *
+     * @param other matcher that should also match in addition to current matcher
+     */
+    infix fun and(other: GlanceNodeMatcher<R>): GlanceNodeMatcher<R> {
+        return GlanceNodeMatcher("($description) && (${other.description})") {
+            matcher(it) && other.matches(it)
+        }
+    }
+
+    /**
+     * Returns whether the given node is matched by this or the [other] matcher.
+     *
+     * @param other matcher that can be tested to match if the current matcher doesn't.
+     */
+    infix fun or(other: GlanceNodeMatcher<R>): GlanceNodeMatcher<R> {
+        return GlanceNodeMatcher("($description) || (${other.description})") {
+            matcher(it) || other.matches(it)
+        }
+    }
+
+    /**
+     * Returns whether the given node does not match the matcher.
+     */
+    operator fun not(): GlanceNodeMatcher<R> {
+        return GlanceNodeMatcher(("NOT ($description)")) {
+            !matcher(it)
+        }
+    }
 }
diff --git a/glance/glance-testing/src/main/java/androidx/glance/testing/GlanceNodeSelector.kt b/glance/glance-testing/src/main/java/androidx/glance/testing/GlanceNodeSelector.kt
new file mode 100644
index 0000000..f06d499
--- /dev/null
+++ b/glance/glance-testing/src/main/java/androidx/glance/testing/GlanceNodeSelector.kt
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.glance.testing
+
+import androidx.annotation.RestrictTo
+
+/**
+ * A chainable selector that allows specifying how to select nodes from a collection.
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+class GlanceNodeSelector<R>(
+    val description: String,
+    private val previousChainedSelector: GlanceNodeSelector<R>? = null,
+    private val selector: (Iterable<GlanceNode<R>>) -> SelectionResult<R>
+) {
+
+    /**
+     * Returns nodes selected by previous chained selectors followed by the current selector.
+     */
+    fun map(nodes: Iterable<GlanceNode<R>>): SelectionResult<R> {
+        val previousSelectionResult = previousChainedSelector?.map(nodes)
+        val inputNodes = previousSelectionResult?.selectedNodes ?: nodes
+        return selector(inputNodes)
+    }
+}
+
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+class SelectionResult<R>(
+    val selectedNodes: List<GlanceNode<R>>,
+    val errorMessageOnNoMatch: String? = null
+)
+
+/**
+ * Constructs an entry-point selector that selects nodes satisfying the matcher condition. Used at
+ * the entry points such as [GlanceNodeAssertionsProvider.onNode] and
+ * [GlanceNodeAssertionsProvider.onAllNodes] where there is no previous chained selector.
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+fun <R> GlanceNodeMatcher<R>.matcherToSelector(): GlanceNodeSelector<R> {
+    return GlanceNodeSelector(
+        description = description,
+        previousChainedSelector = null
+    ) { glanceNodes ->
+        SelectionResult(
+            selectedNodes = glanceNodes.filter { matches(it) }
+        )
+    }
+}
+
+/**
+ * Wraps the current selector with a chained selector that selects a node at a given index from the
+ * the result of current selection.
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+fun <R> GlanceNodeSelector<R>.addIndexedSelector(index: Int): GlanceNodeSelector<R> {
+    return GlanceNodeSelector(
+        description = "(${this.description})[$index]",
+        previousChainedSelector = this
+    ) { nodes ->
+        val nodesList = nodes.toList()
+        val minimumExpectedCount = index + 1
+        if (index >= 0 && index < nodesList.size) {
+            SelectionResult(
+                selectedNodes = listOf(nodesList[index])
+            )
+        } else {
+            SelectionResult(
+                selectedNodes = emptyList(),
+                errorMessageOnNoMatch = buildErrorReasonForIndexOutOfMatchedNodeBounds(
+                    description,
+                    requestedIndex = minimumExpectedCount,
+                    actualCount = nodesList.size
+                )
+            )
+        }
+    }
+}
+
+/**
+ * Wraps the current selector with a chained matcher-based selector that filters the list of nodes
+ * to return ones matched by the matcher.
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+fun <R> GlanceNodeSelector<R>.addMatcherSelector(
+    selectorName: String,
+    matcher: GlanceNodeMatcher<R>
+): GlanceNodeSelector<R> {
+    return GlanceNodeSelector(
+        description = "(${this.description}).$selectorName(${matcher.description})",
+        previousChainedSelector = this
+    ) { nodes ->
+        SelectionResult(
+            selectedNodes = nodes.filter { matcher.matches(it) }
+        )
+    }
+}
+
+/**
+ * Wraps the current selector with a chained matcher-based selector that ensures only one node is
+ * returned by current selector and selects children of that node.
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+fun <R> GlanceNodeSelector<R>.addChildrenSelector(): GlanceNodeSelector<R> {
+    return GlanceNodeSelector(
+        description = "($description).children()",
+        previousChainedSelector = this
+    ) { nodes ->
+        if (nodes.count() != 1) {
+            SelectionResult(
+                selectedNodes = emptyList(),
+                errorMessageOnNoMatch = buildErrorReasonForCountMismatch(
+                    matcherDescription = description,
+                    expectedCount = 1,
+                    actualCount = nodes.count()
+                )
+            )
+        } else {
+            SelectionResult(
+                selectedNodes = nodes.single().children()
+            )
+        }
+    }
+}
diff --git a/glance/glance-testing/src/main/java/androidx/glance/testing/TestContext.kt b/glance/glance-testing/src/main/java/androidx/glance/testing/TestContext.kt
index 1ab76a3..419a304 100644
--- a/glance/glance-testing/src/main/java/androidx/glance/testing/TestContext.kt
+++ b/glance/glance-testing/src/main/java/androidx/glance/testing/TestContext.kt
@@ -23,13 +23,55 @@
  */
 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
 class TestContext<R, T : GlanceNode<R>> {
+    var rootGlanceNode: T? = null
+    private var allNodes: List<GlanceNode<R>> = emptyList()
+
     /**
-     * To be called on every onNode to restart matching and clear cache.
+     * Returns all nodes in single flat list (either from cache or by traversing the hierarchy from
+     * root glance node).
      */
-    fun reset() {
-        cachedMatchedNodes = emptyList()
+    private fun getAllNodes(): List<GlanceNode<R>> {
+        val rootGlanceNode =
+            checkNotNull(rootGlanceNode) { "No root GlanceNode found." }
+        if (this.allNodes.isEmpty()) {
+            val allNodes = mutableListOf<GlanceNode<R>>()
+
+            fun collectAllNodesRecursive(currentNode: GlanceNode<R>) {
+                allNodes.add(currentNode)
+                val children = currentNode.children()
+                for (index in children.indices) {
+                    collectAllNodesRecursive(children[index])
+                }
+            }
+
+            collectAllNodesRecursive(rootGlanceNode)
+            this.allNodes = allNodes.toList()
+        }
+
+        return this.allNodes
     }
 
-    var rootGlanceNode: T? = null
-    var cachedMatchedNodes: List<GlanceNode<R>> = emptyList()
+    /**
+     * Finds nodes matching the given selector from the list of all nodes in the hierarchy.
+     *
+     * @throws AssertionError if provided selector results in an error due to no match.
+     */
+    fun findMatchingNodes(
+        selector: GlanceNodeSelector<R>,
+        errorMessageOnFail: String
+    ): List<GlanceNode<R>> {
+        val allNodes = getAllNodes()
+        val selectionResult = selector.map(allNodes)
+
+        if (selectionResult.errorMessageOnNoMatch != null) {
+            throw AssertionError(
+                buildErrorMessageWithReason(
+                    errorMessageOnFail = errorMessageOnFail,
+                    reason = selectionResult.errorMessageOnNoMatch
+                )
+            )
+        }
+
+        return selectionResult.selectedNodes
+    }
 }
diff --git a/glance/glance-testing/src/main/java/androidx/glance/testing/unit/GlanceMappedNode.kt b/glance/glance-testing/src/main/java/androidx/glance/testing/unit/GlanceMappedNode.kt
index 8b20029..929fc80 100644
--- a/glance/glance-testing/src/main/java/androidx/glance/testing/unit/GlanceMappedNode.kt
+++ b/glance/glance-testing/src/main/java/androidx/glance/testing/unit/GlanceMappedNode.kt
@@ -19,6 +19,7 @@
 import androidx.annotation.RestrictTo
 import androidx.annotation.RestrictTo.Scope
 import androidx.glance.Emittable
+import androidx.glance.EmittableLazyItemWithChildren
 import androidx.glance.EmittableWithChildren
 import androidx.glance.testing.GlanceNode
 
@@ -60,13 +61,23 @@
     override fun children(): List<GlanceNode<MappedNode>> {
         val emittable = mappedNode.emittable
         if (emittable is EmittableWithChildren) {
-            return emittable.children.map { child ->
-                GlanceMappedNode(child)
-            }
+            return emittable.toMappedNodes()
         }
         return emptyList()
     }
 
+    private fun EmittableWithChildren.toMappedNodes(): List<GlanceMappedNode> {
+        val mappedNodes = mutableListOf<GlanceMappedNode>()
+        children.forEach { child ->
+            if (child is EmittableLazyItemWithChildren) {
+                mappedNodes.addAll(child.toMappedNodes())
+            } else {
+                mappedNodes.add(GlanceMappedNode(child))
+            }
+        }
+        return mappedNodes.toList()
+    }
+
     @RestrictTo(Scope.LIBRARY_GROUP)
     override fun toDebugString(): String {
         // TODO(b/201779038): map to a more readable format.
diff --git a/glance/glance-testing/src/main/java/androidx/glance/testing/unit/TestUtils.kt b/glance/glance-testing/src/main/java/androidx/glance/testing/unit/TestUtils.kt
index 40539aa..17935b0 100644
--- a/glance/glance-testing/src/main/java/androidx/glance/testing/unit/TestUtils.kt
+++ b/glance/glance-testing/src/main/java/androidx/glance/testing/unit/TestUtils.kt
@@ -19,9 +19,12 @@
 import androidx.annotation.RestrictTo
 import androidx.glance.Emittable
 import androidx.glance.testing.GlanceNodeAssertion
+import androidx.glance.testing.GlanceNodeAssertionCollection
 import androidx.glance.testing.GlanceNodeMatcher
 import androidx.glance.testing.TestContext
+import androidx.glance.testing.matcherToSelector
 
+// Equivalent to calling GlanceNodeAssertionsProvider.onNode
 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
 fun getGlanceNodeAssertionFor(
     emittable: Emittable,
@@ -30,7 +33,21 @@
     val testContext = TestContext<MappedNode, GlanceMappedNode>()
     testContext.rootGlanceNode = GlanceMappedNode(emittable)
     return GlanceNodeAssertion(
-        matcher = onNodeMatcher,
-        testContext = testContext
+        testContext = testContext,
+        selector = onNodeMatcher.matcherToSelector()
+    )
+}
+
+// Equivalent to calling GlanceNodeAssertionsProvider.onAllNodes
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+fun getGlanceNodeAssertionCollectionFor(
+    emittable: Emittable,
+    onAllNodesMatcher: GlanceNodeMatcher<MappedNode>
+): GlanceNodeAssertionCollection<MappedNode, GlanceMappedNode> {
+    val testContext = TestContext<MappedNode, GlanceMappedNode>()
+    testContext.rootGlanceNode = GlanceMappedNode(emittable)
+    return GlanceNodeAssertionCollection(
+        testContext = testContext,
+        selector = onAllNodesMatcher.matcherToSelector()
     )
 }
diff --git a/glance/glance-testing/src/main/java/androidx/glance/testing/unit/UnitTestAssertionExtensions.kt b/glance/glance-testing/src/main/java/androidx/glance/testing/unit/UnitTestAssertionExtensions.kt
index 2aa1aca..715910f 100644
--- a/glance/glance-testing/src/main/java/androidx/glance/testing/unit/UnitTestAssertionExtensions.kt
+++ b/glance/glance-testing/src/main/java/androidx/glance/testing/unit/UnitTestAssertionExtensions.kt
@@ -30,6 +30,35 @@
 internal typealias UnitTestAssertion = GlanceNodeAssertion<MappedNode, GlanceMappedNode>
 
 /**
+ * Asserts that text on the given node is a text node and its text contains the provided [text] as
+ * substring.
+ *
+ * @param text value to match.
+ * @param ignoreCase whether to perform case insensitive matching
+ */
+@JvmOverloads
+fun UnitTestAssertion.assertHasText(
+    text: String,
+    ignoreCase: Boolean = false
+): UnitTestAssertion {
+    return assert(hasText(text, ignoreCase))
+}
+
+/**
+ * Asserts that text on the given node is text node and its text is equal to the provided [text].
+ *
+ * @param text value to match.
+ * @param ignoreCase whether to perform case insensitive matching
+ */
+@JvmOverloads
+fun UnitTestAssertion.assertHasTextEqualTo(
+    text: String,
+    ignoreCase: Boolean = false
+): UnitTestAssertion {
+    return assert(hasTextEqualTo(text, ignoreCase))
+}
+
+/**
  * Asserts that a given node is annotated by the given test tag.
  *
  * @param testTag value to match against the free form string specified in the `testTag` semantics
@@ -41,11 +70,10 @@
 }
 
 /**
- * Asserts that a given node matches content description with the provided [value]
+ * Asserts that the content description set on the node contains the provided [value] as substring.
  *
- * @param value value to match as one of the items in the list of content descriptions.
- * @param substring whether to use substring matching.
- * @param ignoreCase whether case should be ignored.
+ * @param value value that should be matched as a substring of the node's content description.
+ * @param ignoreCase whether case should be ignored. Defaults to case sensitive.
  *
  * @see SemanticsProperties.ContentDescription
  *
@@ -54,10 +82,27 @@
 @JvmOverloads
 fun UnitTestAssertion.assertHasContentDescription(
     value: String,
-    substring: Boolean = false,
     ignoreCase: Boolean = false
 ): UnitTestAssertion {
-    return assert(hasContentDescription(value, substring, ignoreCase))
+    return assert(hasContentDescription(value, ignoreCase))
+}
+
+/**
+ * Asserts that the content description set on the node is equal to the provided [value]
+ *
+ * @param value value that should be matched to be equal to the node's content description.
+ * @param ignoreCase whether case should be ignored. Defaults to case sensitive.
+ *
+ * @see SemanticsProperties.ContentDescription
+ *
+ * @throws AssertionError if the matcher does not match or the node can no longer be found.
+ */
+@JvmOverloads
+fun UnitTestAssertion.assertHasContentDescriptionEqualTo(
+    value: String,
+    ignoreCase: Boolean = false
+): UnitTestAssertion {
+    return assert(hasContentDescriptionEqualTo(value, ignoreCase))
 }
 
 /**
@@ -81,9 +126,6 @@
 /**
  * Asserts that a given node has a clickable set with action that starts an activity.
  *
- * This can be passed in "onNode" and "onNodeAll" functions on assertion providers to filter out
- * matching node(s) or in assertions to validate that node(s) satisfy the condition.
- *
  * @param activityClass class of the activity that is expected to have been passed in the
  *                      `actionStartActivity` method call
  * @param parameters the parameters associated with the action that are expected to have been passed
diff --git a/glance/glance-testing/src/main/java/androidx/glance/testing/unit/UnitTestFilters.kt b/glance/glance-testing/src/main/java/androidx/glance/testing/unit/UnitTestFilters.kt
index 1e3d858..6d83d4c 100644
--- a/glance/glance-testing/src/main/java/androidx/glance/testing/unit/UnitTestFilters.kt
+++ b/glance/glance-testing/src/main/java/androidx/glance/testing/unit/UnitTestFilters.kt
@@ -28,6 +28,8 @@
 import androidx.glance.semantics.SemanticsModifier
 import androidx.glance.semantics.SemanticsProperties
 import androidx.glance.semantics.SemanticsPropertyKey
+import androidx.glance.testing.GlanceNode
+import androidx.glance.testing.GlanceNodeAssertionsProvider
 import androidx.glance.testing.GlanceNodeMatcher
 
 // This file contains common filters that can be passed in "onNode", "onAllNodes" or
@@ -37,7 +39,8 @@
 /**
  * Returns a matcher that matches if a node is annotated by the given test tag.
  *
- * <p>This can be passed in "onNode" and "onNodeAll" functions on assertion providers to filter out
+ * This can be passed in [GlanceNodeAssertionsProvider.onNode] and
+ * [GlanceNodeAssertionsProvider.onAllNodes] functions on assertion providers to filter out
  * matching node(s) or in assertions to validate that node(s) satisfy the condition.
  *
  * @param testTag value to match against the free form string specified in the `testTag` semantics
@@ -59,31 +62,67 @@
 }
 
 /**
- * Returns whether the node matches content description with the provided [value]
+ * Returns whether the content description set directly on the node contains the provided [value].
  *
- * @param value value to match as one of the items in the list of content descriptions.
- * @param substring whether to use substring matching.
- * @param ignoreCase whether case should be ignored.
+ * This can be passed in [GlanceNodeAssertionsProvider.onNode] and
+ * [GlanceNodeAssertionsProvider.onAllNodes] functions on assertion providers to filter out
+ * matching node(s) or in assertions to validate that node(s) satisfy the condition.
+ *
+ * @param value value that should be substring of the content description set directly on the node.
+ * @param ignoreCase whether case should be ignored. Default is case sensitive.
  *
  * @see SemanticsProperties.ContentDescription
  */
 @JvmOverloads
 fun hasContentDescription(
     value: String,
-    substring: Boolean = false,
     ignoreCase: Boolean = false
 ): GlanceNodeMatcher<MappedNode> =
     GlanceNodeMatcher(
-        description = if (substring) {
+        description =
             "${SemanticsProperties.ContentDescription.name} contains '$value'" +
-                " (ignoreCase: '$ignoreCase')"
-        } else {
-            "${SemanticsProperties.ContentDescription.name} = '$value' (ignoreCase: '$ignoreCase')"
-        }
+                " (ignoreCase: '$ignoreCase') as substring"
     ) { node ->
         node.value.emittable.modifier.any {
             it is SemanticsModifier &&
-                hasContentDescription(it, value, substring, ignoreCase)
+                hasContentDescription(
+                    semanticsModifier = it,
+                    value = value,
+                    substring = true,
+                    ignoreCase = ignoreCase)
+        }
+    }
+
+/**
+ * Returns whether the content description set directly on the node is equal to the provided
+ * [value].
+ *
+ * This can be passed in [GlanceNodeAssertionsProvider.onNode] and
+ * [GlanceNodeAssertionsProvider.onAllNodes] functions on assertion providers to filter out
+ * matching node(s) or in assertions to validate that node(s) satisfy the condition.
+ *
+ * @param value value that should match exactly with content description set directly on the node.
+ * @param ignoreCase whether case should be ignored. Default is case sensitive.
+ *
+ * @see SemanticsProperties.ContentDescription
+ */
+@JvmOverloads
+fun hasContentDescriptionEqualTo(
+    value: String,
+    ignoreCase: Boolean = false
+): GlanceNodeMatcher<MappedNode> =
+    GlanceNodeMatcher(
+        description =
+        "${SemanticsProperties.ContentDescription.name} == '$value' (ignoreCase: '$ignoreCase')"
+    ) { node ->
+        node.value.emittable.modifier.any {
+            it is SemanticsModifier &&
+                hasContentDescription(
+                    semanticsModifier = it,
+                    value = value,
+                    substring = false,
+                    ignoreCase = ignoreCase
+                )
         }
     }
 
@@ -105,43 +144,54 @@
 }
 
 /**
- * Returns a matcher that matches if text on node matches the provided text.
+ * Returns a matcher that matches if text on node contains the provided text as its substring.
  *
- * This can be passed in "onNode" and "onNodeAll" functions on assertion providers to filter out
+ * This can be passed in [GlanceNodeAssertionsProvider.onNode] and
+ * [GlanceNodeAssertionsProvider.onAllNodes] functions on assertion providers to filter out
  * matching node(s) or in assertions to validate that node(s) satisfy the condition.
  *
- * @param text value to match.
- * @param substring whether to perform substring matching
- * @param ignoreCase whether to perform case insensitive matching
+ * @param text value that should be matched as a substring of the node's text.
+ * @param ignoreCase whether to perform case insensitive matching. Defaults to case sensitive
+ *                   matching.
  */
 @JvmOverloads
 fun hasText(
     text: String,
-    substring: Boolean = false,
     ignoreCase: Boolean = false
 ): GlanceNodeMatcher<MappedNode> = GlanceNodeMatcher(
-    if (substring) {
-        "contains '$text' (ignoreCase: $ignoreCase) as substring"
-    } else {
-        "has text = '$text' (ignoreCase: '$ignoreCase')"
-    }
+    description = "contains text '$text' (ignoreCase: '$ignoreCase') as substring"
 ) { node ->
     val emittable = node.value.emittable
-    if (emittable is EmittableWithText) {
-        if (substring) {
-            emittable.text.contains(text, ignoreCase)
-        } else {
-            emittable.text.equals(text, ignoreCase)
-        }
-    } else {
-        false
-    }
+    emittable is EmittableWithText && emittable.text.contains(text, ignoreCase)
+}
+
+/**
+ * Returns a matcher that matches if node is a text node and its text is equal to the provided text.
+ *
+ * This can be passed in [GlanceNodeAssertionsProvider.onNode] and
+ * [GlanceNodeAssertionsProvider.onAllNodes] functions on assertion providers to filter out
+ * matching node(s) or in assertions to validate that node(s) satisfy the condition.
+ *
+ * @param text value that should exactly match the node's text.
+ * @param ignoreCase whether to perform case insensitive matching. Defaults to case sensitive
+ *                   matching.
+ */
+@JvmOverloads
+fun hasTextEqualTo(
+    text: String,
+    ignoreCase: Boolean = false
+): GlanceNodeMatcher<MappedNode> = GlanceNodeMatcher(
+    description = "text == '$text' (ignoreCase: '$ignoreCase')"
+) { node ->
+    val emittable = node.value.emittable
+    emittable is EmittableWithText && emittable.text.equals(text, ignoreCase)
 }
 
 /**
  * Returns a matcher that matches if the given node has clickable modifier set.
  *
- * This can be passed in "onNode" and "onNodeAll" functions on assertion providers to filter out
+ * This can be passed in [GlanceNodeAssertionsProvider.onNode] and
+ * [GlanceNodeAssertionsProvider.onAllNodes] functions on assertion providers to filter out
  * matching node(s) or in assertions to validate that node(s) satisfy the condition.
  */
 fun hasClickAction(): GlanceNodeMatcher<MappedNode> = GlanceNodeMatcher(
@@ -156,7 +206,8 @@
  * Returns a matcher that matches if the given node doesn't have a clickable modifier or `onClick`
  * set.
  *
- * This can be passed in "onNode" and "onNodeAll" functions on assertion providers to filter out
+ * This can be passed in [GlanceNodeAssertionsProvider.onNode] and
+ * [GlanceNodeAssertionsProvider.onAllNodes] functions on assertion providers to filter out
  * matching node(s) or in assertions to validate that node(s) satisfy the condition.
  */
 fun hasNoClickAction(): GlanceNodeMatcher<MappedNode> = GlanceNodeMatcher(
@@ -171,7 +222,8 @@
  * Returns a matcher that matches if a given node has a clickable set with action that starts an
  * activity.
  *
- * This can be passed in "onNode" and "onNodeAll" functions on assertion providers to filter out
+ * This can be passed in [GlanceNodeAssertionsProvider.onNode] and
+ * [GlanceNodeAssertionsProvider.onAllNodes] functions on assertion providers to filter out
  * matching node(s) or in assertions to validate that node(s) satisfy the condition.
  *
  * @param activityClass class of the activity that is expected to have been passed in the
@@ -213,10 +265,39 @@
 }
 
 /**
+ * Returns a matcher that matches if a given node has a descendant node somewhere in its
+ * sub-hierarchy that the matches the provided matcher.
+ *
+ * This can be passed in [GlanceNodeAssertionsProvider.onNode] and
+ * [GlanceNodeAssertionsProvider.onAllNodes] functions on assertion providers to filter out
+ * matching node(s) or in assertions to validate that node(s) satisfy the condition.
+ *
+ * @param matcher a matcher that needs to be satisfied for the descendant node to be matched
+ */
+fun hasAnyDescendant(matcher: GlanceNodeMatcher<MappedNode>): GlanceNodeMatcher<MappedNode> {
+
+    fun checkIfSubtreeMatchesRecursive(
+        matcher: GlanceNodeMatcher<MappedNode>,
+        node: GlanceNode<MappedNode>
+    ): Boolean {
+        if (matcher.matchesAny(node.children())) {
+            return true
+        }
+
+        return node.children().any { checkIfSubtreeMatchesRecursive(matcher, it) }
+    }
+
+    return GlanceNodeMatcher("hasAnyDescendantThat(${matcher.description})") {
+        checkIfSubtreeMatchesRecursive(matcher, it)
+    }
+}
+
+/**
  * Returns a matcher that matches if a given node has a clickable set with action that starts an
  * activity.
  *
- * This can be passed in "onNode" and "onNodeAll" functions on assertion providers to filter out
+ * This can be passed in [GlanceNodeAssertionsProvider.onNode] and
+ * [GlanceNodeAssertionsProvider.onAllNodes] functions on assertion providers to filter out
  * matching node(s) or in assertions to validate that node(s) satisfy the condition.
  *
  * @param componentName component of the activity that is expected to have been passed in the
diff --git a/glance/glance-testing/src/test/kotlin/androidx/glance/testing/AssertionErrorMessagesTest.kt b/glance/glance-testing/src/test/kotlin/androidx/glance/testing/AssertionErrorMessagesTest.kt
index e4bebe09..e82031c 100644
--- a/glance/glance-testing/src/test/kotlin/androidx/glance/testing/AssertionErrorMessagesTest.kt
+++ b/glance/glance-testing/src/test/kotlin/androidx/glance/testing/AssertionErrorMessagesTest.kt
@@ -24,11 +24,13 @@
 class AssertionErrorMessagesTest {
     @Test
     fun countMismatch_expectedNone() {
-        val resultMessage = buildErrorMessageForCountMismatch(
-            errorMessage = "Failed assert",
-            matcherDescription = "testTag = 'my-node'",
-            expectedCount = 0,
-            actualCount = 1
+        val resultMessage = buildErrorMessageWithReason(
+            errorMessageOnFail = "Failed assert",
+            reason = buildErrorReasonForCountMismatch(
+                matcherDescription = "testTag = 'my-node'",
+                expectedCount = 0,
+                actualCount = 1
+            )
         )
 
         assertThat(resultMessage).isEqualTo(
@@ -40,11 +42,13 @@
 
     @Test
     fun countMismatch_expectedButFoundNone() {
-        val resultMessage = buildErrorMessageForCountMismatch(
-            errorMessage = "Failed assert",
-            matcherDescription = "testTag = 'my-node'",
-            expectedCount = 2,
-            actualCount = 0
+        val resultMessage = buildErrorMessageWithReason(
+            errorMessageOnFail = "Failed assert",
+            reason = buildErrorReasonForCountMismatch(
+                matcherDescription = "testTag = 'my-node'",
+                expectedCount = 2,
+                actualCount = 0
+            )
         )
 
         assertThat(resultMessage).isEqualTo(
@@ -55,14 +59,14 @@
     }
 
     @Test
-    fun generalErrorMessage() {
+    fun generalErrorMessage_singleNode() {
         val node = GlanceMappedNode(
             EmittableText().also { it.text = "test text" }
         )
 
         val resultMessage = buildGeneralErrorMessage(
             errorMessage = "Failed to match the condition: (testTag = 'my-node')",
-            glanceNode = node
+            node = node
         )
 
         assertThat(resultMessage).isEqualTo(
@@ -70,4 +74,26 @@
                 "\nGlance Node: ${node.toDebugString()}"
         )
     }
+
+    @Test
+    fun generalErrorMessage_multipleNodes() {
+        val node1 = GlanceMappedNode(
+            EmittableText().also { it.text = "text1" }
+        )
+        val node2 = GlanceMappedNode(
+            EmittableText().also { it.text = "text2" }
+        )
+
+        val resultMessage = buildGeneralErrorMessage(
+            errorMessage = "Failed to match the condition: (testTag = 'my-node')",
+            nodes = listOf(node1, node2)
+        )
+
+        assertThat(resultMessage).isEqualTo(
+            "Failed to match the condition: (testTag = 'my-node')" +
+                "\nFound 2 node(s) that don't match." +
+                "\nNon-matching Glance Node #1: ${node1.toDebugString()}" +
+                "\nNon-matching Glance Node #2: ${node2.toDebugString()}"
+        )
+    }
 }
diff --git a/glance/glance-testing/src/test/kotlin/androidx/glance/testing/GlanceNodeAssertionCollectionTest.kt b/glance/glance-testing/src/test/kotlin/androidx/glance/testing/GlanceNodeAssertionCollectionTest.kt
new file mode 100644
index 0000000..7d1202a
--- /dev/null
+++ b/glance/glance-testing/src/test/kotlin/androidx/glance/testing/GlanceNodeAssertionCollectionTest.kt
@@ -0,0 +1,600 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.glance.testing
+
+import androidx.glance.GlanceModifier
+import androidx.glance.action.ActionModifier
+import androidx.glance.action.LambdaAction
+import androidx.glance.layout.EmittableColumn
+import androidx.glance.layout.EmittableSpacer
+import androidx.glance.semantics.semantics
+import androidx.glance.semantics.testTag
+import androidx.glance.testing.unit.assertHasText
+import androidx.glance.testing.unit.getGlanceNodeAssertionCollectionFor
+import androidx.glance.testing.unit.getGlanceNodeAssertionFor
+import androidx.glance.testing.unit.hasClickAction
+import androidx.glance.testing.unit.hasTestTag
+import androidx.glance.testing.unit.hasText
+import androidx.glance.testing.unit.hasTextEqualTo
+import androidx.glance.text.EmittableText
+import com.google.common.truth.Truth.assertThat
+import org.junit.Assert.assertThrows
+import org.junit.Test
+
+class GlanceNodeAssertionCollectionTest {
+    @Test
+    fun assertAll_noNodesToAssertOn() {
+        // This is the object that in real usage a onAllNodes(matcher) would return.
+        val assertion = getGlanceNodeAssertionCollectionFor(
+            onAllNodesMatcher = hasClickAction(),
+            emittable = EmittableColumn().apply {
+                children.add(EmittableText().apply { text = "some text" })
+                children.add(EmittableSpacer())
+                children.add(EmittableText().apply { text = "another text" })
+            }
+        )
+
+        assertion.assertAll(hasText("substring"))
+        // no error even if no nodes with click action were available to perform assertAll; on the
+        // other hand calling assertCountEquals(x) before assertAll would have thrown an error
+    }
+
+    @Test
+    fun assertAll_allMatchingNodes() {
+        val assertion = getGlanceNodeAssertionCollectionFor(
+            onAllNodesMatcher = hasClickAction(),
+            emittable = EmittableColumn().apply {
+                children.add(EmittableText().apply {
+                    text = "some substring text"
+                    modifier = ActionModifier(LambdaAction("1") {})
+                })
+                children.add(EmittableSpacer())
+                children.add(EmittableText().apply {
+                    text = "another substring text"
+                    modifier = ActionModifier(LambdaAction("2") {})
+                })
+            }
+        )
+
+        assertion.assertAll(hasText("substring"))
+        // no error
+    }
+
+    @Test
+    fun assertAll_noneMatch_throwsError() {
+        val assertion = getGlanceNodeAssertionCollectionFor(
+            onAllNodesMatcher = hasClickAction(),
+            emittable = EmittableColumn().apply {
+                children.add(EmittableText().apply {
+                    text = "some text"
+                    modifier = ActionModifier(LambdaAction("1") {})
+                })
+                children.add(EmittableSpacer())
+                children.add(EmittableText().apply {
+                    text = "another text"
+                    modifier = ActionModifier(LambdaAction("2") {})
+                })
+            }
+        )
+
+        val assertionError = assertThrows(AssertionError::class.java) {
+            assertion.assertAll(hasText("substring"))
+        }
+
+        assertThat(assertionError).hasMessageThat().contains(
+            "Failed to assertAll(contains text 'substring' (ignoreCase: 'false') as substring)" +
+                "\nFound 2 node(s) that don't match."
+        )
+    }
+
+    @Test
+    fun assertAll_someNotMatch_throwsError() {
+        val assertion = getGlanceNodeAssertionCollectionFor(
+            onAllNodesMatcher = hasClickAction(),
+            emittable = EmittableColumn().apply {
+                children.add(EmittableText().apply {
+                    text = "some substring text"
+                    modifier = ActionModifier(LambdaAction("1") {})
+                })
+                children.add(EmittableSpacer())
+                children.add(EmittableText().apply {
+                    text = "another text"
+                    modifier = ActionModifier(LambdaAction("2") {})
+                })
+            }
+        )
+
+        val assertionError = assertThrows(AssertionError::class.java) {
+            assertion.assertAll(hasText("substring"))
+        }
+
+        assertThat(assertionError).hasMessageThat().contains(
+            "Failed to assertAll(contains text 'substring' (ignoreCase: 'false') as substring)" +
+                "\nFound 1 node(s) that don't match."
+        )
+    }
+
+    @Test
+    fun assertAny_noNodesToAssertOn_assertionError() {
+        val assertion = getGlanceNodeAssertionCollectionFor(
+            onAllNodesMatcher = hasClickAction(),
+            emittable = EmittableColumn().apply {
+                children.add(EmittableText().apply { text = "some text" })
+                children.add(EmittableSpacer())
+                children.add(EmittableText().apply { text = "another text" })
+            }
+        )
+
+        val assertionError = assertThrows(AssertionError::class.java) {
+            assertion.assertAny(hasText("substring"))
+        }
+
+        assertThat(assertionError).hasMessageThat().contains(
+            "Failed to assertAny(contains text 'substring' (ignoreCase: 'false') as substring)" +
+                "\nReason: Expected to receive at least 1 node " +
+                "but 0 nodes were found for condition: (has click action)"
+        )
+    }
+
+    @Test
+    fun assertAny_noneMatch_assertionError() {
+        val assertion = getGlanceNodeAssertionCollectionFor(
+            onAllNodesMatcher = hasClickAction(),
+            emittable = EmittableColumn().apply {
+                children.add(EmittableText().apply {
+                    text = "some text"
+                    modifier = ActionModifier(LambdaAction("1") {})
+                })
+                children.add(EmittableSpacer())
+                children.add(EmittableText().apply {
+                    text = "another text"
+                    modifier = ActionModifier(LambdaAction("2") {})
+                })
+            }
+        )
+
+        val assertionError = assertThrows(AssertionError::class.java) {
+            assertion.assertAny(hasText("expected-substring"))
+        }
+
+        assertThat(assertionError).hasMessageThat().contains(
+            "Failed to assertAny(contains text 'expected-substring' " +
+                "(ignoreCase: 'false') as substring)" +
+                "\nFound 2 node(s) that don't match."
+        )
+    }
+
+    @Test
+    fun assertAny_oneMatch() {
+        val assertion = getGlanceNodeAssertionCollectionFor(
+            onAllNodesMatcher = hasClickAction(),
+            emittable = EmittableColumn().apply {
+                children.add(EmittableText().apply {
+                    text = "some text"
+                    modifier = ActionModifier(LambdaAction("1") {})
+                })
+                children.add(EmittableSpacer())
+                children.add(EmittableText().apply {
+                    text = "another substring text"
+                    modifier = ActionModifier(LambdaAction("2") {})
+                })
+            }
+        )
+
+        assertion.assertAny(hasText("substring"))
+    }
+
+    @Test
+    fun assertAny_multipleMatch() {
+        val assertion = getGlanceNodeAssertionCollectionFor(
+            onAllNodesMatcher = hasClickAction(),
+            emittable = EmittableColumn().apply {
+                children.add(EmittableText().apply {
+                    text = "some text"
+                    modifier = ActionModifier(LambdaAction("1") {})
+                })
+                children.add(EmittableSpacer())
+                children.add(EmittableText().apply {
+                    text = "another substring text"
+                    modifier = ActionModifier(LambdaAction("2") {})
+                })
+                children.add(EmittableSpacer())
+                children.add(EmittableText().apply {
+                    text = "yet another substring text"
+                    modifier = ActionModifier(LambdaAction("3") {})
+                })
+            }
+        )
+
+        assertion.assertAny(hasText("substring"))
+    }
+
+    @Test
+    fun assertAllAfterFilter_matchingNodes() {
+        val assertion = getGlanceNodeAssertionCollectionFor(
+            onAllNodesMatcher = hasClickAction(),
+            emittable = EmittableColumn().apply {
+                children.add(EmittableText().apply {
+                    text = "some substring text"
+                    modifier = ActionModifier(LambdaAction("1") {})
+                })
+                children.add(EmittableSpacer())
+                children.add(EmittableText().apply {
+                    text = "another text"
+                    modifier = ActionModifier(LambdaAction("2") {})
+                })
+                children.add(EmittableSpacer())
+                children.add(EmittableText().apply {
+                    text = "yet another substring text"
+                    modifier = ActionModifier(LambdaAction("3") {})
+                })
+            }
+        )
+
+        assertion
+            .filter(hasText("substring"))
+            .assertAll(hasText("text"))
+    }
+
+    @Test
+    fun assertAllAfterFilter_noFilteredNodes_noError() {
+        val assertion = getGlanceNodeAssertionCollectionFor(
+            onAllNodesMatcher = hasClickAction(),
+            emittable = EmittableColumn().apply {
+                children.add(EmittableText().apply {
+                    text = "some substring text"
+                    modifier = ActionModifier(LambdaAction("1") {})
+                })
+                children.add(EmittableSpacer())
+                children.add(EmittableText().apply {
+                    text = "another text"
+                    modifier = ActionModifier(LambdaAction("2") {})
+                })
+                children.add(EmittableSpacer())
+                children.add(EmittableText().apply {
+                    text = "yet another substring text"
+                    modifier = ActionModifier(LambdaAction("3") {})
+                })
+            }
+        )
+
+        assertion
+            .filter(hasText("word"))
+            .assertAll(hasText("text"))
+    }
+
+    @Test
+    fun assertAnyAfterFilter_matchingNodes() {
+        val assertion = getGlanceNodeAssertionCollectionFor(
+            onAllNodesMatcher = hasClickAction(),
+            emittable = EmittableColumn().apply {
+                children.add(EmittableText().apply {
+                    text = "some substring"
+                    modifier = ActionModifier(LambdaAction("1") {})
+                })
+                children.add(EmittableSpacer())
+                children.add(EmittableText().apply {
+                    text = "another text"
+                    modifier = ActionModifier(LambdaAction("2") {})
+                })
+                children.add(EmittableSpacer())
+                children.add(EmittableText().apply {
+                    text = "yet another substring text"
+                    modifier = ActionModifier(LambdaAction("3") {})
+                })
+            }
+        )
+
+        assertion
+            .filter(hasText("substring"))
+            .assertAny(hasText("text"))
+    }
+
+    @Test
+    fun assertAnyAfterFilter_noFilteredNodes_assertionError() {
+        val assertion = getGlanceNodeAssertionCollectionFor(
+            onAllNodesMatcher = hasClickAction(),
+            emittable = EmittableColumn().apply {
+                children.add(EmittableText().apply {
+                    text = "some substring text"
+                    modifier = ActionModifier(LambdaAction("1") {})
+                })
+                children.add(EmittableSpacer())
+                children.add(EmittableText().apply {
+                    text = "another text"
+                    modifier = ActionModifier(LambdaAction("2") {})
+                })
+                children.add(EmittableSpacer())
+                children.add(EmittableText().apply {
+                    text = "yet another substring text"
+                    modifier = ActionModifier(LambdaAction("3") {})
+                })
+            }
+        )
+
+        val assertionError = assertThrows(AssertionError::class.java) {
+            assertion
+                .filter(hasText("word"))
+                .assertAny(hasText("text"))
+        }
+
+        assertThat(assertionError).hasMessageThat().contains(
+            "Failed to assertAny(contains text 'text' (ignoreCase: 'false') as substring)" +
+                "\nReason: Expected to receive at least 1 node but 0 nodes were found for " +
+                "condition: " +
+                "((has click action).filter(contains text 'word' (ignoreCase: 'false') " +
+                "as substring))"
+        )
+    }
+
+    @Test
+    fun assertCountEqualsAfterFilter_matchingNodes() {
+        val assertion = getGlanceNodeAssertionCollectionFor(
+            onAllNodesMatcher = hasClickAction(),
+            emittable = EmittableColumn().apply {
+                children.add(EmittableText().apply {
+                    text = "some substring text"
+                    modifier = ActionModifier(LambdaAction("1") {})
+                })
+                children.add(EmittableSpacer())
+                children.add(EmittableText().apply {
+                    text = "another text"
+                    modifier = ActionModifier(LambdaAction("2") {})
+                })
+                children.add(EmittableSpacer())
+                children.add(EmittableText().apply {
+                    text = "yet another substring text"
+                    modifier = ActionModifier(LambdaAction("3") {})
+                })
+            }
+        )
+
+        assertion
+            .filter(hasText("text"))
+            .assertCountEquals(3)
+    }
+
+    @Test
+    fun assertCountEqualsAfterFilter_noFilteredNodes_assertionError() {
+        val assertion = getGlanceNodeAssertionCollectionFor(
+            onAllNodesMatcher = hasClickAction(),
+            emittable = EmittableColumn().apply {
+                children.add(EmittableText().apply {
+                    text = "some substring text"
+                    modifier = ActionModifier(LambdaAction("1") {})
+                })
+                children.add(EmittableSpacer())
+                children.add(EmittableText().apply {
+                    text = "another text"
+                    modifier = ActionModifier(LambdaAction("2") {})
+                })
+                children.add(EmittableSpacer())
+                children.add(EmittableText().apply {
+                    text = "yet another substring text"
+                    modifier = ActionModifier(LambdaAction("3") {})
+                })
+            }
+        )
+
+        val assertionError = assertThrows(AssertionError::class.java) {
+            assertion
+                .filter(hasText("word"))
+                .assertCountEquals(1)
+        }
+
+        assertThat(assertionError).hasMessageThat().contains(
+            "Failed to assert count of nodes" +
+                "\nReason: Expected '1' node(s) matching condition: " +
+                "(has click action).filter(contains text 'word' " +
+                "(ignoreCase: 'false') as substring), " +
+                "but found '0'"
+        )
+    }
+
+    @Test
+    fun multipleFilters() {
+        val assertion = getGlanceNodeAssertionCollectionFor(
+            onAllNodesMatcher = hasClickAction(),
+            emittable = EmittableColumn().apply {
+                children.add(EmittableText().apply {
+                    text = "some text"
+                    modifier = ActionModifier(LambdaAction("1") {})
+                })
+                children.add(EmittableSpacer())
+                children.add(EmittableText().apply {
+                    text = "another substring"
+                    modifier = ActionModifier(LambdaAction("2") {})
+                })
+                children.add(EmittableSpacer())
+                children.add(EmittableText().apply {
+                    text = "yet another substring text"
+                    modifier = ActionModifier(LambdaAction("3") {})
+                })
+            }
+        )
+
+        assertion
+            .filter(hasText("text"))
+            .assertCountEquals(2)
+            .filter(hasText("substring"))
+            .assertCountEquals(1)
+    }
+
+    @Test
+    fun getIndexOnFilter() {
+        val assertion = getGlanceNodeAssertionCollectionFor(
+            onAllNodesMatcher = hasClickAction(),
+            emittable = EmittableColumn().apply {
+                children.add(EmittableText().apply {
+                    text = "some text"
+                    modifier = ActionModifier(LambdaAction("1") {})
+                })
+                children.add(EmittableSpacer())
+                children.add(EmittableText().apply {
+                    text = "another substring"
+                    modifier = ActionModifier(LambdaAction("2") {})
+                })
+                children.add(EmittableSpacer())
+                children.add(EmittableText().apply {
+                    text = "yet another substring text"
+                    modifier = ActionModifier(LambdaAction("3") {})
+                })
+            }
+        )
+
+        assertion
+            .filter(hasText("text"))
+            .assertCountEquals(2)
+            .get(index = 1)
+            .assert(hasTextEqualTo("yet another substring text"))
+    }
+
+    @Test
+    fun collectionGetIndex_notEnoughNodes_assertionError() {
+        val assertion = getGlanceNodeAssertionCollectionFor(
+            onAllNodesMatcher = hasClickAction(),
+            emittable = EmittableColumn().apply {
+                children.add(EmittableText().apply {
+                    text = "some text"
+                    modifier = ActionModifier(LambdaAction("1") {})
+                })
+                children.add(EmittableSpacer())
+                children.add(EmittableText().apply {
+                    text = "another substring"
+                    modifier = ActionModifier(LambdaAction("2") {})
+                })
+                children.add(EmittableSpacer())
+                children.add(EmittableText().apply {
+                    text = "yet another substring text"
+                    modifier = ActionModifier(LambdaAction("3") {})
+                })
+            }
+        )
+
+        val assertionError = assertThrows(AssertionError::class.java) {
+            assertion
+                .filter(hasText("text"))
+                .assertCountEquals(2)
+                .get(index = 3) // index out of bounds.
+                .assert(hasTextEqualTo("yet another substring text"))
+        }
+
+        assertThat(assertionError).hasMessageThat().contains(
+            "Failed to assert condition: " +
+                "(text == 'yet another substring text' (ignoreCase: 'false'))" +
+                "\nReason: Not enough node(s) matching condition: " +
+                "((has click action).filter(contains text 'text' " +
+                "(ignoreCase: 'false') as substring)) " +
+                "to get node at index '4'. Found '2' matching node(s)"
+        )
+    }
+
+    @Test
+    fun assertOnChildren_multipleChildren() {
+        val assertion = getGlanceNodeAssertionFor(
+            onNodeMatcher = hasTestTag("test-list"),
+            emittable = EmittableColumn().apply {
+                modifier = GlanceModifier.semantics { testTag = "test-list" }
+                children.add(EmittableText().apply {
+                    text = "some text"
+                    modifier = ActionModifier(LambdaAction("1") {})
+                })
+                children.add(EmittableText().apply {
+                    text = "another substring"
+                    modifier = ActionModifier(LambdaAction("2") {})
+                })
+            }
+        )
+
+        assertion
+            .onChildren()
+            .assertCountEquals(2)
+            .assertAll(hasClickAction())
+    }
+
+    @Test
+    fun assertOnChildren_noChildren() {
+        val assertion = getGlanceNodeAssertionFor(
+            onNodeMatcher = hasTestTag("test-list"),
+            emittable = EmittableColumn().apply {
+                modifier = GlanceModifier.semantics { testTag = "test-list" }
+            }
+        )
+
+        assertion.onChildren().assertCountEquals(0)
+    }
+
+    @Test
+    fun assertAnyOnChildren_noChildren_assertionError() {
+        val assertion = getGlanceNodeAssertionFor(
+            onNodeMatcher = hasTestTag("test-list"),
+            emittable = EmittableColumn().apply {
+                modifier = GlanceModifier.semantics { testTag = "test-list" }
+            }
+        )
+
+        val assertionError = assertThrows(AssertionError::class.java) {
+            assertion.onChildren().assertCountEquals(1)
+        }
+
+        assertThat(assertionError).hasMessageThat().contains(
+            "Failed to assert count of nodes" +
+                "\nReason: Expected '1' node(s) matching condition: " +
+                "(TestTag = 'test-list').children(), but found '0'"
+        )
+    }
+
+    @Test
+    fun filterOnChildren() {
+        val assertion = getGlanceNodeAssertionFor(
+            onNodeMatcher = hasTestTag("test-list"),
+            emittable = EmittableColumn().apply {
+                modifier = GlanceModifier.semantics { testTag = "test-list" }
+                children.add(EmittableText().apply {
+                    text = "some text"
+                    modifier = ActionModifier(LambdaAction("1") {})
+                })
+                children.add(EmittableText().apply {
+                    text = "another substring"
+                    modifier = ActionModifier(LambdaAction("2") {})
+                })
+            }
+        )
+
+        assertion
+            .onChildren()
+            .filter(hasText("substring"))
+            .assertCountEquals(1)
+    }
+
+    @Test
+    fun getIndexOnChildren() {
+        val assertion = getGlanceNodeAssertionFor(
+            onNodeMatcher = hasTestTag("test-list"),
+            emittable = EmittableColumn().apply {
+                modifier = GlanceModifier.semantics { testTag = "test-list" }
+                children.add(EmittableText().apply { text = "text-1" })
+                children.add(EmittableText().apply { text = "text-2" })
+            }
+        )
+
+        assertion
+            .onChildren()
+            .get(index = 0)
+            .assertHasText("text-1")
+    }
+}
diff --git a/glance/glance-testing/src/test/kotlin/androidx/glance/testing/GlanceNodeAssertionTest.kt b/glance/glance-testing/src/test/kotlin/androidx/glance/testing/GlanceNodeAssertionTest.kt
index c27c769..6718627 100644
--- a/glance/glance-testing/src/test/kotlin/androidx/glance/testing/GlanceNodeAssertionTest.kt
+++ b/glance/glance-testing/src/test/kotlin/androidx/glance/testing/GlanceNodeAssertionTest.kt
@@ -21,8 +21,7 @@
 import androidx.glance.layout.EmittableSpacer
 import androidx.glance.semantics.semantics
 import androidx.glance.semantics.testTag
-import androidx.glance.testing.unit.GlanceMappedNode
-import androidx.glance.testing.unit.MappedNode
+import androidx.glance.testing.unit.getGlanceNodeAssertionFor
 import androidx.glance.testing.unit.hasTestTag
 import androidx.glance.testing.unit.hasText
 import androidx.glance.text.EmittableText
@@ -35,22 +34,17 @@
 class GlanceNodeAssertionTest {
     @Test
     fun assertExists_success() {
-        val testContext = TestContext<MappedNode, GlanceMappedNode>()
-        // set root node of test tree to be traversed
-        testContext.rootGlanceNode = GlanceMappedNode(
-            EmittableColumn().apply {
+        // This is the object that in real usage a rule.onNode(matcher) would return.
+        val assertion = getGlanceNodeAssertionFor(
+            emittable = EmittableColumn().apply {
                 children.add(EmittableText().apply { text = "some text" })
                 children.add(EmittableSpacer())
                 children.add(EmittableText().apply {
                     text = "another text"
                     modifier = GlanceModifier.semantics { testTag = "existing-test-tag" }
                 })
-            }
-        )
-        // This is the object that in real usage a rule.onNode(matcher) would return.
-        val assertion = GlanceNodeAssertion(
-            matcher = hasTestTag(testTag = "existing-test-tag"),
-            testContext = testContext
+            },
+            onNodeMatcher = hasTestTag(testTag = "existing-test-tag"),
         )
 
         assertion.assertExists()
@@ -59,23 +53,16 @@
 
     @Test
     fun assertExists_error() {
-        val testContext = TestContext<MappedNode, GlanceMappedNode>()
-        // set root node of test tree to be traversed
-        testContext.rootGlanceNode =
-            GlanceMappedNode(
-                EmittableColumn().apply {
-                    children.add(EmittableText().apply { text = "some text" })
-                    children.add(EmittableSpacer())
-                    children.add(EmittableText().apply {
-                        text = "another text"
-                        modifier = GlanceModifier.semantics { testTag = "existing-test-tag" }
-                    })
-                }
-            )
-        // This is the object that in real usage a rule.onNode(matcher) would return.
-        val assertion = GlanceNodeAssertion(
-            matcher = hasTestTag(testTag = "non-existing-test-tag"),
-            testContext = testContext
+        val assertion = getGlanceNodeAssertionFor(
+            emittable = EmittableColumn().apply {
+                children.add(EmittableText().apply { text = "some text" })
+                children.add(EmittableSpacer())
+                children.add(EmittableText().apply {
+                    text = "another text"
+                    modifier = GlanceModifier.semantics { testTag = "existing-test-tag" }
+                })
+            },
+            onNodeMatcher = hasTestTag(testTag = "non-existing-test-tag")
         )
 
         val assertionError = assertThrows(AssertionError::class.java) {
@@ -91,24 +78,16 @@
 
     @Test
     fun assertDoesNotExist_success() {
-        val testContext = TestContext<MappedNode, GlanceMappedNode>()
-        // set root node of test tree to be traversed
-        testContext.rootGlanceNode =
-            GlanceMappedNode(
-                EmittableColumn().apply {
-                    children.add(EmittableText().apply { text = "some text" })
-                    children.add(EmittableSpacer())
-                    children.add(EmittableText().apply {
-                        text = "another text"
-                        modifier = GlanceModifier.semantics { testTag = "existing-test-tag" }
-                    })
-                }
-            )
-
-        // This is the object that in real usage a rule.onNode(matcher) would return.
-        val assertion = GlanceNodeAssertion(
-            matcher = hasTestTag(testTag = "non-existing-test-tag"),
-            testContext = testContext
+        val assertion = getGlanceNodeAssertionFor(
+            emittable = EmittableColumn().apply {
+                children.add(EmittableText().apply { text = "some text" })
+                children.add(EmittableSpacer())
+                children.add(EmittableText().apply {
+                    text = "another text"
+                    modifier = GlanceModifier.semantics { testTag = "existing-test-tag" }
+                })
+            },
+            onNodeMatcher = hasTestTag(testTag = "non-existing-test-tag")
         )
 
         assertion.assertDoesNotExist()
@@ -117,23 +96,16 @@
 
     @Test
     fun assertDoesNotExist_error() {
-        val testContext = TestContext<MappedNode, GlanceMappedNode>()
-        // set root node of test tree to be traversed
-        testContext.rootGlanceNode =
-            GlanceMappedNode(
-                EmittableColumn().apply {
-                    children.add(EmittableText().apply { text = "some text" })
-                    children.add(EmittableSpacer())
-                    children.add(EmittableText().apply {
-                        text = "another text"
-                        modifier = GlanceModifier.semantics { testTag = "existing-test-tag" }
-                    })
-                }
-            )
-        // This is the object that in real usage a rule.onNode(matcher) would return.
-        val assertion = GlanceNodeAssertion(
-            matcher = hasTestTag(testTag = "existing-test-tag"),
-            testContext = testContext
+        val assertion = getGlanceNodeAssertionFor(
+            emittable = EmittableColumn().apply {
+                children.add(EmittableText().apply { text = "some text" })
+                children.add(EmittableSpacer())
+                children.add(EmittableText().apply {
+                    text = "another text"
+                    modifier = GlanceModifier.semantics { testTag = "existing-test-tag" }
+                })
+            },
+            onNodeMatcher = hasTestTag(testTag = "existing-test-tag")
         )
 
         val assertionError = assertThrows(AssertionError::class.java) {
@@ -149,23 +121,16 @@
 
     @Test
     fun assert_withMatcher_success() {
-        val testContext = TestContext<MappedNode, GlanceMappedNode>()
-        // set root node of test tree to be traversed
-        testContext.rootGlanceNode =
-            GlanceMappedNode(
-                EmittableColumn().apply {
-                    children.add(EmittableText().apply { text = "some text" })
-                    children.add(EmittableSpacer())
-                    children.add(EmittableText().apply {
-                        text = "another text"
-                        modifier = GlanceModifier.semantics { testTag = "existing-test-tag" }
-                    })
-                }
-            )
-        // This is the object that in real usage a rule.onNode(matcher) would return.
-        val assertion = GlanceNodeAssertion(
-            matcher = hasTestTag(testTag = "existing-test-tag"),
-            testContext = testContext
+        val assertion = getGlanceNodeAssertionFor(
+            emittable = EmittableColumn().apply {
+                children.add(EmittableText().apply { text = "some text" })
+                children.add(EmittableSpacer())
+                children.add(EmittableText().apply {
+                    text = "another text"
+                    modifier = GlanceModifier.semantics { testTag = "existing-test-tag" }
+                })
+            },
+            onNodeMatcher = hasTestTag(testTag = "existing-test-tag")
         )
 
         assertion.assert(hasText(text = "another text"))
@@ -174,24 +139,16 @@
 
     @Test
     fun chainAssertions() {
-        val testContext = TestContext<MappedNode, GlanceMappedNode>()
-        // set root node of test tree to be traversed
-        testContext.rootGlanceNode =
-            GlanceMappedNode(
-                MappedNode(
-                    EmittableColumn().apply {
-                        children.add(EmittableText().apply { text = "some text" })
-                        children.add(EmittableSpacer())
-                        children.add(EmittableText().apply {
-                            text = "another text"
-                            modifier = GlanceModifier.semantics { testTag = "existing-test-tag" }
-                        })
-                    })
-            )
-        // This is the object that in real usage a rule.onNode(matcher) would return.
-        val assertion = GlanceNodeAssertion(
-            matcher = hasTestTag(testTag = "existing-test-tag"),
-            testContext = testContext
+        val assertion = getGlanceNodeAssertionFor(
+            emittable = EmittableColumn().apply {
+                children.add(EmittableText().apply { text = "some text" })
+                children.add(EmittableSpacer())
+                children.add(EmittableText().apply {
+                    text = "another text"
+                    modifier = GlanceModifier.semantics { testTag = "existing-test-tag" }
+                })
+            },
+            onNodeMatcher = hasTestTag(testTag = "existing-test-tag")
         )
 
         assertion
@@ -202,25 +159,16 @@
 
     @Test
     fun chainAssertion_failureInFirst() {
-        val testContext = TestContext<MappedNode, GlanceMappedNode>()
-        // set root node of test tree to be traversed
-        testContext.rootGlanceNode =
-            GlanceMappedNode(
-                MappedNode(
-                    EmittableColumn().apply {
-                        children.add(EmittableText().apply { text = "some text" })
-                        children.add(EmittableSpacer())
-                        children.add(EmittableText().apply {
-                            text = "another text"
-                            modifier = GlanceModifier.semantics { testTag = "existing-test-tag" }
-                        })
-                    }
-                )
-            )
-        // This is the object that in real usage a rule.onNode(matcher) would return.
-        val assertion = GlanceNodeAssertion(
-            matcher = hasTestTag(testTag = "existing-test-tag"),
-            testContext = testContext
+        val assertion = getGlanceNodeAssertionFor(
+            emittable = EmittableColumn().apply {
+                children.add(EmittableText().apply { text = "some text" })
+                children.add(EmittableSpacer())
+                children.add(EmittableText().apply {
+                    text = "another text"
+                    modifier = GlanceModifier.semantics { testTag = "existing-test-tag" }
+                })
+            },
+            onNodeMatcher = hasTestTag(testTag = "existing-test-tag")
         )
 
         val assertionError = assertThrows(AssertionError::class.java) {
@@ -240,25 +188,16 @@
 
     @Test
     fun chainAssertion_failureInSecond() {
-        val testContext = TestContext<MappedNode, GlanceMappedNode>()
-        // set root node of test tree to be traversed
-        testContext.rootGlanceNode =
-            GlanceMappedNode(
-                MappedNode(
-                    EmittableColumn().apply {
-                        children.add(EmittableText().apply { text = "some text" })
-                        children.add(EmittableSpacer())
-                        children.add(EmittableText().apply {
-                            text = "another text"
-                            modifier = GlanceModifier.semantics { testTag = "existing-test-tag" }
-                        })
-                    }
-                )
-            )
-        // This is the object that in real usage a rule.onNode(matcher) would return.
-        val assertion = GlanceNodeAssertion(
-            matcher = hasTestTag(testTag = "existing-test-tag"),
-            testContext = testContext
+        val assertion = getGlanceNodeAssertionFor(
+            emittable = EmittableColumn().apply {
+                children.add(EmittableText().apply { text = "some text" })
+                children.add(EmittableSpacer())
+                children.add(EmittableText().apply {
+                    text = "another text"
+                    modifier = GlanceModifier.semantics { testTag = "existing-test-tag" }
+                })
+            },
+            onNodeMatcher = hasTestTag(testTag = "existing-test-tag")
         )
 
         val assertionError = assertThrows(AssertionError::class.java) {
@@ -271,7 +210,7 @@
             .hasMessageThat()
             .startsWith(
                 "Failed to assert condition: " +
-                    "(has text = 'non-existing text' (ignoreCase: 'false'))" +
+                    "(contains text 'non-existing text' (ignoreCase: 'false') as substring)" +
                     "\nGlance Node:"
             )
     }
diff --git a/glance/glance-testing/src/test/kotlin/androidx/glance/testing/unit/GlanceMappedNodeMatcherTest.kt b/glance/glance-testing/src/test/kotlin/androidx/glance/testing/unit/GlanceMappedNodeMatcherTest.kt
new file mode 100644
index 0000000..880393f
--- /dev/null
+++ b/glance/glance-testing/src/test/kotlin/androidx/glance/testing/unit/GlanceMappedNodeMatcherTest.kt
@@ -0,0 +1,333 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.glance.testing.unit
+
+import androidx.glance.GlanceModifier
+import androidx.glance.layout.EmittableColumn
+import androidx.glance.semantics.semantics
+import androidx.glance.semantics.testTag
+import androidx.glance.text.EmittableText
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+
+class GlanceMappedNodeMatcherTest {
+    @Test
+    fun matchAny_match_returnsTrue() {
+        val node1 = GlanceMappedNode(
+            EmittableText().apply {
+                text = "node1"
+            }
+        )
+        val node2 = GlanceMappedNode(
+            EmittableColumn().apply {
+                modifier = GlanceModifier.semantics { testTag = "existing-test-tag" }
+                EmittableText().apply { text = "node2" }
+            }
+        )
+
+        val result = hasTestTag("existing-test-tag").matchesAny(listOf(node1, node2))
+
+        assertThat(result).isTrue()
+    }
+
+    @Test
+    fun matchAny_noMatch_returnsFalse() {
+        val node1 = GlanceMappedNode(
+            EmittableText().apply {
+                text = "node1"
+            }
+        )
+        val node2 = GlanceMappedNode(
+            EmittableColumn().apply {
+                children += EmittableText().apply {
+                    text = "node2"
+                    // this won't be inspected, as EmittableColumn node is being run against
+                    // matcher, not its children
+                    modifier = GlanceModifier.semantics { testTag = "existing-test-tag" }
+                }
+            }
+        )
+
+        val result = hasTestTag("existing-test-tag").matchesAny(listOf(node1, node2))
+
+        assertThat(result).isFalse()
+    }
+
+    @Test
+    fun andBetweenMatchers_match_returnsTrue() {
+        val node = GlanceMappedNode(
+            EmittableText().apply {
+                text = "node"
+                modifier = GlanceModifier.semantics { testTag = "test-tag" }
+            }
+        )
+
+        val result = (hasTestTag("test-tag") and hasText("node")).matches(node)
+
+        assertThat(result).isTrue()
+    }
+
+    @Test
+    fun andBetweenMatchers_partialMatch_returnsFalse() {
+        val node = GlanceMappedNode(
+            EmittableText().apply {
+                text = "node"
+                modifier = GlanceModifier.semantics { testTag = "test-tag" }
+            }
+        )
+
+        val result = (hasTestTag("test-tag") and hasText("non-existing-node"))
+            .matches(node)
+
+        assertThat(result).isFalse()
+    }
+
+    @Test
+    fun andBetweenMatchers_noMatch_returnsFalse() {
+        val node = GlanceMappedNode(
+            EmittableText().apply {
+                text = "node"
+                modifier = GlanceModifier.semantics { testTag = "test-tag" }
+            }
+        )
+
+        val result = (hasTestTag("non-existing") and hasText("non-existing-node"))
+            .matches(node)
+
+        assertThat(result).isFalse()
+    }
+
+    @Test
+    fun orBetweenMatchers_bothMatch_returnsTrue() {
+        val node = GlanceMappedNode(
+            EmittableText().apply {
+                text = "node"
+                modifier = GlanceModifier.semantics { testTag = "test-tag" }
+            }
+        )
+
+        val result = (hasTestTag("test-tag") or hasText("node"))
+            .matches(node)
+
+        assertThat(result).isTrue()
+    }
+
+    @Test
+    fun orBetweenMatchers_secondMatch_returnsTrue() {
+        val node = GlanceMappedNode(
+            EmittableText().apply {
+                text = "node"
+                modifier = GlanceModifier.semantics { testTag = "test-tag" }
+            }
+        )
+
+        val result = (hasTestTag("non-existing-tag") or hasText("node"))
+            .matches(node)
+
+        assertThat(result).isTrue()
+    }
+
+    @Test
+    fun orBetweenMatchers_noneMatch_returnsFalse() {
+        val node = GlanceMappedNode(
+            EmittableText().apply {
+                text = "node"
+                modifier = GlanceModifier.semantics { testTag = "test-tag" }
+            }
+        )
+
+        val result = (hasTestTag("non-existing-tag") or hasText("non-existing-node"))
+            .matches(node)
+
+        assertThat(result).isFalse()
+    }
+
+    @Test
+    fun not_match_returnsTrue() {
+        val node = GlanceMappedNode(
+            EmittableText().apply {
+                text = "node"
+                modifier = GlanceModifier.semantics { testTag = "test-tag" }
+            }
+        )
+
+        val result = (!hasTestTag("non-existing-test-tag")).matches(node)
+
+        assertThat(result).isTrue()
+    }
+
+    @Test
+    fun not_noMatch_returnsFalse() {
+        val node = GlanceMappedNode(
+            EmittableText().apply {
+                text = "node"
+                modifier = GlanceModifier.semantics { testTag = "test-tag" }
+            }
+        )
+
+        val result = (!hasTestTag("test-tag")).matches(node)
+
+        assertThat(result).isFalse()
+    }
+
+    @Test
+    fun hasTestTag_match_returnsTrue() {
+        // a single node that will be matched against matcher returned by the filter under test
+        val testSingleNode = GlanceMappedNode(
+            EmittableText().apply {
+                text = "some text"
+                modifier = GlanceModifier.semantics { testTag = "existing-test-tag" }
+            }
+        )
+
+        val result = hasTestTag("existing-test-tag").matches(testSingleNode)
+
+        assertThat(result).isTrue()
+    }
+
+    @Test
+    fun hasTestTag_noMatch_returnsFalse() {
+        val testSingleNode = GlanceMappedNode(
+            EmittableText().apply {
+                text = "some text"
+                modifier = GlanceModifier.semantics { testTag = "existing-test-tag" }
+            }
+        )
+
+        val result = hasTestTag("non-existing-test-tag").matches(testSingleNode)
+
+        assertThat(result).isFalse()
+    }
+
+    @Test
+    fun hasTextEqualTo_match_returnsTrue() {
+        val testSingleNode = GlanceMappedNode(
+            EmittableText().apply {
+                text = "existing text"
+            }
+        )
+
+        val result = hasTextEqualTo("existing text").matches(testSingleNode)
+
+        assertThat(result).isTrue()
+    }
+
+    @Test
+    fun hasTextEqualTo_noMatch_returnsFalse() {
+        val testSingleNode = GlanceMappedNode(
+            EmittableText().apply {
+                text = "existing text"
+            }
+        )
+
+        val result = hasTextEqualTo("non-existing text").matches(testSingleNode)
+
+        assertThat(result).isFalse()
+    }
+
+    @Test
+    fun hasTextEqualTo_caseInsensitiveMatch_returnsTrue() {
+        val testSingleNode = GlanceMappedNode(
+            EmittableText().apply {
+                text = "some EXISTING text"
+            }
+        )
+
+        val result =
+            hasTextEqualTo(
+                text = "SOME existing TEXT",
+                ignoreCase = true
+            ).matches(testSingleNode)
+
+        assertThat(result).isTrue()
+    }
+
+    @Test
+    fun hasTextEqualTo_caseInsensitiveButNoMatch_returnsFalse() {
+        val testSingleNode = GlanceMappedNode(
+            EmittableText().apply {
+                text = "some EXISTING text"
+            }
+        )
+
+        val result =
+            hasTextEqualTo(
+                text = "SOME non-existing TEXT",
+                ignoreCase = true
+            ).matches(testSingleNode)
+
+        assertThat(result).isFalse()
+    }
+
+    @Test
+    fun hasText_match_returnsTrue() {
+        val testSingleNode = GlanceMappedNode(
+            EmittableText().apply {
+                text = "some existing text"
+            }
+        )
+
+        val result = hasText("existing").matches(testSingleNode)
+
+        assertThat(result).isTrue()
+    }
+
+    @Test
+    fun hasText_noMatch_returnsFalse() {
+        val testSingleNode = GlanceMappedNode(
+            EmittableText().apply {
+                text = "some existing text"
+            }
+        )
+
+        val result = hasText("non-existing").matches(testSingleNode)
+
+        assertThat(result).isFalse()
+    }
+
+    @Test
+    fun hasText_insensitiveMatch_returnsTrue() {
+        val testSingleNode = GlanceMappedNode(
+            EmittableText().apply {
+                text = "some EXISTING text"
+            }
+        )
+
+        val result = hasText(
+            text = "existing",
+            ignoreCase = true
+        ).matches(testSingleNode)
+
+        assertThat(result).isTrue()
+    }
+
+    @Test
+    fun hasText_caseInsensitiveButNoMatch_returnsFalse() {
+        val testSingleNode = GlanceMappedNode(
+            EmittableText().apply {
+                text = "some EXISTING text"
+            }
+        )
+
+        val result = hasText(
+            text = "non-EXISTING",
+            ignoreCase = true
+        ).matches(testSingleNode)
+
+        assertThat(result).isFalse()
+    }
+}
diff --git a/glance/glance-testing/src/test/kotlin/androidx/glance/testing/unit/UnitTestAssertionExtensionsTest.kt b/glance/glance-testing/src/test/kotlin/androidx/glance/testing/unit/UnitTestAssertionExtensionsTest.kt
index b404ec7..d4800b2 100644
--- a/glance/glance-testing/src/test/kotlin/androidx/glance/testing/unit/UnitTestAssertionExtensionsTest.kt
+++ b/glance/glance-testing/src/test/kotlin/androidx/glance/testing/unit/UnitTestAssertionExtensionsTest.kt
@@ -30,6 +30,162 @@
 // and relevant to unit tests
 class UnitTestAssertionExtensionsTest {
     @Test
+    fun assertHasTextEqualTo_matching() {
+        val nodeAssertion = getGlanceNodeAssertionFor(
+            emittable = EmittableColumn().apply {
+                children.add(EmittableText().apply {
+                    text = "test text"
+                    modifier = GlanceModifier.semantics { testTag = "test-tag" }
+                })
+            },
+            onNodeMatcher = hasTestTag("test-tag")
+        )
+
+        nodeAssertion.assertHasTextEqualTo("test text")
+    }
+
+    @Test
+    fun assertHasTextEqualTo_ignoreCase_matching() {
+        val nodeAssertion = getGlanceNodeAssertionFor(
+            emittable = EmittableColumn().apply {
+                children.add(EmittableText().apply {
+                    text = "test text"
+                    modifier = GlanceModifier.semantics { testTag = "test-tag" }
+                })
+            },
+            onNodeMatcher = hasTestTag("test-tag")
+        )
+
+        nodeAssertion.assertHasTextEqualTo(text = "TEST TEXT", ignoreCase = true)
+    }
+
+    @Test
+    fun assertHasTextEqualTo_notMatching_assertionError() {
+        val nodeAssertion = getGlanceNodeAssertionFor(
+            emittable = EmittableColumn().apply {
+                children.add(EmittableText().apply {
+                    text = "test text"
+                    modifier = GlanceModifier.semantics { testTag = "test-tag" }
+                })
+            },
+            onNodeMatcher = hasTestTag("test-tag")
+        )
+
+        val assertionError = assertThrows(AssertionError::class.java) {
+            nodeAssertion.assertHasTextEqualTo("non-existing text")
+        }
+
+        assertThat(assertionError)
+            .hasMessageThat()
+            .contains(
+                "Failed to assert condition: " +
+                    "(text == 'non-existing text' (ignoreCase: 'false'))"
+            )
+    }
+
+    @Test
+    fun assertHasTextEqualTo_ignoreCaseAndNotMatching_assertionError() {
+        val nodeAssertion = getGlanceNodeAssertionFor(
+            emittable = EmittableColumn().apply {
+                children.add(EmittableText().apply {
+                    text = "test text"
+                    modifier = GlanceModifier.semantics { testTag = "test-tag" }
+                })
+            },
+            onNodeMatcher = hasTestTag("test-tag")
+        )
+
+        val assertionError = assertThrows(AssertionError::class.java) {
+            nodeAssertion.assertHasTextEqualTo("NON-EXISTING TEXT", ignoreCase = true)
+        }
+
+        assertThat(assertionError)
+            .hasMessageThat()
+            .contains(
+                "Failed to assert condition: " +
+                    "(text == 'NON-EXISTING TEXT' (ignoreCase: 'true'))"
+            )
+    }
+
+    @Test
+    fun assertHasText_matching() {
+        val nodeAssertion = getGlanceNodeAssertionFor(
+            emittable = EmittableColumn().apply {
+                children.add(EmittableText().apply {
+                    text = "test text"
+                    modifier = GlanceModifier.semantics { testTag = "test-tag" }
+                })
+            },
+            onNodeMatcher = hasTestTag("test-tag")
+        )
+
+        nodeAssertion.assertHasText(text = "text")
+    }
+
+    @Test
+    fun assertHasText_ignoreCase_matching() {
+        val nodeAssertion = getGlanceNodeAssertionFor(
+            emittable = EmittableColumn().apply {
+                children.add(EmittableText().apply {
+                    text = "test text"
+                    modifier = GlanceModifier.semantics { testTag = "test-tag" }
+                })
+            },
+            onNodeMatcher = hasTestTag("test-tag")
+        )
+
+        nodeAssertion.assertHasText(text = "TEXT", ignoreCase = true)
+    }
+
+    @Test
+    fun assertHasText_notMatching_assertionError() {
+        val nodeAssertion = getGlanceNodeAssertionFor(
+            emittable = EmittableColumn().apply {
+                children.add(EmittableText().apply {
+                    text = "test text"
+                    modifier = GlanceModifier.semantics { testTag = "test-tag" }
+                })
+            },
+            onNodeMatcher = hasTestTag("test-tag")
+        )
+
+        val assertionError = assertThrows(AssertionError::class.java) {
+            nodeAssertion.assertHasText("non-existing")
+        }
+
+        assertThat(assertionError)
+            .hasMessageThat()
+            .contains(
+                "Failed to assert condition: " +
+                    "(contains text 'non-existing' (ignoreCase: 'false') as substring)"
+            )
+    }
+
+    @Test
+    fun assertHasText_ignoreCaseAndNotMatching_assertionError() {
+        val nodeAssertion = getGlanceNodeAssertionFor(
+            emittable = EmittableColumn().apply {
+                children.add(EmittableText().apply {
+                    text = "test text"
+                    modifier = GlanceModifier.semantics { testTag = "test-tag" }
+                })
+            },
+            onNodeMatcher = hasTestTag("test-tag")
+        )
+
+        val assertionError = assertThrows(AssertionError::class.java) {
+            nodeAssertion.assertHasText(text = "NON-EXISTING", ignoreCase = true)
+        }
+
+        assertThat(assertionError)
+            .hasMessageThat()
+            .contains(
+                "Failed to assert condition: " +
+                    "(contains text 'NON-EXISTING' (ignoreCase: 'true') as substring)"
+            )
+    }
+
+    @Test
     fun assertHasTestTag_matching() {
         val nodeAssertion = getGlanceNodeAssertionFor(
             emittable = EmittableColumn().apply {
@@ -66,6 +222,99 @@
     }
 
     @Test
+    fun assertHasContentDescriptionEqualTo_matching() {
+        val nodeAssertion = getGlanceNodeAssertionFor(
+            emittable = EmittableColumn().apply {
+                children.add(EmittableText().apply {
+                    text = "test text"
+                    modifier = GlanceModifier.semantics {
+                        testTag = "test-tag"
+                        contentDescription = "test text description"
+                    }
+                })
+            },
+            onNodeMatcher = hasTestTag("test-tag")
+        )
+
+        nodeAssertion.assertHasContentDescriptionEqualTo("test text description")
+    }
+
+    @Test
+    fun assertHasContentDescriptionEqualTo_ignoreCaseMatching() {
+        val nodeAssertion = getGlanceNodeAssertionFor(
+            emittable = EmittableColumn().apply {
+                children.add(EmittableText().apply {
+                    text = "test text"
+                    modifier = GlanceModifier.semantics {
+                        testTag = "test-tag"
+                        contentDescription = "test text description"
+                    }
+                })
+            },
+            onNodeMatcher = hasTestTag("test-tag")
+        )
+
+        nodeAssertion.assertHasContentDescriptionEqualTo(
+            value = "TEST TEXT DESCRIPTION",
+            ignoreCase = true
+        )
+    }
+
+    @Test
+    fun assertHasContentDescriptionEqualTo_notMatching_assertionError() {
+        val nodeAssertion = getGlanceNodeAssertionFor(
+            emittable = EmittableColumn().apply {
+                children.add(EmittableText().apply {
+                    text = "test text"
+                    modifier = GlanceModifier.semantics { testTag = "test-tag" }
+                })
+            },
+            onNodeMatcher = hasTestTag("test-tag")
+        )
+
+        val assertionError = assertThrows(AssertionError::class.java) {
+            nodeAssertion.assertHasContentDescriptionEqualTo("text description")
+        }
+
+        assertThat(assertionError)
+            .hasMessageThat()
+            .contains(
+                "Failed to assert condition: " +
+                    "(ContentDescription == 'text description' (ignoreCase: 'false'))"
+            )
+    }
+
+    @Test
+    fun assertHasContentDescriptionEqualTo_ignoreCaseAndNotMatching_assertionError() {
+        val nodeAssertion = getGlanceNodeAssertionFor(
+            emittable = EmittableColumn().apply {
+                children.add(EmittableText().apply {
+                    text = "test text"
+                    modifier = GlanceModifier.semantics {
+                        testTag = "test-tag"
+                        contentDescription = "test text description"
+                    }
+                })
+            },
+            onNodeMatcher = hasTestTag("test-tag")
+        )
+
+        val assertionError = assertThrows(AssertionError::class.java) {
+            nodeAssertion.assertHasContentDescriptionEqualTo(
+                value = "TEST DESCRIPTION",
+                ignoreCase = true
+            )
+        }
+
+        assertThat(assertionError)
+            .hasMessageThat()
+            .contains(
+                "Failed to assert condition: " +
+                    "(ContentDescription == 'TEST DESCRIPTION' (ignoreCase: 'true'))"
+            )
+    }
+
+    @Test
     fun assertHasContentDescription_matching() {
         val nodeAssertion = getGlanceNodeAssertionFor(
             emittable = EmittableColumn().apply {
@@ -80,7 +329,28 @@
             onNodeMatcher = hasTestTag("test-tag")
         )
 
-        nodeAssertion.assertHasContentDescription("test text description")
+        nodeAssertion.assertHasContentDescription("text")
+    }
+
+    @Test
+    fun assertHasContentDescription_ignoreCaseMatching() {
+        val nodeAssertion = getGlanceNodeAssertionFor(
+            emittable = EmittableColumn().apply {
+                children.add(EmittableText().apply {
+                    text = "test text"
+                    modifier = GlanceModifier.semantics {
+                        testTag = "test-tag"
+                        contentDescription = "test text description"
+                    }
+                })
+            },
+            onNodeMatcher = hasTestTag("test-tag")
+        )
+
+        nodeAssertion.assertHasContentDescription(
+            value = "TEXT",
+            ignoreCase = true
+        )
     }
 
     @Test
@@ -103,7 +373,39 @@
             .hasMessageThat()
             .contains(
                 "Failed to assert condition: " +
-                    "(ContentDescription = 'test text description' (ignoreCase: 'false'))"
+                    "(ContentDescription contains 'test text description' " +
+                    "(ignoreCase: 'false') as substring)"
+            )
+    }
+
+    @Test
+    fun assertHasContentDescription_ignoreCaseAndNotMatching_assertionError() {
+        val nodeAssertion = getGlanceNodeAssertionFor(
+            emittable = EmittableColumn().apply {
+                children.add(EmittableText().apply {
+                    text = "test text"
+                    modifier = GlanceModifier.semantics {
+                        testTag = "test-tag"
+                        contentDescription = "text"
+                    }
+                })
+            },
+            onNodeMatcher = hasTestTag("test-tag")
+        )
+
+        val assertionError = assertThrows(AssertionError::class.java) {
+            nodeAssertion.assertHasContentDescription(
+                value = "TEXT DESCRIPTION",
+                ignoreCase = true
+            )
+        }
+
+        assertThat(assertionError)
+            .hasMessageThat()
+            .contains(
+                "Failed to assert condition: " +
+                    "(ContentDescription contains 'TEXT DESCRIPTION' (ignoreCase: 'true') " +
+                    "as substring)"
             )
     }
 }
diff --git a/glance/glance-testing/src/test/kotlin/androidx/glance/testing/unit/GlanceMappedNodeFiltersAndMatcherTest.kt b/glance/glance-testing/src/test/kotlin/androidx/glance/testing/unit/UnitTestFiltersTest.kt
similarity index 62%
rename from glance/glance-testing/src/test/kotlin/androidx/glance/testing/unit/GlanceMappedNodeFiltersAndMatcherTest.kt
rename to glance/glance-testing/src/test/kotlin/androidx/glance/testing/unit/UnitTestFiltersTest.kt
index 2fb3c52..69aa1a9 100644
--- a/glance/glance-testing/src/test/kotlin/androidx/glance/testing/unit/GlanceMappedNodeFiltersAndMatcherTest.kt
+++ b/glance/glance-testing/src/test/kotlin/androidx/glance/testing/unit/UnitTestFiltersTest.kt
@@ -24,49 +24,7 @@
 import com.google.common.truth.Truth.assertThat
 import org.junit.Test
 
-class GlanceMappedNodeFiltersAndMatcherTest {
-    @Test
-    fun matchAny_match_returnsTrue() {
-        val node1 = GlanceMappedNode(
-            EmittableText().apply {
-                text = "node1"
-            }
-        )
-        val node2 = GlanceMappedNode(
-            EmittableColumn().apply {
-                modifier = GlanceModifier.semantics { testTag = "existing-test-tag" }
-                EmittableText().apply { text = "node2" }
-            }
-        )
-
-        val result = hasTestTag("existing-test-tag").matchesAny(listOf(node1, node2))
-
-        assertThat(result).isTrue()
-    }
-
-    @Test
-    fun matchAny_noMatch_returnsFalse() {
-        val node1 = GlanceMappedNode(
-            EmittableText().apply {
-                text = "node1"
-            }
-        )
-        val node2 = GlanceMappedNode(
-            EmittableColumn().apply {
-                EmittableText().apply {
-                    text = "node2"
-                    // this won't be inspected, as EmittableColumn node is being run against
-                    // matcher, not its children
-                    modifier = GlanceModifier.semantics { testTag = "existing-test-tag" }
-                }
-            }
-        )
-
-        val result = hasTestTag("existing-test-tag").matchesAny(listOf(node1, node2))
-
-        assertThat(result).isFalse()
-    }
-
+class UnitTestFiltersTest {
     @Test
     fun hasTestTag_match_returnsTrue() {
         // a single node that will be matched against matcher returned by the filter under test
@@ -97,14 +55,74 @@
     }
 
     @Test
-    fun hasText_match_returnsTrue() {
+    fun hasTextEqualTo_match_returnsTrue() {
         val testSingleNode = GlanceMappedNode(
             EmittableText().apply {
                 text = "existing text"
             }
         )
 
-        val result = hasText("existing text").matches(testSingleNode)
+        val result = hasTextEqualTo("existing text").matches(testSingleNode)
+
+        assertThat(result).isTrue()
+    }
+
+    @Test
+    fun hasTextEqualTo_noMatch_returnsFalse() {
+        val testSingleNode = GlanceMappedNode(
+            EmittableText().apply {
+                text = "existing text"
+            }
+        )
+
+        val result = hasTextEqualTo("non-existing text").matches(testSingleNode)
+
+        assertThat(result).isFalse()
+    }
+
+    @Test
+    fun hasTextEqualTo_caseInsensitiveMatch_returnsTrue() {
+        val testSingleNode = GlanceMappedNode(
+            EmittableText().apply {
+                text = "some EXISTING text"
+            }
+        )
+
+        val result =
+            hasTextEqualTo(
+                text = "SOME existing TEXT",
+                ignoreCase = true
+            ).matches(testSingleNode)
+
+        assertThat(result).isTrue()
+    }
+
+    @Test
+    fun hasTextEqualTo_caseInsensitiveButNoMatch_returnsFalse() {
+        val testSingleNode = GlanceMappedNode(
+            EmittableText().apply {
+                text = "some EXISTING text"
+            }
+        )
+
+        val result =
+            hasTextEqualTo(
+                text = "SOME non-existing TEXT",
+                ignoreCase = true
+            ).matches(testSingleNode)
+
+        assertThat(result).isFalse()
+    }
+
+    @Test
+    fun hasText_match_returnsTrue() {
+        val testSingleNode = GlanceMappedNode(
+            EmittableText().apply {
+                text = "some existing text"
+            }
+        )
+
+        val result = hasText("existing").matches(testSingleNode)
 
         assertThat(result).isTrue()
     }
@@ -113,94 +131,91 @@
     fun hasText_noMatch_returnsFalse() {
         val testSingleNode = GlanceMappedNode(
             EmittableText().apply {
-                text = "existing text"
-            }
-        )
-
-        val result = hasText("non-existing text").matches(testSingleNode)
-
-        assertThat(result).isFalse()
-    }
-
-    @Test
-    fun hasText_subStringMatch_returnsTrue() {
-        val testSingleNode = GlanceMappedNode(
-            EmittableText().apply {
                 text = "some existing text"
             }
         )
 
-        val result = hasText(text = "existing", substring = true).matches(testSingleNode)
-
-        assertThat(result).isTrue()
-    }
-
-    @Test
-    fun hasText_subStringNoMatch_returnsFalse() {
-        val testSingleNode = GlanceMappedNode(
-            EmittableText().apply {
-                text = "some existing text"
-            }
-        )
-
-        val result = hasText(text = "non-existing", substring = true).matches(testSingleNode)
+        val result = hasText("non-existing").matches(testSingleNode)
 
         assertThat(result).isFalse()
     }
 
     @Test
-    fun hasText_subStringCaseInsensitiveMatch_returnsTrue() {
+    fun hasText_insensitiveMatch_returnsTrue() {
         val testSingleNode = GlanceMappedNode(
             EmittableText().apply {
                 text = "some EXISTING text"
             }
         )
 
-        val result =
-            hasText(text = "existing", substring = true, ignoreCase = true).matches(testSingleNode)
+        val result = hasText(
+            text = "existing",
+            ignoreCase = true
+        ).matches(testSingleNode)
 
         assertThat(result).isTrue()
     }
 
     @Test
-    fun hasText_subStringCaseInsensitiveNoMatch_returnsFalse() {
+    fun hasText_caseInsensitiveButNoMatch_returnsFalse() {
         val testSingleNode = GlanceMappedNode(
             EmittableText().apply {
                 text = "some EXISTING text"
             }
         )
 
-        val result =
-            hasText(text = "non-EXISTING", substring = true, ignoreCase = true)
-                .matches(testSingleNode)
+        val result = hasText(
+            text = "non-EXISTING",
+            ignoreCase = true
+        ).matches(testSingleNode)
 
         assertThat(result).isFalse()
     }
 
     @Test
-    fun hasText_caseInsensitiveMatch_returnsTrue() {
-        val testSingleNode = GlanceMappedNode(
-            EmittableText().apply {
-                text = "some EXISTING text"
+    fun hasAnyDescendant_match_returnsTrue() {
+        val testNode = GlanceMappedNode(
+            EmittableColumn().apply {
+                children += EmittableText().apply {
+                    text = "node1"
+                }
+                children += EmittableColumn().apply {
+                    children += EmittableText().apply {
+                        text = "node2-a"
+                    }
+                    children += EmittableText().apply {
+                        text = "node2-b"
+                    }
+                }
             }
         )
 
         val result =
-            hasText(text = "SOME existing TEXT", ignoreCase = true).matches(testSingleNode)
+            hasAnyDescendant(hasText("node2-b")).matches(testNode)
 
         assertThat(result).isTrue()
     }
 
     @Test
-    fun hasText_caseInsensitiveNoMatch_returnsFalse() {
-        val testSingleNode = GlanceMappedNode(
-            EmittableText().apply {
-                text = "some EXISTING text"
+    fun hasAnyDescendant_noMatch_returnsFalse() {
+        val testNode = GlanceMappedNode(
+            EmittableColumn().apply {
+                children += EmittableText().apply {
+                    text = "node1"
+                }
+                children += EmittableColumn().apply {
+                    children += EmittableText().apply {
+                        text = "node2-a"
+                    }
+                    children += EmittableText().apply {
+                        text = "node2-b"
+                    }
+                }
             }
         )
 
         val result =
-            hasText(text = "SOME non-existing TEXT", ignoreCase = true).matches(testSingleNode)
+            hasAnyDescendant(hasText("node3-a")).matches(testNode)
 
         assertThat(result).isFalse()
     }
diff --git a/gradle/README.md b/gradle/README.md
index e945e4e..bd7a571 100644
--- a/gradle/README.md
+++ b/gradle/README.md
@@ -24,24 +24,13 @@
 
 [Configuration file for Gradle dependency verification](https://docs.gradle.org/current/userguide/dependency_verification.html#sub:verification-metadata) used by androidx to make sure dependencies are [signed with trusted signatures](https://docs.gradle.org/current/userguide/dependency_verification.html#sec:signature-verificationn) and that unsigned artifacts have [expected checksums](https://docs.gradle.org/current/userguide/dependency_verification.html#sec:checksum-verification).
 
-When adding a new artifact
-- if it is signed, then run:
+When adding a new artifact, first run:
 ```
 development/update-verification-metadata.sh
 ```
-to trust the signature of the new artifact.
+to trust the signature (or checksum) of the new artifact.
 
-- if it is not signed, then run the following to add generated checksums to `verification-metadata.xml`:
-
-```
-./gradlew -M sha256 buildOnServer --dry-run
-```
-
-Then you will want to diff `gradle/verification-metadata.dryrun.xml` and
-`gradle/verification-metadata.xml` using your favorite tool (e.g. meld) can copy over the entries
-that are relevant to your new artifacts.
-
-Each new checksum that you copy over in this way must be associated with a bug that is tracking
+Then, if any checksums were added, make sure they're associated with a bug that is tracking
 an effort to build or acquire a signed version of this dependency.  To associate with a bug,
 please add an `androidx:reason` attribute to a string that contains a URL for a bug filed
 either in buganizer or github:
@@ -57,8 +46,6 @@
 </component>
 ```
 
-After doing this, you can then delete all the `verification-*-dryrun.*` files.
-
 ### If that doesn't work.
 
 If the artifact is not signed, and does not get automatically added to
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index db17c37..ea083dd 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -26,14 +26,14 @@
 byteBuddy = "1.12.10"
 asm = "9.3"
 cmake = "3.22.1"
-dagger = "2.46.1"
+dagger = "2.48"
 dexmaker = "2.28.3"
 dokka = "1.8.20-dev-214"
 espresso = "3.6.0-alpha01"
 espressoDevice = "1.0.0-alpha05"
 grpc = "1.52.0"
 guavaJre = "31.1-jre"
-hilt = "2.46.1"
+hilt = "2.48"
 incap = "0.2"
 jcodec = "0.2.5"
 kotlin17 = "1.7.10"
@@ -230,11 +230,11 @@
 opentest4j = { module = "org.opentest4j:opentest4j", version = "1.2.0" }
 playFeatureDelivery = { module = "com.google.android.play:feature-delivery", version = "2.0.1" }
 playCore = { module = "com.google.android.play:core", version = "1.10.3" }
-playServicesAuth = {module = "com.google.android.gms:play-services-auth", version = "20.5.0"}
+playServicesAuth = {module = "com.google.android.gms:play-services-auth", version = "20.7.0"}
 playServicesBase = { module = "com.google.android.gms:play-services-base", version = "17.0.0" }
 playServicesBasement = { module = "com.google.android.gms:play-services-basement", version = "17.0.0" }
 playServicesDevicePerformance = { module = "com.google.android.gms:play-services-deviceperformance", version = "16.0.0" }
-playServicesFido = {module = "com.google.android.gms:play-services-fido", version = "20.0.1"}
+playServicesFido = {module = "com.google.android.gms:play-services-fido", version = "20.1.0"}
 playServicesWearable = { module = "com.google.android.gms:play-services-wearable", version = "17.1.0" }
 paparazzi = { module = "app.cash.paparazzi:paparazzi", version.ref = "paparazzi" }
 paparazziNativeJvm = { module = "app.cash.paparazzi:layoutlib-native-jdk11", version.ref = "paparazziNative" }
diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml
index 18337be..0b3b82b 100644
--- a/gradle/verification-metadata.xml
+++ b/gradle/verification-metadata.xml
@@ -511,6 +511,11 @@
             <sha256 value="32001db2443b339dd21f5b79ff29d1ade722d1ba080c214bde819f0f72d1604d" origin="Generated by Gradle"/>
          </artifact>
       </component>
+      <component group="com.github.johnrengelman.shadow" name="com.github.johnrengelman.shadow.gradle.plugin" version="8.1.1">
+         <artifact name="com.github.johnrengelman.shadow.gradle.plugin-8.1.1.pom">
+            <sha256 value="3cb3886b97df6e066f108c316b219f262c97c3cb2df6da78927e645deb643cb0" origin="Generated by Gradle" reason="Artifact is not signed"/>
+         </artifact>
+      </component>
       <component group="com.google" name="google" version="1">
          <artifact name="google-1.pom">
             <sha256 value="cd6db17a11a31ede794ccbd1df0e4d9750f640234731f21cff885a9997277e81" origin="Generated by Gradle" reason="Artifact is not signed"/>
@@ -678,11 +683,6 @@
             </sha256>
          </artifact>
       </component>
-      <component group="com.github.johnrengelman.shadow" name="com.github.johnrengelman.shadow.gradle.plugin" version="8.1.1">
-         <artifact name="com.github.johnrengelman.shadow.gradle.plugin-8.1.1.pom">
-            <sha256 value="3cb3886b97df6e066f108c316b219f262c97c3cb2df6da78927e645deb643cb0" origin="Generated by Gradle" reason="Artifact is not signed"/>
-         </artifact>
-      </component>
       <component group="javax.annotation" name="jsr250-api" version="1.0">
          <artifact name="jsr250-api-1.0.jar">
             <sha256 value="a1a922d0d9b6d183ed3800dfac01d1e1eb159f0e8c6f94736931c1def54a941f" origin="Generated by Gradle"/>
diff --git a/health/connect/connect-client/api/current.txt b/health/connect/connect-client/api/current.txt
index 3e9c371..7b0863a 100644
--- a/health/connect/connect-client/api/current.txt
+++ b/health/connect/connect-client/api/current.txt
@@ -9,6 +9,7 @@
     method public suspend Object? deleteRecords(kotlin.reflect.KClass<? extends androidx.health.connect.client.records.Record> recordType, java.util.List<java.lang.String> recordIdsList, java.util.List<java.lang.String> clientRecordIdsList, kotlin.coroutines.Continuation<? super kotlin.Unit>);
     method public suspend Object? getChanges(String changesToken, kotlin.coroutines.Continuation<? super androidx.health.connect.client.response.ChangesResponse>);
     method public suspend Object? getChangesToken(androidx.health.connect.client.request.ChangesTokenRequest request, kotlin.coroutines.Continuation<? super java.lang.String>);
+    method public static String getHealthConnectManageDataAction(android.content.Context context);
     method public static String getHealthConnectSettingsAction();
     method public static androidx.health.connect.client.HealthConnectClient getOrCreate(android.content.Context context);
     method public static androidx.health.connect.client.HealthConnectClient getOrCreate(android.content.Context context, optional String providerPackageName);
@@ -28,6 +29,7 @@
   }
 
   public static final class HealthConnectClient.Companion {
+    method public String getHealthConnectManageDataAction(android.content.Context context);
     method public String getHealthConnectSettingsAction();
     method public androidx.health.connect.client.HealthConnectClient getOrCreate(android.content.Context context);
     method public androidx.health.connect.client.HealthConnectClient getOrCreate(android.content.Context context, optional String providerPackageName);
diff --git a/health/connect/connect-client/api/restricted_current.txt b/health/connect/connect-client/api/restricted_current.txt
index 7bccf0e..beb3500f 100644
--- a/health/connect/connect-client/api/restricted_current.txt
+++ b/health/connect/connect-client/api/restricted_current.txt
@@ -9,6 +9,7 @@
     method public suspend Object? deleteRecords(kotlin.reflect.KClass<? extends androidx.health.connect.client.records.Record> recordType, java.util.List<java.lang.String> recordIdsList, java.util.List<java.lang.String> clientRecordIdsList, kotlin.coroutines.Continuation<? super kotlin.Unit>);
     method public suspend Object? getChanges(String changesToken, kotlin.coroutines.Continuation<? super androidx.health.connect.client.response.ChangesResponse>);
     method public suspend Object? getChangesToken(androidx.health.connect.client.request.ChangesTokenRequest request, kotlin.coroutines.Continuation<? super java.lang.String>);
+    method public static String getHealthConnectManageDataAction(android.content.Context context);
     method public static String getHealthConnectSettingsAction();
     method public static androidx.health.connect.client.HealthConnectClient getOrCreate(android.content.Context context);
     method public static androidx.health.connect.client.HealthConnectClient getOrCreate(android.content.Context context, optional String providerPackageName);
@@ -28,6 +29,7 @@
   }
 
   public static final class HealthConnectClient.Companion {
+    method public String getHealthConnectManageDataAction(android.content.Context context);
     method public String getHealthConnectSettingsAction();
     method public androidx.health.connect.client.HealthConnectClient getOrCreate(android.content.Context context);
     method public androidx.health.connect.client.HealthConnectClient getOrCreate(android.content.Context context, optional String providerPackageName);
diff --git a/health/connect/connect-client/src/main/java/androidx/health/connect/client/HealthConnectClient.kt b/health/connect/connect-client/src/main/java/androidx/health/connect/client/HealthConnectClient.kt
index fce572a..4f74132 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/connect/client/HealthConnectClient.kt
+++ b/health/connect/connect-client/src/main/java/androidx/health/connect/client/HealthConnectClient.kt
@@ -320,6 +320,13 @@
             "androidx.health.ACTION_HEALTH_CONNECT_SETTINGS"
 
         /**
+         * The minimum version code of the default provider APK that supports manage data intent
+         * action.
+         */
+        @RestrictTo(RestrictTo.Scope.LIBRARY)
+        internal const val ACTION_MANAGE_DATA_MIN_SUPPORTED_VERSION_CODE = 82932
+
+        /**
          * Intent action to open Health Connect settings on this phone. Developers should use this
          * if they want to re-direct the user to Health Connect.
          */
@@ -461,6 +468,29 @@
             )
         }
 
+        /**
+         * Intent action to open Health Connect data management screen on this phone. Developers
+         * should use this if they want to re-direct the user to Health Connect data management.
+         *
+         * @param context the context
+         * @return Intent action to open Health Connect data management screen.
+         */
+        @JvmStatic
+        fun getHealthConnectManageDataAction(context: Context): String {
+            val action = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
+                "android.health.connect.action.MANAGE_HEALTH_DATA"
+            } else if (isProviderAvailable(
+                    context = context,
+                    providerVersionCode = ACTION_MANAGE_DATA_MIN_SUPPORTED_VERSION_CODE
+                )
+            ) {
+                "androidx.health.ACTION_MANAGE_HEALTH_DATA"
+            } else {
+                ACTION_HEALTH_CONNECT_SETTINGS
+            }
+            return action
+        }
+
         @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.P)
         internal fun isSdkVersionSufficient() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P
 
@@ -471,11 +501,16 @@
         internal fun isProviderAvailable(
             context: Context,
             providerPackageName: String = DEFAULT_PROVIDER_PACKAGE_NAME,
+            providerVersionCode: Int = DEFAULT_PROVIDER_MIN_VERSION_CODE
         ): Boolean {
             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
                 return true
             }
-            return isPackageInstalled(context.packageManager, providerPackageName)
+            return isPackageInstalled(
+                context.packageManager,
+                providerPackageName,
+                providerVersionCode
+            )
         }
 
         internal fun isProviderAvailableLegacy(
@@ -488,6 +523,7 @@
         private fun isPackageInstalled(
             packageManager: PackageManager,
             packageName: String,
+            versionCode: Int = DEFAULT_PROVIDER_MIN_VERSION_CODE
         ): Boolean {
             val packageInfo: PackageInfo =
                 try {
@@ -498,8 +534,7 @@
                 }
             return packageInfo.applicationInfo.enabled &&
                 (packageName != DEFAULT_PROVIDER_PACKAGE_NAME ||
-                    PackageInfoCompat.getLongVersionCode(packageInfo) >=
-                        DEFAULT_PROVIDER_MIN_VERSION_CODE) &&
+                    PackageInfoCompat.getLongVersionCode(packageInfo) >= versionCode) &&
                 hasBindableService(packageManager, packageName)
         }
 
diff --git a/health/connect/connect-client/src/test/java/androidx/health/connect/client/HealthConnectClientTest.kt b/health/connect/connect-client/src/test/java/androidx/health/connect/client/HealthConnectClientTest.kt
index 2b6a910..81036fd 100644
--- a/health/connect/connect-client/src/test/java/androidx/health/connect/client/HealthConnectClientTest.kt
+++ b/health/connect/connect-client/src/test/java/androidx/health/connect/client/HealthConnectClientTest.kt
@@ -178,6 +178,45 @@
         }
     }
 
+    @Test
+    @Config(sdk = [Build.VERSION_CODES.P])
+    fun getHealthConnectManageDataAction_unsupportedClient_returnsDefaultIntent() {
+        installPackage(
+            context,
+            HealthConnectClient.DEFAULT_PROVIDER_PACKAGE_NAME,
+            versionCode = HealthConnectClient.DEFAULT_PROVIDER_MIN_VERSION_CODE,
+            enabled = true
+        )
+
+        assertThat(HealthConnectClient.getHealthConnectManageDataAction(context)).isEqualTo(
+            HealthConnectClient.ACTION_HEALTH_CONNECT_SETTINGS
+        )
+    }
+
+    @Test
+    @Config(sdk = [Build.VERSION_CODES.P])
+    fun getHealthConnectManageDataAction_supportedClient() {
+        installPackage(
+            context,
+            HealthConnectClient.DEFAULT_PROVIDER_PACKAGE_NAME,
+            versionCode = HealthConnectClient.ACTION_MANAGE_DATA_MIN_SUPPORTED_VERSION_CODE,
+            enabled = true
+        )
+        installService(context, HealthConnectClient.DEFAULT_PROVIDER_PACKAGE_NAME)
+
+        assertThat(HealthConnectClient.getHealthConnectManageDataAction(context)).isEqualTo(
+            "androidx.health.ACTION_MANAGE_HEALTH_DATA"
+        )
+    }
+
+    @Test
+    @Config(minSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+    fun getHealthConnectManageDataAction_platformSupported() {
+        assertThat(HealthConnectClient.getHealthConnectManageDataAction(context)).isEqualTo(
+            "android.health.connect.action.MANAGE_HEALTH_DATA"
+        )
+    }
+
     private fun installPackage(
         context: Context,
         packageName: String,
diff --git a/javascriptengine/javascriptengine/api/aidlRelease/current/org/chromium/android_webview/js_sandbox/common/IJsSandboxIsolateClient.aidl b/javascriptengine/javascriptengine/api/aidlRelease/current/org/chromium/android_webview/js_sandbox/common/IJsSandboxIsolateClient.aidl
new file mode 100644
index 0000000..b00a1ca
--- /dev/null
+++ b/javascriptengine/javascriptengine/api/aidlRelease/current/org/chromium/android_webview/js_sandbox/common/IJsSandboxIsolateClient.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2023 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package org.chromium.android_webview.js_sandbox.common;
+/* @hide */
+interface IJsSandboxIsolateClient {
+  void onTerminated(int status, String message) = 1;
+  const int TERMINATE_UNKNOWN_ERROR = 1;
+  const int TERMINATE_SANDBOX_DEAD = 2;
+  const int TERMINATE_MEMORY_LIMIT_EXCEEDED = 3;
+}
diff --git a/javascriptengine/javascriptengine/api/aidlRelease/current/org/chromium/android_webview/js_sandbox/common/IJsSandboxService.aidl b/javascriptengine/javascriptengine/api/aidlRelease/current/org/chromium/android_webview/js_sandbox/common/IJsSandboxService.aidl
index cd3aae0..78a0831 100644
--- a/javascriptengine/javascriptengine/api/aidlRelease/current/org/chromium/android_webview/js_sandbox/common/IJsSandboxService.aidl
+++ b/javascriptengine/javascriptengine/api/aidlRelease/current/org/chromium/android_webview/js_sandbox/common/IJsSandboxService.aidl
@@ -37,9 +37,11 @@
   org.chromium.android_webview.js_sandbox.common.IJsSandboxIsolate createIsolate() = 0;
   List<String> getSupportedFeatures() = 1;
   org.chromium.android_webview.js_sandbox.common.IJsSandboxIsolate createIsolateWithMaxHeapSizeBytes(long maxHeapSize) = 2;
+  org.chromium.android_webview.js_sandbox.common.IJsSandboxIsolate createIsolate2(long maxHeapSize, org.chromium.android_webview.js_sandbox.common.IJsSandboxIsolateClient isolateClient) = 3;
   const String ISOLATE_TERMINATION = "ISOLATE_TERMINATION";
   const String ISOLATE_MAX_HEAP_SIZE_LIMIT = "ISOLATE_MAX_HEAP_SIZE_LIMIT";
   const String WASM_FROM_ARRAY_BUFFER = "WASM_FROM_ARRAY_BUFFER";
   const String EVALUATE_WITHOUT_TRANSACTION_LIMIT = "EVALUATE_WITHOUT_TRANSACTION_LIMIT";
   const String CONSOLE_MESSAGING = "CONSOLE_MESSAGING";
+  const String ISOLATE_CLIENT = "ISOLATE_CLIENT";
 }
diff --git a/javascriptengine/javascriptengine/api/current.txt b/javascriptengine/javascriptengine/api/current.txt
index e523e0b..77b4206c 100644
--- a/javascriptengine/javascriptengine/api/current.txt
+++ b/javascriptengine/javascriptengine/api/current.txt
@@ -20,7 +20,7 @@
     field public static final int DEFAULT_MAX_EVALUATION_RETURN_SIZE_BYTES = 20971520; // 0x1400000
   }
 
-  public final class IsolateTerminatedException extends androidx.javascriptengine.JavaScriptException {
+  public class IsolateTerminatedException extends androidx.javascriptengine.JavaScriptException {
     ctor public IsolateTerminatedException();
   }
 
@@ -74,12 +74,12 @@
     field public static final String JS_FEATURE_WASM_COMPILATION = "JS_FEATURE_WASM_COMPILATION";
   }
 
-  public final class MemoryLimitExceededException extends androidx.javascriptengine.JavaScriptException {
+  public final class MemoryLimitExceededException extends androidx.javascriptengine.IsolateTerminatedException {
     ctor public MemoryLimitExceededException();
     ctor public MemoryLimitExceededException(String);
   }
 
-  public final class SandboxDeadException extends androidx.javascriptengine.JavaScriptException {
+  public final class SandboxDeadException extends androidx.javascriptengine.IsolateTerminatedException {
     ctor public SandboxDeadException();
   }
 
diff --git a/javascriptengine/javascriptengine/api/restricted_current.txt b/javascriptengine/javascriptengine/api/restricted_current.txt
index e523e0b..77b4206c 100644
--- a/javascriptengine/javascriptengine/api/restricted_current.txt
+++ b/javascriptengine/javascriptengine/api/restricted_current.txt
@@ -20,7 +20,7 @@
     field public static final int DEFAULT_MAX_EVALUATION_RETURN_SIZE_BYTES = 20971520; // 0x1400000
   }
 
-  public final class IsolateTerminatedException extends androidx.javascriptengine.JavaScriptException {
+  public class IsolateTerminatedException extends androidx.javascriptengine.JavaScriptException {
     ctor public IsolateTerminatedException();
   }
 
@@ -74,12 +74,12 @@
     field public static final String JS_FEATURE_WASM_COMPILATION = "JS_FEATURE_WASM_COMPILATION";
   }
 
-  public final class MemoryLimitExceededException extends androidx.javascriptengine.JavaScriptException {
+  public final class MemoryLimitExceededException extends androidx.javascriptengine.IsolateTerminatedException {
     ctor public MemoryLimitExceededException();
     ctor public MemoryLimitExceededException(String);
   }
 
-  public final class SandboxDeadException extends androidx.javascriptengine.JavaScriptException {
+  public final class SandboxDeadException extends androidx.javascriptengine.IsolateTerminatedException {
     ctor public SandboxDeadException();
   }
 
diff --git a/javascriptengine/javascriptengine/src/androidTest/java/androidx/javascriptengine/WebViewJavaScriptSandboxTest.java b/javascriptengine/javascriptengine/src/androidTest/java/androidx/javascriptengine/WebViewJavaScriptSandboxTest.java
index 8252afd..d1f5af0 100644
--- a/javascriptengine/javascriptengine/src/androidTest/java/androidx/javascriptengine/WebViewJavaScriptSandboxTest.java
+++ b/javascriptengine/javascriptengine/src/androidTest/java/androidx/javascriptengine/WebViewJavaScriptSandboxTest.java
@@ -17,12 +17,9 @@
 package androidx.javascriptengine;
 
 import android.content.Context;
-import android.content.pm.PackageInfo;
-import android.webkit.WebView;
 
 import androidx.annotation.GuardedBy;
 import androidx.annotation.NonNull;
-import androidx.core.content.pm.PackageInfoCompat;
 import androidx.test.core.app.ApplicationProvider;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.LargeTest;
@@ -58,18 +55,6 @@
         Assume.assumeTrue(JavaScriptSandbox.isSupported());
     }
 
-    // Get the current WebView provider version. In a versionCode of AAAABBBCD, AAAA is the build
-    // number and BBB is the patch number. C and D may usually be ignored.
-    //
-    // Strongly prefer using feature flags over version checks if possible.
-    public long getWebViewVersion() {
-        PackageInfo systemWebViewPackage = WebView.getCurrentWebViewPackage();
-        if (systemWebViewPackage == null) {
-            Assert.fail("No current WebView provider");
-        }
-        return PackageInfoCompat.getLongVersionCode(systemWebViewPackage);
-    }
-
     @Test
     @MediumTest
     public void testSimpleJsEvaluation() throws Throwable {
@@ -584,14 +569,6 @@
     @Test
     @LargeTest
     public void testHeapSizeEnforced() throws Throwable {
-        // WebView versions < 110.0.5438.0 do not contain OOM crashes to a single isolate and
-        // instead crash the whole sandbox process. This change is not tracked in a feature flag.
-        // Versions < 110.0.5438.0 are not considered to be broken, but their behavior is not
-        // of interest for this test.
-        // See Chromium change: https://chromium-review.googlesource.com/c/chromium/src/+/4047785
-        Assume.assumeTrue("WebView version does not support per-isolate OOM handling",
-                getWebViewVersion() >= 5438_000_00L);
-
         final long maxHeapSize = REASONABLE_HEAP_SIZE;
         // We need to beat the v8 optimizer to ensure it really allocates the required memory. Note
         // that we're allocating an array of elements - not bytes. Filling will ensure that the
@@ -608,9 +585,11 @@
         try (JavaScriptSandbox jsSandbox = jsSandboxFuture1.get(5, TimeUnit.SECONDS)) {
             Assume.assumeTrue(jsSandbox.isFeatureSupported(
                     JavaScriptSandbox.JS_FEATURE_ISOLATE_MAX_HEAP_SIZE));
-
             Assume.assumeTrue(
                     jsSandbox.isFeatureSupported(JavaScriptSandbox.JS_FEATURE_PROMISE_RETURN));
+            Assume.assumeTrue(
+                    jsSandbox.isFeatureSupported(JavaScriptSandbox.JS_FEATURE_ISOLATE_CLIENT));
+
             IsolateStartupParameters isolateStartupParameters = new IsolateStartupParameters();
             isolateStartupParameters.setMaxHeapSizeBytes(maxHeapSize);
             try (JavaScriptIsolate jsIsolate1 = jsSandbox.createIsolate(isolateStartupParameters);
@@ -625,8 +604,7 @@
                 // Wait for jsIsolate2 to fully initialize before using jsIsolate1.
                 jsIsolate2.evaluateJavaScriptAsync(stableCode).get(5, TimeUnit.SECONDS);
 
-                // Check that the heap limit is enforced and that it reports this was the evaluation
-                // that exceeded the limit.
+                // Check that the heap limit is enforced.
                 try {
                     // Use a generous timeout for OOM, as it may involve multiple rounds of garbage
                     // collection.
@@ -638,13 +616,22 @@
                     }
                 }
 
+                // Wait for termination, but don't close the isolate.
+                final CountDownLatch latch = new CountDownLatch(1);
+                jsIsolate1.addOnTerminatedCallback(Runnable::run, info -> {
+                    Assert.assertEquals(TerminationInfo.STATUS_MEMORY_LIMIT_EXCEEDED,
+                            info.getStatus());
+                    latch.countDown();
+                });
+                Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
+
                 // Check that the previously submitted (but unresolved) promise evaluation reports a
                 // crash
                 try {
                     earlyUnresolvedResultFuture.get(5, TimeUnit.SECONDS);
                     Assert.fail("Should have thrown.");
                 } catch (ExecutionException e) {
-                    if (!(e.getCause() instanceof IsolateTerminatedException)) {
+                    if (!(e.getCause() instanceof MemoryLimitExceededException)) {
                         throw e;
                     }
                 }
@@ -667,11 +654,18 @@
                     }
                 }
 
-                // Check that other pre-existing isolates can still be used.
+                // Check that other pre-existing isolate in the same sandbox can no longer be used.
+                // (That the sandbox as a whole is dead.)
                 ListenableFuture<String> otherIsolateResultFuture =
                         jsIsolate2.evaluateJavaScriptAsync(stableCode);
-                String otherIsolateResult = otherIsolateResultFuture.get(5, TimeUnit.SECONDS);
-                Assert.assertEquals(stableExpected, otherIsolateResult);
+                try {
+                    otherIsolateResultFuture.get(5, TimeUnit.SECONDS);
+                    Assert.fail("Should have thrown.");
+                } catch (ExecutionException e) {
+                    if (!(e.getCause() instanceof SandboxDeadException)) {
+                        throw e;
+                    }
+                }
             }
         }
     }
@@ -679,14 +673,6 @@
     @Test
     @LargeTest
     public void testIsolateCreationAfterCrash() throws Throwable {
-        // WebView versions < 110.0.5438.0 do not contain OOM crashes to a single isolate and
-        // instead crash the whole sandbox process. This change is not tracked in a feature flag.
-        // Versions < 110.0.5438.0 are not considered to be broken, but their behavior is not
-        // of interest for this test.
-        // See Chromium change: https://chromium-review.googlesource.com/c/chromium/src/+/4047785
-        Assume.assumeTrue("WebView version does not support per-isolate OOM handling",
-                getWebViewVersion() >= 5438_000_00L);
-
         final long maxHeapSize = REASONABLE_HEAP_SIZE;
         // We need to beat the v8 optimizer to ensure it really allocates the required memory. Note
         // that we're allocating an array of elements - not bytes. Filling will ensure that the
@@ -704,14 +690,15 @@
                     JavaScriptSandbox.JS_FEATURE_ISOLATE_MAX_HEAP_SIZE));
             Assume.assumeTrue(
                     jsSandbox.isFeatureSupported(JavaScriptSandbox.JS_FEATURE_PROMISE_RETURN));
+            Assume.assumeTrue(
+                    jsSandbox.isFeatureSupported(JavaScriptSandbox.JS_FEATURE_ISOLATE_CLIENT));
             IsolateStartupParameters isolateStartupParameters = new IsolateStartupParameters();
             isolateStartupParameters.setMaxHeapSizeBytes(maxHeapSize);
             try (JavaScriptIsolate jsIsolate1 = jsSandbox.createIsolate(isolateStartupParameters)) {
                 ListenableFuture<String> oomResultFuture =
                         jsIsolate1.evaluateJavaScriptAsync(oomingCode);
 
-                // Check that the heap limit is enforced and that it reports this was the evaluation
-                // that exceeded the limit.
+                // Check that the heap limit is enforced.
                 try {
                     // Use a generous timeout for OOM, as it may involve multiple rounds of garbage
                     // collection.
@@ -723,28 +710,22 @@
                     }
                 }
 
-                // Check that other isolates can still be created and used (without closing
-                // jsIsolate1).
-                try (JavaScriptIsolate jsIsolate2 =
-                             jsSandbox.createIsolate(isolateStartupParameters)) {
-                    ListenableFuture<String> resultFuture =
-                            jsIsolate2.evaluateJavaScriptAsync(stableCode);
-                    String result = resultFuture.get(5, TimeUnit.SECONDS);
-                    Assert.assertEquals(stableExpected, result);
-                }
-            }
+                final CountDownLatch latch = new CountDownLatch(1);
+                jsIsolate1.addOnTerminatedCallback(Runnable::run, info -> {
+                    Assert.assertEquals(TerminationInfo.STATUS_MEMORY_LIMIT_EXCEEDED,
+                            info.getStatus());
+                    latch.countDown();
+                });
+                Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
 
-            // Check that other isolates can still be created and used (after closing jsIsolate1).
-            try (JavaScriptIsolate jsIsolate = jsSandbox.createIsolate(isolateStartupParameters)) {
-                ListenableFuture<String> resultFuture =
-                        jsIsolate.evaluateJavaScriptAsync(stableCode);
-                String result = resultFuture.get(5, TimeUnit.SECONDS);
-                Assert.assertEquals(stableExpected, result);
+                // Check that new isolates can no longer be created in the same sandbox.
+                Assert.assertThrows(IllegalStateException.class,
+                        () -> jsSandbox.createIsolate(isolateStartupParameters));
             }
         }
 
-        // Check that the old sandbox with the "crashed" isolate can be torn down and that a new
-        // sandbox and isolate can be spun up.
+        // Check that after the old OOMed sandbox is closed and torn down that a new sandbox and
+        // isolate can be spun up.
         ListenableFuture<JavaScriptSandbox> jsSandboxFuture2 =
                 JavaScriptSandbox.createConnectedInstanceAsync(context);
         try (JavaScriptSandbox jsSandbox = jsSandboxFuture2.get(5, TimeUnit.SECONDS);
@@ -1144,4 +1125,80 @@
             Assert.assertEquals(expected, result);
         }
     }
+
+    @Test
+    @LargeTest
+    public void testTerminationNotificationForSandboxDeath() throws Throwable {
+        final Context context = ApplicationProvider.getApplicationContext();
+        final ListenableFuture<JavaScriptSandbox> jsSandboxFuture =
+                JavaScriptSandbox.createConnectedInstanceAsync(context);
+        try (JavaScriptSandbox jsSandbox = jsSandboxFuture.get(5, TimeUnit.SECONDS)) {
+            try (JavaScriptIsolate jsIsolate = jsSandbox.createIsolate()) {
+                final ListenableFuture<String> loopFuture =
+                        jsIsolate.evaluateJavaScriptAsync("while(true);");
+
+                final CountDownLatch latch = new CountDownLatch(2);
+
+                final Runnable futureCallback = () -> {
+                    try {
+                        loopFuture.get();
+                        Assert.fail("Should have thrown.");
+                    } catch (ExecutionException e) {
+                        if (!(e.getCause() instanceof SandboxDeadException)) {
+                            Assert.fail("Wrong exception for evaluation: " + e);
+                        }
+                    } catch (InterruptedException e) {
+                        Assert.fail("Interrupted: " + e);
+                    }
+                    latch.countDown();
+                };
+                loopFuture.addListener(futureCallback, Runnable::run);
+
+                jsIsolate.addOnTerminatedCallback(Runnable::run, info -> {
+                    Assert.assertEquals(TerminationInfo.STATUS_SANDBOX_DEAD, info.getStatus());
+                    latch.countDown();
+                });
+
+                jsSandbox.close();
+
+                Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
+            }
+        }
+    }
+
+    @Test
+    @LargeTest
+    public void testOomOutsideOfEvaluation() throws Throwable {
+        final Context context = ApplicationProvider.getApplicationContext();
+        final ListenableFuture<JavaScriptSandbox> jsSandboxFuture =
+                JavaScriptSandbox.createConnectedInstanceAsync(context);
+        try (JavaScriptSandbox jsSandbox = jsSandboxFuture.get(5, TimeUnit.SECONDS)) {
+            Assume.assumeTrue(jsSandbox.isFeatureSupported(
+                    JavaScriptSandbox.JS_FEATURE_ISOLATE_MAX_HEAP_SIZE));
+            Assume.assumeTrue(
+                    jsSandbox.isFeatureSupported(JavaScriptSandbox.JS_FEATURE_ISOLATE_CLIENT));
+            IsolateStartupParameters isolateStartupParameters = new IsolateStartupParameters();
+            isolateStartupParameters.setMaxHeapSizeBytes(REASONABLE_HEAP_SIZE);
+            try (JavaScriptIsolate jsIsolate = jsSandbox.createIsolate(isolateStartupParameters)) {
+                // OOM should occur in a microtask, not during this evaluation, so we should
+                // never get a MemoryLimitExceededException from the evaluation future.
+                final String code = ""
+                        + "const bytes = [0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00];"
+                        + "WebAssembly.compile(new Uint8Array(bytes)).then(() => {"
+                        + "  this.array ="
+                        + "    Array(" + REASONABLE_HEAP_SIZE + ").fill(Math.random(), 0);"
+                        + "});"
+                        + "'PASS'";
+                jsIsolate.evaluateJavaScriptAsync(code).get(5, TimeUnit.SECONDS);
+
+                final CountDownLatch latch = new CountDownLatch(1);
+                jsIsolate.addOnTerminatedCallback(Runnable::run, info -> {
+                    Assert.assertEquals(
+                            TerminationInfo.STATUS_MEMORY_LIMIT_EXCEEDED, info.getStatus());
+                    latch.countDown();
+                });
+                Assert.assertTrue(latch.await(60, TimeUnit.SECONDS));
+            }
+        }
+    }
 }
diff --git a/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/EnvironmentDeadState.java b/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/EnvironmentDeadState.java
index 0c99deb..c10d56fd 100644
--- a/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/EnvironmentDeadState.java
+++ b/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/EnvironmentDeadState.java
@@ -18,6 +18,7 @@
 
 import androidx.annotation.NonNull;
 import androidx.concurrent.futures.CallbackToFutureAdapter;
+import androidx.core.util.Consumer;
 
 import com.google.common.util.concurrent.ListenableFuture;
 
@@ -25,15 +26,19 @@
 
 /**
  * Covers the case where the environment is dead.
- *
+ * <p>
  * This state covers cases where the developer explicitly closes the sandbox or sandbox/isolate
  * being dead outside of the control of the developer.
+ * <p>
+ * Although being in this state is considered terminated from the app perspective, the service
+ * side may still technically be running.
  */
 final class EnvironmentDeadState implements IsolateState {
-    private final JavaScriptException mException;
+    @NonNull
+    private final TerminationInfo mTerminationInfo;
 
-    EnvironmentDeadState(JavaScriptException e) {
-        mException = e;
+    EnvironmentDeadState(@NonNull TerminationInfo terminationInfo) {
+        mTerminationInfo = terminationInfo;
     }
 
     @NonNull
@@ -41,7 +46,7 @@
     public ListenableFuture<String> evaluateJavaScriptAsync(@NonNull String code) {
         return CallbackToFutureAdapter.getFuture(completer -> {
             final String futureDebugMessage = "evaluateJavascript Future";
-            completer.setException(mException);
+            completer.setException(mTerminationInfo.toJavaScriptException());
             return futureDebugMessage;
         });
     }
@@ -69,12 +74,16 @@
     }
 
     @Override
-    public IsolateState setSandboxDead() {
-        return new EnvironmentDeadState(new SandboxDeadException());
+    public boolean canDie() {
+        return false;
     }
 
     @Override
-    public IsolateState setIsolateDead() {
-        return this;
+    public void addOnTerminatedCallback(@NonNull Executor executor,
+            @NonNull Consumer<TerminationInfo> callback) {
+        executor.execute(() -> callback.accept(mTerminationInfo));
     }
+
+    @Override
+    public void removeOnTerminatedCallback(@NonNull Consumer<TerminationInfo> callback) {}
 }
diff --git a/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/IsolateClosedState.java b/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/IsolateClosedState.java
index 927bbe0..ba944b1 100644
--- a/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/IsolateClosedState.java
+++ b/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/IsolateClosedState.java
@@ -17,48 +17,55 @@
 package androidx.javascriptengine;
 
 import androidx.annotation.NonNull;
+import androidx.core.util.Consumer;
 
 import com.google.common.util.concurrent.ListenableFuture;
 
 import java.util.concurrent.Executor;
 
 /**
- * Covers the case where the isolate is explicitly closed by the developer.
+ * Covers cases where the isolate is explicitly closed or uninitialized.
+ * <p>
+ * Although being in this state is considered terminated from the app perspective, the service
+ * side may still technically be running.
  */
 final class IsolateClosedState implements IsolateState {
-    IsolateClosedState() {
+    @NonNull
+    private final String mDescription;
+    IsolateClosedState(@NonNull String description) {
+        mDescription = description;
     }
 
     @NonNull
     @Override
     public ListenableFuture<String> evaluateJavaScriptAsync(@NonNull String code) {
-        throw new IllegalStateException("Calling evaluateJavaScriptAsync() after closing the"
-                + "Isolate");
+        throw new IllegalStateException(
+                "Calling evaluateJavaScriptAsync() when " + mDescription);
     }
 
     @Override
     public void setConsoleCallback(@NonNull Executor executor,
             @NonNull JavaScriptConsoleCallback callback) {
         throw new IllegalStateException(
-                "Calling setConsoleCallback() after closing the Isolate");
+                "Calling setConsoleCallback() when " + mDescription);
     }
 
     @Override
     public void setConsoleCallback(@NonNull JavaScriptConsoleCallback callback) {
         throw new IllegalStateException(
-                "Calling setConsoleCallback() after closing the Isolate");
+                "Calling setConsoleCallback() when " + mDescription);
     }
 
     @Override
     public void clearConsoleCallback() {
         throw new IllegalStateException(
-                "Calling clearConsoleCallback() after closing the Isolate");
+                "Calling clearConsoleCallback() when " + mDescription);
     }
 
     @Override
     public boolean provideNamedData(@NonNull String name, @NonNull byte[] inputBytes) {
         throw new IllegalStateException(
-                "Calling provideNamedData() after closing the Isolate");
+                "Calling provideNamedData() when " + mDescription);
     }
 
     @Override
@@ -66,12 +73,20 @@
     }
 
     @Override
-    public IsolateState setSandboxDead() {
-        return this;
+    public boolean canDie() {
+        return false;
     }
 
     @Override
-    public IsolateState setIsolateDead() {
-        return this;
+    public void addOnTerminatedCallback(@NonNull Executor executor,
+            @NonNull Consumer<TerminationInfo> callback) {
+        throw new IllegalStateException(
+                "Calling addOnTerminatedCallback() when " + mDescription);
+    }
+
+    @Override
+    public void removeOnTerminatedCallback(@NonNull Consumer<TerminationInfo> callback) {
+        throw new IllegalStateException(
+                "Calling removeOnTerminatedCallback() when " + mDescription);
     }
 }
diff --git a/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/IsolateStartupParameters.java b/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/IsolateStartupParameters.java
index a1f5013..fe7714f 100644
--- a/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/IsolateStartupParameters.java
+++ b/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/IsolateStartupParameters.java
@@ -47,10 +47,17 @@
      * some multiple of bytes, be increased to some minimum value, or reduced to some maximum
      * supported value.
      * <p>
-     * Exceeding this limit will usually result in a {@link MemoryLimitExceededException},
-     * but beware that not all JavaScript sandbox service implementations (particularly older ones)
-     * handle memory exhaustion equally gracefully, and may crash the entire sandbox (see
-     * {@link SandboxDeadException}).
+     * Exceeding this limit will usually result in all unfinished and future evaluations failing
+     * with {@link MemoryLimitExceededException} and the isolate terminating with a status of
+     * {@link TerminationInfo#STATUS_MEMORY_LIMIT_EXCEEDED}. Note that exceeding the memory limit
+     * will take down the entire sandbox - not just the responsible isolate - and all other
+     * isolates will receive generic {@link SandboxDeadException} and
+     * {@link TerminationInfo#STATUS_SANDBOX_DEAD} errors.
+     * <p>
+     * Not all JavaScript sandbox service implementations (particularly older ones) handle memory
+     * exhaustion equally, and may crash the sandbox without attributing the failure to memory
+     * exhaustion in a particular isolate.
+     *
      * @param size heap size in bytes
      */
     @RequiresFeature(name = JavaScriptSandbox.JS_FEATURE_ISOLATE_MAX_HEAP_SIZE,
diff --git a/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/IsolateState.java b/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/IsolateState.java
index 5a44f48..6188bc9 100644
--- a/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/IsolateState.java
+++ b/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/IsolateState.java
@@ -17,6 +17,7 @@
 package androidx.javascriptengine;
 
 import androidx.annotation.NonNull;
+import androidx.core.util.Consumer;
 
 import com.google.common.util.concurrent.ListenableFuture;
 
@@ -24,17 +25,16 @@
 
 /**
  * Interface for State design pattern.
- *
+ * <p>
  * Isolates can be in different states due to events within/outside the control of the developer.
  * This pattern allows us to extract out the state related behaviour without maintaining it all in
  * the JavaScriptIsolate class which proved to be error-prone and hard to read.
- *
+ * <p>
  * State specific behaviour are implemented in concrete classes that implements this interface.
- *
+ * <p>
  * Refer: https://en.wikipedia.org/wiki/State_pattern
  */
 interface IsolateState {
-
     @NonNull
     ListenableFuture<String> evaluateJavaScriptAsync(@NonNull String code);
 
@@ -49,7 +49,22 @@
 
     void close();
 
-    IsolateState setIsolateDead();
+    /**
+     * Check whether the current state is permitted to transition to a dead state
+     *
+     * @return true iff a transition to a dead state is permitted.
+     */
+    boolean canDie();
 
-    IsolateState setSandboxDead();
+    /**
+     * Method to run after this state has been replaced by a dead state.
+     *
+     * @param terminationInfo The termination info describing the death.
+     */
+    default void onDied(@NonNull TerminationInfo terminationInfo) {}
+
+    void addOnTerminatedCallback(@NonNull Executor executor,
+            @NonNull Consumer<TerminationInfo> callback);
+
+    void removeOnTerminatedCallback(@NonNull Consumer<TerminationInfo> callback);
 }
diff --git a/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/IsolateTerminatedException.java b/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/IsolateTerminatedException.java
index b7547ecb..8548c19 100644
--- a/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/IsolateTerminatedException.java
+++ b/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/IsolateTerminatedException.java
@@ -16,27 +16,42 @@
 
 package androidx.javascriptengine;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.core.util.Consumer;
+
+import java.util.concurrent.Executor;
+
 /**
  * Exception thrown when evaluation is terminated due to the {@link JavaScriptIsolate} being closed
- * or crashing.
+ * or due to some crash.
  * <p>
  * Calling {@link JavaScriptIsolate#close()} will cause this exception to be thrown for all
  * previously requested but pending evaluations.
  * <p>
- * If the individual isolate has crashed, for example, due to exceeding a memory limit, this
- * exception will also be thrown for all pending and future evaluations (until
- * {@link JavaScriptIsolate#close()} is called).
- * <p>
- * Note that if the sandbox as a whole has crashed or been closed, {@link SandboxDeadException} will
- * be thrown instead.
+ * If an isolate has crashed (but not been closed), subsequently requested evaluations will fail
+ * immediately with an IsolateTerminatedException (or a subclass) consistent with that
+ * used for evaluations submitted before the crash.
  * <p>
  * Note that this exception will not be thrown if the isolate has been explicitly closed before a
  * call to {@link JavaScriptIsolate#evaluateJavaScriptAsync(String)}, which will instead immediately
  * throw an IllegalStateException (and not asynchronously via a future). This applies even if the
  * isolate was closed following a crash.
+ * <p>
+ * Do not attempt to parse the information in this exception's message as it may change between
+ * JavaScriptEngine versions.
+ * <p>
+ * Note that it is possible for an isolate to crash outside of submitted evaluations, in which
+ * case an IsolateTerminatedException may not be observed. Consider instead using
+ * {@link JavaScriptIsolate#addOnTerminatedCallback(Executor, Consumer)} if you need to reliably
+ * or immediately detect isolate crashes rather than evaluation failures.
  */
-public final class IsolateTerminatedException extends JavaScriptException {
+public class IsolateTerminatedException extends JavaScriptException {
     public IsolateTerminatedException() {
         super();
     }
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    public IsolateTerminatedException(@NonNull String message) {
+        super(message);
+    }
 }
diff --git a/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/IsolateUsableState.java b/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/IsolateUsableState.java
index e253c86..8f7f2f9 100644
--- a/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/IsolateUsableState.java
+++ b/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/IsolateUsableState.java
@@ -24,6 +24,7 @@
 
 import androidx.annotation.NonNull;
 import androidx.concurrent.futures.CallbackToFutureAdapter;
+import androidx.core.util.Consumer;
 import androidx.javascriptengine.common.LengthLimitExceededException;
 import androidx.javascriptengine.common.Utils;
 
@@ -37,6 +38,7 @@
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Objects;
 import java.util.Set;
@@ -65,6 +67,11 @@
     @GuardedBy("mLock")
     private Set<CallbackToFutureAdapter.Completer<String>> mPendingCompleterSet =
             new HashSet<>();
+    // mOnTerminatedCallbacks does not require this.mLock, as all accesses should be performed
+    // whilst holding the mLock of the JavaScriptIsolate that owns this state object.
+    @NonNull
+    private final HashMap<Consumer<TerminationInfo>, Executor> mOnTerminatedCallbacks =
+            new HashMap<>();
 
     private class IJsSandboxIsolateSyncCallbackStubWrapper extends
             IJsSandboxIsolateSyncCallback.Stub {
@@ -79,6 +86,9 @@
         @Override
         public void reportResultWithFd(AssetFileDescriptor afd) {
             Objects.requireNonNull(afd);
+            // The completer needs to be removed before offloading to the executor, otherwise there
+            // is a race to complete it if all evaluations are cancelled.
+            removePending(mCompleter);
             mJsIsolate.mJsSandbox.mThreadPoolTaskExecutor.execute(
                     () -> {
                         String result;
@@ -87,13 +97,11 @@
                                     mMaxEvaluationReturnSizeBytes,
                                     /*truncate=*/false);
                         } catch (IOException | UnsupportedOperationException ex) {
-                            removePending(mCompleter);
                             mCompleter.setException(
                                     new JavaScriptException(
                                             "Retrieving result failed: " + ex.getMessage()));
                             return;
                         } catch (LengthLimitExceededException ex) {
-                            removePending(mCompleter);
                             if (ex.getMessage() != null) {
                                 mCompleter.setException(
                                         new EvaluationResultSizeLimitExceededException(
@@ -111,6 +119,9 @@
         @Override
         public void reportErrorWithFd(@ExecutionErrorTypes int type, AssetFileDescriptor afd) {
             Objects.requireNonNull(afd);
+            // The completer needs to be removed before offloading to the executor, otherwise there
+            // is a race to complete it if all evaluations are cancelled.
+            removePending(mCompleter);
             mJsIsolate.mJsSandbox.mThreadPoolTaskExecutor.execute(
                     () -> {
                         String error;
@@ -119,7 +130,6 @@
                                     mMaxEvaluationReturnSizeBytes,
                                     /*truncate=*/true);
                         } catch (IOException | UnsupportedOperationException ex) {
-                            removePending(mCompleter);
                             mCompleter.setException(
                                     new JavaScriptException(
                                             "Retrieving error failed: " + ex.getMessage()));
@@ -144,6 +154,7 @@
         @Override
         public void reportResult(String result) {
             Objects.requireNonNull(result);
+            removePending(mCompleter);
             final long identityToken = Binder.clearCallingIdentity();
             try {
                 handleEvaluationResult(mCompleter, result);
@@ -155,6 +166,7 @@
         @Override
         public void reportError(@ExecutionErrorTypes int type, String error) {
             Objects.requireNonNull(error);
+            removePending(mCompleter);
             final long identityToken = Binder.clearCallingIdentity();
             try {
                 handleEvaluationError(mCompleter, type, error);
@@ -239,11 +251,12 @@
                     new IJsSandboxIsolateCallbackStubWrapper(completer);
             try {
                 mJsIsolateStub.evaluateJavascript(code, callbackStub);
-                addToPendingCompleterSet(completer);
+                addPending(completer);
             } catch (DeadObjectException e) {
                 // The sandbox process has died.
-                mJsIsolate.maybeSetSandboxDead();
-                completer.setException(new SandboxDeadException());
+                final TerminationInfo terminationInfo = mJsIsolate.maybeSetSandboxDead();
+                Objects.requireNonNull(terminationInfo);
+                completer.setException(terminationInfo.toJavaScriptException());
             } catch (RemoteException e) {
                 completer.setException(new RuntimeException(e));
             }
@@ -309,49 +322,52 @@
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException was thrown during close()", e);
         }
-        cancelAllPendingEvaluations(new IsolateTerminatedException());
+        cancelAllPendingEvaluations(new IsolateTerminatedException("isolate closed"));
     }
 
     @Override
-    public IsolateState setIsolateDead() {
-        IsolateTerminatedException exception = new IsolateTerminatedException();
-        cancelAllPendingEvaluations(exception);
-        return new EnvironmentDeadState(exception);
+    public boolean canDie() {
+        return true;
     }
 
     @Override
-    public IsolateState setSandboxDead() {
-        SandboxDeadException exception = new SandboxDeadException();
-        cancelAllPendingEvaluations(exception);
-        return new EnvironmentDeadState(exception);
+    public void onDied(@NonNull TerminationInfo terminationInfo) {
+        cancelAllPendingEvaluations(terminationInfo.toJavaScriptException());
+        mOnTerminatedCallbacks.forEach(
+                (callback, executor) -> executor.execute(() -> callback.accept(terminationInfo)));
     }
 
+    // Caller should call mJsIsolate.removePending(mCompleter) first
     void handleEvaluationError(@NonNull CallbackToFutureAdapter.Completer<String> completer,
             int type, @NonNull String error) {
-        removePending(completer);
-        boolean crashing = false;
         switch (type) {
             case IJsSandboxIsolateSyncCallback.JS_EVALUATION_ERROR:
                 completer.setException(new EvaluationFailedException(error));
                 break;
             case IJsSandboxIsolateSyncCallback.MEMORY_LIMIT_EXCEEDED:
-                completer.setException(new MemoryLimitExceededException(error));
-                crashing = true;
+                // Note that we won't ever receive a MEMORY_LIMIT_EXCEEDED evaluation error if
+                // the service side supports termination notifications, so this only handles the
+                // case where it doesn't.
+                final TerminationInfo terminationInfo =
+                        new TerminationInfo(TerminationInfo.STATUS_MEMORY_LIMIT_EXCEEDED, error);
+                mJsIsolate.maybeSetIsolateDead(terminationInfo);
+                // The completer was already removed from the set, so we're responsible for it.
+                // Use our exception even if the isolate was already dead or closed. This might
+                // result in an exception which is inconsistent with everything else if there was
+                // a death or close before we called maybeSetIsolateDead above, but that requires
+                // the app to have already set up a race condition.
+                completer.setException(terminationInfo.toJavaScriptException());
                 break;
             default:
                 completer.setException(new JavaScriptException(
-                        "Crashing due to unknown JavaScriptException: " + error));
-                // Assume the worst
-                crashing = true;
-        }
-        if (crashing) {
-            mJsIsolate.maybeSetIsolateDead();
+                        "Unknown error: code " + type + ": " + error));
+                break;
         }
     }
 
+    // Caller should call mJsIsolate.removePending(mCompleter) first
     void handleEvaluationResult(@NonNull CallbackToFutureAdapter.Completer<String> completer,
             @NonNull String result) {
-        removePending(completer);
         completer.set(result);
     }
 
@@ -361,7 +377,7 @@
         }
     }
 
-    void addToPendingCompleterSet(@NonNull CallbackToFutureAdapter.Completer<String> completer) {
+    void addPending(@NonNull CallbackToFutureAdapter.Completer<String> completer) {
         synchronized (mLock) {
             mPendingCompleterSet.add(completer);
         }
@@ -394,11 +410,12 @@
                     mJsIsolateStub.evaluateJavascriptWithFd(codeAfd,
                             callbackStub);
                 }
-                addToPendingCompleterSet(completer);
+                addPending(completer);
             } catch (DeadObjectException e) {
                 // The sandbox process has died.
-                mJsIsolate.maybeSetSandboxDead();
-                completer.setException(new SandboxDeadException());
+                final TerminationInfo terminationInfo = mJsIsolate.maybeSetSandboxDead();
+                Objects.requireNonNull(terminationInfo);
+                completer.setException(terminationInfo.toJavaScriptException());
             } catch (RemoteException | IOException e) {
                 completer.setException(new RuntimeException(e));
             }
@@ -406,4 +423,19 @@
             return futureDebugMessage;
         });
     }
+
+    @Override
+    public void addOnTerminatedCallback(@NonNull Executor executor,
+            @NonNull Consumer<TerminationInfo> callback) {
+        if (mOnTerminatedCallbacks.putIfAbsent(callback, executor) != null) {
+            throw new IllegalStateException("Termination callback already registered");
+        }
+    }
+
+    @Override
+    public void removeOnTerminatedCallback(@NonNull Consumer<TerminationInfo> callback) {
+        synchronized (mLock) {
+            mOnTerminatedCallbacks.remove(callback);
+        }
+    }
 }
diff --git a/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/JavaScriptIsolate.java b/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/JavaScriptIsolate.java
index df63307..ab19538 100644
--- a/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/JavaScriptIsolate.java
+++ b/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/JavaScriptIsolate.java
@@ -16,12 +16,20 @@
 
 package androidx.javascriptengine;
 
+import android.os.Binder;
+import android.os.RemoteException;
+import android.util.Log;
+
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.annotation.RequiresFeature;
+import androidx.annotation.RestrictTo;
+import androidx.core.util.Consumer;
 
 import com.google.common.util.concurrent.ListenableFuture;
 
 import org.chromium.android_webview.js_sandbox.common.IJsSandboxIsolate;
+import org.chromium.android_webview.js_sandbox.common.IJsSandboxIsolateClient;
 
 import java.util.Objects;
 import java.util.concurrent.Executor;
@@ -49,44 +57,106 @@
     private final Object mLock = new Object();
     private final CloseGuardHelper mGuard = CloseGuardHelper.create();
 
+    @NonNull
     final JavaScriptSandbox mJsSandbox;
 
     @GuardedBy("mLock")
     @NonNull
     private IsolateState mIsolateState;
 
-    JavaScriptIsolate(@NonNull IJsSandboxIsolate jsIsolateStub, @NonNull JavaScriptSandbox sandbox,
-            @NonNull IsolateStartupParameters settings) {
+    private final class JsSandboxIsolateClient extends IJsSandboxIsolateClient.Stub {
+        JsSandboxIsolateClient() {}
+
+        @Override
+        public void onTerminated(int status, String message) {
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                // If we're already closed, this will do nothing
+                maybeSetIsolateDead(new TerminationInfo(status, message));
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+    }
+
+    @NonNull
+    static JavaScriptIsolate create(@NonNull JavaScriptSandbox sandbox,
+            IsolateStartupParameters settings) throws RemoteException {
+        final JavaScriptIsolate isolate = new JavaScriptIsolate(sandbox);
+        isolate.initialize(settings);
+        return isolate;
+    }
+
+    private JavaScriptIsolate(@NonNull JavaScriptSandbox sandbox) {
+        mJsSandbox = sandbox;
         synchronized (mLock) {
+            mIsolateState = new IsolateClosedState("isolate not initialized");
+        }
+    }
+
+    // Create an isolate on the service side and complete initialization.
+    // This is done outside of the constructor to avoid leaking a partially constructed
+    // JavaScriptIsolate to the service (which would complicate thread-safety).
+    private void initialize(@NonNull IsolateStartupParameters settings) throws RemoteException {
+        synchronized (mLock) {
+            final IJsSandboxIsolateClient instanceCallback;
+            if (mJsSandbox.isFeatureSupported(
+                    JavaScriptSandbox.JS_FEATURE_ISOLATE_CLIENT)) {
+                instanceCallback = new JsSandboxIsolateClient();
+            } else {
+                instanceCallback = null;
+            }
+            IJsSandboxIsolate jsIsolateStub = mJsSandbox.createIsolateOnService(settings,
+                    instanceCallback);
             mIsolateState = new IsolateUsableState(this, jsIsolateStub,
                     settings.getMaxEvaluationReturnSizeBytes());
+            mGuard.open("close");
         }
-        mJsSandbox = sandbox;
-        mGuard.open("close");
-        // This should be at the end of the constructor.
     }
 
     /**
      * Changes the state to denote that the isolate is dead.
-     *
+     * <p>
      * {@link IsolateClosedState} takes precedence so it will not change state if the current state
-     * is {@link IsolateClosedState}
+     * is {@link IsolateClosedState}.
+     * <p>
+     * If the isolate is already dead, the existing dead state is preserved.
+     *
+     * @return true iff the state was changed to a new EnvironmentDeadState
      */
-    void maybeSetIsolateDead() {
+    boolean maybeSetIsolateDead(@NonNull TerminationInfo terminationInfo) {
         synchronized (mLock) {
-            mIsolateState = mIsolateState.setIsolateDead();
+            if (terminationInfo.getStatus() == TerminationInfo.STATUS_MEMORY_LIMIT_EXCEEDED) {
+                Log.e(TAG, "isolate exceeded its heap memory limit - killing sandbox");
+                mJsSandbox.kill();
+            }
+            final IsolateState oldState = mIsolateState;
+            if (oldState.canDie()) {
+                mIsolateState = new EnvironmentDeadState(terminationInfo);
+                oldState.onDied(terminationInfo);
+                return true;
+            }
         }
+        return false;
     }
 
     /**
      * Changes the state to denote that the sandbox is dead.
+     * <p>
+     * See {@link #maybeSetIsolateDead(TerminationInfo)} for additional information.
      *
-     * {@link IsolateClosedState} takes precedence so it will not change state if the current state
-     * is {@link IsolateClosedState}
+     * @return the generated termination info if it was set, or null if the state did not change.
      */
-    void maybeSetSandboxDead() {
+    @Nullable
+    TerminationInfo maybeSetSandboxDead() {
         synchronized (mLock) {
-            mIsolateState = mIsolateState.setSandboxDead();
+            final TerminationInfo terminationInfo =
+                    new TerminationInfo(TerminationInfo.STATUS_SANDBOX_DEAD, "sandbox dead");
+            if (maybeSetIsolateDead(terminationInfo)) {
+                return terminationInfo;
+            } else {
+                return null;
+            }
         }
     }
 
@@ -143,23 +213,28 @@
     /**
      * Closes the {@link JavaScriptIsolate} object and renders it unusable.
      * <p>
-     * Once closed, no more method calls should be made. Pending evaluations resolve with
-     * {@link IsolateTerminatedException} immediately.
+     * Once closed, no more method calls should be made. Pending evaluations will reject with
+     * an {@link IsolateTerminatedException} immediately.
      * <p>
      * If {@link JavaScriptSandbox#isFeatureSupported(String)} is {@code true} for {@link
-     * JavaScriptSandbox#JS_FEATURE_ISOLATE_TERMINATION}, then any pending evaluation is immediately
-     * terminated and memory is freed. If it is {@code false}, the isolate will not get cleaned
+     * JavaScriptSandbox#JS_FEATURE_ISOLATE_TERMINATION}, then any pending evaluations are
+     * terminated. If it is {@code false}, the isolate will not get cleaned
      * up until the pending evaluations have run to completion and will consume resources until
      * then.
+     * <p>
+     * Closing an isolate via this method does not wait on the isolate to clean up. Resources
+     * held by the isolate may remain in use for a duration after this method returns.
      */
     @Override
     public void close() {
         synchronized (mLock) {
             mIsolateState.close();
-            mIsolateState = new IsolateClosedState();
-            mJsSandbox.removeFromIsolateSet(this);
-            mGuard.close();
+            mIsolateState = new IsolateClosedState("isolate closed");
         }
+        // Do not hold mLock whilst calling into JavaScriptSandbox, as JavaScriptSandbox also has
+        // its own lock and may want to call into JavaScriptIsolate from another thread.
+        mJsSandbox.removeFromIsolateSet(this);
+        mGuard.close();
     }
 
     /**
@@ -296,4 +371,58 @@
             mIsolateState.clearConsoleCallback();
         }
     }
+
+    /**
+     * Add a callback to listen for isolate crashes.
+     * <p>
+     * There is no guaranteed order to when these callbacks are triggered and unfinished
+     * evaluations' futures are rejected.
+     * <p>
+     * Registering a callback after the isolate has crashed will result in it being executed
+     * immediately on the supplied executor with the isolate's {@link TerminationInfo} as an
+     * argument.
+     * <p>
+     * Closing an isolate via {@link #close()} is not considered a crash, even if there are
+     * unresolved evaluations, and will not trigger termination callbacks.
+     *
+     * @param executor Executor with which to run callback.
+     * @param callback Consumer to be called with TerminationInfo when a crash occurs.
+     * @throws IllegalStateException if the callback is already registered (using any executor).
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    public void addOnTerminatedCallback(@NonNull Executor executor,
+            @NonNull Consumer<TerminationInfo> callback) {
+        Objects.requireNonNull(executor);
+        Objects.requireNonNull(callback);
+        synchronized (mLock) {
+            mIsolateState.addOnTerminatedCallback(executor, callback);
+        }
+    }
+
+    /**
+     * Add a callback to listen for isolate crashes.
+     * <p>
+     * This is the same as calling {@link #addOnTerminatedCallback(Executor, Consumer)} using the
+     * main executor of the context used to create the {@link JavaScriptSandbox} object.
+     *
+     * @param callback Consumer to be called with TerminationInfo when a crash occurs.
+     * @throws IllegalStateException if the callback is already registered (using any executor).
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    public void addOnTerminatedCallback(@NonNull Consumer<TerminationInfo> callback) {
+        addOnTerminatedCallback(mJsSandbox.getMainExecutor(), callback);
+    }
+
+    /**
+     * Remove a callback previously registered with addOnTerminatedCallback.
+     *
+     * @param callback The callback to unregister, if currently registered.
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    public void removeOnTerminatedCallback(@NonNull Consumer<TerminationInfo> callback) {
+        Objects.requireNonNull(callback);
+        synchronized (mLock) {
+            mIsolateState.removeOnTerminatedCallback(callback);
+        }
+    }
 }
diff --git a/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/JavaScriptSandbox.java b/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/JavaScriptSandbox.java
index 834502a..8a5c048 100644
--- a/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/JavaScriptSandbox.java
+++ b/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/JavaScriptSandbox.java
@@ -37,21 +37,25 @@
 import com.google.common.util.concurrent.ListenableFuture;
 
 import org.chromium.android_webview.js_sandbox.common.IJsSandboxIsolate;
+import org.chromium.android_webview.js_sandbox.common.IJsSandboxIsolateClient;
 import org.chromium.android_webview.js_sandbox.common.IJsSandboxService;
 
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Objects;
+import java.util.Set;
 import java.util.concurrent.Executor;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
 
 import javax.annotation.concurrent.GuardedBy;
 
@@ -88,14 +92,24 @@
     private final Object mLock = new Object();
     private final CloseGuardHelper mGuard = CloseGuardHelper.create();
 
+    // This is null iff the sandbox is closed.
     @Nullable
     @GuardedBy("mLock")
     private IJsSandboxService mJsSandboxService;
 
-    private final ConnectionSetup mConnection;
+    // Don't use mLock for the connection, allowing it to be severed at any time, regardless of
+    // the status of the main mLock. Use an AtomicReference instead.
+    //
+    // The underlying ConnectionSetup is nullable, and is null iff the service has been unbound
+    // (which should also imply dead or closed).
+    @NonNull
+    private final AtomicReference<ConnectionSetup> mConnection;
+    @NonNull
+    private final Context mContext;
 
     @GuardedBy("mLock")
-    private final HashSet<JavaScriptIsolate> mActiveIsolateSet = new HashSet<>();
+    @NonNull
+    private Set<JavaScriptIsolate> mActiveIsolateSet;
 
     final ExecutorService mThreadPoolTaskExecutor =
             Executors.newCachedThreadPool(new ThreadFactory() {
@@ -120,6 +134,7 @@
                     JS_FEATURE_ISOLATE_MAX_HEAP_SIZE,
                     JS_FEATURE_EVALUATE_WITHOUT_TRANSACTION_LIMIT,
                     JS_FEATURE_CONSOLE_MESSAGING,
+                    JS_FEATURE_ISOLATE_CLIENT,
             })
     @Retention(RetentionPolicy.SOURCE)
     @Target({ElementType.PARAMETER, ElementType.METHOD})
@@ -198,6 +213,15 @@
      */
     public static final String JS_FEATURE_CONSOLE_MESSAGING = "JS_FEATURE_CONSOLE_MESSAGING";
 
+    /**
+     * Feature for {@link #isFeatureSupported(String)}.
+     * <p>
+     * When this feature is present, the service can be provided with a Binder interface for
+     * calling into the client, independent of callbacks.
+     */
+    static final String JS_FEATURE_ISOLATE_CLIENT =
+            "JS_FEATURE_ISOLATE_CLIENT";
+
     // This set must not be modified after JavaScriptSandbox construction.
     @NonNull
     private final HashSet<String> mClientSideFeatureSet;
@@ -207,7 +231,8 @@
         private CallbackToFutureAdapter.Completer<JavaScriptSandbox> mCompleter;
         @Nullable
         private JavaScriptSandbox mJsSandbox;
-        final Context mContext;
+        @NonNull
+        private final Context mContext;
 
         @Override
         @SuppressWarnings("NullAway")
@@ -222,7 +247,7 @@
             IJsSandboxService jsSandboxService =
                     IJsSandboxService.Stub.asInterface(service);
             try {
-                mJsSandbox = new JavaScriptSandbox(this, jsSandboxService);
+                mJsSandbox = new JavaScriptSandbox(mContext, this, jsSandboxService);
             } catch (RemoteException e) {
                 runShutdownTasks(e);
                 return;
@@ -386,12 +411,14 @@
 
     // We prevent direct initializations of this class.
     // Use JavaScriptSandbox.createConnectedInstance().
-    JavaScriptSandbox(@NonNull ConnectionSetup connectionSetup,
+    JavaScriptSandbox(@NonNull Context context, @NonNull ConnectionSetup connectionSetup,
             @NonNull IJsSandboxService jsSandboxService) throws RemoteException {
-        mConnection = connectionSetup;
+        mContext = context;
+        mConnection = new AtomicReference<>(connectionSetup);
         mJsSandboxService = jsSandboxService;
         final List<String> features = mJsSandboxService.getSupportedFeatures();
         mClientSideFeatureSet = buildClientSideFeatureSet(features);
+        mActiveIsolateSet = new HashSet<>();
         mGuard.open("close");
         // This should be at the end of the constructor.
     }
@@ -415,27 +442,39 @@
     public JavaScriptIsolate createIsolate(@NonNull IsolateStartupParameters settings) {
         Objects.requireNonNull(settings);
         synchronized (mLock) {
-            if (mJsSandboxService == null) {
+            // TODO(b/290750354, b/290749782): Implement separate closed vs dead state and use
+            //  that instead of a mConnection nullness check.
+            if (mJsSandboxService == null || mConnection.get() == null) {
                 throw new IllegalStateException(
                         "Attempting to createIsolate on a service that isn't connected");
             }
-            IJsSandboxIsolate isolateStub;
+            final JavaScriptIsolate isolate;
             try {
-                if (settings.getMaxHeapSizeBytes()
-                        == IsolateStartupParameters.DEFAULT_ISOLATE_HEAP_SIZE) {
-                    isolateStub = mJsSandboxService.createIsolate();
-                } else {
-                    isolateStub = mJsSandboxService.createIsolateWithMaxHeapSizeBytes(
-                            settings.getMaxHeapSizeBytes());
-                    if (isolateStub == null) {
-                        throw new RuntimeException(
-                                "Service implementation doesn't support setting maximum heap size");
-                    }
-                }
+                isolate = JavaScriptIsolate.create(this, settings);
             } catch (RemoteException e) {
+                // TODO(b/286055647): Handle sandbox dying during createIsolate more sensibly.
                 throw new RuntimeException(e);
             }
-            return createJsIsolateLocked(isolateStub, settings);
+            mActiveIsolateSet.add(isolate);
+            return isolate;
+        }
+    }
+
+    // In practice, this method should only be called whilst already holding mLock, but it is
+    // called via JavaScriptIsolate and this constraint cannot be cleanly expressed via GuardedBy.
+    IJsSandboxIsolate createIsolateOnService(@NonNull IsolateStartupParameters settings,
+            @Nullable IJsSandboxIsolateClient isolateInstanceCallback) throws RemoteException {
+        synchronized (mLock) {
+            Objects.requireNonNull(mJsSandboxService);
+            if (isFeatureSupported(JavaScriptSandbox.JS_FEATURE_ISOLATE_CLIENT)) {
+                return mJsSandboxService.createIsolate2(settings.getMaxHeapSizeBytes(),
+                        isolateInstanceCallback);
+            } else if (isFeatureSupported(JavaScriptSandbox.JS_FEATURE_ISOLATE_MAX_HEAP_SIZE)) {
+                return mJsSandboxService.createIsolateWithMaxHeapSizeBytes(
+                        settings.getMaxHeapSizeBytes());
+            } else {
+                return mJsSandboxService.createIsolate();
+            }
         }
     }
 
@@ -459,19 +498,12 @@
         if (features.contains(IJsSandboxService.CONSOLE_MESSAGING)) {
             featureSet.add(JS_FEATURE_CONSOLE_MESSAGING);
         }
+        if (features.contains(IJsSandboxService.ISOLATE_CLIENT + ":DEV")) {
+            featureSet.add(JS_FEATURE_ISOLATE_CLIENT);
+        }
         return featureSet;
     }
 
-    @GuardedBy("mLock")
-    @NonNull
-    @SuppressWarnings("NullAway")
-    private JavaScriptIsolate createJsIsolateLocked(@NonNull IJsSandboxIsolate isolateStub,
-            @NonNull IsolateStartupParameters settings) {
-        JavaScriptIsolate isolate = new JavaScriptIsolate(isolateStub, this, settings);
-        mActiveIsolateSet.add(isolate);
-        return isolate;
-    }
-
     /**
      * Checks whether a given feature is supported by the JS Sandbox implementation.
      * <p>
@@ -512,28 +544,51 @@
             if (mJsSandboxService == null) {
                 return;
             }
-            // This is the closest thing to a .close() method for ExecutorServices. This doesn't
-            // force the threads or their Runnables to immediately terminate, but will ensure
-            // that once the
-            // worker threads finish their current runnable (if any) that the thread pool terminates
-            // them, preventing a leak of threads.
-            mThreadPoolTaskExecutor.shutdownNow();
-            notifyIsolatesAboutClosureLocked();
-            mConnection.mContext.unbindService(mConnection);
+            unbindService();
             // Currently we consider that we are ready for a new connection once we unbind. This
             // might not be true if the process is not immediately killed by ActivityManager once it
             // is unbound.
             sIsReadyToConnect.set(true);
             mJsSandboxService = null;
         }
+        notifyIsolatesAboutClosure();
+        // This is the closest thing to a .close() method for ExecutorServices. This doesn't
+        // force the threads or their Runnables to immediately terminate, but will ensure
+        // that once the worker threads finish their current runnable (if any) that the thread
+        // pool terminates them, preventing a leak of threads.
+        mThreadPoolTaskExecutor.shutdownNow();
     }
 
-    @GuardedBy("mLock")
-    private void notifyIsolatesAboutClosureLocked() {
-        for (JavaScriptIsolate ele : mActiveIsolateSet) {
-            ele.maybeSetSandboxDead();
+    // Unbind the service if it hasn't been unbound already.
+    private void unbindService() {
+        final ConnectionSetup connection = mConnection.getAndSet(null);
+        if (connection != null) {
+            mContext.unbindService(connection);
         }
-        mActiveIsolateSet.clear();
+    }
+
+    // Kill the sandbox immediately.
+    //
+    // This will unbind the sandbox service so that any future IPC will fail immediately.
+    // However, isolates will be notified asynchronously, from the main thread.
+    void kill() {
+        unbindService();
+        // TODO(b/290750354, b/290749782): Implement separate closed vs dead state.
+        getMainExecutor().execute(this::close);
+    }
+
+    private void notifyIsolatesAboutClosure() {
+        // Do not hold mLock whilst calling into JavaScriptIsolate, as JavaScriptIsolate also has
+        // its own lock and may want to call into JavaScriptSandbox from another thread.
+        final Set<JavaScriptIsolate> activeIsolateSet;
+        synchronized (mLock) {
+            activeIsolateSet = mActiveIsolateSet;
+            mActiveIsolateSet = Collections.emptySet();
+        }
+        for (JavaScriptIsolate isolate : activeIsolateSet) {
+            isolate.maybeSetIsolateDead(new TerminationInfo(TerminationInfo.STATUS_SANDBOX_DEAD,
+                    "sandbox closed"));
+        }
     }
 
     @Override
@@ -553,6 +608,6 @@
 
     @NonNull
     Executor getMainExecutor() {
-        return ContextCompat.getMainExecutor(mConnection.mContext);
+        return ContextCompat.getMainExecutor(mContext);
     }
 }
diff --git a/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/MemoryLimitExceededException.java b/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/MemoryLimitExceededException.java
index f4330cc..415b2d7 100644
--- a/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/MemoryLimitExceededException.java
+++ b/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/MemoryLimitExceededException.java
@@ -17,31 +17,34 @@
 package androidx.javascriptengine;
 
 import androidx.annotation.NonNull;
+import androidx.core.util.Consumer;
+
+import java.util.concurrent.Executor;
 
 /**
- * Indicates that a JavaScriptIsolate's evaluation failed due to exceeding its heap size limit.
+ * Indicates that a JavaScriptIsolate's evaluation failed due to the isolate exceeding its heap
+ * size limit.
  * <p>
  * This exception may be thrown when exceeding the heap size limit configured for the isolate via
  * {@link IsolateStartupParameters}, or the default limit. Beware that it will not be thrown if the
  * Android system as a whole has run out of memory before the JavaScript environment has reached
  * its configured heap limit.
  * <p>
- * The isolate may not continue to be used after this exception has been thrown, and other pending
- * evaluations for the isolate will fail. The isolate may continue to hold onto resources (even if
- * explicitly closed) until the sandbox has been shutdown. Therefore, it is recommended that the
- * sandbox be restarted at the earliest opportunity in order to reclaim these resources.
+ * If an evaluation fails with a MemoryLimitExceededException, it does not imply that that
+ * particular evaluation was in any way responsible for any excessive memory usage.
+ * MemoryLimitExceededException will be raised for all unresolved and future requested evaluations
+ * regardless of their culpability.
  * <p>
- * Other isolates within the same sandbox may continue to be used, created, and closed as normal.
- * <p>
- * Beware that not all JavaScript sandbox service implementations (particularly older ones)
- * handle memory exhaustion equally gracefully, and may instead crash the entire sandbox (see
- * {@link SandboxDeadException}).
+ * An isolate may run out of memory outside of an explicit evaluation (such as in a microtask), so
+ * you should generally not use this exception to detect out of memory issues - instead, use
+ * {@link JavaScriptIsolate#addOnTerminatedCallback(Executor, Consumer)} and check
+ * for an isolate termination status of {@link TerminationInfo#STATUS_MEMORY_LIMIT_EXCEEDED}.
  */
-public final class MemoryLimitExceededException extends JavaScriptException {
-    public MemoryLimitExceededException(@NonNull String error) {
-        super(error);
-    }
+public final class MemoryLimitExceededException extends IsolateTerminatedException {
     public MemoryLimitExceededException() {
         super();
     }
+    public MemoryLimitExceededException(@NonNull String error) {
+        super(error);
+    }
 }
diff --git a/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/SandboxDeadException.java b/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/SandboxDeadException.java
index 229dee08..f3439b7 100644
--- a/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/SandboxDeadException.java
+++ b/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/SandboxDeadException.java
@@ -16,19 +16,20 @@
 
 package androidx.javascriptengine;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+
 /**
  * Exception thrown when evaluation is terminated due the {@link JavaScriptSandbox} being dead.
  * This can happen when {@link JavaScriptSandbox#close()} is called or when the sandbox process
  * is killed by the framework.
- * <p>
- * This is different from {@link IsolateTerminatedException} which occurs when the
- * {@link JavaScriptIsolate} within a {@link JavaScriptSandbox} is terminated.
- * <p>
- * This exception will continue to be thrown for all future evaluation requests on unclosed
- * isolates.
  */
-public final class SandboxDeadException extends JavaScriptException {
+public final class SandboxDeadException extends IsolateTerminatedException {
     public SandboxDeadException() {
         super();
     }
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    public SandboxDeadException(@NonNull String message) {
+        super(message);
+    }
 }
diff --git a/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/TerminationInfo.java b/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/TerminationInfo.java
new file mode 100644
index 0000000..fc828de
--- /dev/null
+++ b/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/TerminationInfo.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2023 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.javascriptengine;
+
+import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+
+import org.chromium.android_webview.js_sandbox.common.IJsSandboxIsolateClient;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Information about how and why an isolate has terminated.
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+public class TerminationInfo {
+    /**
+     * Termination status code for an isolate.
+     */
+    @IntDef({STATUS_UNKNOWN_ERROR, STATUS_SANDBOX_DEAD, STATUS_MEMORY_LIMIT_EXCEEDED})
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Status {
+    }
+
+    /**
+     * The isolate (but not necessarily the sandbox) has crashed for an unknown reason.
+     */
+    public static final int STATUS_UNKNOWN_ERROR = IJsSandboxIsolateClient.TERMINATE_UNKNOWN_ERROR;
+    /**
+     * The whole sandbox died (or was closed), taking this isolate with it.
+     */
+    public static final int STATUS_SANDBOX_DEAD = IJsSandboxIsolateClient.TERMINATE_SANDBOX_DEAD;
+    /**
+     * The isolate exceeded its heap size limit.
+     * <p>
+     * The isolate may continue to hold onto resources (even if explicitly closed) until the
+     * sandbox has been shutdown. If necessary, restart the sandbox at the earliest opportunity in
+     * order to reclaim these resources.
+     * <p>
+     * Note that memory exhaustion will kill the whole sandbox, so any other isolates within the
+     * same sandbox will be terminated with {@link #STATUS_SANDBOX_DEAD}.
+     */
+    public static final int STATUS_MEMORY_LIMIT_EXCEEDED =
+            IJsSandboxIsolateClient.TERMINATE_MEMORY_LIMIT_EXCEEDED;
+    @Status
+    private final int mStatus;
+    @NonNull
+    private final String mMessage;
+
+    TerminationInfo(@Status int status, @NonNull String message) {
+        mStatus = status;
+        mMessage = message;
+    }
+
+    /**
+     * Get the status code of the termination.
+     * <p>
+     * New status codes may be added with new JavaScriptEngine versions.
+     *
+     * @return status code of the termination.
+     */
+    @Status
+    public int getStatus() {
+        return mStatus;
+    }
+
+    /**
+     * Describe the status code of the termination.
+     * These strings are not stable between JavaScriptEngine versions.
+     *
+     * @return description of status code of the termination.
+     */
+    @NonNull
+    public String getStatusString() {
+        switch (mStatus) {
+            case STATUS_UNKNOWN_ERROR:
+                return "unknown error";
+            case STATUS_SANDBOX_DEAD:
+                return "sandbox dead";
+            case STATUS_MEMORY_LIMIT_EXCEEDED:
+                return "memory limit exceeded";
+            default:
+                return "unknown error code " + mStatus;
+        }
+    }
+
+    /**
+     * Get the message associated with this termination.
+     * The content or format of these messages is not stable between JavaScriptEngine versions.
+     *
+     * @return Human-readable message about the termination.
+     */
+    @NonNull
+    public String getMessage() {
+        return mMessage;
+    }
+
+    /**
+     * Describe the termination.
+     * The content or format of this description is not stable between JavaScriptEngine versions.
+     *
+     * @return Human-readable description of the termination.
+     */
+    @NonNull
+    @Override
+    public String toString() {
+        return getStatusString() + ": " + getMessage();
+    }
+
+    @NonNull
+    IsolateTerminatedException toJavaScriptException() {
+        switch (mStatus) {
+            case STATUS_SANDBOX_DEAD:
+                return new SandboxDeadException(this.toString());
+            case STATUS_MEMORY_LIMIT_EXCEEDED:
+                return new MemoryLimitExceededException(this.toString());
+            default:
+                return new IsolateTerminatedException(this.toString());
+        }
+    }
+}
diff --git a/javascriptengine/javascriptengine/src/main/stableAidl/org/chromium/android_webview/js_sandbox/common/IJsSandboxIsolateClient.aidl b/javascriptengine/javascriptengine/src/main/stableAidl/org/chromium/android_webview/js_sandbox/common/IJsSandboxIsolateClient.aidl
new file mode 100644
index 0000000..6574ae4
--- /dev/null
+++ b/javascriptengine/javascriptengine/src/main/stableAidl/org/chromium/android_webview/js_sandbox/common/IJsSandboxIsolateClient.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2023 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 org.chromium.android_webview.js_sandbox.common;
+
+/**
+ * Callbacks for isolate events, not specific to evaluations.
+ * @hide
+ */
+interface IJsSandboxIsolateClient {
+    // These crash codes may be generated on either the client or service side.
+
+    // The isolate terminated for an unknown reason.
+    const int TERMINATE_UNKNOWN_ERROR = 1;
+    // The sandbox died.
+    //
+    // This is typically generated client-side as the service may die before it gets a chance to
+    // send a message to the client.
+    const int TERMINATE_SANDBOX_DEAD = 2;
+    // The isolate exceeded its heap size limit.
+    const int TERMINATE_MEMORY_LIMIT_EXCEEDED = 3;
+
+    /**
+     * Informs the client that the isolate should now be considered terminated.
+     *
+     * @param status  A status code describing the reason for the termination. Must be one of the
+     *                constants beginning "TERMINATE_".
+     * @param message Unstructured information about the termination. May be null.
+     */
+    void onTerminated(int status, String message) = 1;
+}
diff --git a/javascriptengine/javascriptengine/src/main/stableAidl/org/chromium/android_webview/js_sandbox/common/IJsSandboxService.aidl b/javascriptengine/javascriptengine/src/main/stableAidl/org/chromium/android_webview/js_sandbox/common/IJsSandboxService.aidl
index 0453988..8afe48c 100644
--- a/javascriptengine/javascriptengine/src/main/stableAidl/org/chromium/android_webview/js_sandbox/common/IJsSandboxService.aidl
+++ b/javascriptengine/javascriptengine/src/main/stableAidl/org/chromium/android_webview/js_sandbox/common/IJsSandboxService.aidl
@@ -16,6 +16,7 @@
 
 package org.chromium.android_webview.js_sandbox.common;
 import org.chromium.android_webview.js_sandbox.common.IJsSandboxIsolate;
+import org.chromium.android_webview.js_sandbox.common.IJsSandboxIsolateClient;
 
 /**
  * Used by the embedding app to execute JavaScript in a sandboxed environment.
@@ -62,9 +63,21 @@
     const String CONSOLE_MESSAGING = "CONSOLE_MESSAGING";
 
     /**
+     * Feature flag indicating that the client may provide the service side with an
+     * IJsSandboxIsolateClient, allowing the service to call into the client regardless of ongoing
+     * evaluations.
+     */
+    const String ISOLATE_CLIENT = "ISOLATE_CLIENT";
+
+    /**
      * @return A list of feature names supported by this implementation.
      */
     List<String> getSupportedFeatures() = 1;
 
     IJsSandboxIsolate createIsolateWithMaxHeapSizeBytes(long maxHeapSize) = 2;
+
+    /**
+     * Create an isolate with a given heap size and service-to-client interface.
+     */
+    IJsSandboxIsolate createIsolate2(long maxHeapSize, IJsSandboxIsolateClient isolateClient) = 3;
 }
diff --git a/libraryversions.toml b/libraryversions.toml
index 0e3bb10..55a1d9a 100644
--- a/libraryversions.toml
+++ b/libraryversions.toml
@@ -44,6 +44,7 @@
 CORE_TELECOM = "1.0.0-alpha01"
 CORE_UWB = "1.0.0-alpha08"
 CREDENTIALS = "1.2.0-beta04"
+CREDENTIALS_FIDO_QUARANTINE = "1.0.0-alpha01"
 CURSORADAPTER = "1.1.0-alpha01"
 CUSTOMVIEW = "1.2.0-alpha03"
 CUSTOMVIEW_POOLINGCONTAINER = "1.1.0-alpha01"
@@ -201,6 +202,7 @@
 CORE_HAPTICS = { group = "androidx.core.haptics", atomicGroupVersion = "versions.CORE_HAPTICS" }
 CORE_UWB = { group = "androidx.core.uwb", atomicGroupVersion = "versions.CORE_UWB" }
 CREDENTIALS = { group = "androidx.credentials", atomicGroupVersion = "versions.CREDENTIALS" }
+CREDENTIALS_FIDO = { group = "androidx.credentials.credentials-fido", atomicGroupVersion = "versions.CREDENTIALS_FIDO_QUARANTINE" }
 CURSORADAPTER = { group = "androidx.cursoradapter", atomicGroupVersion = "versions.CURSORADAPTER" }
 CUSTOMVIEW = { group = "androidx.customview" }
 DATASTORE = { group = "androidx.datastore", atomicGroupVersion = "versions.DATASTORE" }
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/build.gradle b/privacysandbox/sdkruntime/sdkruntime-client/build.gradle
index 5de128a..e8985b4 100644
--- a/privacysandbox/sdkruntime/sdkruntime-client/build.gradle
+++ b/privacysandbox/sdkruntime/sdkruntime-client/build.gradle
@@ -92,7 +92,6 @@
 dependencies {
     api(libs.kotlinStdlib)
     api(libs.kotlinCoroutinesCore)
-    implementation(libs.multidex)
     implementation("androidx.core:core-ktx:1.12.0-alpha05")
 
     api project(path: ':privacysandbox:sdkruntime:sdkruntime-core')
diff --git a/privacysandbox/ui/ui-provider/src/main/java/androidx/privacysandbox/ui/provider/BinderAdapterDelegate.kt b/privacysandbox/ui/ui-provider/src/main/java/androidx/privacysandbox/ui/provider/BinderAdapterDelegate.kt
index 1acb8cc..6639148 100644
--- a/privacysandbox/ui/ui-provider/src/main/java/androidx/privacysandbox/ui/provider/BinderAdapterDelegate.kt
+++ b/privacysandbox/ui/ui-provider/src/main/java/androidx/privacysandbox/ui/provider/BinderAdapterDelegate.kt
@@ -26,6 +26,7 @@
 import android.os.Handler
 import android.os.IBinder
 import android.os.Looper
+import android.util.Log
 import android.view.SurfaceControlViewHost
 import androidx.annotation.RequiresApi
 import androidx.annotation.VisibleForTesting
@@ -56,6 +57,11 @@
     private val adapter: SandboxedUiAdapter
 ) : ISandboxedUiAdapter.Stub() {
 
+    companion object {
+        private const val TAG = "BinderAdapterDelegate"
+        private const val FRAME_TIMEOUT_MILLIS = 1000.toLong()
+    }
+
     fun openSession(
         context: Context,
         windowInputToken: IBinder,
@@ -121,13 +127,25 @@
                 surfaceControlViewHost.setView(view, initialWidth, initialHeight)
             }
 
-            val surfacePackage = surfaceControlViewHost.surfacePackage
-            val remoteSessionController =
-                RemoteSessionController(surfaceControlViewHost, session)
-            remoteSessionClient.onRemoteSessionOpened(
-                surfacePackage, remoteSessionController,
-                /* isZOrderOnTop= */ true
-            )
+            // This var is not locked as it will be set to false by the first event that can trigger
+            // sending the remote session opened callback.
+            var alreadyOpenedSession = false
+            view.viewTreeObserver.registerFrameCommitCallback {
+                if (!alreadyOpenedSession) {
+                    alreadyOpenedSession = true
+                    sendRemoteSessionOpened(session)
+                }
+            }
+
+            // If a frame commit callback is not triggered within the timeout (such as when the
+            // screen is off), open the session anyway.
+            Handler(Looper.getMainLooper()).postDelayed({
+                if (!alreadyOpenedSession) {
+                    Log.w(TAG, "Frame not committed within $FRAME_TIMEOUT_MILLIS ms.")
+                    alreadyOpenedSession = true
+                    sendRemoteSessionOpened(session)
+                }
+            }, FRAME_TIMEOUT_MILLIS)
         }
 
         override fun onSessionError(throwable: Throwable) {
@@ -138,6 +156,16 @@
             remoteSessionClient.onResizeRequested(width, height)
         }
 
+        private fun sendRemoteSessionOpened(session: SandboxedUiAdapter.Session) {
+            val surfacePackage = surfaceControlViewHost.surfacePackage
+            val remoteSessionController =
+                RemoteSessionController(surfaceControlViewHost, session)
+            remoteSessionClient.onRemoteSessionOpened(
+                surfacePackage, remoteSessionController,
+                /* isZOrderOnTop= */ true
+            )
+        }
+
         @VisibleForTesting
         private inner class RemoteSessionController(
             val surfaceControlViewHost: SurfaceControlViewHost,
diff --git a/privacysandbox/ui/ui-tests/src/androidTest/java/androidx/privacysandbox/ui/tests/endtoend/IntegrationTests.kt b/privacysandbox/ui/ui-tests/src/androidTest/java/androidx/privacysandbox/ui/tests/endtoend/IntegrationTests.kt
index ae63942..e1ba4e8 100644
--- a/privacysandbox/ui/ui-tests/src/androidTest/java/androidx/privacysandbox/ui/tests/endtoend/IntegrationTests.kt
+++ b/privacysandbox/ui/ui-tests/src/androidTest/java/androidx/privacysandbox/ui/tests/endtoend/IntegrationTests.kt
@@ -39,6 +39,7 @@
 import androidx.test.filters.MediumTest
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.testutils.withActivity
+import com.google.common.truth.Truth.assertThat
 import java.util.concurrent.CountDownLatch
 import java.util.concurrent.Executor
 import java.util.concurrent.TimeUnit
@@ -77,7 +78,7 @@
         errorLatch = CountDownLatch(1)
         stateChangeListener = TestStateChangeListener(errorLatch)
         view.addStateChangedListener(stateChangeListener)
-        activity.runOnUiThread(Runnable {
+        activity.runOnUiThread {
             val linearLayout = LinearLayout(context)
             linearLayout.layoutParams = LinearLayout.LayoutParams(
                 LinearLayout.LayoutParams.MATCH_PARENT,
@@ -86,7 +87,7 @@
             activity.setContentView(linearLayout)
             view.layoutParams = LinearLayout.LayoutParams(100, 100)
             linearLayout.addView(view)
-        })
+        }
     }
 
     @Ignore // b/271299184
@@ -166,7 +167,7 @@
         val adapter = TestSandboxedUiAdapter(openSessionLatch, null, false)
         val coreLibInfo = adapter.toCoreLibInfo(context)
         val adapterFromCoreLibInfo = SandboxedUiAdapterFactory.createFromCoreLibInfo(coreLibInfo)
-        var testSessionClient = TestSandboxedUiAdapter.TestSessionClient()
+        val testSessionClient = TestSandboxedUiAdapter.TestSessionClient()
 
         adapterFromCoreLibInfo.openSession(
             context,
@@ -178,10 +179,9 @@
             testSessionClient
         )
 
-        openSessionLatch.await(TIMEOUT, TimeUnit.MILLISECONDS)
-        assertTrue(openSessionLatch.count == 0.toLong())
-        assertTrue(adapter.isOpenSessionCalled)
-        assertTrue(testSessionClient.isSessionOpened)
+        assertThat(openSessionLatch.await(TIMEOUT, TimeUnit.MILLISECONDS)).isTrue()
+        assertThat(adapter.isOpenSessionCalled).isTrue()
+        assertThat(testSessionClient.isSessionOpened).isTrue()
     }
 
     @Test
@@ -312,11 +312,12 @@
         }
 
         class TestSessionClient : SandboxedUiAdapter.SessionClient {
-
-            var isSessionOpened = false
+            private val latch = CountDownLatch(1)
+            val isSessionOpened: Boolean
+                get() = latch.await(TIMEOUT, TimeUnit.MILLISECONDS)
 
             override fun onSessionOpened(session: SandboxedUiAdapter.Session) {
-                isSessionOpened = true
+                latch.countDown()
             }
 
             override fun onSessionError(throwable: Throwable) {
diff --git a/settings.gradle b/settings.gradle
index 75096da..7459ae1 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -707,6 +707,7 @@
 includeProject(":core:uwb:uwb-rxjava3", [BuildType.MAIN])
 includeProject(":credentials:credentials", [BuildType.MAIN])
 includeProject(":credentials:credentials-samples", "credentials/credentials/samples", [BuildType.MAIN])
+includeProject(":credentials:credentials-fido:credentials-fido", [BuildType.MAIN])
 includeProject(":credentials:credentials-play-services-auth", [BuildType.MAIN])
 includeProject(":credentials:credentials-provider", [BuildType.MAIN])
 includeProject(":cursoradapter:cursoradapter", [BuildType.MAIN])
diff --git a/tv/integration-tests/playground/src/main/baseline-prof.txt b/tv/integration-tests/playground/src/main/baseline-prof.txt
new file mode 100644
index 0000000..970cd8b
--- /dev/null
+++ b/tv/integration-tests/playground/src/main/baseline-prof.txt
@@ -0,0 +1,5623 @@
+HPLandroidx/collection/ArrayMap$EntrySet;-><init>(Ljava/util/Map;I)V
+HPLandroidx/compose/foundation/layout/SizeElement;->equals(Ljava/lang/Object;)Z
+HPLandroidx/compose/runtime/ComposerImpl$CompositionContextImpl;->unregisterComposer$runtime_release(Landroidx/compose/runtime/Composer;)V
+HPLandroidx/compose/runtime/ComposerImpl$CompositionContextImpl;->unregisterComposition$runtime_release(Landroidx/compose/runtime/CompositionImpl;)V
+HPLandroidx/compose/runtime/ComposerImpl;->dispose$runtime_release()V
+HPLandroidx/compose/runtime/CompositionImpl;->dispose()V
+HPLandroidx/compose/runtime/Recomposer;->unregisterComposition$runtime_release(Landroidx/compose/runtime/CompositionImpl;)V
+HPLandroidx/compose/runtime/SlotWriter$groupSlots$1;-><init>(IILandroidx/compose/runtime/SlotWriter;)V
+HPLandroidx/compose/runtime/SlotWriter$groupSlots$1;->hasNext()Z
+HPLandroidx/compose/runtime/SlotWriter$groupSlots$1;->next()Ljava/lang/Object;
+HPLandroidx/compose/runtime/SlotWriter;->removeGroup()Z
+HPLandroidx/compose/runtime/SlotWriter;->removeGroups(II)Z
+HPLandroidx/compose/runtime/SlotWriter;->removeSlots(III)V
+HPLandroidx/compose/runtime/SlotWriter;->skipGroup()I
+HPLandroidx/compose/runtime/internal/ComposableLambdaImpl;->trackRead(Landroidx/compose/runtime/Composer;)V
+HPLandroidx/compose/runtime/snapshots/TransparentObserverMutableSnapshot;->getCurrentSnapshot()Landroidx/compose/runtime/snapshots/MutableSnapshot;
+HPLandroidx/compose/ui/focus/FocusOwnerImpl$moveFocus$foundNextItem$1;->invoke(Landroidx/compose/ui/layout/BeyondBoundsLayout$BeyondBoundsScope;)Ljava/lang/Boolean;
+HPLandroidx/compose/ui/layout/Placeable$PlacementScope;->placeWithLayer-aW-9-wM$default(Landroidx/compose/ui/layout/Placeable$PlacementScope;Landroidx/compose/ui/layout/Placeable;J)V
+HPLandroidx/compose/ui/modifier/BackwardsCompatLocalMap;->get$ui_release(Landroidx/compose/ui/modifier/ProvidableModifierLocal;)Ljava/lang/Object;
+HPLandroidx/compose/ui/node/LayoutNode;->detach$ui_release()V
+HPLandroidx/compose/ui/node/LayoutNode;->onChildRemoved(Landroidx/compose/ui/node/LayoutNode;)V
+HPLandroidx/compose/ui/node/LayoutNode;->removeAll$ui_release()V
+HPLandroidx/compose/ui/node/LayoutNode;->removeAt$ui_release(II)V
+HPLandroidx/compose/ui/node/MeasureAndLayoutDelegate;->requestRemeasure(Landroidx/compose/ui/node/LayoutNode;Z)Z
+HPLandroidx/compose/ui/node/UiApplier;->clear()V
+HPLandroidx/compose/ui/platform/AndroidComposeView;->getFocusedRect(Landroid/graphics/Rect;)V
+HPLandroidx/tv/foundation/lazy/layout/LazyLayoutBeyondBoundsInfo$Interval;-><init>(II)V
+HPLandroidx/tv/foundation/lazy/list/LazyLayoutBeyondBoundsModifierLocal$layout$2;-><init>(Landroidx/tv/foundation/lazy/list/LazyLayoutBeyondBoundsModifierLocal;Lkotlin/jvm/internal/Ref$ObjectRef;I)V
+HPLandroidx/tv/foundation/lazy/list/LazyLayoutBeyondBoundsModifierLocal$layout$2;->getHasMoreContent()Z
+HPLandroidx/tv/foundation/lazy/list/LazyLayoutBeyondBoundsModifierLocal;->hasMoreContent-FR3nfPY(Landroidx/tv/foundation/lazy/layout/LazyLayoutBeyondBoundsInfo$Interval;I)Z
+HPLandroidx/tv/foundation/lazy/list/LazyLayoutBeyondBoundsModifierLocal;->isForward-4vf7U8o(I)Z
+HPLandroidx/tv/foundation/lazy/list/LazyListBeyondBoundsState;->getFirstPlacedIndex()I
+HPLandroidx/tv/foundation/lazy/list/LazyListBeyondBoundsState;->getHasVisibleItems()Z
+HPLandroidx/tv/foundation/lazy/list/LazyListBeyondBoundsState;->getItemCount()I
+HPLandroidx/tv/foundation/lazy/list/LazyListBeyondBoundsState;->getLastPlacedIndex()I
+HPLandroidx/tv/foundation/lazy/list/LazyListBeyondBoundsState;->remeasure()V
+HPLcom/example/tvcomposebasedtests/JankStatsAggregator;->issueJankReport(Ljava/lang/String;)V
+HPLcom/google/gson/Gson$3;->write(Lcom/google/gson/stream/JsonWriter;Ljava/lang/Boolean;)V
+HPLcom/google/gson/Gson$3;->write(Lcom/google/gson/stream/JsonWriter;Ljava/lang/Number;)V
+HPLcom/google/gson/Gson$3;->write(Lcom/google/gson/stream/JsonWriter;Ljava/lang/Object;)V
+HPLcom/google/gson/Gson;->getAdapter(Lcom/google/gson/reflect/TypeToken;)Lcom/google/gson/TypeAdapter;
+HPLcom/google/gson/JsonArray;-><init>()V
+HPLcom/google/gson/JsonArray;->iterator()Ljava/util/Iterator;
+HPLcom/google/gson/JsonObject;-><init>()V
+HPLcom/google/gson/JsonPrimitive;-><init>(Ljava/lang/Boolean;)V
+HPLcom/google/gson/JsonPrimitive;-><init>(Ljava/lang/Number;)V
+HPLcom/google/gson/JsonPrimitive;->getAsNumber()Ljava/lang/Number;
+HPLcom/google/gson/internal/LinkedTreeMap$LinkedTreeMapIterator;-><init>(Lcom/google/gson/internal/LinkedTreeMap;)V
+HPLcom/google/gson/internal/LinkedTreeMap$LinkedTreeMapIterator;->hasNext()Z
+HPLcom/google/gson/internal/LinkedTreeMap$Node;-><init>(Z)V
+HPLcom/google/gson/internal/LinkedTreeMap$Node;-><init>(ZLcom/google/gson/internal/LinkedTreeMap$Node;Ljava/lang/Object;Lcom/google/gson/internal/LinkedTreeMap$Node;Lcom/google/gson/internal/LinkedTreeMap$Node;)V
+HPLcom/google/gson/internal/LinkedTreeMap$Node;->getValue()Ljava/lang/Object;
+HPLcom/google/gson/internal/LinkedTreeMap;-><init>(Z)V
+HPLcom/google/gson/internal/LinkedTreeMap;->entrySet()Ljava/util/Set;
+HPLcom/google/gson/internal/LinkedTreeMap;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HPLcom/google/gson/internal/LinkedTreeMap;->rebalance(Lcom/google/gson/internal/LinkedTreeMap$Node;Z)V
+HPLcom/google/gson/internal/LinkedTreeMap;->replaceInParent(Lcom/google/gson/internal/LinkedTreeMap$Node;Lcom/google/gson/internal/LinkedTreeMap$Node;)V
+HPLcom/google/gson/internal/LinkedTreeMap;->rotateLeft(Lcom/google/gson/internal/LinkedTreeMap$Node;)V
+HPLcom/google/gson/internal/LinkedTreeMap;->rotateRight(Lcom/google/gson/internal/LinkedTreeMap$Node;)V
+HPLcom/google/gson/internal/bind/JsonTreeWriter;-><init>()V
+HPLcom/google/gson/internal/bind/JsonTreeWriter;->beginArray()V
+HPLcom/google/gson/internal/bind/JsonTreeWriter;->endArray()V
+HPLcom/google/gson/internal/bind/JsonTreeWriter;->endObject()V
+HPLcom/google/gson/internal/bind/JsonTreeWriter;->get()Lcom/google/gson/JsonElement;
+HPLcom/google/gson/internal/bind/JsonTreeWriter;->name(Ljava/lang/String;)V
+HPLcom/google/gson/internal/bind/JsonTreeWriter;->peek()Lcom/google/gson/JsonElement;
+HPLcom/google/gson/internal/bind/JsonTreeWriter;->put(Lcom/google/gson/JsonElement;)V
+HPLcom/google/gson/internal/bind/JsonTreeWriter;->value(J)V
+HPLcom/google/gson/internal/bind/ReflectiveTypeAdapterFactory$1;->write(Lcom/google/gson/stream/JsonWriter;Ljava/lang/Object;)V
+HPLcom/google/gson/internal/bind/ReflectiveTypeAdapterFactory$Adapter;->write(Lcom/google/gson/stream/JsonWriter;Ljava/lang/Object;)V
+HPLcom/google/gson/internal/bind/TypeAdapters$34$1;->write(Lcom/google/gson/stream/JsonWriter;Ljava/lang/Object;)V
+HPLcom/google/gson/internal/bind/TypeAdapters$EnumTypeAdapter;-><init>(Lcom/google/gson/Gson;Lcom/google/gson/TypeAdapter;Ljava/lang/reflect/Type;)V
+HPLcom/google/gson/reflect/TypeToken;-><init>(Ljava/lang/reflect/Type;)V
+HPLcom/google/gson/reflect/TypeToken;->equals(Ljava/lang/Object;)Z
+HPLcom/google/gson/reflect/TypeToken;->hashCode()I
+HPLcom/google/gson/stream/JsonWriter;-><init>(Ljava/io/Writer;)V
+HPLcom/google/gson/stream/JsonWriter;->beforeValue()V
+HPLcom/google/gson/stream/JsonWriter;->beginArray()V
+HPLcom/google/gson/stream/JsonWriter;->beginObject()V
+HPLcom/google/gson/stream/JsonWriter;->close(IIC)V
+HPLcom/google/gson/stream/JsonWriter;->endObject()V
+HPLcom/google/gson/stream/JsonWriter;->peek()I
+HPLcom/google/gson/stream/JsonWriter;->string(Ljava/lang/String;)V
+HPLcom/google/gson/stream/JsonWriter;->value(Ljava/lang/Number;)V
+HPLcom/google/gson/stream/JsonWriter;->value(Z)V
+HPLcom/google/gson/stream/JsonWriter;->writeDeferredName()V
+HPLkotlin/ResultKt;->canonicalize(Ljava/lang/reflect/Type;)Ljava/lang/reflect/Type;
+HPLkotlin/ResultKt;->getRawType(Ljava/lang/reflect/Type;)Ljava/lang/Class;
+HPLkotlin/TuplesKt;->fastFilter(Ljava/util/ArrayList;Lkotlin/jvm/functions/Function1;)Ljava/util/ArrayList;
+HPLkotlin/TuplesKt;->removeCurrentGroup(Landroidx/compose/runtime/SlotWriter;Landroidx/compose/runtime/CompositionImpl$RememberEventDispatcher;)V
+HPLkotlin/collections/ArrayDeque;->add(ILjava/lang/Object;)V
+HPLkotlin/collections/CollectionsKt___CollectionsKt;->first(Ljava/util/List;)Ljava/lang/Object;
+HSPL_COROUTINE/ArtificialStackFrames;-><init>(I)V
+HSPL_COROUTINE/ArtificialStackFrames;-><init>(II)V
+HSPLandroidx/activity/ComponentActivity$$ExternalSyntheticLambda0;-><init>(ILjava/lang/Object;)V
+HSPLandroidx/activity/ComponentActivity$$ExternalSyntheticLambda1;-><init>(Landroidx/activity/ComponentActivity;)V
+HSPLandroidx/activity/ComponentActivity$$ExternalSyntheticLambda2;-><init>(ILjava/lang/Object;)V
+HSPLandroidx/activity/ComponentActivity$$ExternalSyntheticLambda3;-><init>(Landroidx/activity/ComponentActivity;)V
+HSPLandroidx/activity/ComponentActivity$$ExternalSyntheticLambda3;->onContextAvailable()V
+HSPLandroidx/activity/ComponentActivity$1;-><init>(Landroid/view/KeyEvent$Callback;I)V
+HSPLandroidx/activity/ComponentActivity$2;-><init>()V
+HSPLandroidx/activity/ComponentActivity$3;-><init>(Landroidx/activity/ComponentActivity;)V
+HSPLandroidx/activity/ComponentActivity$3;->onStateChanged(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V
+HSPLandroidx/activity/ComponentActivity$4;-><init>(Landroidx/activity/ComponentActivity;)V
+HSPLandroidx/activity/ComponentActivity$4;->onStateChanged(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V
+HSPLandroidx/activity/ComponentActivity$5;-><init>(Landroidx/activity/ComponentActivity;)V
+HSPLandroidx/activity/ComponentActivity$5;->onStateChanged(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V
+HSPLandroidx/activity/ComponentActivity$ReportFullyDrawnExecutorApi16Impl;-><init>(Landroidx/activity/ComponentActivity;)V
+HSPLandroidx/activity/ComponentActivity$ReportFullyDrawnExecutorApi16Impl;->onDraw()V
+HSPLandroidx/activity/ComponentActivity$ReportFullyDrawnExecutorApi16Impl;->viewCreated(Landroid/view/View;)V
+HSPLandroidx/activity/ComponentActivity;-><init>()V
+HSPLandroidx/activity/ComponentActivity;->ensureViewModelStore()V
+HSPLandroidx/activity/ComponentActivity;->getLifecycle()Landroidx/lifecycle/LifecycleRegistry;
+HSPLandroidx/activity/ComponentActivity;->getViewModelStore()Landroidx/lifecycle/ViewModelStore;
+HSPLandroidx/activity/ComponentActivity;->initViewTreeOwners()V
+HSPLandroidx/activity/ComponentActivity;->onCreate(Landroid/os/Bundle;)V
+HSPLandroidx/activity/ComponentActivity;->setContentView(Landroid/view/View;Landroid/view/ViewGroup$LayoutParams;)V
+HSPLandroidx/activity/FullyDrawnReporter;-><init>(Landroidx/activity/ComponentActivity$ReportFullyDrawnExecutorApi16Impl;Landroidx/activity/ComponentActivity$$ExternalSyntheticLambda1;)V
+HSPLandroidx/activity/OnBackPressedDispatcher;-><init>(Landroidx/activity/ComponentActivity$1;)V
+HSPLandroidx/activity/compose/ComponentActivityKt;-><clinit>()V
+HSPLandroidx/activity/compose/ComponentActivityKt;->setContent$default(Landroidx/activity/ComponentActivity;Landroidx/compose/runtime/internal/ComposableLambdaImpl;)V
+HSPLandroidx/activity/contextaware/ContextAwareHelper;-><init>()V
+HSPLandroidx/activity/result/ActivityResult$1;-><init>(I)V
+HSPLandroidx/arch/core/executor/ArchTaskExecutor;-><init>()V
+HSPLandroidx/arch/core/executor/ArchTaskExecutor;->getInstance()Landroidx/arch/core/executor/ArchTaskExecutor;
+HSPLandroidx/arch/core/executor/DefaultTaskExecutor$1;-><init>()V
+HSPLandroidx/arch/core/executor/DefaultTaskExecutor;-><init>()V
+HSPLandroidx/arch/core/internal/FastSafeIterableMap;-><init>()V
+HSPLandroidx/arch/core/internal/FastSafeIterableMap;->get(Ljava/lang/Object;)Landroidx/arch/core/internal/SafeIterableMap$Entry;
+HSPLandroidx/arch/core/internal/FastSafeIterableMap;->remove(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/arch/core/internal/SafeIterableMap$AscendingIterator;-><init>(Landroidx/arch/core/internal/SafeIterableMap$Entry;Landroidx/arch/core/internal/SafeIterableMap$Entry;I)V
+HSPLandroidx/arch/core/internal/SafeIterableMap$Entry;-><init>(Ljava/lang/Object;Ljava/lang/Object;)V
+HSPLandroidx/arch/core/internal/SafeIterableMap$Entry;->getKey()Ljava/lang/Object;
+HSPLandroidx/arch/core/internal/SafeIterableMap$Entry;->getValue()Ljava/lang/Object;
+HSPLandroidx/arch/core/internal/SafeIterableMap$IteratorWithAdditions;-><init>(Landroidx/arch/core/internal/SafeIterableMap;)V
+HSPLandroidx/arch/core/internal/SafeIterableMap$IteratorWithAdditions;->hasNext()Z
+HSPLandroidx/arch/core/internal/SafeIterableMap$IteratorWithAdditions;->next()Ljava/lang/Object;
+HSPLandroidx/arch/core/internal/SafeIterableMap$IteratorWithAdditions;->supportRemove(Landroidx/arch/core/internal/SafeIterableMap$Entry;)V
+HSPLandroidx/arch/core/internal/SafeIterableMap$ListIterator;-><init>(Landroidx/arch/core/internal/SafeIterableMap$Entry;Landroidx/arch/core/internal/SafeIterableMap$Entry;)V
+HSPLandroidx/arch/core/internal/SafeIterableMap$ListIterator;->hasNext()Z
+HSPLandroidx/arch/core/internal/SafeIterableMap;-><init>()V
+HSPLandroidx/arch/core/internal/SafeIterableMap;->get(Ljava/lang/Object;)Landroidx/arch/core/internal/SafeIterableMap$Entry;
+HSPLandroidx/arch/core/internal/SafeIterableMap;->iterator()Ljava/util/Iterator;
+HSPLandroidx/arch/core/internal/SafeIterableMap;->remove(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/collection/ArraySet;-><clinit>()V
+HSPLandroidx/collection/ArraySet;-><init>()V
+HSPLandroidx/collection/ArraySet;->add(Ljava/lang/Object;)Z
+HSPLandroidx/collection/ArraySet;->allocArrays(I)V
+HSPLandroidx/collection/ArraySet;->clear()V
+HSPLandroidx/collection/ArraySet;->freeArrays([I[Ljava/lang/Object;I)V
+HSPLandroidx/collection/ArraySet;->indexOf(ILjava/lang/Object;)I
+HSPLandroidx/collection/ArraySet;->toArray()[Ljava/lang/Object;
+HSPLandroidx/collection/LongSparseArray;-><clinit>()V
+HSPLandroidx/collection/LongSparseArray;-><init>(I)V
+HSPLandroidx/collection/SimpleArrayMap;-><init>()V
+HSPLandroidx/collection/SparseArrayCompat;-><clinit>()V
+HSPLandroidx/collection/SparseArrayCompat;-><init>()V
+HSPLandroidx/compose/animation/FlingCalculator;-><init>(FLandroidx/compose/ui/unit/Density;)V
+HSPLandroidx/compose/animation/FlingCalculatorKt;-><clinit>()V
+HSPLandroidx/compose/animation/SingleValueAnimationKt;-><clinit>()V
+HSPLandroidx/compose/animation/SingleValueAnimationKt;->animateColorAsState-euL9pac(JLjava/lang/String;Landroidx/compose/runtime/Composer;I)Landroidx/compose/runtime/State;
+HSPLandroidx/compose/animation/SplineBasedFloatDecayAnimationSpec;-><init>(Landroidx/compose/ui/unit/Density;)V
+HSPLandroidx/compose/animation/SplineBasedFloatDecayAnimationSpec_androidKt;-><clinit>()V
+HSPLandroidx/compose/animation/core/Animatable$runAnimation$2;-><init>(Landroidx/compose/animation/core/Animatable;Ljava/lang/Object;Landroidx/compose/animation/core/Animation;JLkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/animation/core/Animatable$runAnimation$2;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/Animatable$runAnimation$2;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/Animatable;-><init>(Ljava/lang/Object;Landroidx/compose/animation/core/TwoWayConverterImpl;Ljava/lang/Object;)V
+HSPLandroidx/compose/animation/core/Animatable;->animateTo$default(Landroidx/compose/animation/core/Animatable;Ljava/lang/Object;Landroidx/compose/animation/core/AnimationSpec;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/Animatable;->getValue()Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/AnimateAsStateKt$animateValueAsState$2;-><init>(Lkotlinx/coroutines/channels/Channel;Ljava/lang/Object;)V
+HSPLandroidx/compose/animation/core/AnimateAsStateKt$animateValueAsState$2;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/AnimateAsStateKt$animateValueAsState$3$1;-><init>(Ljava/lang/Object;Landroidx/compose/animation/core/Animatable;Landroidx/compose/runtime/State;Landroidx/compose/runtime/State;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/animation/core/AnimateAsStateKt$animateValueAsState$3$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/animation/core/AnimateAsStateKt$animateValueAsState$3$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/AnimateAsStateKt$animateValueAsState$3;-><init>(Lkotlinx/coroutines/channels/Channel;Landroidx/compose/animation/core/Animatable;Landroidx/compose/runtime/State;Landroidx/compose/runtime/State;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/animation/core/AnimateAsStateKt$animateValueAsState$3;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/animation/core/AnimateAsStateKt$animateValueAsState$3;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/AnimateAsStateKt;-><clinit>()V
+HSPLandroidx/compose/animation/core/AnimateAsStateKt;->animateDpAsState-AjpBEmI(FLjava/lang/String;Landroidx/compose/runtime/Composer;II)Landroidx/compose/runtime/State;
+HSPLandroidx/compose/animation/core/AnimateAsStateKt;->animateFloatAsState(FLandroidx/compose/animation/core/TweenSpec;Ljava/lang/String;Landroidx/compose/runtime/Composer;II)Landroidx/compose/runtime/State;
+HSPLandroidx/compose/animation/core/AnimateAsStateKt;->animateValueAsState(Ljava/lang/Object;Landroidx/compose/animation/core/TwoWayConverterImpl;Landroidx/compose/animation/core/AnimationSpec;Ljava/lang/Float;Ljava/lang/String;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;II)Landroidx/compose/runtime/State;
+HSPLandroidx/compose/animation/core/Animation;->isFinishedFromNanos(J)Z
+HSPLandroidx/compose/animation/core/AnimationEndReason$EnumUnboxingLocalUtility;-><clinit>()V
+HSPLandroidx/compose/animation/core/AnimationEndReason$EnumUnboxingLocalUtility;->compareTo(II)I
+HSPLandroidx/compose/animation/core/AnimationEndReason$EnumUnboxingLocalUtility;->ordinal(I)I
+HSPLandroidx/compose/animation/core/AnimationEndReason$EnumUnboxingLocalUtility;->values(I)[I
+HSPLandroidx/compose/animation/core/AnimationResult;-><init>(Landroidx/compose/animation/core/AnimationState;I)V
+HSPLandroidx/compose/animation/core/AnimationScope;-><init>(Ljava/lang/Object;Landroidx/compose/animation/core/TwoWayConverterImpl;Landroidx/compose/animation/core/AnimationVector;JLjava/lang/Object;JLandroidx/compose/animation/core/SuspendAnimationKt$animate$7;)V
+HSPLandroidx/compose/animation/core/AnimationScope;->getValue()Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/AnimationState;-><init>(Landroidx/compose/animation/core/TwoWayConverterImpl;Ljava/lang/Object;Landroidx/compose/animation/core/AnimationVector;I)V
+HSPLandroidx/compose/animation/core/AnimationState;-><init>(Landroidx/compose/animation/core/TwoWayConverterImpl;Ljava/lang/Object;Landroidx/compose/animation/core/AnimationVector;JJZ)V
+HSPLandroidx/compose/animation/core/AnimationState;->getValue()Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/AnimationVector1D;-><init>(F)V
+HSPLandroidx/compose/animation/core/AnimationVector1D;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/animation/core/AnimationVector1D;->get$animation_core_release(I)F
+HSPLandroidx/compose/animation/core/AnimationVector1D;->getSize$animation_core_release()I
+HSPLandroidx/compose/animation/core/AnimationVector1D;->newVector$animation_core_release()Landroidx/compose/animation/core/AnimationVector;
+HSPLandroidx/compose/animation/core/AnimationVector1D;->reset$animation_core_release()V
+HSPLandroidx/compose/animation/core/AnimationVector1D;->set$animation_core_release(FI)V
+HSPLandroidx/compose/animation/core/AnimationVector2D;-><init>(FF)V
+HSPLandroidx/compose/animation/core/AnimationVector3D;-><init>(FFF)V
+HSPLandroidx/compose/animation/core/AnimationVector4D;-><init>(FFFF)V
+HSPLandroidx/compose/animation/core/AnimationVector4D;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/animation/core/AnimationVector4D;->get$animation_core_release(I)F
+HSPLandroidx/compose/animation/core/AnimationVector4D;->getSize$animation_core_release()I
+HSPLandroidx/compose/animation/core/AnimationVector4D;->newVector$animation_core_release()Landroidx/compose/animation/core/AnimationVector;
+HSPLandroidx/compose/animation/core/AnimationVector4D;->reset$animation_core_release()V
+HSPLandroidx/compose/animation/core/AnimationVector4D;->set$animation_core_release(FI)V
+HSPLandroidx/compose/animation/core/ComplexDouble;-><init>(DD)V
+HSPLandroidx/compose/animation/core/CubicBezierEasing;-><init>(FFF)V
+HSPLandroidx/compose/animation/core/CubicBezierEasing;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/animation/core/CubicBezierEasing;->transform(F)F
+HSPLandroidx/compose/animation/core/DecayAnimationSpecImpl;-><init>(Landroidx/compose/animation/SplineBasedFloatDecayAnimationSpec;)V
+HSPLandroidx/compose/animation/core/EasingKt;-><clinit>()V
+HSPLandroidx/compose/animation/core/FloatSpringSpec;-><init>(FFF)V
+HSPLandroidx/compose/animation/core/FloatSpringSpec;->getDurationNanos(FFF)J
+HSPLandroidx/compose/animation/core/FloatSpringSpec;->getEndVelocity(FFF)F
+HSPLandroidx/compose/animation/core/FloatSpringSpec;->getValueFromNanos(JFFF)F
+HSPLandroidx/compose/animation/core/FloatSpringSpec;->getVelocityFromNanos(JFFF)F
+HSPLandroidx/compose/animation/core/FloatTweenSpec;-><init>(IILandroidx/compose/animation/core/Easing;)V
+HSPLandroidx/compose/animation/core/FloatTweenSpec;->getValueFromNanos(JFFF)F
+HSPLandroidx/compose/animation/core/FloatTweenSpec;->getVelocityFromNanos(JFFF)F
+HSPLandroidx/compose/animation/core/MutatorMutex$Mutator;-><init>(ILkotlinx/coroutines/Job;)V
+HSPLandroidx/compose/animation/core/MutatorMutex$mutate$2;-><init>(ILandroidx/compose/animation/core/MutatorMutex;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/animation/core/MutatorMutex$mutate$2;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/animation/core/MutatorMutex$mutate$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/MutatorMutex$mutate$2;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/MutatorMutex;-><init>()V
+HSPLandroidx/compose/animation/core/SpringSimulation;-><init>()V
+HSPLandroidx/compose/animation/core/SpringSimulation;->updateValues-IJZedt4$animation_core_release(FFJ)J
+HSPLandroidx/compose/animation/core/SpringSpec;-><init>(FFLjava/lang/Object;)V
+HSPLandroidx/compose/animation/core/SpringSpec;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/animation/core/SpringSpec;->vectorize(Landroidx/compose/animation/core/TwoWayConverterImpl;)Landroidx/compose/animation/core/VectorizedFiniteAnimationSpec;
+HSPLandroidx/compose/animation/core/SuspendAnimationKt$animate$4;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/SuspendAnimationKt$animate$6;-><init>(Lkotlin/jvm/internal/Ref$ObjectRef;Ljava/lang/Object;Landroidx/compose/animation/core/Animation;Landroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationState;FLkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/animation/core/SuspendAnimationKt$animate$6;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/SuspendAnimationKt$animate$7;-><init>(Landroidx/compose/animation/core/AnimationState;I)V
+HSPLandroidx/compose/animation/core/SuspendAnimationKt$animate$9;-><init>(Lkotlin/jvm/internal/Ref$ObjectRef;FLandroidx/compose/animation/core/Animation;Landroidx/compose/animation/core/AnimationState;Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/animation/core/SuspendAnimationKt$animate$9;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/TargetBasedAnimation;-><init>(Landroidx/compose/animation/core/AnimationSpec;Landroidx/compose/animation/core/TwoWayConverterImpl;Ljava/lang/Object;Ljava/lang/Object;Landroidx/compose/animation/core/AnimationVector;)V
+HSPLandroidx/compose/animation/core/TargetBasedAnimation;->getDurationNanos()J
+HSPLandroidx/compose/animation/core/TargetBasedAnimation;->getTargetValue()Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/TargetBasedAnimation;->getTypeConverter()Landroidx/compose/animation/core/TwoWayConverterImpl;
+HSPLandroidx/compose/animation/core/TargetBasedAnimation;->getValueFromNanos(J)Ljava/lang/Object;
+HSPLandroidx/compose/animation/core/TargetBasedAnimation;->getVelocityVectorFromNanos(J)Landroidx/compose/animation/core/AnimationVector;
+HSPLandroidx/compose/animation/core/TargetBasedAnimation;->isInfinite()Z
+HSPLandroidx/compose/animation/core/TweenSpec;-><init>(IILandroidx/compose/animation/core/Easing;)V
+HSPLandroidx/compose/animation/core/TweenSpec;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/animation/core/TweenSpec;->vectorize(Landroidx/compose/animation/core/TwoWayConverterImpl;)Landroidx/compose/animation/core/VectorizedFiniteAnimationSpec;
+HSPLandroidx/compose/animation/core/TwoWayConverterImpl;-><init>(Landroidx/compose/foundation/ImageKt$Image$1$1;Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/animation/core/VectorConvertersKt;-><clinit>()V
+HSPLandroidx/compose/animation/core/VectorizedFloatAnimationSpec;-><init>(Landroidx/compose/animation/core/FloatAnimationSpec;)V
+HSPLandroidx/compose/animation/core/VectorizedFloatAnimationSpec;-><init>(Landroidx/compose/ui/input/pointer/util/PointerIdArray;)V
+HSPLandroidx/compose/animation/core/VectorizedFloatAnimationSpec;->getDurationNanos(Landroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;)J
+HSPLandroidx/compose/animation/core/VectorizedFloatAnimationSpec;->getEndVelocity(Landroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;)Landroidx/compose/animation/core/AnimationVector;
+HSPLandroidx/compose/animation/core/VectorizedFloatAnimationSpec;->getValueFromNanos(JLandroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;)Landroidx/compose/animation/core/AnimationVector;
+HSPLandroidx/compose/animation/core/VectorizedFloatAnimationSpec;->getVelocityFromNanos(JLandroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;)Landroidx/compose/animation/core/AnimationVector;
+HSPLandroidx/compose/animation/core/VectorizedSpringSpec;-><init>(FFLandroidx/compose/animation/core/AnimationVector;)V
+HSPLandroidx/compose/animation/core/VectorizedSpringSpec;->getDurationNanos(Landroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;)J
+HSPLandroidx/compose/animation/core/VectorizedSpringSpec;->getEndVelocity(Landroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;)Landroidx/compose/animation/core/AnimationVector;
+HSPLandroidx/compose/animation/core/VectorizedSpringSpec;->getValueFromNanos(JLandroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;)Landroidx/compose/animation/core/AnimationVector;
+HSPLandroidx/compose/animation/core/VectorizedSpringSpec;->getVelocityFromNanos(JLandroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;)Landroidx/compose/animation/core/AnimationVector;
+HSPLandroidx/compose/animation/core/VectorizedSpringSpec;->isInfinite()V
+HSPLandroidx/compose/animation/core/VectorizedTweenSpec;-><init>(IILandroidx/compose/animation/core/Easing;)V
+HSPLandroidx/compose/animation/core/VectorizedTweenSpec;->getValueFromNanos(JLandroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;)Landroidx/compose/animation/core/AnimationVector;
+HSPLandroidx/compose/animation/core/VectorizedTweenSpec;->getVelocityFromNanos(JLandroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;Landroidx/compose/animation/core/AnimationVector;)Landroidx/compose/animation/core/AnimationVector;
+HSPLandroidx/compose/animation/core/VisibilityThresholdsKt;-><clinit>()V
+HSPLandroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect$effectModifier$1;-><init>(Landroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect$onNewSize$1;-><init>(Landroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;)V
+HSPLandroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect$onNewSize$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;-><init>(Landroid/content/Context;Landroidx/compose/foundation/OverscrollConfiguration;)V
+HSPLandroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;->animateToRelease()V
+HSPLandroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;->getEffectModifier()Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;->invalidateOverscroll()V
+HSPLandroidx/compose/foundation/AndroidOverscrollKt;-><clinit>()V
+HSPLandroidx/compose/foundation/Api31Impl;-><clinit>()V
+HSPLandroidx/compose/foundation/Api31Impl;->create(Landroid/content/Context;Landroid/util/AttributeSet;)Landroid/widget/EdgeEffect;
+HSPLandroidx/compose/foundation/Api31Impl;->getDistance(Landroid/widget/EdgeEffect;)F
+HSPLandroidx/compose/foundation/BackgroundElement;-><init>(JLandroidx/compose/ui/graphics/Shape;)V
+HSPLandroidx/compose/foundation/BackgroundElement;->create()Landroidx/compose/ui/Modifier$Node;
+HSPLandroidx/compose/foundation/BackgroundElement;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/foundation/BackgroundElement;->update(Landroidx/compose/ui/Modifier$Node;)V
+HSPLandroidx/compose/foundation/BackgroundNode;-><init>(JLandroidx/compose/ui/graphics/Brush;FLandroidx/compose/ui/graphics/Shape;)V
+HSPLandroidx/compose/foundation/BackgroundNode;->draw(Landroidx/compose/ui/graphics/drawscope/ContentDrawScope;)V
+HSPLandroidx/compose/foundation/BorderKt$drawRectBorder$1;-><init>(Landroidx/compose/ui/graphics/Brush;JJLkotlin/ResultKt;)V
+HSPLandroidx/compose/foundation/BorderKt$drawRectBorder$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/BorderModifierNode;-><init>(FLandroidx/compose/ui/graphics/Brush;Landroidx/compose/ui/graphics/Shape;)V
+HSPLandroidx/compose/foundation/BorderModifierNodeElement;-><init>(FLandroidx/compose/ui/graphics/Brush;Landroidx/compose/ui/graphics/Shape;)V
+HSPLandroidx/compose/foundation/BorderModifierNodeElement;->create()Landroidx/compose/ui/Modifier$Node;
+HSPLandroidx/compose/foundation/BorderModifierNodeElement;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/foundation/BorderModifierNodeElement;->update(Landroidx/compose/ui/Modifier$Node;)V
+HSPLandroidx/compose/foundation/BorderStroke;-><init>(FLandroidx/compose/ui/graphics/SolidColor;)V
+HSPLandroidx/compose/foundation/ClipScrollableContainerKt;-><clinit>()V
+HSPLandroidx/compose/foundation/DrawOverscrollModifier;-><init>(Landroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;)V
+HSPLandroidx/compose/foundation/DrawOverscrollModifier;->draw(Landroidx/compose/ui/graphics/drawscope/ContentDrawScope;)V
+HSPLandroidx/compose/foundation/FocusableElement;-><init>(Landroidx/compose/foundation/interaction/MutableInteractionSourceImpl;)V
+HSPLandroidx/compose/foundation/FocusableElement;->create()Landroidx/compose/ui/Modifier$Node;
+HSPLandroidx/compose/foundation/FocusableElement;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/foundation/FocusableInteractionNode$emitWithFallback$1;-><init>(Landroidx/compose/foundation/interaction/MutableInteractionSourceImpl;Landroidx/compose/foundation/interaction/Interaction;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/foundation/FocusableInteractionNode$emitWithFallback$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/foundation/FocusableInteractionNode$emitWithFallback$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/FocusableInteractionNode;-><init>(Landroidx/compose/foundation/interaction/MutableInteractionSourceImpl;)V
+HSPLandroidx/compose/foundation/FocusableInteractionNode;->emitWithFallback(Landroidx/compose/foundation/interaction/MutableInteractionSourceImpl;Landroidx/compose/foundation/interaction/Interaction;)V
+HSPLandroidx/compose/foundation/FocusableKt$FocusableInNonTouchModeElement$1;-><init>()V
+HSPLandroidx/compose/foundation/FocusableKt;-><clinit>()V
+HSPLandroidx/compose/foundation/FocusableKt;->focusable$default(Landroidx/compose/ui/Modifier;Landroidx/compose/foundation/interaction/MutableInteractionSourceImpl;I)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/FocusableNode$onFocusEvent$1;-><init>(Landroidx/compose/foundation/FocusableNode;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/foundation/FocusableNode$onFocusEvent$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/foundation/FocusableNode$onFocusEvent$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/FocusableNode;-><init>(Landroidx/compose/foundation/interaction/MutableInteractionSourceImpl;)V
+HSPLandroidx/compose/foundation/FocusableNode;->onFocusEvent(Landroidx/compose/ui/focus/FocusStateImpl;)V
+HSPLandroidx/compose/foundation/FocusableNode;->onGloballyPositioned(Landroidx/compose/ui/node/NodeCoordinator;)V
+HSPLandroidx/compose/foundation/FocusableNode;->onPlaced(Landroidx/compose/ui/node/NodeCoordinator;)V
+HSPLandroidx/compose/foundation/FocusablePinnableContainerNode;->onReset()V
+HSPLandroidx/compose/foundation/FocusableSemanticsNode;-><init>()V
+HSPLandroidx/compose/foundation/FocusedBoundsKt;-><clinit>()V
+HSPLandroidx/compose/foundation/FocusedBoundsNode;->onGloballyPositioned(Landroidx/compose/ui/node/NodeCoordinator;)V
+HSPLandroidx/compose/foundation/FocusedBoundsObserverNode;-><init>(Lkotlin/collections/AbstractMap$toString$1;)V
+HSPLandroidx/compose/foundation/FocusedBoundsObserverNode;->getProvidedValues()Landroidx/tv/material3/TabKt;
+HSPLandroidx/compose/foundation/FocusedBoundsObserverNode;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/ImageKt$Image$1$1;-><clinit>()V
+HSPLandroidx/compose/foundation/ImageKt$Image$1$1;-><init>(I)V
+HSPLandroidx/compose/foundation/ImageKt$Image$1$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/ImageKt$Image$1;-><clinit>()V
+HSPLandroidx/compose/foundation/ImageKt$Image$1;->measure-3p2s80s(Landroidx/compose/ui/layout/MeasureScope;Ljava/util/List;J)Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/compose/foundation/ImageKt;->Image(Landroidx/compose/ui/graphics/painter/Painter;Ljava/lang/String;Landroidx/compose/ui/Modifier;Landroidx/compose/ui/Alignment;Landroidx/compose/ui/layout/ContentScale;FLandroidx/compose/ui/graphics/BlendModeColorFilter;Landroidx/compose/runtime/Composer;II)V
+HSPLandroidx/compose/foundation/ImageKt;->background-bw27NRU(Landroidx/compose/ui/Modifier;JLandroidx/compose/ui/graphics/Shape;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/ImageKt;->checkScrollableContainerConstraints-K40F9xA(JLandroidx/compose/foundation/gestures/Orientation;)V
+HSPLandroidx/compose/foundation/ImageKt;->create(Landroid/content/Context;)Landroid/widget/EdgeEffect;
+HSPLandroidx/compose/foundation/ImageKt;->getDistanceCompat(Landroid/widget/EdgeEffect;)F
+HSPLandroidx/compose/foundation/IndicationKt$indication$2;-><init>(Ljava/lang/Object;ILjava/lang/Object;)V
+HSPLandroidx/compose/foundation/IndicationKt$indication$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/IndicationKt;-><clinit>()V
+HSPLandroidx/compose/foundation/IndicationModifier;-><init>(Landroidx/compose/foundation/IndicationInstance;)V
+HSPLandroidx/compose/foundation/IndicationModifier;->draw(Landroidx/compose/ui/graphics/drawscope/ContentDrawScope;)V
+HSPLandroidx/compose/foundation/MutatePriority;-><clinit>()V
+HSPLandroidx/compose/foundation/MutatePriority;-><init>(ILjava/lang/String;)V
+HSPLandroidx/compose/foundation/MutatorMutex$Mutator;-><init>(Landroidx/compose/foundation/MutatePriority;Lkotlinx/coroutines/Job;)V
+HSPLandroidx/compose/foundation/MutatorMutex$mutateWith$2;-><init>(Landroidx/compose/foundation/MutatePriority;Landroidx/compose/foundation/MutatorMutex;Lkotlin/jvm/functions/Function2;Ljava/lang/Object;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/foundation/MutatorMutex$mutateWith$2;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/foundation/MutatorMutex$mutateWith$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/MutatorMutex$mutateWith$2;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/MutatorMutex;-><init>()V
+HSPLandroidx/compose/foundation/OverscrollConfiguration;-><init>()V
+HSPLandroidx/compose/foundation/OverscrollConfigurationKt;-><clinit>()V
+HSPLandroidx/compose/foundation/ScrollKt$rememberScrollState$1$1;-><init>(I)V
+HSPLandroidx/compose/foundation/ScrollKt$rememberScrollState$1$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/foundation/ScrollKt$scroll$2$semantics$1$1;-><init>(ZLkotlinx/coroutines/CoroutineScope;Landroidx/tv/foundation/lazy/layout/LazyLayoutSemanticState;)V
+HSPLandroidx/compose/foundation/ScrollKt$scroll$2$semantics$1;-><init>(ZZZLandroidx/compose/foundation/ScrollState;Lkotlinx/coroutines/CoroutineScope;)V
+HSPLandroidx/compose/foundation/ScrollKt$scroll$2;-><init>(Landroidx/compose/foundation/ScrollState;Landroidx/compose/foundation/gestures/FlingBehavior;ZZ)V
+HSPLandroidx/compose/foundation/ScrollKt$scroll$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/ScrollState$canScrollForward$2;-><init>(Landroidx/compose/foundation/ScrollState;I)V
+HSPLandroidx/compose/foundation/ScrollState;-><clinit>()V
+HSPLandroidx/compose/foundation/ScrollState;-><init>(I)V
+HSPLandroidx/compose/foundation/ScrollState;->getValue()I
+HSPLandroidx/compose/foundation/ScrollingLayoutElement;-><init>(Landroidx/compose/foundation/ScrollState;ZZ)V
+HSPLandroidx/compose/foundation/ScrollingLayoutElement;->create()Landroidx/compose/ui/Modifier$Node;
+HSPLandroidx/compose/foundation/ScrollingLayoutNode;-><init>(Landroidx/compose/foundation/ScrollState;ZZ)V
+HSPLandroidx/compose/foundation/ScrollingLayoutNode;->measure-3p2s80s(Landroidx/compose/ui/layout/MeasureScope;Landroidx/compose/ui/layout/Measurable;J)Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/compose/foundation/gestures/BringIntoViewRequestPriorityQueue;-><init>()V
+HSPLandroidx/compose/foundation/gestures/BringIntoViewRequestPriorityQueue;->cancelAndRemoveAll(Ljava/util/concurrent/CancellationException;)V
+HSPLandroidx/compose/foundation/gestures/BringIntoViewSpec$Companion$DefaultBringIntoViewSpec$1;-><init>()V
+HSPLandroidx/compose/foundation/gestures/BringIntoViewSpec$Companion$DefaultBringIntoViewSpec$1;->calculateScrollDistance(FFF)F
+HSPLandroidx/compose/foundation/gestures/BringIntoViewSpec$Companion$DefaultBringIntoViewSpec$1;->getScrollAnimationSpec()Landroidx/compose/animation/core/AnimationSpec;
+HSPLandroidx/compose/foundation/gestures/BringIntoViewSpec$Companion;-><clinit>()V
+HSPLandroidx/compose/foundation/gestures/BringIntoViewSpec;-><clinit>()V
+HSPLandroidx/compose/foundation/gestures/ContentInViewNode$Request;-><init>(Landroidx/compose/foundation/relocation/BringIntoViewResponderNode$bringChildIntoView$2$1$1;Lkotlinx/coroutines/CancellableContinuationImpl;)V
+HSPLandroidx/compose/foundation/gestures/ContentInViewNode$launchAnimation$2$1;-><init>(Landroidx/compose/foundation/gestures/ContentInViewNode;Lkotlinx/coroutines/Job;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/foundation/gestures/ContentInViewNode$launchAnimation$2$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/foundation/gestures/ContentInViewNode$launchAnimation$2$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/ContentInViewNode$launchAnimation$2$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/ContentInViewNode$launchAnimation$2;-><init>(Landroidx/compose/foundation/gestures/ContentInViewNode;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/foundation/gestures/ContentInViewNode$launchAnimation$2;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/foundation/gestures/ContentInViewNode$launchAnimation$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/ContentInViewNode$launchAnimation$2;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/ContentInViewNode;-><init>(Landroidx/compose/foundation/gestures/Orientation;Landroidx/compose/foundation/gestures/ScrollableState;ZLandroidx/compose/foundation/gestures/BringIntoViewSpec;)V
+HSPLandroidx/compose/foundation/gestures/ContentInViewNode;->access$calculateScrollDelta(Landroidx/compose/foundation/gestures/ContentInViewNode;)F
+HSPLandroidx/compose/foundation/gestures/ContentInViewNode;->isMaxVisible-O0kMr_c(Landroidx/compose/ui/geometry/Rect;J)Z
+HSPLandroidx/compose/foundation/gestures/ContentInViewNode;->launchAnimation()V
+HSPLandroidx/compose/foundation/gestures/ContentInViewNode;->onPlaced(Landroidx/compose/ui/node/NodeCoordinator;)V
+HSPLandroidx/compose/foundation/gestures/ContentInViewNode;->onRemeasured-ozmzZPI(J)V
+HSPLandroidx/compose/foundation/gestures/ContentInViewNode;->relocationOffset-BMxPBkI(Landroidx/compose/ui/geometry/Rect;J)J
+HSPLandroidx/compose/foundation/gestures/DefaultFlingBehavior;-><init>(Landroidx/compose/animation/core/DecayAnimationSpecImpl;)V
+HSPLandroidx/compose/foundation/gestures/DefaultScrollableState$scroll$2$1;-><init>(Landroidx/compose/foundation/gestures/DefaultScrollableState;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/foundation/gestures/DefaultScrollableState$scroll$2$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/foundation/gestures/DefaultScrollableState$scroll$2$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/DefaultScrollableState$scroll$2$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/DefaultScrollableState$scroll$2;-><init>(Landroidx/compose/foundation/gestures/DefaultScrollableState;Landroidx/compose/foundation/MutatePriority;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/foundation/gestures/DefaultScrollableState$scroll$2;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/foundation/gestures/DefaultScrollableState$scroll$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/DefaultScrollableState$scroll$2;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/DefaultScrollableState$scrollScope$1;-><init>(Landroidx/compose/foundation/gestures/DefaultScrollableState;)V
+HSPLandroidx/compose/foundation/gestures/DefaultScrollableState$scrollScope$1;->scrollBy(F)F
+HSPLandroidx/compose/foundation/gestures/DefaultScrollableState;-><init>(Lkotlin/collections/AbstractMap$toString$1;)V
+HSPLandroidx/compose/foundation/gestures/DefaultScrollableState;->scroll(Landroidx/compose/foundation/MutatePriority;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/DraggableKt$awaitDrag$2;-><init>(ILjava/lang/Object;Ljava/lang/Object;Z)V
+HSPLandroidx/compose/foundation/gestures/DraggableKt$awaitDrag$2;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/DraggableNode$onAttach$1;-><init>(Landroidx/compose/foundation/gestures/DraggableNode;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/foundation/gestures/DraggableNode$onAttach$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/foundation/gestures/DraggableNode$onAttach$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/DraggableNode$pointerInputNode$1;-><init>(Landroidx/compose/foundation/gestures/DraggableNode;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/foundation/gestures/DraggableNode;-><init>(Landroidx/compose/foundation/gestures/ScrollDraggableState;Landroidx/compose/foundation/gestures/Orientation;ZLandroidx/compose/foundation/interaction/MutableInteractionSourceImpl;Landroidx/compose/ui/node/LayoutNode$_foldedChildren$1;Landroidx/compose/foundation/gestures/ScrollableKt$NoOpOnDragStarted$1;Landroidx/compose/foundation/gestures/ScrollableGesturesNode$onDragStopped$1;)V
+HSPLandroidx/compose/foundation/gestures/DraggableNode;->onAttach()V
+HSPLandroidx/compose/foundation/gestures/ModifierLocalScrollableContainerProvider;-><init>(Z)V
+HSPLandroidx/compose/foundation/gestures/ModifierLocalScrollableContainerProvider;->getProvidedValues()Landroidx/tv/material3/TabKt;
+HSPLandroidx/compose/foundation/gestures/MouseWheelScrollNode$1;-><init>(Landroidx/compose/foundation/gestures/MouseWheelScrollNode;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/foundation/gestures/MouseWheelScrollNode;-><init>(Landroidx/compose/foundation/gestures/ScrollingLogic;)V
+HSPLandroidx/compose/foundation/gestures/MouseWheelScrollNode;->onAttach()V
+HSPLandroidx/compose/foundation/gestures/Orientation;-><clinit>()V
+HSPLandroidx/compose/foundation/gestures/Orientation;-><init>(ILjava/lang/String;)V
+HSPLandroidx/compose/foundation/gestures/ScrollDraggableState;-><init>(Landroidx/compose/foundation/gestures/ScrollingLogic;)V
+HSPLandroidx/compose/foundation/gestures/ScrollableElement;-><init>(Landroidx/compose/foundation/gestures/ScrollableState;Landroidx/compose/foundation/gestures/Orientation;Landroidx/compose/foundation/OverscrollEffect;ZZLandroidx/compose/foundation/gestures/FlingBehavior;Landroidx/compose/foundation/interaction/MutableInteractionSourceImpl;Landroidx/compose/foundation/gestures/BringIntoViewSpec;)V
+HSPLandroidx/compose/foundation/gestures/ScrollableElement;->create()Landroidx/compose/ui/Modifier$Node;
+HSPLandroidx/compose/foundation/gestures/ScrollableGesturesNode$onDragStopped$1;-><init>(Landroidx/compose/foundation/gestures/ScrollableGesturesNode;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/foundation/gestures/ScrollableGesturesNode;-><init>(Landroidx/compose/foundation/gestures/ScrollingLogic;Landroidx/compose/foundation/gestures/Orientation;ZLandroidx/compose/ui/input/nestedscroll/NestedScrollDispatcher;Landroidx/compose/foundation/interaction/MutableInteractionSourceImpl;)V
+HSPLandroidx/compose/foundation/gestures/ScrollableKt$NoOpOnDragStarted$1;-><init>(ILkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/foundation/gestures/ScrollableKt$UnityDensity$1;->getDensity()F
+HSPLandroidx/compose/foundation/gestures/ScrollableKt;-><clinit>()V
+HSPLandroidx/compose/foundation/gestures/ScrollableKt;->scrollable$default(Landroidx/compose/foundation/gestures/ScrollableState;Landroidx/compose/foundation/gestures/Orientation;Landroidx/compose/foundation/OverscrollEffect;ZZLandroidx/compose/foundation/gestures/FlingBehavior;Landroidx/compose/foundation/interaction/MutableInteractionSourceImpl;Landroidx/tv/foundation/TvBringIntoViewSpec;I)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/gestures/ScrollableNestedScrollConnection;-><init>(Landroidx/compose/foundation/gestures/ScrollingLogic;Z)V
+HSPLandroidx/compose/foundation/gestures/ScrollableNode;-><init>(Landroidx/compose/foundation/gestures/ScrollableState;Landroidx/compose/foundation/gestures/Orientation;Landroidx/compose/foundation/OverscrollEffect;ZZLandroidx/compose/foundation/gestures/FlingBehavior;Landroidx/compose/foundation/interaction/MutableInteractionSourceImpl;Landroidx/compose/foundation/gestures/BringIntoViewSpec;)V
+HSPLandroidx/compose/foundation/gestures/ScrollableNode;->applyFocusProperties(Landroidx/compose/ui/focus/FocusProperties;)V
+HSPLandroidx/compose/foundation/gestures/ScrollableNode;->onAttach()V
+HSPLandroidx/compose/foundation/gestures/ScrollableState;->scroll$default(Landroidx/compose/foundation/gestures/ScrollableState;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/ScrollingLogic;-><init>(Landroidx/compose/foundation/gestures/ScrollableState;Landroidx/compose/foundation/gestures/Orientation;Landroidx/compose/foundation/OverscrollEffect;ZLandroidx/compose/foundation/gestures/FlingBehavior;Landroidx/compose/ui/input/nestedscroll/NestedScrollDispatcher;)V
+HSPLandroidx/compose/foundation/gestures/UpdatableAnimationState$animateToZero$1;-><init>(Landroidx/compose/foundation/gestures/UpdatableAnimationState;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/foundation/gestures/UpdatableAnimationState$animateToZero$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/UpdatableAnimationState$animateToZero$4;-><init>(Landroidx/compose/foundation/gestures/UpdatableAnimationState;FLkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/foundation/gestures/UpdatableAnimationState$animateToZero$4;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/gestures/UpdatableAnimationState;-><clinit>()V
+HSPLandroidx/compose/foundation/gestures/UpdatableAnimationState;-><init>(Landroidx/compose/animation/core/AnimationSpec;)V
+HSPLandroidx/compose/foundation/gestures/UpdatableAnimationState;->animateToZero(Landroidx/compose/foundation/layout/OffsetNode$measure$1;Landroidx/compose/ui/node/LayoutNode$_foldedChildren$1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/interaction/FocusInteraction$Unfocus;-><init>(Landroidx/compose/foundation/interaction/FocusInteraction$Focus;)V
+HSPLandroidx/compose/foundation/interaction/FocusInteractionKt$collectIsFocusedAsState$1$1$1;-><init>(Ljava/util/ArrayList;Landroidx/compose/runtime/MutableState;I)V
+HSPLandroidx/compose/foundation/interaction/FocusInteractionKt$collectIsFocusedAsState$1$1$1;->emit(Landroidx/compose/foundation/interaction/Interaction;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/interaction/FocusInteractionKt$collectIsFocusedAsState$1$1$1;->emit(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/interaction/FocusInteractionKt$collectIsFocusedAsState$1$1;-><init>(Landroidx/compose/foundation/interaction/InteractionSource;Landroidx/compose/runtime/MutableState;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/foundation/interaction/FocusInteractionKt$collectIsFocusedAsState$1$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/foundation/interaction/FocusInteractionKt$collectIsFocusedAsState$1$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/interaction/MutableInteractionSourceImpl;-><init>()V
+HSPLandroidx/compose/foundation/interaction/MutableInteractionSourceImpl;->emit(Landroidx/compose/foundation/interaction/Interaction;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/interaction/PressInteraction$Press;-><init>(J)V
+HSPLandroidx/compose/foundation/interaction/PressInteractionKt$collectIsPressedAsState$1$1;-><init>(Landroidx/compose/foundation/interaction/InteractionSource;Landroidx/compose/runtime/MutableState;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/foundation/interaction/PressInteractionKt$collectIsPressedAsState$1$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/foundation/interaction/PressInteractionKt$collectIsPressedAsState$1$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/layout/Arrangement$Center$1;-><init>(I)V
+HSPLandroidx/compose/foundation/layout/Arrangement$Center$1;->arrange(ILandroidx/compose/ui/unit/Density;Landroidx/compose/ui/unit/LayoutDirection;[I[I)V
+HSPLandroidx/compose/foundation/layout/Arrangement$Center$1;->getSpacing-D9Ej5fM()F
+HSPLandroidx/compose/foundation/layout/Arrangement$End$1;-><init>(I)V
+HSPLandroidx/compose/foundation/layout/Arrangement$SpacedAligned;-><init>(F)V
+HSPLandroidx/compose/foundation/layout/Arrangement$SpacedAligned;->arrange(ILandroidx/compose/ui/unit/Density;Landroidx/compose/ui/unit/LayoutDirection;[I[I)V
+HSPLandroidx/compose/foundation/layout/Arrangement$SpacedAligned;->arrange(Landroidx/compose/ui/unit/Density;I[I[I)V
+HSPLandroidx/compose/foundation/layout/Arrangement$SpacedAligned;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/foundation/layout/Arrangement$SpacedAligned;->getSpacing-D9Ej5fM()F
+HSPLandroidx/compose/foundation/layout/Arrangement$Top$1;-><init>(I)V
+HSPLandroidx/compose/foundation/layout/Arrangement$Top$1;->arrange(Landroidx/compose/ui/unit/Density;I[I[I)V
+HSPLandroidx/compose/foundation/layout/Arrangement;-><clinit>()V
+HSPLandroidx/compose/foundation/layout/Arrangement;->placeCenter$foundation_layout_release(I[I[IZ)V
+HSPLandroidx/compose/foundation/layout/Arrangement;->placeLeftOrTop$foundation_layout_release([I[IZ)V
+HSPLandroidx/compose/foundation/layout/BoxKt$Box$2;-><init>(IILjava/lang/Object;)V
+HSPLandroidx/compose/foundation/layout/BoxKt$Box$2;->invoke(Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/foundation/layout/BoxKt$Box$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/layout/BoxKt$EmptyBoxMeasurePolicy$1;-><clinit>()V
+HSPLandroidx/compose/foundation/layout/BoxKt$EmptyBoxMeasurePolicy$1;->measure-3p2s80s(Landroidx/compose/ui/layout/MeasureScope;Ljava/util/List;J)Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/compose/foundation/layout/BoxKt$boxMeasurePolicy$1$2;-><init>(Landroidx/compose/ui/layout/Placeable;Landroidx/compose/ui/layout/Measurable;Landroidx/compose/ui/layout/MeasureScope;IILandroidx/compose/ui/Alignment;)V
+HSPLandroidx/compose/foundation/layout/BoxKt$boxMeasurePolicy$1$2;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/layout/BoxKt$boxMeasurePolicy$1;-><init>(Z)V
+HSPLandroidx/compose/foundation/layout/BoxKt$boxMeasurePolicy$1;->measure-3p2s80s(Landroidx/compose/ui/layout/MeasureScope;Ljava/util/List;J)Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/compose/foundation/layout/BoxKt;-><clinit>()V
+HSPLandroidx/compose/foundation/layout/BoxKt;->Box(Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/foundation/layout/BoxKt;->access$placeInBox(Landroidx/compose/ui/layout/Placeable$PlacementScope;Landroidx/compose/ui/layout/Placeable;Landroidx/compose/ui/layout/Measurable;Landroidx/compose/ui/unit/LayoutDirection;IILandroidx/compose/ui/Alignment;)V
+HSPLandroidx/compose/foundation/layout/BoxKt;->rememberBoxMeasurePolicy(ZLandroidx/compose/runtime/Composer;)Landroidx/compose/ui/layout/MeasurePolicy;
+HSPLandroidx/compose/foundation/layout/BoxScopeInstance;-><clinit>()V
+HSPLandroidx/compose/foundation/layout/ColumnKt;-><clinit>()V
+HSPLandroidx/compose/foundation/layout/ColumnKt;->columnMeasurePolicy(Landroidx/compose/foundation/layout/Arrangement$Vertical;Landroidx/compose/runtime/Composer;)Landroidx/compose/ui/layout/MeasurePolicy;
+HSPLandroidx/compose/foundation/layout/CrossAxisAlignment$VerticalCrossAxisAlignment;-><init>(ILjava/lang/Object;)V
+HSPLandroidx/compose/foundation/layout/CrossAxisAlignment$VerticalCrossAxisAlignment;->align$foundation_layout_release(ILandroidx/compose/ui/unit/LayoutDirection;)I
+HSPLandroidx/compose/foundation/layout/FillElement;-><init>(IF)V
+HSPLandroidx/compose/foundation/layout/FillElement;->create()Landroidx/compose/ui/Modifier$Node;
+HSPLandroidx/compose/foundation/layout/FillElement;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/foundation/layout/FillNode;-><init>(IF)V
+HSPLandroidx/compose/foundation/layout/FillNode;->measure-3p2s80s(Landroidx/compose/ui/layout/MeasureScope;Landroidx/compose/ui/layout/Measurable;J)Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/compose/foundation/layout/HorizontalAlignElement;-><init>()V
+HSPLandroidx/compose/foundation/layout/HorizontalAlignElement;->create()Landroidx/compose/ui/Modifier$Node;
+HSPLandroidx/compose/foundation/layout/HorizontalAlignElement;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/foundation/layout/HorizontalAlignNode;-><init>(Landroidx/compose/ui/Alignment$Horizontal;)V
+HSPLandroidx/compose/foundation/layout/HorizontalAlignNode;->modifyParentData(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/layout/OffsetElement;-><init>(FF)V
+HSPLandroidx/compose/foundation/layout/OffsetElement;->create()Landroidx/compose/ui/Modifier$Node;
+HSPLandroidx/compose/foundation/layout/OffsetElement;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/foundation/layout/OffsetKt;->Spacer(Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;)V
+HSPLandroidx/compose/foundation/layout/OffsetKt;->access$intrinsicSize(Ljava/util/List;Landroidx/compose/ui/CombinedModifier$toString$1;Landroidx/compose/ui/CombinedModifier$toString$1;IIII)I
+HSPLandroidx/compose/foundation/layout/OffsetKt;->getRowColumnParentData(Landroidx/compose/ui/layout/Measurable;)Landroidx/compose/foundation/layout/RowColumnParentData;
+HSPLandroidx/compose/foundation/layout/OffsetKt;->getWeight(Landroidx/compose/foundation/layout/RowColumnParentData;)F
+HSPLandroidx/compose/foundation/layout/OffsetKt;->offset-VpY3zN4(Landroidx/compose/ui/Modifier;FF)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/layout/OffsetKt;->padding-3ABfNKs(Landroidx/compose/ui/Modifier;F)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/layout/OffsetKt;->padding-VpY3zN4(FF)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/layout/OffsetKt;->size(Landroidx/compose/ui/Alignment;Z)Landroidx/compose/foundation/layout/WrapContentElement;
+HSPLandroidx/compose/foundation/layout/OffsetKt;->toBoxConstraints-OenEA2s(JI)J
+HSPLandroidx/compose/foundation/layout/OffsetNode$measure$1;-><init>(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;I)V
+HSPLandroidx/compose/foundation/layout/OffsetNode$measure$1;->invoke(Landroidx/compose/ui/layout/Placeable$PlacementScope;)V
+HSPLandroidx/compose/foundation/layout/OffsetNode$measure$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/layout/OffsetNode;-><init>(FFZ)V
+HSPLandroidx/compose/foundation/layout/OffsetNode;->measure-3p2s80s(Landroidx/compose/ui/layout/MeasureScope;Landroidx/compose/ui/layout/Measurable;J)Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/compose/foundation/layout/PaddingElement;-><init>(FFFF)V
+HSPLandroidx/compose/foundation/layout/PaddingElement;->create()Landroidx/compose/ui/Modifier$Node;
+HSPLandroidx/compose/foundation/layout/PaddingElement;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/foundation/layout/PaddingNode;-><init>(FFFFZ)V
+HSPLandroidx/compose/foundation/layout/PaddingNode;->measure-3p2s80s(Landroidx/compose/ui/layout/MeasureScope;Landroidx/compose/ui/layout/Measurable;J)Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/compose/foundation/layout/PaddingValuesImpl;-><init>(FFFF)V
+HSPLandroidx/compose/foundation/layout/RowColumnImplKt$rowColumnMeasurePolicy$1;-><init>(ILkotlin/jvm/functions/Function5;FLandroidx/compose/foundation/layout/CrossAxisAlignment$VerticalCrossAxisAlignment;)V
+HSPLandroidx/compose/foundation/layout/RowColumnImplKt$rowColumnMeasurePolicy$1;->maxIntrinsicHeight(Landroidx/compose/ui/node/NodeCoordinator;Ljava/util/List;I)I
+HSPLandroidx/compose/foundation/layout/RowColumnImplKt$rowColumnMeasurePolicy$1;->measure-3p2s80s(Landroidx/compose/ui/layout/MeasureScope;Ljava/util/List;J)Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/compose/foundation/layout/RowColumnMeasureHelperResult;-><init>(III[I)V
+HSPLandroidx/compose/foundation/layout/RowColumnMeasurementHelper;-><init>(ILkotlin/jvm/functions/Function5;FILandroidx/compose/foundation/layout/OffsetKt;Ljava/util/List;[Landroidx/compose/ui/layout/Placeable;)V
+HSPLandroidx/compose/foundation/layout/RowColumnParentData;-><init>()V
+HSPLandroidx/compose/foundation/layout/RowKt$DefaultRowMeasurePolicy$1;-><clinit>()V
+HSPLandroidx/compose/foundation/layout/RowKt$DefaultRowMeasurePolicy$1;-><init>(I)V
+HSPLandroidx/compose/foundation/layout/RowKt$DefaultRowMeasurePolicy$1;->invoke(ILandroidx/compose/ui/unit/Density;Landroidx/compose/ui/unit/LayoutDirection;[I[I)V
+HSPLandroidx/compose/foundation/layout/RowKt$DefaultRowMeasurePolicy$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/io/Serializable;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/layout/RowKt$rowMeasurePolicy$1$1;-><init>(ILjava/lang/Object;)V
+HSPLandroidx/compose/foundation/layout/RowKt$rowMeasurePolicy$1$1;->invoke(ILandroidx/compose/ui/unit/Density;Landroidx/compose/ui/unit/LayoutDirection;[I[I)V
+HSPLandroidx/compose/foundation/layout/RowKt$rowMeasurePolicy$1$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/io/Serializable;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/layout/RowKt;-><clinit>()V
+HSPLandroidx/compose/foundation/layout/RowKt;->rowMeasurePolicy(Landroidx/compose/foundation/layout/Arrangement$Horizontal;Landroidx/compose/ui/BiasAlignment$Vertical;Landroidx/compose/runtime/Composer;)Landroidx/compose/ui/layout/MeasurePolicy;
+HSPLandroidx/compose/foundation/layout/RowScopeInstance;-><clinit>()V
+HSPLandroidx/compose/foundation/layout/SizeElement;-><init>(FFFFI)V
+HSPLandroidx/compose/foundation/layout/SizeElement;->create()Landroidx/compose/ui/Modifier$Node;
+HSPLandroidx/compose/foundation/layout/SizeKt;-><clinit>()V
+HSPLandroidx/compose/foundation/layout/SizeKt;->fillMaxWidth$default(Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/layout/SizeKt;->height-3ABfNKs(Landroidx/compose/ui/Modifier;F)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/layout/SizeKt;->width-3ABfNKs(Landroidx/compose/ui/Modifier;F)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/layout/SizeKt;->wrapContentSize$default(Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/foundation/layout/SizeNode;-><init>(FFFFZ)V
+HSPLandroidx/compose/foundation/layout/SizeNode;->getTargetConstraints-OenEA2s(Landroidx/compose/ui/unit/Density;)J
+HSPLandroidx/compose/foundation/layout/SizeNode;->measure-3p2s80s(Landroidx/compose/ui/layout/MeasureScope;Landroidx/compose/ui/layout/Measurable;J)Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/compose/foundation/layout/SpacerMeasurePolicy;-><clinit>()V
+HSPLandroidx/compose/foundation/layout/SpacerMeasurePolicy;->measure-3p2s80s(Landroidx/compose/ui/layout/MeasureScope;Ljava/util/List;J)Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/compose/foundation/layout/WrapContentElement;-><init>(IZLcom/example/tvcomposebasedtests/tvComponents/AppKt$App$1;Ljava/lang/Object;)V
+HSPLandroidx/compose/foundation/layout/WrapContentElement;->create()Landroidx/compose/ui/Modifier$Node;
+HSPLandroidx/compose/foundation/layout/WrapContentElement;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/foundation/layout/WrapContentNode$measure$1;-><init>(Landroidx/compose/foundation/layout/WrapContentNode;ILandroidx/compose/ui/layout/Placeable;ILandroidx/compose/ui/layout/MeasureScope;)V
+HSPLandroidx/compose/foundation/layout/WrapContentNode$measure$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/layout/WrapContentNode;-><init>(IZLkotlin/jvm/functions/Function2;)V
+HSPLandroidx/compose/foundation/layout/WrapContentNode;->measure-3p2s80s(Landroidx/compose/ui/layout/MeasureScope;Landroidx/compose/ui/layout/Measurable;J)Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/compose/foundation/lazy/layout/DefaultLazyKey;-><clinit>()V
+HSPLandroidx/compose/foundation/lazy/layout/DefaultLazyKey;-><init>(I)V
+HSPLandroidx/compose/foundation/lazy/layout/DefaultLazyKey;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/foundation/lazy/layout/DefaultLazyKey;->hashCode()I
+HSPLandroidx/compose/foundation/lazy/layout/IntervalList$Interval;-><init>(IILandroidx/compose/foundation/lazy/layout/LazyLayoutIntervalContent$Interval;)V
+HSPLandroidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory$CachedItemContent;-><init>(Landroidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory;ILjava/lang/Object;Ljava/lang/Object;)V
+HSPLandroidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory$CachedItemContent;->getContent()Lkotlin/jvm/functions/Function2;
+HSPLandroidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory;-><init>(Landroidx/compose/runtime/saveable/SaveableStateHolder;Landroidx/compose/foundation/lazy/layout/LazyLayoutKt$LazyLayout$3$itemContentFactory$1$1;)V
+HSPLandroidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory;->getContent(Ljava/lang/Object;ILjava/lang/Object;)Lkotlin/jvm/functions/Function2;
+HSPLandroidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory;->getContentType(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/lazy/layout/LazyLayoutItemReusePolicy;-><init>(Landroidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory;)V
+HSPLandroidx/compose/foundation/lazy/layout/LazyLayoutItemReusePolicy;->areCompatible(Ljava/lang/Object;Ljava/lang/Object;)Z
+HSPLandroidx/compose/foundation/lazy/layout/LazyLayoutItemReusePolicy;->getSlotsToRetain(Landroidx/compose/ui/layout/SubcomposeSlotReusePolicy$SlotIdsSet;)V
+HSPLandroidx/compose/foundation/lazy/layout/LazyLayoutKt$LazyLayout$3$2$1;-><init>(Ljava/lang/Object;ILjava/lang/Object;)V
+HSPLandroidx/compose/foundation/lazy/layout/LazyLayoutKt$LazyLayout$3$2$1;->invoke(Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/foundation/lazy/layout/LazyLayoutKt$LazyLayout$3$2$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/lazy/layout/LazyLayoutKt$LazyLayout$3$itemContentFactory$1$1;-><init>(Landroidx/compose/runtime/State;I)V
+HSPLandroidx/compose/foundation/lazy/layout/LazyLayoutKt$LazyLayout$3$itemContentFactory$1$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/foundation/lazy/layout/LazyLayoutKt$LazyLayout$3;-><init>(Landroidx/compose/foundation/lazy/layout/LazyLayoutPrefetchState;Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function2;ILandroidx/compose/runtime/MutableState;)V
+HSPLandroidx/compose/foundation/lazy/layout/LazyLayoutKt$LazyLayout$3;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/lazy/layout/LazyLayoutMeasureScopeImpl;-><init>(Landroidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory;Landroidx/compose/ui/layout/SubcomposeMeasureScope;)V
+HSPLandroidx/compose/foundation/lazy/layout/LazyLayoutMeasureScopeImpl;->getLayoutDirection()Landroidx/compose/ui/unit/LayoutDirection;
+HSPLandroidx/compose/foundation/lazy/layout/LazyLayoutMeasureScopeImpl;->isLookingAhead()Z
+HSPLandroidx/compose/foundation/lazy/layout/LazyLayoutMeasureScopeImpl;->layout(IILjava/util/Map;Lkotlin/jvm/functions/Function1;)Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/compose/foundation/lazy/layout/LazyLayoutMeasureScopeImpl;->measure-0kLqBqw(JI)Ljava/util/List;
+HSPLandroidx/compose/foundation/lazy/layout/LazyLayoutMeasureScopeImpl;->roundToPx-0680j_4(F)I
+HSPLandroidx/compose/foundation/lazy/layout/LazyLayoutPinnableItem;-><init>(Ljava/lang/Object;Landroidx/compose/foundation/lazy/layout/LazyLayoutPinnedItemList;)V
+HSPLandroidx/compose/foundation/lazy/layout/LazyLayoutPinnableItem;->getPinsCount()I
+HSPLandroidx/compose/foundation/lazy/layout/LazyLayoutPinnableItem;->pin()Landroidx/compose/foundation/lazy/layout/LazyLayoutPinnableItem;
+HSPLandroidx/compose/foundation/lazy/layout/LazyLayoutPinnableItem;->release()V
+HSPLandroidx/compose/foundation/lazy/layout/LazyLayoutPinnedItemList;-><init>()V
+HSPLandroidx/compose/foundation/lazy/layout/LazyLayoutPinnedItemList;->get(I)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/lazy/layout/LazyLayoutPinnedItemList;->isEmpty()Z
+HSPLandroidx/compose/foundation/lazy/layout/LazyLayoutPinnedItemList;->size()I
+HSPLandroidx/compose/foundation/lazy/layout/LazyLayoutPrefetchState;->schedulePrefetch-0kLqBqw(JI)Landroidx/compose/foundation/lazy/layout/LazyLayoutPrefetchState$PrefetchHandle;
+HSPLandroidx/compose/foundation/lazy/layout/LazyLayoutPrefetcher$PrefetchRequest;-><init>(IJ)V
+HSPLandroidx/compose/foundation/lazy/layout/LazyLayoutPrefetcher$PrefetchRequest;->cancel()V
+HSPLandroidx/compose/foundation/lazy/layout/LazyLayoutPrefetcher;-><init>(Landroidx/compose/foundation/lazy/layout/LazyLayoutPrefetchState;Landroidx/compose/ui/layout/SubcomposeLayoutState;Landroidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory;Landroid/view/View;)V
+HSPLandroidx/compose/foundation/lazy/layout/LazyLayoutPrefetcher;->doFrame(J)V
+HSPLandroidx/compose/foundation/lazy/layout/LazyLayoutPrefetcher;->onRemembered()V
+HSPLandroidx/compose/foundation/lazy/layout/LazyLayoutPrefetcher;->run()V
+HSPLandroidx/compose/foundation/lazy/layout/LazySaveableStateHolder$1;-><init>(Landroidx/compose/runtime/saveable/SaveableStateRegistry;I)V
+HSPLandroidx/compose/foundation/lazy/layout/LazySaveableStateHolder$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/lazy/layout/LazySaveableStateHolder$SaveableStateProvider$2$invoke$$inlined$onDispose$1;-><init>(Ljava/lang/Object;ILjava/lang/Object;)V
+HSPLandroidx/compose/foundation/lazy/layout/LazySaveableStateHolder$SaveableStateProvider$2$invoke$$inlined$onDispose$1;->dispose()V
+HSPLandroidx/compose/foundation/lazy/layout/LazySaveableStateHolder;-><init>(Landroidx/compose/runtime/saveable/SaveableStateRegistry;Ljava/util/Map;)V
+HSPLandroidx/compose/foundation/lazy/layout/LazySaveableStateHolder;->SaveableStateProvider(Ljava/lang/Object;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/foundation/lazy/layout/LazySaveableStateHolder;->canBeSaved(Ljava/lang/Object;)Z
+HSPLandroidx/compose/foundation/lazy/layout/LazySaveableStateHolder;->consumeRestored(Ljava/lang/String;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/lazy/layout/LazySaveableStateHolder;->performSave()Ljava/util/Map;
+HSPLandroidx/compose/foundation/lazy/layout/LazySaveableStateHolder;->registerProvider(Ljava/lang/String;Lkotlin/jvm/functions/Function0;)Landroidx/compose/runtime/saveable/SaveableStateRegistryImpl$registerProvider$3;
+HSPLandroidx/compose/foundation/lazy/layout/MutableIntervalList;-><init>()V
+HSPLandroidx/compose/foundation/lazy/layout/MutableIntervalList;->addInterval(ILandroidx/compose/foundation/lazy/layout/LazyLayoutIntervalContent$Interval;)V
+HSPLandroidx/compose/foundation/lazy/layout/MutableIntervalList;->checkIndexBounds(I)V
+HSPLandroidx/compose/foundation/lazy/layout/MutableIntervalList;->get(I)Landroidx/compose/foundation/lazy/layout/IntervalList$Interval;
+HSPLandroidx/compose/foundation/relocation/BringIntoViewChildNode;-><init>()V
+HSPLandroidx/compose/foundation/relocation/BringIntoViewChildNode;->getLayoutCoordinates()Landroidx/compose/ui/layout/LayoutCoordinates;
+HSPLandroidx/compose/foundation/relocation/BringIntoViewChildNode;->onPlaced(Landroidx/compose/ui/node/NodeCoordinator;)V
+HSPLandroidx/compose/foundation/relocation/BringIntoViewKt;-><clinit>()V
+HSPLandroidx/compose/foundation/relocation/BringIntoViewRequesterImpl$bringIntoView$1;-><init>(Landroidx/compose/foundation/relocation/BringIntoViewRequesterImpl;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/foundation/relocation/BringIntoViewRequesterImpl$bringIntoView$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/relocation/BringIntoViewRequesterImpl;-><init>()V
+HSPLandroidx/compose/foundation/relocation/BringIntoViewRequesterImpl;->bringIntoView(Landroidx/compose/ui/geometry/Rect;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/relocation/BringIntoViewRequesterNode;-><init>(Landroidx/compose/foundation/relocation/BringIntoViewRequesterImpl;)V
+HSPLandroidx/compose/foundation/relocation/BringIntoViewRequesterNode;->onAttach()V
+HSPLandroidx/compose/foundation/relocation/BringIntoViewRequesterNode;->onDetach()V
+HSPLandroidx/compose/foundation/relocation/BringIntoViewResponderNode$bringChildIntoView$2$1$1;-><init>(Landroidx/compose/foundation/relocation/BringIntoViewResponderNode;Landroidx/compose/ui/layout/LayoutCoordinates;Lkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/foundation/relocation/BringIntoViewResponderNode$bringChildIntoView$2$1$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/foundation/relocation/BringIntoViewResponderNode$bringChildIntoView$2$1;-><init>(Landroidx/compose/foundation/relocation/BringIntoViewResponderNode;Landroidx/compose/ui/layout/LayoutCoordinates;Lkotlin/jvm/functions/Function0;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/foundation/relocation/BringIntoViewResponderNode$bringChildIntoView$2$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/foundation/relocation/BringIntoViewResponderNode$bringChildIntoView$2$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/relocation/BringIntoViewResponderNode$bringChildIntoView$2$2;-><init>(Landroidx/compose/foundation/relocation/BringIntoViewResponderNode;Lkotlin/jvm/functions/Function0;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/foundation/relocation/BringIntoViewResponderNode$bringChildIntoView$2$2;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/foundation/relocation/BringIntoViewResponderNode$bringChildIntoView$2$2;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/relocation/BringIntoViewResponderNode$bringChildIntoView$2;-><init>(Landroidx/compose/foundation/relocation/BringIntoViewResponderNode;Landroidx/compose/ui/layout/LayoutCoordinates;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/foundation/relocation/BringIntoViewResponderNode$bringChildIntoView$2;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/foundation/relocation/BringIntoViewResponderNode$bringChildIntoView$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/relocation/BringIntoViewResponderNode$bringChildIntoView$2;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/relocation/BringIntoViewResponderNode$bringChildIntoView$parentRect$1;-><init>(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;I)V
+HSPLandroidx/compose/foundation/relocation/BringIntoViewResponderNode$bringChildIntoView$parentRect$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/foundation/relocation/BringIntoViewResponderNode;-><init>(Landroidx/compose/foundation/gestures/ContentInViewNode;)V
+HSPLandroidx/compose/foundation/relocation/BringIntoViewResponderNode;->access$bringChildIntoView$localRect(Landroidx/compose/foundation/relocation/BringIntoViewResponderNode;Landroidx/compose/ui/layout/LayoutCoordinates;Lkotlin/jvm/functions/Function0;)Landroidx/compose/ui/geometry/Rect;
+HSPLandroidx/compose/foundation/relocation/BringIntoViewResponderNode;->bringChildIntoView(Landroidx/compose/ui/layout/LayoutCoordinates;Lkotlin/jvm/functions/Function0;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/relocation/BringIntoViewResponderNode;->getProvidedValues()Landroidx/tv/material3/TabKt;
+HSPLandroidx/compose/foundation/relocation/BringIntoViewResponder_androidKt$defaultBringIntoViewParent$1;-><init>(Landroidx/compose/ui/node/CompositionLocalConsumerModifierNode;)V
+HSPLandroidx/compose/foundation/relocation/BringIntoViewResponder_androidKt$defaultBringIntoViewParent$1;->bringChildIntoView(Landroidx/compose/ui/layout/LayoutCoordinates;Lkotlin/jvm/functions/Function0;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/foundation/shape/CornerBasedShape;-><init>(Landroidx/compose/foundation/shape/CornerSize;Landroidx/compose/foundation/shape/CornerSize;Landroidx/compose/foundation/shape/CornerSize;Landroidx/compose/foundation/shape/CornerSize;)V
+HSPLandroidx/compose/foundation/shape/CornerBasedShape;->createOutline-Pq9zytI(JLandroidx/compose/ui/unit/LayoutDirection;Landroidx/compose/ui/unit/Density;)Landroidx/compose/ui/graphics/BrushKt;
+HSPLandroidx/compose/foundation/shape/DpCornerSize;-><init>(F)V
+HSPLandroidx/compose/foundation/shape/PercentCornerSize;-><init>(F)V
+HSPLandroidx/compose/foundation/shape/PercentCornerSize;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/foundation/shape/PercentCornerSize;->toPx-TmRCtEA(JLandroidx/compose/ui/unit/Density;)F
+HSPLandroidx/compose/foundation/shape/RoundedCornerShape;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/foundation/shape/RoundedCornerShapeKt;-><clinit>()V
+HSPLandroidx/compose/foundation/shape/RoundedCornerShapeKt;->RoundedCornerShape-0680j_4(F)Landroidx/compose/foundation/shape/RoundedCornerShape;
+HSPLandroidx/compose/foundation/text/EmptyMeasurePolicy;-><clinit>()V
+HSPLandroidx/compose/foundation/text/EmptyMeasurePolicy;->measure-3p2s80s(Landroidx/compose/ui/layout/MeasureScope;Ljava/util/List;J)Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/compose/foundation/text/modifiers/InlineDensity;-><clinit>()V
+HSPLandroidx/compose/foundation/text/modifiers/MultiParagraphLayoutCache;-><init>(Landroidx/compose/ui/text/AnnotatedString;Landroidx/compose/ui/text/TextStyle;Landroidx/compose/ui/text/font/FontFamily$Resolver;IZIILjava/util/List;)V
+HSPLandroidx/compose/foundation/text/modifiers/MultiParagraphLayoutCache;->intrinsicHeight(ILandroidx/compose/ui/unit/LayoutDirection;)I
+HSPLandroidx/compose/foundation/text/modifiers/MultiParagraphLayoutCache;->layoutText-K40F9xA(JLandroidx/compose/ui/unit/LayoutDirection;)Landroidx/compose/ui/text/MultiParagraph;
+HSPLandroidx/compose/foundation/text/modifiers/MultiParagraphLayoutCache;->setDensity$foundation_release(Landroidx/compose/ui/unit/Density;)V
+HSPLandroidx/compose/foundation/text/modifiers/MultiParagraphLayoutCache;->setLayoutDirection(Landroidx/compose/ui/unit/LayoutDirection;)Landroidx/compose/ui/text/MultiParagraphIntrinsics;
+HSPLandroidx/compose/foundation/text/modifiers/TextAnnotatedStringElement;-><init>(Landroidx/compose/ui/text/AnnotatedString;Landroidx/compose/ui/text/TextStyle;Landroidx/compose/ui/text/font/FontFamily$Resolver;Lkotlin/jvm/functions/Function1;IZII)V
+HSPLandroidx/compose/foundation/text/modifiers/TextAnnotatedStringElement;->create()Landroidx/compose/ui/Modifier$Node;
+HSPLandroidx/compose/foundation/text/modifiers/TextAnnotatedStringElement;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/foundation/text/modifiers/TextAnnotatedStringElement;->update(Landroidx/compose/ui/Modifier$Node;)V
+HSPLandroidx/compose/foundation/text/modifiers/TextAnnotatedStringNode;-><init>(Landroidx/compose/ui/text/AnnotatedString;Landroidx/compose/ui/text/TextStyle;Landroidx/compose/ui/text/font/FontFamily$Resolver;Lkotlin/jvm/functions/Function1;IZIILjava/util/List;Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/foundation/text/modifiers/TextAnnotatedStringNode;->doInvalidations(ZZZZ)V
+HSPLandroidx/compose/foundation/text/modifiers/TextAnnotatedStringNode;->draw(Landroidx/compose/ui/graphics/drawscope/ContentDrawScope;)V
+HSPLandroidx/compose/foundation/text/modifiers/TextAnnotatedStringNode;->getLayoutCache()Landroidx/compose/foundation/text/modifiers/MultiParagraphLayoutCache;
+HSPLandroidx/compose/foundation/text/modifiers/TextAnnotatedStringNode;->getLayoutCache(Landroidx/compose/ui/unit/Density;)Landroidx/compose/foundation/text/modifiers/MultiParagraphLayoutCache;
+HSPLandroidx/compose/foundation/text/modifiers/TextAnnotatedStringNode;->getTextSubstitution()Landroidx/compose/foundation/text/modifiers/TextAnnotatedStringNode$TextSubstitutionValue;
+HSPLandroidx/compose/foundation/text/modifiers/TextAnnotatedStringNode;->maxIntrinsicHeight(Landroidx/compose/ui/layout/IntrinsicMeasureScope;Landroidx/compose/ui/layout/Measurable;I)I
+HSPLandroidx/compose/foundation/text/modifiers/TextAnnotatedStringNode;->maxIntrinsicWidth(Landroidx/compose/ui/layout/IntrinsicMeasureScope;Landroidx/compose/ui/layout/Measurable;I)I
+HSPLandroidx/compose/foundation/text/modifiers/TextAnnotatedStringNode;->measure-3p2s80s(Landroidx/compose/ui/layout/MeasureScope;Landroidx/compose/ui/layout/Measurable;J)Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/compose/foundation/text/modifiers/TextAnnotatedStringNode;->updateCallbacks(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Z
+HSPLandroidx/compose/foundation/text/modifiers/TextAnnotatedStringNode;->updateLayoutRelatedArgs-MPT68mk(Landroidx/compose/ui/text/TextStyle;Ljava/util/List;IIZLandroidx/compose/ui/text/font/FontFamily$Resolver;I)Z
+HSPLandroidx/compose/foundation/text/selection/SelectionRegistrarKt;-><clinit>()V
+HSPLandroidx/compose/foundation/text/selection/TextSelectionColors;-><init>(JJ)V
+HSPLandroidx/compose/foundation/text/selection/TextSelectionColorsKt;-><clinit>()V
+HSPLandroidx/compose/material/ripple/PlatformRipple;-><init>(ZFLandroidx/compose/runtime/MutableState;)V
+HSPLandroidx/compose/material/ripple/RippleAlpha;-><init>(FFFF)V
+HSPLandroidx/compose/material/ripple/RippleKt;-><clinit>()V
+HSPLandroidx/compose/material/ripple/RippleThemeKt;-><clinit>()V
+HSPLandroidx/compose/material3/ColorScheme;-><init>(JJJJJJJJJJJJJJJJJJJJJJJJJJJJJ)V
+HSPLandroidx/compose/material3/ColorScheme;->getBackground-0d7_KjU()J
+HSPLandroidx/compose/material3/ColorScheme;->getPrimary-0d7_KjU()J
+HSPLandroidx/compose/material3/ColorScheme;->getSurface-0d7_KjU()J
+HSPLandroidx/compose/material3/ColorSchemeKt;-><clinit>()V
+HSPLandroidx/compose/material3/ColorSchemeKt;->darkColorScheme-G1PFc-w$default(JJJI)Landroidx/compose/material3/ColorScheme;
+HSPLandroidx/compose/material3/MaterialRippleTheme;-><clinit>()V
+HSPLandroidx/compose/material3/MaterialThemeKt$MaterialTheme$2;-><init>(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;III)V
+HSPLandroidx/compose/material3/ShapeDefaults;-><clinit>()V
+HSPLandroidx/compose/material3/Shapes;-><init>(Landroidx/compose/foundation/shape/RoundedCornerShape;Landroidx/compose/foundation/shape/RoundedCornerShape;Landroidx/compose/foundation/shape/RoundedCornerShape;I)V
+HSPLandroidx/compose/material3/ShapesKt$LocalShapes$1;-><clinit>()V
+HSPLandroidx/compose/material3/ShapesKt$LocalShapes$1;-><init>(I)V
+HSPLandroidx/compose/material3/ShapesKt$LocalShapes$1;->invoke()Landroidx/compose/ui/node/LayoutNode;
+HSPLandroidx/compose/material3/ShapesKt$LocalShapes$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/material3/ShapesKt;-><clinit>()V
+HSPLandroidx/compose/material3/TextKt$ProvideTextStyle$1;-><init>(IILjava/lang/Object;Ljava/lang/Object;)V
+HSPLandroidx/compose/material3/TextKt$ProvideTextStyle$1;->invoke(Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/material3/TextKt$ProvideTextStyle$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/material3/TextKt$Text$1;-><clinit>()V
+HSPLandroidx/compose/material3/TextKt$Text$1;-><init>()V
+HSPLandroidx/compose/material3/TextKt$Text$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/material3/TextKt;-><clinit>()V
+HSPLandroidx/compose/material3/TextKt;->ProvideTextStyle(Landroidx/compose/ui/text/TextStyle;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/material3/TextKt;->Text-fLXpl1I(Ljava/lang/String;Landroidx/compose/ui/Modifier;JJLandroidx/compose/ui/text/font/FontStyle;Landroidx/compose/ui/text/font/FontWeight;Landroidx/compose/ui/text/font/FontFamily;JLandroidx/compose/ui/text/style/TextDecoration;Landroidx/compose/ui/text/style/TextAlign;JIZILkotlin/jvm/functions/Function1;Landroidx/compose/ui/text/TextStyle;Landroidx/compose/runtime/Composer;III)V
+HSPLandroidx/compose/material3/Typography;-><init>(Landroidx/compose/ui/text/TextStyle;I)V
+HSPLandroidx/compose/material3/TypographyKt;-><clinit>()V
+HSPLandroidx/compose/material3/tokens/ColorDarkTokens;-><clinit>()V
+HSPLandroidx/compose/material3/tokens/PaletteTokens;-><clinit>()V
+HSPLandroidx/compose/material3/tokens/ShapeTokens;-><clinit>()V
+HSPLandroidx/compose/material3/tokens/TypeScaleTokens;-><clinit>()V
+HSPLandroidx/compose/material3/tokens/TypefaceTokens;-><clinit>()V
+HSPLandroidx/compose/material3/tokens/TypographyTokens;-><clinit>()V
+HSPLandroidx/compose/runtime/Anchor;-><init>(I)V
+HSPLandroidx/compose/runtime/BroadcastFrameClock$FrameAwaiter;-><init>(Lkotlin/jvm/functions/Function1;Lkotlinx/coroutines/CancellableContinuationImpl;)V
+HSPLandroidx/compose/runtime/BroadcastFrameClock;-><init>(Landroidx/compose/runtime/Pending$keyMap$2;)V
+HSPLandroidx/compose/runtime/BroadcastFrameClock;->fold(Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/BroadcastFrameClock;->get(Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext$Element;
+HSPLandroidx/compose/runtime/BroadcastFrameClock;->sendFrame(J)V
+HSPLandroidx/compose/runtime/BroadcastFrameClock;->withFrameNanos(Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/ComposableSingletons$CompositionKt;-><clinit>()V
+HSPLandroidx/compose/runtime/ComposerImpl$CompositionContextHolder;-><init>(Landroidx/compose/runtime/ComposerImpl$CompositionContextImpl;)V
+HSPLandroidx/compose/runtime/ComposerImpl$CompositionContextHolder;->onRemembered()V
+HSPLandroidx/compose/runtime/ComposerImpl$CompositionContextImpl;-><init>(Landroidx/compose/runtime/ComposerImpl;IZLandroidx/compose/runtime/CompositionObserverHolder;)V
+HSPLandroidx/compose/runtime/ComposerImpl$CompositionContextImpl;->composeInitial$runtime_release(Landroidx/compose/runtime/CompositionImpl;Landroidx/compose/runtime/internal/ComposableLambdaImpl;)V
+HSPLandroidx/compose/runtime/ComposerImpl$CompositionContextImpl;->doneComposing$runtime_release()V
+HSPLandroidx/compose/runtime/ComposerImpl$CompositionContextImpl;->getCollectingParameterInformation$runtime_release()Z
+HSPLandroidx/compose/runtime/ComposerImpl$CompositionContextImpl;->getCompositionLocalScope$runtime_release()Landroidx/compose/runtime/PersistentCompositionLocalMap;
+HSPLandroidx/compose/runtime/ComposerImpl$CompositionContextImpl;->getCompoundHashKey$runtime_release()I
+HSPLandroidx/compose/runtime/ComposerImpl$CompositionContextImpl;->getEffectCoroutineContext()Lkotlin/coroutines/CoroutineContext;
+HSPLandroidx/compose/runtime/ComposerImpl$CompositionContextImpl;->getObserverHolder$runtime_release()Landroidx/compose/runtime/CompositionObserverHolder;
+HSPLandroidx/compose/runtime/ComposerImpl$CompositionContextImpl;->invalidate$runtime_release(Landroidx/compose/runtime/CompositionImpl;)V
+HSPLandroidx/compose/runtime/ComposerImpl$CompositionContextImpl;->registerComposer$runtime_release(Landroidx/compose/runtime/ComposerImpl;)V
+HSPLandroidx/compose/runtime/ComposerImpl$CompositionContextImpl;->startComposing$runtime_release()V
+HSPLandroidx/compose/runtime/ComposerImpl$derivedStateObserver$1;-><init>(ILjava/lang/Object;)V
+HSPLandroidx/compose/runtime/ComposerImpl$derivedStateObserver$1;->done()V
+HSPLandroidx/compose/runtime/ComposerImpl$derivedStateObserver$1;->start()V
+HSPLandroidx/compose/runtime/ComposerImpl;-><init>(Landroidx/compose/ui/node/UiApplier;Landroidx/compose/runtime/CompositionContext;Landroidx/compose/runtime/SlotTable;Ljava/util/HashSet;Landroidx/compose/runtime/changelist/ChangeList;Landroidx/compose/runtime/changelist/ChangeList;Landroidx/compose/runtime/CompositionImpl;)V
+HSPLandroidx/compose/runtime/ComposerImpl;->apply(Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)V
+HSPLandroidx/compose/runtime/ComposerImpl;->changed(F)Z
+HSPLandroidx/compose/runtime/ComposerImpl;->changed(I)Z
+HSPLandroidx/compose/runtime/ComposerImpl;->changed(J)Z
+HSPLandroidx/compose/runtime/ComposerImpl;->changed(Ljava/lang/Object;)Z
+HSPLandroidx/compose/runtime/ComposerImpl;->changed(Z)Z
+HSPLandroidx/compose/runtime/ComposerImpl;->changedInstance(Ljava/lang/Object;)Z
+HSPLandroidx/compose/runtime/ComposerImpl;->cleanUpCompose()V
+HSPLandroidx/compose/runtime/ComposerImpl;->compoundKeyOf(III)I
+HSPLandroidx/compose/runtime/ComposerImpl;->consume(Landroidx/compose/runtime/ProvidableCompositionLocal;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/ComposerImpl;->createFreshInsertTable()V
+HSPLandroidx/compose/runtime/ComposerImpl;->createNode(Lkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/runtime/ComposerImpl;->currentCompositionLocalScope()Landroidx/compose/runtime/PersistentCompositionLocalMap;
+HSPLandroidx/compose/runtime/ComposerImpl;->deactivateToEndGroup(Z)V
+HSPLandroidx/compose/runtime/ComposerImpl;->doCompose(Landroidx/core/content/res/ComplexColorCompat;Landroidx/compose/runtime/internal/ComposableLambdaImpl;)V
+HSPLandroidx/compose/runtime/ComposerImpl;->doRecordDownsFor(II)V
+HSPLandroidx/compose/runtime/ComposerImpl;->endDefaults()V
+HSPLandroidx/compose/runtime/ComposerImpl;->endRestartGroup()Landroidx/compose/runtime/RecomposeScopeImpl;
+HSPLandroidx/compose/runtime/ComposerImpl;->endReusableGroup()V
+HSPLandroidx/compose/runtime/ComposerImpl;->endRoot()V
+HSPLandroidx/compose/runtime/ComposerImpl;->enterGroup(ZLandroidx/compose/runtime/Pending;)V
+HSPLandroidx/compose/runtime/ComposerImpl;->getCurrentRecomposeScope$runtime_release()Landroidx/compose/runtime/RecomposeScopeImpl;
+HSPLandroidx/compose/runtime/ComposerImpl;->getDefaultsInvalid()Z
+HSPLandroidx/compose/runtime/ComposerImpl;->getSkipping()Z
+HSPLandroidx/compose/runtime/ComposerImpl;->nextSlot()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/ComposerImpl;->recompose$runtime_release(Landroidx/core/content/res/ComplexColorCompat;)Z
+HSPLandroidx/compose/runtime/ComposerImpl;->recomposeToGroupEnd()V
+HSPLandroidx/compose/runtime/ComposerImpl;->recordUpsAndDowns(III)V
+HSPLandroidx/compose/runtime/ComposerImpl;->skipCurrentGroup()V
+HSPLandroidx/compose/runtime/ComposerImpl;->skipReaderToGroupEnd()V
+HSPLandroidx/compose/runtime/ComposerImpl;->skipToGroupEnd()V
+HSPLandroidx/compose/runtime/ComposerImpl;->start-BaiHCIY(IILandroidx/compose/runtime/OpaqueKey;Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/ComposerImpl;->startDefaults()V
+HSPLandroidx/compose/runtime/ComposerImpl;->startGroup(ILandroidx/compose/runtime/OpaqueKey;)V
+HSPLandroidx/compose/runtime/ComposerImpl;->startReaderGroup(Ljava/lang/Object;Z)V
+HSPLandroidx/compose/runtime/ComposerImpl;->startReplaceableGroup(I)V
+HSPLandroidx/compose/runtime/ComposerImpl;->startRestartGroup(I)Landroidx/compose/runtime/ComposerImpl;
+HSPLandroidx/compose/runtime/ComposerImpl;->startReusableGroup(Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/ComposerImpl;->startReusableNode()V
+HSPLandroidx/compose/runtime/ComposerImpl;->startRoot()V
+HSPLandroidx/compose/runtime/ComposerImpl;->tryImminentInvalidation$runtime_release(Landroidx/compose/runtime/RecomposeScopeImpl;Ljava/lang/Object;)Z
+HSPLandroidx/compose/runtime/ComposerImpl;->updateCompoundKeyWhenWeEnterGroup(Ljava/lang/Object;ILjava/lang/Object;)V
+HSPLandroidx/compose/runtime/ComposerImpl;->updateCompoundKeyWhenWeEnterGroupKeyHash(I)V
+HSPLandroidx/compose/runtime/ComposerImpl;->updateCompoundKeyWhenWeExitGroup(Ljava/lang/Object;ILjava/lang/Object;)V
+HSPLandroidx/compose/runtime/ComposerImpl;->updateCompoundKeyWhenWeExitGroupKeyHash(I)V
+HSPLandroidx/compose/runtime/ComposerImpl;->updateNodeCount(II)V
+HSPLandroidx/compose/runtime/ComposerImpl;->updateNodeCountOverrides(II)V
+HSPLandroidx/compose/runtime/ComposerImpl;->updateProviderMapGroup(Landroidx/compose/runtime/PersistentCompositionLocalMap;Landroidx/compose/runtime/internal/PersistentCompositionLocalHashMap;)Landroidx/compose/runtime/internal/PersistentCompositionLocalHashMap;
+HSPLandroidx/compose/runtime/ComposerImpl;->updatedNodeCount(I)I
+HSPLandroidx/compose/runtime/ComposerImpl;->useNode()V
+HSPLandroidx/compose/runtime/CompositionContext;->doneComposing$runtime_release()V
+HSPLandroidx/compose/runtime/CompositionContext;->getCompositionLocalScope$runtime_release()Landroidx/compose/runtime/PersistentCompositionLocalMap;
+HSPLandroidx/compose/runtime/CompositionContext;->getObserverHolder$runtime_release()Landroidx/compose/runtime/CompositionObserverHolder;
+HSPLandroidx/compose/runtime/CompositionContext;->registerComposer$runtime_release(Landroidx/compose/runtime/ComposerImpl;)V
+HSPLandroidx/compose/runtime/CompositionContext;->startComposing$runtime_release()V
+HSPLandroidx/compose/runtime/CompositionContextKt;-><clinit>()V
+HSPLandroidx/compose/runtime/CompositionImpl$RememberEventDispatcher;-><init>(Ljava/util/HashSet;)V
+HSPLandroidx/compose/runtime/CompositionImpl$RememberEventDispatcher;->dispatchAbandons()V
+HSPLandroidx/compose/runtime/CompositionImpl$RememberEventDispatcher;->dispatchRememberObservers()V
+HSPLandroidx/compose/runtime/CompositionImpl;-><init>(Landroidx/compose/runtime/CompositionContext;Landroidx/compose/ui/node/UiApplier;)V
+HSPLandroidx/compose/runtime/CompositionImpl;->addPendingInvalidationsLocked(Ljava/util/HashSet;Ljava/lang/Object;Z)Ljava/util/HashSet;
+HSPLandroidx/compose/runtime/CompositionImpl;->addPendingInvalidationsLocked(Ljava/util/Set;Z)V
+HSPLandroidx/compose/runtime/CompositionImpl;->applyChanges()V
+HSPLandroidx/compose/runtime/CompositionImpl;->applyChangesInLocked(Landroidx/compose/runtime/changelist/ChangeList;)V
+HSPLandroidx/compose/runtime/CompositionImpl;->applyLateChanges()V
+HSPLandroidx/compose/runtime/CompositionImpl;->changesApplied()V
+HSPLandroidx/compose/runtime/CompositionImpl;->cleanUpDerivedStateObservations()V
+HSPLandroidx/compose/runtime/CompositionImpl;->composeContent(Landroidx/compose/runtime/internal/ComposableLambdaImpl;)V
+HSPLandroidx/compose/runtime/CompositionImpl;->drainPendingModificationsForCompositionLocked()V
+HSPLandroidx/compose/runtime/CompositionImpl;->drainPendingModificationsLocked()V
+HSPLandroidx/compose/runtime/CompositionImpl;->getHasInvalidations()Z
+HSPLandroidx/compose/runtime/CompositionImpl;->invalidate$enumunboxing$(Landroidx/compose/runtime/RecomposeScopeImpl;Ljava/lang/Object;)I
+HSPLandroidx/compose/runtime/CompositionImpl;->invalidateChecked$enumunboxing$(Landroidx/compose/runtime/RecomposeScopeImpl;Landroidx/compose/runtime/Anchor;Ljava/lang/Object;)I
+HSPLandroidx/compose/runtime/CompositionImpl;->invalidateScopeOfLocked(Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/CompositionImpl;->isDisposed()Z
+HSPLandroidx/compose/runtime/CompositionImpl;->observer()V
+HSPLandroidx/compose/runtime/CompositionImpl;->observesAnyOf(Landroidx/compose/runtime/collection/IdentityArraySet;)Z
+HSPLandroidx/compose/runtime/CompositionImpl;->recompose()Z
+HSPLandroidx/compose/runtime/CompositionImpl;->recomposeScopeReleased()V
+HSPLandroidx/compose/runtime/CompositionImpl;->recordModificationsOf(Landroidx/compose/runtime/collection/IdentityArraySet;)V
+HSPLandroidx/compose/runtime/CompositionImpl;->recordReadOf(Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/CompositionImpl;->recordWriteOf(Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/CompositionImpl;->setContent(Lkotlin/jvm/functions/Function2;)V
+HSPLandroidx/compose/runtime/CompositionKt;-><clinit>()V
+HSPLandroidx/compose/runtime/CompositionLocal;-><init>(Lkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/runtime/CompositionLocalMap$Companion;-><clinit>()V
+HSPLandroidx/compose/runtime/CompositionLocalMap;-><clinit>()V
+HSPLandroidx/compose/runtime/CompositionObserverHolder;-><init>()V
+HSPLandroidx/compose/runtime/CompositionScopedCoroutineScopeCanceller;-><init>(Lkotlinx/coroutines/internal/ContextScope;)V
+HSPLandroidx/compose/runtime/CompositionScopedCoroutineScopeCanceller;->onRemembered()V
+HSPLandroidx/compose/runtime/DerivedSnapshotState$ResultRecord;-><clinit>()V
+HSPLandroidx/compose/runtime/DerivedSnapshotState$ResultRecord;-><init>()V
+HSPLandroidx/compose/runtime/DerivedSnapshotState$ResultRecord;->assign(Landroidx/compose/runtime/snapshots/StateRecord;)V
+HSPLandroidx/compose/runtime/DerivedSnapshotState$ResultRecord;->create()Landroidx/compose/runtime/snapshots/StateRecord;
+HSPLandroidx/compose/runtime/DerivedSnapshotState$ResultRecord;->isValid(Landroidx/compose/runtime/DerivedSnapshotState;Landroidx/compose/runtime/snapshots/Snapshot;)Z
+HSPLandroidx/compose/runtime/DerivedSnapshotState$ResultRecord;->readableHash(Landroidx/compose/runtime/DerivedSnapshotState;Landroidx/compose/runtime/snapshots/Snapshot;)I
+HSPLandroidx/compose/runtime/DerivedSnapshotState;-><init>(Landroidx/compose/runtime/ReferentialEqualityPolicy;Lkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/runtime/DerivedSnapshotState;->currentRecord(Landroidx/compose/runtime/DerivedSnapshotState$ResultRecord;Landroidx/compose/runtime/snapshots/Snapshot;ZLkotlin/jvm/functions/Function0;)Landroidx/compose/runtime/DerivedSnapshotState$ResultRecord;
+HSPLandroidx/compose/runtime/DerivedSnapshotState;->getCurrentRecord()Landroidx/compose/runtime/DerivedSnapshotState$ResultRecord;
+HSPLandroidx/compose/runtime/DerivedSnapshotState;->getFirstStateRecord()Landroidx/compose/runtime/snapshots/StateRecord;
+HSPLandroidx/compose/runtime/DerivedSnapshotState;->getValue()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/DerivedSnapshotState;->prependStateRecord(Landroidx/compose/runtime/snapshots/StateRecord;)V
+HSPLandroidx/compose/runtime/DisposableEffectImpl;-><init>(Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/runtime/DisposableEffectImpl;->onForgotten()V
+HSPLandroidx/compose/runtime/DisposableEffectImpl;->onRemembered()V
+HSPLandroidx/compose/runtime/DynamicProvidableCompositionLocal;-><init>(Landroidx/compose/runtime/SnapshotMutationPolicy;Lkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/runtime/DynamicProvidableCompositionLocal;->updatedStateOf$runtime_release(Ljava/lang/Object;Landroidx/compose/runtime/State;)Landroidx/compose/runtime/State;
+HSPLandroidx/compose/runtime/GroupInfo;-><init>(III)V
+HSPLandroidx/compose/runtime/IntStack;-><init>()V
+HSPLandroidx/compose/runtime/IntStack;-><init>(I)V
+HSPLandroidx/compose/runtime/IntStack;->getSize()I
+HSPLandroidx/compose/runtime/IntStack;->pop()I
+HSPLandroidx/compose/runtime/IntStack;->push(I)V
+HSPLandroidx/compose/runtime/IntStack;->pushDiagonal(III)V
+HSPLandroidx/compose/runtime/IntStack;->pushRange(IIII)V
+HSPLandroidx/compose/runtime/IntStack;->quickSort(II)V
+HSPLandroidx/compose/runtime/IntStack;->swapDiagonal(II)V
+HSPLandroidx/compose/runtime/Invalidation;-><init>(Landroidx/compose/runtime/RecomposeScopeImpl;ILandroidx/compose/runtime/collection/IdentityArraySet;)V
+HSPLandroidx/compose/runtime/KeyInfo;-><init>(ILjava/lang/Object;II)V
+HSPLandroidx/compose/runtime/Latch$await$2$2;-><init>(Ljava/lang/Object;ILjava/lang/Object;)V
+HSPLandroidx/compose/runtime/Latch$await$2$2;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Latch$await$2$2;->invoke(Ljava/lang/Throwable;)V
+HSPLandroidx/compose/runtime/Latch;-><init>()V
+HSPLandroidx/compose/runtime/Latch;-><init>(I)V
+HSPLandroidx/compose/runtime/Latch;->add(Landroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/runtime/Latch;->contains(Landroidx/compose/ui/node/LayoutNode;)Z
+HSPLandroidx/compose/runtime/Latch;->pop()Landroidx/compose/ui/node/LayoutNode;
+HSPLandroidx/compose/runtime/Latch;->remove(Landroidx/compose/ui/node/LayoutNode;)Z
+HSPLandroidx/compose/runtime/LaunchedEffectImpl;-><init>(Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;)V
+HSPLandroidx/compose/runtime/LaunchedEffectImpl;->onForgotten()V
+HSPLandroidx/compose/runtime/LaunchedEffectImpl;->onRemembered()V
+HSPLandroidx/compose/runtime/LazyValueHolder;-><init>(Lkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/runtime/LazyValueHolder;->getValue()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/MonotonicFrameClock;->getKey()Lkotlin/coroutines/CoroutineContext$Key;
+HSPLandroidx/compose/runtime/OpaqueKey;-><init>(Ljava/lang/String;)V
+HSPLandroidx/compose/runtime/OpaqueKey;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/runtime/OpaqueKey;->hashCode()I
+HSPLandroidx/compose/runtime/ParcelableSnapshotMutableFloatState;-><clinit>()V
+HSPLandroidx/compose/runtime/ParcelableSnapshotMutableIntState;-><clinit>()V
+HSPLandroidx/compose/runtime/ParcelableSnapshotMutableState;-><clinit>()V
+HSPLandroidx/compose/runtime/PausableMonotonicFrameClock$withFrameNanos$1;-><init>(Landroidx/compose/runtime/PausableMonotonicFrameClock;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/runtime/PausableMonotonicFrameClock$withFrameNanos$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/PausableMonotonicFrameClock;-><init>(Landroidx/compose/runtime/MonotonicFrameClock;)V
+HSPLandroidx/compose/runtime/PausableMonotonicFrameClock;->fold(Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/PausableMonotonicFrameClock;->get(Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext$Element;
+HSPLandroidx/compose/runtime/PausableMonotonicFrameClock;->minusKey(Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext;
+HSPLandroidx/compose/runtime/PausableMonotonicFrameClock;->withFrameNanos(Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Pending$keyMap$2;-><init>(ILjava/lang/Object;)V
+HSPLandroidx/compose/runtime/Pending$keyMap$2;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Pending;-><init>(ILjava/util/ArrayList;)V
+HSPLandroidx/compose/runtime/ProduceStateScopeImpl;-><init>(Landroidx/compose/runtime/MutableState;Lkotlin/coroutines/CoroutineContext;)V
+HSPLandroidx/compose/runtime/ProduceStateScopeImpl;->setValue(Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/ProvidableCompositionLocal;->provides(Ljava/lang/Object;)Landroidx/compose/runtime/ProvidedValue;
+HSPLandroidx/compose/runtime/ProvidedValue;-><init>(Landroidx/compose/runtime/CompositionLocal;Ljava/lang/Object;Z)V
+HSPLandroidx/compose/runtime/RecomposeScopeImpl$end$1$2;-><init>(IILjava/lang/Object;Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/RecomposeScopeImpl$end$1$2;-><init>(Landroidx/compose/runtime/DerivedSnapshotState;Landroidx/core/content/res/ComplexColorCompat;I)V
+HSPLandroidx/compose/runtime/RecomposeScopeImpl$end$1$2;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/RecomposeScopeImpl;-><init>(Landroidx/compose/runtime/CompositionImpl;)V
+HSPLandroidx/compose/runtime/RecomposeScopeImpl;->invalidateForResult$enumunboxing$(Ljava/lang/Object;)I
+HSPLandroidx/compose/runtime/Recomposer$State;-><clinit>()V
+HSPLandroidx/compose/runtime/Recomposer$State;-><init>(ILjava/lang/String;)V
+HSPLandroidx/compose/runtime/Recomposer$effectJob$1$1;-><init>(ILjava/lang/Object;)V
+HSPLandroidx/compose/runtime/Recomposer$effectJob$1$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Recomposer$join$2;-><init>(Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/runtime/Recomposer$join$2;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/runtime/Recomposer$join$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Recomposer$join$2;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Recomposer$performRecompose$1$1;-><init>(Ljava/lang/Object;ILjava/lang/Object;)V
+HSPLandroidx/compose/runtime/Recomposer$performRecompose$1$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Recomposer$performRecompose$1$1;->invoke()V
+HSPLandroidx/compose/runtime/Recomposer$recompositionRunner$2$3;-><init>(Lkotlin/jvm/functions/Function3;Landroidx/compose/runtime/MonotonicFrameClock;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/runtime/Recomposer$recompositionRunner$2$3;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/runtime/Recomposer$recompositionRunner$2$3;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Recomposer$recompositionRunner$2$3;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Recomposer$recompositionRunner$2$unregisterApplyObserver$1;-><init>(ILjava/lang/Object;)V
+HSPLandroidx/compose/runtime/Recomposer$recompositionRunner$2$unregisterApplyObserver$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Recomposer$recompositionRunner$2$unregisterApplyObserver$1;->invoke(Ljava/util/Set;)V
+HSPLandroidx/compose/runtime/Recomposer$recompositionRunner$2;-><init>(Landroidx/compose/runtime/Recomposer;Lkotlin/jvm/functions/Function3;Landroidx/compose/runtime/MonotonicFrameClock;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/runtime/Recomposer$recompositionRunner$2;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/runtime/Recomposer$recompositionRunner$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Recomposer$recompositionRunner$2;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Recomposer$runRecomposeAndApplyChanges$2$1;-><init>(Landroidx/compose/runtime/Recomposer;Landroidx/compose/runtime/collection/IdentityArraySet;Landroidx/compose/runtime/collection/IdentityArraySet;Ljava/util/List;Ljava/util/List;Ljava/util/Set;Ljava/util/List;Ljava/util/Set;)V
+HSPLandroidx/compose/runtime/Recomposer$runRecomposeAndApplyChanges$2$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Recomposer$runRecomposeAndApplyChanges$2;-><init>(Landroidx/compose/runtime/Recomposer;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/runtime/Recomposer$runRecomposeAndApplyChanges$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Recomposer$runRecomposeAndApplyChanges$2;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Recomposer;-><clinit>()V
+HSPLandroidx/compose/runtime/Recomposer;-><init>(Lkotlin/coroutines/CoroutineContext;)V
+HSPLandroidx/compose/runtime/Recomposer;->access$performRecompose(Landroidx/compose/runtime/Recomposer;Landroidx/compose/runtime/CompositionImpl;Landroidx/compose/runtime/collection/IdentityArraySet;)Landroidx/compose/runtime/CompositionImpl;
+HSPLandroidx/compose/runtime/Recomposer;->access$recordComposerModifications(Landroidx/compose/runtime/Recomposer;)Z
+HSPLandroidx/compose/runtime/Recomposer;->applyAndCheck(Landroidx/compose/runtime/snapshots/MutableSnapshot;)V
+HSPLandroidx/compose/runtime/Recomposer;->composeInitial$runtime_release(Landroidx/compose/runtime/CompositionImpl;Landroidx/compose/runtime/internal/ComposableLambdaImpl;)V
+HSPLandroidx/compose/runtime/Recomposer;->deriveStateLocked()Lkotlinx/coroutines/CancellableContinuation;
+HSPLandroidx/compose/runtime/Recomposer;->getCollectingParameterInformation$runtime_release()Z
+HSPLandroidx/compose/runtime/Recomposer;->getCompoundHashKey$runtime_release()I
+HSPLandroidx/compose/runtime/Recomposer;->getEffectCoroutineContext()Lkotlin/coroutines/CoroutineContext;
+HSPLandroidx/compose/runtime/Recomposer;->getHasBroadcastFrameClockAwaitersLocked()Z
+HSPLandroidx/compose/runtime/Recomposer;->getHasSchedulingWork()Z
+HSPLandroidx/compose/runtime/Recomposer;->getKnownCompositions()Ljava/util/List;
+HSPLandroidx/compose/runtime/Recomposer;->invalidate$runtime_release(Landroidx/compose/runtime/CompositionImpl;)V
+HSPLandroidx/compose/runtime/Recomposer;->performInitialMovableContentInserts(Landroidx/compose/runtime/CompositionImpl;)V
+HSPLandroidx/compose/runtime/ReferentialEqualityPolicy;-><clinit>()V
+HSPLandroidx/compose/runtime/ReferentialEqualityPolicy;->equivalent(Ljava/lang/Object;Ljava/lang/Object;)Z
+HSPLandroidx/compose/runtime/SkippableUpdater;-><init>(Landroidx/compose/runtime/Composer;)V
+HSPLandroidx/compose/runtime/SlotReader;-><init>(Landroidx/compose/runtime/SlotTable;)V
+HSPLandroidx/compose/runtime/SlotReader;->anchor(I)Landroidx/compose/runtime/Anchor;
+HSPLandroidx/compose/runtime/SlotReader;->aux([II)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/SlotReader;->close()V
+HSPLandroidx/compose/runtime/SlotReader;->endGroup()V
+HSPLandroidx/compose/runtime/SlotReader;->getGroupAux()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/SlotReader;->getGroupKey()I
+HSPLandroidx/compose/runtime/SlotReader;->groupGet(II)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/SlotReader;->groupSize(I)I
+HSPLandroidx/compose/runtime/SlotReader;->isNode(I)Z
+HSPLandroidx/compose/runtime/SlotReader;->node(I)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/SlotReader;->nodeCount(I)I
+HSPLandroidx/compose/runtime/SlotReader;->objectKey([II)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/SlotReader;->parent(I)I
+HSPLandroidx/compose/runtime/SlotReader;->reposition(I)V
+HSPLandroidx/compose/runtime/SlotReader;->skipGroup()I
+HSPLandroidx/compose/runtime/SlotReader;->skipToGroupEnd()V
+HSPLandroidx/compose/runtime/SlotReader;->startGroup()V
+HSPLandroidx/compose/runtime/SlotTable;-><init>()V
+HSPLandroidx/compose/runtime/SlotTable;->anchorIndex(Landroidx/compose/runtime/Anchor;)I
+HSPLandroidx/compose/runtime/SlotTable;->openReader()Landroidx/compose/runtime/SlotReader;
+HSPLandroidx/compose/runtime/SlotTable;->openWriter()Landroidx/compose/runtime/SlotWriter;
+HSPLandroidx/compose/runtime/SlotTable;->ownsAnchor(Landroidx/compose/runtime/Anchor;)Z
+HSPLandroidx/compose/runtime/SlotWriter;-><clinit>()V
+HSPLandroidx/compose/runtime/SlotWriter;-><init>(Landroidx/compose/runtime/SlotTable;)V
+HSPLandroidx/compose/runtime/SlotWriter;->advanceBy(I)V
+HSPLandroidx/compose/runtime/SlotWriter;->anchor(I)Landroidx/compose/runtime/Anchor;
+HSPLandroidx/compose/runtime/SlotWriter;->auxIndex([II)I
+HSPLandroidx/compose/runtime/SlotWriter;->beginInsert()V
+HSPLandroidx/compose/runtime/SlotWriter;->close()V
+HSPLandroidx/compose/runtime/SlotWriter;->dataIndex([II)I
+HSPLandroidx/compose/runtime/SlotWriter;->dataIndexToDataAddress(I)I
+HSPLandroidx/compose/runtime/SlotWriter;->endInsert()V
+HSPLandroidx/compose/runtime/SlotWriter;->getSize$runtime_release()I
+HSPLandroidx/compose/runtime/SlotWriter;->groupIndexToAddress(I)I
+HSPLandroidx/compose/runtime/SlotWriter;->groupSize(I)I
+HSPLandroidx/compose/runtime/SlotWriter;->markGroup$default(Landroidx/compose/runtime/SlotWriter;)V
+HSPLandroidx/compose/runtime/SlotWriter;->moveFrom(Landroidx/compose/runtime/SlotTable;I)V
+HSPLandroidx/compose/runtime/SlotWriter;->moveGroupGapTo(I)V
+HSPLandroidx/compose/runtime/SlotWriter;->moveSlotGapTo(II)V
+HSPLandroidx/compose/runtime/SlotWriter;->node(I)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/SlotWriter;->parent(I)I
+HSPLandroidx/compose/runtime/SlotWriter;->parent([II)I
+HSPLandroidx/compose/runtime/SlotWriter;->recalculateMarks()V
+HSPLandroidx/compose/runtime/SlotWriter;->set(IILjava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/SlotWriter;->skipToGroupEnd()V
+HSPLandroidx/compose/runtime/SlotWriter;->slotIndex([II)I
+HSPLandroidx/compose/runtime/SlotWriter;->updateAux(Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/SlotWriter;->updateContainsMark(I)V
+HSPLandroidx/compose/runtime/SlotWriter;->updateNodeOfGroup(ILjava/lang/Object;)V
+HSPLandroidx/compose/runtime/SnapshotMutableFloatStateImpl$FloatStateStateRecord;-><init>(F)V
+HSPLandroidx/compose/runtime/SnapshotMutableFloatStateImpl;-><init>(F)V
+HSPLandroidx/compose/runtime/SnapshotMutableFloatStateImpl;->setFloatValue(F)V
+HSPLandroidx/compose/runtime/SnapshotMutableIntStateImpl$IntStateStateRecord;-><init>(I)V
+HSPLandroidx/compose/runtime/SnapshotMutableIntStateImpl$IntStateStateRecord;->assign(Landroidx/compose/runtime/snapshots/StateRecord;)V
+HSPLandroidx/compose/runtime/SnapshotMutableIntStateImpl$IntStateStateRecord;->create()Landroidx/compose/runtime/snapshots/StateRecord;
+HSPLandroidx/compose/runtime/SnapshotMutableIntStateImpl;-><init>(I)V
+HSPLandroidx/compose/runtime/SnapshotMutableIntStateImpl;->getFirstStateRecord()Landroidx/compose/runtime/snapshots/StateRecord;
+HSPLandroidx/compose/runtime/SnapshotMutableIntStateImpl;->getIntValue()I
+HSPLandroidx/compose/runtime/SnapshotMutableIntStateImpl;->prependStateRecord(Landroidx/compose/runtime/snapshots/StateRecord;)V
+HSPLandroidx/compose/runtime/SnapshotMutableIntStateImpl;->setIntValue(I)V
+HSPLandroidx/compose/runtime/SnapshotMutableStateImpl$StateStateRecord;-><init>(Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/SnapshotMutableStateImpl$StateStateRecord;->assign(Landroidx/compose/runtime/snapshots/StateRecord;)V
+HSPLandroidx/compose/runtime/SnapshotMutableStateImpl$StateStateRecord;->create()Landroidx/compose/runtime/snapshots/StateRecord;
+HSPLandroidx/compose/runtime/SnapshotMutableStateImpl;-><init>(Ljava/lang/Object;Landroidx/compose/runtime/SnapshotMutationPolicy;)V
+HSPLandroidx/compose/runtime/SnapshotMutableStateImpl;->getFirstStateRecord()Landroidx/compose/runtime/snapshots/StateRecord;
+HSPLandroidx/compose/runtime/SnapshotMutableStateImpl;->getValue()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/SnapshotMutableStateImpl;->prependStateRecord(Landroidx/compose/runtime/snapshots/StateRecord;)V
+HSPLandroidx/compose/runtime/SnapshotMutableStateImpl;->setValue(Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/SnapshotStateKt__DerivedStateKt;-><clinit>()V
+HSPLandroidx/compose/runtime/SnapshotStateKt__ProduceStateKt$produceState$3;-><init>(Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/MutableState;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/runtime/SnapshotStateKt__ProduceStateKt$produceState$3;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/runtime/SnapshotStateKt__ProduceStateKt$produceState$3;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/SnapshotStateKt__SnapshotFlowKt$collectAsState$1$1;-><init>(Landroidx/compose/runtime/ProduceStateScopeImpl;I)V
+HSPLandroidx/compose/runtime/SnapshotStateKt__SnapshotFlowKt$collectAsState$1$1;->emit(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/SnapshotStateKt__SnapshotFlowKt$collectAsState$1;-><init>(Lkotlin/coroutines/CoroutineContext;Lkotlinx/coroutines/flow/Flow;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/runtime/SnapshotStateKt__SnapshotFlowKt$collectAsState$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/runtime/SnapshotStateKt__SnapshotFlowKt$collectAsState$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/SnapshotStateKt__SnapshotFlowKt$collectAsState$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Stack;-><init>()V
+HSPLandroidx/compose/runtime/Stack;-><init>(I)V
+HSPLandroidx/compose/runtime/Stack;-><init>(II)V
+HSPLandroidx/compose/runtime/Stack;-><init>(ILjava/lang/Object;)V
+HSPLandroidx/compose/runtime/Stack;-><init>(Landroid/content/Context;)V
+HSPLandroidx/compose/runtime/Stack;-><init>(Ljava/nio/ByteBuffer;)V
+HSPLandroidx/compose/runtime/Stack;->clear()V
+HSPLandroidx/compose/runtime/Stack;->load(Lokhttp3/MediaType;)V
+HSPLandroidx/compose/runtime/Stack;->pop()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/Stack;->readUnsignedInt()J
+HSPLandroidx/compose/runtime/Stack;->skip(I)V
+HSPLandroidx/compose/runtime/StaticProvidableCompositionLocal;->updatedStateOf$runtime_release(Ljava/lang/Object;Landroidx/compose/runtime/State;)Landroidx/compose/runtime/State;
+HSPLandroidx/compose/runtime/StaticValueHolder;-><init>(Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/StaticValueHolder;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/runtime/StaticValueHolder;->getValue()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/StructuralEqualityPolicy;-><clinit>()V
+HSPLandroidx/compose/runtime/StructuralEqualityPolicy;->equivalent(Ljava/lang/Object;Ljava/lang/Object;)Z
+HSPLandroidx/compose/runtime/changelist/ChangeList;-><init>()V
+HSPLandroidx/compose/runtime/changelist/ChangeList;->executeAndFlushAllPendingChanges(Landroidx/compose/runtime/Applier;Landroidx/compose/runtime/SlotWriter;Landroidx/compose/runtime/CompositionImpl$RememberEventDispatcher;)V
+HSPLandroidx/compose/runtime/changelist/ChangeList;->isEmpty()Z
+HSPLandroidx/compose/runtime/changelist/ComposerChangeListWriter;-><init>(Landroidx/compose/runtime/ComposerImpl;Landroidx/compose/runtime/changelist/ChangeList;)V
+HSPLandroidx/compose/runtime/changelist/ComposerChangeListWriter;->moveUp()V
+HSPLandroidx/compose/runtime/changelist/ComposerChangeListWriter;->pushPendingUpsAndDowns()V
+HSPLandroidx/compose/runtime/changelist/ComposerChangeListWriter;->realizeNodeMovementOperations()V
+HSPLandroidx/compose/runtime/changelist/ComposerChangeListWriter;->realizeOperationLocation(Z)V
+HSPLandroidx/compose/runtime/changelist/FixupList;-><init>()V
+HSPLandroidx/compose/runtime/changelist/Operation$AdvanceSlotsBy;-><clinit>()V
+HSPLandroidx/compose/runtime/changelist/Operation$AdvanceSlotsBy;-><init>()V
+HSPLandroidx/compose/runtime/changelist/Operation$AdvanceSlotsBy;->execute(Landroidx/compose/runtime/changelist/Operations$OpIterator;Landroidx/compose/runtime/Applier;Landroidx/compose/runtime/SlotWriter;Landroidx/compose/runtime/CompositionImpl$RememberEventDispatcher;)V
+HSPLandroidx/compose/runtime/changelist/Operation$DeactivateCurrentGroup;-><clinit>()V
+HSPLandroidx/compose/runtime/changelist/Operation$DeactivateCurrentGroup;-><init>()V
+HSPLandroidx/compose/runtime/changelist/Operation$DeactivateCurrentGroup;->execute(Landroidx/compose/runtime/changelist/Operations$OpIterator;Landroidx/compose/runtime/Applier;Landroidx/compose/runtime/SlotWriter;Landroidx/compose/runtime/CompositionImpl$RememberEventDispatcher;)V
+HSPLandroidx/compose/runtime/changelist/Operation$Downs;-><clinit>()V
+HSPLandroidx/compose/runtime/changelist/Operation$Downs;-><init>()V
+HSPLandroidx/compose/runtime/changelist/Operation$Downs;->execute(Landroidx/compose/runtime/changelist/Operations$OpIterator;Landroidx/compose/runtime/Applier;Landroidx/compose/runtime/SlotWriter;Landroidx/compose/runtime/CompositionImpl$RememberEventDispatcher;)V
+HSPLandroidx/compose/runtime/changelist/Operation$InsertNodeFixup;-><clinit>()V
+HSPLandroidx/compose/runtime/changelist/Operation$InsertNodeFixup;-><init>()V
+HSPLandroidx/compose/runtime/changelist/Operation$InsertNodeFixup;->execute(Landroidx/compose/runtime/changelist/Operations$OpIterator;Landroidx/compose/runtime/Applier;Landroidx/compose/runtime/SlotWriter;Landroidx/compose/runtime/CompositionImpl$RememberEventDispatcher;)V
+HSPLandroidx/compose/runtime/changelist/Operation$InsertSlotsWithFixups;-><clinit>()V
+HSPLandroidx/compose/runtime/changelist/Operation$InsertSlotsWithFixups;-><init>()V
+HSPLandroidx/compose/runtime/changelist/Operation$InsertSlotsWithFixups;->execute(Landroidx/compose/runtime/changelist/Operations$OpIterator;Landroidx/compose/runtime/Applier;Landroidx/compose/runtime/SlotWriter;Landroidx/compose/runtime/CompositionImpl$RememberEventDispatcher;)V
+HSPLandroidx/compose/runtime/changelist/Operation$PostInsertNodeFixup;-><clinit>()V
+HSPLandroidx/compose/runtime/changelist/Operation$PostInsertNodeFixup;-><init>()V
+HSPLandroidx/compose/runtime/changelist/Operation$PostInsertNodeFixup;->execute(Landroidx/compose/runtime/changelist/Operations$OpIterator;Landroidx/compose/runtime/Applier;Landroidx/compose/runtime/SlotWriter;Landroidx/compose/runtime/CompositionImpl$RememberEventDispatcher;)V
+HSPLandroidx/compose/runtime/changelist/Operation$Remember;-><clinit>()V
+HSPLandroidx/compose/runtime/changelist/Operation$Remember;-><init>()V
+HSPLandroidx/compose/runtime/changelist/Operation$Remember;->execute(Landroidx/compose/runtime/changelist/Operations$OpIterator;Landroidx/compose/runtime/Applier;Landroidx/compose/runtime/SlotWriter;Landroidx/compose/runtime/CompositionImpl$RememberEventDispatcher;)V
+HSPLandroidx/compose/runtime/changelist/Operation$SideEffect;-><clinit>()V
+HSPLandroidx/compose/runtime/changelist/Operation$SideEffect;-><init>()V
+HSPLandroidx/compose/runtime/changelist/Operation$SideEffect;->execute(Landroidx/compose/runtime/changelist/Operations$OpIterator;Landroidx/compose/runtime/Applier;Landroidx/compose/runtime/SlotWriter;Landroidx/compose/runtime/CompositionImpl$RememberEventDispatcher;)V
+HSPLandroidx/compose/runtime/changelist/Operation$UpdateAuxData;-><clinit>()V
+HSPLandroidx/compose/runtime/changelist/Operation$UpdateAuxData;-><init>()V
+HSPLandroidx/compose/runtime/changelist/Operation$UpdateAuxData;->execute(Landroidx/compose/runtime/changelist/Operations$OpIterator;Landroidx/compose/runtime/Applier;Landroidx/compose/runtime/SlotWriter;Landroidx/compose/runtime/CompositionImpl$RememberEventDispatcher;)V
+HSPLandroidx/compose/runtime/changelist/Operation$UpdateNode;-><clinit>()V
+HSPLandroidx/compose/runtime/changelist/Operation$UpdateNode;-><init>()V
+HSPLandroidx/compose/runtime/changelist/Operation$UpdateNode;->execute(Landroidx/compose/runtime/changelist/Operations$OpIterator;Landroidx/compose/runtime/Applier;Landroidx/compose/runtime/SlotWriter;Landroidx/compose/runtime/CompositionImpl$RememberEventDispatcher;)V
+HSPLandroidx/compose/runtime/changelist/Operation$UpdateValue;-><clinit>()V
+HSPLandroidx/compose/runtime/changelist/Operation$UpdateValue;-><init>()V
+HSPLandroidx/compose/runtime/changelist/Operation$UpdateValue;->execute(Landroidx/compose/runtime/changelist/Operations$OpIterator;Landroidx/compose/runtime/Applier;Landroidx/compose/runtime/SlotWriter;Landroidx/compose/runtime/CompositionImpl$RememberEventDispatcher;)V
+HSPLandroidx/compose/runtime/changelist/Operation$Ups;-><clinit>()V
+HSPLandroidx/compose/runtime/changelist/Operation$Ups;-><init>()V
+HSPLandroidx/compose/runtime/changelist/Operation$Ups;->execute(Landroidx/compose/runtime/changelist/Operations$OpIterator;Landroidx/compose/runtime/Applier;Landroidx/compose/runtime/SlotWriter;Landroidx/compose/runtime/CompositionImpl$RememberEventDispatcher;)V
+HSPLandroidx/compose/runtime/changelist/Operation$UseCurrentNode;-><clinit>()V
+HSPLandroidx/compose/runtime/changelist/Operation$UseCurrentNode;-><init>()V
+HSPLandroidx/compose/runtime/changelist/Operation$UseCurrentNode;->execute(Landroidx/compose/runtime/changelist/Operations$OpIterator;Landroidx/compose/runtime/Applier;Landroidx/compose/runtime/SlotWriter;Landroidx/compose/runtime/CompositionImpl$RememberEventDispatcher;)V
+HSPLandroidx/compose/runtime/changelist/Operation;-><init>(II)V
+HSPLandroidx/compose/runtime/changelist/Operation;-><init>(III)V
+HSPLandroidx/compose/runtime/changelist/Operations$OpIterator;-><init>(Landroidx/compose/runtime/changelist/Operations;)V
+HSPLandroidx/compose/runtime/changelist/Operations$OpIterator;->getInt-w8GmfQM(I)I
+HSPLandroidx/compose/runtime/changelist/Operations$OpIterator;->getObject-31yXWZQ(I)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/changelist/Operations;-><init>()V
+HSPLandroidx/compose/runtime/changelist/Operations;->access$createExpectedArgMask(Landroidx/compose/runtime/changelist/Operations;I)I
+HSPLandroidx/compose/runtime/changelist/Operations;->clear()V
+HSPLandroidx/compose/runtime/changelist/Operations;->executeAndFlushAllPendingOperations(Landroidx/compose/runtime/Applier;Landroidx/compose/runtime/SlotWriter;Landroidx/compose/runtime/CompositionImpl$RememberEventDispatcher;)V
+HSPLandroidx/compose/runtime/changelist/Operations;->peekOperation()Landroidx/compose/runtime/changelist/Operation;
+HSPLandroidx/compose/runtime/changelist/Operations;->push(Landroidx/compose/runtime/changelist/Operation;)V
+HSPLandroidx/compose/runtime/changelist/Operations;->pushOp(Landroidx/compose/runtime/changelist/Operation;)V
+HSPLandroidx/compose/runtime/collection/IdentityArrayIntMap;-><init>()V
+HSPLandroidx/compose/runtime/collection/IdentityArrayIntMap;->add(ILjava/lang/Object;)I
+HSPLandroidx/compose/runtime/collection/IdentityArrayMap$asMap$1$entries$1$iterator$1$1;-><init>(Ljava/lang/Object;Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/collection/IdentityArrayMap$asMap$1$entries$1$iterator$1$1;->getKey()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/collection/IdentityArrayMap$asMap$1$entries$1$iterator$1$1;->getValue()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/collection/IdentityArraySet;-><init>()V
+HSPLandroidx/compose/runtime/collection/IdentityArraySet;->add(Ljava/lang/Object;)Z
+HSPLandroidx/compose/runtime/collection/IdentityArraySet;->addAll(Ljava/util/Collection;)V
+HSPLandroidx/compose/runtime/collection/IdentityArraySet;->clear()V
+HSPLandroidx/compose/runtime/collection/IdentityArraySet;->contains(Ljava/lang/Object;)Z
+HSPLandroidx/compose/runtime/collection/IdentityArraySet;->find(Ljava/lang/Object;)I
+HSPLandroidx/compose/runtime/collection/IdentityArraySet;->isEmpty()Z
+HSPLandroidx/compose/runtime/collection/IdentityArraySet;->isNotEmpty()Z
+HSPLandroidx/compose/runtime/collection/IdentityArraySet;->iterator()Ljava/util/Iterator;
+HSPLandroidx/compose/runtime/collection/IdentityArraySet;->remove(Ljava/lang/Object;)Z
+HSPLandroidx/compose/runtime/collection/MutableVector$MutableVectorList;-><init>(Landroidx/compose/runtime/collection/MutableVector;)V
+HSPLandroidx/compose/runtime/collection/MutableVector$MutableVectorList;->get(I)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/collection/MutableVector$MutableVectorList;->indexOf(Ljava/lang/Object;)I
+HSPLandroidx/compose/runtime/collection/MutableVector$MutableVectorList;->isEmpty()Z
+HSPLandroidx/compose/runtime/collection/MutableVector$MutableVectorList;->iterator()Ljava/util/Iterator;
+HSPLandroidx/compose/runtime/collection/MutableVector$MutableVectorList;->size()I
+HSPLandroidx/compose/runtime/collection/MutableVector$VectorListIterator;-><init>(ILjava/util/List;)V
+HSPLandroidx/compose/runtime/collection/MutableVector$VectorListIterator;->hasNext()Z
+HSPLandroidx/compose/runtime/collection/MutableVector$VectorListIterator;->next()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/collection/MutableVector;-><init>([Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/collection/MutableVector;->add(ILjava/lang/Object;)V
+HSPLandroidx/compose/runtime/collection/MutableVector;->add(Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/collection/MutableVector;->addAll(ILandroidx/compose/runtime/collection/MutableVector;)V
+HSPLandroidx/compose/runtime/collection/MutableVector;->asMutableList()Ljava/util/List;
+HSPLandroidx/compose/runtime/collection/MutableVector;->clear()V
+HSPLandroidx/compose/runtime/collection/MutableVector;->contains(Ljava/lang/Object;)Z
+HSPLandroidx/compose/runtime/collection/MutableVector;->ensureCapacity(I)V
+HSPLandroidx/compose/runtime/collection/MutableVector;->indexOf(Ljava/lang/Object;)I
+HSPLandroidx/compose/runtime/collection/MutableVector;->isEmpty()Z
+HSPLandroidx/compose/runtime/collection/MutableVector;->isNotEmpty()Z
+HSPLandroidx/compose/runtime/collection/MutableVector;->remove(Ljava/lang/Object;)Z
+HSPLandroidx/compose/runtime/collection/MutableVector;->removeAt(I)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/collection/MutableVector;->removeRange(II)V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableList/SmallPersistentVector;-><clinit>()V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableList/SmallPersistentVector;-><init>([Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableList/SmallPersistentVector;->add(Ljava/lang/Object;)Landroidx/compose/runtime/external/kotlinx/collections/immutable/PersistentList;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableList/SmallPersistentVector;->get(I)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableList/SmallPersistentVector;->getSize()I
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableList/SmallPersistentVector;->indexOf(Ljava/lang/Object;)I
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableList/SmallPersistentVector;->removeAt(I)Landroidx/compose/runtime/external/kotlinx/collections/immutable/PersistentList;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMap;-><clinit>()V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMap;-><init>(Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;I)V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMap;->containsKey(Ljava/lang/Object;)Z
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMap;->get(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMap;->put(Ljava/lang/Object;Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/persistentOrderedSet/Links;)Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMap;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapBaseIterator;-><init>(Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;[Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNodeBaseIterator;)V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapBaseIterator;->ensureNextEntryIsReady()V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapBaseIterator;->hasNext()Z
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapBaseIterator;->moveToNextNodeWithData(I)I
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapBaseIterator;->next()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapBuilder;-><init>(Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMap;)V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapBuilder;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapBuilder;->putAll(Ljava/util/Map;)V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapBuilder;->setSize(I)V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapKeys;-><init>(Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMap;I)V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapKeys;->getSize()I
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapKeys;->iterator()Ljava/util/Iterator;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapKeysIterator;-><init>(Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;I)V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;-><clinit>()V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;-><init>(II[Ljava/lang/Object;L_COROUTINE/ArtificialStackFrames;)V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;->bufferMoveEntryToNode(IIILjava/lang/Object;Ljava/lang/Object;IL_COROUTINE/ArtificialStackFrames;)[Ljava/lang/Object;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;->containsKey(IILjava/lang/Object;)Z
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;->elementsIdentityEquals(Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;)Z
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;->entryKeyIndex$runtime_release(I)I
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;->get(IILjava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;->hasEntryAt$runtime_release(I)Z
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;->hasNodeAt(I)Z
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;->makeNode(ILjava/lang/Object;Ljava/lang/Object;ILjava/lang/Object;Ljava/lang/Object;IL_COROUTINE/ArtificialStackFrames;)Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;->mutablePut(ILjava/lang/Object;Ljava/lang/Object;ILandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapBuilder;)Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;->mutablePutAll(Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;ILandroidx/compose/runtime/external/kotlinx/collections/immutable/internal/DeltaCounter;Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapBuilder;)Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;->nodeAtIndex$runtime_release(I)Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;->nodeIndex$runtime_release(I)I
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;->put(IILjava/lang/Object;Ljava/lang/Object;)Landroidx/compose/ui/input/pointer/util/PointerIdArray;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;->valueAtKeyIndex(I)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNodeBaseIterator;-><init>()V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNodeBaseIterator;->reset(II[Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNodeKeysIterator;-><init>(I)V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNodeKeysIterator;->next()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/persistentOrderedSet/Links;-><init>(Ljava/lang/Object;Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/persistentOrderedSet/PersistentOrderedSet;-><clinit>()V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/persistentOrderedSet/PersistentOrderedSet;-><init>(Ljava/lang/Object;Ljava/lang/Object;Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMap;)V
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/persistentOrderedSet/PersistentOrderedSet;->getSize()I
+HSPLandroidx/compose/runtime/external/kotlinx/collections/immutable/internal/DeltaCounter;-><init>()V
+HSPLandroidx/compose/runtime/internal/ComposableLambdaImpl;-><init>(IZ)V
+HSPLandroidx/compose/runtime/internal/ComposableLambdaImpl;->invoke(Ljava/lang/Object;Landroidx/compose/runtime/Composer;I)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/internal/ComposableLambdaImpl;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/internal/ComposableLambdaImpl;->invoke(Ljava/lang/Object;Ljava/lang/Object;Landroidx/compose/runtime/Composer;I)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/internal/ComposableLambdaImpl;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/internal/ComposableLambdaImpl;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/internal/ComposableLambdaImpl;->update(Lkotlin/jvm/internal/Lambda;)V
+HSPLandroidx/compose/runtime/internal/PersistentCompositionLocalHashMap$Builder;-><init>(Landroidx/compose/runtime/internal/PersistentCompositionLocalHashMap;)V
+HSPLandroidx/compose/runtime/internal/PersistentCompositionLocalHashMap$Builder;->build()Landroidx/compose/runtime/internal/PersistentCompositionLocalHashMap;
+HSPLandroidx/compose/runtime/internal/PersistentCompositionLocalHashMap;-><clinit>()V
+HSPLandroidx/compose/runtime/internal/PersistentCompositionLocalHashMap;->containsKey(Ljava/lang/Object;)Z
+HSPLandroidx/compose/runtime/internal/PersistentCompositionLocalHashMap;->get(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/internal/PersistentCompositionLocalHashMap;->putValue(Landroidx/compose/runtime/CompositionLocal;Landroidx/compose/runtime/State;)Landroidx/compose/runtime/internal/PersistentCompositionLocalHashMap;
+HSPLandroidx/compose/runtime/internal/ThreadMap;-><init>(I[J[Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/internal/ThreadMap;->find(J)I
+HSPLandroidx/compose/runtime/internal/ThreadMap;->newWith(JLjava/lang/Object;)Landroidx/compose/runtime/internal/ThreadMap;
+HSPLandroidx/compose/runtime/saveable/ListSaverKt$listSaver$1;-><init>(Lkotlin/coroutines/CoroutineContext$plus$1;)V
+HSPLandroidx/compose/runtime/saveable/ListSaverKt$listSaver$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/saveable/RememberSaveableKt$rememberSaveable$1;-><init>(Landroidx/compose/runtime/saveable/SaveableHolder;Landroidx/compose/runtime/saveable/SaverKt$Saver$1;Landroidx/compose/runtime/saveable/SaveableStateRegistry;Ljava/lang/String;Ljava/lang/Object;[Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/saveable/RememberSaveableKt$rememberSaveable$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/saveable/SaveableHolder;-><init>(Landroidx/compose/runtime/saveable/SaverKt$Saver$1;Landroidx/compose/runtime/saveable/SaveableStateRegistry;Ljava/lang/String;Ljava/lang/Object;[Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/saveable/SaveableHolder;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/runtime/saveable/SaveableHolder;->onRemembered()V
+HSPLandroidx/compose/runtime/saveable/SaveableHolder;->register()V
+HSPLandroidx/compose/runtime/saveable/SaveableStateHolderImpl$RegistryHolder$registry$1;-><init>(Landroidx/compose/runtime/saveable/SaveableStateHolderImpl;)V
+HSPLandroidx/compose/runtime/saveable/SaveableStateHolderImpl$RegistryHolder;-><init>(Landroidx/compose/runtime/saveable/SaveableStateHolderImpl;Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/saveable/SaveableStateHolderImpl$SaveableStateProvider$1$1$invoke$$inlined$onDispose$1;-><init>(Landroidx/compose/runtime/saveable/SaveableStateHolderImpl$RegistryHolder;Landroidx/compose/runtime/saveable/SaveableStateHolderImpl;Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/saveable/SaveableStateHolderImpl$SaveableStateProvider$1$1$invoke$$inlined$onDispose$1;->dispose()V
+HSPLandroidx/compose/runtime/saveable/SaveableStateHolderImpl;-><clinit>()V
+HSPLandroidx/compose/runtime/saveable/SaveableStateHolderImpl;-><init>(Ljava/util/Map;)V
+HSPLandroidx/compose/runtime/saveable/SaveableStateHolderImpl;->SaveableStateProvider(Ljava/lang/Object;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/runtime/saveable/SaveableStateRegistryImpl$registerProvider$3;-><init>(Landroidx/compose/runtime/saveable/SaveableStateRegistryImpl;Ljava/lang/String;Lkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/runtime/saveable/SaveableStateRegistryImpl;-><init>(Ljava/util/Map;Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/runtime/saveable/SaveableStateRegistryImpl;->canBeSaved(Ljava/lang/Object;)Z
+HSPLandroidx/compose/runtime/saveable/SaveableStateRegistryImpl;->consumeRestored(Ljava/lang/String;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/saveable/SaveableStateRegistryImpl;->performSave()Ljava/util/Map;
+HSPLandroidx/compose/runtime/saveable/SaveableStateRegistryImpl;->registerProvider(Ljava/lang/String;Lkotlin/jvm/functions/Function0;)Landroidx/compose/runtime/saveable/SaveableStateRegistryImpl$registerProvider$3;
+HSPLandroidx/compose/runtime/saveable/SaveableStateRegistryKt;-><clinit>()V
+HSPLandroidx/compose/runtime/saveable/SaverKt$Saver$1;-><init>(Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/runtime/saveable/SaverKt;-><clinit>()V
+HSPLandroidx/compose/runtime/snapshots/GlobalSnapshot$1$1$1;-><init>(ILjava/util/List;)V
+HSPLandroidx/compose/runtime/snapshots/GlobalSnapshot$1$1$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/snapshots/GlobalSnapshot;-><init>(ILandroidx/compose/runtime/snapshots/SnapshotIdSet;)V
+HSPLandroidx/compose/runtime/snapshots/GlobalSnapshot;->dispose()V
+HSPLandroidx/compose/runtime/snapshots/GlobalSnapshot;->notifyObjectsInitialized$runtime_release()V
+HSPLandroidx/compose/runtime/snapshots/GlobalSnapshot;->takeNestedMutableSnapshot(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Landroidx/compose/runtime/snapshots/MutableSnapshot;
+HSPLandroidx/compose/runtime/snapshots/MutableSnapshot;-><clinit>()V
+HSPLandroidx/compose/runtime/snapshots/MutableSnapshot;-><init>(ILandroidx/compose/runtime/snapshots/SnapshotIdSet;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/runtime/snapshots/MutableSnapshot;->advance$runtime_release()V
+HSPLandroidx/compose/runtime/snapshots/MutableSnapshot;->apply()Lokhttp3/MediaType;
+HSPLandroidx/compose/runtime/snapshots/MutableSnapshot;->closeLocked$runtime_release()V
+HSPLandroidx/compose/runtime/snapshots/MutableSnapshot;->dispose()V
+HSPLandroidx/compose/runtime/snapshots/MutableSnapshot;->getModified$runtime_release()Landroidx/compose/runtime/collection/IdentityArraySet;
+HSPLandroidx/compose/runtime/snapshots/MutableSnapshot;->getReadObserver$runtime_release()Lkotlin/jvm/functions/Function1;
+HSPLandroidx/compose/runtime/snapshots/MutableSnapshot;->getReadOnly()Z
+HSPLandroidx/compose/runtime/snapshots/MutableSnapshot;->getWriteCount$runtime_release()I
+HSPLandroidx/compose/runtime/snapshots/MutableSnapshot;->getWriteObserver$runtime_release()Lkotlin/jvm/functions/Function1;
+HSPLandroidx/compose/runtime/snapshots/MutableSnapshot;->innerApplyLocked$runtime_release(ILjava/util/HashMap;Landroidx/compose/runtime/snapshots/SnapshotIdSet;)Lokhttp3/MediaType;
+HSPLandroidx/compose/runtime/snapshots/MutableSnapshot;->nestedDeactivated$runtime_release()V
+HSPLandroidx/compose/runtime/snapshots/MutableSnapshot;->notifyObjectsInitialized$runtime_release()V
+HSPLandroidx/compose/runtime/snapshots/MutableSnapshot;->recordModified$runtime_release(Landroidx/compose/runtime/snapshots/StateObject;)V
+HSPLandroidx/compose/runtime/snapshots/MutableSnapshot;->recordPrevious$runtime_release(I)V
+HSPLandroidx/compose/runtime/snapshots/MutableSnapshot;->releasePinnedSnapshotsForCloseLocked$runtime_release()V
+HSPLandroidx/compose/runtime/snapshots/MutableSnapshot;->setModified(Landroidx/compose/runtime/collection/IdentityArraySet;)V
+HSPLandroidx/compose/runtime/snapshots/MutableSnapshot;->setWriteCount$runtime_release(I)V
+HSPLandroidx/compose/runtime/snapshots/Snapshot$Companion$$ExternalSyntheticLambda0;-><init>(Lkotlin/jvm/internal/Lambda;I)V
+HSPLandroidx/compose/runtime/snapshots/Snapshot;-><init>(ILandroidx/compose/runtime/snapshots/SnapshotIdSet;)V
+HSPLandroidx/compose/runtime/snapshots/Snapshot;->getId()I
+HSPLandroidx/compose/runtime/snapshots/Snapshot;->getInvalid$runtime_release()Landroidx/compose/runtime/snapshots/SnapshotIdSet;
+HSPLandroidx/compose/runtime/snapshots/Snapshot;->makeCurrent()Landroidx/compose/runtime/snapshots/Snapshot;
+HSPLandroidx/compose/runtime/snapshots/Snapshot;->restoreCurrent(Landroidx/compose/runtime/snapshots/Snapshot;)V
+HSPLandroidx/compose/runtime/snapshots/Snapshot;->setId$runtime_release(I)V
+HSPLandroidx/compose/runtime/snapshots/Snapshot;->setInvalid$runtime_release(Landroidx/compose/runtime/snapshots/SnapshotIdSet;)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotApplyResult$Success;-><clinit>()V
+HSPLandroidx/compose/runtime/snapshots/SnapshotDoubleIndexHeap;-><init>()V
+HSPLandroidx/compose/runtime/snapshots/SnapshotDoubleIndexHeap;->add(I)I
+HSPLandroidx/compose/runtime/snapshots/SnapshotDoubleIndexHeap;->swap(II)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotIdSet;-><clinit>()V
+HSPLandroidx/compose/runtime/snapshots/SnapshotIdSet;-><init>(JJI[I)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotIdSet;->andNot(Landroidx/compose/runtime/snapshots/SnapshotIdSet;)Landroidx/compose/runtime/snapshots/SnapshotIdSet;
+HSPLandroidx/compose/runtime/snapshots/SnapshotIdSet;->clear(I)Landroidx/compose/runtime/snapshots/SnapshotIdSet;
+HSPLandroidx/compose/runtime/snapshots/SnapshotIdSet;->get(I)Z
+HSPLandroidx/compose/runtime/snapshots/SnapshotIdSet;->or(Landroidx/compose/runtime/snapshots/SnapshotIdSet;)Landroidx/compose/runtime/snapshots/SnapshotIdSet;
+HSPLandroidx/compose/runtime/snapshots/SnapshotIdSet;->set(I)Landroidx/compose/runtime/snapshots/SnapshotIdSet;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt$mergedReadObserver$1;-><init>(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;I)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt$mergedReadObserver$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt$mergedReadObserver$1;->invoke(Ljava/lang/Object;)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;-><clinit>()V
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->access$advanceGlobalSnapshot()V
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->access$mergedWriteObserver(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Lkotlin/jvm/functions/Function1;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->access$optimisticMerges(Landroidx/compose/runtime/snapshots/MutableSnapshot;Landroidx/compose/runtime/snapshots/MutableSnapshot;Landroidx/compose/runtime/snapshots/SnapshotIdSet;)Ljava/util/HashMap;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->access$validateOpen(Landroidx/compose/runtime/snapshots/Snapshot;)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->advanceGlobalSnapshot(Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->checkAndOverwriteUnusedRecordsLocked()V
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->createTransparentSnapshotWithNoParentReadObserver(Landroidx/compose/runtime/snapshots/Snapshot;Lkotlin/jvm/functions/Function1;Z)Landroidx/compose/runtime/snapshots/Snapshot;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->current(Landroidx/compose/runtime/snapshots/StateRecord;)Landroidx/compose/runtime/snapshots/StateRecord;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->currentSnapshot()Landroidx/compose/runtime/snapshots/Snapshot;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->mergedReadObserver(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Z)Lkotlin/jvm/functions/Function1;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->newOverwritableRecordLocked(Landroidx/compose/runtime/snapshots/StateRecord;Landroidx/compose/runtime/snapshots/StateObject;)Landroidx/compose/runtime/snapshots/StateRecord;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->notifyWrite(Landroidx/compose/runtime/snapshots/Snapshot;Landroidx/compose/runtime/snapshots/StateObject;)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->overwritableRecord(Landroidx/compose/runtime/snapshots/StateRecord;Landroidx/compose/runtime/snapshots/StateObject;Landroidx/compose/runtime/snapshots/Snapshot;Landroidx/compose/runtime/snapshots/StateRecord;)Landroidx/compose/runtime/snapshots/StateRecord;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->overwriteUnusedRecordsLocked(Landroidx/compose/runtime/snapshots/StateObject;)Z
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->processForUnusedRecordsLocked(Landroidx/compose/runtime/snapshots/StateObject;)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->readable(Landroidx/compose/runtime/snapshots/StateRecord;ILandroidx/compose/runtime/snapshots/SnapshotIdSet;)Landroidx/compose/runtime/snapshots/StateRecord;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->readable(Landroidx/compose/runtime/snapshots/StateRecord;Landroidx/compose/runtime/snapshots/StateObject;)Landroidx/compose/runtime/snapshots/StateRecord;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->releasePinningLocked(I)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->takeNewGlobalSnapshot(Landroidx/compose/runtime/snapshots/Snapshot;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/snapshots/SnapshotKt;->writableRecord(Landroidx/compose/runtime/snapshots/StateRecord;Landroidx/compose/runtime/snapshots/StateObject;Landroidx/compose/runtime/snapshots/Snapshot;)Landroidx/compose/runtime/snapshots/StateRecord;
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateList$StateListStateRecord;-><init>(Landroidx/compose/runtime/external/kotlinx/collections/immutable/PersistentList;)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateList$StateListStateRecord;->assign(Landroidx/compose/runtime/snapshots/StateRecord;)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateList$StateListStateRecord;->create()Landroidx/compose/runtime/snapshots/StateRecord;
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateList$addAll$1;-><init>(Landroidx/compose/ui/layout/Placeable;II)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateList$addAll$1;->invoke(Landroidx/compose/ui/layout/Placeable$PlacementScope;)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateList$addAll$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateList;-><init>()V
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateList;->add(Ljava/lang/Object;)Z
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateList;->get(I)Ljava/lang/Object;
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateList;->getFirstStateRecord()Landroidx/compose/runtime/snapshots/StateRecord;
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateList;->getReadable$runtime_release()Landroidx/compose/runtime/snapshots/SnapshotStateList$StateListStateRecord;
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateList;->isEmpty()Z
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateList;->prependStateRecord(Landroidx/compose/runtime/snapshots/StateRecord;)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateList;->remove(Ljava/lang/Object;)Z
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateList;->size()I
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateListKt;-><clinit>()V
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap;-><init>(Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap;->observe(Ljava/lang/Object;Lkotlin/collections/AbstractMap$toString$1;Lkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap;->recordInvalidation(Ljava/util/Set;)Z
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap;->recordRead(Ljava/lang/Object;ILjava/lang/Object;Landroidx/compose/runtime/collection/IdentityArrayIntMap;)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap;->removeScopeIf()V
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver;-><init>(Landroidx/compose/ui/platform/AndroidComposeView$focusOwner$1;)V
+HSPLandroidx/compose/runtime/snapshots/SnapshotStateObserver;->access$drainChanges(Landroidx/compose/runtime/snapshots/SnapshotStateObserver;)Z
+HSPLandroidx/compose/runtime/snapshots/StateRecord;-><init>()V
+HSPLandroidx/compose/runtime/snapshots/TransparentObserverMutableSnapshot;-><init>(Landroidx/compose/runtime/snapshots/MutableSnapshot;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;ZZ)V
+HSPLandroidx/compose/runtime/snapshots/TransparentObserverMutableSnapshot;->apply()Lokhttp3/MediaType;
+HSPLandroidx/compose/runtime/snapshots/TransparentObserverMutableSnapshot;->dispose()V
+HSPLandroidx/compose/runtime/snapshots/TransparentObserverMutableSnapshot;->getId()I
+HSPLandroidx/compose/runtime/snapshots/TransparentObserverMutableSnapshot;->getInvalid$runtime_release()Landroidx/compose/runtime/snapshots/SnapshotIdSet;
+HSPLandroidx/compose/runtime/snapshots/TransparentObserverMutableSnapshot;->getReadOnly()Z
+HSPLandroidx/compose/runtime/snapshots/TransparentObserverMutableSnapshot;->getWriteCount$runtime_release()I
+HSPLandroidx/compose/runtime/snapshots/TransparentObserverMutableSnapshot;->notifyObjectsInitialized$runtime_release()V
+HSPLandroidx/compose/runtime/snapshots/TransparentObserverMutableSnapshot;->recordModified$runtime_release(Landroidx/compose/runtime/snapshots/StateObject;)V
+HSPLandroidx/compose/runtime/snapshots/TransparentObserverMutableSnapshot;->setWriteCount$runtime_release(I)V
+HSPLandroidx/compose/runtime/snapshots/TransparentObserverMutableSnapshot;->takeNestedMutableSnapshot(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Landroidx/compose/runtime/snapshots/MutableSnapshot;
+HSPLandroidx/compose/runtime/tooling/InspectionTablesKt;-><clinit>()V
+HSPLandroidx/compose/ui/BiasAlignment$Horizontal;-><init>(F)V
+HSPLandroidx/compose/ui/BiasAlignment$Horizontal;->align(IILandroidx/compose/ui/unit/LayoutDirection;)I
+HSPLandroidx/compose/ui/BiasAlignment$Horizontal;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/BiasAlignment$Vertical;-><init>(F)V
+HSPLandroidx/compose/ui/BiasAlignment$Vertical;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/BiasAlignment;-><init>(FF)V
+HSPLandroidx/compose/ui/BiasAlignment;->align-KFBX0sM(JJLandroidx/compose/ui/unit/LayoutDirection;)J
+HSPLandroidx/compose/ui/BiasAlignment;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/CombinedModifier$toString$1;-><clinit>()V
+HSPLandroidx/compose/ui/CombinedModifier$toString$1;-><init>(I)V
+HSPLandroidx/compose/ui/CombinedModifier$toString$1;->invoke(Landroidx/compose/ui/layout/Measurable;I)Ljava/lang/Integer;
+HSPLandroidx/compose/ui/CombinedModifier$toString$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/CombinedModifier;-><init>(Landroidx/compose/ui/Modifier;Landroidx/compose/ui/Modifier;)V
+HSPLandroidx/compose/ui/CombinedModifier;->all(Lkotlin/jvm/functions/Function1;)Z
+HSPLandroidx/compose/ui/CombinedModifier;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/CombinedModifier;->foldIn(Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/ComposedModifier;-><init>(Lkotlin/jvm/functions/Function3;)V
+HSPLandroidx/compose/ui/Modifier$Companion;-><clinit>()V
+HSPLandroidx/compose/ui/Modifier$Companion;->all(Lkotlin/jvm/functions/Function1;)Z
+HSPLandroidx/compose/ui/Modifier$Companion;->then(Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/Modifier$Element;->all(Lkotlin/jvm/functions/Function1;)Z
+HSPLandroidx/compose/ui/Modifier$Element;->foldIn(Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/Modifier$Node;-><init>()V
+HSPLandroidx/compose/ui/Modifier$Node;->getCoroutineScope()Lkotlinx/coroutines/CoroutineScope;
+HSPLandroidx/compose/ui/Modifier$Node;->getShouldAutoInvalidate()Z
+HSPLandroidx/compose/ui/Modifier$Node;->markAsAttached$ui_release()V
+HSPLandroidx/compose/ui/Modifier$Node;->markAsDetached$ui_release()V
+HSPLandroidx/compose/ui/Modifier$Node;->onAttach()V
+HSPLandroidx/compose/ui/Modifier$Node;->onDetach()V
+HSPLandroidx/compose/ui/Modifier$Node;->onReset()V
+HSPLandroidx/compose/ui/Modifier$Node;->reset$ui_release()V
+HSPLandroidx/compose/ui/Modifier$Node;->runAttachLifecycle$ui_release()V
+HSPLandroidx/compose/ui/Modifier$Node;->runDetachLifecycle$ui_release()V
+HSPLandroidx/compose/ui/Modifier$Node;->updateCoordinator$ui_release(Landroidx/compose/ui/node/NodeCoordinator;)V
+HSPLandroidx/compose/ui/Modifier;->then(Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/MotionDurationScale;->getKey()Lkotlin/coroutines/CoroutineContext$Key;
+HSPLandroidx/compose/ui/ZIndexElement;-><init>()V
+HSPLandroidx/compose/ui/ZIndexElement;->create()Landroidx/compose/ui/Modifier$Node;
+HSPLandroidx/compose/ui/ZIndexElement;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/ZIndexNode$measure$1;-><init>(Ljava/lang/Object;ILjava/lang/Object;)V
+HSPLandroidx/compose/ui/ZIndexNode$measure$1;->invoke(Landroidx/compose/ui/layout/Placeable$PlacementScope;)V
+HSPLandroidx/compose/ui/ZIndexNode$measure$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/ZIndexNode$measure$1;->invoke(Ljava/lang/Throwable;)V
+HSPLandroidx/compose/ui/ZIndexNode;-><init>(F)V
+HSPLandroidx/compose/ui/ZIndexNode;->measure-3p2s80s(Landroidx/compose/ui/layout/MeasureScope;Landroidx/compose/ui/layout/Measurable;J)Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/compose/ui/autofill/AndroidAutofill;-><init>(Landroid/view/View;Landroidx/compose/ui/autofill/AutofillTree;)V
+HSPLandroidx/compose/ui/autofill/AutofillCallback;-><clinit>()V
+HSPLandroidx/compose/ui/autofill/AutofillCallback;->register(Landroidx/compose/ui/autofill/AndroidAutofill;)V
+HSPLandroidx/compose/ui/autofill/AutofillTree;-><init>()V
+HSPLandroidx/compose/ui/draw/CacheDrawModifierNodeImpl;-><init>(Landroidx/compose/ui/draw/CacheDrawScope;Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/draw/CacheDrawModifierNodeImpl;->draw(Landroidx/compose/ui/graphics/drawscope/ContentDrawScope;)V
+HSPLandroidx/compose/ui/draw/CacheDrawModifierNodeImpl;->getDensity()Landroidx/compose/ui/unit/Density;
+HSPLandroidx/compose/ui/draw/CacheDrawModifierNodeImpl;->getLayoutDirection()Landroidx/compose/ui/unit/LayoutDirection;
+HSPLandroidx/compose/ui/draw/CacheDrawModifierNodeImpl;->getSize-NH-jbRc()J
+HSPLandroidx/compose/ui/draw/CacheDrawModifierNodeImpl;->invalidateDrawCache()V
+HSPLandroidx/compose/ui/draw/CacheDrawModifierNodeImpl;->onMeasureResultChanged()V
+HSPLandroidx/compose/ui/draw/CacheDrawScope$onDrawBehind$1;-><init>(ILkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/draw/CacheDrawScope$onDrawBehind$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/draw/CacheDrawScope;-><init>()V
+HSPLandroidx/compose/ui/draw/CacheDrawScope;->getDensity()F
+HSPLandroidx/compose/ui/draw/CacheDrawScope;->getSize-NH-jbRc()J
+HSPLandroidx/compose/ui/draw/CacheDrawScope;->onDrawWithContent(Lkotlin/jvm/functions/Function1;)Landroidx/compose/ui/draw/DrawResult;
+HSPLandroidx/compose/ui/draw/ClipKt;->clip(Landroidx/compose/ui/Modifier;Landroidx/compose/ui/graphics/Shape;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/draw/ClipKt;->clipToBounds(Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/draw/ClipKt;->drawWithCache(Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function1;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/draw/ClipKt;->paint$default(Landroidx/compose/ui/Modifier;Landroidx/compose/ui/graphics/painter/Painter;Landroidx/compose/ui/Alignment;Landroidx/compose/ui/layout/ContentScale;FLandroidx/compose/ui/graphics/BlendModeColorFilter;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/draw/DrawResult;-><init>(Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/draw/DrawWithCacheElement;-><init>(Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/draw/DrawWithCacheElement;->create()Landroidx/compose/ui/Modifier$Node;
+HSPLandroidx/compose/ui/draw/DrawWithCacheElement;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/draw/EmptyBuildDrawCacheParams;-><clinit>()V
+HSPLandroidx/compose/ui/draw/PainterElement;-><init>(Landroidx/compose/ui/graphics/painter/Painter;ZLandroidx/compose/ui/Alignment;Landroidx/compose/ui/layout/ContentScale;FLandroidx/compose/ui/graphics/BlendModeColorFilter;)V
+HSPLandroidx/compose/ui/draw/PainterElement;->create()Landroidx/compose/ui/Modifier$Node;
+HSPLandroidx/compose/ui/draw/PainterElement;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/draw/PainterElement;->update(Landroidx/compose/ui/Modifier$Node;)V
+HSPLandroidx/compose/ui/draw/PainterNode$measure$1;-><init>(Landroidx/compose/ui/layout/Placeable;I)V
+HSPLandroidx/compose/ui/draw/PainterNode$measure$1;->invoke(Landroidx/compose/ui/layout/Placeable$PlacementScope;)V
+HSPLandroidx/compose/ui/draw/PainterNode$measure$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/draw/PainterNode;-><init>(Landroidx/compose/ui/graphics/painter/Painter;ZLandroidx/compose/ui/Alignment;Landroidx/compose/ui/layout/ContentScale;FLandroidx/compose/ui/graphics/BlendModeColorFilter;)V
+HSPLandroidx/compose/ui/draw/PainterNode;->draw(Landroidx/compose/ui/graphics/drawscope/ContentDrawScope;)V
+HSPLandroidx/compose/ui/draw/PainterNode;->getUseIntrinsicSize()Z
+HSPLandroidx/compose/ui/draw/PainterNode;->hasSpecifiedAndFiniteHeight-uvyYCjk(J)Z
+HSPLandroidx/compose/ui/draw/PainterNode;->hasSpecifiedAndFiniteWidth-uvyYCjk(J)Z
+HSPLandroidx/compose/ui/draw/PainterNode;->measure-3p2s80s(Landroidx/compose/ui/layout/MeasureScope;Landroidx/compose/ui/layout/Measurable;J)Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/compose/ui/draw/PainterNode;->modifyConstraints-ZezNO4M(J)J
+HSPLandroidx/compose/ui/focus/FocusChangedElement;-><init>(Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/focus/FocusChangedElement;->create()Landroidx/compose/ui/Modifier$Node;
+HSPLandroidx/compose/ui/focus/FocusChangedElement;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/focus/FocusChangedElement;->update(Landroidx/compose/ui/Modifier$Node;)V
+HSPLandroidx/compose/ui/focus/FocusChangedNode;-><init>(Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/focus/FocusChangedNode;->onFocusEvent(Landroidx/compose/ui/focus/FocusStateImpl;)V
+HSPLandroidx/compose/ui/focus/FocusDirection;-><init>(I)V
+HSPLandroidx/compose/ui/focus/FocusInvalidationManager;-><init>(Landroidx/compose/ui/platform/AndroidComposeView$focusOwner$1;)V
+HSPLandroidx/compose/ui/focus/FocusInvalidationManager;->scheduleInvalidation(Ljava/util/LinkedHashSet;Ljava/lang/Object;)V
+HSPLandroidx/compose/ui/focus/FocusModifierKt;->beamBeats-I7lrPNg(Landroidx/compose/ui/geometry/Rect;Landroidx/compose/ui/geometry/Rect;Landroidx/compose/ui/geometry/Rect;I)Z
+HSPLandroidx/compose/ui/focus/FocusModifierKt;->beamBeats_I7lrPNg$inSourceBeam(ILandroidx/compose/ui/geometry/Rect;Landroidx/compose/ui/geometry/Rect;)Z
+HSPLandroidx/compose/ui/focus/FocusModifierKt;->clearFocus(Landroidx/compose/ui/focus/FocusTargetNode;ZZ)Z
+HSPLandroidx/compose/ui/focus/FocusModifierKt;->collectAccessibleChildren(Landroidx/compose/ui/node/DelegatableNode;Landroidx/compose/runtime/collection/MutableVector;)V
+HSPLandroidx/compose/ui/focus/FocusModifierKt;->findActiveFocusNode(Landroidx/compose/ui/focus/FocusTargetNode;)Landroidx/compose/ui/focus/FocusTargetNode;
+HSPLandroidx/compose/ui/focus/FocusModifierKt;->findBestCandidate-4WY_MpI(Landroidx/compose/runtime/collection/MutableVector;Landroidx/compose/ui/geometry/Rect;I)Landroidx/compose/ui/focus/FocusTargetNode;
+HSPLandroidx/compose/ui/focus/FocusModifierKt;->findChildCorrespondingToFocusEnter--OM-vw8(Landroidx/compose/ui/focus/FocusTargetNode;ILkotlin/jvm/functions/Function1;)Z
+HSPLandroidx/compose/ui/focus/FocusModifierKt;->focusRect(Landroidx/compose/ui/focus/FocusTargetNode;)Landroidx/compose/ui/geometry/Rect;
+HSPLandroidx/compose/ui/focus/FocusModifierKt;->generateAndSearchChildren-4C6V_qg$1(Landroidx/compose/ui/focus/FocusTargetNode;Landroidx/compose/ui/focus/FocusTargetNode;ILkotlin/jvm/functions/Function1;)Z
+HSPLandroidx/compose/ui/focus/FocusModifierKt;->getActiveChild(Landroidx/compose/ui/focus/FocusTargetNode;)Landroidx/compose/ui/focus/FocusTargetNode;
+HSPLandroidx/compose/ui/focus/FocusModifierKt;->getFocusState(Landroidx/compose/ui/focus/FocusEventModifierNode;)Landroidx/compose/ui/focus/FocusStateImpl;
+HSPLandroidx/compose/ui/focus/FocusModifierKt;->grantFocus(Landroidx/compose/ui/focus/FocusTargetNode;)V
+HSPLandroidx/compose/ui/focus/FocusModifierKt;->invalidateFocusEvent(Landroidx/compose/ui/focus/FocusEventModifierNode;)V
+HSPLandroidx/compose/ui/focus/FocusModifierKt;->isBetterCandidate_I7lrPNg$isCandidate(ILandroidx/compose/ui/geometry/Rect;Landroidx/compose/ui/geometry/Rect;)Z
+HSPLandroidx/compose/ui/focus/FocusModifierKt;->isBetterCandidate_I7lrPNg$weightedDistance(ILandroidx/compose/ui/geometry/Rect;Landroidx/compose/ui/geometry/Rect;)J
+HSPLandroidx/compose/ui/focus/FocusModifierKt;->isEligibleForFocusSearch(Landroidx/compose/ui/focus/FocusTargetNode;)Z
+HSPLandroidx/compose/ui/focus/FocusModifierKt;->onFocusChanged(Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function1;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/focus/FocusModifierKt;->performCustomClearFocus-Mxy_nc0(Landroidx/compose/ui/focus/FocusTargetNode;I)I
+HSPLandroidx/compose/ui/focus/FocusModifierKt;->performCustomEnter-Mxy_nc0(Landroidx/compose/ui/focus/FocusTargetNode;I)I
+HSPLandroidx/compose/ui/focus/FocusModifierKt;->performCustomRequestFocus-Mxy_nc0(Landroidx/compose/ui/focus/FocusTargetNode;I)I
+HSPLandroidx/compose/ui/focus/FocusModifierKt;->performRequestFocus(Landroidx/compose/ui/focus/FocusTargetNode;)Z
+HSPLandroidx/compose/ui/focus/FocusModifierKt;->refreshFocusEventNodes(Landroidx/compose/ui/focus/FocusTargetNode;)V
+HSPLandroidx/compose/ui/focus/FocusModifierKt;->requestFocusForChild(Landroidx/compose/ui/focus/FocusTargetNode;Landroidx/compose/ui/focus/FocusTargetNode;)Z
+HSPLandroidx/compose/ui/focus/FocusModifierKt;->requireActiveChild(Landroidx/compose/ui/focus/FocusTargetNode;)Landroidx/compose/ui/focus/FocusTargetNode;
+HSPLandroidx/compose/ui/focus/FocusModifierKt;->requireTransactionManager(Landroidx/compose/ui/focus/FocusTargetNode;)Lcom/google/gson/internal/ConstructorConstructor;
+HSPLandroidx/compose/ui/focus/FocusModifierKt;->searchBeyondBounds--OM-vw8(Landroidx/compose/ui/focus/FocusTargetNode;ILandroidx/compose/ui/focus/FocusOwnerImpl$moveFocus$foundNextItem$1;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/focus/FocusModifierKt;->searchChildren-4C6V_qg$1(Landroidx/compose/ui/focus/FocusTargetNode;Landroidx/compose/ui/focus/FocusTargetNode;ILkotlin/jvm/functions/Function1;)Z
+HSPLandroidx/compose/ui/focus/FocusModifierKt;->twoDimensionalFocusSearch--OM-vw8(Landroidx/compose/ui/focus/FocusTargetNode;ILandroidx/compose/ui/focus/FocusOwnerImpl$moveFocus$foundNextItem$1;)Ljava/lang/Boolean;
+HSPLandroidx/compose/ui/focus/FocusOwnerImpl$modifier$1;-><init>(Landroidx/compose/ui/focus/FocusOwnerImpl;)V
+HSPLandroidx/compose/ui/focus/FocusOwnerImpl$modifier$1;->create()Landroidx/compose/ui/Modifier$Node;
+HSPLandroidx/compose/ui/focus/FocusOwnerImpl$moveFocus$foundNextItem$1;-><init>(Landroidx/compose/ui/focus/FocusTargetNode;Ljava/lang/Object;ILjava/lang/Object;I)V
+HSPLandroidx/compose/ui/focus/FocusOwnerImpl$moveFocus$foundNextItem$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/focus/FocusOwnerImpl;-><init>(Landroidx/compose/ui/platform/AndroidComposeView$focusOwner$1;)V
+HSPLandroidx/compose/ui/focus/FocusOwnerImpl;->moveFocus-3ESFkO8(I)Z
+HSPLandroidx/compose/ui/focus/FocusProperties$exit$1;-><clinit>()V
+HSPLandroidx/compose/ui/focus/FocusProperties$exit$1;-><init>(I)V
+HSPLandroidx/compose/ui/focus/FocusProperties$exit$1;->invoke(Landroidx/compose/ui/node/AlignmentLinesOwner;)V
+HSPLandroidx/compose/ui/focus/FocusProperties$exit$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/focus/FocusProperties$exit$1;->invoke-3ESFkO8()Landroidx/compose/ui/focus/FocusRequester;
+HSPLandroidx/compose/ui/focus/FocusPropertiesImpl;-><init>()V
+HSPLandroidx/compose/ui/focus/FocusPropertiesImpl;->setCanFocus(Z)V
+HSPLandroidx/compose/ui/focus/FocusRequester;-><clinit>()V
+HSPLandroidx/compose/ui/focus/FocusRequester;-><init>()V
+HSPLandroidx/compose/ui/focus/FocusStateImpl;-><clinit>()V
+HSPLandroidx/compose/ui/focus/FocusStateImpl;-><init>(ILjava/lang/String;)V
+HSPLandroidx/compose/ui/focus/FocusStateImpl;->isFocused()Z
+HSPLandroidx/compose/ui/focus/FocusTargetNode$FocusTargetElement;-><clinit>()V
+HSPLandroidx/compose/ui/focus/FocusTargetNode$FocusTargetElement;-><init>()V
+HSPLandroidx/compose/ui/focus/FocusTargetNode$FocusTargetElement;->create()Landroidx/compose/ui/Modifier$Node;
+HSPLandroidx/compose/ui/focus/FocusTargetNode$FocusTargetElement;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/focus/FocusTargetNode;-><init>()V
+HSPLandroidx/compose/ui/focus/FocusTargetNode;->fetchFocusProperties$ui_release()Landroidx/compose/ui/focus/FocusPropertiesImpl;
+HSPLandroidx/compose/ui/focus/FocusTargetNode;->getFocusState()Landroidx/compose/ui/focus/FocusStateImpl;
+HSPLandroidx/compose/ui/focus/FocusTargetNode;->invalidateFocus$ui_release()V
+HSPLandroidx/compose/ui/focus/FocusTargetNode;->onReset()V
+HSPLandroidx/compose/ui/focus/FocusTargetNode;->scheduleInvalidationForFocusEvents$ui_release()V
+HSPLandroidx/compose/ui/focus/FocusTargetNode;->setFocusState(Landroidx/compose/ui/focus/FocusStateImpl;)V
+HSPLandroidx/compose/ui/geometry/CornerRadius;-><clinit>()V
+HSPLandroidx/compose/ui/geometry/CornerRadius;->getX-impl(J)F
+HSPLandroidx/compose/ui/geometry/CornerRadius;->getY-impl(J)F
+HSPLandroidx/compose/ui/geometry/MutableRect;-><init>()V
+HSPLandroidx/compose/ui/geometry/MutableRect;->isEmpty()Z
+HSPLandroidx/compose/ui/geometry/Offset;-><clinit>()V
+HSPLandroidx/compose/ui/geometry/Offset;->getX-impl(J)F
+HSPLandroidx/compose/ui/geometry/Offset;->getY-impl(J)F
+HSPLandroidx/compose/ui/geometry/Rect;-><clinit>()V
+HSPLandroidx/compose/ui/geometry/Rect;-><init>(FFFF)V
+HSPLandroidx/compose/ui/geometry/Rect;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/geometry/Rect;->intersect(Landroidx/compose/ui/geometry/Rect;)Landroidx/compose/ui/geometry/Rect;
+HSPLandroidx/compose/ui/geometry/Rect;->translate(FF)Landroidx/compose/ui/geometry/Rect;
+HSPLandroidx/compose/ui/geometry/Rect;->translate-k-4lQ0M(J)Landroidx/compose/ui/geometry/Rect;
+HSPLandroidx/compose/ui/geometry/RoundRect;-><clinit>()V
+HSPLandroidx/compose/ui/geometry/RoundRect;-><init>(FFFFJJJJ)V
+HSPLandroidx/compose/ui/geometry/Size;-><clinit>()V
+HSPLandroidx/compose/ui/geometry/Size;-><init>(J)V
+HSPLandroidx/compose/ui/geometry/Size;->equals-impl0(JJ)Z
+HSPLandroidx/compose/ui/geometry/Size;->getHeight-impl(J)F
+HSPLandroidx/compose/ui/geometry/Size;->getMinDimension-impl(J)F
+HSPLandroidx/compose/ui/geometry/Size;->getWidth-impl(J)F
+HSPLandroidx/compose/ui/geometry/Size;->isEmpty-impl(J)Z
+HSPLandroidx/compose/ui/graphics/AndroidCanvas;-><init>()V
+HSPLandroidx/compose/ui/graphics/AndroidCanvas;->drawImageRect-HPBpro0(Landroidx/compose/ui/graphics/ImageBitmap;JJJJLandroidx/compose/ui/graphics/AndroidPaint;)V
+HSPLandroidx/compose/ui/graphics/AndroidCanvas;->drawRect(FFFFLandroidx/compose/ui/graphics/AndroidPaint;)V
+HSPLandroidx/compose/ui/graphics/AndroidCanvas;->drawRoundRect(FFFFFFLandroidx/compose/ui/graphics/AndroidPaint;)V
+HSPLandroidx/compose/ui/graphics/AndroidCanvas;->restore()V
+HSPLandroidx/compose/ui/graphics/AndroidCanvas;->save()V
+HSPLandroidx/compose/ui/graphics/AndroidCanvas;->scale(FF)V
+HSPLandroidx/compose/ui/graphics/AndroidCanvas;->translate(FF)V
+HSPLandroidx/compose/ui/graphics/AndroidCanvas_androidKt;-><clinit>()V
+HSPLandroidx/compose/ui/graphics/AndroidImageBitmap;-><init>(Landroid/graphics/Bitmap;)V
+HSPLandroidx/compose/ui/graphics/AndroidPaint;-><init>(Landroid/graphics/Paint;)V
+HSPLandroidx/compose/ui/graphics/AndroidPaint;->setAlpha(F)V
+HSPLandroidx/compose/ui/graphics/AndroidPaint;->setBlendMode-s9anfk8(I)V
+HSPLandroidx/compose/ui/graphics/AndroidPaint;->setColor-8_81llA(J)V
+HSPLandroidx/compose/ui/graphics/AndroidPaint;->setStyle-k9PVt8s(I)V
+HSPLandroidx/compose/ui/graphics/AndroidPaint_androidKt$WhenMappings;-><clinit>()V
+HSPLandroidx/compose/ui/graphics/BlockGraphicsLayerElement;-><init>(Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/graphics/BlockGraphicsLayerElement;->create()Landroidx/compose/ui/Modifier$Node;
+HSPLandroidx/compose/ui/graphics/BlockGraphicsLayerElement;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/graphics/BlockGraphicsLayerModifier;-><init>(Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/graphics/BlockGraphicsLayerModifier;->measure-3p2s80s(Landroidx/compose/ui/layout/MeasureScope;Landroidx/compose/ui/layout/Measurable;J)Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/compose/ui/graphics/Brush;-><init>()V
+HSPLandroidx/compose/ui/graphics/BrushKt;-><clinit>()V
+HSPLandroidx/compose/ui/graphics/BrushKt;->Color$default(III)J
+HSPLandroidx/compose/ui/graphics/BrushKt;->Color(FFFFLandroidx/compose/ui/graphics/colorspace/ColorSpace;)J
+HSPLandroidx/compose/ui/graphics/BrushKt;->Color(I)J
+HSPLandroidx/compose/ui/graphics/BrushKt;->Color(J)J
+HSPLandroidx/compose/ui/graphics/BrushKt;->Paint()Landroidx/compose/ui/graphics/AndroidPaint;
+HSPLandroidx/compose/ui/graphics/BrushKt;->drawOutline-wDX37Ww$default(Landroidx/compose/ui/graphics/drawscope/DrawScope;Landroidx/compose/ui/graphics/BrushKt;J)V
+HSPLandroidx/compose/ui/graphics/BrushKt;->graphicsLayer(Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function1;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/graphics/BrushKt;->graphicsLayer-Ap8cVGQ$default(Landroidx/compose/ui/Modifier;FFLandroidx/compose/ui/graphics/Shape;ZI)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/graphics/BrushKt;->setFrom-tU-YjHk(Landroid/graphics/Matrix;[F)V
+HSPLandroidx/compose/ui/graphics/BrushKt;->toArgb-8_81llA(J)I
+HSPLandroidx/compose/ui/graphics/CanvasZHelper$$ExternalSyntheticApiModelOutline0;->m$1(Landroid/graphics/RenderNode;)I
+HSPLandroidx/compose/ui/graphics/CanvasZHelper$$ExternalSyntheticApiModelOutline0;->m$1(Landroid/graphics/RenderNode;F)V
+HSPLandroidx/compose/ui/graphics/CanvasZHelper$$ExternalSyntheticApiModelOutline0;->m$1(Landroid/graphics/RenderNode;I)V
+HSPLandroidx/compose/ui/graphics/CanvasZHelper$$ExternalSyntheticApiModelOutline0;->m$2(Landroid/graphics/RenderNode;F)V
+HSPLandroidx/compose/ui/graphics/CanvasZHelper$$ExternalSyntheticApiModelOutline0;->m$2(Landroid/graphics/RenderNode;I)V
+HSPLandroidx/compose/ui/graphics/CanvasZHelper$$ExternalSyntheticApiModelOutline0;->m$3(Landroid/graphics/RenderNode;F)V
+HSPLandroidx/compose/ui/graphics/CanvasZHelper$$ExternalSyntheticApiModelOutline0;->m$4(Landroid/graphics/RenderNode;F)V
+HSPLandroidx/compose/ui/graphics/CanvasZHelper$$ExternalSyntheticApiModelOutline0;->m$5(Landroid/graphics/RenderNode;F)V
+HSPLandroidx/compose/ui/graphics/CanvasZHelper$$ExternalSyntheticApiModelOutline0;->m$6(Landroid/graphics/RenderNode;F)V
+HSPLandroidx/compose/ui/graphics/CanvasZHelper$$ExternalSyntheticApiModelOutline0;->m$7(Landroid/graphics/RenderNode;F)V
+HSPLandroidx/compose/ui/graphics/CanvasZHelper$$ExternalSyntheticApiModelOutline0;->m$8(Landroid/graphics/RenderNode;F)V
+HSPLandroidx/compose/ui/graphics/CanvasZHelper$$ExternalSyntheticApiModelOutline0;->m(Landroid/graphics/Canvas;Landroid/graphics/RenderNode;)V
+HSPLandroidx/compose/ui/graphics/CanvasZHelper$$ExternalSyntheticApiModelOutline0;->m(Landroid/graphics/RenderNode;)I
+HSPLandroidx/compose/ui/graphics/CanvasZHelper$$ExternalSyntheticApiModelOutline0;->m(Landroid/graphics/RenderNode;)V
+HSPLandroidx/compose/ui/graphics/CanvasZHelper$$ExternalSyntheticApiModelOutline0;->m(Landroid/graphics/RenderNode;)Z
+HSPLandroidx/compose/ui/graphics/CanvasZHelper$$ExternalSyntheticApiModelOutline0;->m(Landroid/graphics/RenderNode;F)V
+HSPLandroidx/compose/ui/graphics/CanvasZHelper$$ExternalSyntheticApiModelOutline0;->m(Landroid/graphics/RenderNode;I)V
+HSPLandroidx/compose/ui/graphics/CanvasZHelper$$ExternalSyntheticApiModelOutline0;->m(Landroid/graphics/RenderNode;Z)V
+HSPLandroidx/compose/ui/graphics/CanvasZHelper$$ExternalSyntheticApiModelOutline0;->m(Landroid/view/View;)V
+HSPLandroidx/compose/ui/graphics/Color;-><clinit>()V
+HSPLandroidx/compose/ui/graphics/Color;-><init>(J)V
+HSPLandroidx/compose/ui/graphics/Color;->convert-vNxB06k(JLandroidx/compose/ui/graphics/colorspace/ColorSpace;)J
+HSPLandroidx/compose/ui/graphics/Color;->copy-wmQWz5c$default(JF)J
+HSPLandroidx/compose/ui/graphics/Color;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/graphics/Color;->equals-impl0(JJ)Z
+HSPLandroidx/compose/ui/graphics/Color;->getAlpha-impl(J)F
+HSPLandroidx/compose/ui/graphics/Color;->getBlue-impl(J)F
+HSPLandroidx/compose/ui/graphics/Color;->getColorSpace-impl(J)Landroidx/compose/ui/graphics/colorspace/ColorSpace;
+HSPLandroidx/compose/ui/graphics/Color;->getGreen-impl(J)F
+HSPLandroidx/compose/ui/graphics/Color;->getRed-impl(J)F
+HSPLandroidx/compose/ui/graphics/ColorSpaceVerificationHelper$$ExternalSyntheticLambda1;-><init>(ILjava/lang/Object;)V
+HSPLandroidx/compose/ui/graphics/Float16;-><clinit>()V
+HSPLandroidx/compose/ui/graphics/Float16;->constructor-impl(F)S
+HSPLandroidx/compose/ui/graphics/Float16;->toFloat-impl(S)F
+HSPLandroidx/compose/ui/graphics/GraphicsLayerElement;-><init>(FFFFFFFFFFJLandroidx/compose/ui/graphics/Shape;ZJJI)V
+HSPLandroidx/compose/ui/graphics/GraphicsLayerElement;->create()Landroidx/compose/ui/Modifier$Node;
+HSPLandroidx/compose/ui/graphics/GraphicsLayerElement;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/graphics/GraphicsLayerElement;->update(Landroidx/compose/ui/Modifier$Node;)V
+HSPLandroidx/compose/ui/graphics/GraphicsLayerScopeKt;-><clinit>()V
+HSPLandroidx/compose/ui/graphics/Matrix;->constructor-impl$default()[F
+HSPLandroidx/compose/ui/graphics/Matrix;->map-MK-Hz9U([FJ)J
+HSPLandroidx/compose/ui/graphics/Matrix;->map-impl([FLandroidx/compose/ui/geometry/MutableRect;)V
+HSPLandroidx/compose/ui/graphics/Outline$Rectangle;-><init>(Landroidx/compose/ui/geometry/Rect;)V
+HSPLandroidx/compose/ui/graphics/Outline$Rounded;-><init>(Landroidx/compose/ui/geometry/RoundRect;)V
+HSPLandroidx/compose/ui/graphics/RectangleShapeKt$RectangleShape$1;-><init>(I)V
+HSPLandroidx/compose/ui/graphics/RectangleShapeKt$RectangleShape$1;->createOutline-Pq9zytI(JLandroidx/compose/ui/unit/LayoutDirection;Landroidx/compose/ui/unit/Density;)Landroidx/compose/ui/graphics/BrushKt;
+HSPLandroidx/compose/ui/graphics/ReusableGraphicsLayerScope;-><init>()V
+HSPLandroidx/compose/ui/graphics/Shadow;-><clinit>()V
+HSPLandroidx/compose/ui/graphics/Shadow;-><init>(JJF)V
+HSPLandroidx/compose/ui/graphics/Shadow;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/graphics/SimpleGraphicsLayerModifier$layerBlock$1;-><init>(Landroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;)V
+HSPLandroidx/compose/ui/graphics/SimpleGraphicsLayerModifier$layerBlock$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;-><init>(FFFFFFFFFFJLandroidx/compose/ui/graphics/Shape;ZJJI)V
+HSPLandroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;->getShouldAutoInvalidate()Z
+HSPLandroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;->measure-3p2s80s(Landroidx/compose/ui/layout/MeasureScope;Landroidx/compose/ui/layout/Measurable;J)Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/compose/ui/graphics/SolidColor;-><init>(J)V
+HSPLandroidx/compose/ui/graphics/SolidColor;->applyTo-Pq9zytI(FJLandroidx/compose/ui/graphics/AndroidPaint;)V
+HSPLandroidx/compose/ui/graphics/SolidColor;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/graphics/TransformOrigin;-><clinit>()V
+HSPLandroidx/compose/ui/graphics/colorspace/Adaptation;-><clinit>()V
+HSPLandroidx/compose/ui/graphics/colorspace/Adaptation;-><init>([F)V
+HSPLandroidx/compose/ui/graphics/colorspace/ColorModel;-><clinit>()V
+HSPLandroidx/compose/ui/graphics/colorspace/ColorModel;->equals-impl0(JJ)Z
+HSPLandroidx/compose/ui/graphics/colorspace/ColorSpace;-><init>(Ljava/lang/String;JI)V
+HSPLandroidx/compose/ui/graphics/colorspace/ColorSpace;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/graphics/colorspace/ColorSpace;->isSrgb()Z
+HSPLandroidx/compose/ui/graphics/colorspace/ColorSpaces;-><clinit>()V
+HSPLandroidx/compose/ui/graphics/colorspace/Connector$Companion$identity$1;-><init>(Landroidx/compose/ui/graphics/colorspace/ColorSpace;)V
+HSPLandroidx/compose/ui/graphics/colorspace/Connector;-><clinit>()V
+HSPLandroidx/compose/ui/graphics/colorspace/Connector;-><init>(Landroidx/compose/ui/graphics/colorspace/ColorSpace;Landroidx/compose/ui/graphics/colorspace/ColorSpace;I)V
+HSPLandroidx/compose/ui/graphics/colorspace/Connector;-><init>(Landroidx/compose/ui/graphics/colorspace/ColorSpace;Landroidx/compose/ui/graphics/colorspace/ColorSpace;Landroidx/compose/ui/graphics/colorspace/ColorSpace;[F)V
+HSPLandroidx/compose/ui/graphics/colorspace/Connector;->transformToColor-wmQWz5c$ui_graphics_release(FFFF)J
+HSPLandroidx/compose/ui/graphics/colorspace/Lab;-><init>()V
+HSPLandroidx/compose/ui/graphics/colorspace/Oklab;-><clinit>()V
+HSPLandroidx/compose/ui/graphics/colorspace/Oklab;-><init>()V
+HSPLandroidx/compose/ui/graphics/colorspace/Oklab;->getMaxValue(I)F
+HSPLandroidx/compose/ui/graphics/colorspace/Oklab;->getMinValue(I)F
+HSPLandroidx/compose/ui/graphics/colorspace/Oklab;->toXy$ui_graphics_release(FFF)J
+HSPLandroidx/compose/ui/graphics/colorspace/Oklab;->toZ$ui_graphics_release(FFF)F
+HSPLandroidx/compose/ui/graphics/colorspace/Oklab;->xyzaToColor-JlNiLsg$ui_graphics_release(FFFFLandroidx/compose/ui/graphics/colorspace/ColorSpace;)J
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb$$ExternalSyntheticLambda0;-><init>(Landroidx/compose/ui/graphics/colorspace/Rgb;I)V
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb$$ExternalSyntheticLambda0;->invoke(D)D
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb$$ExternalSyntheticLambda1;-><init>(Landroidx/compose/ui/graphics/colorspace/TransferParameters;I)V
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb$$ExternalSyntheticLambda1;->invoke(D)D
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb$$ExternalSyntheticLambda2;-><init>(DI)V
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb$eotf$1;-><init>(Landroidx/compose/ui/graphics/colorspace/Rgb;I)V
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb;-><clinit>()V
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb;-><init>(Ljava/lang/String;[FLandroidx/compose/ui/graphics/colorspace/WhitePoint;DFFI)V
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb;-><init>(Ljava/lang/String;[FLandroidx/compose/ui/graphics/colorspace/WhitePoint;Landroidx/compose/ui/graphics/colorspace/TransferParameters;I)V
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb;-><init>(Ljava/lang/String;[FLandroidx/compose/ui/graphics/colorspace/WhitePoint;[FLandroidx/compose/ui/graphics/colorspace/DoubleFunction;Landroidx/compose/ui/graphics/colorspace/DoubleFunction;FFLandroidx/compose/ui/graphics/colorspace/TransferParameters;I)V
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb;->getMaxValue(I)F
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb;->getMinValue(I)F
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb;->isSrgb()Z
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb;->toXy$ui_graphics_release(FFF)J
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb;->toZ$ui_graphics_release(FFF)F
+HSPLandroidx/compose/ui/graphics/colorspace/Rgb;->xyzaToColor-JlNiLsg$ui_graphics_release(FFFFLandroidx/compose/ui/graphics/colorspace/ColorSpace;)J
+HSPLandroidx/compose/ui/graphics/colorspace/TransferParameters;-><init>(DDDDD)V
+HSPLandroidx/compose/ui/graphics/colorspace/TransferParameters;-><init>(DDDDDDD)V
+HSPLandroidx/compose/ui/graphics/colorspace/WhitePoint;-><init>(FF)V
+HSPLandroidx/compose/ui/graphics/colorspace/WhitePoint;->toXyz$ui_graphics_release()[F
+HSPLandroidx/compose/ui/graphics/colorspace/Xyz;-><init>()V
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope$DrawParams;-><init>()V
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope$drawContext$1;-><init>(Landroidx/compose/ui/graphics/drawscope/CanvasDrawScope;)V
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope$drawContext$1;->getCanvas()Landroidx/compose/ui/graphics/Canvas;
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope$drawContext$1;->getSize-NH-jbRc()J
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope$drawContext$1;->setSize-uvyYCjk(J)V
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope;-><init>()V
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope;->configurePaint-2qPWKa0$default(Landroidx/compose/ui/graphics/drawscope/CanvasDrawScope;JLkotlin/ResultKt;FLandroidx/compose/ui/graphics/BlendModeColorFilter;I)Landroidx/compose/ui/graphics/AndroidPaint;
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope;->configurePaint-swdJneE$default(Landroidx/compose/ui/graphics/drawscope/CanvasDrawScope;Landroidx/compose/ui/graphics/Brush;Lkotlin/ResultKt;FLandroidx/compose/ui/graphics/BlendModeColorFilter;I)Landroidx/compose/ui/graphics/AndroidPaint;
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope;->configurePaint-swdJneE(Landroidx/compose/ui/graphics/Brush;Lkotlin/ResultKt;FLandroidx/compose/ui/graphics/BlendModeColorFilter;II)Landroidx/compose/ui/graphics/AndroidPaint;
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope;->drawImage-AZ2fEMs(Landroidx/compose/ui/graphics/ImageBitmap;JJJJFLkotlin/ResultKt;Landroidx/compose/ui/graphics/BlendModeColorFilter;II)V
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope;->drawRect-AsUm42w(Landroidx/compose/ui/graphics/Brush;JJFLkotlin/ResultKt;Landroidx/compose/ui/graphics/BlendModeColorFilter;I)V
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope;->drawRect-n-J9OG0(JJJFLkotlin/ResultKt;Landroidx/compose/ui/graphics/BlendModeColorFilter;I)V
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope;->drawRoundRect-u-Aw5IA(JJJJLkotlin/ResultKt;FLandroidx/compose/ui/graphics/BlendModeColorFilter;I)V
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope;->getDensity()F
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope;->getDrawContext()Landroidx/compose/ui/graphics/drawscope/CanvasDrawScope$drawContext$1;
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope;->getFontScale()F
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScope;->selectPaint(Lkotlin/ResultKt;)Landroidx/compose/ui/graphics/AndroidPaint;
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScopeKt$asDrawTransform$1;-><init>(Landroidx/compose/ui/graphics/drawscope/CanvasDrawScope$drawContext$1;)V
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScopeKt$asDrawTransform$1;->inset(FFFF)V
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScopeKt$asDrawTransform$1;->scale-0AR0LA0(FFJ)V
+HSPLandroidx/compose/ui/graphics/drawscope/CanvasDrawScopeKt$asDrawTransform$1;->translate(FF)V
+HSPLandroidx/compose/ui/graphics/drawscope/DrawScope;->drawImage-AZ2fEMs$default(Landroidx/compose/ui/graphics/drawscope/DrawScope;Landroidx/compose/ui/graphics/ImageBitmap;JJJFLandroidx/compose/ui/graphics/BlendModeColorFilter;II)V
+HSPLandroidx/compose/ui/graphics/drawscope/DrawScope;->drawRect-AsUm42w$default(Landroidx/compose/ui/graphics/drawscope/DrawScope;Landroidx/compose/ui/graphics/Brush;JJFLkotlin/ResultKt;I)V
+HSPLandroidx/compose/ui/graphics/drawscope/DrawScope;->drawRect-n-J9OG0$default(Landroidx/compose/ui/graphics/drawscope/DrawScope;JJI)V
+HSPLandroidx/compose/ui/graphics/drawscope/DrawScope;->getCenter-F1C5BW0()J
+HSPLandroidx/compose/ui/graphics/drawscope/DrawScope;->getSize-NH-jbRc()J
+HSPLandroidx/compose/ui/graphics/drawscope/DrawScope;->offsetSize-PENXr5M(JJ)J
+HSPLandroidx/compose/ui/graphics/drawscope/Fill;-><clinit>()V
+HSPLandroidx/compose/ui/graphics/drawscope/Stroke;-><init>(FFIII)V
+HSPLandroidx/compose/ui/graphics/drawscope/Stroke;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/graphics/painter/BitmapPainter;-><init>(Landroidx/compose/ui/graphics/ImageBitmap;)V
+HSPLandroidx/compose/ui/graphics/painter/BitmapPainter;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/graphics/painter/BitmapPainter;->getIntrinsicSize-NH-jbRc()J
+HSPLandroidx/compose/ui/graphics/painter/BitmapPainter;->onDraw(Landroidx/compose/ui/graphics/drawscope/DrawScope;)V
+HSPLandroidx/compose/ui/graphics/painter/Painter;-><init>()V
+HSPLandroidx/compose/ui/input/InputMode;-><init>(I)V
+HSPLandroidx/compose/ui/input/InputMode;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/input/InputModeManagerImpl;-><init>(I)V
+HSPLandroidx/compose/ui/input/key/Key;-><clinit>()V
+HSPLandroidx/compose/ui/input/key/Key;->equals-impl0(JJ)Z
+HSPLandroidx/compose/ui/input/key/KeyEvent;-><init>(Landroid/view/KeyEvent;)V
+HSPLandroidx/compose/ui/input/key/KeyInputElement;-><init>(Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/input/key/KeyInputElement;->create()Landroidx/compose/ui/Modifier$Node;
+HSPLandroidx/compose/ui/input/key/KeyInputElement;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/input/key/KeyInputElement;->update(Landroidx/compose/ui/Modifier$Node;)V
+HSPLandroidx/compose/ui/input/key/KeyInputNode;-><init>(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/input/key/Key_androidKt;->Key(I)J
+HSPLandroidx/compose/ui/input/key/Key_androidKt;->onKeyEvent(Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function1;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/input/nestedscroll/NestedScrollDispatcher;-><init>()V
+HSPLandroidx/compose/ui/input/nestedscroll/NestedScrollNode;-><init>(Landroidx/compose/foundation/gestures/ScrollableNestedScrollConnection;Landroidx/compose/ui/input/nestedscroll/NestedScrollDispatcher;)V
+HSPLandroidx/compose/ui/input/nestedscroll/NestedScrollNode;->getProvidedValues()Landroidx/tv/material3/TabKt;
+HSPLandroidx/compose/ui/input/nestedscroll/NestedScrollNode;->onAttach()V
+HSPLandroidx/compose/ui/input/nestedscroll/NestedScrollNodeKt;-><clinit>()V
+HSPLandroidx/compose/ui/input/pointer/AndroidPointerIconType;-><init>(I)V
+HSPLandroidx/compose/ui/input/pointer/MotionEventAdapter;-><init>()V
+HSPLandroidx/compose/ui/input/pointer/NodeParent;-><init>()V
+HSPLandroidx/compose/ui/input/pointer/PointerEvent;-><init>(Ljava/util/List;Lcom/google/gson/internal/ConstructorConstructor;)V
+HSPLandroidx/compose/ui/input/pointer/PointerIcon;-><clinit>()V
+HSPLandroidx/compose/ui/input/pointer/PointerKeyboardModifiers;-><init>(I)V
+HSPLandroidx/compose/ui/input/pointer/PointerKeyboardModifiers;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/input/pointer/SuspendPointerInputElement;-><init>(Ljava/lang/Object;Lokhttp3/MediaType;Lkotlin/jvm/functions/Function2;I)V
+HSPLandroidx/compose/ui/input/pointer/SuspendPointerInputElement;->create()Landroidx/compose/ui/Modifier$Node;
+HSPLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilterKt;-><clinit>()V
+HSPLandroidx/compose/ui/input/pointer/SuspendingPointerInputFilterKt;->pointerInput(Landroidx/compose/ui/Modifier;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/input/pointer/SuspendingPointerInputModifierNodeImpl;-><init>(Lkotlin/jvm/functions/Function2;)V
+HSPLandroidx/compose/ui/input/pointer/util/PointerIdArray;-><init>(FF)V
+HSPLandroidx/compose/ui/input/pointer/util/PointerIdArray;-><init>(FFLandroidx/compose/animation/core/AnimationVector;)V
+HSPLandroidx/compose/ui/input/pointer/util/PointerIdArray;-><init>(I[Landroidx/core/provider/FontsContractCompat$FontInfo;)V
+HSPLandroidx/compose/ui/input/pointer/util/PointerIdArray;-><init>(Landroidx/compose/animation/core/FloatAnimationSpec;)V
+HSPLandroidx/compose/ui/input/pointer/util/PointerIdArray;-><init>(Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;I)V
+HSPLandroidx/compose/ui/input/pointer/util/PointerIdArray;->get(I)Landroidx/compose/animation/core/FloatAnimationSpec;
+HSPLandroidx/compose/ui/input/pointer/util/VelocityTracker1D;-><init>()V
+HSPLandroidx/compose/ui/input/pointer/util/VelocityTracker;-><init>()V
+HSPLandroidx/compose/ui/input/rotary/RotaryInputElement;-><init>()V
+HSPLandroidx/compose/ui/input/rotary/RotaryInputElement;->create()Landroidx/compose/ui/Modifier$Node;
+HSPLandroidx/compose/ui/input/rotary/RotaryInputModifierKt;->onRotaryScrollEvent()Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/input/rotary/RotaryInputNode;-><init>(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/layout/AlignmentLine;-><init>(Lkotlin/jvm/functions/Function2;)V
+HSPLandroidx/compose/ui/layout/AlignmentLineKt$FirstBaseline$1;-><clinit>()V
+HSPLandroidx/compose/ui/layout/AlignmentLineKt$FirstBaseline$1;-><init>()V
+HSPLandroidx/compose/ui/layout/AlignmentLineKt$LastBaseline$1;-><clinit>()V
+HSPLandroidx/compose/ui/layout/AlignmentLineKt$LastBaseline$1;-><init>()V
+HSPLandroidx/compose/ui/layout/AlignmentLineKt;-><clinit>()V
+HSPLandroidx/compose/ui/layout/BeyondBoundsLayoutKt;-><clinit>()V
+HSPLandroidx/compose/ui/layout/ComposableSingletons$SubcomposeLayoutKt;-><clinit>()V
+HSPLandroidx/compose/ui/layout/DefaultIntrinsicMeasurable;-><init>(Landroidx/compose/ui/layout/Measurable;Ljava/lang/Enum;Ljava/lang/Enum;I)V
+HSPLandroidx/compose/ui/layout/DefaultIntrinsicMeasurable;->getParentData()Ljava/lang/Object;
+HSPLandroidx/compose/ui/layout/FixedSizeIntrinsicsPlaceable;-><init>(III)V
+HSPLandroidx/compose/ui/layout/IntrinsicMinMax;-><clinit>()V
+HSPLandroidx/compose/ui/layout/IntrinsicMinMax;-><init>(ILjava/lang/String;)V
+HSPLandroidx/compose/ui/layout/IntrinsicWidthHeight;-><clinit>()V
+HSPLandroidx/compose/ui/layout/IntrinsicWidthHeight;-><init>(ILjava/lang/String;)V
+HSPLandroidx/compose/ui/layout/IntrinsicsMeasureScope;-><init>(Landroidx/compose/ui/layout/IntrinsicMeasureScope;Landroidx/compose/ui/unit/LayoutDirection;)V
+HSPLandroidx/compose/ui/layout/IntrinsicsMeasureScope;->roundToPx-0680j_4(F)I
+HSPLandroidx/compose/ui/layout/LayoutElement;-><init>(Lkotlin/jvm/functions/Function3;)V
+HSPLandroidx/compose/ui/layout/LayoutElement;->create()Landroidx/compose/ui/Modifier$Node;
+HSPLandroidx/compose/ui/layout/LayoutElement;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/layout/LayoutKt$materializerOf$1;-><init>(Landroidx/compose/ui/Modifier;I)V
+HSPLandroidx/compose/ui/layout/LayoutKt$materializerOf$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/layout/LayoutKt$materializerOf$1;->invoke-Deg8D_g(Landroidx/compose/runtime/Composer;Landroidx/compose/runtime/Composer;)V
+HSPLandroidx/compose/ui/layout/LayoutKt;->ScaleFactor(FF)J
+HSPLandroidx/compose/ui/layout/LayoutKt;->SubcomposeLayout(Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;II)V
+HSPLandroidx/compose/ui/layout/LayoutKt;->SubcomposeLayout(Landroidx/compose/ui/layout/SubcomposeLayoutState;Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;II)V
+HSPLandroidx/compose/ui/layout/LayoutKt;->findRootCoordinates(Landroidx/compose/ui/node/NodeCoordinator;)Landroidx/compose/ui/layout/LayoutCoordinates;
+HSPLandroidx/compose/ui/layout/LayoutKt;->layout(Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function3;)Landroidx/compose/ui/Modifier;
+HSPLandroidx/compose/ui/layout/LayoutKt;->modifierMaterializerOf(Landroidx/compose/ui/Modifier;)Landroidx/compose/runtime/internal/ComposableLambdaImpl;
+HSPLandroidx/compose/ui/layout/LayoutKt;->times-UQTWf7w(JJ)J
+HSPLandroidx/compose/ui/layout/LayoutModifierImpl;-><init>(Lkotlin/jvm/functions/Function3;)V
+HSPLandroidx/compose/ui/layout/LayoutModifierImpl;->measure-3p2s80s(Landroidx/compose/ui/layout/MeasureScope;Landroidx/compose/ui/layout/Measurable;J)Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$NodeState;-><init>(Ljava/lang/Object;Landroidx/compose/runtime/internal/ComposableLambdaImpl;)V
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$PostLookaheadMeasureScopeImpl;-><init>(Landroidx/compose/ui/layout/LayoutNodeSubcompositionsState;)V
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$Scope;-><init>(Landroidx/compose/ui/layout/LayoutNodeSubcompositionsState;)V
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$Scope;->getDensity()F
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$Scope;->getLayoutDirection()Landroidx/compose/ui/unit/LayoutDirection;
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$Scope;->isLookingAhead()Z
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$Scope;->subcompose(Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/util/List;
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$createMeasurePolicy$1$measure-3p2s80s$$inlined$createMeasureResult$1;-><init>(Landroidx/compose/ui/layout/MeasureResult;Landroidx/compose/ui/layout/LayoutNodeSubcompositionsState;ILandroidx/compose/ui/layout/MeasureResult;I)V
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$createMeasurePolicy$1$measure-3p2s80s$$inlined$createMeasureResult$1;->getAlignmentLines()Ljava/util/Map;
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$createMeasurePolicy$1$measure-3p2s80s$$inlined$createMeasureResult$1;->getHeight()I
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$createMeasurePolicy$1$measure-3p2s80s$$inlined$createMeasureResult$1;->getWidth()I
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$createMeasurePolicy$1$measure-3p2s80s$$inlined$createMeasureResult$1;->placeChildren()V
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$createMeasurePolicy$1;-><init>(Landroidx/compose/ui/layout/LayoutNodeSubcompositionsState;Lkotlin/jvm/functions/Function2;Ljava/lang/String;)V
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$createMeasurePolicy$1;->measure-3p2s80s(Landroidx/compose/ui/layout/MeasureScope;Ljava/util/List;J)Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$precompose$1;-><init>(Landroidx/compose/ui/layout/LayoutNodeSubcompositionsState;Ljava/lang/Object;)V
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$precompose$1;->dispose()V
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState$precompose$1;->premeasure-0kLqBqw(JI)V
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState;-><init>(Landroidx/compose/ui/node/LayoutNode;Landroidx/compose/ui/layout/SubcomposeSlotReusePolicy;)V
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState;->disposeOrReuseStartingFromIndex(I)V
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState;->makeSureStateIsConsistent()V
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState;->precompose(Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Landroidx/compose/ui/layout/LayoutNodeSubcompositionsState$precompose$1;
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState;->subcompose(Landroidx/compose/ui/node/LayoutNode;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)V
+HSPLandroidx/compose/ui/layout/LayoutNodeSubcompositionsState;->takeNodeFromReusables(Ljava/lang/Object;)Landroidx/compose/ui/node/LayoutNode;
+HSPLandroidx/compose/ui/layout/MeasurePolicy;->maxIntrinsicHeight(Landroidx/compose/ui/node/NodeCoordinator;Ljava/util/List;I)I
+HSPLandroidx/compose/ui/layout/MeasureScope$layout$1;-><init>(IILjava/util/Map;Landroidx/compose/ui/layout/MeasureScope;Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/layout/MeasureScope$layout$1;->getAlignmentLines()Ljava/util/Map;
+HSPLandroidx/compose/ui/layout/MeasureScope$layout$1;->getHeight()I
+HSPLandroidx/compose/ui/layout/MeasureScope$layout$1;->getWidth()I
+HSPLandroidx/compose/ui/layout/MeasureScope$layout$1;->placeChildren()V
+HSPLandroidx/compose/ui/layout/MeasureScope;->layout$default(Landroidx/compose/ui/layout/MeasureScope;IILkotlin/jvm/functions/Function1;)Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/compose/ui/layout/MeasureScope;->layout(IILjava/util/Map;Lkotlin/jvm/functions/Function1;)Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/compose/ui/layout/OnSizeChangedModifier;-><init>(Landroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect$onNewSize$1;)V
+HSPLandroidx/compose/ui/layout/PinnableContainerKt;-><clinit>()V
+HSPLandroidx/compose/ui/layout/Placeable$PlacementScope$Companion;->access$configureForPlacingForAlignment(Landroidx/compose/ui/node/LookaheadCapablePlaceable;)Z
+HSPLandroidx/compose/ui/layout/Placeable$PlacementScope;-><clinit>()V
+HSPLandroidx/compose/ui/layout/Placeable$PlacementScope;->place(Landroidx/compose/ui/layout/Placeable;IIF)V
+HSPLandroidx/compose/ui/layout/Placeable$PlacementScope;->place-70tqf50$default(Landroidx/compose/ui/layout/Placeable$PlacementScope;Landroidx/compose/ui/layout/Placeable;J)V
+HSPLandroidx/compose/ui/layout/Placeable$PlacementScope;->place-70tqf50(Landroidx/compose/ui/layout/Placeable;JF)V
+HSPLandroidx/compose/ui/layout/Placeable$PlacementScope;->placeRelative$default(Landroidx/compose/ui/layout/Placeable$PlacementScope;Landroidx/compose/ui/layout/Placeable;II)V
+HSPLandroidx/compose/ui/layout/Placeable$PlacementScope;->placeRelativeWithLayer$default(Landroidx/compose/ui/layout/Placeable$PlacementScope;Landroidx/compose/ui/layout/Placeable;II)V
+HSPLandroidx/compose/ui/layout/Placeable$PlacementScope;->placeRelativeWithLayer-aW-9-wM$default(Landroidx/compose/ui/layout/Placeable$PlacementScope;Landroidx/compose/ui/layout/Placeable;J)V
+HSPLandroidx/compose/ui/layout/Placeable$PlacementScope;->placeWithLayer$default(Landroidx/compose/ui/layout/Placeable$PlacementScope;Landroidx/compose/ui/layout/Placeable;IILkotlin/jvm/functions/Function1;I)V
+HSPLandroidx/compose/ui/layout/Placeable;-><init>()V
+HSPLandroidx/compose/ui/layout/Placeable;->getMeasuredHeight()I
+HSPLandroidx/compose/ui/layout/Placeable;->getMeasuredWidth()I
+HSPLandroidx/compose/ui/layout/Placeable;->onMeasuredSizeChanged()V
+HSPLandroidx/compose/ui/layout/Placeable;->setMeasuredSize-ozmzZPI(J)V
+HSPLandroidx/compose/ui/layout/Placeable;->setMeasurementConstraints-BRTryo0(J)V
+HSPLandroidx/compose/ui/layout/PlaceableKt;-><clinit>()V
+HSPLandroidx/compose/ui/layout/RootMeasurePolicy$measure$2;-><init>(ILjava/lang/Object;)V
+HSPLandroidx/compose/ui/layout/RootMeasurePolicy$measure$2;->invoke(Landroidx/compose/ui/layout/Placeable$PlacementScope;)V
+HSPLandroidx/compose/ui/layout/RootMeasurePolicy$measure$2;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/layout/RootMeasurePolicy;-><clinit>()V
+HSPLandroidx/compose/ui/layout/RootMeasurePolicy;-><init>()V
+HSPLandroidx/compose/ui/layout/RootMeasurePolicy;->measure-3p2s80s(Landroidx/compose/ui/layout/MeasureScope;Ljava/util/List;J)Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/compose/ui/layout/ScaleFactor;-><clinit>()V
+HSPLandroidx/compose/ui/layout/SubcomposeLayoutKt$SubcomposeLayout$2;-><init>(Ljava/lang/Object;ILjava/lang/Object;II)V
+HSPLandroidx/compose/ui/layout/SubcomposeLayoutKt$SubcomposeLayout$2;->invoke(Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/ui/layout/SubcomposeLayoutKt$SubcomposeLayout$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/layout/SubcomposeLayoutKt$SubcomposeLayout$4;-><init>(ILjava/lang/Object;)V
+HSPLandroidx/compose/ui/layout/SubcomposeLayoutKt$SubcomposeLayout$4;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/ui/layout/SubcomposeLayoutKt$SubcomposeLayout$5$1$invoke$$inlined$onDispose$1;-><init>(ILjava/lang/Object;)V
+HSPLandroidx/compose/ui/layout/SubcomposeLayoutKt$SubcomposeLayout$5$1$invoke$$inlined$onDispose$1;->dispose()V
+HSPLandroidx/compose/ui/layout/SubcomposeLayoutState$setRoot$1;-><init>(Landroidx/compose/ui/layout/SubcomposeLayoutState;I)V
+HSPLandroidx/compose/ui/layout/SubcomposeLayoutState$setRoot$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/layout/SubcomposeLayoutState;-><init>(Landroidx/compose/ui/layout/SubcomposeSlotReusePolicy;)V
+HSPLandroidx/compose/ui/layout/SubcomposeLayoutState;->getState()Landroidx/compose/ui/layout/LayoutNodeSubcompositionsState;
+HSPLandroidx/compose/ui/layout/SubcomposeSlotReusePolicy$SlotIdsSet;-><init>()V
+HSPLandroidx/compose/ui/layout/SubcomposeSlotReusePolicy$SlotIdsSet;->clear()V
+HSPLandroidx/compose/ui/layout/SubcomposeSlotReusePolicy$SlotIdsSet;->contains(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/layout/SubcomposeSlotReusePolicy$SlotIdsSet;->iterator()Ljava/util/Iterator;
+HSPLandroidx/compose/ui/modifier/BackwardsCompatLocalMap;-><init>(Landroidx/compose/ui/modifier/ModifierLocalProvider;)V
+HSPLandroidx/compose/ui/modifier/BackwardsCompatLocalMap;->contains$ui_release(Landroidx/compose/ui/modifier/ModifierLocal;)Z
+HSPLandroidx/compose/ui/modifier/EmptyMap;-><clinit>()V
+HSPLandroidx/compose/ui/modifier/EmptyMap;->contains$ui_release(Landroidx/compose/ui/modifier/ModifierLocal;)Z
+HSPLandroidx/compose/ui/modifier/ModifierLocal;-><init>(Landroidx/compose/material3/ShapesKt$LocalShapes$1;)V
+HSPLandroidx/compose/ui/modifier/ModifierLocalManager;-><init>(Landroidx/compose/ui/node/Owner;)V
+HSPLandroidx/compose/ui/modifier/ModifierLocalModifierNode;->getCurrent(Landroidx/compose/ui/modifier/ProvidableModifierLocal;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/modifier/ModifierLocalModifierNode;->getProvidedValues()Landroidx/tv/material3/TabKt;
+HSPLandroidx/compose/ui/modifier/SingleLocalMap;-><init>(Landroidx/compose/ui/modifier/ModifierLocal;)V
+HSPLandroidx/compose/ui/modifier/SingleLocalMap;->contains$ui_release(Landroidx/compose/ui/modifier/ModifierLocal;)Z
+HSPLandroidx/compose/ui/modifier/SingleLocalMap;->get$ui_release(Landroidx/compose/ui/modifier/ProvidableModifierLocal;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/node/AlignmentLines;-><init>(Landroidx/compose/ui/node/AlignmentLinesOwner;)V
+HSPLandroidx/compose/ui/node/AlignmentLines;->getQueried$ui_release()Z
+HSPLandroidx/compose/ui/node/AlignmentLines;->getRequired$ui_release()Z
+HSPLandroidx/compose/ui/node/AlignmentLines;->onAlignmentsChanged()V
+HSPLandroidx/compose/ui/node/AlignmentLines;->recalculateQueryOwner()V
+HSPLandroidx/compose/ui/node/BackwardsCompatNode;-><init>(Landroidx/compose/ui/Modifier$Element;)V
+HSPLandroidx/compose/ui/node/BackwardsCompatNode;->draw(Landroidx/compose/ui/graphics/drawscope/ContentDrawScope;)V
+HSPLandroidx/compose/ui/node/BackwardsCompatNode;->getProvidedValues()Landroidx/tv/material3/TabKt;
+HSPLandroidx/compose/ui/node/BackwardsCompatNode;->initializeModifier(Z)V
+HSPLandroidx/compose/ui/node/BackwardsCompatNode;->onAttach()V
+HSPLandroidx/compose/ui/node/BackwardsCompatNode;->onGloballyPositioned(Landroidx/compose/ui/node/NodeCoordinator;)V
+HSPLandroidx/compose/ui/node/BackwardsCompatNode;->onMeasureResultChanged()V
+HSPLandroidx/compose/ui/node/BackwardsCompatNode;->onPlaced(Landroidx/compose/ui/node/NodeCoordinator;)V
+HSPLandroidx/compose/ui/node/BackwardsCompatNode;->onRemeasured-ozmzZPI(J)V
+HSPLandroidx/compose/ui/node/BackwardsCompatNode;->unInitializeModifier()V
+HSPLandroidx/compose/ui/node/CanFocusChecker;-><clinit>()V
+HSPLandroidx/compose/ui/node/CanFocusChecker;->setCanFocus(Z)V
+HSPLandroidx/compose/ui/node/ComposeUiNode$Companion;-><clinit>()V
+HSPLandroidx/compose/ui/node/ComposeUiNode;-><clinit>()V
+HSPLandroidx/compose/ui/node/DelegatingNode;-><init>()V
+HSPLandroidx/compose/ui/node/DelegatingNode;->delegate(Landroidx/compose/ui/Modifier$Node;)V
+HSPLandroidx/compose/ui/node/DelegatingNode;->markAsAttached$ui_release()V
+HSPLandroidx/compose/ui/node/DelegatingNode;->markAsDetached$ui_release()V
+HSPLandroidx/compose/ui/node/DelegatingNode;->reset$ui_release()V
+HSPLandroidx/compose/ui/node/DelegatingNode;->runAttachLifecycle$ui_release()V
+HSPLandroidx/compose/ui/node/DelegatingNode;->runDetachLifecycle$ui_release()V
+HSPLandroidx/compose/ui/node/DelegatingNode;->updateCoordinator$ui_release(Landroidx/compose/ui/node/NodeCoordinator;)V
+HSPLandroidx/compose/ui/node/DrawModifierNode;->onMeasureResultChanged()V
+HSPLandroidx/compose/ui/node/HitTestResult;-><init>()V
+HSPLandroidx/compose/ui/node/InnerNodeCoordinator;-><clinit>()V
+HSPLandroidx/compose/ui/node/InnerNodeCoordinator;-><init>(Landroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/node/InnerNodeCoordinator;->getTail()Landroidx/compose/ui/Modifier$Node;
+HSPLandroidx/compose/ui/node/InnerNodeCoordinator;->maxIntrinsicHeight(I)I
+HSPLandroidx/compose/ui/node/InnerNodeCoordinator;->measure-BRTryo0(J)Landroidx/compose/ui/layout/Placeable;
+HSPLandroidx/compose/ui/node/InnerNodeCoordinator;->performDraw(Landroidx/compose/ui/graphics/Canvas;)V
+HSPLandroidx/compose/ui/node/InnerNodeCoordinator;->placeAt-f8xVGno(JFLkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/node/IntrinsicsPolicy;-><init>(Landroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/node/IntrinsicsPolicy;->measurePolicyFromState()Landroidx/compose/ui/layout/MeasurePolicy;
+HSPLandroidx/compose/ui/node/LayerPositionalProperties;-><init>()V
+HSPLandroidx/compose/ui/node/LayoutAwareModifierNode;->onRemeasured-ozmzZPI(J)V
+HSPLandroidx/compose/ui/node/LayoutModifierNode;->maxIntrinsicHeight(Landroidx/compose/ui/layout/IntrinsicMeasureScope;Landroidx/compose/ui/layout/Measurable;I)I
+HSPLandroidx/compose/ui/node/LayoutModifierNode;->maxIntrinsicWidth(Landroidx/compose/ui/layout/IntrinsicMeasureScope;Landroidx/compose/ui/layout/Measurable;I)I
+HSPLandroidx/compose/ui/node/LayoutModifierNodeCoordinator;-><clinit>()V
+HSPLandroidx/compose/ui/node/LayoutModifierNodeCoordinator;-><init>(Landroidx/compose/ui/node/LayoutNode;Landroidx/compose/ui/node/LayoutModifierNode;)V
+HSPLandroidx/compose/ui/node/LayoutModifierNodeCoordinator;->getTail()Landroidx/compose/ui/Modifier$Node;
+HSPLandroidx/compose/ui/node/LayoutModifierNodeCoordinator;->maxIntrinsicHeight(I)I
+HSPLandroidx/compose/ui/node/LayoutModifierNodeCoordinator;->maxIntrinsicWidth(I)I
+HSPLandroidx/compose/ui/node/LayoutModifierNodeCoordinator;->measure-BRTryo0(J)Landroidx/compose/ui/layout/Placeable;
+HSPLandroidx/compose/ui/node/LayoutModifierNodeCoordinator;->performDraw(Landroidx/compose/ui/graphics/Canvas;)V
+HSPLandroidx/compose/ui/node/LayoutModifierNodeCoordinator;->placeAt-f8xVGno(JFLkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/node/LayoutNode$$ExternalSyntheticLambda0;-><init>(I)V
+HSPLandroidx/compose/ui/node/LayoutNode$$ExternalSyntheticLambda0;->compare(Ljava/lang/Object;Ljava/lang/Object;)I
+HSPLandroidx/compose/ui/node/LayoutNode$Companion$ErrorMeasurePolicy$1;-><init>()V
+HSPLandroidx/compose/ui/node/LayoutNode$NoIntrinsicsMeasurePolicy;-><init>(Ljava/lang/String;)V
+HSPLandroidx/compose/ui/node/LayoutNode$WhenMappings;-><clinit>()V
+HSPLandroidx/compose/ui/node/LayoutNode$_foldedChildren$1;-><init>(ILjava/lang/Object;)V
+HSPLandroidx/compose/ui/node/LayoutNode$_foldedChildren$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/ui/node/LayoutNode$_foldedChildren$1;->invoke()V
+HSPLandroidx/compose/ui/node/LayoutNode;-><clinit>()V
+HSPLandroidx/compose/ui/node/LayoutNode;-><init>(IZ)V
+HSPLandroidx/compose/ui/node/LayoutNode;-><init>(ZI)V
+HSPLandroidx/compose/ui/node/LayoutNode;->attach$ui_release(Landroidx/compose/ui/node/Owner;)V
+HSPLandroidx/compose/ui/node/LayoutNode;->clearSubtreeIntrinsicsUsage$ui_release()V
+HSPLandroidx/compose/ui/node/LayoutNode;->clearSubtreePlacementIntrinsicsUsage()V
+HSPLandroidx/compose/ui/node/LayoutNode;->draw$ui_release(Landroidx/compose/ui/graphics/Canvas;)V
+HSPLandroidx/compose/ui/node/LayoutNode;->forceRemeasure()V
+HSPLandroidx/compose/ui/node/LayoutNode;->getChildMeasurables$ui_release()Ljava/util/List;
+HSPLandroidx/compose/ui/node/LayoutNode;->getChildren$ui_release()Ljava/util/List;
+HSPLandroidx/compose/ui/node/LayoutNode;->getFoldedChildren$ui_release()Ljava/util/List;
+HSPLandroidx/compose/ui/node/LayoutNode;->getMeasuredByParent$ui_release$enumunboxing$()I
+HSPLandroidx/compose/ui/node/LayoutNode;->getParent$ui_release()Landroidx/compose/ui/node/LayoutNode;
+HSPLandroidx/compose/ui/node/LayoutNode;->getPlaceOrder$ui_release()I
+HSPLandroidx/compose/ui/node/LayoutNode;->getZSortedChildren()Landroidx/compose/runtime/collection/MutableVector;
+HSPLandroidx/compose/ui/node/LayoutNode;->get_children$ui_release()Landroidx/compose/runtime/collection/MutableVector;
+HSPLandroidx/compose/ui/node/LayoutNode;->insertAt$ui_release(ILandroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/node/LayoutNode;->invalidateLayer$ui_release()V
+HSPLandroidx/compose/ui/node/LayoutNode;->invalidateLayers$ui_release()V
+HSPLandroidx/compose/ui/node/LayoutNode;->invalidateMeasurements$ui_release()V
+HSPLandroidx/compose/ui/node/LayoutNode;->invalidateSemantics$ui_release()V
+HSPLandroidx/compose/ui/node/LayoutNode;->invalidateUnfoldedVirtualChildren()V
+HSPLandroidx/compose/ui/node/LayoutNode;->isAttached()Z
+HSPLandroidx/compose/ui/node/LayoutNode;->isPlaced()Z
+HSPLandroidx/compose/ui/node/LayoutNode;->isValidOwnerScope()Z
+HSPLandroidx/compose/ui/node/LayoutNode;->move$ui_release(III)V
+HSPLandroidx/compose/ui/node/LayoutNode;->onZSortedChildrenInvalidated$ui_release()V
+HSPLandroidx/compose/ui/node/LayoutNode;->requestRelayout$ui_release(Z)V
+HSPLandroidx/compose/ui/node/LayoutNode;->requestRemeasure$ui_release$default(Landroidx/compose/ui/node/LayoutNode;ZI)V
+HSPLandroidx/compose/ui/node/LayoutNode;->rescheduleRemeasureOrRelayout$ui_release(Landroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/node/LayoutNode;->resetSubtreeIntrinsicsUsage$ui_release()V
+HSPLandroidx/compose/ui/node/LayoutNode;->setCompositionLocalMap(Landroidx/compose/runtime/CompositionLocalMap;)V
+HSPLandroidx/compose/ui/node/LayoutNode;->setDensity(Landroidx/compose/ui/unit/Density;)V
+HSPLandroidx/compose/ui/node/LayoutNode;->setLookaheadRoot(Landroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/node/LayoutNode;->setMeasurePolicy(Landroidx/compose/ui/layout/MeasurePolicy;)V
+HSPLandroidx/compose/ui/node/LayoutNode;->setModifier(Landroidx/compose/ui/Modifier;)V
+HSPLandroidx/compose/ui/node/LayoutNode;->setViewConfiguration(Landroidx/compose/ui/platform/ViewConfiguration;)V
+HSPLandroidx/compose/ui/node/LayoutNode;->updateChildrenIfDirty$ui_release()V
+HSPLandroidx/compose/ui/node/LayoutNodeDrawScope;-><init>()V
+HSPLandroidx/compose/ui/node/LayoutNodeDrawScope;->drawContent()V
+HSPLandroidx/compose/ui/node/LayoutNodeDrawScope;->drawDirect-x_KDEd0$ui_release(Landroidx/compose/ui/graphics/Canvas;JLandroidx/compose/ui/node/NodeCoordinator;Landroidx/compose/ui/node/DrawModifierNode;)V
+HSPLandroidx/compose/ui/node/LayoutNodeDrawScope;->drawImage-AZ2fEMs(Landroidx/compose/ui/graphics/ImageBitmap;JJJJFLkotlin/ResultKt;Landroidx/compose/ui/graphics/BlendModeColorFilter;II)V
+HSPLandroidx/compose/ui/node/LayoutNodeDrawScope;->drawRect-AsUm42w(Landroidx/compose/ui/graphics/Brush;JJFLkotlin/ResultKt;Landroidx/compose/ui/graphics/BlendModeColorFilter;I)V
+HSPLandroidx/compose/ui/node/LayoutNodeDrawScope;->drawRect-n-J9OG0(JJJFLkotlin/ResultKt;Landroidx/compose/ui/graphics/BlendModeColorFilter;I)V
+HSPLandroidx/compose/ui/node/LayoutNodeDrawScope;->drawRoundRect-u-Aw5IA(JJJJLkotlin/ResultKt;FLandroidx/compose/ui/graphics/BlendModeColorFilter;I)V
+HSPLandroidx/compose/ui/node/LayoutNodeDrawScope;->getCenter-F1C5BW0()J
+HSPLandroidx/compose/ui/node/LayoutNodeDrawScope;->getDensity()F
+HSPLandroidx/compose/ui/node/LayoutNodeDrawScope;->getFontScale()F
+HSPLandroidx/compose/ui/node/LayoutNodeDrawScope;->getLayoutDirection()Landroidx/compose/ui/unit/LayoutDirection;
+HSPLandroidx/compose/ui/node/LayoutNodeDrawScope;->getSize-NH-jbRc()J
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate$placeOuterCoordinator$1;-><init>(Lkotlin/jvm/functions/Function1;Landroidx/compose/ui/node/LayoutNodeLayoutDelegate;JF)V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate$placeOuterCoordinator$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;-><init>(Landroidx/compose/ui/node/LayoutNodeLayoutDelegate;)V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;->forEachChildAlignmentLinesOwner(Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;->getAlignmentLines()Landroidx/compose/ui/node/LookaheadAlignmentLines;
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;->getChildDelegates$ui_release()Ljava/util/List;
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;->getInnerCoordinator()Landroidx/compose/ui/node/InnerNodeCoordinator;
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;->getMeasuredWidth()I
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;->getParentAlignmentLinesOwner()Landroidx/compose/ui/node/AlignmentLinesOwner;
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;->getParentData()Ljava/lang/Object;
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;->layoutChildren()V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;->markNodeAndSubtreeAsPlaced()V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;->markSubtreeAsNotPlaced()V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;->maxIntrinsicHeight(I)I
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;->maxIntrinsicWidth(I)I
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;->measure-BRTryo0(J)Landroidx/compose/ui/layout/Placeable;
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;->notifyChildrenUsingCoordinatesWhilePlacing()V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;->onIntrinsicsQueried()V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;->onNodePlaced$ui_release()V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;->placeAt-f8xVGno(JFLkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;->placeOuterCoordinator-f8xVGno(JFLkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;->remeasure-BRTryo0(J)Z
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;->replace()V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$performMeasure$2;-><init>(Landroidx/compose/ui/node/LayoutNodeLayoutDelegate;JI)V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$performMeasure$2;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate$performMeasure$2;->invoke()V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate;-><init>(Landroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate;->getOuterCoordinator()Landroidx/compose/ui/node/NodeCoordinator;
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate;->isOutMostLookaheadRoot(Landroidx/compose/ui/node/LayoutNode;)Z
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate;->setCoordinatesAccessedDuringModifierPlacement(Z)V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate;->setCoordinatesAccessedDuringPlacement(Z)V
+HSPLandroidx/compose/ui/node/LayoutNodeLayoutDelegate;->updateParentData()V
+HSPLandroidx/compose/ui/node/LookaheadAlignmentLines;-><init>(Landroidx/compose/ui/node/AlignmentLinesOwner;I)V
+HSPLandroidx/compose/ui/node/LookaheadCapablePlaceable;->invalidateAlignmentLinesFromPositionChange(Landroidx/compose/ui/node/NodeCoordinator;)V
+HSPLandroidx/compose/ui/node/LookaheadCapablePlaceable;->isLookingAhead()Z
+HSPLandroidx/compose/ui/node/MeasureAndLayoutDelegate;-><init>(Landroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/node/MeasureAndLayoutDelegate;->dispatchOnPositionedCallbacks(Z)V
+HSPLandroidx/compose/ui/node/MeasureAndLayoutDelegate;->doLookaheadRemeasure-sdFAvZA(Landroidx/compose/ui/node/LayoutNode;Landroidx/compose/ui/unit/Constraints;)Z
+HSPLandroidx/compose/ui/node/MeasureAndLayoutDelegate;->doRemeasure-sdFAvZA(Landroidx/compose/ui/node/LayoutNode;Landroidx/compose/ui/unit/Constraints;)Z
+HSPLandroidx/compose/ui/node/MeasureAndLayoutDelegate;->forceMeasureTheSubtree(Landroidx/compose/ui/node/LayoutNode;Z)V
+HSPLandroidx/compose/ui/node/MeasureAndLayoutDelegate;->measureAndLayout(Lkotlin/jvm/functions/Function0;)Z
+HSPLandroidx/compose/ui/node/MeasureAndLayoutDelegate;->measureAndLayout-0kLqBqw(Landroidx/compose/ui/node/LayoutNode;J)V
+HSPLandroidx/compose/ui/node/MeasureAndLayoutDelegate;->measureOnly()V
+HSPLandroidx/compose/ui/node/MeasureAndLayoutDelegate;->recurseRemeasure(Landroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/node/MeasureAndLayoutDelegate;->remeasureAndRelayoutIfNeeded(Landroidx/compose/ui/node/LayoutNode;Z)Z
+HSPLandroidx/compose/ui/node/MeasureAndLayoutDelegate;->remeasureOnly(Landroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/node/MeasureAndLayoutDelegate;->requestRelayout(Landroidx/compose/ui/node/LayoutNode;Z)Z
+HSPLandroidx/compose/ui/node/MeasureAndLayoutDelegate;->updateRootConstraints-BRTryo0(J)V
+HSPLandroidx/compose/ui/node/NodeChain$Differ;-><init>(Landroidx/compose/ui/node/NodeChain;Landroidx/compose/ui/Modifier$Node;ILandroidx/compose/runtime/collection/MutableVector;Landroidx/compose/runtime/collection/MutableVector;Z)V
+HSPLandroidx/compose/ui/node/NodeChain$Differ;->areItemsTheSame(II)Z
+HSPLandroidx/compose/ui/node/NodeChain;-><init>(Landroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/node/NodeChain;->access$propagateCoordinator(Landroidx/compose/ui/node/NodeChain;Landroidx/compose/ui/Modifier$Node;Landroidx/compose/ui/node/NodeCoordinator;)V
+HSPLandroidx/compose/ui/node/NodeChain;->createAndInsertNodeAsChild(Landroidx/compose/ui/Modifier$Element;Landroidx/compose/ui/Modifier$Node;)Landroidx/compose/ui/Modifier$Node;
+HSPLandroidx/compose/ui/node/NodeChain;->detachAndRemoveNode(Landroidx/compose/ui/Modifier$Node;)Landroidx/compose/ui/Modifier$Node;
+HSPLandroidx/compose/ui/node/NodeChain;->has-H91voCI$ui_release(I)Z
+HSPLandroidx/compose/ui/node/NodeChain;->runAttachLifecycle()V
+HSPLandroidx/compose/ui/node/NodeChain;->syncCoordinators()V
+HSPLandroidx/compose/ui/node/NodeChain;->updateNode(Landroidx/compose/ui/Modifier$Element;Landroidx/compose/ui/Modifier$Element;Landroidx/compose/ui/Modifier$Node;)V
+HSPLandroidx/compose/ui/node/NodeChainKt;-><clinit>()V
+HSPLandroidx/compose/ui/node/NodeChainKt;->actionForModifiers(Landroidx/compose/ui/Modifier$Element;Landroidx/compose/ui/Modifier$Element;)I
+HSPLandroidx/compose/ui/node/NodeCoordinator$invoke$1;-><init>(Ljava/lang/Object;ILjava/lang/Object;)V
+HSPLandroidx/compose/ui/node/NodeCoordinator$invoke$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/ui/node/NodeCoordinator$invoke$1;->invoke()V
+HSPLandroidx/compose/ui/node/NodeCoordinator;-><clinit>()V
+HSPLandroidx/compose/ui/node/NodeCoordinator;-><init>(Landroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/node/NodeCoordinator;->ancestorToLocal(Landroidx/compose/ui/node/NodeCoordinator;Landroidx/compose/ui/geometry/MutableRect;Z)V
+HSPLandroidx/compose/ui/node/NodeCoordinator;->draw(Landroidx/compose/ui/graphics/Canvas;)V
+HSPLandroidx/compose/ui/node/NodeCoordinator;->drawContainedDrawModifiers(Landroidx/compose/ui/graphics/Canvas;)V
+HSPLandroidx/compose/ui/node/NodeCoordinator;->findCommonAncestor$ui_release(Landroidx/compose/ui/node/NodeCoordinator;)Landroidx/compose/ui/node/NodeCoordinator;
+HSPLandroidx/compose/ui/node/NodeCoordinator;->getAlignmentLinesOwner()Landroidx/compose/ui/node/AlignmentLinesOwner;
+HSPLandroidx/compose/ui/node/NodeCoordinator;->getCoordinates()Landroidx/compose/ui/layout/LayoutCoordinates;
+HSPLandroidx/compose/ui/node/NodeCoordinator;->getDensity()F
+HSPLandroidx/compose/ui/node/NodeCoordinator;->getFontScale()F
+HSPLandroidx/compose/ui/node/NodeCoordinator;->getLayoutDirection()Landroidx/compose/ui/unit/LayoutDirection;
+HSPLandroidx/compose/ui/node/NodeCoordinator;->getLayoutNode()Landroidx/compose/ui/node/LayoutNode;
+HSPLandroidx/compose/ui/node/NodeCoordinator;->getMeasureResult$ui_release()Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/compose/ui/node/NodeCoordinator;->getParent()Landroidx/compose/ui/node/LookaheadCapablePlaceable;
+HSPLandroidx/compose/ui/node/NodeCoordinator;->getParentData()Ljava/lang/Object;
+HSPLandroidx/compose/ui/node/NodeCoordinator;->getParentLayoutCoordinates()Landroidx/compose/ui/layout/LayoutCoordinates;
+HSPLandroidx/compose/ui/node/NodeCoordinator;->getSize-YbymL2g()J
+HSPLandroidx/compose/ui/node/NodeCoordinator;->head-H91voCI(I)Landroidx/compose/ui/Modifier$Node;
+HSPLandroidx/compose/ui/node/NodeCoordinator;->headNode(Z)Landroidx/compose/ui/Modifier$Node;
+HSPLandroidx/compose/ui/node/NodeCoordinator;->invalidateLayer()V
+HSPLandroidx/compose/ui/node/NodeCoordinator;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/node/NodeCoordinator;->isAttached()Z
+HSPLandroidx/compose/ui/node/NodeCoordinator;->isValidOwnerScope()Z
+HSPLandroidx/compose/ui/node/NodeCoordinator;->localBoundingBoxOf(Landroidx/compose/ui/layout/LayoutCoordinates;Z)Landroidx/compose/ui/geometry/Rect;
+HSPLandroidx/compose/ui/node/NodeCoordinator;->localToRoot-MK-Hz9U(J)J
+HSPLandroidx/compose/ui/node/NodeCoordinator;->onCoordinatesUsed$ui_release()V
+HSPLandroidx/compose/ui/node/NodeCoordinator;->onMeasured()V
+HSPLandroidx/compose/ui/node/NodeCoordinator;->onPlaced()V
+HSPLandroidx/compose/ui/node/NodeCoordinator;->placeSelf-f8xVGno(JFLkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/node/NodeCoordinator;->rectInParent$ui_release(Landroidx/compose/ui/geometry/MutableRect;ZZ)V
+HSPLandroidx/compose/ui/node/NodeCoordinator;->setMeasureResult$ui_release(Landroidx/compose/ui/layout/MeasureResult;)V
+HSPLandroidx/compose/ui/node/NodeCoordinator;->toParentPosition-MK-Hz9U(J)J
+HSPLandroidx/compose/ui/node/NodeCoordinator;->updateLayerParameters(Z)V
+HSPLandroidx/compose/ui/node/NodeMeasuringIntrinsics$IntrinsicMinMax;-><clinit>()V
+HSPLandroidx/compose/ui/node/NodeMeasuringIntrinsics$IntrinsicMinMax;-><init>(ILjava/lang/String;)V
+HSPLandroidx/compose/ui/node/NodeMeasuringIntrinsics$IntrinsicWidthHeight;-><clinit>()V
+HSPLandroidx/compose/ui/node/NodeMeasuringIntrinsics$IntrinsicWidthHeight;-><init>(ILjava/lang/String;)V
+HSPLandroidx/compose/ui/node/ObserverNodeOwnerScope;-><init>(Landroidx/compose/ui/node/ObserverModifierNode;)V
+HSPLandroidx/compose/ui/node/ObserverNodeOwnerScope;->isValidOwnerScope()Z
+HSPLandroidx/compose/ui/node/OnPositionedDispatcher$Companion$DepthComparator;-><clinit>()V
+HSPLandroidx/compose/ui/node/OnPositionedDispatcher$Companion$DepthComparator;->compare(Ljava/lang/Object;Ljava/lang/Object;)I
+HSPLandroidx/compose/ui/node/OnPositionedDispatcher;-><init>()V
+HSPLandroidx/compose/ui/node/OnPositionedDispatcher;->dispatchHierarchy(Landroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/node/Owner;->measureAndLayout$default(Landroidx/compose/ui/node/Owner;)V
+HSPLandroidx/compose/ui/node/OwnerSnapshotObserver;-><init>(Landroidx/compose/ui/platform/AndroidComposeView$focusOwner$1;)V
+HSPLandroidx/compose/ui/node/OwnerSnapshotObserver;->observeLayoutModifierSnapshotReads$ui_release(Landroidx/compose/ui/node/LayoutNode;ZLkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/ui/node/OwnerSnapshotObserver;->observeReads$ui_release(Landroidx/compose/ui/node/OwnerScope;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/ui/node/TailModifierNode;-><init>()V
+HSPLandroidx/compose/ui/node/TailModifierNode;->onAttach()V
+HSPLandroidx/compose/ui/node/TailModifierNode;->onDetach()V
+HSPLandroidx/compose/ui/node/UiApplier;-><init>(Landroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/node/UiApplier;->down(Ljava/lang/Object;)V
+HSPLandroidx/compose/ui/node/UiApplier;->getCurrent()Ljava/lang/Object;
+HSPLandroidx/compose/ui/node/UiApplier;->insertBottomUp(ILjava/lang/Object;)V
+HSPLandroidx/compose/ui/node/UiApplier;->insertTopDown(ILjava/lang/Object;)V
+HSPLandroidx/compose/ui/node/UiApplier;->onEndChanges()V
+HSPLandroidx/compose/ui/node/UiApplier;->up()V
+HSPLandroidx/compose/ui/platform/AbstractComposeView;-><init>(Landroid/content/Context;Landroid/util/AttributeSet;I)V
+HSPLandroidx/compose/ui/platform/AbstractComposeView;->addView(Landroid/view/View;ILandroid/view/ViewGroup$LayoutParams;)V
+HSPLandroidx/compose/ui/platform/AbstractComposeView;->addView(Landroid/view/View;Landroid/view/ViewGroup$LayoutParams;)V
+HSPLandroidx/compose/ui/platform/AbstractComposeView;->checkAddView()V
+HSPLandroidx/compose/ui/platform/AbstractComposeView;->ensureCompositionCreated()V
+HSPLandroidx/compose/ui/platform/AbstractComposeView;->isAlive(Landroidx/compose/runtime/CompositionContext;)Z
+HSPLandroidx/compose/ui/platform/AbstractComposeView;->onAttachedToWindow()V
+HSPLandroidx/compose/ui/platform/AbstractComposeView;->onLayout(ZIIII)V
+HSPLandroidx/compose/ui/platform/AbstractComposeView;->onMeasure(II)V
+HSPLandroidx/compose/ui/platform/AbstractComposeView;->onRtlPropertiesChanged(I)V
+HSPLandroidx/compose/ui/platform/AbstractComposeView;->resolveParentCompositionContext()Landroidx/compose/runtime/CompositionContext;
+HSPLandroidx/compose/ui/platform/AbstractComposeView;->setParentCompositionContext(Landroidx/compose/runtime/CompositionContext;)V
+HSPLandroidx/compose/ui/platform/AbstractComposeView;->setParentContext(Landroidx/compose/runtime/CompositionContext;)V
+HSPLandroidx/compose/ui/platform/AbstractComposeView;->setPreviousAttachedWindowToken(Landroid/os/IBinder;)V
+HSPLandroidx/compose/ui/platform/AndroidAccessibilityManager;-><init>(Landroid/content/Context;)V
+HSPLandroidx/compose/ui/platform/AndroidClipboardManager;-><init>(Landroid/content/Context;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView$$ExternalSyntheticApiModelOutline0;->m(Landroid/content/res/Configuration;)I
+HSPLandroidx/compose/ui/platform/AndroidComposeView$$ExternalSyntheticApiModelOutline0;->m(Landroid/graphics/RenderNode;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView$$ExternalSyntheticApiModelOutline0;->m(Landroid/view/View;Landroid/view/translation/ViewTranslationCallback;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView$$ExternalSyntheticLambda1;-><init>(Landroidx/compose/ui/platform/AndroidComposeView;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView$$ExternalSyntheticLambda1;->onGlobalLayout()V
+HSPLandroidx/compose/ui/platform/AndroidComposeView$$ExternalSyntheticLambda2;-><init>(Landroidx/compose/ui/platform/AndroidComposeView;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView$$ExternalSyntheticLambda3;-><init>(Landroidx/compose/ui/platform/AndroidComposeView;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView$$ExternalSyntheticLambda3;->onTouchModeChanged(Z)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView$ViewTreeOwners;-><init>(Landroidx/lifecycle/LifecycleOwner;Landroidx/savedstate/SavedStateRegistryOwner;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView$focusOwner$1;-><init>(Landroidx/compose/ui/platform/AndroidComposeView;I)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView$focusOwner$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/AndroidComposeView$focusOwner$1;->invoke(Lkotlin/jvm/functions/Function0;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView$pointerIconService$1;-><init>(Landroidx/compose/ui/platform/AndroidComposeView;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView$viewTreeOwners$2;-><init>(Landroidx/compose/ui/platform/AndroidComposeView;I)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView$viewTreeOwners$2;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;-><clinit>()V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;-><init>(Landroid/content/Context;Lkotlin/coroutines/CoroutineContext;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->access$get_viewTreeOwners(Landroidx/compose/ui/platform/AndroidComposeView;)Landroidx/compose/ui/platform/AndroidComposeView$ViewTreeOwners;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->convertMeasureSpec-I7RO_PI(I)J
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->dispatchDraw(Landroid/graphics/Canvas;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->dispatchKeyEvent(Landroid/view/KeyEvent;)Z
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->dispatchKeyEventPreIme(Landroid/view/KeyEvent;)Z
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->forceMeasureTheSubtree(Landroidx/compose/ui/node/LayoutNode;Z)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getAccessibilityManager()Landroidx/compose/ui/platform/AccessibilityManager;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getAccessibilityManager()Landroidx/compose/ui/platform/AndroidAccessibilityManager;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getAutofill()Landroidx/compose/ui/autofill/Autofill;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getAutofillTree()Landroidx/compose/ui/autofill/AutofillTree;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getClipboardManager()Landroidx/compose/ui/platform/AndroidClipboardManager;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getClipboardManager()Landroidx/compose/ui/platform/ClipboardManager;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getCoroutineContext()Lkotlin/coroutines/CoroutineContext;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getDensity()Landroidx/compose/ui/unit/Density;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getFocusOwner()Landroidx/compose/ui/focus/FocusOwner;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getFontFamilyResolver()Landroidx/compose/ui/text/font/FontFamily$Resolver;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getFontLoader()Landroidx/compose/ui/text/font/Font$ResourceLoader;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getHapticFeedBack()Landroidx/compose/ui/hapticfeedback/HapticFeedback;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getInputModeManager()Landroidx/compose/ui/input/InputModeManager;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getLayoutDirection()Landroidx/compose/ui/unit/LayoutDirection;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getPointerIconService()Landroidx/compose/ui/input/pointer/PointerIconService;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getRoot()Landroidx/compose/ui/node/LayoutNode;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getSemanticsOwner()Landroidx/compose/ui/semantics/SemanticsOwner;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getSharedDrawScope()Landroidx/compose/ui/node/LayoutNodeDrawScope;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getShowLayoutBounds()Z
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getSnapshotObserver()Landroidx/compose/ui/node/OwnerSnapshotObserver;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getSoftwareKeyboardController()Landroidx/compose/ui/platform/SoftwareKeyboardController;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getTextInputService()Landroidx/compose/ui/text/input/TextInputService;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getTextToolbar()Landroidx/compose/ui/platform/TextToolbar;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getView()Landroid/view/View;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getViewConfiguration()Landroidx/compose/ui/platform/ViewConfiguration;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getViewTreeOwners()Landroidx/compose/ui/platform/AndroidComposeView$ViewTreeOwners;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->getWindowInfo()Landroidx/compose/ui/platform/WindowInfo;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->get_viewTreeOwners()Landroidx/compose/ui/platform/AndroidComposeView$ViewTreeOwners;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->invalidateLayers(Landroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->invalidateLayoutNodeMeasurement(Landroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->measureAndLayout(Z)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->measureAndLayout-0kLqBqw(Landroidx/compose/ui/node/LayoutNode;J)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->notifyLayerIsDirty$ui_release(Landroidx/compose/ui/node/OwnedLayer;Z)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->onAttachedToWindow()V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->onCheckIsTextEditor()Z
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->onCreateInputConnection(Landroid/view/inputmethod/EditorInfo;)Landroid/view/inputmethod/InputConnection;
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->onDraw(Landroid/graphics/Canvas;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->onEndApplyChanges()V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->onFocusChanged(ZILandroid/graphics/Rect;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->onLayout(ZIIII)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->onLayoutChange(Landroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->onMeasure(II)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->onRequestRelayout(Landroidx/compose/ui/node/LayoutNode;ZZ)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->onResume(Landroidx/lifecycle/LifecycleOwner;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->onRtlPropertiesChanged(I)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->onSemanticsChange()V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->onWindowFocusChanged(Z)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->pack-ZIaKswc(II)J
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->recycle$ui_release(Landroidx/compose/ui/node/OwnedLayer;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->scheduleMeasureAndLayout(Landroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->setConfigurationChangeObserver(Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->setLayoutDirection(Landroidx/compose/ui/unit/LayoutDirection;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->setOnViewTreeOwnersAvailable(Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->setShowLayoutBounds(Z)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->set_viewTreeOwners(Landroidx/compose/ui/platform/AndroidComposeView$ViewTreeOwners;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeView;->updatePositionCacheAndDispatch()V
+HSPLandroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat$$ExternalSyntheticLambda1;-><init>(Landroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat$$ExternalSyntheticLambda2;-><init>(Landroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat$1;-><init>(ILjava/lang/Object;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat$1;->onViewAttachedToWindow(Landroid/view/View;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat$MyNodeProvider;-><init>(Landroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat$SemanticsNodeCopy;-><init>(Landroidx/compose/ui/semantics/SemanticsNode;Ljava/util/Map;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat$boundsUpdatesEventLoop$1;-><init>(Landroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat;-><clinit>()V
+HSPLandroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat;-><init>(Landroidx/compose/ui/platform/AndroidComposeView;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat;->boundsUpdatesEventLoop(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat;->getAccessibilityNodeProvider(Landroid/view/View;)Landroidx/core/view/accessibility/AccessibilityNodeProviderCompat;
+HSPLandroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat;->isEnabledForAccessibility()Z
+HSPLandroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat;->onStart(Landroidx/lifecycle/LifecycleOwner;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeViewForceDarkModeQ;-><clinit>()V
+HSPLandroidx/compose/ui/platform/AndroidComposeViewForceDarkModeQ;->disallowForceDark(Landroid/view/View;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeViewTranslationCallbackS;-><clinit>()V
+HSPLandroidx/compose/ui/platform/AndroidComposeViewTranslationCallbackS;->setViewTranslationCallback(Landroid/view/View;Landroid/view/translation/ViewTranslationCallback;)V
+HSPLandroidx/compose/ui/platform/AndroidComposeViewVerificationHelperMethodsO;-><clinit>()V
+HSPLandroidx/compose/ui/platform/AndroidComposeViewVerificationHelperMethodsO;->focusable(Landroid/view/View;IZ)V
+HSPLandroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$obtainImageVectorCache$callbacks$1$1;-><init>(Landroid/content/res/Configuration;Landroidx/compose/ui/res/ImageVectorCache;)V
+HSPLandroidx/compose/ui/platform/AndroidCompositionLocals_androidKt;-><clinit>()V
+HSPLandroidx/compose/ui/platform/AndroidCompositionLocals_androidKt;->ProvideAndroidCompositionLocals(Landroidx/compose/ui/platform/AndroidComposeView;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/ui/platform/AndroidUiDispatcher$dispatchCallback$1;-><init>(Landroidx/compose/ui/platform/AndroidUiDispatcher;)V
+HSPLandroidx/compose/ui/platform/AndroidUiDispatcher$dispatchCallback$1;->doFrame(J)V
+HSPLandroidx/compose/ui/platform/AndroidUiDispatcher$dispatchCallback$1;->run()V
+HSPLandroidx/compose/ui/platform/AndroidUiDispatcher;-><clinit>()V
+HSPLandroidx/compose/ui/platform/AndroidUiDispatcher;-><init>(Landroid/view/Choreographer;Landroid/os/Handler;)V
+HSPLandroidx/compose/ui/platform/AndroidUiDispatcher;->access$performTrampolineDispatch(Landroidx/compose/ui/platform/AndroidUiDispatcher;)V
+HSPLandroidx/compose/ui/platform/AndroidUiDispatcher;->dispatch(Lkotlin/coroutines/CoroutineContext;Ljava/lang/Runnable;)V
+HSPLandroidx/compose/ui/platform/AndroidUiFrameClock$withFrameNanos$2$callback$1;-><init>(Lkotlinx/coroutines/CancellableContinuationImpl;Landroidx/compose/ui/platform/AndroidUiFrameClock;Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/platform/AndroidUiFrameClock$withFrameNanos$2$callback$1;->doFrame(J)V
+HSPLandroidx/compose/ui/platform/AndroidUiFrameClock;-><init>(Landroid/view/Choreographer;Landroidx/compose/ui/platform/AndroidUiDispatcher;)V
+HSPLandroidx/compose/ui/platform/AndroidUiFrameClock;->fold(Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/AndroidUiFrameClock;->get(Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext$Element;
+HSPLandroidx/compose/ui/platform/AndroidUiFrameClock;->minusKey(Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext;
+HSPLandroidx/compose/ui/platform/AndroidUiFrameClock;->withFrameNanos(Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/AndroidViewConfiguration;-><init>(Landroid/view/ViewConfiguration;)V
+HSPLandroidx/compose/ui/platform/CalculateMatrixToWindowApi29;-><init>()V
+HSPLandroidx/compose/ui/platform/ComposableSingletons$Wrapper_androidKt;-><clinit>()V
+HSPLandroidx/compose/ui/platform/ComposeView;-><init>(Landroid/content/Context;)V
+HSPLandroidx/compose/ui/platform/ComposeView;->Content(Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/ui/platform/ComposeView;->getShouldCreateCompositionOnAttachedToWindow()Z
+HSPLandroidx/compose/ui/platform/ComposeView;->setContent(Lkotlin/jvm/functions/Function2;)V
+HSPLandroidx/compose/ui/platform/CompositionLocalsKt;-><clinit>()V
+HSPLandroidx/compose/ui/platform/CompositionLocalsKt;->ProvideCommonCompositionLocals(Landroidx/compose/ui/node/Owner;Landroidx/compose/ui/platform/UriHandler;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/ui/platform/DisposableSaveableStateRegistry;-><init>(Landroidx/compose/runtime/saveable/SaveableStateRegistryImpl;Landroidx/compose/ui/platform/DisposableSaveableStateRegistry_androidKt$DisposableSaveableStateRegistry$1;)V
+HSPLandroidx/compose/ui/platform/DisposableSaveableStateRegistry;->canBeSaved(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/platform/DisposableSaveableStateRegistry;->consumeRestored(Ljava/lang/String;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/DisposableSaveableStateRegistry;->registerProvider(Ljava/lang/String;Lkotlin/jvm/functions/Function0;)Landroidx/compose/runtime/saveable/SaveableStateRegistryImpl$registerProvider$3;
+HSPLandroidx/compose/ui/platform/DisposableSaveableStateRegistry_androidKt$DisposableSaveableStateRegistry$1;-><init>(ZLandroidx/savedstate/SavedStateRegistry;Ljava/lang/String;)V
+HSPLandroidx/compose/ui/platform/GlobalSnapshotManager$ensureStarted$1;-><init>(Lkotlinx/coroutines/channels/Channel;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/ui/platform/GlobalSnapshotManager$ensureStarted$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/ui/platform/GlobalSnapshotManager$ensureStarted$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/GlobalSnapshotManager;-><clinit>()V
+HSPLandroidx/compose/ui/platform/InspectableModifier;-><init>()V
+HSPLandroidx/compose/ui/platform/LayerMatrixCache;-><init>(Landroidx/compose/ui/text/SaversKt$ColorSaver$1;)V
+HSPLandroidx/compose/ui/platform/LayerMatrixCache;->calculateMatrix-GrdbGEg(Ljava/lang/Object;)[F
+HSPLandroidx/compose/ui/platform/LayerMatrixCache;->invalidate()V
+HSPLandroidx/compose/ui/platform/MotionDurationScaleImpl;-><init>()V
+HSPLandroidx/compose/ui/platform/MotionDurationScaleImpl;->fold(Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/MotionDurationScaleImpl;->get(Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext$Element;
+HSPLandroidx/compose/ui/platform/MotionDurationScaleImpl;->getScaleFactor()F
+HSPLandroidx/compose/ui/platform/MotionDurationScaleImpl;->minusKey(Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext;
+HSPLandroidx/compose/ui/platform/OutlineResolver;-><init>(Landroidx/compose/ui/unit/Density;)V
+HSPLandroidx/compose/ui/platform/OutlineResolver;->getOutline()Landroid/graphics/Outline;
+HSPLandroidx/compose/ui/platform/OutlineResolver;->update(Landroidx/compose/ui/graphics/Shape;FZFLandroidx/compose/ui/unit/LayoutDirection;Landroidx/compose/ui/unit/Density;)Z
+HSPLandroidx/compose/ui/platform/OutlineResolver;->updateCache()V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;-><init>()V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->discardDisplayList()V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->drawInto(Landroid/graphics/Canvas;)V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->getAlpha()F
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->getClipToOutline()Z
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->getElevation()F
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->getHasDisplayList()Z
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->getHeight()I
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->getLeft()I
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->getMatrix(Landroid/graphics/Matrix;)V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->getTop()I
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->getWidth()I
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->offsetLeftAndRight(I)V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->offsetTopAndBottom(I)V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->setAlpha(F)V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->setAmbientShadowColor(I)V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->setCameraDistance(F)V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->setClipToBounds(Z)V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->setClipToOutline(Z)V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->setCompositingStrategy-aDBOjCE(I)V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->setElevation(F)V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->setHasOverlappingRendering()Z
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->setOutline(Landroid/graphics/Outline;)V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->setPivotX(F)V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->setPivotY(F)V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->setPosition(IIII)Z
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->setRenderEffect()V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->setRotationX(F)V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->setRotationY(F)V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->setRotationZ(F)V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->setScaleX(F)V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->setScaleY(F)V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->setSpotShadowColor(I)V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->setTranslationX(F)V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29;->setTranslationY(F)V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29VerificationHelper;-><clinit>()V
+HSPLandroidx/compose/ui/platform/RenderNodeApi29VerificationHelper;->setRenderEffect(Landroid/graphics/RenderNode;Landroidx/compose/ui/graphics/RenderEffect;)V
+HSPLandroidx/compose/ui/platform/RenderNodeLayer;-><init>(Landroidx/compose/ui/platform/AndroidComposeView;Lkotlin/jvm/functions/Function1;Landroidx/compose/ui/node/LayoutNode$_foldedChildren$1;)V
+HSPLandroidx/compose/ui/platform/RenderNodeLayer;->destroy()V
+HSPLandroidx/compose/ui/platform/RenderNodeLayer;->drawLayer(Landroidx/compose/ui/graphics/Canvas;)V
+HSPLandroidx/compose/ui/platform/RenderNodeLayer;->invalidate()V
+HSPLandroidx/compose/ui/platform/RenderNodeLayer;->mapBounds(Landroidx/compose/ui/geometry/MutableRect;Z)V
+HSPLandroidx/compose/ui/platform/RenderNodeLayer;->mapOffset-8S9VItk(JZ)J
+HSPLandroidx/compose/ui/platform/RenderNodeLayer;->move--gyyYBs(J)V
+HSPLandroidx/compose/ui/platform/RenderNodeLayer;->resize-ozmzZPI(J)V
+HSPLandroidx/compose/ui/platform/RenderNodeLayer;->reuseLayer(Landroidx/compose/ui/node/LayoutNode$_foldedChildren$1;Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/platform/RenderNodeLayer;->setDirty(Z)V
+HSPLandroidx/compose/ui/platform/RenderNodeLayer;->updateDisplayList()V
+HSPLandroidx/compose/ui/platform/RenderNodeLayer;->updateLayerProperties-dDxr-wY(FFFFFFFFFFJLandroidx/compose/ui/graphics/Shape;ZJJILandroidx/compose/ui/unit/LayoutDirection;Landroidx/compose/ui/unit/Density;)V
+HSPLandroidx/compose/ui/platform/ViewLayer;-><clinit>()V
+HSPLandroidx/compose/ui/platform/WeakCache;-><init>()V
+HSPLandroidx/compose/ui/platform/WeakCache;-><init>(I)V
+HSPLandroidx/compose/ui/platform/WeakCache;-><init>(Landroidx/compose/ui/node/InnerNodeCoordinator;)V
+HSPLandroidx/compose/ui/platform/WeakCache;-><init>(Ljava/lang/Object;ILjava/lang/Object;)V
+HSPLandroidx/compose/ui/platform/WeakCache;->add(Landroidx/compose/ui/node/LayoutNode;Z)V
+HSPLandroidx/compose/ui/platform/WeakCache;->clearWeakReferences()V
+HSPLandroidx/compose/ui/platform/WeakCache;->get$1()Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/WeakCache;->set(Ljava/lang/Object;)V
+HSPLandroidx/compose/ui/platform/WindowInfoImpl;-><clinit>()V
+HSPLandroidx/compose/ui/platform/WindowInfoImpl;-><init>()V
+HSPLandroidx/compose/ui/platform/WindowRecomposerPolicy$createAndInstallWindowRecomposer$unsetJob$1;-><init>(Landroidx/compose/runtime/Recomposer;Landroid/view/View;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/ui/platform/WindowRecomposerPolicy$createAndInstallWindowRecomposer$unsetJob$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/ui/platform/WindowRecomposerPolicy$createAndInstallWindowRecomposer$unsetJob$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/WindowRecomposerPolicy;-><clinit>()V
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt$createLifecycleAwareWindowRecomposer$1;-><init>(Landroid/view/View;Landroidx/compose/runtime/Recomposer;)V
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt$createLifecycleAwareWindowRecomposer$1;->onViewAttachedToWindow(Landroid/view/View;)V
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt$createLifecycleAwareWindowRecomposer$2$WhenMappings;-><clinit>()V
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt$createLifecycleAwareWindowRecomposer$2$onStateChanged$1$1$1;-><init>(Lkotlinx/coroutines/flow/StateFlow;Landroidx/compose/ui/platform/MotionDurationScaleImpl;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt$createLifecycleAwareWindowRecomposer$2$onStateChanged$1$1$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt$createLifecycleAwareWindowRecomposer$2$onStateChanged$1$1$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt$createLifecycleAwareWindowRecomposer$2$onStateChanged$1;-><init>(Lkotlin/jvm/internal/Ref$ObjectRef;Landroidx/compose/runtime/Recomposer;Landroidx/lifecycle/LifecycleOwner;Landroidx/compose/ui/platform/WindowRecomposer_androidKt$createLifecycleAwareWindowRecomposer$2;Landroid/view/View;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt$createLifecycleAwareWindowRecomposer$2$onStateChanged$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt$createLifecycleAwareWindowRecomposer$2$onStateChanged$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt$createLifecycleAwareWindowRecomposer$2$onStateChanged$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt$createLifecycleAwareWindowRecomposer$2;-><init>(Lkotlinx/coroutines/internal/ContextScope;Landroidx/compose/runtime/PausableMonotonicFrameClock;Landroidx/compose/runtime/Recomposer;Lkotlin/jvm/internal/Ref$ObjectRef;Landroid/view/View;)V
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt$createLifecycleAwareWindowRecomposer$2;->onStateChanged(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt$getAnimationScaleFlowFor$1$1$1;-><init>(Landroid/content/ContentResolver;Landroid/net/Uri;Landroidx/emoji2/text/FontRequestEmojiCompatConfig$FontRequestMetadataLoader$1;Lkotlinx/coroutines/channels/Channel;Landroid/content/Context;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt$getAnimationScaleFlowFor$1$1$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt$getAnimationScaleFlowFor$1$1$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt$getAnimationScaleFlowFor$1$1$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt;-><clinit>()V
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt;->access$getAnimationScaleFlowFor(Landroid/content/Context;)Lkotlinx/coroutines/flow/StateFlow;
+HSPLandroidx/compose/ui/platform/WindowRecomposer_androidKt;->getCompositionContext(Landroid/view/View;)Landroidx/compose/runtime/CompositionContext;
+HSPLandroidx/compose/ui/platform/WrappedComposition$setContent$1$1$1;-><init>(Landroidx/compose/ui/platform/WrappedComposition;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/compose/ui/platform/WrappedComposition$setContent$1$1$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLandroidx/compose/ui/platform/WrappedComposition$setContent$1$1$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/WrappedComposition$setContent$1$1;-><init>(Landroidx/compose/ui/platform/WrappedComposition;Lkotlin/jvm/functions/Function2;I)V
+HSPLandroidx/compose/ui/platform/WrappedComposition$setContent$1$1;->invoke(Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/compose/ui/platform/WrappedComposition$setContent$1$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/WrappedComposition$setContent$1;-><init>(Ljava/lang/Object;ILjava/lang/Object;)V
+HSPLandroidx/compose/ui/platform/WrappedComposition$setContent$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/platform/WrappedComposition;-><init>(Landroidx/compose/ui/platform/AndroidComposeView;Landroidx/compose/runtime/CompositionImpl;)V
+HSPLandroidx/compose/ui/platform/WrappedComposition;->onStateChanged(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V
+HSPLandroidx/compose/ui/platform/WrappedComposition;->setContent(Lkotlin/jvm/functions/Function2;)V
+HSPLandroidx/compose/ui/platform/WrapperRenderNodeLayerHelperMethods;-><clinit>()V
+HSPLandroidx/compose/ui/platform/WrapperRenderNodeLayerHelperMethods;->onDescendantInvalidated(Landroidx/compose/ui/platform/AndroidComposeView;)V
+HSPLandroidx/compose/ui/platform/WrapperVerificationHelperMethods;-><clinit>()V
+HSPLandroidx/compose/ui/platform/WrapperVerificationHelperMethods;->attributeSourceResourceMap(Landroid/view/View;)Ljava/util/Map;
+HSPLandroidx/compose/ui/platform/Wrapper_androidKt;-><clinit>()V
+HSPLandroidx/compose/ui/platform/Wrapper_androidKt;->setContent(Landroidx/compose/ui/platform/AbstractComposeView;Landroidx/compose/runtime/CompositionContext;Landroidx/compose/runtime/internal/ComposableLambdaImpl;)Landroidx/compose/runtime/Composition;
+HSPLandroidx/compose/ui/res/ImageVectorCache;-><init>()V
+HSPLandroidx/compose/ui/semantics/AppendedSemanticsElement;-><init>(Lkotlin/jvm/functions/Function1;Z)V
+HSPLandroidx/compose/ui/semantics/AppendedSemanticsElement;->create()Landroidx/compose/ui/Modifier$Node;
+HSPLandroidx/compose/ui/semantics/AppendedSemanticsElement;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/semantics/AppendedSemanticsElement;->update(Landroidx/compose/ui/Modifier$Node;)V
+HSPLandroidx/compose/ui/semantics/CollectionInfo;-><init>(II)V
+HSPLandroidx/compose/ui/semantics/CoreSemanticsModifierNode;-><init>(ZLkotlin/jvm/functions/Function1;)V
+HSPLandroidx/compose/ui/semantics/EmptySemanticsElement;-><clinit>()V
+HSPLandroidx/compose/ui/semantics/EmptySemanticsElement;-><init>()V
+HSPLandroidx/compose/ui/semantics/EmptySemanticsElement;->create()Landroidx/compose/ui/Modifier$Node;
+HSPLandroidx/compose/ui/semantics/ScrollAxisRange;-><init>(Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Z)V
+HSPLandroidx/compose/ui/semantics/SemanticsConfiguration;-><init>()V
+HSPLandroidx/compose/ui/semantics/SemanticsConfiguration;->contains(Landroidx/compose/ui/semantics/SemanticsPropertyKey;)Z
+HSPLandroidx/compose/ui/semantics/SemanticsModifierKt;-><clinit>()V
+HSPLandroidx/compose/ui/semantics/SemanticsNode;-><init>(Landroidx/compose/ui/Modifier$Node;ZLandroidx/compose/ui/node/LayoutNode;Landroidx/compose/ui/semantics/SemanticsConfiguration;)V
+HSPLandroidx/compose/ui/semantics/SemanticsNode;->fillOneLayerOfSemanticsWrappers(Landroidx/compose/ui/node/LayoutNode;Ljava/util/ArrayList;)V
+HSPLandroidx/compose/ui/semantics/SemanticsNode;->getChildren(ZZ)Ljava/util/List;
+HSPLandroidx/compose/ui/semantics/SemanticsNode;->getReplacedChildren$ui_release()Ljava/util/List;
+HSPLandroidx/compose/ui/semantics/SemanticsNode;->isMergingSemanticsOfDescendants()Z
+HSPLandroidx/compose/ui/semantics/SemanticsNode;->unmergedChildren$ui_release(Z)Ljava/util/List;
+HSPLandroidx/compose/ui/semantics/SemanticsOwner;-><init>(Landroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/semantics/SemanticsOwner;->getUnmergedRootSemanticsNode()Landroidx/compose/ui/semantics/SemanticsNode;
+HSPLandroidx/compose/ui/semantics/SemanticsProperties;-><clinit>()V
+HSPLandroidx/compose/ui/semantics/SemanticsPropertyKey;-><init>(Ljava/lang/String;)V
+HSPLandroidx/compose/ui/semantics/SemanticsPropertyKey;-><init>(Ljava/lang/String;Lkotlin/jvm/functions/Function2;)V
+HSPLandroidx/compose/ui/text/AndroidParagraph;-><init>(Landroidx/compose/ui/text/platform/AndroidParagraphIntrinsics;IZJ)V
+HSPLandroidx/compose/ui/text/AndroidParagraph;->constructTextLayout(IILandroid/text/TextUtils$TruncateAt;IIIII)Landroidx/compose/ui/text/android/TextLayout;
+HSPLandroidx/compose/ui/text/AndroidParagraph;->getHeight()F
+HSPLandroidx/compose/ui/text/AndroidParagraph;->getWidth()F
+HSPLandroidx/compose/ui/text/AndroidParagraph;->paint(Landroidx/compose/ui/graphics/Canvas;)V
+HSPLandroidx/compose/ui/text/AndroidParagraph;->paint-LG529CI(Landroidx/compose/ui/graphics/Canvas;JLandroidx/compose/ui/graphics/Shadow;Landroidx/compose/ui/text/style/TextDecoration;Lkotlin/ResultKt;I)V
+HSPLandroidx/compose/ui/text/AnnotatedString$Range;-><init>(IILjava/lang/Object;)V
+HSPLandroidx/compose/ui/text/AnnotatedString$Range;-><init>(Ljava/lang/Object;IILjava/lang/String;)V
+HSPLandroidx/compose/ui/text/AnnotatedString;-><init>(Ljava/lang/String;Ljava/util/List;Ljava/util/List;Ljava/util/List;)V
+HSPLandroidx/compose/ui/text/AnnotatedString;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/text/AnnotatedStringKt;-><clinit>()V
+HSPLandroidx/compose/ui/text/EmojiSupportMatch;-><init>(I)V
+HSPLandroidx/compose/ui/text/MultiParagraph;->paint-LG529CI$default(Landroidx/compose/ui/text/MultiParagraph;Landroidx/compose/ui/graphics/Canvas;JLandroidx/compose/ui/graphics/Shadow;Landroidx/compose/ui/text/style/TextDecoration;Lkotlin/ResultKt;)V
+HSPLandroidx/compose/ui/text/MultiParagraphIntrinsics$maxIntrinsicWidth$2;-><init>(Landroidx/compose/ui/text/MultiParagraphIntrinsics;I)V
+HSPLandroidx/compose/ui/text/MultiParagraphIntrinsics$maxIntrinsicWidth$2;->invoke$1()Ljava/lang/Float;
+HSPLandroidx/compose/ui/text/MultiParagraphIntrinsics$maxIntrinsicWidth$2;->invoke()Ljava/lang/Object;
+HSPLandroidx/compose/ui/text/MultiParagraphIntrinsics;-><init>(Landroidx/compose/ui/text/AnnotatedString;Landroidx/compose/ui/text/TextStyle;Ljava/util/List;Landroidx/compose/ui/unit/Density;Landroidx/compose/ui/text/font/FontFamily$Resolver;)V
+HSPLandroidx/compose/ui/text/MultiParagraphIntrinsics;->getHasStaleResolvedFonts()Z
+HSPLandroidx/compose/ui/text/MultiParagraphIntrinsics;->getMaxIntrinsicWidth()F
+HSPLandroidx/compose/ui/text/ParagraphInfo;-><init>(Landroidx/compose/ui/text/AndroidParagraph;IIIIFF)V
+HSPLandroidx/compose/ui/text/ParagraphIntrinsicInfo;-><init>(Landroidx/compose/ui/text/platform/AndroidParagraphIntrinsics;II)V
+HSPLandroidx/compose/ui/text/ParagraphStyle;-><init>(Landroidx/compose/ui/text/style/TextAlign;Landroidx/compose/ui/text/style/TextDirection;JLandroidx/compose/ui/text/style/TextIndent;Landroidx/compose/ui/text/PlatformParagraphStyle;Landroidx/compose/ui/text/style/LineHeightStyle;Landroidx/compose/ui/text/style/LineBreak;Landroidx/compose/ui/text/style/Hyphens;Landroidx/compose/ui/text/style/TextMotion;)V
+HSPLandroidx/compose/ui/text/ParagraphStyle;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/text/ParagraphStyle;->merge(Landroidx/compose/ui/text/ParagraphStyle;)Landroidx/compose/ui/text/ParagraphStyle;
+HSPLandroidx/compose/ui/text/ParagraphStyleKt;-><clinit>()V
+HSPLandroidx/compose/ui/text/ParagraphStyleKt;->fastMerge-HtYhynw(Landroidx/compose/ui/text/ParagraphStyle;Landroidx/compose/ui/text/style/TextAlign;Landroidx/compose/ui/text/style/TextDirection;JLandroidx/compose/ui/text/style/TextIndent;Landroidx/compose/ui/text/PlatformParagraphStyle;Landroidx/compose/ui/text/style/LineHeightStyle;Landroidx/compose/ui/text/style/LineBreak;Landroidx/compose/ui/text/style/Hyphens;Landroidx/compose/ui/text/style/TextMotion;)Landroidx/compose/ui/text/ParagraphStyle;
+HSPLandroidx/compose/ui/text/PlatformParagraphStyle;-><init>(I)V
+HSPLandroidx/compose/ui/text/PlatformParagraphStyle;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/text/PlatformTextStyle;-><init>(Landroidx/compose/ui/text/PlatformParagraphStyle;)V
+HSPLandroidx/compose/ui/text/SaversKt$ColorSaver$1;-><clinit>()V
+HSPLandroidx/compose/ui/text/SaversKt$ColorSaver$1;-><init>(I)V
+HSPLandroidx/compose/ui/text/SaversKt$ColorSaver$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/text/SaversKt$ColorSaver$2;-><clinit>()V
+HSPLandroidx/compose/ui/text/SaversKt$ColorSaver$2;-><init>(I)V
+HSPLandroidx/compose/ui/text/SaversKt$ColorSaver$2;->invoke(Landroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/compose/ui/text/SaversKt$ColorSaver$2;->invoke(Ljava/lang/Object;)Ljava/lang/Boolean;
+HSPLandroidx/compose/ui/text/SaversKt$ColorSaver$2;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/text/SpanStyle;-><init>(JJLandroidx/compose/ui/text/font/FontWeight;Landroidx/compose/ui/text/font/FontStyle;Landroidx/compose/ui/text/font/FontSynthesis;Landroidx/compose/ui/text/font/FontFamily;Ljava/lang/String;JLandroidx/compose/ui/text/style/BaselineShift;Landroidx/compose/ui/text/style/TextGeometricTransform;Landroidx/compose/ui/text/intl/LocaleList;JLandroidx/compose/ui/text/style/TextDecoration;Landroidx/compose/ui/graphics/Shadow;I)V
+HSPLandroidx/compose/ui/text/SpanStyle;-><init>(JJLandroidx/compose/ui/text/font/FontWeight;Landroidx/compose/ui/text/font/FontStyle;Landroidx/compose/ui/text/font/FontSynthesis;Landroidx/compose/ui/text/font/FontFamily;Ljava/lang/String;JLandroidx/compose/ui/text/style/BaselineShift;Landroidx/compose/ui/text/style/TextGeometricTransform;Landroidx/compose/ui/text/intl/LocaleList;JLandroidx/compose/ui/text/style/TextDecoration;Landroidx/compose/ui/graphics/Shadow;Lkotlin/ResultKt;)V
+HSPLandroidx/compose/ui/text/SpanStyle;-><init>(Landroidx/compose/ui/text/style/TextForegroundStyle;JLandroidx/compose/ui/text/font/FontWeight;Landroidx/compose/ui/text/font/FontStyle;Landroidx/compose/ui/text/font/FontSynthesis;Landroidx/compose/ui/text/font/FontFamily;Ljava/lang/String;JLandroidx/compose/ui/text/style/BaselineShift;Landroidx/compose/ui/text/style/TextGeometricTransform;Landroidx/compose/ui/text/intl/LocaleList;JLandroidx/compose/ui/text/style/TextDecoration;Landroidx/compose/ui/graphics/Shadow;Lkotlin/ResultKt;)V
+HSPLandroidx/compose/ui/text/SpanStyle;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/text/SpanStyle;->getColor-0d7_KjU()J
+HSPLandroidx/compose/ui/text/SpanStyle;->hasSameLayoutAffectingAttributes$ui_text_release(Landroidx/compose/ui/text/SpanStyle;)Z
+HSPLandroidx/compose/ui/text/SpanStyle;->hasSameNonLayoutAttributes$ui_text_release(Landroidx/compose/ui/text/SpanStyle;)Z
+HSPLandroidx/compose/ui/text/SpanStyle;->merge(Landroidx/compose/ui/text/SpanStyle;)Landroidx/compose/ui/text/SpanStyle;
+HSPLandroidx/compose/ui/text/SpanStyleKt;-><clinit>()V
+HSPLandroidx/compose/ui/text/SpanStyleKt;->fastMerge-dSHsh3o(Landroidx/compose/ui/text/SpanStyle;JLandroidx/compose/ui/graphics/Brush;FJLandroidx/compose/ui/text/font/FontWeight;Landroidx/compose/ui/text/font/FontStyle;Landroidx/compose/ui/text/font/FontSynthesis;Landroidx/compose/ui/text/font/FontFamily;Ljava/lang/String;JLandroidx/compose/ui/text/style/BaselineShift;Landroidx/compose/ui/text/style/TextGeometricTransform;Landroidx/compose/ui/text/intl/LocaleList;JLandroidx/compose/ui/text/style/TextDecoration;Landroidx/compose/ui/graphics/Shadow;Lkotlin/ResultKt;)Landroidx/compose/ui/text/SpanStyle;
+HSPLandroidx/compose/ui/text/TextLayoutInput;-><init>(Landroidx/compose/ui/text/AnnotatedString;Landroidx/compose/ui/text/TextStyle;Ljava/util/List;IZILandroidx/compose/ui/unit/Density;Landroidx/compose/ui/unit/LayoutDirection;Landroidx/compose/ui/text/font/FontFamily$Resolver;J)V
+HSPLandroidx/compose/ui/text/TextLayoutResult;-><init>(Landroidx/compose/ui/text/TextLayoutInput;Landroidx/compose/ui/text/MultiParagraph;J)V
+HSPLandroidx/compose/ui/text/TextRange;-><clinit>()V
+HSPLandroidx/compose/ui/text/TextRange;->getEnd-impl(J)I
+HSPLandroidx/compose/ui/text/TextStyle;-><clinit>()V
+HSPLandroidx/compose/ui/text/TextStyle;-><init>(JJLandroidx/compose/ui/text/font/FontWeight;Landroidx/compose/ui/text/font/FontStyle;Landroidx/compose/ui/text/font/FontFamily;JLandroidx/compose/ui/text/style/TextDecoration;Landroidx/compose/ui/text/style/TextAlign;JI)V
+HSPLandroidx/compose/ui/text/TextStyle;-><init>(JLandroidx/compose/ui/text/font/FontWeight;Landroidx/compose/ui/text/font/DefaultFontFamily;I)V
+HSPLandroidx/compose/ui/text/TextStyle;-><init>(Landroidx/compose/ui/text/SpanStyle;Landroidx/compose/ui/text/ParagraphStyle;)V
+HSPLandroidx/compose/ui/text/TextStyle;-><init>(Landroidx/compose/ui/text/SpanStyle;Landroidx/compose/ui/text/ParagraphStyle;Landroidx/compose/ui/text/PlatformTextStyle;)V
+HSPLandroidx/compose/ui/text/TextStyle;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/text/TextStyle;->getColor-0d7_KjU()J
+HSPLandroidx/compose/ui/text/TextStyle;->merge(Landroidx/compose/ui/text/TextStyle;)Landroidx/compose/ui/text/TextStyle;
+HSPLandroidx/compose/ui/text/TextStyle;->merge-Z1GrekI$default(IJJJJLandroidx/compose/ui/text/TextStyle;Landroidx/compose/ui/text/font/FontFamily;Landroidx/compose/ui/text/font/FontStyle;Landroidx/compose/ui/text/font/FontWeight;Landroidx/compose/ui/text/style/TextAlign;Landroidx/compose/ui/text/style/TextDecoration;)Landroidx/compose/ui/text/TextStyle;
+HSPLandroidx/compose/ui/text/android/BoringLayoutFactoryDefault;->create(Ljava/lang/CharSequence;Landroid/text/TextPaint;ILandroid/text/Layout$Alignment;FFLandroid/text/BoringLayout$Metrics;ZLandroid/text/TextUtils$TruncateAt;I)Landroid/text/BoringLayout;
+HSPLandroidx/compose/ui/text/android/BoringLayoutFactoryDefault;->isBoring(Ljava/lang/CharSequence;Landroid/text/TextPaint;Landroid/text/TextDirectionHeuristic;)Landroid/text/BoringLayout$Metrics;
+HSPLandroidx/compose/ui/text/android/LayoutIntrinsics;-><init>(Ljava/lang/CharSequence;Landroidx/compose/ui/text/platform/AndroidTextPaint;I)V
+HSPLandroidx/compose/ui/text/android/LayoutIntrinsics;->getBoringMetrics()Landroid/text/BoringLayout$Metrics;
+HSPLandroidx/compose/ui/text/android/LayoutIntrinsics;->getMaxIntrinsicWidth()F
+HSPLandroidx/compose/ui/text/android/Paint29$$ExternalSyntheticApiModelOutline0;->m$1(Landroid/graphics/RenderNode;)F
+HSPLandroidx/compose/ui/text/android/Paint29$$ExternalSyntheticApiModelOutline0;->m$1(Landroid/graphics/RenderNode;)Z
+HSPLandroidx/compose/ui/text/android/Paint29$$ExternalSyntheticApiModelOutline0;->m$1(Landroid/graphics/RenderNode;F)V
+HSPLandroidx/compose/ui/text/android/Paint29$$ExternalSyntheticApiModelOutline0;->m$2(Landroid/graphics/RenderNode;)V
+HSPLandroidx/compose/ui/text/android/Paint29$$ExternalSyntheticApiModelOutline0;->m$2(Landroid/graphics/RenderNode;F)V
+HSPLandroidx/compose/ui/text/android/Paint29$$ExternalSyntheticApiModelOutline0;->m$3(Landroid/graphics/RenderNode;)I
+HSPLandroidx/compose/ui/text/android/Paint29$$ExternalSyntheticApiModelOutline0;->m$3(Landroid/graphics/RenderNode;)V
+HSPLandroidx/compose/ui/text/android/Paint29$$ExternalSyntheticApiModelOutline0;->m()Landroid/graphics/RenderNode;
+HSPLandroidx/compose/ui/text/android/Paint29$$ExternalSyntheticApiModelOutline0;->m(Landroid/graphics/Paint;Ljava/lang/CharSequence;IILandroid/graphics/Rect;)V
+HSPLandroidx/compose/ui/text/android/Paint29$$ExternalSyntheticApiModelOutline0;->m(Landroid/graphics/RenderNode;)F
+HSPLandroidx/compose/ui/text/android/Paint29$$ExternalSyntheticApiModelOutline0;->m(Landroid/graphics/RenderNode;)I
+HSPLandroidx/compose/ui/text/android/Paint29$$ExternalSyntheticApiModelOutline0;->m(Landroid/graphics/RenderNode;)Landroid/graphics/RecordingCanvas;
+HSPLandroidx/compose/ui/text/android/Paint29$$ExternalSyntheticApiModelOutline0;->m(Landroid/graphics/RenderNode;)V
+HSPLandroidx/compose/ui/text/android/Paint29$$ExternalSyntheticApiModelOutline0;->m(Landroid/graphics/RenderNode;)Z
+HSPLandroidx/compose/ui/text/android/Paint29$$ExternalSyntheticApiModelOutline0;->m(Landroid/graphics/RenderNode;F)V
+HSPLandroidx/compose/ui/text/android/Paint29$$ExternalSyntheticApiModelOutline0;->m(Landroid/graphics/RenderNode;I)V
+HSPLandroidx/compose/ui/text/android/Paint29$$ExternalSyntheticApiModelOutline0;->m(Landroid/graphics/RenderNode;IIII)Z
+HSPLandroidx/compose/ui/text/android/Paint29$$ExternalSyntheticApiModelOutline0;->m(Landroid/graphics/RenderNode;Landroid/graphics/Matrix;)V
+HSPLandroidx/compose/ui/text/android/Paint29$$ExternalSyntheticApiModelOutline0;->m(Landroid/graphics/RenderNode;Landroid/graphics/Outline;)V
+HSPLandroidx/compose/ui/text/android/Paint29$$ExternalSyntheticApiModelOutline0;->m(Landroid/graphics/RenderNode;Z)V
+HSPLandroidx/compose/ui/text/android/Paint29$$ExternalSyntheticApiModelOutline0;->m(Landroid/view/View;)Ljava/util/Map;
+HSPLandroidx/compose/ui/text/android/Paint29;->getTextBounds(Landroid/graphics/Paint;Ljava/lang/CharSequence;IILandroid/graphics/Rect;)V
+HSPLandroidx/compose/ui/text/android/StaticLayoutFactory23;->create(Landroidx/compose/ui/text/android/StaticLayoutParams;)Landroid/text/StaticLayout;
+HSPLandroidx/compose/ui/text/android/StaticLayoutFactory26;->setJustificationMode(Landroid/text/StaticLayout$Builder;I)V
+HSPLandroidx/compose/ui/text/android/StaticLayoutFactory28;->setUseLineSpacingFromFallbacks(Landroid/text/StaticLayout$Builder;Z)V
+HSPLandroidx/compose/ui/text/android/StaticLayoutParams;-><init>(Ljava/lang/CharSequence;IILandroidx/compose/ui/text/platform/AndroidTextPaint;ILandroid/text/TextDirectionHeuristic;Landroid/text/Layout$Alignment;ILandroid/text/TextUtils$TruncateAt;IFFIZZIIII[I[I)V
+HSPLandroidx/compose/ui/text/android/TextAlignmentAdapter;-><clinit>()V
+HSPLandroidx/compose/ui/text/android/TextAndroidCanvas;->drawText(Ljava/lang/String;FFLandroid/graphics/Paint;)V
+HSPLandroidx/compose/ui/text/android/TextAndroidCanvas;->drawTextRun(Ljava/lang/CharSequence;IIIIFFZLandroid/graphics/Paint;)V
+HSPLandroidx/compose/ui/text/android/TextAndroidCanvas;->getClipBounds(Landroid/graphics/Rect;)Z
+HSPLandroidx/compose/ui/text/android/TextLayout;-><init>(Ljava/lang/CharSequence;FLandroidx/compose/ui/text/platform/AndroidTextPaint;ILandroid/text/TextUtils$TruncateAt;IZIIIIIILandroidx/compose/ui/text/android/LayoutIntrinsics;)V
+HSPLandroidx/compose/ui/text/android/TextLayout;->getHeight()I
+HSPLandroidx/compose/ui/text/android/TextLayout;->getLineBaseline(I)F
+HSPLandroidx/compose/ui/text/android/TextLayout;->getText()Ljava/lang/CharSequence;
+HSPLandroidx/compose/ui/text/android/TextLayoutKt;-><clinit>()V
+HSPLandroidx/compose/ui/text/android/TextLayoutKt;->getTextDirectionHeuristic(I)Landroid/text/TextDirectionHeuristic;
+HSPLandroidx/compose/ui/text/android/style/LineHeightStyleSpan;-><init>(FIZZF)V
+HSPLandroidx/compose/ui/text/android/style/LineHeightStyleSpan;->chooseHeight(Ljava/lang/CharSequence;IIIILandroid/graphics/Paint$FontMetricsInt;)V
+HSPLandroidx/compose/ui/text/caches/LruCache;-><init>()V
+HSPLandroidx/compose/ui/text/caches/LruCache;->get(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/text/caches/LruCache;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/text/caches/LruCache;->size()I
+HSPLandroidx/compose/ui/text/caches/SimpleArrayMap;-><init>()V
+HSPLandroidx/compose/ui/text/font/AndroidFontResolveInterceptor;-><init>(I)V
+HSPLandroidx/compose/ui/text/font/AndroidFontResolveInterceptor;->interceptFontWeight(Landroidx/compose/ui/text/font/FontWeight;)Landroidx/compose/ui/text/font/FontWeight;
+HSPLandroidx/compose/ui/text/font/AsyncTypefaceCache;-><init>()V
+HSPLandroidx/compose/ui/text/font/FontFamily;-><clinit>()V
+HSPLandroidx/compose/ui/text/font/FontFamilyResolverImpl;-><init>(Landroidx/compose/ui/unit/Dp$Companion;Landroidx/compose/ui/text/font/AndroidFontResolveInterceptor;)V
+HSPLandroidx/compose/ui/text/font/FontFamilyResolverImpl;->resolve(Landroidx/compose/ui/text/font/TypefaceRequest;)Landroidx/compose/ui/text/font/TypefaceResult;
+HSPLandroidx/compose/ui/text/font/FontFamilyResolverImpl;->resolve-DPcqOEQ(Landroidx/compose/ui/text/font/FontFamily;Landroidx/compose/ui/text/font/FontWeight;II)Landroidx/compose/ui/text/font/TypefaceResult;
+HSPLandroidx/compose/ui/text/font/FontFamilyResolverKt;-><clinit>()V
+HSPLandroidx/compose/ui/text/font/FontListFontFamilyTypefaceAdapter$special$$inlined$CoroutineExceptionHandler$1;-><init>()V
+HSPLandroidx/compose/ui/text/font/FontListFontFamilyTypefaceAdapter;-><clinit>()V
+HSPLandroidx/compose/ui/text/font/FontListFontFamilyTypefaceAdapter;-><init>(Landroidx/compose/ui/text/font/AsyncTypefaceCache;)V
+HSPLandroidx/compose/ui/text/font/FontStyle;-><init>(I)V
+HSPLandroidx/compose/ui/text/font/FontSynthesis;-><init>(I)V
+HSPLandroidx/compose/ui/text/font/FontWeight;-><clinit>()V
+HSPLandroidx/compose/ui/text/font/FontWeight;-><init>(I)V
+HSPLandroidx/compose/ui/text/font/FontWeight;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/text/font/PlatformResolveInterceptor$Companion;-><clinit>()V
+HSPLandroidx/compose/ui/text/font/PlatformResolveInterceptor;-><clinit>()V
+HSPLandroidx/compose/ui/text/font/TypefaceRequest;-><init>(Landroidx/compose/ui/text/font/FontFamily;Landroidx/compose/ui/text/font/FontWeight;IILjava/lang/Object;)V
+HSPLandroidx/compose/ui/text/font/TypefaceRequest;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/text/font/TypefaceRequest;->hashCode()I
+HSPLandroidx/compose/ui/text/font/TypefaceResult$Immutable;-><init>(Ljava/lang/Object;Z)V
+HSPLandroidx/compose/ui/text/input/InputMethodManagerImpl;-><init>(Landroid/view/View;)V
+HSPLandroidx/compose/ui/text/input/TextFieldValue;-><clinit>()V
+HSPLandroidx/compose/ui/text/input/TextFieldValue;-><init>(Landroidx/compose/ui/text/AnnotatedString;JLandroidx/compose/ui/text/TextRange;)V
+HSPLandroidx/compose/ui/text/input/TextInputService;-><init>()V
+HSPLandroidx/compose/ui/text/input/TextInputServiceAndroid;-><init>(Landroid/view/View;Landroidx/compose/ui/input/pointer/PositionCalculator;)V
+HSPLandroidx/compose/ui/text/input/TextInputServiceAndroid_androidKt$$ExternalSyntheticLambda0;-><init>(Ljava/lang/Runnable;I)V
+HSPLandroidx/compose/ui/text/input/TextInputServiceAndroid_androidKt$$ExternalSyntheticLambda0;->doFrame(J)V
+HSPLandroidx/compose/ui/text/intl/AndroidLocale;-><init>(Ljava/util/Locale;)V
+HSPLandroidx/compose/ui/text/intl/AndroidLocaleDelegateAPI24;-><init>()V
+HSPLandroidx/compose/ui/text/intl/AndroidLocaleDelegateAPI24;->getCurrent()Landroidx/compose/ui/text/intl/LocaleList;
+HSPLandroidx/compose/ui/text/intl/Locale;-><init>(Landroidx/compose/ui/text/intl/AndroidLocale;)V
+HSPLandroidx/compose/ui/text/intl/LocaleList;-><init>(Ljava/util/List;)V
+HSPLandroidx/compose/ui/text/intl/LocaleList;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/text/intl/PlatformLocaleKt;-><clinit>()V
+HSPLandroidx/compose/ui/text/platform/AndroidParagraphHelper_androidKt;-><clinit>()V
+HSPLandroidx/compose/ui/text/platform/AndroidParagraphIntrinsics$resolveTypeface$1;-><init>(Landroidx/compose/ui/text/platform/AndroidParagraphIntrinsics;)V
+HSPLandroidx/compose/ui/text/platform/AndroidParagraphIntrinsics;-><init>(Landroidx/compose/ui/text/TextStyle;Landroidx/compose/ui/text/font/FontFamily$Resolver;Landroidx/compose/ui/unit/Density;Ljava/lang/String;Ljava/util/List;Ljava/util/List;)V
+HSPLandroidx/compose/ui/text/platform/AndroidParagraphIntrinsics;->getHasStaleResolvedFonts()Z
+HSPLandroidx/compose/ui/text/platform/AndroidParagraphIntrinsics;->getMaxIntrinsicWidth()F
+HSPLandroidx/compose/ui/text/platform/AndroidTextPaint;-><init>(F)V
+HSPLandroidx/compose/ui/text/platform/AndroidTextPaint;->setBrush-12SF9DM(Landroidx/compose/ui/graphics/Brush;JF)V
+HSPLandroidx/compose/ui/text/platform/AndroidTextPaint;->setDrawStyle(Lkotlin/ResultKt;)V
+HSPLandroidx/compose/ui/text/platform/AndroidTextPaint;->setShadow(Landroidx/compose/ui/graphics/Shadow;)V
+HSPLandroidx/compose/ui/text/platform/AndroidTextPaint;->setTextDecoration(Landroidx/compose/ui/text/style/TextDecoration;)V
+HSPLandroidx/compose/ui/text/platform/DefaultImpl$getFontLoadState$initCallback$1;-><init>(Landroidx/compose/runtime/ParcelableSnapshotMutableState;Landroidx/compose/ui/text/platform/DefaultImpl;)V
+HSPLandroidx/compose/ui/text/platform/DefaultImpl;-><init>()V
+HSPLandroidx/compose/ui/text/platform/DefaultImpl;->getFontLoadState()Landroidx/compose/runtime/State;
+HSPLandroidx/compose/ui/text/platform/EmojiCompatStatus;-><clinit>()V
+HSPLandroidx/compose/ui/text/platform/ImmutableBool;-><init>(Z)V
+HSPLandroidx/compose/ui/text/platform/ImmutableBool;->getValue()Ljava/lang/Object;
+HSPLandroidx/compose/ui/text/platform/URLSpanCache;-><init>()V
+HSPLandroidx/compose/ui/text/platform/extensions/LocaleListHelperMethods;-><clinit>()V
+HSPLandroidx/compose/ui/text/style/BaselineShift;-><init>(F)V
+HSPLandroidx/compose/ui/text/style/ColorStyle;-><init>(J)V
+HSPLandroidx/compose/ui/text/style/ColorStyle;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/text/style/ColorStyle;->getAlpha()F
+HSPLandroidx/compose/ui/text/style/ColorStyle;->getBrush()Landroidx/compose/ui/graphics/Brush;
+HSPLandroidx/compose/ui/text/style/ColorStyle;->getColor-0d7_KjU()J
+HSPLandroidx/compose/ui/text/style/Hyphens;-><init>(I)V
+HSPLandroidx/compose/ui/text/style/Hyphens;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/text/style/LineBreak$Strategy;-><init>(I)V
+HSPLandroidx/compose/ui/text/style/LineBreak$Strictness;-><init>(I)V
+HSPLandroidx/compose/ui/text/style/LineBreak$WordBreak;-><init>(I)V
+HSPLandroidx/compose/ui/text/style/LineBreak;-><init>(I)V
+HSPLandroidx/compose/ui/text/style/LineBreak;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/text/style/LineHeightStyle$Alignment;-><clinit>()V
+HSPLandroidx/compose/ui/text/style/LineHeightStyle$Alignment;->constructor-impl(F)V
+HSPLandroidx/compose/ui/text/style/LineHeightStyle;-><clinit>()V
+HSPLandroidx/compose/ui/text/style/LineHeightStyle;-><init>(F)V
+HSPLandroidx/compose/ui/text/style/TextAlign;-><init>(I)V
+HSPLandroidx/compose/ui/text/style/TextAlign;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/text/style/TextDecoration;-><clinit>()V
+HSPLandroidx/compose/ui/text/style/TextDecoration;-><init>(I)V
+HSPLandroidx/compose/ui/text/style/TextDecoration;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/text/style/TextDirection;-><init>(I)V
+HSPLandroidx/compose/ui/text/style/TextDirection;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/text/style/TextForegroundStyle$Unspecified;-><clinit>()V
+HSPLandroidx/compose/ui/text/style/TextForegroundStyle$Unspecified;->getAlpha()F
+HSPLandroidx/compose/ui/text/style/TextForegroundStyle$Unspecified;->getBrush()Landroidx/compose/ui/graphics/Brush;
+HSPLandroidx/compose/ui/text/style/TextForegroundStyle$Unspecified;->getColor-0d7_KjU()J
+HSPLandroidx/compose/ui/text/style/TextGeometricTransform;-><clinit>()V
+HSPLandroidx/compose/ui/text/style/TextGeometricTransform;-><init>(FF)V
+HSPLandroidx/compose/ui/text/style/TextGeometricTransform;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/text/style/TextIndent;-><clinit>()V
+HSPLandroidx/compose/ui/text/style/TextIndent;-><init>(JJ)V
+HSPLandroidx/compose/ui/text/style/TextIndent;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/text/style/TextMotion;-><clinit>()V
+HSPLandroidx/compose/ui/text/style/TextMotion;-><init>(IZ)V
+HSPLandroidx/compose/ui/text/style/TextMotion;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/unit/Constraints;-><clinit>()V
+HSPLandroidx/compose/ui/unit/Constraints;-><init>(J)V
+HSPLandroidx/compose/ui/unit/Constraints;->copy-Zbe2FdA$default(JIIIII)J
+HSPLandroidx/compose/ui/unit/Constraints;->equals-impl0(JJ)Z
+HSPLandroidx/compose/ui/unit/Constraints;->getHasBoundedHeight-impl(J)Z
+HSPLandroidx/compose/ui/unit/Constraints;->getHasBoundedWidth-impl(J)Z
+HSPLandroidx/compose/ui/unit/Constraints;->getHasFixedHeight-impl(J)Z
+HSPLandroidx/compose/ui/unit/Constraints;->getHasFixedWidth-impl(J)Z
+HSPLandroidx/compose/ui/unit/Constraints;->getMaxHeight-impl(J)I
+HSPLandroidx/compose/ui/unit/Constraints;->getMaxWidth-impl(J)I
+HSPLandroidx/compose/ui/unit/Constraints;->getMinHeight-impl(J)I
+HSPLandroidx/compose/ui/unit/Constraints;->getMinWidth-impl(J)I
+HSPLandroidx/compose/ui/unit/Density;->roundToPx-0680j_4(F)I
+HSPLandroidx/compose/ui/unit/Density;->toDp-u2uoSUM(I)F
+HSPLandroidx/compose/ui/unit/Density;->toPx--R2X_6o(J)F
+HSPLandroidx/compose/ui/unit/Density;->toPx-0680j_4(F)F
+HSPLandroidx/compose/ui/unit/DensityImpl;-><init>(FF)V
+HSPLandroidx/compose/ui/unit/DensityImpl;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/unit/DensityImpl;->getDensity()F
+HSPLandroidx/compose/ui/unit/DensityImpl;->getFontScale()F
+HSPLandroidx/compose/ui/unit/Dp$Companion;-><clinit>()V
+HSPLandroidx/compose/ui/unit/Dp$Companion;-><init>(Landroid/content/Context;)V
+HSPLandroidx/compose/ui/unit/Dp$Companion;->access$getIsShowingLayoutBounds()Z
+HSPLandroidx/compose/ui/unit/Dp$Companion;->area([F)F
+HSPLandroidx/compose/ui/unit/Dp$Companion;->bitsNeedForSize(I)I
+HSPLandroidx/compose/ui/unit/Dp$Companion;->createAndroidTypefaceApi28-RetOiIg(Ljava/lang/String;Landroidx/compose/ui/text/font/FontWeight;I)Landroid/graphics/Typeface;
+HSPLandroidx/compose/ui/unit/Dp$Companion;->createConstraints-Zbe2FdA$ui_unit_release(IIII)J
+HSPLandroidx/compose/ui/unit/Dp$Companion;->fixed-JhjzzOo(II)J
+HSPLandroidx/compose/ui/unit/Dp$Companion;->observe(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;)Ljava/lang/Object;
+HSPLandroidx/compose/ui/unit/Dp;-><init>(F)V
+HSPLandroidx/compose/ui/unit/Dp;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/unit/Dp;->equals-impl0(FF)Z
+HSPLandroidx/compose/ui/unit/DpOffset;-><clinit>()V
+HSPLandroidx/compose/ui/unit/DpRect;-><init>(FFFF)V
+HSPLandroidx/compose/ui/unit/DpRect;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/compose/ui/unit/IntOffset;-><clinit>()V
+HSPLandroidx/compose/ui/unit/IntOffset;-><init>(J)V
+HSPLandroidx/compose/ui/unit/IntOffset;->getY-impl(J)I
+HSPLandroidx/compose/ui/unit/IntSize;-><init>(J)V
+HSPLandroidx/compose/ui/unit/IntSize;->equals-impl0(JJ)Z
+HSPLandroidx/compose/ui/unit/IntSize;->getHeight-impl(J)I
+HSPLandroidx/compose/ui/unit/LayoutDirection;-><clinit>()V
+HSPLandroidx/compose/ui/unit/LayoutDirection;-><init>(ILjava/lang/String;)V
+HSPLandroidx/compose/ui/unit/TextUnit;-><clinit>()V
+HSPLandroidx/compose/ui/unit/TextUnit;->equals-impl0(JJ)Z
+HSPLandroidx/compose/ui/unit/TextUnit;->getType-UIouoOA(J)J
+HSPLandroidx/compose/ui/unit/TextUnit;->getValue-impl(J)F
+HSPLandroidx/compose/ui/unit/TextUnitType;-><init>(J)V
+HSPLandroidx/compose/ui/unit/TextUnitType;->equals-impl0(JJ)Z
+HSPLandroidx/core/app/ComponentActivity;-><init>()V
+HSPLandroidx/core/app/ComponentActivity;->dispatchKeyEvent(Landroid/view/KeyEvent;)Z
+HSPLandroidx/core/app/ComponentActivity;->onCreate(Landroid/os/Bundle;)V
+HSPLandroidx/core/app/ComponentActivity;->superDispatchKeyEvent(Landroid/view/KeyEvent;)Z
+HSPLandroidx/core/app/CoreComponentFactory;-><init>()V
+HSPLandroidx/core/app/CoreComponentFactory;->instantiateActivity(Ljava/lang/ClassLoader;Ljava/lang/String;Landroid/content/Intent;)Landroid/app/Activity;
+HSPLandroidx/core/app/CoreComponentFactory;->instantiateApplication(Ljava/lang/ClassLoader;Ljava/lang/String;)Landroid/app/Application;
+HSPLandroidx/core/app/CoreComponentFactory;->instantiateProvider(Ljava/lang/ClassLoader;Ljava/lang/String;)Landroid/content/ContentProvider;
+HSPLandroidx/core/content/res/ComplexColorCompat;-><init>()V
+HSPLandroidx/core/content/res/ComplexColorCompat;-><init>(I)V
+HSPLandroidx/core/content/res/ComplexColorCompat;-><init>(Ljava/lang/Object;)V
+HSPLandroidx/core/content/res/ComplexColorCompat;->find(Ljava/lang/Object;)I
+HSPLandroidx/core/content/res/ComplexColorCompat;->get(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/core/content/res/ComplexColorCompat;->set(Ljava/lang/Object;Ljava/lang/Object;)V
+HSPLandroidx/core/graphics/TypefaceCompat;-><clinit>()V
+HSPLandroidx/core/graphics/TypefaceCompatApi29Impl;-><init>()V
+HSPLandroidx/core/graphics/TypefaceCompatApi29Impl;->createFromFontInfo(Landroid/content/Context;[Landroidx/core/provider/FontsContractCompat$FontInfo;I)Landroid/graphics/Typeface;
+HSPLandroidx/core/graphics/TypefaceCompatApi29Impl;->findBaseFont(Landroid/graphics/fonts/FontFamily;I)Landroid/graphics/fonts/Font;
+HSPLandroidx/core/graphics/TypefaceCompatApi29Impl;->getMatchScore(Landroid/graphics/fonts/FontStyle;Landroid/graphics/fonts/FontStyle;)I
+HSPLandroidx/core/graphics/TypefaceCompatUtil$Api19Impl;->openFileDescriptor(Landroid/content/ContentResolver;Landroid/net/Uri;Ljava/lang/String;Landroid/os/CancellationSignal;)Landroid/os/ParcelFileDescriptor;
+HSPLandroidx/core/os/BuildCompat$Extensions30Impl$$ExternalSyntheticApiModelOutline0;->m$1()I
+HSPLandroidx/core/os/BuildCompat$Extensions30Impl$$ExternalSyntheticApiModelOutline0;->m$2()I
+HSPLandroidx/core/os/BuildCompat$Extensions30Impl$$ExternalSyntheticApiModelOutline0;->m$3()I
+HSPLandroidx/core/os/BuildCompat$Extensions30Impl$$ExternalSyntheticApiModelOutline0;->m()I
+HSPLandroidx/core/os/BuildCompat$Extensions30Impl;-><clinit>()V
+HSPLandroidx/core/os/BuildCompat;-><clinit>()V
+HSPLandroidx/core/os/BuildCompat;->isAtLeastT()Z
+HSPLandroidx/core/os/TraceCompat$Api18Impl;->beginSection(Ljava/lang/String;)V
+HSPLandroidx/core/os/TraceCompat$Api18Impl;->endSection()V
+HSPLandroidx/core/os/TraceCompat;-><clinit>()V
+HSPLandroidx/core/provider/CallbackWithHandler$2;-><init>(ILjava/util/ArrayList;)V
+HSPLandroidx/core/provider/CallbackWithHandler$2;-><init>(Ljava/util/List;ILjava/lang/Throwable;)V
+HSPLandroidx/core/provider/CallbackWithHandler$2;->run()V
+HSPLandroidx/core/provider/FontProvider$Api16Impl;->query(Landroid/content/ContentResolver;Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;)Landroid/database/Cursor;
+HSPLandroidx/core/provider/FontRequest;-><init>(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;)V
+HSPLandroidx/core/provider/FontsContractCompat$FontInfo;-><init>(Landroid/net/Uri;IIZI)V
+HSPLandroidx/core/view/AccessibilityDelegateCompat$AccessibilityDelegateAdapter;-><init>(Landroidx/core/view/AccessibilityDelegateCompat;)V
+HSPLandroidx/core/view/AccessibilityDelegateCompat$AccessibilityDelegateAdapter;->dispatchPopulateAccessibilityEvent(Landroid/view/View;Landroid/view/accessibility/AccessibilityEvent;)Z
+HSPLandroidx/core/view/AccessibilityDelegateCompat$AccessibilityDelegateAdapter;->getAccessibilityNodeProvider(Landroid/view/View;)Landroid/view/accessibility/AccessibilityNodeProvider;
+HSPLandroidx/core/view/AccessibilityDelegateCompat$AccessibilityDelegateAdapter;->onInitializeAccessibilityEvent(Landroid/view/View;Landroid/view/accessibility/AccessibilityEvent;)V
+HSPLandroidx/core/view/AccessibilityDelegateCompat$AccessibilityDelegateAdapter;->onPopulateAccessibilityEvent(Landroid/view/View;Landroid/view/accessibility/AccessibilityEvent;)V
+HSPLandroidx/core/view/AccessibilityDelegateCompat$AccessibilityDelegateAdapter;->sendAccessibilityEvent(Landroid/view/View;I)V
+HSPLandroidx/core/view/AccessibilityDelegateCompat$AccessibilityDelegateAdapter;->sendAccessibilityEventUnchecked(Landroid/view/View;Landroid/view/accessibility/AccessibilityEvent;)V
+HSPLandroidx/core/view/AccessibilityDelegateCompat;-><clinit>()V
+HSPLandroidx/core/view/AccessibilityDelegateCompat;-><init>()V
+HSPLandroidx/core/view/MenuHostHelper;-><init>(Landroidx/activity/ComponentActivity$$ExternalSyntheticLambda0;)V
+HSPLandroidx/core/view/MenuHostHelper;-><init>(Ljava/lang/reflect/Method;Ljava/lang/reflect/Method;Ljava/lang/reflect/Method;)V
+HSPLandroidx/core/view/ViewCompat$$ExternalSyntheticLambda0;-><init>(I)V
+HSPLandroidx/core/view/ViewCompat$$ExternalSyntheticLambda0;->invoke(D)D
+HSPLandroidx/core/view/ViewCompat$Api29Impl;->getContentCaptureSession(Landroid/view/View;)Landroid/view/contentcapture/ContentCaptureSession;
+HSPLandroidx/core/view/ViewCompat$Api30Impl;->setImportantForContentCapture(Landroid/view/View;I)V
+HSPLandroidx/core/view/ViewCompat;-><clinit>()V
+HSPLandroidx/core/view/accessibility/AccessibilityNodeProviderCompat;-><init>(Ljava/lang/Object;)V
+HSPLandroidx/customview/poolingcontainer/PoolingContainerListenerHolder;-><init>()V
+HSPLandroidx/emoji2/text/ConcurrencyHelpers$$ExternalSyntheticLambda0;-><init>(Ljava/lang/String;)V
+HSPLandroidx/emoji2/text/ConcurrencyHelpers$$ExternalSyntheticLambda0;->newThread(Ljava/lang/Runnable;)Ljava/lang/Thread;
+HSPLandroidx/emoji2/text/ConcurrencyHelpers$Handler28Impl;->createAsync(Landroid/os/Looper;)Landroid/os/Handler;
+HSPLandroidx/emoji2/text/DefaultGlyphChecker;-><clinit>()V
+HSPLandroidx/emoji2/text/DefaultGlyphChecker;-><init>()V
+HSPLandroidx/emoji2/text/EmojiCompat$CompatInternal19$1;-><init>(Landroidx/emoji2/text/EmojiCompat$CompatInternal19;)V
+HSPLandroidx/emoji2/text/EmojiCompat$CompatInternal19$1;->onLoaded(Landroidx/emoji2/text/MetadataRepo;)V
+HSPLandroidx/emoji2/text/EmojiCompat$CompatInternal19;-><init>(Landroidx/emoji2/text/EmojiCompat;)V
+HSPLandroidx/emoji2/text/EmojiCompat$CompatInternal19;->process(Ljava/lang/CharSequence;IZ)Ljava/lang/CharSequence;
+HSPLandroidx/emoji2/text/EmojiCompat$Config;-><init>(Landroidx/emoji2/text/EmojiCompat$MetadataRepoLoader;)V
+HSPLandroidx/emoji2/text/EmojiCompat;-><clinit>()V
+HSPLandroidx/emoji2/text/EmojiCompat;-><init>(Landroidx/emoji2/text/FontRequestEmojiCompatConfig;)V
+HSPLandroidx/emoji2/text/EmojiCompat;->get()Landroidx/emoji2/text/EmojiCompat;
+HSPLandroidx/emoji2/text/EmojiCompat;->getLoadState()I
+HSPLandroidx/emoji2/text/EmojiCompat;->load()V
+HSPLandroidx/emoji2/text/EmojiCompat;->onMetadataLoadSuccess()V
+HSPLandroidx/emoji2/text/EmojiCompatInitializer$1;-><init>(Landroidx/emoji2/text/EmojiCompatInitializer;Landroidx/lifecycle/Lifecycle;)V
+HSPLandroidx/emoji2/text/EmojiCompatInitializer$1;->onResume(Landroidx/lifecycle/LifecycleOwner;)V
+HSPLandroidx/emoji2/text/EmojiCompatInitializer$BackgroundDefaultLoader$$ExternalSyntheticLambda0;-><init>(Landroidx/compose/runtime/Stack;Lokhttp3/MediaType;Ljava/util/concurrent/ThreadPoolExecutor;)V
+HSPLandroidx/emoji2/text/EmojiCompatInitializer$BackgroundDefaultLoader$$ExternalSyntheticLambda0;->run()V
+HSPLandroidx/emoji2/text/EmojiCompatInitializer$BackgroundDefaultLoader$1;-><init>(Lokhttp3/MediaType;Ljava/util/concurrent/ThreadPoolExecutor;)V
+HSPLandroidx/emoji2/text/EmojiCompatInitializer$BackgroundDefaultLoader$1;->onLoaded(Landroidx/emoji2/text/MetadataRepo;)V
+HSPLandroidx/emoji2/text/EmojiCompatInitializer$LoadEmojiCompatRunnable;->run()V
+HSPLandroidx/emoji2/text/EmojiCompatInitializer;-><init>()V
+HSPLandroidx/emoji2/text/EmojiCompatInitializer;->create(Landroid/content/Context;)Ljava/lang/Boolean;
+HSPLandroidx/emoji2/text/EmojiCompatInitializer;->create(Landroid/content/Context;)Ljava/lang/Object;
+HSPLandroidx/emoji2/text/EmojiCompatInitializer;->dependencies()Ljava/util/List;
+HSPLandroidx/emoji2/text/EmojiProcessor$EmojiProcessAddSpanCallback;-><init>(Landroidx/emoji2/text/UnprecomputeTextOnModificationSpannable;Lkotlin/ULong$Companion;)V
+HSPLandroidx/emoji2/text/EmojiProcessor$EmojiProcessAddSpanCallback;->getResult()Ljava/lang/Object;
+HSPLandroidx/emoji2/text/EmojiProcessor$ProcessorSm;-><init>(Landroidx/emoji2/text/MetadataRepo$Node;Z[I)V
+HSPLandroidx/emoji2/text/EmojiProcessor$ProcessorSm;->shouldUseEmojiPresentationStyleForSingleCodepoint()Z
+HSPLandroidx/emoji2/text/EmojiProcessor;-><init>(Landroidx/compose/ui/node/LayoutNode;)V
+HSPLandroidx/emoji2/text/EmojiProcessor;-><init>(Landroidx/emoji2/text/MetadataRepo;Lkotlin/ULong$Companion;Landroidx/emoji2/text/DefaultGlyphChecker;Ljava/util/Set;)V
+HSPLandroidx/emoji2/text/EmojiProcessor;->process(Ljava/lang/String;IIIZLandroidx/emoji2/text/EmojiProcessor$EmojiProcessCallback;)Ljava/lang/Object;
+HSPLandroidx/emoji2/text/FontRequestEmojiCompatConfig$FontRequestMetadataLoader$$ExternalSyntheticLambda0;-><init>(Landroidx/emoji2/text/FontRequestEmojiCompatConfig$FontRequestMetadataLoader;I)V
+HSPLandroidx/emoji2/text/FontRequestEmojiCompatConfig$FontRequestMetadataLoader$$ExternalSyntheticLambda0;->run()V
+HSPLandroidx/emoji2/text/FontRequestEmojiCompatConfig$FontRequestMetadataLoader$1;-><init>(Lkotlinx/coroutines/channels/BufferedChannel;Landroid/os/Handler;I)V
+HSPLandroidx/emoji2/text/FontRequestEmojiCompatConfig$FontRequestMetadataLoader;-><init>(Landroid/content/Context;Landroidx/core/provider/FontRequest;)V
+HSPLandroidx/emoji2/text/FontRequestEmojiCompatConfig$FontRequestMetadataLoader;->cleanUp()V
+HSPLandroidx/emoji2/text/FontRequestEmojiCompatConfig$FontRequestMetadataLoader;->load(Lokhttp3/MediaType;)V
+HSPLandroidx/emoji2/text/FontRequestEmojiCompatConfig$FontRequestMetadataLoader;->loadInternal()V
+HSPLandroidx/emoji2/text/FontRequestEmojiCompatConfig$FontRequestMetadataLoader;->retrieveFontInfo()Landroidx/core/provider/FontsContractCompat$FontInfo;
+HSPLandroidx/emoji2/text/FontRequestEmojiCompatConfig;-><clinit>()V
+HSPLandroidx/emoji2/text/FontRequestEmojiCompatConfig;-><init>(Landroid/content/Context;)V
+HSPLandroidx/emoji2/text/FontRequestEmojiCompatConfig;-><init>(Landroid/content/Context;Landroidx/core/provider/FontRequest;)V
+HSPLandroidx/emoji2/text/MetadataRepo$Node;-><init>(I)V
+HSPLandroidx/emoji2/text/MetadataRepo$Node;->put(Landroidx/emoji2/text/TypefaceEmojiRasterizer;II)V
+HSPLandroidx/emoji2/text/MetadataRepo;-><init>(Landroid/graphics/Typeface;Landroidx/emoji2/text/flatbuffer/MetadataList;)V
+HSPLandroidx/emoji2/text/TypefaceEmojiRasterizer;-><clinit>()V
+HSPLandroidx/emoji2/text/TypefaceEmojiRasterizer;-><init>(Landroidx/emoji2/text/MetadataRepo;I)V
+HSPLandroidx/emoji2/text/TypefaceEmojiRasterizer;->getCodepointAt(I)I
+HSPLandroidx/emoji2/text/TypefaceEmojiRasterizer;->getCodepointsLength()I
+HSPLandroidx/emoji2/text/TypefaceEmojiRasterizer;->getMetadataItem()Landroidx/emoji2/text/flatbuffer/MetadataItem;
+HSPLandroidx/emoji2/text/flatbuffer/Table;-><init>()V
+HSPLandroidx/emoji2/text/flatbuffer/Table;->__offset(I)I
+HSPLandroidx/lifecycle/DefaultLifecycleObserver;->onResume(Landroidx/lifecycle/LifecycleOwner;)V
+HSPLandroidx/lifecycle/DefaultLifecycleObserver;->onStart(Landroidx/lifecycle/LifecycleOwner;)V
+HSPLandroidx/lifecycle/DefaultLifecycleObserverAdapter$WhenMappings;-><clinit>()V
+HSPLandroidx/lifecycle/DefaultLifecycleObserverAdapter;-><init>(Landroidx/lifecycle/DefaultLifecycleObserver;Landroidx/lifecycle/LifecycleEventObserver;)V
+HSPLandroidx/lifecycle/DefaultLifecycleObserverAdapter;->onStateChanged(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V
+HSPLandroidx/lifecycle/EmptyActivityLifecycleCallbacks;->onActivityCreated(Landroid/app/Activity;Landroid/os/Bundle;)V
+HSPLandroidx/lifecycle/EmptyActivityLifecycleCallbacks;->onActivityResumed(Landroid/app/Activity;)V
+HSPLandroidx/lifecycle/EmptyActivityLifecycleCallbacks;->onActivityStarted(Landroid/app/Activity;)V
+HSPLandroidx/lifecycle/Lifecycle$Event$Companion;->upFrom(Landroidx/lifecycle/Lifecycle$State;)Landroidx/lifecycle/Lifecycle$Event;
+HSPLandroidx/lifecycle/Lifecycle$Event$WhenMappings;-><clinit>()V
+HSPLandroidx/lifecycle/Lifecycle$Event;-><clinit>()V
+HSPLandroidx/lifecycle/Lifecycle$Event;-><init>(ILjava/lang/String;)V
+HSPLandroidx/lifecycle/Lifecycle$Event;->getTargetState()Landroidx/lifecycle/Lifecycle$State;
+HSPLandroidx/lifecycle/Lifecycle$Event;->values()[Landroidx/lifecycle/Lifecycle$Event;
+HSPLandroidx/lifecycle/Lifecycle$State;-><clinit>()V
+HSPLandroidx/lifecycle/Lifecycle$State;-><init>(ILjava/lang/String;)V
+HSPLandroidx/lifecycle/Lifecycle;-><init>()V
+HSPLandroidx/lifecycle/LifecycleDestroyedException;-><init>(I)V
+HSPLandroidx/lifecycle/LifecycleDestroyedException;-><init>(II)V
+HSPLandroidx/lifecycle/LifecycleDestroyedException;->fillInStackTrace()Ljava/lang/Throwable;
+HSPLandroidx/lifecycle/LifecycleDispatcher$DispatcherActivityCallback;-><init>()V
+HSPLandroidx/lifecycle/LifecycleDispatcher$DispatcherActivityCallback;->onActivityCreated(Landroid/app/Activity;Landroid/os/Bundle;)V
+HSPLandroidx/lifecycle/LifecycleDispatcher;-><clinit>()V
+HSPLandroidx/lifecycle/LifecycleRegistry$ObserverWithState;-><init>(Landroidx/lifecycle/LifecycleObserver;Landroidx/lifecycle/Lifecycle$State;)V
+HSPLandroidx/lifecycle/LifecycleRegistry$ObserverWithState;->dispatchEvent(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V
+HSPLandroidx/lifecycle/LifecycleRegistry;-><init>(Landroidx/lifecycle/LifecycleOwner;)V
+HSPLandroidx/lifecycle/LifecycleRegistry;->addObserver(Landroidx/lifecycle/LifecycleObserver;)V
+HSPLandroidx/lifecycle/LifecycleRegistry;->calculateTargetState(Landroidx/lifecycle/LifecycleObserver;)Landroidx/lifecycle/Lifecycle$State;
+HSPLandroidx/lifecycle/LifecycleRegistry;->enforceMainThreadIfNeeded(Ljava/lang/String;)V
+HSPLandroidx/lifecycle/LifecycleRegistry;->handleLifecycleEvent(Landroidx/lifecycle/Lifecycle$Event;)V
+HSPLandroidx/lifecycle/LifecycleRegistry;->moveToState(Landroidx/lifecycle/Lifecycle$State;)V
+HSPLandroidx/lifecycle/LifecycleRegistry;->removeObserver(Landroidx/lifecycle/LifecycleObserver;)V
+HSPLandroidx/lifecycle/LifecycleRegistry;->sync()V
+HSPLandroidx/lifecycle/Lifecycling;-><clinit>()V
+HSPLandroidx/lifecycle/ProcessLifecycleInitializer;-><init>()V
+HSPLandroidx/lifecycle/ProcessLifecycleInitializer;->create(Landroid/content/Context;)Ljava/lang/Object;
+HSPLandroidx/lifecycle/ProcessLifecycleInitializer;->dependencies()Ljava/util/List;
+HSPLandroidx/lifecycle/ProcessLifecycleOwner$Api29Impl;->registerActivityLifecycleCallbacks(Landroid/app/Activity;Landroid/app/Application$ActivityLifecycleCallbacks;)V
+HSPLandroidx/lifecycle/ProcessLifecycleOwner$attach$1$onActivityPreCreated$1;-><init>(Landroidx/lifecycle/ProcessLifecycleOwner;)V
+HSPLandroidx/lifecycle/ProcessLifecycleOwner$attach$1$onActivityPreCreated$1;->onActivityPostResumed(Landroid/app/Activity;)V
+HSPLandroidx/lifecycle/ProcessLifecycleOwner$attach$1$onActivityPreCreated$1;->onActivityPostStarted(Landroid/app/Activity;)V
+HSPLandroidx/lifecycle/ProcessLifecycleOwner$attach$1;-><init>(Landroidx/lifecycle/ProcessLifecycleOwner;)V
+HSPLandroidx/lifecycle/ProcessLifecycleOwner$attach$1;->onActivityCreated(Landroid/app/Activity;Landroid/os/Bundle;)V
+HSPLandroidx/lifecycle/ProcessLifecycleOwner$attach$1;->onActivityPreCreated(Landroid/app/Activity;Landroid/os/Bundle;)V
+HSPLandroidx/lifecycle/ProcessLifecycleOwner$initializationListener$1;-><init>(Landroidx/lifecycle/ProcessLifecycleOwner;)V
+HSPLandroidx/lifecycle/ProcessLifecycleOwner;-><clinit>()V
+HSPLandroidx/lifecycle/ProcessLifecycleOwner;-><init>()V
+HSPLandroidx/lifecycle/ProcessLifecycleOwner;->activityResumed$lifecycle_process_release()V
+HSPLandroidx/lifecycle/ProcessLifecycleOwner;->getLifecycle()Landroidx/lifecycle/LifecycleRegistry;
+HSPLandroidx/lifecycle/ReportFragment$LifecycleCallbacks;-><clinit>()V
+HSPLandroidx/lifecycle/ReportFragment$LifecycleCallbacks;-><init>()V
+HSPLandroidx/lifecycle/ReportFragment$LifecycleCallbacks;->onActivityCreated(Landroid/app/Activity;Landroid/os/Bundle;)V
+HSPLandroidx/lifecycle/ReportFragment$LifecycleCallbacks;->onActivityPostCreated(Landroid/app/Activity;Landroid/os/Bundle;)V
+HSPLandroidx/lifecycle/ReportFragment$LifecycleCallbacks;->onActivityPostResumed(Landroid/app/Activity;)V
+HSPLandroidx/lifecycle/ReportFragment$LifecycleCallbacks;->onActivityPostStarted(Landroid/app/Activity;)V
+HSPLandroidx/lifecycle/ReportFragment$LifecycleCallbacks;->onActivityResumed(Landroid/app/Activity;)V
+HSPLandroidx/lifecycle/ReportFragment$LifecycleCallbacks;->onActivityStarted(Landroid/app/Activity;)V
+HSPLandroidx/lifecycle/ReportFragment;-><init>()V
+HSPLandroidx/lifecycle/ReportFragment;->dispatch(Landroidx/lifecycle/Lifecycle$Event;)V
+HSPLandroidx/lifecycle/ReportFragment;->onActivityCreated(Landroid/os/Bundle;)V
+HSPLandroidx/lifecycle/ReportFragment;->onResume()V
+HSPLandroidx/lifecycle/ReportFragment;->onStart()V
+HSPLandroidx/lifecycle/SavedStateHandleAttacher;-><init>(Landroidx/lifecycle/SavedStateHandlesProvider;)V
+HSPLandroidx/lifecycle/SavedStateHandleAttacher;->onStateChanged(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V
+HSPLandroidx/lifecycle/SavedStateHandlesProvider;-><init>(Landroidx/savedstate/SavedStateRegistry;Landroidx/lifecycle/ViewModelStoreOwner;)V
+HSPLandroidx/lifecycle/SavedStateHandlesVM;-><init>()V
+HSPLandroidx/lifecycle/ViewModelStore;-><init>()V
+HSPLandroidx/lifecycle/viewmodel/CreationExtras$Empty;-><clinit>()V
+HSPLandroidx/lifecycle/viewmodel/CreationExtras;-><init>()V
+HSPLandroidx/lifecycle/viewmodel/MutableCreationExtras;-><init>(Landroidx/lifecycle/viewmodel/CreationExtras;)V
+HSPLandroidx/lifecycle/viewmodel/ViewModelInitializer;-><init>(Ljava/lang/Class;)V
+HSPLandroidx/metrics/performance/DelegatingFrameMetricsListener;-><init>(Ljava/util/ArrayList;)V
+HSPLandroidx/metrics/performance/DelegatingFrameMetricsListener;->onFrameMetricsAvailable(Landroid/view/Window;Landroid/view/FrameMetrics;I)V
+HSPLandroidx/metrics/performance/FrameData;-><init>(JJZLjava/util/ArrayList;)V
+HSPLandroidx/metrics/performance/FrameDataApi24;-><init>(JJJZLjava/util/ArrayList;)V
+HSPLandroidx/metrics/performance/FrameDataApi31;-><init>(JJJJZLjava/util/ArrayList;)V
+HSPLandroidx/metrics/performance/FrameDataApi31;->copy()Landroidx/metrics/performance/FrameData;
+HSPLandroidx/metrics/performance/JankStats;-><init>(Landroid/view/Window;Lcom/example/tvcomposebasedtests/JankStatsAggregator$listener$1;)V
+HSPLandroidx/metrics/performance/JankStats;->logFrameData$metrics_performance_release(Landroidx/metrics/performance/FrameData;)V
+HSPLandroidx/metrics/performance/JankStatsApi16Impl;-><init>(Landroidx/metrics/performance/JankStats;Landroid/view/View;)V
+HSPLandroidx/metrics/performance/JankStatsApi22Impl;-><init>(Landroidx/metrics/performance/JankStats;Landroid/view/View;)V
+HSPLandroidx/metrics/performance/JankStatsApi24Impl$$ExternalSyntheticLambda0;-><init>(Landroidx/metrics/performance/JankStatsApi24Impl;Landroidx/metrics/performance/JankStats;)V
+HSPLandroidx/metrics/performance/JankStatsApi24Impl$$ExternalSyntheticLambda0;->onFrameMetricsAvailable(Landroid/view/Window;Landroid/view/FrameMetrics;I)V
+HSPLandroidx/metrics/performance/JankStatsApi24Impl;-><init>(Landroidx/metrics/performance/JankStats;Landroid/view/View;Landroid/view/Window;)V
+HSPLandroidx/metrics/performance/JankStatsApi24Impl;->getOrCreateFrameMetricsListenerDelegator(Landroid/view/Window;)Landroidx/metrics/performance/DelegatingFrameMetricsListener;
+HSPLandroidx/metrics/performance/JankStatsApi24Impl;->setupFrameTimer(Z)V
+HSPLandroidx/metrics/performance/JankStatsApi26Impl;-><init>(Landroidx/metrics/performance/JankStats;Landroid/view/View;Landroid/view/Window;)V
+HSPLandroidx/metrics/performance/JankStatsApi26Impl;->getFrameStartTime$metrics_performance_release(Landroid/view/FrameMetrics;)J
+HSPLandroidx/metrics/performance/JankStatsApi31Impl;-><init>(Landroidx/metrics/performance/JankStats;Landroid/view/View;Landroid/view/Window;)V
+HSPLandroidx/metrics/performance/JankStatsApi31Impl;->getExpectedFrameDuration(Landroid/view/FrameMetrics;)J
+HSPLandroidx/metrics/performance/JankStatsApi31Impl;->getFrameData$metrics_performance_release(JJLandroid/view/FrameMetrics;)Landroidx/metrics/performance/FrameDataApi24;
+HSPLandroidx/metrics/performance/PerformanceMetricsState;-><init>()V
+HSPLandroidx/metrics/performance/PerformanceMetricsState;->addFrameState(JJLjava/util/ArrayList;Ljava/util/ArrayList;)V
+HSPLandroidx/metrics/performance/PerformanceMetricsState;->cleanupSingleFrameStates$metrics_performance_release()V
+HSPLandroidx/metrics/performance/PerformanceMetricsState;->getIntervalStates$metrics_performance_release(JJLjava/util/ArrayList;)V
+HSPLandroidx/profileinstaller/ProfileInstallerInitializer$$ExternalSyntheticLambda0;-><init>(Ljava/lang/Object;ILjava/lang/Object;)V
+HSPLandroidx/profileinstaller/ProfileInstallerInitializer$$ExternalSyntheticLambda0;->run()V
+HSPLandroidx/profileinstaller/ProfileInstallerInitializer$$ExternalSyntheticLambda1;-><init>(Landroid/content/Context;I)V
+HSPLandroidx/profileinstaller/ProfileInstallerInitializer$Choreographer16Impl;->postFrameCallback(Ljava/lang/Runnable;)V
+HSPLandroidx/profileinstaller/ProfileInstallerInitializer$Handler28Impl;->createAsync(Landroid/os/Looper;)Landroid/os/Handler;
+HSPLandroidx/profileinstaller/ProfileInstallerInitializer;-><init>()V
+HSPLandroidx/profileinstaller/ProfileInstallerInitializer;->create(Landroid/content/Context;)Ljava/lang/Object;
+HSPLandroidx/profileinstaller/ProfileInstallerInitializer;->dependencies()Ljava/util/List;
+HSPLandroidx/savedstate/Recreator;-><init>(Landroidx/savedstate/SavedStateRegistryOwner;)V
+HSPLandroidx/savedstate/Recreator;->onStateChanged(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V
+HSPLandroidx/savedstate/SavedStateRegistry$$ExternalSyntheticLambda0;-><init>(Landroidx/savedstate/SavedStateRegistry;)V
+HSPLandroidx/savedstate/SavedStateRegistry$$ExternalSyntheticLambda0;->onStateChanged(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V
+HSPLandroidx/savedstate/SavedStateRegistry;-><init>()V
+HSPLandroidx/savedstate/SavedStateRegistry;->consumeRestoredStateForKey(Ljava/lang/String;)Landroid/os/Bundle;
+HSPLandroidx/savedstate/SavedStateRegistry;->registerSavedStateProvider(Ljava/lang/String;Landroidx/savedstate/SavedStateRegistry$SavedStateProvider;)V
+HSPLandroidx/savedstate/SavedStateRegistryController;-><init>(Landroidx/savedstate/SavedStateRegistryOwner;)V
+HSPLandroidx/savedstate/SavedStateRegistryController;->performAttach()V
+HSPLandroidx/startup/AppInitializer;-><clinit>()V
+HSPLandroidx/startup/AppInitializer;-><init>(Landroid/content/Context;)V
+HSPLandroidx/startup/AppInitializer;->discoverAndInitialize(Landroid/os/Bundle;)V
+HSPLandroidx/startup/AppInitializer;->doInitialize(Ljava/lang/Class;Ljava/util/HashSet;)Ljava/lang/Object;
+HSPLandroidx/startup/AppInitializer;->getInstance(Landroid/content/Context;)Landroidx/startup/AppInitializer;
+HSPLandroidx/startup/InitializationProvider;-><init>()V
+HSPLandroidx/startup/InitializationProvider;->onCreate()Z
+HSPLandroidx/tracing/Trace$$ExternalSyntheticApiModelOutline0;->m()Z
+HSPLandroidx/tracing/Trace$$ExternalSyntheticApiModelOutline0;->m(Landroid/app/Activity;Landroidx/lifecycle/ReportFragment$LifecycleCallbacks;)V
+HSPLandroidx/tv/foundation/PivotOffsets;-><init>()V
+HSPLandroidx/tv/foundation/TvBringIntoViewSpec;-><init>(Landroidx/tv/foundation/PivotOffsets;Z)V
+HSPLandroidx/tv/foundation/TvBringIntoViewSpec;->calculateScrollDistance(FFF)F
+HSPLandroidx/tv/foundation/TvBringIntoViewSpec;->getScrollAnimationSpec()Landroidx/compose/animation/core/AnimationSpec;
+HSPLandroidx/tv/foundation/lazy/grid/LazyGridItemPlacementAnimator;-><init>(I)V
+HSPLandroidx/tv/foundation/lazy/grid/LazyGridItemPlacementAnimator;->reset()V
+HSPLandroidx/tv/foundation/lazy/grid/LazyGridKt$rememberLazyGridMeasurePolicy$1$1$3;-><init>(Landroidx/compose/foundation/lazy/layout/LazyLayoutMeasureScopeImpl;JIII)V
+HSPLandroidx/tv/foundation/lazy/grid/LazyGridKt$rememberLazyGridMeasurePolicy$1$1$3;->invoke(IILkotlin/jvm/functions/Function1;)Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/tv/foundation/lazy/grid/LazyGridKt$rememberLazyGridMeasurePolicy$1$1$3;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/tv/foundation/lazy/grid/LazyGridScrollPosition;-><init>(III)V
+HSPLandroidx/tv/foundation/lazy/grid/LazyGridScrollPosition;->getIndex()I
+HSPLandroidx/tv/foundation/lazy/grid/LazyGridScrollPosition;->setIndex(I)V
+HSPLandroidx/tv/foundation/lazy/grid/LazyGridScrollPosition;->update(II)V
+HSPLandroidx/tv/foundation/lazy/grid/TvLazyGridState$remeasurementModifier$1;-><init>(Landroidx/compose/foundation/gestures/ScrollableState;I)V
+HSPLandroidx/tv/foundation/lazy/layout/AwaitFirstLayoutModifier$waitForFirstLayout$1;-><init>(Landroidx/tv/foundation/lazy/layout/AwaitFirstLayoutModifier;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/tv/foundation/lazy/layout/AwaitFirstLayoutModifier;->waitForFirstLayout(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/tv/foundation/lazy/layout/LazyLayoutNearestRangeState;-><clinit>()V
+HSPLandroidx/tv/foundation/lazy/layout/LazyLayoutNearestRangeState;-><init>(III)V
+HSPLandroidx/tv/foundation/lazy/layout/LazyLayoutNearestRangeState;->getValue()Ljava/lang/Object;
+HSPLandroidx/tv/foundation/lazy/layout/LazyLayoutNearestRangeState;->update(I)V
+HSPLandroidx/tv/foundation/lazy/layout/LazyLayoutSemanticsKt$LazyLayoutSemanticState$1;-><init>(Landroidx/tv/foundation/lazy/list/TvLazyListState;Z)V
+HSPLandroidx/tv/foundation/lazy/layout/LazyLayoutSemanticsKt$LazyLayoutSemanticState$1;->collectionInfo()Landroidx/compose/ui/semantics/CollectionInfo;
+HSPLandroidx/tv/foundation/lazy/layout/LazyLayoutSemanticsKt$lazyLayoutSemantics$1$1;-><init>(Landroidx/tv/material3/TabKt$Tab$3$1;ZLandroidx/compose/ui/semantics/ScrollAxisRange;Landroidx/compose/foundation/ScrollKt$scroll$2$semantics$1$1;Landroidx/compose/foundation/layout/OffsetNode$measure$1;Landroidx/compose/ui/semantics/CollectionInfo;)V
+HSPLandroidx/tv/foundation/lazy/layout/NearestRangeKeyIndexMap$2$1;-><init>(IILjava/util/HashMap;Landroidx/tv/foundation/lazy/layout/NearestRangeKeyIndexMap;)V
+HSPLandroidx/tv/foundation/lazy/layout/NearestRangeKeyIndexMap$2$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/tv/foundation/lazy/layout/NearestRangeKeyIndexMap;-><init>(Lkotlin/ranges/IntRange;Landroidx/tv/material3/TabKt;)V
+HSPLandroidx/tv/foundation/lazy/layout/NearestRangeKeyIndexMap;->getKey(I)Ljava/lang/Object;
+HSPLandroidx/tv/foundation/lazy/list/EmptyLazyListLayoutInfo;-><clinit>()V
+HSPLandroidx/tv/foundation/lazy/list/LazyLayoutBeyondBoundsModifierLocal;-><clinit>()V
+HSPLandroidx/tv/foundation/lazy/list/LazyLayoutBeyondBoundsModifierLocal;-><init>(Landroidx/tv/foundation/lazy/list/LazyLayoutBeyondBoundsState;Landroidx/compose/runtime/Stack;ZLandroidx/compose/ui/unit/LayoutDirection;Landroidx/compose/foundation/gestures/Orientation;)V
+HSPLandroidx/tv/foundation/lazy/list/LazyLayoutBeyondBoundsModifierLocal;->getKey()Landroidx/compose/ui/modifier/ProvidableModifierLocal;
+HSPLandroidx/tv/foundation/lazy/list/LazyListBeyondBoundsState;-><init>(Landroidx/tv/foundation/lazy/list/TvLazyListState;I)V
+HSPLandroidx/tv/foundation/lazy/list/LazyListItemProviderImpl;-><init>(Landroidx/tv/foundation/lazy/list/TvLazyListState;Landroidx/tv/foundation/lazy/list/TvLazyListIntervalContent;Landroidx/tv/foundation/lazy/list/TvLazyListItemScopeImpl;Landroidx/tv/foundation/lazy/layout/NearestRangeKeyIndexMap;)V
+HSPLandroidx/tv/foundation/lazy/list/LazyListItemProviderImpl;->Item(ILjava/lang/Object;Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/tv/foundation/lazy/list/LazyListItemProviderImpl;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/tv/foundation/lazy/list/LazyListItemProviderImpl;->getContentType(I)Ljava/lang/Object;
+HSPLandroidx/tv/foundation/lazy/list/LazyListItemProviderImpl;->getItemCount()I
+HSPLandroidx/tv/foundation/lazy/list/LazyListItemProviderImpl;->getKey(I)Ljava/lang/Object;
+HSPLandroidx/tv/foundation/lazy/list/LazyListKt$rememberLazyListMeasurePolicy$1$1$measuredItemProvider$1;-><init>(JZLandroidx/tv/foundation/lazy/list/LazyListItemProviderImpl;Landroidx/compose/foundation/lazy/layout/LazyLayoutMeasureScopeImpl;IILandroidx/compose/ui/Alignment$Horizontal;Landroidx/compose/ui/Alignment$Vertical;ZIIJ)V
+HSPLandroidx/tv/foundation/lazy/list/LazyListKt$rememberLazyListMeasurePolicy$1$1$measuredItemProvider$1;->getAndMeasure(I)Landroidx/tv/foundation/lazy/list/LazyListMeasuredItem;
+HSPLandroidx/tv/foundation/lazy/list/LazyListKt$rememberLazyListMeasurePolicy$1$1;-><init>(Landroidx/tv/foundation/lazy/list/TvLazyListState;ZLandroidx/compose/foundation/layout/PaddingValuesImpl;ZLkotlin/reflect/KProperty0;Landroidx/compose/foundation/layout/Arrangement$Vertical;Landroidx/compose/foundation/layout/Arrangement$Horizontal;ILandroidx/compose/ui/Alignment$Horizontal;Landroidx/compose/ui/Alignment$Vertical;)V
+HSPLandroidx/tv/foundation/lazy/list/LazyListKt$rememberLazyListMeasurePolicy$1$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/tv/foundation/lazy/list/LazyListMeasureResult;-><init>(Landroidx/tv/foundation/lazy/list/LazyListMeasuredItem;IZFLandroidx/compose/ui/layout/MeasureResult;FLjava/util/List;II)V
+HSPLandroidx/tv/foundation/lazy/list/LazyListMeasureResult;->getAlignmentLines()Ljava/util/Map;
+HSPLandroidx/tv/foundation/lazy/list/LazyListMeasureResult;->getHeight()I
+HSPLandroidx/tv/foundation/lazy/list/LazyListMeasureResult;->getTotalItemsCount()I
+HSPLandroidx/tv/foundation/lazy/list/LazyListMeasureResult;->getVisibleItemsInfo()Ljava/util/List;
+HSPLandroidx/tv/foundation/lazy/list/LazyListMeasureResult;->getWidth()I
+HSPLandroidx/tv/foundation/lazy/list/LazyListMeasureResult;->placeChildren()V
+HSPLandroidx/tv/foundation/lazy/list/LazyListMeasuredItem;-><init>(ILjava/util/List;ZLandroidx/compose/ui/Alignment$Horizontal;Landroidx/compose/ui/Alignment$Vertical;Landroidx/compose/ui/unit/LayoutDirection;ZIIIJLjava/lang/Object;Ljava/lang/Object;)V
+HSPLandroidx/tv/foundation/lazy/list/LazyListMeasuredItem;->getParentData(I)V
+HSPLandroidx/tv/foundation/lazy/list/LazyListMeasuredItem;->place(Landroidx/compose/ui/layout/Placeable$PlacementScope;)V
+HSPLandroidx/tv/foundation/lazy/list/LazyListMeasuredItem;->position(III)V
+HSPLandroidx/tv/foundation/lazy/list/LazyListStateKt$rememberTvLazyListState$1$1;-><init>(III)V
+HSPLandroidx/tv/foundation/lazy/list/LazyListStateKt$rememberTvLazyListState$1$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/tv/foundation/lazy/list/LazyListStateKt;-><clinit>()V
+HSPLandroidx/tv/foundation/lazy/list/LazyListStateKt;->rememberTvLazyListState(Landroidx/compose/runtime/Composer;)Landroidx/tv/foundation/lazy/list/TvLazyListState;
+HSPLandroidx/tv/foundation/lazy/list/TvLazyListInterval;-><init>(Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/internal/ComposableLambdaImpl;)V
+HSPLandroidx/tv/foundation/lazy/list/TvLazyListInterval;->getKey()Lkotlin/jvm/functions/Function1;
+HSPLandroidx/tv/foundation/lazy/list/TvLazyListInterval;->getType()Lkotlin/jvm/functions/Function1;
+HSPLandroidx/tv/foundation/lazy/list/TvLazyListIntervalContent;-><init>(Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/tv/foundation/lazy/list/TvLazyListIntervalContent;->getIntervals()Landroidx/compose/foundation/lazy/layout/MutableIntervalList;
+HSPLandroidx/tv/foundation/lazy/list/TvLazyListItemScopeImpl;-><init>()V
+HSPLandroidx/tv/foundation/lazy/list/TvLazyListScope;->items$default(Landroidx/tv/foundation/lazy/list/TvLazyListScope;ILandroidx/compose/runtime/internal/ComposableLambdaImpl;)V
+HSPLandroidx/tv/foundation/lazy/list/TvLazyListState$scroll$1;-><init>(Landroidx/tv/foundation/lazy/list/TvLazyListState;Lkotlin/coroutines/Continuation;)V
+HSPLandroidx/tv/foundation/lazy/list/TvLazyListState$scroll$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/tv/foundation/lazy/list/TvLazyListState;-><clinit>()V
+HSPLandroidx/tv/foundation/lazy/list/TvLazyListState;-><init>(II)V
+HSPLandroidx/tv/foundation/lazy/list/TvLazyListState;->applyMeasureResult$tv_foundation_release(Landroidx/tv/foundation/lazy/list/LazyListMeasureResult;Z)V
+HSPLandroidx/tv/foundation/lazy/list/TvLazyListState;->getCanScrollBackward()Z
+HSPLandroidx/tv/foundation/lazy/list/TvLazyListState;->getCanScrollForward()Z
+HSPLandroidx/tv/foundation/lazy/list/TvLazyListState;->scroll(Landroidx/compose/foundation/MutatePriority;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/tv/material3/Border;-><clinit>()V
+HSPLandroidx/tv/material3/Border;-><init>(Landroidx/compose/foundation/BorderStroke;FLandroidx/compose/ui/graphics/Shape;)V
+HSPLandroidx/tv/material3/Border;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/tv/material3/ColorScheme;-><init>(JJJJJJJJJJJJJJJJJJJJJJJJJJJJJ)V
+HSPLandroidx/tv/material3/ColorScheme;->getInverseSurface-0d7_KjU()J
+HSPLandroidx/tv/material3/ColorScheme;->getOnSurface-0d7_KjU()J
+HSPLandroidx/tv/material3/ColorScheme;->getSurface-0d7_KjU()J
+HSPLandroidx/tv/material3/ColorSchemeKt$LocalColorScheme$1;-><clinit>()V
+HSPLandroidx/tv/material3/ColorSchemeKt$LocalColorScheme$1;-><init>(I)V
+HSPLandroidx/tv/material3/ColorSchemeKt$LocalColorScheme$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/tv/material3/ColorSchemeKt;-><clinit>()V
+HSPLandroidx/tv/material3/ColorSchemeKt;->contentColorFor-ek8zF_U(JLandroidx/compose/runtime/Composer;)J
+HSPLandroidx/tv/material3/ContentColorKt;-><clinit>()V
+HSPLandroidx/tv/material3/Glow;-><clinit>()V
+HSPLandroidx/tv/material3/Glow;-><init>(JF)V
+HSPLandroidx/tv/material3/Glow;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/tv/material3/GlowIndication;-><init>(JLandroidx/compose/ui/graphics/Shape;FFF)V
+HSPLandroidx/tv/material3/GlowIndication;->rememberUpdatedInstance(Landroidx/compose/foundation/interaction/InteractionSource;Landroidx/compose/runtime/Composer;)Landroidx/compose/foundation/IndicationInstance;
+HSPLandroidx/tv/material3/GlowIndicationInstance;-><init>(JLandroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/unit/Density;FFF)V
+HSPLandroidx/tv/material3/GlowIndicationInstance;->drawIndication(Landroidx/compose/ui/graphics/drawscope/ContentDrawScope;)V
+HSPLandroidx/tv/material3/ScaleIndication;-><init>(F)V
+HSPLandroidx/tv/material3/ScaleIndicationInstance;-><init>(F)V
+HSPLandroidx/tv/material3/ScaleIndicationInstance;->drawIndication(Landroidx/compose/ui/graphics/drawscope/ContentDrawScope;)V
+HSPLandroidx/tv/material3/ScaleIndicationTokens;-><clinit>()V
+HSPLandroidx/tv/material3/ShapesKt$LocalShapes$1;-><clinit>()V
+HSPLandroidx/tv/material3/ShapesKt$LocalShapes$1;-><init>(I)V
+HSPLandroidx/tv/material3/ShapesKt$LocalShapes$1;->invoke()Ljava/lang/Object;
+HSPLandroidx/tv/material3/SurfaceKt$Surface$4;-><init>(ZLkotlin/jvm/functions/Function1;Landroidx/compose/ui/Modifier;ZLkotlin/jvm/functions/Function0;FLandroidx/tv/material3/ToggleableSurfaceShape;Landroidx/tv/material3/ToggleableSurfaceColors;Landroidx/tv/material3/ToggleableSurfaceScale;Landroidx/tv/material3/ToggleableSurfaceBorder;Landroidx/tv/material3/ToggleableSurfaceGlow;Landroidx/compose/foundation/interaction/MutableInteractionSourceImpl;Lkotlin/jvm/functions/Function3;III)V
+HSPLandroidx/tv/material3/SurfaceKt$SurfaceImpl$2$2$1;-><init>(ILjava/lang/Object;)V
+HSPLandroidx/tv/material3/SurfaceKt$SurfaceImpl$2$2$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/tv/material3/SurfaceKt$SurfaceImpl$2$4$1;-><init>(Landroidx/compose/ui/graphics/Shape;JI)V
+HSPLandroidx/tv/material3/SurfaceKt$SurfaceImpl$2$4$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/tv/material3/SurfaceKt$SurfaceImpl$2$5$1;-><init>(FLandroidx/compose/ui/graphics/Shape;)V
+HSPLandroidx/tv/material3/SurfaceKt$SurfaceImpl$2$5$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/tv/material3/SurfaceKt$SurfaceImpl$2;-><init>(JILandroidx/compose/ui/Modifier;Landroidx/compose/foundation/interaction/MutableInteractionSourceImpl;FLandroidx/tv/material3/Glow;Landroidx/compose/ui/graphics/Shape;Landroidx/tv/material3/Border;FLandroidx/compose/runtime/MutableState;ZLkotlin/jvm/functions/Function3;I)V
+HSPLandroidx/tv/material3/SurfaceKt$SurfaceImpl$3;-><init>(Landroidx/compose/ui/Modifier;ZZLandroidx/compose/ui/graphics/Shape;JJFLandroidx/tv/material3/Border;Landroidx/tv/material3/Glow;FLandroidx/compose/foundation/interaction/MutableInteractionSourceImpl;Lkotlin/jvm/functions/Function3;III)V
+HSPLandroidx/tv/material3/SurfaceKt$SurfaceImpl$3;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/tv/material3/SurfaceKt$handleDPadEnter$2$1;-><init>(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;I)V
+HSPLandroidx/tv/material3/SurfaceKt$handleDPadEnter$2$1;->invoke(Landroidx/compose/animation/core/AnimationScope;)V
+HSPLandroidx/tv/material3/SurfaceKt$handleDPadEnter$2$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/tv/material3/SurfaceKt$handleDPadEnter$2$2;-><init>(Lkotlinx/coroutines/CoroutineScope;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function1;ZLandroidx/compose/foundation/interaction/MutableInteractionSourceImpl;Landroidx/compose/foundation/interaction/PressInteraction$Press;Landroidx/compose/runtime/MutableState;)V
+HSPLandroidx/tv/material3/SurfaceKt$handleDPadEnter$2$2;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/tv/material3/SurfaceKt$handleDPadEnter$2;-><init>(Landroidx/compose/foundation/interaction/MutableInteractionSourceImpl;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function1;ZZ)V
+HSPLandroidx/tv/material3/SurfaceKt$handleDPadEnter$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/tv/material3/SurfaceKt$tvToggleable$1$1;-><init>(Landroidx/compose/ui/platform/AndroidComposeView;Z)V
+HSPLandroidx/tv/material3/SurfaceKt$tvToggleable$1$2;-><init>(Lkotlin/jvm/functions/Function0;I)V
+HSPLandroidx/tv/material3/SurfaceKt$tvToggleable$1$2;->invoke()Ljava/lang/Object;
+HSPLandroidx/tv/material3/SurfaceKt$tvToggleable$1;-><init>(ZLkotlin/jvm/functions/Function1;ZLkotlin/jvm/functions/Function0;)V
+HSPLandroidx/tv/material3/SurfaceKt;-><clinit>()V
+HSPLandroidx/tv/material3/SurfaceKt;->Surface-xYaah8o(ZLkotlin/jvm/functions/Function1;Landroidx/compose/ui/Modifier;ZLkotlin/jvm/functions/Function0;FLandroidx/tv/material3/ToggleableSurfaceShape;Landroidx/tv/material3/ToggleableSurfaceColors;Landroidx/tv/material3/ToggleableSurfaceScale;Landroidx/tv/material3/ToggleableSurfaceBorder;Landroidx/tv/material3/ToggleableSurfaceGlow;Landroidx/compose/foundation/interaction/MutableInteractionSourceImpl;Lkotlin/jvm/functions/Function3;Landroidx/compose/runtime/Composer;III)V
+HSPLandroidx/tv/material3/SurfaceKt;->Surface_xYaah8o$lambda$4(Landroidx/compose/runtime/MutableState;)Z
+HSPLandroidx/tv/material3/SurfaceKt;->Surface_xYaah8o$lambda$5(Landroidx/compose/runtime/MutableState;)Z
+HSPLandroidx/tv/material3/SurfaceKt;->access$surfaceColorAtElevation-CLU3JFs(JFLandroidx/compose/runtime/Composer;)J
+HSPLandroidx/tv/material3/TabColors;-><init>(JJJJJJJJ)V
+HSPLandroidx/tv/material3/TabKt$Tab$1;-><clinit>()V
+HSPLandroidx/tv/material3/TabKt$Tab$1;-><init>()V
+HSPLandroidx/tv/material3/TabKt$Tab$3$1;-><init>(Lkotlin/jvm/functions/Function0;I)V
+HSPLandroidx/tv/material3/TabKt$Tab$3$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/tv/material3/TabKt$Tab$4$1;-><init>(IZ)V
+HSPLandroidx/tv/material3/TabKt$Tab$4$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/tv/material3/TabKt$Tab$6;-><init>(Lkotlin/jvm/functions/Function3;I)V
+HSPLandroidx/tv/material3/TabKt$Tab$6;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/tv/material3/TabKt$Tab$7;-><init>(Landroidx/tv/material3/TabRowScopeImpl;ZLkotlin/jvm/functions/Function0;Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function0;ZLandroidx/tv/material3/TabColors;Landroidx/compose/foundation/interaction/MutableInteractionSourceImpl;Lkotlin/jvm/functions/Function3;II)V
+HSPLandroidx/tv/material3/TabKt;-><clinit>()V
+HSPLandroidx/tv/material3/TabKt;->BasicText-BpD7jsM(Ljava/lang/String;Landroidx/compose/ui/Modifier;Landroidx/compose/ui/text/TextStyle;Lkotlin/jvm/functions/Function1;IZILandroidx/compose/runtime/Composer;II)V
+HSPLandroidx/tv/material3/TabKt;->BasicText-VhcvRP8(Ljava/lang/String;Landroidx/compose/ui/Modifier;Landroidx/compose/ui/text/TextStyle;Lkotlin/jvm/functions/Function1;IZIILandroidx/compose/runtime/Composer;II)V
+HSPLandroidx/tv/material3/TabKt;->DisposableEffect(Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;)V
+HSPLandroidx/tv/material3/TabKt;->LaunchedEffect(Ljava/lang/Object;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;)V
+HSPLandroidx/tv/material3/TabKt;->LaunchedEffect(Ljava/lang/Object;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;)V
+HSPLandroidx/tv/material3/TabKt;->LazyLayout(Lkotlin/jvm/functions/Function0;Landroidx/compose/ui/Modifier;Landroidx/compose/foundation/lazy/layout/LazyLayoutPrefetchState;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;II)V
+HSPLandroidx/tv/material3/TabKt;->LazyLayoutPrefetcher(Landroidx/compose/foundation/lazy/layout/LazyLayoutPrefetchState;Landroidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory;Landroidx/compose/ui/layout/SubcomposeLayoutState;Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/tv/material3/TabKt;->SideEffect(Lkotlin/jvm/functions/Function0;Landroidx/compose/runtime/Composer;)V
+HSPLandroidx/tv/material3/TabKt;->Tab(Landroidx/tv/material3/TabRowScopeImpl;ZLkotlin/jvm/functions/Function0;Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function0;ZLandroidx/tv/material3/TabColors;Landroidx/compose/foundation/interaction/MutableInteractionSourceImpl;Lkotlin/jvm/functions/Function3;Landroidx/compose/runtime/Composer;II)V
+HSPLandroidx/tv/material3/TabKt;->TabRow-pAZo6Ak(ILandroidx/compose/ui/Modifier;JJLkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function4;Lkotlin/jvm/functions/Function3;Landroidx/compose/runtime/Composer;II)V
+HSPLandroidx/tv/material3/TabKt;->access$binarySearch(ILandroidx/compose/runtime/collection/MutableVector;)I
+HSPLandroidx/tv/material3/TabKt;->animate(Landroidx/compose/animation/core/AnimationState;Landroidx/compose/animation/core/Animation;JLkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/tv/material3/TabKt;->callWithFrameNanos(Landroidx/compose/animation/core/Animation;Lkotlin/jvm/functions/Function1;Landroidx/compose/animation/core/SuspendAnimationKt$animate$4;)Ljava/lang/Object;
+HSPLandroidx/tv/material3/TabKt;->collectIsFocusedAsState(Landroidx/compose/foundation/interaction/InteractionSource;Landroidx/compose/runtime/Composer;I)Landroidx/compose/runtime/MutableState;
+HSPLandroidx/tv/material3/TabKt;->complexSqrt(D)Landroidx/compose/animation/core/ComplexDouble;
+HSPLandroidx/tv/material3/TabKt;->copy(Landroidx/compose/animation/core/AnimationVector;)Landroidx/compose/animation/core/AnimationVector;
+HSPLandroidx/tv/material3/TabKt;->createCompositionCoroutineScope(Landroidx/compose/runtime/Composer;)Lkotlinx/coroutines/internal/ContextScope;
+HSPLandroidx/tv/material3/TabKt;->derivedStateObservers()Landroidx/compose/runtime/collection/MutableVector;
+HSPLandroidx/tv/material3/TabKt;->doAnimationFrameWithScale(Landroidx/compose/animation/core/AnimationScope;JFLandroidx/compose/animation/core/Animation;Landroidx/compose/animation/core/AnimationState;Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/tv/material3/TabKt;->finalConstraints-tfFHcEY(JZIF)J
+HSPLandroidx/tv/material3/TabKt;->getContentType(I)Ljava/lang/Object;
+HSPLandroidx/tv/material3/TabKt;->getDurationScale(Lkotlin/coroutines/CoroutineContext;)F
+HSPLandroidx/tv/material3/TabKt;->getPoolingContainerListenerHolder(Landroid/view/View;)Landroidx/customview/poolingcontainer/PoolingContainerListenerHolder;
+HSPLandroidx/tv/material3/TabKt;->mutableStateOf$default(Ljava/lang/Object;)Landroidx/compose/runtime/ParcelableSnapshotMutableState;
+HSPLandroidx/tv/material3/TabKt;->read(Landroidx/compose/runtime/PersistentCompositionLocalMap;Landroidx/compose/runtime/ProvidableCompositionLocal;)Ljava/lang/Object;
+HSPLandroidx/tv/material3/TabKt;->rememberSaveable([Ljava/lang/Object;Landroidx/compose/runtime/saveable/SaverKt$Saver$1;Lkotlin/jvm/functions/Function0;Landroidx/compose/runtime/Composer;)Ljava/lang/Object;
+HSPLandroidx/tv/material3/TabKt;->rememberUpdatedState(Ljava/lang/Object;Landroidx/compose/runtime/Composer;)Landroidx/compose/runtime/MutableState;
+HSPLandroidx/tv/material3/TabKt;->resumeCancellableWith(Lkotlin/coroutines/Continuation;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)V
+HSPLandroidx/tv/material3/TabKt;->spring$default(FLjava/lang/Comparable;I)Landroidx/compose/animation/core/SpringSpec;
+HSPLandroidx/tv/material3/TabKt;->tween$default(ILandroidx/compose/animation/core/Easing;)Landroidx/compose/animation/core/TweenSpec;
+HSPLandroidx/tv/material3/TabKt;->updateCompositionMap([Landroidx/compose/runtime/ProvidedValue;Landroidx/compose/runtime/PersistentCompositionLocalMap;Landroidx/compose/runtime/PersistentCompositionLocalMap;)Landroidx/compose/runtime/internal/PersistentCompositionLocalHashMap;
+HSPLandroidx/tv/material3/TabKt;->updateState(Landroidx/compose/animation/core/AnimationScope;Landroidx/compose/animation/core/AnimationState;)V
+HSPLandroidx/tv/material3/TabKt;->withFrameNanos(Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLandroidx/tv/material3/TabRowDefaults$PillIndicator$1;-><init>(Landroidx/tv/material3/TabRowDefaults;Landroidx/compose/ui/unit/DpRect;ZLandroidx/compose/ui/Modifier;JJII)V
+HSPLandroidx/tv/material3/TabRowDefaults$PillIndicator$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/tv/material3/TabRowDefaults;-><clinit>()V
+HSPLandroidx/tv/material3/TabRowDefaults;->PillIndicator-jA1GFJw(Landroidx/compose/ui/unit/DpRect;ZLandroidx/compose/ui/Modifier;JJLandroidx/compose/runtime/Composer;II)V
+HSPLandroidx/tv/material3/TabRowKt$TabRow$1;-><init>(I)V
+HSPLandroidx/tv/material3/TabRowKt$TabRow$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/tv/material3/TabRowKt$TabRow$2$1$1;-><init>(Landroidx/compose/runtime/MutableState;I)V
+HSPLandroidx/tv/material3/TabRowKt$TabRow$2$1$1;->invoke(Landroidx/compose/ui/focus/FocusState;)V
+HSPLandroidx/tv/material3/TabRowKt$TabRow$2$1$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/tv/material3/TabRowKt$TabRow$2$2$1$1$2;-><init>(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;II)V
+HSPLandroidx/tv/material3/TabRowKt$TabRow$2$2$1$1$2;-><init>(Lkotlin/jvm/functions/Function4;Ljava/util/ArrayList;ILandroidx/compose/runtime/MutableState;)V
+HSPLandroidx/tv/material3/TabRowKt$TabRow$2$2$1$1$2;->invoke(Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/tv/material3/TabRowKt$TabRow$2$2$1$1$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/tv/material3/TabRowKt$TabRow$2$2$1$1;-><init>(Ljava/util/ArrayList;Landroidx/compose/ui/layout/SubcomposeMeasureScope;Ljava/util/ArrayList;ILkotlin/jvm/functions/Function4;ILandroidx/compose/runtime/MutableState;II)V
+HSPLandroidx/tv/material3/TabRowKt$TabRow$2$2$1$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/tv/material3/TabRowKt$TabRow$2$2$1$separators$1;-><init>(IILkotlin/jvm/functions/Function1;)V
+HSPLandroidx/tv/material3/TabRowKt$TabRow$2$2$1$separators$1;-><init>(ILkotlin/jvm/functions/Function2;I)V
+HSPLandroidx/tv/material3/TabRowKt$TabRow$2$2$1$separators$1;->invoke(Landroidx/compose/runtime/Composer;I)V
+HSPLandroidx/tv/material3/TabRowKt$TabRow$2$2$1$separators$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/tv/material3/TabRowKt$TabRow$2$2$1;-><init>(Landroidx/compose/runtime/MutableState;Lkotlin/jvm/functions/Function3;ILkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function4;)V
+HSPLandroidx/tv/material3/TabRowKt$TabRow$2$2$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/tv/material3/TabRowKt$TabRow$2;-><init>(Landroidx/compose/ui/Modifier;JLandroidx/compose/foundation/ScrollState;Landroidx/compose/runtime/MutableState;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function4;I)V
+HSPLandroidx/tv/material3/TabRowKt$TabRow$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/tv/material3/TabRowKt$TabRow$3;-><init>(ILandroidx/compose/ui/Modifier;JJLkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function4;Lkotlin/jvm/functions/Function3;II)V
+HSPLandroidx/tv/material3/TabRowScopeImpl;-><init>(Z)V
+HSPLandroidx/tv/material3/TabRowSlots;-><clinit>()V
+HSPLandroidx/tv/material3/TabRowSlots;-><init>(ILjava/lang/String;)V
+HSPLandroidx/tv/material3/TextKt$Text$1;-><clinit>()V
+HSPLandroidx/tv/material3/TextKt$Text$1;-><init>()V
+HSPLandroidx/tv/material3/TextKt$Text$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/tv/material3/TextKt$Text$2;-><init>(Ljava/lang/String;Landroidx/compose/ui/Modifier;JJLandroidx/compose/ui/text/font/FontStyle;Landroidx/compose/ui/text/font/FontWeight;Landroidx/compose/ui/text/font/FontFamily;JLandroidx/compose/ui/text/style/TextDecoration;Landroidx/compose/ui/text/style/TextAlign;JIZILkotlin/jvm/functions/Function1;Landroidx/compose/ui/text/TextStyle;IIII)V
+HSPLandroidx/tv/material3/TextKt;-><clinit>()V
+HSPLandroidx/tv/material3/TextKt;->Text-fLXpl1I(Ljava/lang/String;Landroidx/compose/ui/Modifier;JJLandroidx/compose/ui/text/font/FontStyle;Landroidx/compose/ui/text/font/FontWeight;Landroidx/compose/ui/text/font/FontFamily;JLandroidx/compose/ui/text/style/TextDecoration;Landroidx/compose/ui/text/style/TextAlign;JIZILkotlin/jvm/functions/Function1;Landroidx/compose/ui/text/TextStyle;Landroidx/compose/runtime/Composer;III)V
+HSPLandroidx/tv/material3/ToggleableSurfaceBorder;-><init>(Landroidx/tv/material3/Border;Landroidx/tv/material3/Border;Landroidx/tv/material3/Border;Landroidx/tv/material3/Border;Landroidx/tv/material3/Border;Landroidx/tv/material3/Border;Landroidx/tv/material3/Border;Landroidx/tv/material3/Border;Landroidx/tv/material3/Border;Landroidx/tv/material3/Border;)V
+HSPLandroidx/tv/material3/ToggleableSurfaceColors;-><init>(JJJJJJJJJJJJJJ)V
+HSPLandroidx/tv/material3/ToggleableSurfaceColors;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/tv/material3/ToggleableSurfaceGlow;-><init>(Landroidx/tv/material3/Glow;Landroidx/tv/material3/Glow;Landroidx/tv/material3/Glow;Landroidx/tv/material3/Glow;Landroidx/tv/material3/Glow;Landroidx/tv/material3/Glow;)V
+HSPLandroidx/tv/material3/ToggleableSurfaceScale;-><clinit>()V
+HSPLandroidx/tv/material3/ToggleableSurfaceScale;-><init>(FFFFFFFFFF)V
+HSPLandroidx/tv/material3/ToggleableSurfaceShape;-><init>(Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;)V
+HSPLandroidx/tv/material3/ToggleableSurfaceShape;->equals(Ljava/lang/Object;)Z
+HSPLandroidx/tv/material3/tokens/ColorLightTokens;-><clinit>()V
+HSPLandroidx/tv/material3/tokens/Elevation;-><clinit>()V
+HSPLandroidx/tv/material3/tokens/PaletteTokens;-><clinit>()V
+HSPLandroidx/tv/material3/tokens/ShapeTokens$BorderDefaultShape$1;-><clinit>()V
+HSPLandroidx/tv/material3/tokens/ShapeTokens$BorderDefaultShape$1;-><init>(I)V
+HSPLandroidx/tv/material3/tokens/ShapeTokens$BorderDefaultShape$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLandroidx/tv/material3/tokens/ShapeTokens$BorderDefaultShape$1;->invoke(Ljava/util/List;II)Ljava/lang/Integer;
+HSPLandroidx/tv/material3/tokens/ShapeTokens$BorderDefaultShape$1;->invoke-3p2s80s(Landroidx/compose/ui/layout/MeasureScope;Landroidx/compose/ui/layout/Measurable;J)Landroidx/compose/ui/layout/MeasureResult;
+HSPLandroidx/tv/material3/tokens/TypographyTokensKt;-><clinit>()V
+HSPLcom/example/tvcomposebasedtests/ComposableSingletons$MainActivityKt;-><clinit>()V
+HSPLcom/example/tvcomposebasedtests/ComposableSingletons$UtilsKt$lambda-1$1;-><clinit>()V
+HSPLcom/example/tvcomposebasedtests/ComposableSingletons$UtilsKt$lambda-1$1;-><init>(I)V
+HSPLcom/example/tvcomposebasedtests/ComposableSingletons$UtilsKt$lambda-1$1;->invoke(Landroidx/tv/foundation/lazy/list/TvLazyListItemScopeImpl;ILandroidx/compose/runtime/Composer;I)V
+HSPLcom/example/tvcomposebasedtests/ComposableSingletons$UtilsKt$lambda-1$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLcom/example/tvcomposebasedtests/Config;-><init>(Landroid/content/Context;Landroidx/activity/ComponentActivity;II)V
+HSPLcom/example/tvcomposebasedtests/Config;->toString()Ljava/lang/String;
+HSPLcom/example/tvcomposebasedtests/JankStatsAggregator$listener$1;-><init>(Lcom/example/tvcomposebasedtests/JankStatsAggregator;)V
+HSPLcom/example/tvcomposebasedtests/JankStatsAggregator;-><init>(Landroid/view/Window;Lcom/example/tvcomposebasedtests/MainActivity$jankReportListener$1;)V
+HSPLcom/example/tvcomposebasedtests/MainActivity$jankReportListener$1;-><init>(Lcom/example/tvcomposebasedtests/MainActivity;)V
+HSPLcom/example/tvcomposebasedtests/MainActivity$startFrameMetrics$listener$1;-><init>(Lcom/example/tvcomposebasedtests/MainActivity;)V
+HSPLcom/example/tvcomposebasedtests/MainActivity$startFrameMetrics$listener$1;->onFrameMetricsAvailable(Landroid/view/Window;Landroid/view/FrameMetrics;I)V
+HSPLcom/example/tvcomposebasedtests/MainActivity;-><init>()V
+HSPLcom/example/tvcomposebasedtests/MainActivity;->onCreate(Landroid/os/Bundle;)V
+HSPLcom/example/tvcomposebasedtests/MainActivity;->onResume()V
+HSPLcom/example/tvcomposebasedtests/UtilsKt$AddJankMetrics$1$2;-><init>(ILjava/lang/Object;)V
+HSPLcom/example/tvcomposebasedtests/UtilsKt$AddJankMetrics$1$2;->emit(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLcom/example/tvcomposebasedtests/UtilsKt$ScrollingRow$1$1$1;-><init>(II)V
+HSPLcom/example/tvcomposebasedtests/UtilsKt$ScrollingRow$1$1$1;->invoke(Landroidx/tv/foundation/lazy/list/TvLazyListScope;)V
+HSPLcom/example/tvcomposebasedtests/UtilsKt$ScrollingRow$1$1$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLcom/example/tvcomposebasedtests/UtilsKt$ScrollingRow$2;-><init>(III)V
+HSPLcom/example/tvcomposebasedtests/UtilsKt$ScrollingRow$2;->invoke(Landroidx/compose/runtime/Composer;I)V
+HSPLcom/example/tvcomposebasedtests/UtilsKt$ScrollingRow$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLcom/example/tvcomposebasedtests/UtilsKt;-><clinit>()V
+HSPLcom/example/tvcomposebasedtests/tvComponents/AppKt$App$1;-><init>(ILjava/lang/Object;)V
+HSPLcom/example/tvcomposebasedtests/tvComponents/AppKt$App$1;->invoke(Landroidx/compose/runtime/Composer;I)V
+HSPLcom/example/tvcomposebasedtests/tvComponents/AppKt$App$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLcom/example/tvcomposebasedtests/tvComponents/AppKt$App$1;->invoke-5SAbXVA(JLandroidx/compose/ui/unit/LayoutDirection;)J
+HSPLcom/example/tvcomposebasedtests/tvComponents/ComposableSingletons$LazyContainersKt;-><clinit>()V
+HSPLcom/example/tvcomposebasedtests/tvComponents/ComposableSingletons$TopNavigationKt;-><clinit>()V
+HSPLcom/example/tvcomposebasedtests/tvComponents/Navigation;-><clinit>()V
+HSPLcom/example/tvcomposebasedtests/tvComponents/Navigation;-><init>(Ljava/lang/String;ILjava/lang/String;Landroidx/compose/runtime/internal/ComposableLambdaImpl;)V
+HSPLcom/example/tvcomposebasedtests/tvComponents/Navigation;->values()[Lcom/example/tvcomposebasedtests/tvComponents/Navigation;
+HSPLcom/example/tvcomposebasedtests/tvComponents/TopNavigationKt$PillIndicatorTabRow$1$1$1$1;-><init>(ILkotlin/jvm/functions/Function1;)V
+HSPLcom/example/tvcomposebasedtests/tvComponents/TopNavigationKt$PillIndicatorTabRow$1$1$1$1;->invoke()Ljava/lang/Object;
+HSPLcom/example/tvcomposebasedtests/tvComponents/TopNavigationKt$PillIndicatorTabRow$1;-><init>(IILjava/util/List;Lkotlin/jvm/functions/Function1;)V
+HSPLcom/example/tvcomposebasedtests/tvComponents/TopNavigationKt$PillIndicatorTabRow$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLcom/example/tvcomposebasedtests/tvComponents/TopNavigationKt$TopNavigation$3$1;-><init>(Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/MutableState;Lkotlin/coroutines/Continuation;)V
+HSPLcom/example/tvcomposebasedtests/tvComponents/TopNavigationKt$TopNavigation$3$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLcom/example/tvcomposebasedtests/tvComponents/TopNavigationKt$TopNavigation$3$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLcom/google/gson/internal/ConstructorConstructor;-><init>()V
+HSPLcom/google/gson/internal/ConstructorConstructor;->access$commitTransaction(Lcom/google/gson/internal/ConstructorConstructor;)V
+HSPLcom/google/gson/internal/LinkedTreeMap$1;-><init>(I)V
+HSPLcom/google/gson/internal/LinkedTreeMap$1;->compare(Ljava/lang/Object;Ljava/lang/Object;)I
+HSPLkotlin/Pair;-><init>(Ljava/lang/Object;Ljava/lang/Object;)V
+HSPLkotlin/Result$Failure;-><init>(Ljava/lang/Throwable;)V
+HSPLkotlin/Result;->exceptionOrNull-impl(Ljava/lang/Object;)Ljava/lang/Throwable;
+HSPLkotlin/ResultKt$$ExternalSyntheticCheckNotZero0;->m$1()Ljava/util/Iterator;
+HSPLkotlin/ResultKt$$ExternalSyntheticCheckNotZero0;->m(III)I
+HSPLkotlin/ResultKt$$ExternalSyntheticCheckNotZero0;->m(ILjava/lang/String;)V
+HSPLkotlin/ResultKt$$ExternalSyntheticCheckNotZero0;->m(Ljava/lang/Object;)V
+HSPLkotlin/ResultKt$$ExternalSyntheticCheckNotZero0;->stringValueOf$1(I)Ljava/lang/String;
+HSPLkotlin/ResultKt$$ExternalSyntheticCheckNotZero0;->stringValueOf$2(I)Ljava/lang/String;
+HSPLkotlin/ResultKt$$ExternalSyntheticCheckNotZero0;->valueOf$1(Ljava/lang/String;)I
+HSPLkotlin/ResultKt$$ExternalSyntheticCheckNotZero0;->valueOf(Ljava/lang/String;)I
+HSPLkotlin/ResultKt;-><clinit>()V
+HSPLkotlin/ResultKt;-><init>(Landroidx/metrics/performance/JankStats;)V
+HSPLkotlin/ResultKt;->App(Landroidx/compose/runtime/Composer;I)V
+HSPLkotlin/ResultKt;->Constraints$default(III)J
+HSPLkotlin/ResultKt;->Constraints(IIII)J
+HSPLkotlin/ResultKt;->Density(Landroid/content/Context;)Landroidx/compose/ui/unit/DensityImpl;
+HSPLkotlin/ResultKt;->DpOffset-YgX7TsA(FF)J
+HSPLkotlin/ResultKt;->IntOffset(II)J
+HSPLkotlin/ResultKt;->IntSize(II)J
+HSPLkotlin/ResultKt;->MaterialTheme(Landroidx/compose/material3/ColorScheme;Landroidx/compose/material3/Shapes;Landroidx/compose/material3/Typography;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;II)V
+HSPLkotlin/ResultKt;->SampleCardItem(ILandroidx/compose/runtime/Composer;I)V
+HSPLkotlin/ResultKt;->SampleTvLazyRow(ILandroidx/compose/runtime/Composer;I)V
+HSPLkotlin/ResultKt;->TvLazyRow(Landroidx/compose/ui/Modifier;Landroidx/tv/foundation/lazy/list/TvLazyListState;Landroidx/compose/foundation/layout/PaddingValuesImpl;ZLandroidx/compose/foundation/layout/Arrangement$Horizontal;Landroidx/compose/ui/Alignment$Vertical;ZLandroidx/tv/foundation/PivotOffsets;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;II)V
+HSPLkotlin/ResultKt;->access$getHasEmojiCompat(Landroidx/compose/ui/text/TextStyle;)Z
+HSPLkotlin/ResultKt;->areEqual(Ljava/lang/Object;Ljava/lang/Object;)Z
+HSPLkotlin/ResultKt;->canBeSavedToBundle(Ljava/lang/Object;)Z
+HSPLkotlin/ResultKt;->checkArgument(Ljava/lang/String;Z)V
+HSPLkotlin/ResultKt;->checkElementIndex$runtime_release(II)V
+HSPLkotlin/ResultKt;->checkNotNull$1(Ljava/lang/Object;Ljava/lang/String;)V
+HSPLkotlin/ResultKt;->checkNotNull(Ljava/lang/Object;)V
+HSPLkotlin/ResultKt;->checkNotNull(Ljava/lang/Object;Ljava/lang/String;)V
+HSPLkotlin/ResultKt;->checkNotNullExpressionValue(Ljava/lang/Object;Ljava/lang/String;)V
+HSPLkotlin/ResultKt;->checkNotNullParameter(Ljava/lang/Object;Ljava/lang/String;)V
+HSPLkotlin/ResultKt;->compare(II)I
+HSPLkotlin/ResultKt;->constrain-4WqzIAM(JJ)J
+HSPLkotlin/ResultKt;->constrainHeight-K40F9xA(JI)I
+HSPLkotlin/ResultKt;->constrainWidth-K40F9xA(JI)I
+HSPLkotlin/ResultKt;->create(Landroid/content/Context;)Landroidx/emoji2/text/FontRequestEmojiCompatConfig;
+HSPLkotlin/ResultKt;->createCoroutineUnintercepted(Ljava/lang/Object;Lkotlin/coroutines/Continuation;Lkotlin/jvm/functions/Function2;)Lkotlin/coroutines/Continuation;
+HSPLkotlin/ResultKt;->createFailure(Ljava/lang/Throwable;)Lkotlin/Result$Failure;
+HSPLkotlin/ResultKt;->distinctUntilChanged(Lkotlinx/coroutines/flow/Flow;)Lkotlinx/coroutines/flow/Flow;
+HSPLkotlin/ResultKt;->emitAllImpl$FlowKt__ChannelsKt(Lkotlinx/coroutines/flow/FlowCollector;Lkotlinx/coroutines/channels/ProducerCoroutine;ZLkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlin/ResultKt;->ensureActive(Lkotlin/coroutines/CoroutineContext;)V
+HSPLkotlin/ResultKt;->findIndexByKey$1(Landroidx/compose/foundation/lazy/layout/LazyLayoutItemProvider;Ljava/lang/Object;I)I
+HSPLkotlin/ResultKt;->first(Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlin/ResultKt;->get(Landroid/view/View;)Landroidx/lifecycle/LifecycleOwner;
+HSPLkotlin/ResultKt;->getExclusions()Ljava/util/Set;
+HSPLkotlin/ResultKt;->getJob(Lkotlin/coroutines/CoroutineContext;)Lkotlinx/coroutines/Job;
+HSPLkotlin/ResultKt;->getOrCreateCancellableContinuation(Lkotlin/coroutines/Continuation;)Lkotlinx/coroutines/CancellableContinuationImpl;
+HSPLkotlin/ResultKt;->getProgressionLastElement(III)I
+HSPLkotlin/ResultKt;->getSp(D)J
+HSPLkotlin/ResultKt;->getSp(I)J
+HSPLkotlin/ResultKt;->hasFontAttributes(Landroidx/compose/ui/text/SpanStyle;)Z
+HSPLkotlin/ResultKt;->intercepted(Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLkotlin/ResultKt;->isEnabled()Z
+HSPLkotlin/ResultKt;->isUnspecified--R2X_6o(J)Z
+HSPLkotlin/ResultKt;->launch$default(Lkotlinx/coroutines/CoroutineScope;Lkotlinx/coroutines/android/HandlerContext;ILkotlin/jvm/functions/Function2;I)Lkotlinx/coroutines/StandaloneCoroutine;
+HSPLkotlin/ResultKt;->launch(Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/CoroutineContext;ILkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/StandaloneCoroutine;
+HSPLkotlin/ResultKt;->lazyLayoutSemantics(Landroidx/compose/ui/Modifier;Lkotlin/reflect/KProperty0;Landroidx/tv/foundation/lazy/layout/LazyLayoutSemanticState;Landroidx/compose/foundation/gestures/Orientation;ZZLandroidx/compose/runtime/Composer;)Landroidx/compose/ui/Modifier;
+HSPLkotlin/ResultKt;->mapCapacity(I)I
+HSPLkotlin/ResultKt;->materializeModifier(Landroidx/compose/runtime/Composer;Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier;
+HSPLkotlin/ResultKt;->mmap(Landroid/content/Context;Landroid/net/Uri;)Ljava/nio/MappedByteBuffer;
+HSPLkotlin/ResultKt;->offset-NN6Ew-U(IIJ)J
+HSPLkotlin/ResultKt;->overscrollEffect(Landroidx/compose/runtime/Composer;)Landroidx/compose/foundation/OverscrollEffect;
+HSPLkotlin/ResultKt;->pack(FJ)J
+HSPLkotlin/ResultKt;->plus(Lkotlin/coroutines/CoroutineContext;Lkotlin/coroutines/CoroutineContext;)Lkotlin/coroutines/CoroutineContext;
+HSPLkotlin/ResultKt;->read(Ljava/nio/MappedByteBuffer;)Landroidx/emoji2/text/flatbuffer/MetadataList;
+HSPLkotlin/ResultKt;->recoverResult(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlin/ResultKt;->requireOwner(Landroidx/compose/ui/node/LayoutNode;)Landroidx/compose/ui/node/Owner;
+HSPLkotlin/ResultKt;->resolveLineHeightInPx-o2QH7mI(JFLandroidx/compose/ui/unit/Density;)F
+HSPLkotlin/ResultKt;->restoreThreadContext(Lkotlin/coroutines/CoroutineContext;Ljava/lang/Object;)V
+HSPLkotlin/ResultKt;->resume(Lkotlinx/coroutines/DispatchedTask;Lkotlin/coroutines/Continuation;Z)V
+HSPLkotlin/ResultKt;->roundToInt(F)I
+HSPLkotlin/ResultKt;->scrollableWithPivot(Landroidx/compose/ui/Modifier;Landroidx/compose/foundation/gestures/ScrollableState;Landroidx/compose/foundation/gestures/Orientation;Landroidx/tv/foundation/PivotOffsets;ZZ)Landroidx/compose/ui/Modifier;
+HSPLkotlin/ResultKt;->startUndispatchedOrReturn(Lkotlinx/coroutines/internal/ScopeCoroutine;Lkotlinx/coroutines/internal/ScopeCoroutine;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
+HSPLkotlin/ResultKt;->stateIn(Lkotlinx/coroutines/flow/SafeFlow;Lkotlinx/coroutines/internal/ContextScope;Lkotlinx/coroutines/flow/StartedWhileSubscribed;Ljava/lang/Float;)Lkotlinx/coroutines/flow/ReadonlyStateFlow;
+HSPLkotlin/ResultKt;->systemProp$default(Ljava/lang/String;IIII)I
+HSPLkotlin/ResultKt;->systemProp(Ljava/lang/String;JJJ)J
+HSPLkotlin/ResultKt;->threadContextElements(Lkotlin/coroutines/CoroutineContext;)Ljava/lang/Object;
+HSPLkotlin/ResultKt;->throwOnFailure(Ljava/lang/Object;)V
+HSPLkotlin/ResultKt;->toSize-ozmzZPI(J)J
+HSPLkotlin/ResultKt;->ulongToDouble(J)D
+HSPLkotlin/ResultKt;->updateThreadContext(Lkotlin/coroutines/CoroutineContext;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlin/ResultKt;->withContext(Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlin/SynchronizedLazyImpl;-><init>(Lkotlin/jvm/functions/Function0;)V
+HSPLkotlin/SynchronizedLazyImpl;->getValue()Ljava/lang/Object;
+HSPLkotlin/TuplesKt;-><clinit>()V
+HSPLkotlin/TuplesKt;->CornerRadius(FF)J
+HSPLkotlin/TuplesKt;->LazyList(Landroidx/compose/ui/Modifier;Landroidx/tv/foundation/lazy/list/TvLazyListState;Landroidx/compose/foundation/layout/PaddingValuesImpl;ZZZILandroidx/tv/foundation/PivotOffsets;Landroidx/compose/ui/Alignment$Horizontal;Landroidx/compose/foundation/layout/Arrangement$Vertical;Landroidx/compose/ui/Alignment$Vertical;Landroidx/compose/foundation/layout/Arrangement$Horizontal;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;III)V
+HSPLkotlin/TuplesKt;->PillIndicatorTabRow(Ljava/util/List;ILkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;I)V
+HSPLkotlin/TuplesKt;->Rect-tz77jQw(JJ)Landroidx/compose/ui/geometry/Rect;
+HSPLkotlin/TuplesKt;->ScrollPositionUpdater(Lkotlin/jvm/functions/Function0;Landroidx/tv/foundation/lazy/list/TvLazyListState;Landroidx/compose/runtime/Composer;I)V
+HSPLkotlin/TuplesKt;->Size(FF)J
+HSPLkotlin/TuplesKt;->TopNavigation(Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;II)V
+HSPLkotlin/TuplesKt;->access$addLayoutNodeChildren(Landroidx/compose/runtime/collection/MutableVector;Landroidx/compose/ui/Modifier$Node;)V
+HSPLkotlin/TuplesKt;->access$insertEntryAtIndex([Ljava/lang/Object;ILjava/lang/Object;Ljava/lang/Object;)[Ljava/lang/Object;
+HSPLkotlin/TuplesKt;->access$pop(Landroidx/compose/runtime/collection/MutableVector;)Landroidx/compose/ui/Modifier$Node;
+HSPLkotlin/TuplesKt;->access$removeRange(Ljava/util/ArrayList;II)V
+HSPLkotlin/TuplesKt;->asLayoutModifierNode(Landroidx/compose/ui/Modifier$Node;)Landroidx/compose/ui/node/LayoutModifierNode;
+HSPLkotlin/TuplesKt;->autoInvalidateInsertedNode(Landroidx/compose/ui/Modifier$Node;)V
+HSPLkotlin/TuplesKt;->autoInvalidateNodeIncludingDelegates(Landroidx/compose/ui/Modifier$Node;II)V
+HSPLkotlin/TuplesKt;->autoInvalidateNodeSelf(Landroidx/compose/ui/Modifier$Node;II)V
+HSPLkotlin/TuplesKt;->autoInvalidateUpdatedNode(Landroidx/compose/ui/Modifier$Node;)V
+HSPLkotlin/TuplesKt;->beforeCheckcastToFunctionOfArity(ILjava/lang/Object;)V
+HSPLkotlin/TuplesKt;->binarySearch([II)I
+HSPLkotlin/TuplesKt;->bitsForSlot(II)I
+HSPLkotlin/TuplesKt;->calculateLazyLayoutPinnedIndices(Landroidx/compose/foundation/lazy/layout/LazyLayoutItemProvider;Landroidx/compose/foundation/lazy/layout/LazyLayoutPinnedItemList;Landroidx/compose/runtime/Stack;)Ljava/util/List;
+HSPLkotlin/TuplesKt;->calculateNodeKindSetFrom(Landroidx/compose/ui/Modifier$Element;)I
+HSPLkotlin/TuplesKt;->calculateNodeKindSetFrom(Landroidx/compose/ui/Modifier$Node;)I
+HSPLkotlin/TuplesKt;->calculateNodeKindSetFromIncludingDelegates(Landroidx/compose/ui/Modifier$Node;)I
+HSPLkotlin/TuplesKt;->checkRadix(I)V
+HSPLkotlin/TuplesKt;->coerceIn(DDD)D
+HSPLkotlin/TuplesKt;->coerceIn(FFF)F
+HSPLkotlin/TuplesKt;->coerceIn(III)I
+HSPLkotlin/TuplesKt;->compareValues(Ljava/lang/Comparable;Ljava/lang/Comparable;)I
+HSPLkotlin/TuplesKt;->composableLambda(Landroidx/compose/runtime/Composer;ILkotlin/jvm/internal/Lambda;)Landroidx/compose/runtime/internal/ComposableLambdaImpl;
+HSPLkotlin/TuplesKt;->composableLambdaInstance(ILkotlin/jvm/internal/Lambda;Z)Landroidx/compose/runtime/internal/ComposableLambdaImpl;
+HSPLkotlin/TuplesKt;->currentValueOf(Landroidx/compose/ui/node/CompositionLocalConsumerModifierNode;Landroidx/compose/runtime/ProvidableCompositionLocal;)Ljava/lang/Object;
+HSPLkotlin/TuplesKt;->findLocation(ILjava/util/List;)I
+HSPLkotlin/TuplesKt;->findSegmentInternal(Lkotlinx/coroutines/internal/Segment;JLkotlin/jvm/functions/Function2;)Ljava/lang/Object;
+HSPLkotlin/TuplesKt;->get(Lkotlin/coroutines/CoroutineContext$Element;Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext$Element;
+HSPLkotlin/TuplesKt;->getCenter-uvyYCjk(J)J
+HSPLkotlin/TuplesKt;->getEllipsizedLeftPadding(Landroid/text/Layout;ILandroid/graphics/Paint;)F
+HSPLkotlin/TuplesKt;->getEllipsizedRightPadding(Landroid/text/Layout;ILandroid/graphics/Paint;)F
+HSPLkotlin/TuplesKt;->getIncludeSelfInTraversal-H91voCI(I)Z
+HSPLkotlin/TuplesKt;->getLastIndex(Ljava/util/List;)I
+HSPLkotlin/TuplesKt;->invalidateDraw(Landroidx/compose/ui/node/DrawModifierNode;)V
+HSPLkotlin/TuplesKt;->invalidateMeasurement(Landroidx/compose/ui/node/LayoutModifierNode;)V
+HSPLkotlin/TuplesKt;->invalidateSemantics(Landroidx/compose/ui/node/SemanticsModifierNode;)V
+HSPLkotlin/TuplesKt;->isWhitespace(C)Z
+HSPLkotlin/TuplesKt;->lazy(Lkotlin/jvm/functions/Function0;)Lkotlin/Lazy;
+HSPLkotlin/TuplesKt;->listOf(Ljava/lang/Object;)Ljava/util/List;
+HSPLkotlin/TuplesKt;->listOf([Ljava/lang/Object;)Ljava/util/List;
+HSPLkotlin/TuplesKt;->minusKey(Lkotlin/coroutines/CoroutineContext$Element;Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext;
+HSPLkotlin/TuplesKt;->observeReads(Landroidx/compose/ui/Modifier$Node;Lkotlin/jvm/functions/Function0;)V
+HSPLkotlin/TuplesKt;->painterResource(ILandroidx/compose/runtime/Composer;)Landroidx/compose/ui/graphics/painter/Painter;
+HSPLkotlin/TuplesKt;->replacableWith(Landroidx/compose/runtime/RecomposeScope;Landroidx/compose/runtime/RecomposeScopeImpl;)Z
+HSPLkotlin/TuplesKt;->requireCoordinator-64DMado(Landroidx/compose/ui/node/DelegatableNode;I)Landroidx/compose/ui/node/NodeCoordinator;
+HSPLkotlin/TuplesKt;->requireLayoutNode(Landroidx/compose/ui/node/DelegatableNode;)Landroidx/compose/ui/node/LayoutNode;
+HSPLkotlin/TuplesKt;->requireOwner(Landroidx/compose/ui/node/DelegatableNode;)Landroidx/compose/ui/node/Owner;
+HSPLkotlin/TuplesKt;->resolveDefaults(Landroidx/compose/ui/text/TextStyle;Landroidx/compose/ui/unit/LayoutDirection;)Landroidx/compose/ui/text/TextStyle;
+HSPLkotlin/TuplesKt;->runtimeCheck(Z)V
+HSPLkotlin/TuplesKt;->until(II)Lkotlin/ranges/IntRange;
+HSPLkotlin/ULong$Companion;-><init>()V
+HSPLkotlin/ULong$Companion;-><init>(I)V
+HSPLkotlin/ULong$Companion;-><init>(II)V
+HSPLkotlin/ULong$Companion;->checkElementIndex$kotlin_stdlib(II)V
+HSPLkotlin/ULong$Companion;->computeScaleFactor-H7hwNQA(JJ)J
+HSPLkotlin/ULong$Companion;->dispatch$lifecycle_runtime_release(Landroid/app/Activity;Landroidx/lifecycle/Lifecycle$Event;)V
+HSPLkotlin/ULong$Companion;->getHolderForHierarchy(Landroid/view/View;)Landroidx/metrics/performance/PerformanceMetricsState$Holder;
+HSPLkotlin/ULong$Companion;->injectIfNeededIn(Landroid/app/Activity;)V
+HSPLkotlin/UNINITIALIZED_VALUE;-><clinit>()V
+HSPLkotlin/Unit;-><clinit>()V
+HSPLkotlin/UnsafeLazyImpl;-><init>(Lkotlin/jvm/functions/Function0;)V
+HSPLkotlin/UnsafeLazyImpl;->getValue()Ljava/lang/Object;
+HSPLkotlin/collections/AbstractCollection;->isEmpty()Z
+HSPLkotlin/collections/AbstractCollection;->size()I
+HSPLkotlin/collections/AbstractList;->equals(Ljava/lang/Object;)Z
+HSPLkotlin/collections/AbstractMap$toString$1;-><init>(ILjava/lang/Object;)V
+HSPLkotlin/collections/AbstractMap$toString$1;->invoke()Landroidx/compose/runtime/DisposableEffectResult;
+HSPLkotlin/collections/AbstractMap$toString$1;->invoke(F)Ljava/lang/Float;
+HSPLkotlin/collections/AbstractMap$toString$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlin/collections/AbstractMap$toString$1;->invoke(Ljava/lang/Object;)V
+HSPLkotlin/collections/AbstractMap;->entrySet()Ljava/util/Set;
+HSPLkotlin/collections/AbstractMap;->equals(Ljava/lang/Object;)Z
+HSPLkotlin/collections/AbstractMap;->size()I
+HSPLkotlin/collections/AbstractMutableList;-><init>()V
+HSPLkotlin/collections/AbstractMutableList;->size()I
+HSPLkotlin/collections/AbstractSet;->equals(Ljava/lang/Object;)Z
+HSPLkotlin/collections/ArrayDeque;-><clinit>()V
+HSPLkotlin/collections/ArrayDeque;-><init>()V
+HSPLkotlin/collections/ArrayDeque;->addLast(Ljava/lang/Object;)V
+HSPLkotlin/collections/ArrayDeque;->ensureCapacity(I)V
+HSPLkotlin/collections/ArrayDeque;->first()Ljava/lang/Object;
+HSPLkotlin/collections/ArrayDeque;->get(I)Ljava/lang/Object;
+HSPLkotlin/collections/ArrayDeque;->getSize()I
+HSPLkotlin/collections/ArrayDeque;->incremented(I)I
+HSPLkotlin/collections/ArrayDeque;->isEmpty()Z
+HSPLkotlin/collections/ArrayDeque;->positiveMod(I)I
+HSPLkotlin/collections/ArrayDeque;->removeFirst()Ljava/lang/Object;
+HSPLkotlin/collections/ArraysKt___ArraysKt;->asList([Ljava/lang/Object;)Ljava/util/List;
+HSPLkotlin/collections/ArraysKt___ArraysKt;->collectionSizeOrDefault(Ljava/lang/Iterable;)I
+HSPLkotlin/collections/ArraysKt___ArraysKt;->copyInto$default([I[III)V
+HSPLkotlin/collections/ArraysKt___ArraysKt;->copyInto$default([Ljava/lang/Object;[Ljava/lang/Object;III)V
+HSPLkotlin/collections/ArraysKt___ArraysKt;->copyInto([I[IIII)V
+HSPLkotlin/collections/ArraysKt___ArraysKt;->copyInto([Ljava/lang/Object;[Ljava/lang/Object;III)V
+HSPLkotlin/collections/ArraysKt___ArraysKt;->fill$default([Ljava/lang/Object;)V
+HSPLkotlin/collections/ArraysKt___ArraysKt;->fill(II[Ljava/lang/Object;)V
+HSPLkotlin/collections/ArraysKt___ArraysKt;->indexOf([Ljava/lang/Object;Ljava/lang/Object;)I
+HSPLkotlin/collections/CollectionsKt__MutableCollectionsJVMKt;->sortWith(Ljava/util/List;Ljava/util/Comparator;)V
+HSPLkotlin/collections/CollectionsKt__ReversedViewsKt;->addAll(Ljava/lang/Iterable;Ljava/util/Collection;)V
+HSPLkotlin/collections/CollectionsKt___CollectionsKt;->firstOrNull(Ljava/util/List;)Ljava/lang/Object;
+HSPLkotlin/collections/CollectionsKt___CollectionsKt;->last(Ljava/util/List;)Ljava/lang/Object;
+HSPLkotlin/collections/CollectionsKt___CollectionsKt;->plus(Ljava/util/List;Ljava/io/Serializable;)Ljava/util/ArrayList;
+HSPLkotlin/collections/CollectionsKt___CollectionsKt;->toIntArray(Ljava/util/ArrayList;)[I
+HSPLkotlin/collections/EmptyList;-><clinit>()V
+HSPLkotlin/collections/EmptyList;->contains(Ljava/lang/Object;)Z
+HSPLkotlin/collections/EmptyList;->isEmpty()Z
+HSPLkotlin/collections/EmptyList;->size()I
+HSPLkotlin/collections/EmptyList;->toArray()[Ljava/lang/Object;
+HSPLkotlin/collections/EmptyMap;-><clinit>()V
+HSPLkotlin/collections/EmptyMap;->isEmpty()Z
+HSPLkotlin/collections/EmptyMap;->size()I
+HSPLkotlin/coroutines/AbstractCoroutineContextElement;-><init>(Lkotlin/coroutines/CoroutineContext$Key;)V
+HSPLkotlin/coroutines/AbstractCoroutineContextElement;->fold(Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
+HSPLkotlin/coroutines/AbstractCoroutineContextElement;->get(Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext$Element;
+HSPLkotlin/coroutines/AbstractCoroutineContextElement;->getKey()Lkotlin/coroutines/CoroutineContext$Key;
+HSPLkotlin/coroutines/AbstractCoroutineContextElement;->minusKey(Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext;
+HSPLkotlin/coroutines/AbstractCoroutineContextElement;->plus(Lkotlin/coroutines/CoroutineContext;)Lkotlin/coroutines/CoroutineContext;
+HSPLkotlin/coroutines/AbstractCoroutineContextKey;-><init>(Lkotlin/coroutines/CoroutineContext$Key;Lkotlin/jvm/functions/Function1;)V
+HSPLkotlin/coroutines/CombinedContext;-><init>(Lkotlin/coroutines/CoroutineContext$Element;Lkotlin/coroutines/CoroutineContext;)V
+HSPLkotlin/coroutines/CombinedContext;->fold(Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
+HSPLkotlin/coroutines/CombinedContext;->minusKey(Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext;
+HSPLkotlin/coroutines/CombinedContext;->plus(Lkotlin/coroutines/CoroutineContext;)Lkotlin/coroutines/CoroutineContext;
+HSPLkotlin/coroutines/CoroutineContext$plus$1;-><clinit>()V
+HSPLkotlin/coroutines/CoroutineContext$plus$1;-><init>(I)V
+HSPLkotlin/coroutines/CoroutineContext$plus$1;->invoke(Landroidx/compose/runtime/Composer;I)V
+HSPLkotlin/coroutines/CoroutineContext$plus$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlin/coroutines/EmptyCoroutineContext;-><clinit>()V
+HSPLkotlin/coroutines/EmptyCoroutineContext;->fold(Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
+HSPLkotlin/coroutines/EmptyCoroutineContext;->plus(Lkotlin/coroutines/CoroutineContext;)Lkotlin/coroutines/CoroutineContext;
+HSPLkotlin/coroutines/intrinsics/CoroutineSingletons;-><clinit>()V
+HSPLkotlin/coroutines/intrinsics/CoroutineSingletons;-><init>(ILjava/lang/String;)V
+HSPLkotlin/coroutines/jvm/internal/BaseContinuationImpl;-><init>(Lkotlin/coroutines/Continuation;)V
+HSPLkotlin/coroutines/jvm/internal/BaseContinuationImpl;->resumeWith(Ljava/lang/Object;)V
+HSPLkotlin/coroutines/jvm/internal/CompletedContinuation;-><clinit>()V
+HSPLkotlin/coroutines/jvm/internal/ContinuationImpl;-><init>(Lkotlin/coroutines/Continuation;)V
+HSPLkotlin/coroutines/jvm/internal/ContinuationImpl;-><init>(Lkotlin/coroutines/Continuation;Lkotlin/coroutines/CoroutineContext;)V
+HSPLkotlin/coroutines/jvm/internal/ContinuationImpl;->getContext()Lkotlin/coroutines/CoroutineContext;
+HSPLkotlin/coroutines/jvm/internal/ContinuationImpl;->releaseIntercepted()V
+HSPLkotlin/coroutines/jvm/internal/SuspendLambda;-><init>(ILkotlin/coroutines/Continuation;)V
+HSPLkotlin/coroutines/jvm/internal/SuspendLambda;->getArity()I
+HSPLkotlin/jvm/internal/ArrayIterator;-><init>(ILjava/lang/Object;)V
+HSPLkotlin/jvm/internal/ArrayIterator;->hasNext()Z
+HSPLkotlin/jvm/internal/ArrayIterator;->next()Ljava/lang/Object;
+HSPLkotlin/jvm/internal/CallableReference$NoReceiver;-><clinit>()V
+HSPLkotlin/jvm/internal/CallableReference;-><init>(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Z)V
+HSPLkotlin/jvm/internal/ClassReference;-><clinit>()V
+HSPLkotlin/jvm/internal/ClassReference;-><init>(Ljava/lang/Class;)V
+HSPLkotlin/jvm/internal/ClassReference;->getJClass()Ljava/lang/Class;
+HSPLkotlin/jvm/internal/FunctionReferenceImpl;-><init>(ILjava/lang/Class;Ljava/lang/String;Ljava/lang/String;I)V
+HSPLkotlin/jvm/internal/Lambda;-><init>(I)V
+HSPLkotlin/jvm/internal/Lambda;->getArity()I
+HSPLkotlin/jvm/internal/PropertyReference0Impl;->invoke()Ljava/lang/Object;
+HSPLkotlin/jvm/internal/PropertyReference;-><init>(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;I)V
+HSPLkotlin/jvm/internal/PropertyReference;->equals(Ljava/lang/Object;)Z
+HSPLkotlin/jvm/internal/Reflection;-><clinit>()V
+HSPLkotlin/jvm/internal/Reflection;->getOrCreateKotlinClass(Ljava/lang/Class;)Lkotlin/jvm/internal/ClassReference;
+HSPLkotlin/random/FallbackThreadLocalRandom$implStorage$1;-><init>(I)V
+HSPLkotlin/ranges/IntProgression;-><init>(III)V
+HSPLkotlin/ranges/IntProgression;->iterator()Ljava/util/Iterator;
+HSPLkotlin/ranges/IntProgressionIterator;-><init>(III)V
+HSPLkotlin/ranges/IntProgressionIterator;->hasNext()Z
+HSPLkotlin/ranges/IntProgressionIterator;->nextInt()I
+HSPLkotlin/ranges/IntRange;-><clinit>()V
+HSPLkotlin/ranges/IntRange;-><init>(II)V
+HSPLkotlin/ranges/IntRange;->equals(Ljava/lang/Object;)Z
+HSPLkotlin/ranges/IntRange;->isEmpty()Z
+HSPLkotlin/sequences/ConstrainedOnceSequence;-><init>(Lkotlin/sequences/SequencesKt__SequencesKt$asSequence$$inlined$Sequence$1;)V
+HSPLkotlin/sequences/ConstrainedOnceSequence;->iterator()Ljava/util/Iterator;
+HSPLkotlin/sequences/FilteringSequence$iterator$1;-><init>(Lkotlin/sequences/FilteringSequence;)V
+HSPLkotlin/sequences/FilteringSequence$iterator$1;->calcNext()V
+HSPLkotlin/sequences/FilteringSequence$iterator$1;->hasNext()Z
+HSPLkotlin/sequences/FilteringSequence$iterator$1;->next()Ljava/lang/Object;
+HSPLkotlin/sequences/FilteringSequence;-><init>(Lkotlin/sequences/GeneratorSequence;)V
+HSPLkotlin/sequences/GeneratorSequence$iterator$1;-><init>(Lkotlin/sequences/GeneratorSequence;)V
+HSPLkotlin/sequences/GeneratorSequence$iterator$1;->calcNext()V
+HSPLkotlin/sequences/GeneratorSequence$iterator$1;->hasNext()Z
+HSPLkotlin/sequences/GeneratorSequence$iterator$1;->next()Ljava/lang/Object;
+HSPLkotlin/sequences/GeneratorSequence;-><init>(Landroidx/compose/ui/node/LayoutNode$_foldedChildren$1;Lkotlin/jvm/functions/Function1;)V
+HSPLkotlin/sequences/GeneratorSequence;-><init>(Lkotlin/sequences/Sequence;Lkotlin/jvm/functions/Function1;)V
+HSPLkotlin/sequences/GeneratorSequence;->iterator()Ljava/util/Iterator;
+HSPLkotlin/sequences/SequencesKt;->firstOrNull(Lkotlin/sequences/FilteringSequence;)Ljava/lang/Object;
+HSPLkotlin/sequences/SequencesKt;->mapNotNull(Lkotlin/sequences/Sequence;Lkotlinx/coroutines/CoroutineDispatcher$Key$1;)Lkotlin/sequences/FilteringSequence;
+HSPLkotlin/sequences/SequencesKt;->toList(Lkotlin/sequences/Sequence;)Ljava/util/List;
+HSPLkotlin/sequences/SequencesKt__SequencesKt$asSequence$$inlined$Sequence$1;-><init>(ILjava/lang/Object;)V
+HSPLkotlin/sequences/SequencesKt__SequencesKt$asSequence$$inlined$Sequence$1;->iterator()Ljava/util/Iterator;
+HSPLkotlin/sequences/TransformingSequence$iterator$1;-><init>(Lkotlin/sequences/GeneratorSequence;)V
+HSPLkotlin/sequences/TransformingSequence$iterator$1;->hasNext()Z
+HSPLkotlin/sequences/TransformingSequence$iterator$1;->next()Ljava/lang/Object;
+HSPLkotlin/text/StringsKt__IndentKt$getIndentFunction$2;-><init>(ILjava/lang/String;)V
+HSPLkotlin/text/StringsKt__RegexExtensionsKt;->generateSequence(Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)Lkotlin/sequences/Sequence;
+HSPLkotlin/text/StringsKt__StringsKt;->endsWith$default(Ljava/lang/CharSequence;Ljava/lang/String;)Z
+HSPLkotlin/text/StringsKt__StringsKt;->getLastIndex(Ljava/lang/CharSequence;)I
+HSPLkotlin/text/StringsKt__StringsKt;->indexOf(Ljava/lang/CharSequence;Ljava/lang/String;IZ)I
+HSPLkotlin/text/StringsKt__StringsKt;->isBlank(Ljava/lang/CharSequence;)Z
+HSPLkotlin/text/StringsKt__StringsKt;->replace$default(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
+HSPLkotlin/text/StringsKt__StringsKt;->substringAfterLast$default(Ljava/lang/String;)Ljava/lang/String;
+HSPLkotlin/text/StringsKt___StringsKt;->last(Ljava/lang/CharSequence;)C
+HSPLkotlinx/coroutines/AbstractCoroutine;-><init>(Lkotlin/coroutines/CoroutineContext;Z)V
+HSPLkotlinx/coroutines/AbstractCoroutine;->getContext()Lkotlin/coroutines/CoroutineContext;
+HSPLkotlinx/coroutines/AbstractCoroutine;->getCoroutineContext()Lkotlin/coroutines/CoroutineContext;
+HSPLkotlinx/coroutines/AbstractCoroutine;->isActive()Z
+HSPLkotlinx/coroutines/AbstractCoroutine;->onCancelled(Ljava/lang/Throwable;Z)V
+HSPLkotlinx/coroutines/AbstractCoroutine;->onCompleted(Ljava/lang/Object;)V
+HSPLkotlinx/coroutines/AbstractCoroutine;->onCompletionInternal(Ljava/lang/Object;)V
+HSPLkotlinx/coroutines/AbstractCoroutine;->resumeWith(Ljava/lang/Object;)V
+HSPLkotlinx/coroutines/AbstractCoroutine;->start$enumunboxing$(ILkotlinx/coroutines/AbstractCoroutine;Lkotlin/jvm/functions/Function2;)V
+HSPLkotlinx/coroutines/Active;-><clinit>()V
+HSPLkotlinx/coroutines/BlockingEventLoop;-><init>(Ljava/lang/Thread;)V
+HSPLkotlinx/coroutines/CancelHandler;-><init>()V
+HSPLkotlinx/coroutines/CancellableContinuationImpl;-><clinit>()V
+HSPLkotlinx/coroutines/CancellableContinuationImpl;-><init>(ILkotlin/coroutines/Continuation;)V
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->callCancelHandler(Lkotlinx/coroutines/CancelHandler;Ljava/lang/Throwable;)V
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->callSegmentOnCancellation(Lkotlinx/coroutines/internal/Segment;Ljava/lang/Throwable;)V
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->cancel(Ljava/lang/Throwable;)Z
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->completeResume(Ljava/lang/Object;)V
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->detachChild$kotlinx_coroutines_core()V
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->dispatchResume(I)V
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->getContinuationCancellationCause(Lkotlinx/coroutines/JobSupport;)Ljava/lang/Throwable;
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->getDelegate$kotlinx_coroutines_core()Lkotlin/coroutines/Continuation;
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->getExceptionalResult$kotlinx_coroutines_core(Ljava/lang/Object;)Ljava/lang/Throwable;
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->getResult()Ljava/lang/Object;
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->getSuccessfulResult$kotlinx_coroutines_core(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->initCancellability()V
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->installParentHandle()Lkotlinx/coroutines/DisposableHandle;
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->invokeOnCancellation(Lkotlin/jvm/functions/Function1;)V
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->invokeOnCancellation(Lkotlinx/coroutines/internal/Segment;I)V
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->invokeOnCancellationImpl(Ljava/lang/Object;)V
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->isReusable()Z
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->releaseClaimedReusableContinuation$kotlinx_coroutines_core()V
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->resumeImpl(Ljava/lang/Object;ILkotlin/jvm/functions/Function1;)V
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->resumeWith(Ljava/lang/Object;)V
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->resumedState(Lkotlinx/coroutines/NotCompleted;Ljava/lang/Object;ILkotlin/jvm/functions/Function1;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->takeState$kotlinx_coroutines_core()Ljava/lang/Object;
+HSPLkotlinx/coroutines/CancellableContinuationImpl;->tryResume(Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)Lkotlinx/coroutines/internal/Symbol;
+HSPLkotlinx/coroutines/CancelledContinuation;-><clinit>()V
+HSPLkotlinx/coroutines/CancelledContinuation;-><init>(Lkotlin/coroutines/Continuation;Ljava/lang/Throwable;Z)V
+HSPLkotlinx/coroutines/ChildContinuation;-><init>(Lkotlinx/coroutines/CancellableContinuationImpl;)V
+HSPLkotlinx/coroutines/ChildContinuation;->invoke(Ljava/lang/Throwable;)V
+HSPLkotlinx/coroutines/ChildHandleNode;-><init>(Lkotlinx/coroutines/JobSupport;)V
+HSPLkotlinx/coroutines/ChildHandleNode;->childCancelled(Ljava/lang/Throwable;)Z
+HSPLkotlinx/coroutines/ChildHandleNode;->invoke(Ljava/lang/Throwable;)V
+HSPLkotlinx/coroutines/CompletedContinuation;-><init>(Ljava/lang/Object;Lkotlinx/coroutines/CancelHandler;Lkotlin/jvm/functions/Function1;Ljava/lang/Object;Ljava/lang/Throwable;)V
+HSPLkotlinx/coroutines/CompletedContinuation;-><init>(Ljava/lang/Object;Lkotlinx/coroutines/CancelHandler;Lkotlin/jvm/functions/Function1;Ljava/util/concurrent/CancellationException;I)V
+HSPLkotlinx/coroutines/CompletedExceptionally;-><clinit>()V
+HSPLkotlinx/coroutines/CompletedExceptionally;-><init>(Ljava/lang/Throwable;Z)V
+HSPLkotlinx/coroutines/CoroutineContextKt$foldCopies$1;-><clinit>()V
+HSPLkotlinx/coroutines/CoroutineContextKt$foldCopies$1;-><init>(I)V
+HSPLkotlinx/coroutines/CoroutineContextKt$foldCopies$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/CoroutineDispatcher$Key$1;-><clinit>()V
+HSPLkotlinx/coroutines/CoroutineDispatcher$Key$1;-><init>(I)V
+HSPLkotlinx/coroutines/CoroutineDispatcher$Key$1;->invoke(Landroid/view/View;)Landroid/view/View;
+HSPLkotlinx/coroutines/CoroutineDispatcher$Key$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/CoroutineDispatcher$Key;-><init>(I)V
+HSPLkotlinx/coroutines/CoroutineDispatcher;-><clinit>()V
+HSPLkotlinx/coroutines/CoroutineDispatcher;-><init>()V
+HSPLkotlinx/coroutines/CoroutineDispatcher;->get(Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext$Element;
+HSPLkotlinx/coroutines/CoroutineDispatcher;->isDispatchNeeded()Z
+HSPLkotlinx/coroutines/CoroutineDispatcher;->minusKey(Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext;
+HSPLkotlinx/coroutines/DefaultExecutor;-><clinit>()V
+HSPLkotlinx/coroutines/DefaultExecutorKt;-><clinit>()V
+HSPLkotlinx/coroutines/DispatchedTask;-><init>(I)V
+HSPLkotlinx/coroutines/DispatchedTask;->getExceptionalResult$kotlinx_coroutines_core(Ljava/lang/Object;)Ljava/lang/Throwable;
+HSPLkotlinx/coroutines/DispatchedTask;->getSuccessfulResult$kotlinx_coroutines_core(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/DispatchedTask;->handleFatalException(Ljava/lang/Throwable;Ljava/lang/Throwable;)V
+HSPLkotlinx/coroutines/DispatchedTask;->run()V
+HSPLkotlinx/coroutines/Dispatchers;-><clinit>()V
+HSPLkotlinx/coroutines/Empty;-><init>(Z)V
+HSPLkotlinx/coroutines/Empty;->getList()Lkotlinx/coroutines/NodeList;
+HSPLkotlinx/coroutines/Empty;->isActive()Z
+HSPLkotlinx/coroutines/EventLoopImplBase;-><clinit>()V
+HSPLkotlinx/coroutines/EventLoopImplBase;-><init>()V
+HSPLkotlinx/coroutines/EventLoopImplPlatform;-><init>()V
+HSPLkotlinx/coroutines/EventLoopImplPlatform;->decrementUseCount(Z)V
+HSPLkotlinx/coroutines/EventLoopImplPlatform;->incrementUseCount(Z)V
+HSPLkotlinx/coroutines/EventLoopImplPlatform;->isUnconfinedLoopActive()Z
+HSPLkotlinx/coroutines/EventLoopImplPlatform;->processUnconfinedEvent()Z
+HSPLkotlinx/coroutines/ExecutorCoroutineDispatcher$Key$1;-><clinit>()V
+HSPLkotlinx/coroutines/ExecutorCoroutineDispatcher$Key$1;-><init>(I)V
+HSPLkotlinx/coroutines/ExecutorCoroutineDispatcher$Key$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/ExecutorCoroutineDispatcher;-><clinit>()V
+HSPLkotlinx/coroutines/GlobalScope;-><clinit>()V
+HSPLkotlinx/coroutines/GlobalScope;->getCoroutineContext()Lkotlin/coroutines/CoroutineContext;
+HSPLkotlinx/coroutines/InvokeOnCancel;-><init>(ILjava/lang/Object;)V
+HSPLkotlinx/coroutines/InvokeOnCancel;->invoke(Ljava/lang/Throwable;)V
+HSPLkotlinx/coroutines/InvokeOnCompletion;-><init>(ILjava/lang/Object;)V
+HSPLkotlinx/coroutines/JobImpl;-><init>(Lkotlinx/coroutines/Job;)V
+HSPLkotlinx/coroutines/JobImpl;->getHandlesException$kotlinx_coroutines_core()Z
+HSPLkotlinx/coroutines/JobImpl;->getOnCancelComplete$kotlinx_coroutines_core()Z
+HSPLkotlinx/coroutines/JobNode;-><init>()V
+HSPLkotlinx/coroutines/JobNode;->dispose()V
+HSPLkotlinx/coroutines/JobNode;->getJob()Lkotlinx/coroutines/JobSupport;
+HSPLkotlinx/coroutines/JobNode;->getList()Lkotlinx/coroutines/NodeList;
+HSPLkotlinx/coroutines/JobNode;->isActive()Z
+HSPLkotlinx/coroutines/JobSupport$ChildCompletion;-><init>(Lkotlinx/coroutines/JobSupport;Lkotlinx/coroutines/JobSupport$Finishing;Lkotlinx/coroutines/ChildHandleNode;Ljava/lang/Object;)V
+HSPLkotlinx/coroutines/JobSupport$ChildCompletion;->invoke(Ljava/lang/Throwable;)V
+HSPLkotlinx/coroutines/JobSupport$Finishing;-><clinit>()V
+HSPLkotlinx/coroutines/JobSupport$Finishing;-><init>(Lkotlinx/coroutines/NodeList;Ljava/lang/Throwable;)V
+HSPLkotlinx/coroutines/JobSupport$Finishing;->addExceptionLocked(Ljava/lang/Throwable;)V
+HSPLkotlinx/coroutines/JobSupport$Finishing;->getList()Lkotlinx/coroutines/NodeList;
+HSPLkotlinx/coroutines/JobSupport$Finishing;->getRootCause()Ljava/lang/Throwable;
+HSPLkotlinx/coroutines/JobSupport$Finishing;->isCancelling()Z
+HSPLkotlinx/coroutines/JobSupport$Finishing;->isCompleting()Z
+HSPLkotlinx/coroutines/JobSupport$Finishing;->sealLocked(Ljava/lang/Throwable;)Ljava/util/ArrayList;
+HSPLkotlinx/coroutines/JobSupport$addLastAtomic$$inlined$addLastIf$1;-><init>(Lkotlinx/coroutines/internal/LockFreeLinkedListNode;Lkotlinx/coroutines/JobSupport;Ljava/lang/Object;)V
+HSPLkotlinx/coroutines/JobSupport$addLastAtomic$$inlined$addLastIf$1;->complete(Ljava/lang/Object;Ljava/lang/Object;)V
+HSPLkotlinx/coroutines/JobSupport$addLastAtomic$$inlined$addLastIf$1;->prepare(Ljava/lang/Object;)Lkotlinx/coroutines/internal/Symbol;
+HSPLkotlinx/coroutines/JobSupport;-><clinit>()V
+HSPLkotlinx/coroutines/JobSupport;-><init>(Z)V
+HSPLkotlinx/coroutines/JobSupport;->addLastAtomic(Ljava/lang/Object;Lkotlinx/coroutines/NodeList;Lkotlinx/coroutines/JobNode;)Z
+HSPLkotlinx/coroutines/JobSupport;->afterCompletion(Ljava/lang/Object;)V
+HSPLkotlinx/coroutines/JobSupport;->afterResume(Ljava/lang/Object;)V
+HSPLkotlinx/coroutines/JobSupport;->cancel(Ljava/util/concurrent/CancellationException;)V
+HSPLkotlinx/coroutines/JobSupport;->cancelImpl$kotlinx_coroutines_core(Ljava/lang/Object;)Z
+HSPLkotlinx/coroutines/JobSupport;->cancelInternal(Ljava/util/concurrent/CancellationException;)V
+HSPLkotlinx/coroutines/JobSupport;->cancelParent(Ljava/lang/Throwable;)Z
+HSPLkotlinx/coroutines/JobSupport;->childCancelled(Ljava/lang/Throwable;)Z
+HSPLkotlinx/coroutines/JobSupport;->completeStateFinalization(Lkotlinx/coroutines/Incomplete;Ljava/lang/Object;)V
+HSPLkotlinx/coroutines/JobSupport;->createCauseException(Ljava/lang/Object;)Ljava/lang/Throwable;
+HSPLkotlinx/coroutines/JobSupport;->finalizeFinishingState(Lkotlinx/coroutines/JobSupport$Finishing;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/JobSupport;->fold(Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/JobSupport;->get(Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext$Element;
+HSPLkotlinx/coroutines/JobSupport;->getCancellationException()Ljava/util/concurrent/CancellationException;
+HSPLkotlinx/coroutines/JobSupport;->getFinalRootCause(Lkotlinx/coroutines/JobSupport$Finishing;Ljava/util/ArrayList;)Ljava/lang/Throwable;
+HSPLkotlinx/coroutines/JobSupport;->getKey()Lkotlin/coroutines/CoroutineContext$Key;
+HSPLkotlinx/coroutines/JobSupport;->getOnCancelComplete$kotlinx_coroutines_core()Z
+HSPLkotlinx/coroutines/JobSupport;->getOrPromoteCancellingList(Lkotlinx/coroutines/Incomplete;)Lkotlinx/coroutines/NodeList;
+HSPLkotlinx/coroutines/JobSupport;->getState$kotlinx_coroutines_core()Ljava/lang/Object;
+HSPLkotlinx/coroutines/JobSupport;->initParentJob(Lkotlinx/coroutines/Job;)V
+HSPLkotlinx/coroutines/JobSupport;->invokeOnCompletion(ZZLkotlin/jvm/functions/Function1;)Lkotlinx/coroutines/DisposableHandle;
+HSPLkotlinx/coroutines/JobSupport;->isActive()Z
+HSPLkotlinx/coroutines/JobSupport;->isScopedCoroutine()Z
+HSPLkotlinx/coroutines/JobSupport;->makeCompletingOnce$kotlinx_coroutines_core(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/JobSupport;->minusKey(Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext;
+HSPLkotlinx/coroutines/JobSupport;->nextChild(Lkotlinx/coroutines/internal/LockFreeLinkedListNode;)Lkotlinx/coroutines/ChildHandleNode;
+HSPLkotlinx/coroutines/JobSupport;->notifyCancelling(Lkotlinx/coroutines/NodeList;Ljava/lang/Throwable;)V
+HSPLkotlinx/coroutines/JobSupport;->onCompletionInternal(Ljava/lang/Object;)V
+HSPLkotlinx/coroutines/JobSupport;->plus(Lkotlin/coroutines/CoroutineContext;)Lkotlin/coroutines/CoroutineContext;
+HSPLkotlinx/coroutines/JobSupport;->promoteSingleToNodeList(Lkotlinx/coroutines/JobNode;)V
+HSPLkotlinx/coroutines/JobSupport;->startInternal(Ljava/lang/Object;)I
+HSPLkotlinx/coroutines/JobSupport;->tryMakeCompleting(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/JobSupport;->tryWaitForChild(Lkotlinx/coroutines/JobSupport$Finishing;Lkotlinx/coroutines/ChildHandleNode;Ljava/lang/Object;)Z
+HSPLkotlinx/coroutines/NodeList;-><init>()V
+HSPLkotlinx/coroutines/NodeList;->getList()Lkotlinx/coroutines/NodeList;
+HSPLkotlinx/coroutines/NodeList;->isActive()Z
+HSPLkotlinx/coroutines/NodeList;->isRemoved()Z
+HSPLkotlinx/coroutines/NonDisposableHandle;-><clinit>()V
+HSPLkotlinx/coroutines/NonDisposableHandle;->dispose()V
+HSPLkotlinx/coroutines/ThreadLocalEventLoop;-><clinit>()V
+HSPLkotlinx/coroutines/ThreadLocalEventLoop;->getEventLoop$kotlinx_coroutines_core()Lkotlinx/coroutines/EventLoopImplPlatform;
+HSPLkotlinx/coroutines/Unconfined;-><clinit>()V
+HSPLkotlinx/coroutines/UndispatchedCoroutine;-><init>(Lkotlin/coroutines/Continuation;Lkotlin/coroutines/CoroutineContext;)V
+HSPLkotlinx/coroutines/UndispatchedMarker;-><clinit>()V
+HSPLkotlinx/coroutines/UndispatchedMarker;->fold(Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/UndispatchedMarker;->get(Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext$Element;
+HSPLkotlinx/coroutines/UndispatchedMarker;->getKey()Lkotlin/coroutines/CoroutineContext$Key;
+HSPLkotlinx/coroutines/android/AndroidDispatcherFactory;-><init>()V
+HSPLkotlinx/coroutines/android/AndroidDispatcherFactory;->createDispatcher(Ljava/util/List;)Lkotlinx/coroutines/MainCoroutineDispatcher;
+HSPLkotlinx/coroutines/android/HandlerContext;-><init>(Landroid/os/Handler;)V
+HSPLkotlinx/coroutines/android/HandlerContext;-><init>(Landroid/os/Handler;Ljava/lang/String;Z)V
+HSPLkotlinx/coroutines/android/HandlerContext;->dispatch(Lkotlin/coroutines/CoroutineContext;Ljava/lang/Runnable;)V
+HSPLkotlinx/coroutines/android/HandlerContext;->isDispatchNeeded()Z
+HSPLkotlinx/coroutines/android/HandlerDispatcherKt;-><clinit>()V
+HSPLkotlinx/coroutines/android/HandlerDispatcherKt;->asHandler(Landroid/os/Looper;)Landroid/os/Handler;
+HSPLkotlinx/coroutines/channels/BufferOverflow;-><clinit>()V
+HSPLkotlinx/coroutines/channels/BufferOverflow;-><init>(ILjava/lang/String;)V
+HSPLkotlinx/coroutines/channels/BufferedChannel$BufferedChannelIterator;-><init>(Lkotlinx/coroutines/channels/BufferedChannel;)V
+HSPLkotlinx/coroutines/channels/BufferedChannel$BufferedChannelIterator;->hasNext(Lkotlin/coroutines/jvm/internal/ContinuationImpl;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/channels/BufferedChannel$BufferedChannelIterator;->invokeOnCancellation(Lkotlinx/coroutines/internal/Segment;I)V
+HSPLkotlinx/coroutines/channels/BufferedChannel$BufferedChannelIterator;->next()Ljava/lang/Object;
+HSPLkotlinx/coroutines/channels/BufferedChannel;-><clinit>()V
+HSPLkotlinx/coroutines/channels/BufferedChannel;-><init>(ILkotlin/jvm/functions/Function1;)V
+HSPLkotlinx/coroutines/channels/BufferedChannel;->access$findSegmentSend(Lkotlinx/coroutines/channels/BufferedChannel;JLkotlinx/coroutines/channels/ChannelSegment;)Lkotlinx/coroutines/channels/ChannelSegment;
+HSPLkotlinx/coroutines/channels/BufferedChannel;->access$updateCellSend(Lkotlinx/coroutines/channels/BufferedChannel;Lkotlinx/coroutines/channels/ChannelSegment;ILjava/lang/Object;JLjava/lang/Object;Z)I
+HSPLkotlinx/coroutines/channels/BufferedChannel;->bufferOrRendezvousSend(J)Z
+HSPLkotlinx/coroutines/channels/BufferedChannel;->dropFirstElementUntilTheSpecifiedCellIsInTheBuffer(J)V
+HSPLkotlinx/coroutines/channels/BufferedChannel;->expandBuffer()V
+HSPLkotlinx/coroutines/channels/BufferedChannel;->findSegmentReceive(JLkotlinx/coroutines/channels/ChannelSegment;)Lkotlinx/coroutines/channels/ChannelSegment;
+HSPLkotlinx/coroutines/channels/BufferedChannel;->getBufferEndCounter()J
+HSPLkotlinx/coroutines/channels/BufferedChannel;->getReceiversCounter$kotlinx_coroutines_core()J
+HSPLkotlinx/coroutines/channels/BufferedChannel;->getSendersCounter$kotlinx_coroutines_core()J
+HSPLkotlinx/coroutines/channels/BufferedChannel;->incCompletedExpandBufferAttempts(J)V
+HSPLkotlinx/coroutines/channels/BufferedChannel;->isClosed(JZ)Z
+HSPLkotlinx/coroutines/channels/BufferedChannel;->isClosedForReceive()Z
+HSPLkotlinx/coroutines/channels/BufferedChannel;->isRendezvousOrUnlimited()Z
+HSPLkotlinx/coroutines/channels/BufferedChannel;->iterator()Lkotlinx/coroutines/channels/BufferedChannel$BufferedChannelIterator;
+HSPLkotlinx/coroutines/channels/BufferedChannel;->receive(Lkotlin/coroutines/jvm/internal/SuspendLambda;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/channels/BufferedChannel;->send(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/channels/BufferedChannel;->tryReceive-PtdJZtk()Ljava/lang/Object;
+HSPLkotlinx/coroutines/channels/BufferedChannel;->tryResumeReceiver(Ljava/lang/Object;Ljava/lang/Object;)Z
+HSPLkotlinx/coroutines/channels/BufferedChannel;->updateCellReceive(Lkotlinx/coroutines/channels/ChannelSegment;IJLjava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/channels/BufferedChannel;->waitExpandBufferCompletion$kotlinx_coroutines_core(J)V
+HSPLkotlinx/coroutines/channels/BufferedChannelKt$createSegmentFunction$1;-><clinit>()V
+HSPLkotlinx/coroutines/channels/BufferedChannelKt$createSegmentFunction$1;-><init>()V
+HSPLkotlinx/coroutines/channels/BufferedChannelKt$createSegmentFunction$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/channels/BufferedChannelKt;-><clinit>()V
+HSPLkotlinx/coroutines/channels/BufferedChannelKt;->tryResume0(Lkotlinx/coroutines/CancellableContinuation;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)Z
+HSPLkotlinx/coroutines/channels/Channel$Factory;-><clinit>()V
+HSPLkotlinx/coroutines/channels/Channel;-><clinit>()V
+HSPLkotlinx/coroutines/channels/ChannelSegment;-><init>(JLkotlinx/coroutines/channels/ChannelSegment;Lkotlinx/coroutines/channels/BufferedChannel;I)V
+HSPLkotlinx/coroutines/channels/ChannelSegment;->casState$kotlinx_coroutines_core(Ljava/lang/Object;ILjava/lang/Object;)Z
+HSPLkotlinx/coroutines/channels/ChannelSegment;->getNumberOfSlots()I
+HSPLkotlinx/coroutines/channels/ChannelSegment;->getState$kotlinx_coroutines_core(I)Ljava/lang/Object;
+HSPLkotlinx/coroutines/channels/ChannelSegment;->onCancellation(ILkotlin/coroutines/CoroutineContext;)V
+HSPLkotlinx/coroutines/channels/ChannelSegment;->onCancelledRequest(IZ)V
+HSPLkotlinx/coroutines/channels/ChannelSegment;->retrieveElement$kotlinx_coroutines_core(I)Ljava/lang/Object;
+HSPLkotlinx/coroutines/channels/ChannelSegment;->setElementLazy(ILjava/lang/Object;)V
+HSPLkotlinx/coroutines/channels/ChannelSegment;->setState$kotlinx_coroutines_core(ILkotlinx/coroutines/internal/Symbol;)V
+HSPLkotlinx/coroutines/channels/ConflatedBufferedChannel;-><init>(ILkotlinx/coroutines/channels/BufferOverflow;Lkotlin/jvm/functions/Function1;)V
+HSPLkotlinx/coroutines/channels/ConflatedBufferedChannel;->trySend-JP2dKIU(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/channels/ConflatedBufferedChannel;->trySendImpl-Mj0NB7M(Ljava/lang/Object;Z)Ljava/lang/Object;
+HSPLkotlinx/coroutines/channels/ProducerCoroutine;-><init>(Lkotlin/coroutines/CoroutineContext;Lkotlinx/coroutines/channels/BufferedChannel;)V
+HSPLkotlinx/coroutines/channels/ProducerCoroutine;->iterator()Lkotlinx/coroutines/channels/BufferedChannel$BufferedChannelIterator;
+HSPLkotlinx/coroutines/channels/ProducerCoroutine;->send(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/AbstractFlow$collect$1;-><init>(Lkotlinx/coroutines/flow/SafeFlow;Lkotlin/coroutines/Continuation;)V
+HSPLkotlinx/coroutines/flow/DistinctFlowImpl$collect$2$emit$1;-><init>(Lkotlinx/coroutines/flow/DistinctFlowImpl$collect$2;Lkotlin/coroutines/Continuation;)V
+HSPLkotlinx/coroutines/flow/DistinctFlowImpl$collect$2;-><init>(Lkotlinx/coroutines/flow/DistinctFlowImpl;Lkotlin/jvm/internal/Ref$ObjectRef;Lkotlinx/coroutines/flow/FlowCollector;)V
+HSPLkotlinx/coroutines/flow/DistinctFlowImpl$collect$2;->emit(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/DistinctFlowImpl;-><init>(Lkotlinx/coroutines/flow/Flow;)V
+HSPLkotlinx/coroutines/flow/DistinctFlowImpl;->collect(Lkotlinx/coroutines/flow/FlowCollector;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/FlowKt__ChannelsKt$emitAllImpl$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/FlowKt__LimitKt$dropWhile$$inlined$unsafeFlow$1;-><init>(Lkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest;Lkotlinx/coroutines/flow/StartedWhileSubscribed$command$2;)V
+HSPLkotlinx/coroutines/flow/FlowKt__LimitKt$dropWhile$$inlined$unsafeFlow$1;->collect(Lkotlinx/coroutines/flow/FlowCollector;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/FlowKt__LimitKt$dropWhile$1$1$emit$1;-><init>(Lkotlinx/coroutines/flow/FlowKt__LimitKt$dropWhile$1$1;Lkotlin/coroutines/Continuation;)V
+HSPLkotlinx/coroutines/flow/FlowKt__LimitKt$dropWhile$1$1;-><init>(Lkotlin/jvm/internal/Ref$BooleanRef;Lkotlinx/coroutines/flow/FlowCollector;Lkotlin/jvm/functions/Function2;)V
+HSPLkotlinx/coroutines/flow/FlowKt__LimitKt$dropWhile$1$1;->emit(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/FlowKt__MergeKt$mapLatest$1;-><init>(Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)V
+HSPLkotlinx/coroutines/flow/FlowKt__MergeKt$mapLatest$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/FlowKt__MergeKt$mapLatest$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/FlowKt__MergeKt;-><clinit>()V
+HSPLkotlinx/coroutines/flow/FlowKt__ReduceKt$first$$inlined$collectWhile$2$1;-><init>(Lkotlinx/coroutines/flow/FlowKt__ReduceKt$first$$inlined$collectWhile$2;Lkotlin/coroutines/Continuation;)V
+HSPLkotlinx/coroutines/flow/FlowKt__ReduceKt$first$$inlined$collectWhile$2;-><init>(Lkotlin/jvm/functions/Function2;Lkotlin/jvm/internal/Ref$ObjectRef;)V
+HSPLkotlinx/coroutines/flow/FlowKt__ReduceKt$first$$inlined$collectWhile$2;->emit(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/FlowKt__ShareKt$launchSharing$1$2;-><init>(Lkotlinx/coroutines/flow/Flow;Lkotlinx/coroutines/flow/MutableSharedFlow;Ljava/lang/Object;Lkotlin/coroutines/Continuation;)V
+HSPLkotlinx/coroutines/flow/FlowKt__ShareKt$launchSharing$1$2;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLkotlinx/coroutines/flow/FlowKt__ShareKt$launchSharing$1$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/FlowKt__ShareKt$launchSharing$1$2;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/FlowKt__ShareKt$launchSharing$1;-><init>(Lkotlinx/coroutines/flow/SharingStarted;Lkotlinx/coroutines/flow/Flow;Lkotlinx/coroutines/flow/MutableSharedFlow;Ljava/lang/Object;Lkotlin/coroutines/Continuation;)V
+HSPLkotlinx/coroutines/flow/FlowKt__ShareKt$launchSharing$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLkotlinx/coroutines/flow/FlowKt__ShareKt$launchSharing$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/FlowKt__ShareKt$launchSharing$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/ReadonlyStateFlow;-><init>(Lkotlinx/coroutines/flow/StateFlowImpl;)V
+HSPLkotlinx/coroutines/flow/ReadonlyStateFlow;->collect(Lkotlinx/coroutines/flow/FlowCollector;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/ReadonlyStateFlow;->getValue()Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/SafeFlow;-><init>(Lkotlin/jvm/functions/Function2;)V
+HSPLkotlinx/coroutines/flow/SafeFlow;->collect(Lkotlinx/coroutines/flow/FlowCollector;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/SharedFlowImpl$collect$1;-><init>(Lkotlinx/coroutines/flow/SharedFlowImpl;Lkotlin/coroutines/Continuation;)V
+HSPLkotlinx/coroutines/flow/SharedFlowImpl$collect$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/SharedFlowImpl;-><init>(IILkotlinx/coroutines/channels/BufferOverflow;)V
+HSPLkotlinx/coroutines/flow/SharedFlowImpl;->awaitValue(Lkotlinx/coroutines/flow/SharedFlowSlot;Lkotlinx/coroutines/flow/SharedFlowImpl$collect$1;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/SharedFlowImpl;->cleanupTailLocked()V
+HSPLkotlinx/coroutines/flow/SharedFlowImpl;->collect$suspendImpl(Lkotlinx/coroutines/flow/SharedFlowImpl;Lkotlinx/coroutines/flow/FlowCollector;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/intrinsics/CoroutineSingletons;
+HSPLkotlinx/coroutines/flow/SharedFlowImpl;->collect(Lkotlinx/coroutines/flow/FlowCollector;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/SharedFlowImpl;->createSlot()Lkotlinx/coroutines/flow/internal/AbstractSharedFlowSlot;
+HSPLkotlinx/coroutines/flow/SharedFlowImpl;->createSlotArray()[Lkotlinx/coroutines/flow/internal/AbstractSharedFlowSlot;
+HSPLkotlinx/coroutines/flow/SharedFlowImpl;->dropOldestLocked()V
+HSPLkotlinx/coroutines/flow/SharedFlowImpl;->emit(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/SharedFlowImpl;->enqueueLocked(Ljava/lang/Object;)V
+HSPLkotlinx/coroutines/flow/SharedFlowImpl;->findSlotsToResumeLocked([Lkotlin/coroutines/Continuation;)[Lkotlin/coroutines/Continuation;
+HSPLkotlinx/coroutines/flow/SharedFlowImpl;->getHead()J
+HSPLkotlinx/coroutines/flow/SharedFlowImpl;->growBuffer(II[Ljava/lang/Object;)[Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/SharedFlowImpl;->tryEmit(Ljava/lang/Object;)Z
+HSPLkotlinx/coroutines/flow/SharedFlowImpl;->tryEmitLocked(Ljava/lang/Object;)Z
+HSPLkotlinx/coroutines/flow/SharedFlowImpl;->tryPeekLocked(Lkotlinx/coroutines/flow/SharedFlowSlot;)J
+HSPLkotlinx/coroutines/flow/SharedFlowImpl;->tryTakeValue(Lkotlinx/coroutines/flow/SharedFlowSlot;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/SharedFlowImpl;->updateBufferLocked(JJJJ)V
+HSPLkotlinx/coroutines/flow/SharedFlowImpl;->updateCollectorIndexLocked$kotlinx_coroutines_core(J)[Lkotlin/coroutines/Continuation;
+HSPLkotlinx/coroutines/flow/SharedFlowSlot;-><init>()V
+HSPLkotlinx/coroutines/flow/SharedFlowSlot;->allocateLocked(Lkotlinx/coroutines/flow/internal/AbstractSharedFlow;)Z
+HSPLkotlinx/coroutines/flow/SharingCommand;-><clinit>()V
+HSPLkotlinx/coroutines/flow/SharingCommand;-><init>(ILjava/lang/String;)V
+HSPLkotlinx/coroutines/flow/SharingConfig;-><init>()V
+HSPLkotlinx/coroutines/flow/SharingConfig;-><init>(ILkotlin/coroutines/CoroutineContext;Lkotlinx/coroutines/channels/BufferOverflow;Lkotlinx/coroutines/flow/Flow;)V
+HSPLkotlinx/coroutines/flow/SharingConfig;->add(Ljava/lang/Object;Ljava/lang/Object;)V
+HSPLkotlinx/coroutines/flow/SharingConfig;->contains(Ljava/lang/Object;)Z
+HSPLkotlinx/coroutines/flow/SharingConfig;->find(Ljava/lang/Object;)I
+HSPLkotlinx/coroutines/flow/SharingConfig;->remove(Ljava/lang/Object;Ljava/lang/Object;)Z
+HSPLkotlinx/coroutines/flow/SharingConfig;->removeScope(Ljava/lang/Object;)V
+HSPLkotlinx/coroutines/flow/SharingConfig;->scopeSetAt(I)Landroidx/compose/runtime/collection/IdentityArraySet;
+HSPLkotlinx/coroutines/flow/StartedLazily;-><init>(I)V
+HSPLkotlinx/coroutines/flow/StartedWhileSubscribed$command$1;-><init>(Lkotlinx/coroutines/flow/StartedWhileSubscribed;Lkotlin/coroutines/Continuation;)V
+HSPLkotlinx/coroutines/flow/StartedWhileSubscribed$command$1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/StartedWhileSubscribed$command$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/StartedWhileSubscribed$command$2;-><init>(Lkotlin/coroutines/Continuation;)V
+HSPLkotlinx/coroutines/flow/StartedWhileSubscribed$command$2;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLkotlinx/coroutines/flow/StartedWhileSubscribed$command$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/StartedWhileSubscribed$command$2;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/StartedWhileSubscribed;-><init>(JJ)V
+HSPLkotlinx/coroutines/flow/StartedWhileSubscribed;->command(Lkotlinx/coroutines/flow/internal/SubscriptionCountStateFlow;)Lkotlinx/coroutines/flow/Flow;
+HSPLkotlinx/coroutines/flow/StartedWhileSubscribed;->equals(Ljava/lang/Object;)Z
+HSPLkotlinx/coroutines/flow/StateFlowImpl$collect$1;-><init>(Lkotlinx/coroutines/flow/StateFlowImpl;Lkotlin/coroutines/Continuation;)V
+HSPLkotlinx/coroutines/flow/StateFlowImpl$collect$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/StateFlowImpl;-><clinit>()V
+HSPLkotlinx/coroutines/flow/StateFlowImpl;-><init>(Ljava/lang/Object;)V
+HSPLkotlinx/coroutines/flow/StateFlowImpl;->collect(Lkotlinx/coroutines/flow/FlowCollector;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/StateFlowImpl;->createSlot()Lkotlinx/coroutines/flow/internal/AbstractSharedFlowSlot;
+HSPLkotlinx/coroutines/flow/StateFlowImpl;->createSlotArray()[Lkotlinx/coroutines/flow/internal/AbstractSharedFlowSlot;
+HSPLkotlinx/coroutines/flow/StateFlowImpl;->getValue()Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/StateFlowImpl;->setValue(Ljava/lang/Object;)V
+HSPLkotlinx/coroutines/flow/StateFlowImpl;->updateState(Ljava/lang/Object;Ljava/lang/Object;)Z
+HSPLkotlinx/coroutines/flow/StateFlowSlot;-><clinit>()V
+HSPLkotlinx/coroutines/flow/StateFlowSlot;->allocateLocked(Lkotlinx/coroutines/flow/internal/AbstractSharedFlow;)Z
+HSPLkotlinx/coroutines/flow/internal/AbstractSharedFlow;->allocateSlot()Lkotlinx/coroutines/flow/internal/AbstractSharedFlowSlot;
+HSPLkotlinx/coroutines/flow/internal/ChannelFlow$collect$2;-><init>(Lkotlin/coroutines/Continuation;Lkotlinx/coroutines/flow/FlowCollector;Lkotlinx/coroutines/flow/internal/ChannelFlow;)V
+HSPLkotlinx/coroutines/flow/internal/ChannelFlow$collect$2;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLkotlinx/coroutines/flow/internal/ChannelFlow$collect$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/internal/ChannelFlow$collect$2;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/internal/ChannelFlow$collectToFun$1;-><init>(Lkotlinx/coroutines/flow/internal/ChannelFlow;Lkotlin/coroutines/Continuation;)V
+HSPLkotlinx/coroutines/flow/internal/ChannelFlow$collectToFun$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLkotlinx/coroutines/flow/internal/ChannelFlow$collectToFun$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/internal/ChannelFlow;-><init>(Lkotlin/coroutines/CoroutineContext;ILkotlinx/coroutines/channels/BufferOverflow;)V
+HSPLkotlinx/coroutines/flow/internal/ChannelFlow;->fuse(Lkotlin/coroutines/CoroutineContext;ILkotlinx/coroutines/channels/BufferOverflow;)Lkotlinx/coroutines/flow/Flow;
+HSPLkotlinx/coroutines/flow/internal/ChannelFlowOperator;-><init>(ILkotlin/coroutines/CoroutineContext;Lkotlinx/coroutines/channels/BufferOverflow;Lkotlinx/coroutines/flow/Flow;)V
+HSPLkotlinx/coroutines/flow/internal/ChannelFlowOperator;->collect(Lkotlinx/coroutines/flow/FlowCollector;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest$flowCollect$3$1$2;-><init>(Lkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest;Lkotlinx/coroutines/flow/FlowCollector;Ljava/lang/Object;Lkotlin/coroutines/Continuation;)V
+HSPLkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest$flowCollect$3$1$2;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest$flowCollect$3$1$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest$flowCollect$3$1$2;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest$flowCollect$3$1$emit$1;-><init>(Lkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest$flowCollect$3$1;Lkotlin/coroutines/Continuation;)V
+HSPLkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest$flowCollect$3$1;-><init>(Lkotlin/jvm/internal/Ref$ObjectRef;Lkotlinx/coroutines/CoroutineScope;Lkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest;Lkotlinx/coroutines/flow/FlowCollector;)V
+HSPLkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest$flowCollect$3$1;->emit(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest$flowCollect$3;-><init>(Lkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest;Lkotlinx/coroutines/flow/FlowCollector;Lkotlin/coroutines/Continuation;)V
+HSPLkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest$flowCollect$3;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+HSPLkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest$flowCollect$3;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest$flowCollect$3;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest;-><init>(Lkotlin/jvm/functions/Function3;Lkotlinx/coroutines/flow/Flow;Lkotlin/coroutines/CoroutineContext;ILkotlinx/coroutines/channels/BufferOverflow;)V
+HSPLkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest;->create(Lkotlin/coroutines/CoroutineContext;ILkotlinx/coroutines/channels/BufferOverflow;)Lkotlinx/coroutines/flow/internal/ChannelFlow;
+HSPLkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest;->flowCollect(Lkotlinx/coroutines/flow/FlowCollector;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/internal/NoOpContinuation;-><clinit>()V
+HSPLkotlinx/coroutines/flow/internal/NopCollector;-><clinit>()V
+HSPLkotlinx/coroutines/flow/internal/SafeCollector;-><init>(Lkotlinx/coroutines/flow/FlowCollector;Lkotlin/coroutines/CoroutineContext;)V
+HSPLkotlinx/coroutines/flow/internal/SendingCollector;-><init>(Lkotlinx/coroutines/channels/ProducerScope;)V
+HSPLkotlinx/coroutines/flow/internal/SendingCollector;->emit(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/flow/internal/SubscriptionCountStateFlow;-><init>(I)V
+HSPLkotlinx/coroutines/internal/AtomicOp;-><clinit>()V
+HSPLkotlinx/coroutines/internal/AtomicOp;-><init>()V
+HSPLkotlinx/coroutines/internal/AtomicOp;->perform(Ljava/lang/Object;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/internal/ConcurrentLinkedListNode;-><clinit>()V
+HSPLkotlinx/coroutines/internal/ConcurrentLinkedListNode;-><init>(Lkotlinx/coroutines/internal/ConcurrentLinkedListNode;)V
+HSPLkotlinx/coroutines/internal/ConcurrentLinkedListNode;->cleanPrev()V
+HSPLkotlinx/coroutines/internal/ConcurrentLinkedListNode;->getNext()Lkotlinx/coroutines/internal/ConcurrentLinkedListNode;
+HSPLkotlinx/coroutines/internal/ContextScope;-><init>(Lkotlin/coroutines/CoroutineContext;)V
+HSPLkotlinx/coroutines/internal/ContextScope;->getCoroutineContext()Lkotlin/coroutines/CoroutineContext;
+HSPLkotlinx/coroutines/internal/DispatchedContinuation;-><clinit>()V
+HSPLkotlinx/coroutines/internal/DispatchedContinuation;-><init>(Lkotlinx/coroutines/CoroutineDispatcher;Lkotlin/coroutines/jvm/internal/ContinuationImpl;)V
+HSPLkotlinx/coroutines/internal/DispatchedContinuation;->getContext()Lkotlin/coroutines/CoroutineContext;
+HSPLkotlinx/coroutines/internal/DispatchedContinuation;->getDelegate$kotlinx_coroutines_core()Lkotlin/coroutines/Continuation;
+HSPLkotlinx/coroutines/internal/DispatchedContinuation;->resumeWith(Ljava/lang/Object;)V
+HSPLkotlinx/coroutines/internal/DispatchedContinuation;->takeState$kotlinx_coroutines_core()Ljava/lang/Object;
+HSPLkotlinx/coroutines/internal/LimitedDispatcher;-><clinit>()V
+HSPLkotlinx/coroutines/internal/LimitedDispatcher;-><init>(Lkotlinx/coroutines/scheduling/UnlimitedIoScheduler;I)V
+HSPLkotlinx/coroutines/internal/LockFreeLinkedListNode$toString$1;-><init>(ILjava/lang/Object;)V
+HSPLkotlinx/coroutines/internal/LockFreeLinkedListNode;-><clinit>()V
+HSPLkotlinx/coroutines/internal/LockFreeLinkedListNode;-><init>()V
+HSPLkotlinx/coroutines/internal/LockFreeLinkedListNode;->correctPrev()Lkotlinx/coroutines/internal/LockFreeLinkedListNode;
+HSPLkotlinx/coroutines/internal/LockFreeLinkedListNode;->finishAdd(Lkotlinx/coroutines/internal/LockFreeLinkedListNode;)V
+HSPLkotlinx/coroutines/internal/LockFreeLinkedListNode;->getNext()Ljava/lang/Object;
+HSPLkotlinx/coroutines/internal/LockFreeLinkedListNode;->getNextNode()Lkotlinx/coroutines/internal/LockFreeLinkedListNode;
+HSPLkotlinx/coroutines/internal/LockFreeLinkedListNode;->getPrevNode()Lkotlinx/coroutines/internal/LockFreeLinkedListNode;
+HSPLkotlinx/coroutines/internal/LockFreeLinkedListNode;->isRemoved()Z
+HSPLkotlinx/coroutines/internal/LockFreeTaskQueue;-><clinit>()V
+HSPLkotlinx/coroutines/internal/LockFreeTaskQueue;-><init>()V
+HSPLkotlinx/coroutines/internal/LockFreeTaskQueueCore;-><clinit>()V
+HSPLkotlinx/coroutines/internal/LockFreeTaskQueueCore;-><init>(IZ)V
+HSPLkotlinx/coroutines/internal/MainDispatcherLoader;-><clinit>()V
+HSPLkotlinx/coroutines/internal/Removed;-><init>(Lkotlinx/coroutines/internal/LockFreeLinkedListNode;)V
+HSPLkotlinx/coroutines/internal/ResizableAtomicArray;-><init>(I)V
+HSPLkotlinx/coroutines/internal/ScopeCoroutine;-><init>(Lkotlin/coroutines/Continuation;Lkotlin/coroutines/CoroutineContext;)V
+HSPLkotlinx/coroutines/internal/ScopeCoroutine;->afterCompletion(Ljava/lang/Object;)V
+HSPLkotlinx/coroutines/internal/ScopeCoroutine;->afterResume(Ljava/lang/Object;)V
+HSPLkotlinx/coroutines/internal/ScopeCoroutine;->isScopedCoroutine()Z
+HSPLkotlinx/coroutines/internal/Segment;-><clinit>()V
+HSPLkotlinx/coroutines/internal/Segment;-><init>(JLkotlinx/coroutines/internal/Segment;I)V
+HSPLkotlinx/coroutines/internal/Segment;->decPointers$kotlinx_coroutines_core()Z
+HSPLkotlinx/coroutines/internal/Segment;->isRemoved()Z
+HSPLkotlinx/coroutines/internal/Segment;->onSlotCleaned()V
+HSPLkotlinx/coroutines/internal/Segment;->tryIncPointers$kotlinx_coroutines_core()Z
+HSPLkotlinx/coroutines/internal/Symbol;-><init>(ILjava/lang/String;)V
+HSPLkotlinx/coroutines/internal/SystemPropsKt__SystemPropsKt;-><clinit>()V
+HSPLkotlinx/coroutines/scheduling/CoroutineScheduler;-><clinit>()V
+HSPLkotlinx/coroutines/scheduling/CoroutineScheduler;-><init>(IIJLjava/lang/String;)V
+HSPLkotlinx/coroutines/scheduling/DefaultIoScheduler;-><clinit>()V
+HSPLkotlinx/coroutines/scheduling/DefaultScheduler;-><clinit>()V
+HSPLkotlinx/coroutines/scheduling/DefaultScheduler;-><init>()V
+HSPLkotlinx/coroutines/scheduling/NanoTimeSource;-><clinit>()V
+HSPLkotlinx/coroutines/scheduling/SchedulerCoroutineDispatcher;-><init>(IIJLjava/lang/String;)V
+HSPLkotlinx/coroutines/scheduling/Task;-><init>(JLkotlin/ULong$Companion;)V
+HSPLkotlinx/coroutines/scheduling/TasksKt;-><clinit>()V
+HSPLkotlinx/coroutines/scheduling/UnlimitedIoScheduler;-><clinit>()V
+HSPLkotlinx/coroutines/sync/MutexImpl$CancellableContinuationWithOwner$resume$2;-><init>(Lkotlinx/coroutines/sync/MutexImpl;Lkotlinx/coroutines/sync/MutexImpl$CancellableContinuationWithOwner;I)V
+HSPLkotlinx/coroutines/sync/MutexImpl$CancellableContinuationWithOwner;-><init>(Lkotlinx/coroutines/sync/MutexImpl;Lkotlinx/coroutines/CancellableContinuationImpl;)V
+HSPLkotlinx/coroutines/sync/MutexImpl$CancellableContinuationWithOwner;->completeResume(Ljava/lang/Object;)V
+HSPLkotlinx/coroutines/sync/MutexImpl$CancellableContinuationWithOwner;->invokeOnCancellation(Lkotlinx/coroutines/internal/Segment;I)V
+HSPLkotlinx/coroutines/sync/MutexImpl$CancellableContinuationWithOwner;->tryResume(Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)Lkotlinx/coroutines/internal/Symbol;
+HSPLkotlinx/coroutines/sync/MutexImpl;-><clinit>()V
+HSPLkotlinx/coroutines/sync/MutexImpl;-><init>(Z)V
+HSPLkotlinx/coroutines/sync/MutexImpl;->isLocked()Z
+HSPLkotlinx/coroutines/sync/MutexImpl;->lock(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLkotlinx/coroutines/sync/MutexImpl;->unlock(Ljava/lang/Object;)V
+HSPLkotlinx/coroutines/sync/SemaphoreImpl$addAcquireToQueue$createNewSegment$1;-><clinit>()V
+HSPLkotlinx/coroutines/sync/SemaphoreImpl$addAcquireToQueue$createNewSegment$1;-><init>()V
+HSPLkotlinx/coroutines/sync/SemaphoreImpl$tryResumeNextFromQueue$createNewSegment$1;-><clinit>()V
+HSPLkotlinx/coroutines/sync/SemaphoreImpl$tryResumeNextFromQueue$createNewSegment$1;-><init>()V
+HSPLkotlinx/coroutines/sync/SemaphoreImpl;-><clinit>()V
+HSPLkotlinx/coroutines/sync/SemaphoreImpl;-><init>(I)V
+HSPLkotlinx/coroutines/sync/SemaphoreImpl;->acquire(Lkotlinx/coroutines/sync/MutexImpl$CancellableContinuationWithOwner;)V
+HSPLkotlinx/coroutines/sync/SemaphoreImpl;->release()V
+HSPLkotlinx/coroutines/sync/SemaphoreKt;-><clinit>()V
+HSPLkotlinx/coroutines/sync/SemaphoreSegment;-><init>(JLkotlinx/coroutines/sync/SemaphoreSegment;I)V
+HSPLkotlinx/coroutines/sync/SemaphoreSegment;->getNumberOfSlots()I
+HSPLokhttp3/Headers$Builder;-><init>()V
+HSPLokhttp3/Headers$Builder;->add(I)V
+HSPLokhttp3/Headers$Builder;->takeMax()I
+HSPLokhttp3/MediaType;-><clinit>()V
+HSPLokhttp3/MediaType;->Channel$default(ILkotlinx/coroutines/channels/BufferOverflow;I)Lkotlinx/coroutines/channels/BufferedChannel;
+HSPLokhttp3/MediaType;->CompositionLocalProvider(Landroidx/compose/runtime/ProvidedValue;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;I)V
+HSPLokhttp3/MediaType;->CoroutineScope(Lkotlin/coroutines/CoroutineContext;)Lkotlinx/coroutines/internal/ContextScope;
+HSPLokhttp3/MediaType;->LazyLayoutPinnableItem(Ljava/lang/Object;ILandroidx/compose/foundation/lazy/layout/LazyLayoutPinnedItemList;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;I)V
+HSPLokhttp3/MediaType;->LazySaveableStateHolderProvider(Lkotlin/jvm/functions/Function3;Landroidx/compose/runtime/Composer;I)V
+HSPLokhttp3/MediaType;->Offset(FF)J
+HSPLokhttp3/MediaType;->ParagraphIntrinsics(Landroidx/compose/ui/text/TextStyle;Landroidx/compose/ui/text/font/FontFamily$Resolver;Landroidx/compose/ui/unit/Density;Ljava/lang/String;Ljava/util/List;Ljava/util/List;)Landroidx/compose/ui/text/platform/AndroidParagraphIntrinsics;
+HSPLokhttp3/MediaType;->RoundRect-gG7oq9Y(FFFFJ)Landroidx/compose/ui/geometry/RoundRect;
+HSPLokhttp3/MediaType;->TextRange(II)J
+HSPLokhttp3/MediaType;->access$SkippableItem-JVlU9Rs(Landroidx/compose/foundation/lazy/layout/LazyLayoutItemProvider;Ljava/lang/Object;ILjava/lang/Object;Landroidx/compose/runtime/Composer;I)V
+HSPLokhttp3/MediaType;->access$checkIndex(ILjava/util/List;)V
+HSPLokhttp3/MediaType;->access$containsMark([II)Z
+HSPLokhttp3/MediaType;->access$groupSize([II)I
+HSPLokhttp3/MediaType;->access$hasAux([II)Z
+HSPLokhttp3/MediaType;->access$isChainUpdate(Landroidx/compose/ui/node/BackwardsCompatNode;)Z
+HSPLokhttp3/MediaType;->access$isNode([II)Z
+HSPLokhttp3/MediaType;->access$nodeCount([II)I
+HSPLokhttp3/MediaType;->access$slotAnchor([II)I
+HSPLokhttp3/MediaType;->access$updateGroupSize([III)V
+HSPLokhttp3/MediaType;->access$updateNodeCount([III)V
+HSPLokhttp3/MediaType;->adapt$default(Landroidx/compose/ui/graphics/colorspace/ColorSpace;)Landroidx/compose/ui/graphics/colorspace/ColorSpace;
+HSPLokhttp3/MediaType;->cancel(Lkotlinx/coroutines/CoroutineScope;Landroidx/lifecycle/LifecycleDestroyedException;)V
+HSPLokhttp3/MediaType;->ceilToIntPx(F)I
+HSPLokhttp3/MediaType;->checkParallelism(I)V
+HSPLokhttp3/MediaType;->chromaticAdaptation([F[F[F)[F
+HSPLokhttp3/MediaType;->coerceIn-8ffj60Q(IJ)J
+HSPLokhttp3/MediaType;->collectIsPressedAsState(Landroidx/compose/foundation/interaction/InteractionSource;Landroidx/compose/runtime/Composer;I)Landroidx/compose/runtime/MutableState;
+HSPLokhttp3/MediaType;->colors-u3YEpmA(JJJJJJJJJJJJLandroidx/compose/runtime/Composer;II)Landroidx/tv/material3/ToggleableSurfaceColors;
+HSPLokhttp3/MediaType;->compare(Landroidx/compose/ui/graphics/colorspace/WhitePoint;Landroidx/compose/ui/graphics/colorspace/WhitePoint;)Z
+HSPLokhttp3/MediaType;->coroutineScope(Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+HSPLokhttp3/MediaType;->countOneBits(I)I
+HSPLokhttp3/MediaType;->createFontFamilyResolver(Landroid/content/Context;)Landroidx/compose/ui/text/font/FontFamilyResolverImpl;
+HSPLokhttp3/MediaType;->foldCopies(Lkotlin/coroutines/CoroutineContext;Lkotlin/coroutines/CoroutineContext;Z)Lkotlin/coroutines/CoroutineContext;
+HSPLokhttp3/MediaType;->getCharSequenceBounds(Landroid/text/TextPaint;Ljava/lang/CharSequence;II)Landroid/graphics/Rect;
+HSPLokhttp3/MediaType;->getFontFamilyResult(Landroid/content/Context;Landroidx/core/provider/FontRequest;)Landroidx/compose/ui/input/pointer/util/PointerIdArray;
+HSPLokhttp3/MediaType;->getOrNull(Landroidx/compose/ui/semantics/SemanticsConfiguration;Landroidx/compose/ui/semantics/SemanticsPropertyKey;)Ljava/lang/Object;
+HSPLokhttp3/MediaType;->getSegment-impl(Ljava/lang/Object;)Lkotlinx/coroutines/internal/Segment;
+HSPLokhttp3/MediaType;->inverse3x3([F)[F
+HSPLokhttp3/MediaType;->invokeComposable(Landroidx/compose/runtime/Composer;Lkotlin/jvm/functions/Function2;)V
+HSPLokhttp3/MediaType;->invokeOnCompletion$default(Lkotlinx/coroutines/Job;ZLkotlinx/coroutines/JobNode;I)Lkotlinx/coroutines/DisposableHandle;
+HSPLokhttp3/MediaType;->isActive(Lkotlinx/coroutines/CoroutineScope;)Z
+HSPLokhttp3/MediaType;->isClosed-impl(Ljava/lang/Object;)Z
+HSPLokhttp3/MediaType;->mul3x3([F[F)[F
+HSPLokhttp3/MediaType;->mul3x3Diag([F[F)[F
+HSPLokhttp3/MediaType;->mul3x3Float3([F[F)V
+HSPLokhttp3/MediaType;->mul3x3Float3_0([FFFF)F
+HSPLokhttp3/MediaType;->mul3x3Float3_1([FFFF)F
+HSPLokhttp3/MediaType;->mul3x3Float3_2([FFFF)F
+HSPLokhttp3/MediaType;->search(Ljava/util/ArrayList;II)I
+HSPLokhttp3/MediaType;->set-impl(Landroidx/compose/runtime/Composer;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)V
+HSPLokhttp3/MediaType;->setInt-A6tL2VI(Landroidx/compose/runtime/changelist/Operations;II)V
+HSPLokhttp3/MediaType;->setObject-DKhxnng(Landroidx/compose/runtime/changelist/Operations;ILjava/lang/Object;)V
+HSPLokhttp3/MediaType;->shape(Landroidx/compose/ui/graphics/RectangleShapeKt$RectangleShape$1;Landroidx/compose/runtime/Composer;I)Landroidx/tv/material3/ToggleableSurfaceShape;
+HSPLokhttp3/MediaType;->toArray(Ljava/util/Collection;)[Ljava/lang/Object;
+HSPLokhttp3/MediaType;->updateChangedFlags(I)I
+L_COROUTINE/ArtificialStackFrames;
+Landroidx/activity/ComponentActivity$$ExternalSyntheticLambda0;
+Landroidx/activity/ComponentActivity$$ExternalSyntheticLambda1;
+Landroidx/activity/ComponentActivity$$ExternalSyntheticLambda2;
+Landroidx/activity/ComponentActivity$$ExternalSyntheticLambda3;
+Landroidx/activity/ComponentActivity$1;
+Landroidx/activity/ComponentActivity$2;
+Landroidx/activity/ComponentActivity$3;
+Landroidx/activity/ComponentActivity$4;
+Landroidx/activity/ComponentActivity$5;
+Landroidx/activity/ComponentActivity$NonConfigurationInstances;
+Landroidx/activity/ComponentActivity$ReportFullyDrawnExecutorApi16Impl;
+Landroidx/activity/ComponentActivity;
+Landroidx/activity/FullyDrawnReporter;
+Landroidx/activity/OnBackPressedDispatcher;
+Landroidx/activity/compose/ComponentActivityKt;
+Landroidx/activity/contextaware/ContextAwareHelper;
+Landroidx/activity/result/ActivityResult$1;
+Landroidx/arch/core/executor/ArchTaskExecutor;
+Landroidx/arch/core/executor/DefaultTaskExecutor$1;
+Landroidx/arch/core/executor/DefaultTaskExecutor;
+Landroidx/arch/core/internal/FastSafeIterableMap;
+Landroidx/arch/core/internal/SafeIterableMap$AscendingIterator;
+Landroidx/arch/core/internal/SafeIterableMap$Entry;
+Landroidx/arch/core/internal/SafeIterableMap$IteratorWithAdditions;
+Landroidx/arch/core/internal/SafeIterableMap$ListIterator;
+Landroidx/arch/core/internal/SafeIterableMap$SupportRemove;
+Landroidx/arch/core/internal/SafeIterableMap;
+Landroidx/collection/ArrayMap;
+Landroidx/collection/ArraySet;
+Landroidx/collection/LongSparseArray;
+Landroidx/collection/SimpleArrayMap;
+Landroidx/collection/SparseArrayCompat;
+Landroidx/compose/animation/FlingCalculator;
+Landroidx/compose/animation/FlingCalculatorKt;
+Landroidx/compose/animation/SingleValueAnimationKt;
+Landroidx/compose/animation/SplineBasedFloatDecayAnimationSpec;
+Landroidx/compose/animation/SplineBasedFloatDecayAnimationSpec_androidKt;
+Landroidx/compose/animation/core/Animatable$runAnimation$2;
+Landroidx/compose/animation/core/Animatable;
+Landroidx/compose/animation/core/AnimateAsStateKt$animateValueAsState$2;
+Landroidx/compose/animation/core/AnimateAsStateKt$animateValueAsState$3$1;
+Landroidx/compose/animation/core/AnimateAsStateKt$animateValueAsState$3;
+Landroidx/compose/animation/core/AnimateAsStateKt;
+Landroidx/compose/animation/core/Animation;
+Landroidx/compose/animation/core/AnimationEndReason$EnumUnboxingLocalUtility;
+Landroidx/compose/animation/core/AnimationResult;
+Landroidx/compose/animation/core/AnimationScope;
+Landroidx/compose/animation/core/AnimationSpec;
+Landroidx/compose/animation/core/AnimationState;
+Landroidx/compose/animation/core/AnimationVector1D;
+Landroidx/compose/animation/core/AnimationVector2D;
+Landroidx/compose/animation/core/AnimationVector3D;
+Landroidx/compose/animation/core/AnimationVector4D;
+Landroidx/compose/animation/core/AnimationVector;
+Landroidx/compose/animation/core/Animations;
+Landroidx/compose/animation/core/ComplexDouble;
+Landroidx/compose/animation/core/CubicBezierEasing;
+Landroidx/compose/animation/core/DecayAnimationSpecImpl;
+Landroidx/compose/animation/core/Easing;
+Landroidx/compose/animation/core/EasingKt$$ExternalSyntheticLambda0;
+Landroidx/compose/animation/core/EasingKt;
+Landroidx/compose/animation/core/FloatAnimationSpec;
+Landroidx/compose/animation/core/FloatDecayAnimationSpec;
+Landroidx/compose/animation/core/FloatSpringSpec;
+Landroidx/compose/animation/core/FloatTweenSpec;
+Landroidx/compose/animation/core/MutatorMutex$Mutator;
+Landroidx/compose/animation/core/MutatorMutex$mutate$2;
+Landroidx/compose/animation/core/MutatorMutex;
+Landroidx/compose/animation/core/SpringSimulation;
+Landroidx/compose/animation/core/SpringSpec;
+Landroidx/compose/animation/core/SuspendAnimationKt$animate$4;
+Landroidx/compose/animation/core/SuspendAnimationKt$animate$6;
+Landroidx/compose/animation/core/SuspendAnimationKt$animate$7;
+Landroidx/compose/animation/core/SuspendAnimationKt$animate$9;
+Landroidx/compose/animation/core/TargetBasedAnimation;
+Landroidx/compose/animation/core/TweenSpec;
+Landroidx/compose/animation/core/TwoWayConverterImpl;
+Landroidx/compose/animation/core/VectorConvertersKt;
+Landroidx/compose/animation/core/VectorizedDurationBasedAnimationSpec;
+Landroidx/compose/animation/core/VectorizedFiniteAnimationSpec;
+Landroidx/compose/animation/core/VectorizedFloatAnimationSpec;
+Landroidx/compose/animation/core/VectorizedSpringSpec;
+Landroidx/compose/animation/core/VectorizedTweenSpec;
+Landroidx/compose/animation/core/VisibilityThresholdsKt;
+Landroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect$effectModifier$1;
+Landroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect$onNewSize$1;
+Landroidx/compose/foundation/AndroidEdgeEffectOverscrollEffect;
+Landroidx/compose/foundation/AndroidOverscrollKt;
+Landroidx/compose/foundation/Api31Impl;
+Landroidx/compose/foundation/BackgroundElement;
+Landroidx/compose/foundation/BackgroundNode;
+Landroidx/compose/foundation/BorderCache;
+Landroidx/compose/foundation/BorderKt$drawRectBorder$1;
+Landroidx/compose/foundation/BorderModifierNode$drawGenericBorder$3;
+Landroidx/compose/foundation/BorderModifierNode$drawRoundRectBorder$1;
+Landroidx/compose/foundation/BorderModifierNode;
+Landroidx/compose/foundation/BorderModifierNodeElement;
+Landroidx/compose/foundation/BorderStroke;
+Landroidx/compose/foundation/ClipScrollableContainerKt;
+Landroidx/compose/foundation/DrawOverscrollModifier;
+Landroidx/compose/foundation/FocusableElement;
+Landroidx/compose/foundation/FocusableInteractionNode$emitWithFallback$1;
+Landroidx/compose/foundation/FocusableInteractionNode;
+Landroidx/compose/foundation/FocusableKt$FocusableInNonTouchModeElement$1;
+Landroidx/compose/foundation/FocusableKt;
+Landroidx/compose/foundation/FocusableNode$onFocusEvent$1;
+Landroidx/compose/foundation/FocusableNode;
+Landroidx/compose/foundation/FocusablePinnableContainerNode;
+Landroidx/compose/foundation/FocusableSemanticsNode;
+Landroidx/compose/foundation/FocusedBoundsKt;
+Landroidx/compose/foundation/FocusedBoundsNode;
+Landroidx/compose/foundation/FocusedBoundsObserverNode;
+Landroidx/compose/foundation/ImageKt$Image$1$1;
+Landroidx/compose/foundation/ImageKt$Image$1;
+Landroidx/compose/foundation/ImageKt$Image$2;
+Landroidx/compose/foundation/ImageKt;
+Landroidx/compose/foundation/Indication;
+Landroidx/compose/foundation/IndicationInstance;
+Landroidx/compose/foundation/IndicationKt$indication$2;
+Landroidx/compose/foundation/IndicationKt;
+Landroidx/compose/foundation/IndicationModifier;
+Landroidx/compose/foundation/MutatePriority;
+Landroidx/compose/foundation/MutatorMutex$Mutator;
+Landroidx/compose/foundation/MutatorMutex$mutateWith$2;
+Landroidx/compose/foundation/MutatorMutex;
+Landroidx/compose/foundation/OverscrollConfiguration;
+Landroidx/compose/foundation/OverscrollConfigurationKt;
+Landroidx/compose/foundation/OverscrollEffect;
+Landroidx/compose/foundation/ScrollKt$rememberScrollState$1$1;
+Landroidx/compose/foundation/ScrollKt$scroll$2$semantics$1$1;
+Landroidx/compose/foundation/ScrollKt$scroll$2$semantics$1;
+Landroidx/compose/foundation/ScrollKt$scroll$2;
+Landroidx/compose/foundation/ScrollState$canScrollForward$2;
+Landroidx/compose/foundation/ScrollState;
+Landroidx/compose/foundation/ScrollingLayoutElement;
+Landroidx/compose/foundation/ScrollingLayoutNode;
+Landroidx/compose/foundation/gestures/BringIntoViewRequestPriorityQueue;
+Landroidx/compose/foundation/gestures/BringIntoViewSpec$Companion$DefaultBringIntoViewSpec$1;
+Landroidx/compose/foundation/gestures/BringIntoViewSpec$Companion;
+Landroidx/compose/foundation/gestures/BringIntoViewSpec;
+Landroidx/compose/foundation/gestures/ContentInViewNode$Request;
+Landroidx/compose/foundation/gestures/ContentInViewNode$launchAnimation$2$1;
+Landroidx/compose/foundation/gestures/ContentInViewNode$launchAnimation$2;
+Landroidx/compose/foundation/gestures/ContentInViewNode;
+Landroidx/compose/foundation/gestures/DefaultFlingBehavior;
+Landroidx/compose/foundation/gestures/DefaultScrollableState$scroll$2$1;
+Landroidx/compose/foundation/gestures/DefaultScrollableState$scroll$2;
+Landroidx/compose/foundation/gestures/DefaultScrollableState$scrollScope$1;
+Landroidx/compose/foundation/gestures/DefaultScrollableState;
+Landroidx/compose/foundation/gestures/DraggableKt$awaitDrag$2;
+Landroidx/compose/foundation/gestures/DraggableNode$onAttach$1;
+Landroidx/compose/foundation/gestures/DraggableNode$pointerInputNode$1;
+Landroidx/compose/foundation/gestures/DraggableNode;
+Landroidx/compose/foundation/gestures/FlingBehavior;
+Landroidx/compose/foundation/gestures/ModifierLocalScrollableContainerProvider;
+Landroidx/compose/foundation/gestures/MouseWheelScrollNode$1;
+Landroidx/compose/foundation/gestures/MouseWheelScrollNode;
+Landroidx/compose/foundation/gestures/Orientation;
+Landroidx/compose/foundation/gestures/ScrollDraggableState;
+Landroidx/compose/foundation/gestures/ScrollScope;
+Landroidx/compose/foundation/gestures/ScrollableElement;
+Landroidx/compose/foundation/gestures/ScrollableGesturesNode$onDragStopped$1;
+Landroidx/compose/foundation/gestures/ScrollableGesturesNode;
+Landroidx/compose/foundation/gestures/ScrollableKt$DefaultScrollMotionDurationScale$1;
+Landroidx/compose/foundation/gestures/ScrollableKt$NoOpOnDragStarted$1;
+Landroidx/compose/foundation/gestures/ScrollableKt$NoOpScrollScope$1;
+Landroidx/compose/foundation/gestures/ScrollableKt$UnityDensity$1;
+Landroidx/compose/foundation/gestures/ScrollableKt;
+Landroidx/compose/foundation/gestures/ScrollableNestedScrollConnection;
+Landroidx/compose/foundation/gestures/ScrollableNode;
+Landroidx/compose/foundation/gestures/ScrollableState;
+Landroidx/compose/foundation/gestures/ScrollingLogic;
+Landroidx/compose/foundation/gestures/UpdatableAnimationState$animateToZero$1;
+Landroidx/compose/foundation/gestures/UpdatableAnimationState$animateToZero$4;
+Landroidx/compose/foundation/gestures/UpdatableAnimationState;
+Landroidx/compose/foundation/interaction/FocusInteraction$Focus;
+Landroidx/compose/foundation/interaction/FocusInteraction$Unfocus;
+Landroidx/compose/foundation/interaction/FocusInteractionKt$collectIsFocusedAsState$1$1$1;
+Landroidx/compose/foundation/interaction/FocusInteractionKt$collectIsFocusedAsState$1$1;
+Landroidx/compose/foundation/interaction/Interaction;
+Landroidx/compose/foundation/interaction/InteractionSource;
+Landroidx/compose/foundation/interaction/MutableInteractionSourceImpl;
+Landroidx/compose/foundation/interaction/PressInteraction$Press;
+Landroidx/compose/foundation/interaction/PressInteraction$Release;
+Landroidx/compose/foundation/interaction/PressInteractionKt$collectIsPressedAsState$1$1;
+Landroidx/compose/foundation/layout/Arrangement$Center$1;
+Landroidx/compose/foundation/layout/Arrangement$End$1;
+Landroidx/compose/foundation/layout/Arrangement$Horizontal;
+Landroidx/compose/foundation/layout/Arrangement$SpacedAligned;
+Landroidx/compose/foundation/layout/Arrangement$Top$1;
+Landroidx/compose/foundation/layout/Arrangement$Vertical;
+Landroidx/compose/foundation/layout/Arrangement;
+Landroidx/compose/foundation/layout/BoxKt$Box$2;
+Landroidx/compose/foundation/layout/BoxKt$EmptyBoxMeasurePolicy$1;
+Landroidx/compose/foundation/layout/BoxKt$boxMeasurePolicy$1$2;
+Landroidx/compose/foundation/layout/BoxKt$boxMeasurePolicy$1;
+Landroidx/compose/foundation/layout/BoxKt;
+Landroidx/compose/foundation/layout/BoxScope;
+Landroidx/compose/foundation/layout/BoxScopeInstance;
+Landroidx/compose/foundation/layout/ColumnKt;
+Landroidx/compose/foundation/layout/CrossAxisAlignment$VerticalCrossAxisAlignment;
+Landroidx/compose/foundation/layout/FillElement;
+Landroidx/compose/foundation/layout/FillNode;
+Landroidx/compose/foundation/layout/HorizontalAlignElement;
+Landroidx/compose/foundation/layout/HorizontalAlignNode;
+Landroidx/compose/foundation/layout/OffsetElement;
+Landroidx/compose/foundation/layout/OffsetKt;
+Landroidx/compose/foundation/layout/OffsetNode$measure$1;
+Landroidx/compose/foundation/layout/OffsetNode;
+Landroidx/compose/foundation/layout/PaddingElement;
+Landroidx/compose/foundation/layout/PaddingNode;
+Landroidx/compose/foundation/layout/PaddingValuesImpl;
+Landroidx/compose/foundation/layout/RowColumnImplKt$rowColumnMeasurePolicy$1;
+Landroidx/compose/foundation/layout/RowColumnMeasureHelperResult;
+Landroidx/compose/foundation/layout/RowColumnMeasurementHelper;
+Landroidx/compose/foundation/layout/RowColumnParentData;
+Landroidx/compose/foundation/layout/RowKt$DefaultRowMeasurePolicy$1;
+Landroidx/compose/foundation/layout/RowKt$rowMeasurePolicy$1$1;
+Landroidx/compose/foundation/layout/RowKt;
+Landroidx/compose/foundation/layout/RowScope;
+Landroidx/compose/foundation/layout/RowScopeInstance;
+Landroidx/compose/foundation/layout/SizeElement;
+Landroidx/compose/foundation/layout/SizeKt;
+Landroidx/compose/foundation/layout/SizeNode;
+Landroidx/compose/foundation/layout/SpacerMeasurePolicy;
+Landroidx/compose/foundation/layout/WrapContentElement;
+Landroidx/compose/foundation/layout/WrapContentNode$measure$1;
+Landroidx/compose/foundation/layout/WrapContentNode;
+Landroidx/compose/foundation/lazy/layout/DefaultLazyKey;
+Landroidx/compose/foundation/lazy/layout/IntervalList$Interval;
+Landroidx/compose/foundation/lazy/layout/LazyLayoutIntervalContent$Interval;
+Landroidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory$CachedItemContent;
+Landroidx/compose/foundation/lazy/layout/LazyLayoutItemContentFactory;
+Landroidx/compose/foundation/lazy/layout/LazyLayoutItemProvider;
+Landroidx/compose/foundation/lazy/layout/LazyLayoutItemReusePolicy;
+Landroidx/compose/foundation/lazy/layout/LazyLayoutKt$LazyLayout$3$2$1;
+Landroidx/compose/foundation/lazy/layout/LazyLayoutKt$LazyLayout$3$itemContentFactory$1$1;
+Landroidx/compose/foundation/lazy/layout/LazyLayoutKt$LazyLayout$3;
+Landroidx/compose/foundation/lazy/layout/LazyLayoutMeasureScopeImpl;
+Landroidx/compose/foundation/lazy/layout/LazyLayoutPinnableItem;
+Landroidx/compose/foundation/lazy/layout/LazyLayoutPinnedItemList;
+Landroidx/compose/foundation/lazy/layout/LazyLayoutPrefetchState$PrefetchHandle;
+Landroidx/compose/foundation/lazy/layout/LazyLayoutPrefetchState$Prefetcher;
+Landroidx/compose/foundation/lazy/layout/LazyLayoutPrefetchState;
+Landroidx/compose/foundation/lazy/layout/LazyLayoutPrefetcher$PrefetchRequest;
+Landroidx/compose/foundation/lazy/layout/LazyLayoutPrefetcher;
+Landroidx/compose/foundation/lazy/layout/LazySaveableStateHolder$1;
+Landroidx/compose/foundation/lazy/layout/LazySaveableStateHolder$SaveableStateProvider$2$invoke$$inlined$onDispose$1;
+Landroidx/compose/foundation/lazy/layout/LazySaveableStateHolder;
+Landroidx/compose/foundation/lazy/layout/MutableIntervalList;
+Landroidx/compose/foundation/relocation/BringIntoViewChildNode;
+Landroidx/compose/foundation/relocation/BringIntoViewKt;
+Landroidx/compose/foundation/relocation/BringIntoViewParent;
+Landroidx/compose/foundation/relocation/BringIntoViewRequesterImpl$bringIntoView$1;
+Landroidx/compose/foundation/relocation/BringIntoViewRequesterImpl;
+Landroidx/compose/foundation/relocation/BringIntoViewRequesterNode;
+Landroidx/compose/foundation/relocation/BringIntoViewResponder;
+Landroidx/compose/foundation/relocation/BringIntoViewResponderNode$bringChildIntoView$2$1$1;
+Landroidx/compose/foundation/relocation/BringIntoViewResponderNode$bringChildIntoView$2$1;
+Landroidx/compose/foundation/relocation/BringIntoViewResponderNode$bringChildIntoView$2$2;
+Landroidx/compose/foundation/relocation/BringIntoViewResponderNode$bringChildIntoView$2;
+Landroidx/compose/foundation/relocation/BringIntoViewResponderNode$bringChildIntoView$parentRect$1;
+Landroidx/compose/foundation/relocation/BringIntoViewResponderNode;
+Landroidx/compose/foundation/relocation/BringIntoViewResponder_androidKt$defaultBringIntoViewParent$1;
+Landroidx/compose/foundation/shape/CornerBasedShape;
+Landroidx/compose/foundation/shape/CornerSize;
+Landroidx/compose/foundation/shape/DpCornerSize;
+Landroidx/compose/foundation/shape/GenericShape;
+Landroidx/compose/foundation/shape/PercentCornerSize;
+Landroidx/compose/foundation/shape/RoundedCornerShape;
+Landroidx/compose/foundation/shape/RoundedCornerShapeKt;
+Landroidx/compose/foundation/text/EmptyMeasurePolicy;
+Landroidx/compose/foundation/text/modifiers/InlineDensity;
+Landroidx/compose/foundation/text/modifiers/MinLinesConstrainer;
+Landroidx/compose/foundation/text/modifiers/MultiParagraphLayoutCache;
+Landroidx/compose/foundation/text/modifiers/TextAnnotatedStringElement;
+Landroidx/compose/foundation/text/modifiers/TextAnnotatedStringNode$TextSubstitutionValue;
+Landroidx/compose/foundation/text/modifiers/TextAnnotatedStringNode;
+Landroidx/compose/foundation/text/selection/SelectionRegistrarKt;
+Landroidx/compose/foundation/text/selection/TextSelectionColors;
+Landroidx/compose/foundation/text/selection/TextSelectionColorsKt;
+Landroidx/compose/material/ripple/AndroidRippleIndicationInstance;
+Landroidx/compose/material/ripple/PlatformRipple;
+Landroidx/compose/material/ripple/RippleAlpha;
+Landroidx/compose/material/ripple/RippleIndicationInstance;
+Landroidx/compose/material/ripple/RippleKt;
+Landroidx/compose/material/ripple/RippleTheme;
+Landroidx/compose/material/ripple/RippleThemeKt;
+Landroidx/compose/material3/ColorScheme;
+Landroidx/compose/material3/ColorSchemeKt;
+Landroidx/compose/material3/MaterialRippleTheme;
+Landroidx/compose/material3/MaterialThemeKt$MaterialTheme$2;
+Landroidx/compose/material3/ShapeDefaults;
+Landroidx/compose/material3/Shapes;
+Landroidx/compose/material3/ShapesKt$LocalShapes$1;
+Landroidx/compose/material3/ShapesKt;
+Landroidx/compose/material3/TextKt$ProvideTextStyle$1;
+Landroidx/compose/material3/TextKt$Text$1;
+Landroidx/compose/material3/TextKt;
+Landroidx/compose/material3/Typography;
+Landroidx/compose/material3/TypographyKt;
+Landroidx/compose/material3/tokens/ColorDarkTokens;
+Landroidx/compose/material3/tokens/PaletteTokens;
+Landroidx/compose/material3/tokens/ShapeTokens;
+Landroidx/compose/material3/tokens/TypeScaleTokens;
+Landroidx/compose/material3/tokens/TypefaceTokens;
+Landroidx/compose/material3/tokens/TypographyTokens;
+Landroidx/compose/runtime/Anchor;
+Landroidx/compose/runtime/Applier;
+Landroidx/compose/runtime/BroadcastFrameClock$FrameAwaiter;
+Landroidx/compose/runtime/BroadcastFrameClock;
+Landroidx/compose/runtime/ComposableSingletons$CompositionKt;
+Landroidx/compose/runtime/ComposeNodeLifecycleCallback;
+Landroidx/compose/runtime/Composer;
+Landroidx/compose/runtime/ComposerImpl$CompositionContextHolder;
+Landroidx/compose/runtime/ComposerImpl$CompositionContextImpl;
+Landroidx/compose/runtime/ComposerImpl$derivedStateObserver$1;
+Landroidx/compose/runtime/ComposerImpl;
+Landroidx/compose/runtime/Composition;
+Landroidx/compose/runtime/CompositionContext;
+Landroidx/compose/runtime/CompositionContextKt;
+Landroidx/compose/runtime/CompositionImpl$RememberEventDispatcher;
+Landroidx/compose/runtime/CompositionImpl;
+Landroidx/compose/runtime/CompositionKt;
+Landroidx/compose/runtime/CompositionLocal;
+Landroidx/compose/runtime/CompositionLocalMap$Companion;
+Landroidx/compose/runtime/CompositionLocalMap;
+Landroidx/compose/runtime/CompositionObserverHolder;
+Landroidx/compose/runtime/CompositionScopedCoroutineScopeCanceller;
+Landroidx/compose/runtime/DerivedSnapshotState$ResultRecord;
+Landroidx/compose/runtime/DerivedSnapshotState;
+Landroidx/compose/runtime/DerivedStateObserver;
+Landroidx/compose/runtime/DisposableEffectImpl;
+Landroidx/compose/runtime/DisposableEffectResult;
+Landroidx/compose/runtime/DisposableEffectScope;
+Landroidx/compose/runtime/DynamicProvidableCompositionLocal;
+Landroidx/compose/runtime/GroupInfo;
+Landroidx/compose/runtime/IntStack;
+Landroidx/compose/runtime/Invalidation;
+Landroidx/compose/runtime/JoinedKey;
+Landroidx/compose/runtime/KeyInfo;
+Landroidx/compose/runtime/Latch$await$2$2;
+Landroidx/compose/runtime/Latch;
+Landroidx/compose/runtime/LaunchedEffectImpl;
+Landroidx/compose/runtime/LazyValueHolder;
+Landroidx/compose/runtime/MonotonicFrameClock;
+Landroidx/compose/runtime/MovableContentStateReference;
+Landroidx/compose/runtime/MutableFloatState;
+Landroidx/compose/runtime/MutableIntState;
+Landroidx/compose/runtime/MutableState;
+Landroidx/compose/runtime/OpaqueKey;
+Landroidx/compose/runtime/ParcelableSnapshotMutableFloatState;
+Landroidx/compose/runtime/ParcelableSnapshotMutableIntState;
+Landroidx/compose/runtime/ParcelableSnapshotMutableState$Companion$CREATOR$1;
+Landroidx/compose/runtime/ParcelableSnapshotMutableState;
+Landroidx/compose/runtime/PausableMonotonicFrameClock$withFrameNanos$1;
+Landroidx/compose/runtime/PausableMonotonicFrameClock;
+Landroidx/compose/runtime/Pending$keyMap$2;
+Landroidx/compose/runtime/Pending;
+Landroidx/compose/runtime/PersistentCompositionLocalMap;
+Landroidx/compose/runtime/ProduceStateScopeImpl;
+Landroidx/compose/runtime/ProvidableCompositionLocal;
+Landroidx/compose/runtime/ProvidedValue;
+Landroidx/compose/runtime/RecomposeScope;
+Landroidx/compose/runtime/RecomposeScopeImpl$end$1$2;
+Landroidx/compose/runtime/RecomposeScopeImpl;
+Landroidx/compose/runtime/RecomposeScopeOwner;
+Landroidx/compose/runtime/Recomposer$State;
+Landroidx/compose/runtime/Recomposer$effectJob$1$1;
+Landroidx/compose/runtime/Recomposer$join$2;
+Landroidx/compose/runtime/Recomposer$performRecompose$1$1;
+Landroidx/compose/runtime/Recomposer$recompositionRunner$2$3;
+Landroidx/compose/runtime/Recomposer$recompositionRunner$2$unregisterApplyObserver$1;
+Landroidx/compose/runtime/Recomposer$recompositionRunner$2;
+Landroidx/compose/runtime/Recomposer$runRecomposeAndApplyChanges$2$1;
+Landroidx/compose/runtime/Recomposer$runRecomposeAndApplyChanges$2;
+Landroidx/compose/runtime/Recomposer;
+Landroidx/compose/runtime/ReferentialEqualityPolicy;
+Landroidx/compose/runtime/RememberObserver;
+Landroidx/compose/runtime/SkippableUpdater;
+Landroidx/compose/runtime/SlotReader;
+Landroidx/compose/runtime/SlotTable;
+Landroidx/compose/runtime/SlotWriter;
+Landroidx/compose/runtime/SnapshotMutableFloatStateImpl$FloatStateStateRecord;
+Landroidx/compose/runtime/SnapshotMutableFloatStateImpl;
+Landroidx/compose/runtime/SnapshotMutableIntStateImpl$IntStateStateRecord;
+Landroidx/compose/runtime/SnapshotMutableIntStateImpl;
+Landroidx/compose/runtime/SnapshotMutableStateImpl$StateStateRecord;
+Landroidx/compose/runtime/SnapshotMutableStateImpl;
+Landroidx/compose/runtime/SnapshotMutationPolicy;
+Landroidx/compose/runtime/SnapshotStateKt__DerivedStateKt;
+Landroidx/compose/runtime/SnapshotStateKt__ProduceStateKt$produceState$3;
+Landroidx/compose/runtime/SnapshotStateKt__SnapshotFlowKt$collectAsState$1$1;
+Landroidx/compose/runtime/SnapshotStateKt__SnapshotFlowKt$collectAsState$1;
+Landroidx/compose/runtime/Stack;
+Landroidx/compose/runtime/State;
+Landroidx/compose/runtime/StaticProvidableCompositionLocal;
+Landroidx/compose/runtime/StaticValueHolder;
+Landroidx/compose/runtime/StructuralEqualityPolicy;
+Landroidx/compose/runtime/WeakReference;
+Landroidx/compose/runtime/changelist/ChangeList;
+Landroidx/compose/runtime/changelist/ComposerChangeListWriter;
+Landroidx/compose/runtime/changelist/FixupList;
+Landroidx/compose/runtime/changelist/Operation$AdvanceSlotsBy;
+Landroidx/compose/runtime/changelist/Operation$DeactivateCurrentGroup;
+Landroidx/compose/runtime/changelist/Operation$Downs;
+Landroidx/compose/runtime/changelist/Operation$EndCompositionScope;
+Landroidx/compose/runtime/changelist/Operation$EndCurrentGroup;
+Landroidx/compose/runtime/changelist/Operation$EnsureGroupStarted;
+Landroidx/compose/runtime/changelist/Operation$EnsureRootGroupStarted;
+Landroidx/compose/runtime/changelist/Operation$InsertNodeFixup;
+Landroidx/compose/runtime/changelist/Operation$InsertSlots;
+Landroidx/compose/runtime/changelist/Operation$InsertSlotsWithFixups;
+Landroidx/compose/runtime/changelist/Operation$MoveCurrentGroup;
+Landroidx/compose/runtime/changelist/Operation$PostInsertNodeFixup;
+Landroidx/compose/runtime/changelist/Operation$Remember;
+Landroidx/compose/runtime/changelist/Operation$SideEffect;
+Landroidx/compose/runtime/changelist/Operation$UpdateAuxData;
+Landroidx/compose/runtime/changelist/Operation$UpdateNode;
+Landroidx/compose/runtime/changelist/Operation$UpdateValue;
+Landroidx/compose/runtime/changelist/Operation$Ups;
+Landroidx/compose/runtime/changelist/Operation$UseCurrentNode;
+Landroidx/compose/runtime/changelist/Operation;
+Landroidx/compose/runtime/changelist/Operations$OpIterator;
+Landroidx/compose/runtime/changelist/Operations;
+Landroidx/compose/runtime/collection/IdentityArrayIntMap;
+Landroidx/compose/runtime/collection/IdentityArrayMap$asMap$1$entries$1$iterator$1$1;
+Landroidx/compose/runtime/collection/IdentityArraySet;
+Landroidx/compose/runtime/collection/MutableVector$MutableVectorList;
+Landroidx/compose/runtime/collection/MutableVector$VectorListIterator;
+Landroidx/compose/runtime/collection/MutableVector;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/ImmutableList;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/ImmutableSet;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/PersistentList;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/PersistentMap$Builder;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/PersistentMap;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/PersistentSet;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableList/AbstractPersistentList;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableList/SmallPersistentVector;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMap;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapBaseIterator;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapBuilder;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapKeys;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMapKeysIterator;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNodeBaseIterator;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNodeKeysIterator;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/persistentOrderedSet/Links;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/persistentOrderedSet/PersistentOrderedSet;
+Landroidx/compose/runtime/external/kotlinx/collections/immutable/internal/DeltaCounter;
+Landroidx/compose/runtime/internal/ComposableLambda;
+Landroidx/compose/runtime/internal/ComposableLambdaImpl;
+Landroidx/compose/runtime/internal/PersistentCompositionLocalHashMap$Builder;
+Landroidx/compose/runtime/internal/PersistentCompositionLocalHashMap;
+Landroidx/compose/runtime/internal/ThreadMap;
+Landroidx/compose/runtime/saveable/ListSaverKt$listSaver$1;
+Landroidx/compose/runtime/saveable/RememberSaveableKt$rememberSaveable$1;
+Landroidx/compose/runtime/saveable/SaveableHolder;
+Landroidx/compose/runtime/saveable/SaveableStateHolder;
+Landroidx/compose/runtime/saveable/SaveableStateHolderImpl$RegistryHolder$registry$1;
+Landroidx/compose/runtime/saveable/SaveableStateHolderImpl$RegistryHolder;
+Landroidx/compose/runtime/saveable/SaveableStateHolderImpl$SaveableStateProvider$1$1$invoke$$inlined$onDispose$1;
+Landroidx/compose/runtime/saveable/SaveableStateHolderImpl;
+Landroidx/compose/runtime/saveable/SaveableStateRegistry;
+Landroidx/compose/runtime/saveable/SaveableStateRegistryImpl$registerProvider$3;
+Landroidx/compose/runtime/saveable/SaveableStateRegistryImpl;
+Landroidx/compose/runtime/saveable/SaveableStateRegistryKt;
+Landroidx/compose/runtime/saveable/SaverKt$Saver$1;
+Landroidx/compose/runtime/saveable/SaverKt;
+Landroidx/compose/runtime/snapshots/GlobalSnapshot$1$1$1;
+Landroidx/compose/runtime/snapshots/GlobalSnapshot;
+Landroidx/compose/runtime/snapshots/MutableSnapshot;
+Landroidx/compose/runtime/snapshots/ObserverHandle;
+Landroidx/compose/runtime/snapshots/ReadonlySnapshot;
+Landroidx/compose/runtime/snapshots/Snapshot$Companion$$ExternalSyntheticLambda0;
+Landroidx/compose/runtime/snapshots/Snapshot;
+Landroidx/compose/runtime/snapshots/SnapshotApplyResult$Failure;
+Landroidx/compose/runtime/snapshots/SnapshotApplyResult$Success;
+Landroidx/compose/runtime/snapshots/SnapshotDoubleIndexHeap;
+Landroidx/compose/runtime/snapshots/SnapshotIdSet;
+Landroidx/compose/runtime/snapshots/SnapshotKt$mergedReadObserver$1;
+Landroidx/compose/runtime/snapshots/SnapshotKt;
+Landroidx/compose/runtime/snapshots/SnapshotMutableState;
+Landroidx/compose/runtime/snapshots/SnapshotStateList$StateListStateRecord;
+Landroidx/compose/runtime/snapshots/SnapshotStateList$addAll$1;
+Landroidx/compose/runtime/snapshots/SnapshotStateList;
+Landroidx/compose/runtime/snapshots/SnapshotStateListKt;
+Landroidx/compose/runtime/snapshots/SnapshotStateObserver$ObservedScopeMap;
+Landroidx/compose/runtime/snapshots/SnapshotStateObserver;
+Landroidx/compose/runtime/snapshots/StateObject;
+Landroidx/compose/runtime/snapshots/StateRecord;
+Landroidx/compose/runtime/snapshots/TransparentObserverMutableSnapshot;
+Landroidx/compose/runtime/tooling/InspectionTablesKt;
+Landroidx/compose/ui/Alignment$Horizontal;
+Landroidx/compose/ui/Alignment$Vertical;
+Landroidx/compose/ui/Alignment;
+Landroidx/compose/ui/BiasAlignment$Horizontal;
+Landroidx/compose/ui/BiasAlignment$Vertical;
+Landroidx/compose/ui/BiasAlignment;
+Landroidx/compose/ui/CombinedModifier$toString$1;
+Landroidx/compose/ui/CombinedModifier;
+Landroidx/compose/ui/ComposedModifier;
+Landroidx/compose/ui/CompositionLocalMapInjectionElement;
+Landroidx/compose/ui/Modifier$Companion;
+Landroidx/compose/ui/Modifier$Element;
+Landroidx/compose/ui/Modifier$Node;
+Landroidx/compose/ui/Modifier;
+Landroidx/compose/ui/MotionDurationScale;
+Landroidx/compose/ui/ZIndexElement;
+Landroidx/compose/ui/ZIndexNode$measure$1;
+Landroidx/compose/ui/ZIndexNode;
+Landroidx/compose/ui/autofill/AndroidAutofill;
+Landroidx/compose/ui/autofill/Autofill;
+Landroidx/compose/ui/autofill/AutofillCallback;
+Landroidx/compose/ui/autofill/AutofillTree;
+Landroidx/compose/ui/draw/BuildDrawCacheParams;
+Landroidx/compose/ui/draw/CacheDrawModifierNode;
+Landroidx/compose/ui/draw/CacheDrawModifierNodeImpl;
+Landroidx/compose/ui/draw/CacheDrawScope$onDrawBehind$1;
+Landroidx/compose/ui/draw/CacheDrawScope;
+Landroidx/compose/ui/draw/ClipKt;
+Landroidx/compose/ui/draw/DrawModifier;
+Landroidx/compose/ui/draw/DrawResult;
+Landroidx/compose/ui/draw/DrawWithCacheElement;
+Landroidx/compose/ui/draw/EmptyBuildDrawCacheParams;
+Landroidx/compose/ui/draw/PainterElement;
+Landroidx/compose/ui/draw/PainterNode$measure$1;
+Landroidx/compose/ui/draw/PainterNode;
+Landroidx/compose/ui/focus/FocusChangedElement;
+Landroidx/compose/ui/focus/FocusChangedNode;
+Landroidx/compose/ui/focus/FocusDirection;
+Landroidx/compose/ui/focus/FocusEventModifierNode;
+Landroidx/compose/ui/focus/FocusInvalidationManager;
+Landroidx/compose/ui/focus/FocusModifierKt;
+Landroidx/compose/ui/focus/FocusOwner;
+Landroidx/compose/ui/focus/FocusOwnerImpl$modifier$1;
+Landroidx/compose/ui/focus/FocusOwnerImpl$moveFocus$foundNextItem$1;
+Landroidx/compose/ui/focus/FocusOwnerImpl;
+Landroidx/compose/ui/focus/FocusProperties$exit$1;
+Landroidx/compose/ui/focus/FocusProperties;
+Landroidx/compose/ui/focus/FocusPropertiesImpl;
+Landroidx/compose/ui/focus/FocusPropertiesModifierNode;
+Landroidx/compose/ui/focus/FocusRequester;
+Landroidx/compose/ui/focus/FocusRequesterModifierNode;
+Landroidx/compose/ui/focus/FocusState;
+Landroidx/compose/ui/focus/FocusStateImpl;
+Landroidx/compose/ui/focus/FocusTargetNode$FocusTargetElement;
+Landroidx/compose/ui/focus/FocusTargetNode;
+Landroidx/compose/ui/geometry/CornerRadius;
+Landroidx/compose/ui/geometry/MutableRect;
+Landroidx/compose/ui/geometry/Offset;
+Landroidx/compose/ui/geometry/Rect;
+Landroidx/compose/ui/geometry/RoundRect;
+Landroidx/compose/ui/geometry/Size;
+Landroidx/compose/ui/graphics/AndroidCanvas;
+Landroidx/compose/ui/graphics/AndroidCanvas_androidKt;
+Landroidx/compose/ui/graphics/AndroidImageBitmap;
+Landroidx/compose/ui/graphics/AndroidPaint;
+Landroidx/compose/ui/graphics/AndroidPaint_androidKt$WhenMappings;
+Landroidx/compose/ui/graphics/AndroidPath;
+Landroidx/compose/ui/graphics/BlendModeColorFilter;
+Landroidx/compose/ui/graphics/BlendModeColorFilterHelper;
+Landroidx/compose/ui/graphics/BlockGraphicsLayerElement;
+Landroidx/compose/ui/graphics/BlockGraphicsLayerModifier;
+Landroidx/compose/ui/graphics/Brush;
+Landroidx/compose/ui/graphics/BrushKt$ShaderBrush$1;
+Landroidx/compose/ui/graphics/BrushKt;
+Landroidx/compose/ui/graphics/Canvas;
+Landroidx/compose/ui/graphics/CanvasZHelper$$ExternalSyntheticApiModelOutline0;
+Landroidx/compose/ui/graphics/Color;
+Landroidx/compose/ui/graphics/ColorSpaceVerificationHelper$$ExternalSyntheticLambda1;
+Landroidx/compose/ui/graphics/Float16;
+Landroidx/compose/ui/graphics/GraphicsLayerElement;
+Landroidx/compose/ui/graphics/GraphicsLayerScopeKt;
+Landroidx/compose/ui/graphics/ImageBitmap;
+Landroidx/compose/ui/graphics/ImageBitmapConfig;
+Landroidx/compose/ui/graphics/Matrix;
+Landroidx/compose/ui/graphics/Outline$Generic;
+Landroidx/compose/ui/graphics/Outline$Rectangle;
+Landroidx/compose/ui/graphics/Outline$Rounded;
+Landroidx/compose/ui/graphics/Path;
+Landroidx/compose/ui/graphics/RectangleShapeKt$RectangleShape$1;
+Landroidx/compose/ui/graphics/ReusableGraphicsLayerScope;
+Landroidx/compose/ui/graphics/Shadow;
+Landroidx/compose/ui/graphics/Shape;
+Landroidx/compose/ui/graphics/SimpleGraphicsLayerModifier$layerBlock$1;
+Landroidx/compose/ui/graphics/SimpleGraphicsLayerModifier;
+Landroidx/compose/ui/graphics/SolidColor;
+Landroidx/compose/ui/graphics/TransformOrigin;
+Landroidx/compose/ui/graphics/colorspace/Adaptation$Companion$Bradford$1;
+Landroidx/compose/ui/graphics/colorspace/Adaptation;
+Landroidx/compose/ui/graphics/colorspace/ColorModel;
+Landroidx/compose/ui/graphics/colorspace/ColorSpace;
+Landroidx/compose/ui/graphics/colorspace/ColorSpaces;
+Landroidx/compose/ui/graphics/colorspace/Connector$Companion$identity$1;
+Landroidx/compose/ui/graphics/colorspace/Connector;
+Landroidx/compose/ui/graphics/colorspace/DoubleFunction;
+Landroidx/compose/ui/graphics/colorspace/Lab;
+Landroidx/compose/ui/graphics/colorspace/Oklab;
+Landroidx/compose/ui/graphics/colorspace/Rgb$$ExternalSyntheticLambda0;
+Landroidx/compose/ui/graphics/colorspace/Rgb$$ExternalSyntheticLambda1;
+Landroidx/compose/ui/graphics/colorspace/Rgb$$ExternalSyntheticLambda2;
+Landroidx/compose/ui/graphics/colorspace/Rgb$eotf$1;
+Landroidx/compose/ui/graphics/colorspace/Rgb;
+Landroidx/compose/ui/graphics/colorspace/TransferParameters;
+Landroidx/compose/ui/graphics/colorspace/WhitePoint;
+Landroidx/compose/ui/graphics/colorspace/Xyz;
+Landroidx/compose/ui/graphics/drawscope/CanvasDrawScope$DrawParams;
+Landroidx/compose/ui/graphics/drawscope/CanvasDrawScope$drawContext$1;
+Landroidx/compose/ui/graphics/drawscope/CanvasDrawScope;
+Landroidx/compose/ui/graphics/drawscope/CanvasDrawScopeKt$asDrawTransform$1;
+Landroidx/compose/ui/graphics/drawscope/ContentDrawScope;
+Landroidx/compose/ui/graphics/drawscope/DrawScope;
+Landroidx/compose/ui/graphics/drawscope/EmptyCanvas;
+Landroidx/compose/ui/graphics/drawscope/Fill;
+Landroidx/compose/ui/graphics/drawscope/Stroke;
+Landroidx/compose/ui/graphics/painter/BitmapPainter;
+Landroidx/compose/ui/graphics/painter/Painter;
+Landroidx/compose/ui/graphics/vector/GroupComponent;
+Landroidx/compose/ui/graphics/vector/ImageVector$Builder$GroupParams;
+Landroidx/compose/ui/graphics/vector/ImageVector$Builder;
+Landroidx/compose/ui/graphics/vector/ImageVector;
+Landroidx/compose/ui/graphics/vector/VNode;
+Landroidx/compose/ui/graphics/vector/VectorComponent;
+Landroidx/compose/ui/graphics/vector/VectorGroup;
+Landroidx/compose/ui/graphics/vector/VectorKt;
+Landroidx/compose/ui/graphics/vector/VectorNode;
+Landroidx/compose/ui/graphics/vector/VectorPainter;
+Landroidx/compose/ui/graphics/vector/VectorPath;
+Landroidx/compose/ui/graphics/vector/compat/AndroidVectorParser;
+Landroidx/compose/ui/hapticfeedback/HapticFeedback;
+Landroidx/compose/ui/input/InputMode;
+Landroidx/compose/ui/input/InputModeManager;
+Landroidx/compose/ui/input/InputModeManagerImpl;
+Landroidx/compose/ui/input/key/Key;
+Landroidx/compose/ui/input/key/KeyEvent;
+Landroidx/compose/ui/input/key/KeyInputElement;
+Landroidx/compose/ui/input/key/KeyInputModifierNode;
+Landroidx/compose/ui/input/key/KeyInputNode;
+Landroidx/compose/ui/input/key/Key_androidKt;
+Landroidx/compose/ui/input/nestedscroll/NestedScrollConnection;
+Landroidx/compose/ui/input/nestedscroll/NestedScrollDispatcher;
+Landroidx/compose/ui/input/nestedscroll/NestedScrollNode;
+Landroidx/compose/ui/input/nestedscroll/NestedScrollNodeKt;
+Landroidx/compose/ui/input/pointer/AndroidPointerIconType;
+Landroidx/compose/ui/input/pointer/MotionEventAdapter;
+Landroidx/compose/ui/input/pointer/Node;
+Landroidx/compose/ui/input/pointer/NodeParent;
+Landroidx/compose/ui/input/pointer/PointerEvent;
+Landroidx/compose/ui/input/pointer/PointerIcon;
+Landroidx/compose/ui/input/pointer/PointerIconService;
+Landroidx/compose/ui/input/pointer/PointerInputChange;
+Landroidx/compose/ui/input/pointer/PointerInputScope;
+Landroidx/compose/ui/input/pointer/PointerKeyboardModifiers;
+Landroidx/compose/ui/input/pointer/PositionCalculator;
+Landroidx/compose/ui/input/pointer/SuspendPointerInputElement;
+Landroidx/compose/ui/input/pointer/SuspendingPointerInputFilterKt;
+Landroidx/compose/ui/input/pointer/SuspendingPointerInputModifierNode;
+Landroidx/compose/ui/input/pointer/SuspendingPointerInputModifierNodeImpl$PointerEventHandlerCoroutine;
+Landroidx/compose/ui/input/pointer/SuspendingPointerInputModifierNodeImpl;
+Landroidx/compose/ui/input/pointer/util/DataPointAtTime;
+Landroidx/compose/ui/input/pointer/util/PointerIdArray;
+Landroidx/compose/ui/input/pointer/util/VelocityTracker1D;
+Landroidx/compose/ui/input/pointer/util/VelocityTracker;
+Landroidx/compose/ui/input/rotary/RotaryInputElement;
+Landroidx/compose/ui/input/rotary/RotaryInputModifierKt;
+Landroidx/compose/ui/input/rotary/RotaryInputModifierNode;
+Landroidx/compose/ui/input/rotary/RotaryInputNode;
+Landroidx/compose/ui/layout/AlignmentLine;
+Landroidx/compose/ui/layout/AlignmentLineKt$FirstBaseline$1;
+Landroidx/compose/ui/layout/AlignmentLineKt$LastBaseline$1;
+Landroidx/compose/ui/layout/AlignmentLineKt;
+Landroidx/compose/ui/layout/BeyondBoundsLayout$BeyondBoundsScope;
+Landroidx/compose/ui/layout/BeyondBoundsLayout;
+Landroidx/compose/ui/layout/BeyondBoundsLayoutKt;
+Landroidx/compose/ui/layout/ComposableSingletons$SubcomposeLayoutKt;
+Landroidx/compose/ui/layout/ContentScale;
+Landroidx/compose/ui/layout/DefaultIntrinsicMeasurable;
+Landroidx/compose/ui/layout/FixedSizeIntrinsicsPlaceable;
+Landroidx/compose/ui/layout/HorizontalAlignmentLine;
+Landroidx/compose/ui/layout/IntrinsicMeasureScope;
+Landroidx/compose/ui/layout/IntrinsicMinMax;
+Landroidx/compose/ui/layout/IntrinsicWidthHeight;
+Landroidx/compose/ui/layout/IntrinsicsMeasureScope;
+Landroidx/compose/ui/layout/LayoutCoordinates;
+Landroidx/compose/ui/layout/LayoutElement;
+Landroidx/compose/ui/layout/LayoutKt$materializerOf$1;
+Landroidx/compose/ui/layout/LayoutKt;
+Landroidx/compose/ui/layout/LayoutModifierImpl;
+Landroidx/compose/ui/layout/LayoutNodeSubcompositionsState$NodeState;
+Landroidx/compose/ui/layout/LayoutNodeSubcompositionsState$PostLookaheadMeasureScopeImpl;
+Landroidx/compose/ui/layout/LayoutNodeSubcompositionsState$Scope;
+Landroidx/compose/ui/layout/LayoutNodeSubcompositionsState$createMeasurePolicy$1$measure-3p2s80s$$inlined$createMeasureResult$1;
+Landroidx/compose/ui/layout/LayoutNodeSubcompositionsState$createMeasurePolicy$1;
+Landroidx/compose/ui/layout/LayoutNodeSubcompositionsState$precompose$1;
+Landroidx/compose/ui/layout/LayoutNodeSubcompositionsState;
+Landroidx/compose/ui/layout/LookaheadLayoutCoordinates;
+Landroidx/compose/ui/layout/Measurable;
+Landroidx/compose/ui/layout/MeasurePolicy;
+Landroidx/compose/ui/layout/MeasureResult;
+Landroidx/compose/ui/layout/MeasureScope$layout$1;
+Landroidx/compose/ui/layout/MeasureScope;
+Landroidx/compose/ui/layout/Measured;
+Landroidx/compose/ui/layout/OnRemeasuredModifier;
+Landroidx/compose/ui/layout/OnSizeChangedModifier;
+Landroidx/compose/ui/layout/PinnableContainerKt;
+Landroidx/compose/ui/layout/Placeable$PlacementScope$Companion;
+Landroidx/compose/ui/layout/Placeable$PlacementScope;
+Landroidx/compose/ui/layout/Placeable;
+Landroidx/compose/ui/layout/PlaceableKt;
+Landroidx/compose/ui/layout/Remeasurement;
+Landroidx/compose/ui/layout/RemeasurementModifier;
+Landroidx/compose/ui/layout/RootMeasurePolicy$measure$2;
+Landroidx/compose/ui/layout/RootMeasurePolicy;
+Landroidx/compose/ui/layout/ScaleFactor;
+Landroidx/compose/ui/layout/SubcomposeLayoutKt$SubcomposeLayout$2;
+Landroidx/compose/ui/layout/SubcomposeLayoutKt$SubcomposeLayout$4;
+Landroidx/compose/ui/layout/SubcomposeLayoutKt$SubcomposeLayout$5$1$invoke$$inlined$onDispose$1;
+Landroidx/compose/ui/layout/SubcomposeLayoutState$setRoot$1;
+Landroidx/compose/ui/layout/SubcomposeLayoutState;
+Landroidx/compose/ui/layout/SubcomposeMeasureScope;
+Landroidx/compose/ui/layout/SubcomposeSlotReusePolicy$SlotIdsSet;
+Landroidx/compose/ui/layout/SubcomposeSlotReusePolicy;
+Landroidx/compose/ui/modifier/BackwardsCompatLocalMap;
+Landroidx/compose/ui/modifier/EmptyMap;
+Landroidx/compose/ui/modifier/ModifierLocal;
+Landroidx/compose/ui/modifier/ModifierLocalConsumer;
+Landroidx/compose/ui/modifier/ModifierLocalManager;
+Landroidx/compose/ui/modifier/ModifierLocalModifierNode;
+Landroidx/compose/ui/modifier/ModifierLocalProvider;
+Landroidx/compose/ui/modifier/ModifierLocalReadScope;
+Landroidx/compose/ui/modifier/ProvidableModifierLocal;
+Landroidx/compose/ui/modifier/SingleLocalMap;
+Landroidx/compose/ui/node/AlignmentLines;
+Landroidx/compose/ui/node/AlignmentLinesOwner;
+Landroidx/compose/ui/node/BackwardsCompatNode;
+Landroidx/compose/ui/node/CanFocusChecker;
+Landroidx/compose/ui/node/ComposeUiNode$Companion;
+Landroidx/compose/ui/node/ComposeUiNode;
+Landroidx/compose/ui/node/CompositionLocalConsumerModifierNode;
+Landroidx/compose/ui/node/DelegatableNode;
+Landroidx/compose/ui/node/DelegatingNode;
+Landroidx/compose/ui/node/DrawModifierNode;
+Landroidx/compose/ui/node/GlobalPositionAwareModifierNode;
+Landroidx/compose/ui/node/HitTestResult;
+Landroidx/compose/ui/node/InnerNodeCoordinator;
+Landroidx/compose/ui/node/IntrinsicsPolicy;
+Landroidx/compose/ui/node/LayerPositionalProperties;
+Landroidx/compose/ui/node/LayoutAwareModifierNode;
+Landroidx/compose/ui/node/LayoutModifierNode;
+Landroidx/compose/ui/node/LayoutModifierNodeCoordinator;
+Landroidx/compose/ui/node/LayoutNode$$ExternalSyntheticLambda0;
+Landroidx/compose/ui/node/LayoutNode$Companion$DummyViewConfiguration$1;
+Landroidx/compose/ui/node/LayoutNode$Companion$ErrorMeasurePolicy$1;
+Landroidx/compose/ui/node/LayoutNode$NoIntrinsicsMeasurePolicy;
+Landroidx/compose/ui/node/LayoutNode$WhenMappings;
+Landroidx/compose/ui/node/LayoutNode$_foldedChildren$1;
+Landroidx/compose/ui/node/LayoutNode;
+Landroidx/compose/ui/node/LayoutNodeDrawScope;
+Landroidx/compose/ui/node/LayoutNodeLayoutDelegate$LookaheadPassDelegate;
+Landroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate$placeOuterCoordinator$1;
+Landroidx/compose/ui/node/LayoutNodeLayoutDelegate$MeasurePassDelegate;
+Landroidx/compose/ui/node/LayoutNodeLayoutDelegate$performMeasure$2;
+Landroidx/compose/ui/node/LayoutNodeLayoutDelegate;
+Landroidx/compose/ui/node/LookaheadAlignmentLines;
+Landroidx/compose/ui/node/LookaheadCapablePlaceable;
+Landroidx/compose/ui/node/LookaheadDelegate;
+Landroidx/compose/ui/node/MeasureAndLayoutDelegate$PostponedRequest;
+Landroidx/compose/ui/node/MeasureAndLayoutDelegate;
+Landroidx/compose/ui/node/ModifierNodeElement;
+Landroidx/compose/ui/node/NodeChain$Differ;
+Landroidx/compose/ui/node/NodeChain;
+Landroidx/compose/ui/node/NodeChainKt$SentinelHead$1;
+Landroidx/compose/ui/node/NodeChainKt;
+Landroidx/compose/ui/node/NodeCoordinator$HitTestSource;
+Landroidx/compose/ui/node/NodeCoordinator$invoke$1;
+Landroidx/compose/ui/node/NodeCoordinator;
+Landroidx/compose/ui/node/NodeMeasuringIntrinsics$IntrinsicMinMax;
+Landroidx/compose/ui/node/NodeMeasuringIntrinsics$IntrinsicWidthHeight;
+Landroidx/compose/ui/node/ObserverModifierNode;
+Landroidx/compose/ui/node/ObserverNodeOwnerScope;
+Landroidx/compose/ui/node/OnPositionedDispatcher$Companion$DepthComparator;
+Landroidx/compose/ui/node/OnPositionedDispatcher;
+Landroidx/compose/ui/node/OwnedLayer;
+Landroidx/compose/ui/node/Owner$OnLayoutCompletedListener;
+Landroidx/compose/ui/node/Owner;
+Landroidx/compose/ui/node/OwnerScope;
+Landroidx/compose/ui/node/OwnerSnapshotObserver;
+Landroidx/compose/ui/node/ParentDataModifierNode;
+Landroidx/compose/ui/node/PointerInputModifierNode;
+Landroidx/compose/ui/node/RootForTest;
+Landroidx/compose/ui/node/SemanticsModifierNode;
+Landroidx/compose/ui/node/TailModifierNode;
+Landroidx/compose/ui/node/TreeSet;
+Landroidx/compose/ui/node/UiApplier;
+Landroidx/compose/ui/platform/AbstractComposeView;
+Landroidx/compose/ui/platform/AccessibilityManager;
+Landroidx/compose/ui/platform/AndroidAccessibilityManager;
+Landroidx/compose/ui/platform/AndroidClipboardManager;
+Landroidx/compose/ui/platform/AndroidComposeView$$ExternalSyntheticApiModelOutline0;
+Landroidx/compose/ui/platform/AndroidComposeView$$ExternalSyntheticLambda1;
+Landroidx/compose/ui/platform/AndroidComposeView$$ExternalSyntheticLambda2;
+Landroidx/compose/ui/platform/AndroidComposeView$$ExternalSyntheticLambda3;
+Landroidx/compose/ui/platform/AndroidComposeView$AndroidComposeViewTranslationCallback;
+Landroidx/compose/ui/platform/AndroidComposeView$ViewTreeOwners;
+Landroidx/compose/ui/platform/AndroidComposeView$focusOwner$1;
+Landroidx/compose/ui/platform/AndroidComposeView$pointerIconService$1;
+Landroidx/compose/ui/platform/AndroidComposeView$viewTreeOwners$2;
+Landroidx/compose/ui/platform/AndroidComposeView;
+Landroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat$$ExternalSyntheticLambda1;
+Landroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat$$ExternalSyntheticLambda2;
+Landroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat$1;
+Landroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat$MyNodeProvider;
+Landroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat$SemanticsNodeCopy;
+Landroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat$boundsUpdatesEventLoop$1;
+Landroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat$sendScrollEventIfNeeded$1;
+Landroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat;
+Landroidx/compose/ui/platform/AndroidComposeViewForceDarkModeQ;
+Landroidx/compose/ui/platform/AndroidComposeViewTranslationCallbackS;
+Landroidx/compose/ui/platform/AndroidComposeViewVerificationHelperMethodsN;
+Landroidx/compose/ui/platform/AndroidComposeViewVerificationHelperMethodsO;
+Landroidx/compose/ui/platform/AndroidCompositionLocals_androidKt$obtainImageVectorCache$callbacks$1$1;
+Landroidx/compose/ui/platform/AndroidCompositionLocals_androidKt;
+Landroidx/compose/ui/platform/AndroidUiDispatcher$dispatchCallback$1;
+Landroidx/compose/ui/platform/AndroidUiDispatcher;
+Landroidx/compose/ui/platform/AndroidUiFrameClock$withFrameNanos$2$callback$1;
+Landroidx/compose/ui/platform/AndroidUiFrameClock;
+Landroidx/compose/ui/platform/AndroidUriHandler;
+Landroidx/compose/ui/platform/AndroidViewConfiguration;
+Landroidx/compose/ui/platform/CalculateMatrixToWindow;
+Landroidx/compose/ui/platform/CalculateMatrixToWindowApi29;
+Landroidx/compose/ui/platform/ClipboardManager;
+Landroidx/compose/ui/platform/ComposableSingletons$Wrapper_androidKt;
+Landroidx/compose/ui/platform/ComposeView;
+Landroidx/compose/ui/platform/CompositionLocalsKt;
+Landroidx/compose/ui/platform/DeviceRenderNode;
+Landroidx/compose/ui/platform/DisposableSaveableStateRegistry;
+Landroidx/compose/ui/platform/DisposableSaveableStateRegistry_androidKt$DisposableSaveableStateRegistry$1;
+Landroidx/compose/ui/platform/DrawChildContainer;
+Landroidx/compose/ui/platform/GlobalSnapshotManager$ensureStarted$1;
+Landroidx/compose/ui/platform/GlobalSnapshotManager;
+Landroidx/compose/ui/platform/InspectableModifier$End;
+Landroidx/compose/ui/platform/InspectableModifier;
+Landroidx/compose/ui/platform/LayerMatrixCache;
+Landroidx/compose/ui/platform/MotionDurationScaleImpl;
+Landroidx/compose/ui/platform/OutlineResolver;
+Landroidx/compose/ui/platform/RenderNodeApi29;
+Landroidx/compose/ui/platform/RenderNodeApi29VerificationHelper;
+Landroidx/compose/ui/platform/RenderNodeLayer;
+Landroidx/compose/ui/platform/ScrollObservationScope;
+Landroidx/compose/ui/platform/SoftwareKeyboardController;
+Landroidx/compose/ui/platform/TextToolbar;
+Landroidx/compose/ui/platform/UriHandler;
+Landroidx/compose/ui/platform/ViewCompositionStrategy;
+Landroidx/compose/ui/platform/ViewConfiguration;
+Landroidx/compose/ui/platform/ViewLayer$Companion$OutlineProvider$1;
+Landroidx/compose/ui/platform/ViewLayer;
+Landroidx/compose/ui/platform/ViewLayerContainer;
+Landroidx/compose/ui/platform/WeakCache;
+Landroidx/compose/ui/platform/WindowInfo;
+Landroidx/compose/ui/platform/WindowInfoImpl;
+Landroidx/compose/ui/platform/WindowRecomposerFactory$Companion$$ExternalSyntheticLambda0;
+Landroidx/compose/ui/platform/WindowRecomposerFactory;
+Landroidx/compose/ui/platform/WindowRecomposerPolicy$createAndInstallWindowRecomposer$unsetJob$1;
+Landroidx/compose/ui/platform/WindowRecomposerPolicy;
+Landroidx/compose/ui/platform/WindowRecomposer_androidKt$createLifecycleAwareWindowRecomposer$1;
+Landroidx/compose/ui/platform/WindowRecomposer_androidKt$createLifecycleAwareWindowRecomposer$2$WhenMappings;
+Landroidx/compose/ui/platform/WindowRecomposer_androidKt$createLifecycleAwareWindowRecomposer$2$onStateChanged$1$1$1;
+Landroidx/compose/ui/platform/WindowRecomposer_androidKt$createLifecycleAwareWindowRecomposer$2$onStateChanged$1;
+Landroidx/compose/ui/platform/WindowRecomposer_androidKt$createLifecycleAwareWindowRecomposer$2;
+Landroidx/compose/ui/platform/WindowRecomposer_androidKt$getAnimationScaleFlowFor$1$1$1;
+Landroidx/compose/ui/platform/WindowRecomposer_androidKt;
+Landroidx/compose/ui/platform/WrappedComposition$setContent$1$1$1;
+Landroidx/compose/ui/platform/WrappedComposition$setContent$1$1;
+Landroidx/compose/ui/platform/WrappedComposition$setContent$1;
+Landroidx/compose/ui/platform/WrappedComposition;
+Landroidx/compose/ui/platform/WrapperRenderNodeLayerHelperMethods;
+Landroidx/compose/ui/platform/WrapperVerificationHelperMethods;
+Landroidx/compose/ui/platform/Wrapper_androidKt;
+Landroidx/compose/ui/res/ImageVectorCache$ImageVectorEntry;
+Landroidx/compose/ui/res/ImageVectorCache$Key;
+Landroidx/compose/ui/res/ImageVectorCache;
+Landroidx/compose/ui/semantics/AppendedSemanticsElement;
+Landroidx/compose/ui/semantics/CollectionInfo;
+Landroidx/compose/ui/semantics/CoreSemanticsModifierNode;
+Landroidx/compose/ui/semantics/EmptySemanticsElement;
+Landroidx/compose/ui/semantics/EmptySemanticsModifier;
+Landroidx/compose/ui/semantics/Role;
+Landroidx/compose/ui/semantics/ScrollAxisRange;
+Landroidx/compose/ui/semantics/SemanticsConfiguration;
+Landroidx/compose/ui/semantics/SemanticsModifier;
+Landroidx/compose/ui/semantics/SemanticsModifierKt;
+Landroidx/compose/ui/semantics/SemanticsNode;
+Landroidx/compose/ui/semantics/SemanticsOwner;
+Landroidx/compose/ui/semantics/SemanticsProperties;
+Landroidx/compose/ui/semantics/SemanticsPropertiesKt;
+Landroidx/compose/ui/semantics/SemanticsPropertyKey;
+Landroidx/compose/ui/semantics/SemanticsPropertyReceiver;
+Landroidx/compose/ui/text/AndroidParagraph;
+Landroidx/compose/ui/text/AnnotatedString$Range;
+Landroidx/compose/ui/text/AnnotatedString;
+Landroidx/compose/ui/text/AnnotatedStringKt;
+Landroidx/compose/ui/text/EmojiSupportMatch;
+Landroidx/compose/ui/text/MultiParagraph;
+Landroidx/compose/ui/text/MultiParagraphIntrinsics$maxIntrinsicWidth$2;
+Landroidx/compose/ui/text/MultiParagraphIntrinsics;
+Landroidx/compose/ui/text/ParagraphInfo;
+Landroidx/compose/ui/text/ParagraphIntrinsicInfo;
+Landroidx/compose/ui/text/ParagraphIntrinsics;
+Landroidx/compose/ui/text/ParagraphStyle;
+Landroidx/compose/ui/text/ParagraphStyleKt;
+Landroidx/compose/ui/text/PlatformParagraphStyle;
+Landroidx/compose/ui/text/PlatformTextStyle;
+Landroidx/compose/ui/text/SaversKt$ColorSaver$1;
+Landroidx/compose/ui/text/SaversKt$ColorSaver$2;
+Landroidx/compose/ui/text/SaversKt;
+Landroidx/compose/ui/text/SpanStyle;
+Landroidx/compose/ui/text/SpanStyleKt;
+Landroidx/compose/ui/text/TextLayoutInput;
+Landroidx/compose/ui/text/TextLayoutResult;
+Landroidx/compose/ui/text/TextRange;
+Landroidx/compose/ui/text/TextStyle;
+Landroidx/compose/ui/text/TtsAnnotation;
+Landroidx/compose/ui/text/UrlAnnotation;
+Landroidx/compose/ui/text/VerbatimTtsAnnotation;
+Landroidx/compose/ui/text/android/BoringLayoutFactoryDefault;
+Landroidx/compose/ui/text/android/LayoutIntrinsics;
+Landroidx/compose/ui/text/android/Paint29$$ExternalSyntheticApiModelOutline0;
+Landroidx/compose/ui/text/android/Paint29;
+Landroidx/compose/ui/text/android/StaticLayoutFactory23;
+Landroidx/compose/ui/text/android/StaticLayoutFactory26;
+Landroidx/compose/ui/text/android/StaticLayoutFactory28;
+Landroidx/compose/ui/text/android/StaticLayoutFactoryImpl;
+Landroidx/compose/ui/text/android/StaticLayoutParams;
+Landroidx/compose/ui/text/android/TextAlignmentAdapter;
+Landroidx/compose/ui/text/android/TextAndroidCanvas;
+Landroidx/compose/ui/text/android/TextLayout;
+Landroidx/compose/ui/text/android/TextLayoutKt;
+Landroidx/compose/ui/text/android/style/LetterSpacingSpanEm;
+Landroidx/compose/ui/text/android/style/LetterSpacingSpanPx;
+Landroidx/compose/ui/text/android/style/LineHeightSpan;
+Landroidx/compose/ui/text/android/style/LineHeightStyleSpan;
+Landroidx/compose/ui/text/android/style/PlaceholderSpan;
+Landroidx/compose/ui/text/android/style/ShadowSpan;
+Landroidx/compose/ui/text/android/style/SkewXSpan;
+Landroidx/compose/ui/text/android/style/TextDecorationSpan;
+Landroidx/compose/ui/text/android/style/TypefaceSpan;
+Landroidx/compose/ui/text/caches/LruCache;
+Landroidx/compose/ui/text/caches/SimpleArrayMap;
+Landroidx/compose/ui/text/font/AndroidFontResolveInterceptor;
+Landroidx/compose/ui/text/font/AsyncTypefaceCache;
+Landroidx/compose/ui/text/font/DefaultFontFamily;
+Landroidx/compose/ui/text/font/Font$ResourceLoader;
+Landroidx/compose/ui/text/font/FontFamily$Resolver;
+Landroidx/compose/ui/text/font/FontFamily;
+Landroidx/compose/ui/text/font/FontFamilyResolverImpl;
+Landroidx/compose/ui/text/font/FontFamilyResolverKt;
+Landroidx/compose/ui/text/font/FontListFontFamilyTypefaceAdapter$special$$inlined$CoroutineExceptionHandler$1;
+Landroidx/compose/ui/text/font/FontListFontFamilyTypefaceAdapter;
+Landroidx/compose/ui/text/font/FontStyle;
+Landroidx/compose/ui/text/font/FontSynthesis;
+Landroidx/compose/ui/text/font/FontWeight;
+Landroidx/compose/ui/text/font/GenericFontFamily;
+Landroidx/compose/ui/text/font/PlatformResolveInterceptor$Companion$Default$1;
+Landroidx/compose/ui/text/font/PlatformResolveInterceptor$Companion;
+Landroidx/compose/ui/text/font/PlatformResolveInterceptor;
+Landroidx/compose/ui/text/font/PlatformTypefaces;
+Landroidx/compose/ui/text/font/SystemFontFamily;
+Landroidx/compose/ui/text/font/TypefaceRequest;
+Landroidx/compose/ui/text/font/TypefaceResult$Immutable;
+Landroidx/compose/ui/text/font/TypefaceResult;
+Landroidx/compose/ui/text/input/InputMethodManagerImpl;
+Landroidx/compose/ui/text/input/PlatformTextInputService;
+Landroidx/compose/ui/text/input/TextFieldValue;
+Landroidx/compose/ui/text/input/TextInputService;
+Landroidx/compose/ui/text/input/TextInputServiceAndroid;
+Landroidx/compose/ui/text/input/TextInputServiceAndroid_androidKt$$ExternalSyntheticLambda0;
+Landroidx/compose/ui/text/intl/AndroidLocale;
+Landroidx/compose/ui/text/intl/AndroidLocaleDelegateAPI24;
+Landroidx/compose/ui/text/intl/Locale;
+Landroidx/compose/ui/text/intl/LocaleList;
+Landroidx/compose/ui/text/intl/PlatformLocaleKt;
+Landroidx/compose/ui/text/platform/AndroidParagraphHelper_androidKt$NoopSpan$1;
+Landroidx/compose/ui/text/platform/AndroidParagraphHelper_androidKt;
+Landroidx/compose/ui/text/platform/AndroidParagraphIntrinsics$resolveTypeface$1;
+Landroidx/compose/ui/text/platform/AndroidParagraphIntrinsics;
+Landroidx/compose/ui/text/platform/AndroidTextPaint;
+Landroidx/compose/ui/text/platform/DefaultImpl$getFontLoadState$initCallback$1;
+Landroidx/compose/ui/text/platform/DefaultImpl;
+Landroidx/compose/ui/text/platform/EmojiCompatStatus;
+Landroidx/compose/ui/text/platform/ImmutableBool;
+Landroidx/compose/ui/text/platform/URLSpanCache;
+Landroidx/compose/ui/text/platform/extensions/LocaleListHelperMethods;
+Landroidx/compose/ui/text/platform/style/DrawStyleSpan;
+Landroidx/compose/ui/text/platform/style/ShaderBrushSpan;
+Landroidx/compose/ui/text/style/BaselineShift;
+Landroidx/compose/ui/text/style/BrushStyle;
+Landroidx/compose/ui/text/style/ColorStyle;
+Landroidx/compose/ui/text/style/Hyphens;
+Landroidx/compose/ui/text/style/LineBreak$Strategy;
+Landroidx/compose/ui/text/style/LineBreak$Strictness;
+Landroidx/compose/ui/text/style/LineBreak$WordBreak;
+Landroidx/compose/ui/text/style/LineBreak;
+Landroidx/compose/ui/text/style/LineHeightStyle$Alignment;
+Landroidx/compose/ui/text/style/LineHeightStyle;
+Landroidx/compose/ui/text/style/TextAlign;
+Landroidx/compose/ui/text/style/TextDecoration;
+Landroidx/compose/ui/text/style/TextDirection;
+Landroidx/compose/ui/text/style/TextForegroundStyle$Unspecified;
+Landroidx/compose/ui/text/style/TextForegroundStyle;
+Landroidx/compose/ui/text/style/TextGeometricTransform;
+Landroidx/compose/ui/text/style/TextIndent;
+Landroidx/compose/ui/text/style/TextMotion;
+Landroidx/compose/ui/unit/Constraints;
+Landroidx/compose/ui/unit/Density;
+Landroidx/compose/ui/unit/DensityImpl;
+Landroidx/compose/ui/unit/Dp$Companion;
+Landroidx/compose/ui/unit/Dp;
+Landroidx/compose/ui/unit/DpOffset;
+Landroidx/compose/ui/unit/DpRect;
+Landroidx/compose/ui/unit/IntOffset;
+Landroidx/compose/ui/unit/IntSize;
+Landroidx/compose/ui/unit/LayoutDirection;
+Landroidx/compose/ui/unit/TextUnit;
+Landroidx/compose/ui/unit/TextUnitType;
+Landroidx/core/app/ComponentActivity;
+Landroidx/core/app/CoreComponentFactory;
+Landroidx/core/content/res/ColorStateListInflaterCompat;
+Landroidx/core/content/res/ComplexColorCompat;
+Landroidx/core/graphics/TypefaceCompat;
+Landroidx/core/graphics/TypefaceCompatApi29Impl;
+Landroidx/core/graphics/TypefaceCompatUtil$Api19Impl;
+Landroidx/core/os/BuildCompat$Extensions30Impl$$ExternalSyntheticApiModelOutline0;
+Landroidx/core/os/BuildCompat$Extensions30Impl;
+Landroidx/core/os/BuildCompat;
+Landroidx/core/os/TraceCompat$Api18Impl;
+Landroidx/core/os/TraceCompat;
+Landroidx/core/provider/CallbackWithHandler$2;
+Landroidx/core/provider/FontProvider$Api16Impl;
+Landroidx/core/provider/FontRequest;
+Landroidx/core/provider/FontsContractCompat$FontInfo;
+Landroidx/core/text/TextUtilsCompat$Api17Impl;
+Landroidx/core/text/TextUtilsCompat;
+Landroidx/core/view/AccessibilityDelegateCompat$AccessibilityDelegateAdapter;
+Landroidx/core/view/AccessibilityDelegateCompat;
+Landroidx/core/view/MenuHostHelper;
+Landroidx/core/view/ViewCompat$$ExternalSyntheticLambda0;
+Landroidx/core/view/ViewCompat$Api29Impl;
+Landroidx/core/view/ViewCompat$Api30Impl;
+Landroidx/core/view/ViewCompat;
+Landroidx/core/view/accessibility/AccessibilityNodeProviderCompat;
+Landroidx/customview/poolingcontainer/PoolingContainerListenerHolder;
+Landroidx/emoji2/text/ConcurrencyHelpers$$ExternalSyntheticLambda0;
+Landroidx/emoji2/text/ConcurrencyHelpers$Handler28Impl;
+Landroidx/emoji2/text/DefaultGlyphChecker;
+Landroidx/emoji2/text/EmojiCompat$CompatInternal19$1;
+Landroidx/emoji2/text/EmojiCompat$CompatInternal19;
+Landroidx/emoji2/text/EmojiCompat$Config;
+Landroidx/emoji2/text/EmojiCompat$GlyphChecker;
+Landroidx/emoji2/text/EmojiCompat$MetadataRepoLoader;
+Landroidx/emoji2/text/EmojiCompat;
+Landroidx/emoji2/text/EmojiCompatInitializer$1;
+Landroidx/emoji2/text/EmojiCompatInitializer$BackgroundDefaultLoader$$ExternalSyntheticLambda0;
+Landroidx/emoji2/text/EmojiCompatInitializer$BackgroundDefaultLoader$1;
+Landroidx/emoji2/text/EmojiCompatInitializer$LoadEmojiCompatRunnable;
+Landroidx/emoji2/text/EmojiCompatInitializer;
+Landroidx/emoji2/text/EmojiProcessor$EmojiProcessAddSpanCallback;
+Landroidx/emoji2/text/EmojiProcessor$EmojiProcessCallback;
+Landroidx/emoji2/text/EmojiProcessor$ProcessorSm;
+Landroidx/emoji2/text/EmojiProcessor;
+Landroidx/emoji2/text/FontRequestEmojiCompatConfig$FontRequestMetadataLoader$$ExternalSyntheticLambda0;
+Landroidx/emoji2/text/FontRequestEmojiCompatConfig$FontRequestMetadataLoader$1;
+Landroidx/emoji2/text/FontRequestEmojiCompatConfig$FontRequestMetadataLoader;
+Landroidx/emoji2/text/FontRequestEmojiCompatConfig;
+Landroidx/emoji2/text/MetadataRepo$Node;
+Landroidx/emoji2/text/MetadataRepo;
+Landroidx/emoji2/text/TypefaceEmojiRasterizer;
+Landroidx/emoji2/text/TypefaceEmojiSpan;
+Landroidx/emoji2/text/UnprecomputeTextOnModificationSpannable;
+Landroidx/emoji2/text/flatbuffer/MetadataItem;
+Landroidx/emoji2/text/flatbuffer/MetadataList;
+Landroidx/emoji2/text/flatbuffer/Table;
+Landroidx/lifecycle/DefaultLifecycleObserver;
+Landroidx/lifecycle/DefaultLifecycleObserverAdapter$WhenMappings;
+Landroidx/lifecycle/DefaultLifecycleObserverAdapter;
+Landroidx/lifecycle/EmptyActivityLifecycleCallbacks;
+Landroidx/lifecycle/HasDefaultViewModelProviderFactory;
+Landroidx/lifecycle/Lifecycle$Event$Companion;
+Landroidx/lifecycle/Lifecycle$Event$WhenMappings;
+Landroidx/lifecycle/Lifecycle$Event;
+Landroidx/lifecycle/Lifecycle$State;
+Landroidx/lifecycle/Lifecycle;
+Landroidx/lifecycle/LifecycleDestroyedException;
+Landroidx/lifecycle/LifecycleDispatcher$DispatcherActivityCallback;
+Landroidx/lifecycle/LifecycleDispatcher;
+Landroidx/lifecycle/LifecycleEventObserver;
+Landroidx/lifecycle/LifecycleObserver;
+Landroidx/lifecycle/LifecycleOwner;
+Landroidx/lifecycle/LifecycleRegistry$ObserverWithState;
+Landroidx/lifecycle/LifecycleRegistry;
+Landroidx/lifecycle/Lifecycling;
+Landroidx/lifecycle/ProcessLifecycleInitializer;
+Landroidx/lifecycle/ProcessLifecycleOwner$Api29Impl;
+Landroidx/lifecycle/ProcessLifecycleOwner$attach$1$onActivityPreCreated$1;
+Landroidx/lifecycle/ProcessLifecycleOwner$attach$1;
+Landroidx/lifecycle/ProcessLifecycleOwner$initializationListener$1;
+Landroidx/lifecycle/ProcessLifecycleOwner;
+Landroidx/lifecycle/ReportFragment$LifecycleCallbacks$Companion;
+Landroidx/lifecycle/ReportFragment$LifecycleCallbacks;
+Landroidx/lifecycle/ReportFragment;
+Landroidx/lifecycle/SavedStateHandleAttacher;
+Landroidx/lifecycle/SavedStateHandlesProvider;
+Landroidx/lifecycle/SavedStateHandlesVM;
+Landroidx/lifecycle/ViewModelStore;
+Landroidx/lifecycle/ViewModelStoreOwner;
+Landroidx/lifecycle/viewmodel/CreationExtras$Empty;
+Landroidx/lifecycle/viewmodel/CreationExtras;
+Landroidx/lifecycle/viewmodel/MutableCreationExtras;
+Landroidx/lifecycle/viewmodel/ViewModelInitializer;
+Landroidx/metrics/performance/DelegatingFrameMetricsListener;
+Landroidx/metrics/performance/FrameData;
+Landroidx/metrics/performance/FrameDataApi24;
+Landroidx/metrics/performance/FrameDataApi31;
+Landroidx/metrics/performance/JankStats;
+Landroidx/metrics/performance/JankStatsApi16Impl;
+Landroidx/metrics/performance/JankStatsApi22Impl;
+Landroidx/metrics/performance/JankStatsApi24Impl$$ExternalSyntheticLambda0;
+Landroidx/metrics/performance/JankStatsApi24Impl;
+Landroidx/metrics/performance/JankStatsApi26Impl;
+Landroidx/metrics/performance/JankStatsApi31Impl;
+Landroidx/metrics/performance/PerformanceMetricsState$Holder;
+Landroidx/metrics/performance/PerformanceMetricsState;
+Landroidx/profileinstaller/ProfileInstaller$DiagnosticsCallback;
+Landroidx/profileinstaller/ProfileInstallerInitializer$$ExternalSyntheticLambda0;
+Landroidx/profileinstaller/ProfileInstallerInitializer$$ExternalSyntheticLambda1;
+Landroidx/profileinstaller/ProfileInstallerInitializer$Choreographer16Impl;
+Landroidx/profileinstaller/ProfileInstallerInitializer$Handler28Impl;
+Landroidx/profileinstaller/ProfileInstallerInitializer;
+Landroidx/savedstate/Recreator;
+Landroidx/savedstate/SavedStateRegistry$$ExternalSyntheticLambda0;
+Landroidx/savedstate/SavedStateRegistry$SavedStateProvider;
+Landroidx/savedstate/SavedStateRegistry;
+Landroidx/savedstate/SavedStateRegistryController;
+Landroidx/savedstate/SavedStateRegistryOwner;
+Landroidx/startup/AppInitializer;
+Landroidx/startup/InitializationProvider;
+Landroidx/startup/Initializer;
+Landroidx/tracing/Trace$$ExternalSyntheticApiModelOutline0;
+Landroidx/tv/foundation/PivotOffsets;
+Landroidx/tv/foundation/TvBringIntoViewSpec;
+Landroidx/tv/foundation/lazy/grid/LazyGridIntervalContent;
+Landroidx/tv/foundation/lazy/grid/LazyGridItemPlacementAnimator$onMeasured$$inlined$sortBy$1;
+Landroidx/tv/foundation/lazy/grid/LazyGridItemPlacementAnimator;
+Landroidx/tv/foundation/lazy/grid/LazyGridItemProviderImpl;
+Landroidx/tv/foundation/lazy/grid/LazyGridKt$rememberLazyGridMeasurePolicy$1$1$3;
+Landroidx/tv/foundation/lazy/grid/LazyGridScrollPosition;
+Landroidx/tv/foundation/lazy/grid/TvGridItemSpan;
+Landroidx/tv/foundation/lazy/grid/TvLazyGridItemSpanScope;
+Landroidx/tv/foundation/lazy/grid/TvLazyGridScope;
+Landroidx/tv/foundation/lazy/grid/TvLazyGridState$remeasurementModifier$1;
+Landroidx/tv/foundation/lazy/grid/TvLazyGridState;
+Landroidx/tv/foundation/lazy/layout/AwaitFirstLayoutModifier$waitForFirstLayout$1;
+Landroidx/tv/foundation/lazy/layout/AwaitFirstLayoutModifier;
+Landroidx/tv/foundation/lazy/layout/LazyLayoutBeyondBoundsInfo$Interval;
+Landroidx/tv/foundation/lazy/layout/LazyLayoutKeyIndexMap;
+Landroidx/tv/foundation/lazy/layout/LazyLayoutNearestRangeState;
+Landroidx/tv/foundation/lazy/layout/LazyLayoutSemanticState;
+Landroidx/tv/foundation/lazy/layout/LazyLayoutSemanticsKt$LazyLayoutSemanticState$1;
+Landroidx/tv/foundation/lazy/layout/LazyLayoutSemanticsKt$lazyLayoutSemantics$1$1;
+Landroidx/tv/foundation/lazy/layout/NearestRangeKeyIndexMap$2$1;
+Landroidx/tv/foundation/lazy/layout/NearestRangeKeyIndexMap;
+Landroidx/tv/foundation/lazy/list/EmptyLazyListLayoutInfo;
+Landroidx/tv/foundation/lazy/list/LazyLayoutBeyondBoundsModifierLocal$Companion$emptyBeyondBoundsScope$1;
+Landroidx/tv/foundation/lazy/list/LazyLayoutBeyondBoundsModifierLocal;
+Landroidx/tv/foundation/lazy/list/LazyLayoutBeyondBoundsState;
+Landroidx/tv/foundation/lazy/list/LazyListBeyondBoundsState;
+Landroidx/tv/foundation/lazy/list/LazyListItemPlacementAnimator$onMeasured$$inlined$sortBy$2;
+Landroidx/tv/foundation/lazy/list/LazyListItemProviderImpl;
+Landroidx/tv/foundation/lazy/list/LazyListKt$rememberLazyListMeasurePolicy$1$1$measuredItemProvider$1;
+Landroidx/tv/foundation/lazy/list/LazyListKt$rememberLazyListMeasurePolicy$1$1;
+Landroidx/tv/foundation/lazy/list/LazyListMeasureResult;
+Landroidx/tv/foundation/lazy/list/LazyListMeasuredItem;
+Landroidx/tv/foundation/lazy/list/LazyListStateKt$rememberTvLazyListState$1$1;
+Landroidx/tv/foundation/lazy/list/LazyListStateKt;
+Landroidx/tv/foundation/lazy/list/TvLazyListInterval;
+Landroidx/tv/foundation/lazy/list/TvLazyListIntervalContent;
+Landroidx/tv/foundation/lazy/list/TvLazyListItemScopeImpl;
+Landroidx/tv/foundation/lazy/list/TvLazyListLayoutInfo;
+Landroidx/tv/foundation/lazy/list/TvLazyListScope;
+Landroidx/tv/foundation/lazy/list/TvLazyListState$scroll$1;
+Landroidx/tv/foundation/lazy/list/TvLazyListState;
+Landroidx/tv/material3/Border;
+Landroidx/tv/material3/BorderIndication;
+Landroidx/tv/material3/ColorScheme;
+Landroidx/tv/material3/ColorSchemeKt$LocalColorScheme$1;
+Landroidx/tv/material3/ColorSchemeKt;
+Landroidx/tv/material3/ContentColorKt;
+Landroidx/tv/material3/Glow;
+Landroidx/tv/material3/GlowIndication;
+Landroidx/tv/material3/GlowIndicationInstance;
+Landroidx/tv/material3/ScaleIndication;
+Landroidx/tv/material3/ScaleIndicationInstance;
+Landroidx/tv/material3/ScaleIndicationTokens;
+Landroidx/tv/material3/ShapesKt$LocalShapes$1;
+Landroidx/tv/material3/SurfaceKt$Surface$4;
+Landroidx/tv/material3/SurfaceKt$SurfaceImpl$2$2$1;
+Landroidx/tv/material3/SurfaceKt$SurfaceImpl$2$4$1;
+Landroidx/tv/material3/SurfaceKt$SurfaceImpl$2$5$1;
+Landroidx/tv/material3/SurfaceKt$SurfaceImpl$2;
+Landroidx/tv/material3/SurfaceKt$SurfaceImpl$3;
+Landroidx/tv/material3/SurfaceKt$handleDPadEnter$2$1;
+Landroidx/tv/material3/SurfaceKt$handleDPadEnter$2$2;
+Landroidx/tv/material3/SurfaceKt$handleDPadEnter$2;
+Landroidx/tv/material3/SurfaceKt$tvToggleable$1$1;
+Landroidx/tv/material3/SurfaceKt$tvToggleable$1$2;
+Landroidx/tv/material3/SurfaceKt$tvToggleable$1;
+Landroidx/tv/material3/SurfaceKt;
+Landroidx/tv/material3/TabColors;
+Landroidx/tv/material3/TabKt$Tab$1;
+Landroidx/tv/material3/TabKt$Tab$3$1;
+Landroidx/tv/material3/TabKt$Tab$4$1;
+Landroidx/tv/material3/TabKt$Tab$6;
+Landroidx/tv/material3/TabKt$Tab$7;
+Landroidx/tv/material3/TabKt;
+Landroidx/tv/material3/TabRowDefaults$PillIndicator$1;
+Landroidx/tv/material3/TabRowDefaults;
+Landroidx/tv/material3/TabRowKt$TabRow$1;
+Landroidx/tv/material3/TabRowKt$TabRow$2$1$1;
+Landroidx/tv/material3/TabRowKt$TabRow$2$2$1$1$2;
+Landroidx/tv/material3/TabRowKt$TabRow$2$2$1$1;
+Landroidx/tv/material3/TabRowKt$TabRow$2$2$1$separators$1;
+Landroidx/tv/material3/TabRowKt$TabRow$2$2$1;
+Landroidx/tv/material3/TabRowKt$TabRow$2;
+Landroidx/tv/material3/TabRowKt$TabRow$3;
+Landroidx/tv/material3/TabRowScopeImpl;
+Landroidx/tv/material3/TabRowSlots;
+Landroidx/tv/material3/TextKt$Text$1;
+Landroidx/tv/material3/TextKt$Text$2;
+Landroidx/tv/material3/TextKt;
+Landroidx/tv/material3/ToggleableSurfaceBorder;
+Landroidx/tv/material3/ToggleableSurfaceColors;
+Landroidx/tv/material3/ToggleableSurfaceGlow;
+Landroidx/tv/material3/ToggleableSurfaceScale;
+Landroidx/tv/material3/ToggleableSurfaceShape;
+Landroidx/tv/material3/tokens/ColorLightTokens;
+Landroidx/tv/material3/tokens/Elevation;
+Landroidx/tv/material3/tokens/PaletteTokens;
+Landroidx/tv/material3/tokens/ShapeTokens$BorderDefaultShape$1;
+Landroidx/tv/material3/tokens/ShapeTokens;
+Landroidx/tv/material3/tokens/TypographyTokensKt;
+Lcom/example/tvcomposebasedtests/ComposableSingletons$MainActivityKt;
+Lcom/example/tvcomposebasedtests/ComposableSingletons$UtilsKt$lambda-1$1;
+Lcom/example/tvcomposebasedtests/Config;
+Lcom/example/tvcomposebasedtests/JankStatsAggregator$listener$1;
+Lcom/example/tvcomposebasedtests/JankStatsAggregator;
+Lcom/example/tvcomposebasedtests/MainActivity$jankReportListener$1;
+Lcom/example/tvcomposebasedtests/MainActivity$startFrameMetrics$listener$1;
+Lcom/example/tvcomposebasedtests/MainActivity;
+Lcom/example/tvcomposebasedtests/UtilsKt$AddJankMetrics$1$2;
+Lcom/example/tvcomposebasedtests/UtilsKt$ScrollingRow$1$1$1;
+Lcom/example/tvcomposebasedtests/UtilsKt$ScrollingRow$2;
+Lcom/example/tvcomposebasedtests/UtilsKt;
+Lcom/example/tvcomposebasedtests/tvComponents/AppKt$App$1;
+Lcom/example/tvcomposebasedtests/tvComponents/ComposableSingletons$LazyContainersKt;
+Lcom/example/tvcomposebasedtests/tvComponents/ComposableSingletons$TopNavigationKt;
+Lcom/example/tvcomposebasedtests/tvComponents/Navigation;
+Lcom/example/tvcomposebasedtests/tvComponents/TopNavigationKt$PillIndicatorTabRow$1$1$1$1;
+Lcom/example/tvcomposebasedtests/tvComponents/TopNavigationKt$PillIndicatorTabRow$1;
+Lcom/example/tvcomposebasedtests/tvComponents/TopNavigationKt$TopNavigation$3$1;
+Lcom/google/gson/JsonIOException;
+Lcom/google/gson/internal/ConstructorConstructor;
+Lcom/google/gson/internal/LinkedTreeMap$1;
+Lcom/google/gson/internal/ObjectConstructor;
+Lkotlin/Function;
+Lkotlin/Lazy;
+Lkotlin/Pair;
+Lkotlin/Result$Failure;
+Lkotlin/Result;
+Lkotlin/ResultKt$$ExternalSyntheticCheckNotZero0;
+Lkotlin/ResultKt;
+Lkotlin/SynchronizedLazyImpl;
+Lkotlin/TuplesKt;
+Lkotlin/ULong$Companion;
+Lkotlin/UNINITIALIZED_VALUE;
+Lkotlin/Unit;
+Lkotlin/UnsafeLazyImpl;
+Lkotlin/collections/AbstractCollection;
+Lkotlin/collections/AbstractList;
+Lkotlin/collections/AbstractMap$toString$1;
+Lkotlin/collections/AbstractMap;
+Lkotlin/collections/AbstractMutableList;
+Lkotlin/collections/AbstractSet;
+Lkotlin/collections/ArrayDeque;
+Lkotlin/collections/ArraysKt___ArraysKt;
+Lkotlin/collections/CollectionsKt__MutableCollectionsJVMKt;
+Lkotlin/collections/CollectionsKt__ReversedViewsKt;
+Lkotlin/collections/CollectionsKt___CollectionsKt;
+Lkotlin/collections/EmptyList;
+Lkotlin/collections/EmptyMap;
+Lkotlin/coroutines/AbstractCoroutineContextElement;
+Lkotlin/coroutines/AbstractCoroutineContextKey;
+Lkotlin/coroutines/CombinedContext;
+Lkotlin/coroutines/Continuation;
+Lkotlin/coroutines/ContinuationInterceptor;
+Lkotlin/coroutines/CoroutineContext$Element;
+Lkotlin/coroutines/CoroutineContext$Key;
+Lkotlin/coroutines/CoroutineContext$plus$1;
+Lkotlin/coroutines/CoroutineContext;
+Lkotlin/coroutines/EmptyCoroutineContext;
+Lkotlin/coroutines/intrinsics/CoroutineSingletons;
+Lkotlin/coroutines/jvm/internal/BaseContinuationImpl;
+Lkotlin/coroutines/jvm/internal/CompletedContinuation;
+Lkotlin/coroutines/jvm/internal/ContinuationImpl;
+Lkotlin/coroutines/jvm/internal/CoroutineStackFrame;
+Lkotlin/coroutines/jvm/internal/SuspendLambda;
+Lkotlin/jvm/functions/Function0;
+Lkotlin/jvm/functions/Function12;
+Lkotlin/jvm/functions/Function1;
+Lkotlin/jvm/functions/Function22;
+Lkotlin/jvm/functions/Function2;
+Lkotlin/jvm/functions/Function3;
+Lkotlin/jvm/functions/Function4;
+Lkotlin/jvm/functions/Function5;
+Lkotlin/jvm/internal/ArrayIterator;
+Lkotlin/jvm/internal/CallableReference$NoReceiver;
+Lkotlin/jvm/internal/CallableReference;
+Lkotlin/jvm/internal/ClassBasedDeclarationContainer;
+Lkotlin/jvm/internal/ClassReference;
+Lkotlin/jvm/internal/FunctionBase;
+Lkotlin/jvm/internal/FunctionReferenceImpl;
+Lkotlin/jvm/internal/Lambda;
+Lkotlin/jvm/internal/PropertyReference0Impl;
+Lkotlin/jvm/internal/PropertyReference;
+Lkotlin/jvm/internal/Ref$BooleanRef;
+Lkotlin/jvm/internal/Ref$ObjectRef;
+Lkotlin/jvm/internal/Reflection;
+Lkotlin/jvm/internal/ReflectionFactory;
+Lkotlin/jvm/internal/markers/KMappedMarker;
+Lkotlin/jvm/internal/markers/KMutableCollection;
+Lkotlin/jvm/internal/markers/KMutableMap;
+Lkotlin/math/MathKt;
+Lkotlin/random/FallbackThreadLocalRandom$implStorage$1;
+Lkotlin/ranges/IntProgression;
+Lkotlin/ranges/IntProgressionIterator;
+Lkotlin/ranges/IntRange;
+Lkotlin/reflect/KCallable;
+Lkotlin/reflect/KClass;
+Lkotlin/reflect/KFunction;
+Lkotlin/reflect/KProperty0;
+Lkotlin/reflect/KProperty;
+Lkotlin/sequences/ConstrainedOnceSequence;
+Lkotlin/sequences/FilteringSequence$iterator$1;
+Lkotlin/sequences/FilteringSequence;
+Lkotlin/sequences/GeneratorSequence$iterator$1;
+Lkotlin/sequences/GeneratorSequence;
+Lkotlin/sequences/Sequence;
+Lkotlin/sequences/SequencesKt;
+Lkotlin/sequences/SequencesKt__SequencesKt$asSequence$$inlined$Sequence$1;
+Lkotlin/sequences/TransformingSequence$iterator$1;
+Lkotlin/text/StringsKt__IndentKt$getIndentFunction$2;
+Lkotlin/text/StringsKt__RegexExtensionsKt;
+Lkotlin/text/StringsKt__StringBuilderKt;
+Lkotlin/text/StringsKt__StringNumberConversionsKt;
+Lkotlin/text/StringsKt__StringsKt;
+Lkotlin/text/StringsKt___StringsKt;
+Lkotlinx/coroutines/AbstractCoroutine;
+Lkotlinx/coroutines/Active;
+Lkotlinx/coroutines/BlockingCoroutine;
+Lkotlinx/coroutines/BlockingEventLoop;
+Lkotlinx/coroutines/CancelHandler;
+Lkotlinx/coroutines/CancellableContinuation;
+Lkotlinx/coroutines/CancellableContinuationImpl;
+Lkotlinx/coroutines/CancelledContinuation;
+Lkotlinx/coroutines/ChildContinuation;
+Lkotlinx/coroutines/ChildHandle;
+Lkotlinx/coroutines/ChildHandleNode;
+Lkotlinx/coroutines/ChildJob;
+Lkotlinx/coroutines/CompletableDeferredImpl;
+Lkotlinx/coroutines/CompletedContinuation;
+Lkotlinx/coroutines/CompletedExceptionally;
+Lkotlinx/coroutines/CompletedWithCancellation;
+Lkotlinx/coroutines/CoroutineContextKt$foldCopies$1;
+Lkotlinx/coroutines/CoroutineDispatcher$Key$1;
+Lkotlinx/coroutines/CoroutineDispatcher$Key;
+Lkotlinx/coroutines/CoroutineDispatcher;
+Lkotlinx/coroutines/CoroutineExceptionHandler;
+Lkotlinx/coroutines/CoroutineScope;
+Lkotlinx/coroutines/DefaultExecutor;
+Lkotlinx/coroutines/DefaultExecutorKt;
+Lkotlinx/coroutines/Delay;
+Lkotlinx/coroutines/DispatchedTask;
+Lkotlinx/coroutines/Dispatchers;
+Lkotlinx/coroutines/DisposableHandle;
+Lkotlinx/coroutines/Empty;
+Lkotlinx/coroutines/EventLoopImplBase;
+Lkotlinx/coroutines/EventLoopImplPlatform;
+Lkotlinx/coroutines/ExecutorCoroutineDispatcher$Key$1;
+Lkotlinx/coroutines/ExecutorCoroutineDispatcher;
+Lkotlinx/coroutines/GlobalScope;
+Lkotlinx/coroutines/InactiveNodeList;
+Lkotlinx/coroutines/Incomplete;
+Lkotlinx/coroutines/IncompleteStateBox;
+Lkotlinx/coroutines/InvokeOnCancel;
+Lkotlinx/coroutines/InvokeOnCancelling;
+Lkotlinx/coroutines/InvokeOnCompletion;
+Lkotlinx/coroutines/Job;
+Lkotlinx/coroutines/JobCancellingNode;
+Lkotlinx/coroutines/JobImpl;
+Lkotlinx/coroutines/JobNode;
+Lkotlinx/coroutines/JobSupport$ChildCompletion;
+Lkotlinx/coroutines/JobSupport$Finishing;
+Lkotlinx/coroutines/JobSupport$addLastAtomic$$inlined$addLastIf$1;
+Lkotlinx/coroutines/JobSupport;
+Lkotlinx/coroutines/MainCoroutineDispatcher;
+Lkotlinx/coroutines/NodeList;
+Lkotlinx/coroutines/NonDisposableHandle;
+Lkotlinx/coroutines/NotCompleted;
+Lkotlinx/coroutines/ParentJob;
+Lkotlinx/coroutines/StandaloneCoroutine;
+Lkotlinx/coroutines/SupervisorJobImpl;
+Lkotlinx/coroutines/ThreadLocalEventLoop;
+Lkotlinx/coroutines/TimeoutCancellationException;
+Lkotlinx/coroutines/Unconfined;
+Lkotlinx/coroutines/UndispatchedCoroutine;
+Lkotlinx/coroutines/UndispatchedMarker;
+Lkotlinx/coroutines/Waiter;
+Lkotlinx/coroutines/android/AndroidDispatcherFactory;
+Lkotlinx/coroutines/android/HandlerContext;
+Lkotlinx/coroutines/android/HandlerDispatcher;
+Lkotlinx/coroutines/android/HandlerDispatcherKt;
+Lkotlinx/coroutines/channels/BufferOverflow;
+Lkotlinx/coroutines/channels/BufferedChannel$BufferedChannelIterator;
+Lkotlinx/coroutines/channels/BufferedChannel;
+Lkotlinx/coroutines/channels/BufferedChannelKt$createSegmentFunction$1;
+Lkotlinx/coroutines/channels/BufferedChannelKt;
+Lkotlinx/coroutines/channels/Channel$Factory;
+Lkotlinx/coroutines/channels/Channel;
+Lkotlinx/coroutines/channels/ChannelResult$Closed;
+Lkotlinx/coroutines/channels/ChannelResult$Failed;
+Lkotlinx/coroutines/channels/ChannelSegment;
+Lkotlinx/coroutines/channels/ConflatedBufferedChannel;
+Lkotlinx/coroutines/channels/ProducerCoroutine;
+Lkotlinx/coroutines/channels/ProducerScope;
+Lkotlinx/coroutines/channels/ReceiveChannel;
+Lkotlinx/coroutines/channels/SendChannel;
+Lkotlinx/coroutines/channels/WaiterEB;
+Lkotlinx/coroutines/flow/AbstractFlow$collect$1;
+Lkotlinx/coroutines/flow/DistinctFlowImpl$collect$2$emit$1;
+Lkotlinx/coroutines/flow/DistinctFlowImpl$collect$2;
+Lkotlinx/coroutines/flow/DistinctFlowImpl;
+Lkotlinx/coroutines/flow/Flow;
+Lkotlinx/coroutines/flow/FlowCollector;
+Lkotlinx/coroutines/flow/FlowKt__ChannelsKt$emitAllImpl$1;
+Lkotlinx/coroutines/flow/FlowKt__LimitKt$dropWhile$$inlined$unsafeFlow$1;
+Lkotlinx/coroutines/flow/FlowKt__LimitKt$dropWhile$1$1$emit$1;
+Lkotlinx/coroutines/flow/FlowKt__LimitKt$dropWhile$1$1;
+Lkotlinx/coroutines/flow/FlowKt__MergeKt$mapLatest$1;
+Lkotlinx/coroutines/flow/FlowKt__MergeKt;
+Lkotlinx/coroutines/flow/FlowKt__ReduceKt$first$$inlined$collectWhile$2$1;
+Lkotlinx/coroutines/flow/FlowKt__ReduceKt$first$$inlined$collectWhile$2;
+Lkotlinx/coroutines/flow/FlowKt__ReduceKt$first$3;
+Lkotlinx/coroutines/flow/FlowKt__ShareKt$launchSharing$1$2;
+Lkotlinx/coroutines/flow/FlowKt__ShareKt$launchSharing$1;
+Lkotlinx/coroutines/flow/MutableSharedFlow;
+Lkotlinx/coroutines/flow/ReadonlyStateFlow;
+Lkotlinx/coroutines/flow/SafeFlow;
+Lkotlinx/coroutines/flow/SharedFlowImpl$Emitter;
+Lkotlinx/coroutines/flow/SharedFlowImpl$collect$1;
+Lkotlinx/coroutines/flow/SharedFlowImpl;
+Lkotlinx/coroutines/flow/SharedFlowSlot;
+Lkotlinx/coroutines/flow/SharingCommand;
+Lkotlinx/coroutines/flow/SharingConfig;
+Lkotlinx/coroutines/flow/SharingStarted;
+Lkotlinx/coroutines/flow/StartedLazily;
+Lkotlinx/coroutines/flow/StartedWhileSubscribed$command$1;
+Lkotlinx/coroutines/flow/StartedWhileSubscribed$command$2;
+Lkotlinx/coroutines/flow/StartedWhileSubscribed;
+Lkotlinx/coroutines/flow/StateFlow;
+Lkotlinx/coroutines/flow/StateFlowImpl$collect$1;
+Lkotlinx/coroutines/flow/StateFlowImpl;
+Lkotlinx/coroutines/flow/StateFlowSlot;
+Lkotlinx/coroutines/flow/internal/AbortFlowException;
+Lkotlinx/coroutines/flow/internal/AbstractSharedFlow;
+Lkotlinx/coroutines/flow/internal/AbstractSharedFlowSlot;
+Lkotlinx/coroutines/flow/internal/ChannelFlow$collect$2;
+Lkotlinx/coroutines/flow/internal/ChannelFlow$collectToFun$1;
+Lkotlinx/coroutines/flow/internal/ChannelFlow;
+Lkotlinx/coroutines/flow/internal/ChannelFlowOperator;
+Lkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest$flowCollect$3$1$2;
+Lkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest$flowCollect$3$1$emit$1;
+Lkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest$flowCollect$3$1;
+Lkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest$flowCollect$3;
+Lkotlinx/coroutines/flow/internal/ChannelFlowTransformLatest;
+Lkotlinx/coroutines/flow/internal/FusibleFlow;
+Lkotlinx/coroutines/flow/internal/NoOpContinuation;
+Lkotlinx/coroutines/flow/internal/NopCollector;
+Lkotlinx/coroutines/flow/internal/SafeCollector;
+Lkotlinx/coroutines/flow/internal/SendingCollector;
+Lkotlinx/coroutines/flow/internal/SubscriptionCountStateFlow;
+Lkotlinx/coroutines/internal/AtomicOp;
+Lkotlinx/coroutines/internal/ConcurrentLinkedListNode;
+Lkotlinx/coroutines/internal/ContextScope;
+Lkotlinx/coroutines/internal/DispatchedContinuation;
+Lkotlinx/coroutines/internal/LimitedDispatcher;
+Lkotlinx/coroutines/internal/LockFreeLinkedListNode$toString$1;
+Lkotlinx/coroutines/internal/LockFreeLinkedListNode;
+Lkotlinx/coroutines/internal/LockFreeTaskQueue;
+Lkotlinx/coroutines/internal/LockFreeTaskQueueCore;
+Lkotlinx/coroutines/internal/MainDispatcherFactory;
+Lkotlinx/coroutines/internal/MainDispatcherLoader;
+Lkotlinx/coroutines/internal/OpDescriptor;
+Lkotlinx/coroutines/internal/Removed;
+Lkotlinx/coroutines/internal/ResizableAtomicArray;
+Lkotlinx/coroutines/internal/ScopeCoroutine;
+Lkotlinx/coroutines/internal/Segment;
+Lkotlinx/coroutines/internal/StackTraceRecoveryKt;
+Lkotlinx/coroutines/internal/Symbol;
+Lkotlinx/coroutines/internal/SystemPropsKt__SystemPropsKt;
+Lkotlinx/coroutines/internal/ThreadState;
+Lkotlinx/coroutines/scheduling/CoroutineScheduler;
+Lkotlinx/coroutines/scheduling/DefaultIoScheduler;
+Lkotlinx/coroutines/scheduling/DefaultScheduler;
+Lkotlinx/coroutines/scheduling/GlobalQueue;
+Lkotlinx/coroutines/scheduling/NanoTimeSource;
+Lkotlinx/coroutines/scheduling/SchedulerCoroutineDispatcher;
+Lkotlinx/coroutines/scheduling/Task;
+Lkotlinx/coroutines/scheduling/TasksKt;
+Lkotlinx/coroutines/scheduling/UnlimitedIoScheduler;
+Lkotlinx/coroutines/sync/Mutex;
+Lkotlinx/coroutines/sync/MutexImpl$CancellableContinuationWithOwner$resume$2;
+Lkotlinx/coroutines/sync/MutexImpl$CancellableContinuationWithOwner;
+Lkotlinx/coroutines/sync/MutexImpl;
+Lkotlinx/coroutines/sync/SemaphoreImpl$addAcquireToQueue$createNewSegment$1;
+Lkotlinx/coroutines/sync/SemaphoreImpl$tryResumeNextFromQueue$createNewSegment$1;
+Lkotlinx/coroutines/sync/SemaphoreImpl;
+Lkotlinx/coroutines/sync/SemaphoreKt;
+Lkotlinx/coroutines/sync/SemaphoreSegment;
+Lokhttp3/Headers$Builder;
+Lokhttp3/MediaType;
+PL_COROUTINE/ArtificialStackFrames;->access$removeRunning(Landroidx/compose/runtime/Stack;)V
+PL_COROUTINE/ArtificialStackFrames;->moveGroup(Landroidx/compose/runtime/SlotWriter;ILandroidx/compose/runtime/SlotWriter;ZZZ)Ljava/util/List;
+PLandroidx/activity/ComponentActivity$ReportFullyDrawnExecutorApi16Impl;->run()V
+PLandroidx/arch/core/internal/SafeIterableMap$ListIterator;->next()Ljava/lang/Object;
+PLandroidx/arch/core/internal/SafeIterableMap$ListIterator;->nextNode()Landroidx/arch/core/internal/SafeIterableMap$Entry;
+PLandroidx/arch/core/internal/SafeIterableMap$ListIterator;->supportRemove(Landroidx/arch/core/internal/SafeIterableMap$Entry;)V
+PLandroidx/collection/ArrayMap$EntrySet;->iterator()Ljava/util/Iterator;
+PLandroidx/compose/foundation/DrawOverscrollModifier;->equals(Ljava/lang/Object;)Z
+PLandroidx/compose/foundation/OverscrollConfiguration;->equals(Ljava/lang/Object;)Z
+PLandroidx/compose/foundation/ScrollingLayoutElement;->equals(Ljava/lang/Object;)Z
+PLandroidx/compose/foundation/gestures/BringIntoViewRequestPriorityQueue;->resumeAndRemoveAll()V
+PLandroidx/compose/foundation/gestures/DraggableNode;->disposeInteractionSource()V
+PLandroidx/compose/foundation/gestures/DraggableNode;->onDetach()V
+PLandroidx/compose/foundation/gestures/ScrollableElement;->equals(Ljava/lang/Object;)Z
+PLandroidx/compose/foundation/layout/OffsetElement;->update(Landroidx/compose/ui/Modifier$Node;)V
+PLandroidx/compose/foundation/layout/SizeElement;->update(Landroidx/compose/ui/Modifier$Node;)V
+PLandroidx/compose/foundation/lazy/layout/LazyLayoutPrefetcher;->onForgotten()V
+PLandroidx/compose/runtime/ComposerImpl$CompositionContextHolder;->onForgotten()V
+PLandroidx/compose/runtime/ComposerImpl$CompositionContextImpl;->dispose()V
+PLandroidx/compose/runtime/ComposerImpl;->recordDelete()V
+PLandroidx/compose/runtime/ComposerImpl;->reportFreeMovableContent$reportGroup(Landroidx/compose/runtime/ComposerImpl;IZI)I
+PLandroidx/compose/runtime/ComposerImpl;->reportFreeMovableContent(I)V
+PLandroidx/compose/runtime/CompositionContext;->unregisterComposer$runtime_release(Landroidx/compose/runtime/Composer;)V
+PLandroidx/compose/runtime/CompositionScopedCoroutineScopeCanceller;->onForgotten()V
+PLandroidx/compose/runtime/Pending;->nodePositionOf(Landroidx/compose/runtime/KeyInfo;)I
+PLandroidx/compose/runtime/Pending;->updateNodeCount(II)Z
+PLandroidx/compose/runtime/Recomposer$effectJob$1$1;->invoke(Ljava/lang/Throwable;)V
+PLandroidx/compose/runtime/Recomposer;->cancel()V
+PLandroidx/compose/runtime/Recomposer;->reportRemovedComposition$runtime_release(Landroidx/compose/runtime/CompositionImpl;)V
+PLandroidx/compose/runtime/SlotWriter;->ensureStarted(I)V
+PLandroidx/compose/runtime/SlotWriter;->startGroup()V
+PLandroidx/compose/runtime/changelist/ComposerChangeListWriter;->removeNode(II)V
+PLandroidx/compose/runtime/changelist/Operation$EndCompositionScope;-><clinit>()V
+PLandroidx/compose/runtime/changelist/Operation$EndCompositionScope;-><init>()V
+PLandroidx/compose/runtime/changelist/Operation$EndCompositionScope;->execute(Landroidx/compose/runtime/changelist/Operations$OpIterator;Landroidx/compose/runtime/Applier;Landroidx/compose/runtime/SlotWriter;Landroidx/compose/runtime/CompositionImpl$RememberEventDispatcher;)V
+PLandroidx/compose/runtime/changelist/Operation$EndCurrentGroup;-><clinit>()V
+PLandroidx/compose/runtime/changelist/Operation$EndCurrentGroup;-><init>()V
+PLandroidx/compose/runtime/changelist/Operation$EndCurrentGroup;->execute(Landroidx/compose/runtime/changelist/Operations$OpIterator;Landroidx/compose/runtime/Applier;Landroidx/compose/runtime/SlotWriter;Landroidx/compose/runtime/CompositionImpl$RememberEventDispatcher;)V
+PLandroidx/compose/runtime/changelist/Operation$EnsureGroupStarted;-><clinit>()V
+PLandroidx/compose/runtime/changelist/Operation$EnsureGroupStarted;-><init>()V
+PLandroidx/compose/runtime/changelist/Operation$EnsureGroupStarted;->execute(Landroidx/compose/runtime/changelist/Operations$OpIterator;Landroidx/compose/runtime/Applier;Landroidx/compose/runtime/SlotWriter;Landroidx/compose/runtime/CompositionImpl$RememberEventDispatcher;)V
+PLandroidx/compose/runtime/changelist/Operation$EnsureRootGroupStarted;-><clinit>()V
+PLandroidx/compose/runtime/changelist/Operation$EnsureRootGroupStarted;-><init>()V
+PLandroidx/compose/runtime/changelist/Operation$EnsureRootGroupStarted;->execute(Landroidx/compose/runtime/changelist/Operations$OpIterator;Landroidx/compose/runtime/Applier;Landroidx/compose/runtime/SlotWriter;Landroidx/compose/runtime/CompositionImpl$RememberEventDispatcher;)V
+PLandroidx/compose/runtime/changelist/Operation$RemoveCurrentGroup;-><clinit>()V
+PLandroidx/compose/runtime/changelist/Operation$RemoveCurrentGroup;-><init>()V
+PLandroidx/compose/runtime/changelist/Operation$RemoveCurrentGroup;->execute(Landroidx/compose/runtime/changelist/Operations$OpIterator;Landroidx/compose/runtime/Applier;Landroidx/compose/runtime/SlotWriter;Landroidx/compose/runtime/CompositionImpl$RememberEventDispatcher;)V
+PLandroidx/compose/runtime/changelist/Operation$RemoveNode;-><clinit>()V
+PLandroidx/compose/runtime/changelist/Operation$RemoveNode;-><init>()V
+PLandroidx/compose/runtime/changelist/Operation$RemoveNode;->execute(Landroidx/compose/runtime/changelist/Operations$OpIterator;Landroidx/compose/runtime/Applier;Landroidx/compose/runtime/SlotWriter;Landroidx/compose/runtime/CompositionImpl$RememberEventDispatcher;)V
+PLandroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;->remove(IILandroidx/compose/runtime/Stack;)Landroidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode;
+PLandroidx/compose/runtime/saveable/SaveableHolder;->onForgotten()V
+PLandroidx/compose/runtime/saveable/SaveableStateRegistryImpl$registerProvider$3;->unregister()V
+PLandroidx/compose/runtime/snapshots/Snapshot$Companion$$ExternalSyntheticLambda0;->dispose()V
+PLandroidx/compose/runtime/snapshots/SnapshotIdSet$iterator$1;-><init>(Landroidx/compose/runtime/snapshots/SnapshotIdSet;Lkotlin/coroutines/Continuation;)V
+PLandroidx/compose/runtime/snapshots/SnapshotIdSet$iterator$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+PLandroidx/compose/runtime/snapshots/SnapshotIdSet$iterator$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/runtime/snapshots/SnapshotIdSet;->iterator()Ljava/util/Iterator;
+PLandroidx/compose/ui/autofill/AutofillCallback;->unregister(Landroidx/compose/ui/autofill/AndroidAutofill;)V
+PLandroidx/compose/ui/focus/FocusOwnerImpl;->clearFocus(ZZ)V
+PLandroidx/compose/ui/input/nestedscroll/NestedScrollNode;->onDetach()V
+PLandroidx/compose/ui/input/pointer/SuspendPointerInputElement;->equals(Ljava/lang/Object;)Z
+PLandroidx/compose/ui/input/pointer/SuspendingPointerInputModifierNodeImpl;->onDetach()V
+PLandroidx/compose/ui/input/pointer/SuspendingPointerInputModifierNodeImpl;->resetPointerInputHandler()V
+PLandroidx/compose/ui/layout/OnSizeChangedModifier;->equals(Ljava/lang/Object;)Z
+PLandroidx/compose/ui/modifier/ModifierLocalManager;->invalidate()V
+PLandroidx/compose/ui/node/BackwardsCompatNode;->onDetach()V
+PLandroidx/compose/ui/node/MeasureAndLayoutDelegate$PostponedRequest;-><init>(Landroidx/compose/ui/node/LayoutNode;ZZ)V
+PLandroidx/compose/ui/node/UiApplier;->remove(II)V
+PLandroidx/compose/ui/platform/AndroidComposeView;->getModifierLocalManager()Landroidx/compose/ui/modifier/ModifierLocalManager;
+PLandroidx/compose/ui/platform/AndroidComposeView;->onDetachedFromWindow()V
+PLandroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat$1;->onViewDetachedFromWindow(Landroid/view/View;)V
+PLandroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat$boundsUpdatesEventLoop$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat;->onStop(Landroidx/lifecycle/LifecycleOwner;)V
+PLandroidx/compose/ui/platform/DisposableSaveableStateRegistry_androidKt$DisposableSaveableStateRegistry$1;->invoke()Ljava/lang/Object;
+PLandroidx/compose/ui/platform/WeakCache;-><init>(Lcom/google/gson/internal/ConstructorConstructor;Ljava/lang/Class;)V
+PLandroidx/compose/ui/platform/WindowRecomposer_androidKt$createLifecycleAwareWindowRecomposer$1;->onViewDetachedFromWindow(Landroid/view/View;)V
+PLandroidx/compose/ui/platform/WrappedComposition;->dispose()V
+PLandroidx/compose/ui/text/PlatformTextStyle;->equals(Ljava/lang/Object;)Z
+PLandroidx/concurrent/futures/AbstractResolvableFuture$Listener;-><clinit>()V
+PLandroidx/concurrent/futures/AbstractResolvableFuture$SafeAtomicHelper;-><init>(Ljava/util/concurrent/atomic/AtomicReferenceFieldUpdater;Ljava/util/concurrent/atomic/AtomicReferenceFieldUpdater;Ljava/util/concurrent/atomic/AtomicReferenceFieldUpdater;Ljava/util/concurrent/atomic/AtomicReferenceFieldUpdater;Ljava/util/concurrent/atomic/AtomicReferenceFieldUpdater;)V
+PLandroidx/concurrent/futures/AbstractResolvableFuture$SafeAtomicHelper;->casListeners(Landroidx/concurrent/futures/AbstractResolvableFuture;Landroidx/concurrent/futures/AbstractResolvableFuture$Listener;)Z
+PLandroidx/concurrent/futures/AbstractResolvableFuture$SafeAtomicHelper;->casValue(Landroidx/concurrent/futures/AbstractResolvableFuture;Ljava/lang/Object;Ljava/lang/Object;)Z
+PLandroidx/concurrent/futures/AbstractResolvableFuture$SafeAtomicHelper;->casWaiters(Landroidx/concurrent/futures/AbstractResolvableFuture;Landroidx/concurrent/futures/AbstractResolvableFuture$Waiter;Landroidx/concurrent/futures/AbstractResolvableFuture$Waiter;)Z
+PLandroidx/concurrent/futures/AbstractResolvableFuture$Waiter;-><clinit>()V
+PLandroidx/concurrent/futures/AbstractResolvableFuture$Waiter;-><init>(I)V
+PLandroidx/concurrent/futures/AbstractResolvableFuture;-><clinit>()V
+PLandroidx/concurrent/futures/AbstractResolvableFuture;->complete(Landroidx/concurrent/futures/AbstractResolvableFuture;)V
+PLandroidx/core/view/ViewKt$ancestors$1;-><clinit>()V
+PLandroidx/core/view/ViewKt$ancestors$1;-><init>()V
+PLandroidx/core/view/ViewKt$ancestors$1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+PLandroidx/lifecycle/DefaultLifecycleObserver;->onDestroy(Landroidx/lifecycle/LifecycleOwner;)V
+PLandroidx/lifecycle/DefaultLifecycleObserver;->onStop(Landroidx/lifecycle/LifecycleOwner;)V
+PLandroidx/lifecycle/EmptyActivityLifecycleCallbacks;->onActivityDestroyed(Landroid/app/Activity;)V
+PLandroidx/lifecycle/EmptyActivityLifecycleCallbacks;->onActivityPaused(Landroid/app/Activity;)V
+PLandroidx/lifecycle/EmptyActivityLifecycleCallbacks;->onActivityStopped(Landroid/app/Activity;)V
+PLandroidx/lifecycle/ProcessLifecycleOwner$attach$1;->onActivityPaused(Landroid/app/Activity;)V
+PLandroidx/lifecycle/ProcessLifecycleOwner$attach$1;->onActivityStopped(Landroid/app/Activity;)V
+PLandroidx/lifecycle/ReportFragment$LifecycleCallbacks;->onActivityDestroyed(Landroid/app/Activity;)V
+PLandroidx/lifecycle/ReportFragment$LifecycleCallbacks;->onActivityPaused(Landroid/app/Activity;)V
+PLandroidx/lifecycle/ReportFragment$LifecycleCallbacks;->onActivityPreDestroyed(Landroid/app/Activity;)V
+PLandroidx/lifecycle/ReportFragment$LifecycleCallbacks;->onActivityPrePaused(Landroid/app/Activity;)V
+PLandroidx/lifecycle/ReportFragment$LifecycleCallbacks;->onActivityPreStopped(Landroid/app/Activity;)V
+PLandroidx/lifecycle/ReportFragment$LifecycleCallbacks;->onActivityStopped(Landroid/app/Activity;)V
+PLandroidx/lifecycle/ReportFragment;->onDestroy()V
+PLandroidx/lifecycle/ReportFragment;->onPause()V
+PLandroidx/lifecycle/ReportFragment;->onStop()V
+PLandroidx/metrics/performance/JankStatsApi24Impl;->removeFrameMetricsListenerDelegate(Landroidx/metrics/performance/JankStatsApi24Impl$$ExternalSyntheticLambda0;Landroid/view/Window;)V
+PLandroidx/profileinstaller/ProfileInstaller$$ExternalSyntheticLambda1;-><init>(I)V
+PLandroidx/profileinstaller/ProfileInstallerInitializer$$ExternalSyntheticLambda1;->run()V
+PLandroidx/profileinstaller/ProfileVerifier$Cache;-><init>(IIJJ)V
+PLandroidx/profileinstaller/ProfileVerifier$Cache;->writeOnFile(Ljava/io/File;)V
+PLandroidx/profileinstaller/ProfileVerifier;-><clinit>()V
+PLandroidx/profileinstaller/ProfileVerifier;->setCompilationStatus(IZZ)Landroidx/compose/ui/unit/Dp$Companion;
+PLandroidx/profileinstaller/ProfileVerifier;->writeProfileVerification(Landroid/content/Context;Z)V
+PLandroidx/tv/foundation/lazy/layout/LazyLayoutBeyondBoundsInfo$Interval;->equals(Ljava/lang/Object;)Z
+PLandroidx/tv/foundation/lazy/list/LazyLayoutBeyondBoundsModifierLocal;->getValue()Ljava/lang/Object;
+PLcom/example/tvcomposebasedtests/MainActivity;->onPause()V
+PLcom/google/gson/FieldNamingPolicy$1;-><init>()V
+PLcom/google/gson/FieldNamingPolicy$1;->translateName(Ljava/lang/reflect/Field;)Ljava/lang/String;
+PLcom/google/gson/FieldNamingPolicy$2;-><init>()V
+PLcom/google/gson/FieldNamingPolicy$3;-><init>()V
+PLcom/google/gson/FieldNamingPolicy$4;-><init>()V
+PLcom/google/gson/FieldNamingPolicy$5;-><init>()V
+PLcom/google/gson/FieldNamingPolicy$6;-><init>()V
+PLcom/google/gson/FieldNamingPolicy$7;-><init>()V
+PLcom/google/gson/FieldNamingPolicy;-><clinit>()V
+PLcom/google/gson/FieldNamingPolicy;-><init>(Ljava/lang/String;I)V
+PLcom/google/gson/Gson$1;-><init>(I)V
+PLcom/google/gson/Gson$3;-><init>(I)V
+PLcom/google/gson/Gson$4;-><init>(Lcom/google/gson/TypeAdapter;I)V
+PLcom/google/gson/Gson$FutureTypeAdapter;-><init>()V
+PLcom/google/gson/Gson;-><init>()V
+PLcom/google/gson/Gson;->newJsonWriter(Ljava/io/Writer;)Lcom/google/gson/stream/JsonWriter;
+PLcom/google/gson/Gson;->toJson(Lcom/google/gson/JsonObject;Lcom/google/gson/stream/JsonWriter;)V
+PLcom/google/gson/JsonNull;-><clinit>()V
+PLcom/google/gson/JsonPrimitive;-><init>(Ljava/lang/String;)V
+PLcom/google/gson/ToNumberPolicy$1;-><init>()V
+PLcom/google/gson/ToNumberPolicy$2;-><init>()V
+PLcom/google/gson/ToNumberPolicy$3;-><init>()V
+PLcom/google/gson/ToNumberPolicy$4;-><init>()V
+PLcom/google/gson/ToNumberPolicy;-><clinit>()V
+PLcom/google/gson/ToNumberPolicy;-><init>(Ljava/lang/String;I)V
+PLcom/google/gson/TypeAdapter;->nullSafe()Lcom/google/gson/Gson$4;
+PLcom/google/gson/internal/$Gson$Types$ParameterizedTypeImpl;-><init>(Ljava/lang/reflect/Type;Ljava/lang/reflect/Type;[Ljava/lang/reflect/Type;)V
+PLcom/google/gson/internal/$Gson$Types$ParameterizedTypeImpl;->getActualTypeArguments()[Ljava/lang/reflect/Type;
+PLcom/google/gson/internal/ConstructorConstructor;-><init>(Ljava/util/Map;Ljava/util/List;)V
+PLcom/google/gson/internal/ConstructorConstructor;->checkInstantiable(Ljava/lang/Class;)Ljava/lang/String;
+PLcom/google/gson/internal/ConstructorConstructor;->get(Lcom/google/gson/reflect/TypeToken;)Lcom/google/gson/internal/ObjectConstructor;
+PLcom/google/gson/internal/Excluder;-><clinit>()V
+PLcom/google/gson/internal/Excluder;-><init>()V
+PLcom/google/gson/internal/Excluder;->create(Lcom/google/gson/Gson;Lcom/google/gson/reflect/TypeToken;)Lcom/google/gson/TypeAdapter;
+PLcom/google/gson/internal/Excluder;->excludeClassInStrategy(Z)V
+PLcom/google/gson/internal/Excluder;->isAnonymousOrNonStaticLocal(Ljava/lang/Class;)Z
+PLcom/google/gson/internal/LinkedTreeMap$KeySet$1;-><init>(Landroidx/collection/ArrayMap$EntrySet;)V
+PLcom/google/gson/internal/LinkedTreeMap$KeySet$1;->next()Ljava/lang/Object;
+PLcom/google/gson/internal/LinkedTreeMap$LinkedTreeMapIterator;->nextNode()Lcom/google/gson/internal/LinkedTreeMap$Node;
+PLcom/google/gson/internal/LinkedTreeMap$Node;->getKey()Ljava/lang/Object;
+PLcom/google/gson/internal/LinkedTreeMap;-><clinit>()V
+PLcom/google/gson/internal/bind/ArrayTypeAdapter;-><clinit>()V
+PLcom/google/gson/internal/bind/CollectionTypeAdapterFactory;-><init>(Lcom/google/gson/internal/ConstructorConstructor;I)V
+PLcom/google/gson/internal/bind/CollectionTypeAdapterFactory;->create(Lcom/google/gson/Gson;Lcom/google/gson/reflect/TypeToken;)Lcom/google/gson/TypeAdapter;
+PLcom/google/gson/internal/bind/DateTypeAdapter;-><clinit>()V
+PLcom/google/gson/internal/bind/JsonTreeWriter$1;-><init>()V
+PLcom/google/gson/internal/bind/JsonTreeWriter;-><clinit>()V
+PLcom/google/gson/internal/bind/JsonTreeWriter;->beginObject()V
+PLcom/google/gson/internal/bind/JsonTreeWriter;->value(Ljava/lang/Boolean;)V
+PLcom/google/gson/internal/bind/MapTypeAdapterFactory;-><init>(Lcom/google/gson/internal/ConstructorConstructor;)V
+PLcom/google/gson/internal/bind/MapTypeAdapterFactory;->create(Lcom/google/gson/Gson;Lcom/google/gson/reflect/TypeToken;)Lcom/google/gson/TypeAdapter;
+PLcom/google/gson/internal/bind/NumberTypeAdapter$1;-><init>(ILjava/lang/Object;)V
+PLcom/google/gson/internal/bind/NumberTypeAdapter$1;->create(Lcom/google/gson/Gson;Lcom/google/gson/reflect/TypeToken;)Lcom/google/gson/TypeAdapter;
+PLcom/google/gson/internal/bind/NumberTypeAdapter;-><clinit>()V
+PLcom/google/gson/internal/bind/ObjectTypeAdapter;-><clinit>()V
+PLcom/google/gson/internal/bind/ObjectTypeAdapter;-><init>(Lcom/google/gson/Gson;)V
+PLcom/google/gson/internal/bind/ReflectiveTypeAdapterFactory$1;-><init>(Ljava/lang/String;Ljava/lang/reflect/Field;ZZLjava/lang/reflect/Method;ZLcom/google/gson/TypeAdapter;Lcom/google/gson/Gson;Lcom/google/gson/reflect/TypeToken;)V
+PLcom/google/gson/internal/bind/ReflectiveTypeAdapterFactory$Adapter;-><init>(Ljava/util/LinkedHashMap;)V
+PLcom/google/gson/internal/bind/ReflectiveTypeAdapterFactory;-><init>(Lcom/google/gson/internal/ConstructorConstructor;Lcom/google/gson/internal/Excluder;Lcom/google/gson/internal/bind/CollectionTypeAdapterFactory;Ljava/util/List;)V
+PLcom/google/gson/internal/bind/ReflectiveTypeAdapterFactory;->create(Lcom/google/gson/Gson;Lcom/google/gson/reflect/TypeToken;)Lcom/google/gson/TypeAdapter;
+PLcom/google/gson/internal/bind/ReflectiveTypeAdapterFactory;->getBoundFields(Lcom/google/gson/Gson;Lcom/google/gson/reflect/TypeToken;Ljava/lang/Class;Z)Ljava/util/LinkedHashMap;
+PLcom/google/gson/internal/bind/ReflectiveTypeAdapterFactory;->includeField(Ljava/lang/reflect/Field;Z)Z
+PLcom/google/gson/internal/bind/TypeAdapters$29;-><init>(I)V
+PLcom/google/gson/internal/bind/TypeAdapters$29;->create(Lcom/google/gson/Gson;Lcom/google/gson/reflect/TypeToken;)Lcom/google/gson/TypeAdapter;
+PLcom/google/gson/internal/bind/TypeAdapters$31;-><init>(Ljava/lang/Class;Lcom/google/gson/TypeAdapter;I)V
+PLcom/google/gson/internal/bind/TypeAdapters$31;->create(Lcom/google/gson/Gson;Lcom/google/gson/reflect/TypeToken;)Lcom/google/gson/TypeAdapter;
+PLcom/google/gson/internal/bind/TypeAdapters$32;-><init>(Ljava/lang/Class;Ljava/lang/Class;Lcom/google/gson/TypeAdapter;I)V
+PLcom/google/gson/internal/bind/TypeAdapters$32;->create(Lcom/google/gson/Gson;Lcom/google/gson/reflect/TypeToken;)Lcom/google/gson/TypeAdapter;
+PLcom/google/gson/internal/bind/TypeAdapters$34$1;-><init>(Lcom/google/gson/Gson;Ljava/lang/reflect/Type;Lcom/google/gson/TypeAdapter;Lcom/google/gson/internal/ObjectConstructor;)V
+PLcom/google/gson/internal/bind/TypeAdapters;-><clinit>()V
+PLcom/google/gson/internal/bind/TypeAdapters;->newFactory(Ljava/lang/Class;Lcom/google/gson/TypeAdapter;)Lcom/google/gson/internal/bind/TypeAdapters$31;
+PLcom/google/gson/internal/bind/TypeAdapters;->newFactory(Ljava/lang/Class;Ljava/lang/Class;Lcom/google/gson/TypeAdapter;)Lcom/google/gson/internal/bind/TypeAdapters$32;
+PLcom/google/gson/internal/reflect/ReflectionHelper$RecordNotSupportedHelper;-><init>()V
+PLcom/google/gson/internal/reflect/ReflectionHelper$RecordNotSupportedHelper;->isRecord(Ljava/lang/Class;)Z
+PLcom/google/gson/internal/reflect/ReflectionHelper$RecordSupportedHelper;-><init>()V
+PLcom/google/gson/internal/reflect/ReflectionHelper;-><clinit>()V
+PLcom/google/gson/internal/reflect/ReflectionHelper;->makeAccessible(Ljava/lang/reflect/AccessibleObject;)V
+PLcom/google/gson/internal/sql/SqlDateTypeAdapter;-><clinit>()V
+PLcom/google/gson/internal/sql/SqlTimeTypeAdapter;-><clinit>()V
+PLcom/google/gson/internal/sql/SqlTimestampTypeAdapter;-><clinit>()V
+PLcom/google/gson/internal/sql/SqlTypesSupport;-><clinit>()V
+PLcom/google/gson/stream/JsonWriter;-><clinit>()V
+PLcom/google/gson/stream/JsonWriter;->endArray()V
+PLcom/google/gson/stream/JsonWriter;->name(Ljava/lang/String;)V
+PLcom/google/gson/stream/JsonWriter;->newline()V
+PLkotlin/ResultKt;->SampleTvLazyColumn(ILandroidx/compose/runtime/Composer;I)V
+PLkotlin/ResultKt;->TvLazyColumn(Landroidx/compose/ui/Modifier;Landroidx/tv/foundation/lazy/list/TvLazyListState;Landroidx/compose/foundation/layout/PaddingValuesImpl;ZLandroidx/compose/foundation/layout/Arrangement$Vertical;Landroidx/compose/ui/Alignment$Horizontal;ZLandroidx/tv/foundation/PivotOffsets;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;II)V
+PLkotlin/ResultKt;->checkArgument(Z)V
+PLkotlin/ResultKt;->checkNotPrimitive(Ljava/lang/reflect/Type;)V
+PLkotlin/ResultKt;->equals(Ljava/lang/reflect/Type;Ljava/lang/reflect/Type;)Z
+PLkotlin/ResultKt;->getFilterResult(Ljava/util/List;)V
+PLkotlin/ResultKt;->getGenericSupertype(Ljava/lang/reflect/Type;Ljava/lang/Class;Ljava/lang/Class;)Ljava/lang/reflect/Type;
+PLkotlin/ResultKt;->getSupertype(Ljava/lang/reflect/Type;Ljava/lang/Class;Ljava/lang/Class;)Ljava/lang/reflect/Type;
+PLkotlin/ResultKt;->resolve(Ljava/lang/reflect/Type;Ljava/lang/Class;Ljava/lang/reflect/Type;Ljava/util/HashMap;)Ljava/lang/reflect/Type;
+PLkotlin/ResultKt;->write(Lcom/google/gson/JsonElement;Lcom/google/gson/stream/JsonWriter;)V
+PLkotlin/TuplesKt;-><init>(I)V
+PLkotlin/TuplesKt;-><init>(Ljava/lang/Object;)V
+PLkotlin/TuplesKt;->access$removeEntryAtIndex([Ljava/lang/Object;I)[Ljava/lang/Object;
+PLkotlin/TuplesKt;->asMutableCollection(Ljava/util/LinkedHashSet;)Ljava/util/Collection;
+PLkotlin/TuplesKt;->closeFinally(Ljava/io/Closeable;Ljava/lang/Throwable;)V
+PLkotlin/TuplesKt;->writeProfile(Landroid/content/Context;Landroidx/profileinstaller/ProfileInstaller$$ExternalSyntheticLambda1;Landroidx/profileinstaller/ProfileInstaller$DiagnosticsCallback;Z)V
+PLkotlin/ULong$Companion;->checkPositionIndex$kotlin_stdlib(II)V
+PLkotlin/ULong$Companion;->onResultReceived(ILjava/lang/Object;)V
+PLkotlin/collections/CollectionsKt___CollectionsKt;->minus(Ljava/util/List;Lkotlin/Function;)Ljava/util/ArrayList;
+PLkotlin/coroutines/jvm/internal/BaseContinuationImpl;->releaseIntercepted()V
+PLkotlin/coroutines/jvm/internal/RestrictedContinuationImpl;-><init>(Lkotlin/coroutines/Continuation;)V
+PLkotlin/coroutines/jvm/internal/RestrictedSuspendLambda;-><init>(Lkotlin/coroutines/Continuation;)V
+PLkotlin/sequences/SequenceBuilderIterator;-><init>()V
+PLkotlin/sequences/SequenceBuilderIterator;->getContext()Lkotlin/coroutines/CoroutineContext;
+PLkotlin/sequences/SequenceBuilderIterator;->hasNext()Z
+PLkotlin/sequences/SequenceBuilderIterator;->next()Ljava/lang/Object;
+PLkotlin/sequences/SequenceBuilderIterator;->resumeWith(Ljava/lang/Object;)V
+PLkotlin/sequences/SequenceBuilderIterator;->yield(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)V
+PLkotlin/text/Charsets;-><clinit>()V
+PLkotlinx/coroutines/AbstractCoroutine;->cancellationExceptionMessage()Ljava/lang/String;
+PLkotlinx/coroutines/InvokeOnCompletion;->invoke(Ljava/lang/Throwable;)V
+PLkotlinx/coroutines/JobCancellationException;-><init>(Ljava/lang/String;Ljava/lang/Throwable;Lkotlinx/coroutines/Job;)V
+PLkotlinx/coroutines/JobCancellationException;->equals(Ljava/lang/Object;)Z
+PLkotlinx/coroutines/JobCancellationException;->fillInStackTrace()Ljava/lang/Throwable;
+PLkotlinx/coroutines/JobSupport$Finishing;->isActive()Z
+PLkotlinx/coroutines/JobSupport;->cancellationExceptionMessage()Ljava/lang/String;
+PLkotlinx/coroutines/UndispatchedCoroutine;->afterResume(Ljava/lang/Object;)V
+PLkotlinx/coroutines/flow/FlowKt__ReduceKt$first$3;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+PLkotlinx/coroutines/flow/SharedFlowSlot;->freeLocked(Lkotlinx/coroutines/flow/internal/AbstractSharedFlow;)[Lkotlin/coroutines/Continuation;
+PLkotlinx/coroutines/flow/SharingConfig;->clear()V
+PLkotlinx/coroutines/flow/StateFlowSlot;->freeLocked(Lkotlinx/coroutines/flow/internal/AbstractSharedFlow;)[Lkotlin/coroutines/Continuation;
+PLkotlinx/coroutines/flow/internal/AbstractSharedFlow;->freeSlot(Lkotlinx/coroutines/flow/internal/AbstractSharedFlowSlot;)V
+PLkotlinx/coroutines/internal/DispatchedContinuation;->cancelCompletedResult$kotlinx_coroutines_core(Ljava/lang/Object;Ljava/util/concurrent/CancellationException;)V
+PLokhttp3/MediaType;->access$locationOf(Ljava/util/ArrayList;II)I
diff --git a/tv/onboarding.md b/tv/onboarding.md
index 32d68cf..70a6c9d 100644
--- a/tv/onboarding.md
+++ b/tv/onboarding.md
@@ -1,51 +1,64 @@
 # Onboarding to Compose for TV libraries
 
-## Getting Started
+## Learn about Jetpack Compose
+1. The [Compose landing page][compose-landing-page] provides an overview of Compose and its features.
+2. The [Compose Quick Tutorial][compose-quick-tutorial] walks you through the basics of Compose using code examples.
+3. The [Compose Course][compose-course] is a more comprehensive guide to Compose, covering topics such as layout, animations, and state management.
 
-1. See what Google suggests are [good design patterns][good-design-patterns]
-   and [offered components][tv-components]
-2. Consult the documentation for information on the packages and various components that are
-   offered.
-    * [tv-foundation][tv-foundation]
-    * [tv-foundation-lazy-list][tv-foundation-lazy-list]
-    * [tv-foundation-lazy-grid][tv-foundation-lazy-grid]
-    * [tv-material][tv-material]
-3. Read documentation and examples on [developer.android.com][dac]
-4. Read up on the [codelabs][codelabs]
-5. Ensure that you are on the latest version of [Compose for TV libraries][compose-for-tv-libraries]
+
+## Learn about Compose for TV
+1. Explore the [available components][tv-components] and the [design patterns][good-design-patterns] that Google recommends.
+2. Consult the documentation for information on the packages and various components available.
+   * [tv-foundation][tv-foundation]
+   * [tv-foundation-lazy-list][tv-foundation-lazy-list]
+   * [tv-foundation-lazy-grid][tv-foundation-lazy-grid]
+   * [tv-material][tv-material]
+3. Refer to the documentation and examples on [developer.android.com][dac].
+4. Get up to speed with the [codelabs][codelabs].
+5. Find the sample app on [GitHub][github-sample-app].
+
+## If you run into issues
+1. Make sure that you are using the most recent version of [Compose for TV libraries][compose-for-tv-libraries]
    and Jetpack compose.
-6. Read the FAQs below
-7. Check with the community
-    * [stack overflow][stackoverflow]
-    * slack (TBD)
-    * discord (TBD)
-8. Check if there is a bug already reported on [issue-tracker][issue-tracker]
-9. [File a bug on issue-tracker][issue-tracker-file-a-bug]
-10. Contact a Developer Relations partner from Google who can involve someone from the engineering
-    team as necessary
+2. Read the FAQs below.
+3. Check with the community over on  [stack overflow][stackoverflow].
+4. Check if there is a bug already reported on [issue-tracker][issue-tracker].
+5. File a bug on [issue-tracker][issue-tracker-file-a-bug].
+6. Reach out to a Google Developer Relations partner who can, if necessary, bring in someone from the engineering team.
 
 ## FAQs
 
-1. How can I improve the performance of my app written using tv-compose?
-    * Any [performance improvements][improve-performance] suggested for a Compose app would
-      generally apply to apps built with Compose for TV libraries too.
-    * Use [baseline profiles][baseline-profiles] as recommended
-      in [Jetpack Compose Performance guide][jetpack-compose-performance].
-      Watch [Making apps blazing fast with Baseline Profiles][making-apps-blazing-fast-with-baseline-profiles]
-    * Checkout [Interpreting Compose Compiler Metrics][interpreting-compose-compiler-metrics].
-2. My app is crashing!
-    * Ensure that you are on the latest alpha version
-      of [Compose for TV libraries][compose-for-tv-libraries] and Jetpack Compose
-    * Check if there is a bug already reported on [issue-tracker][issue-tracker]
-    * [File a bug on issue-tracker][issue-tracker-file-a-bug]
-3. The Navigation drawer is pushing my content aside. I don’t like it.
+1. ### How can I improve the performance of my app written using tv-compose?
+   * [Performance improvements][improve-performance] suggested for a Compose app would typically apply to apps built with Compose for TV libraries as well.
+   * Use [baseline profiles][baseline-profiles] as recommended
+     in [Jetpack Compose Performance guide][jetpack-compose-performance].
+     Watch [Making apps blazing fast with Baseline Profiles][making-apps-blazing-fast-with-baseline-profiles].
+   * Check out [Interpreting Compose Compiler Metrics][interpreting-compose-compiler-metrics].
+2. ### My app is crashing!
+   * Ensure that you are on the latest version.
+     of [Compose for TV libraries][compose-for-tv-libraries] and Jetpack Compose
+   * Check if there is a bug already reported on [issue-tracker][issue-tracker].
+   * [File a bug on issue-tracker][issue-tracker-file-a-bug].
+3. ### The Navigation drawer is pushing my content aside. I don’t like it.
    Consider using a [Modal Navigation Drawer][modal-navigation-drawer] provided
-   in [Compose for TV library][compose-for-tv-modal-navigation-drawer]
+   in [Compose for TV library][compose-for-tv-modal-navigation-drawer].
+4. ### Sideloading baseline profiles to test performance, without releasing the app.
+   Refer to the steps for [applying baseline profiles][tv-samples-baseline-profiles] in the
+   Jetstream sample app.
+
+
+[compose-landing-page]: https://developer.android.com/jetpack/compose
+
+[compose-quick-tutorial]: https://developer.android.com/jetpack/compose/tutorial
+
+[compose-course]: https://developer.android.com/courses/jetpack-compose/course
 
 [good-design-patterns]: https://developer.android.com/design/ui/tv
 
 [dac]: https://developer.android.com/training/tv/playback/compose
 
+[github-sample-app]: https://github.com/android/tv-samples/tree/main/JetStreamCompose
+
 [modal-navigation-drawer]: https://m3.material.io/components/navigation-drawer/overview#15a3aa10-1be4-4be4-8370-36a1779f65e5
 
 [compose-for-tv-modal-navigation-drawer]: https://developer.android.com/reference/kotlin/androidx/tv/material3/package-summary#ModalNavigationDrawer(kotlin.Function1,androidx.compose.ui.Modifier,androidx.tv.material3.DrawerState,androidx.compose.ui.graphics.Color,kotlin.Function0)
@@ -79,3 +92,5 @@
 [tv-foundation-lazy-grid]: https://developer.android.com/reference/kotlin/androidx/tv/foundation/lazy/grid/package-summary
 
 [tv-material]: https://developer.android.com/reference/kotlin/androidx/tv/material3/package-summary
+
+[tv-samples-baseline-profiles]: https://github.com/android/tv-samples/blob/main/JetStreamCompose/baseline-profiles.md
\ No newline at end of file
diff --git a/tv/tv-material/api/api_lint.ignore b/tv/tv-material/api/api_lint.ignore
new file mode 100644
index 0000000..5954166
--- /dev/null
+++ b/tv/tv-material/api/api_lint.ignore
@@ -0,0 +1,4 @@
+// Baseline format: 1.0
+
+GetterSetterNames: field NavigationDrawerScope.doesNavigationDrawerHaveFocus:
+    Invalid name for boolean property `doesNavigationDrawerHaveFocus`. Should start with one of `has`, `can`, `should`, `is`.
\ No newline at end of file
diff --git a/tv/tv-material/api/current.txt b/tv/tv-material/api/current.txt
index 1ea43bf..dcdfda26 100644
--- a/tv/tv-material/api/current.txt
+++ b/tv/tv-material/api/current.txt
@@ -690,6 +690,10 @@
     property public final androidx.tv.material3.Glow selectedGlow;
   }
 
+  public final class NavigationDrawerItemKt {
+    method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void NavigationDrawerItem(androidx.tv.material3.NavigationDrawerScope, boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> leadingContent, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingContent, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingContent, optional float tonalElevation, optional androidx.tv.material3.NavigationDrawerItemShape shape, optional androidx.tv.material3.NavigationDrawerItemColors colors, optional androidx.tv.material3.NavigationDrawerItemScale scale, optional androidx.tv.material3.NavigationDrawerItemBorder border, optional androidx.tv.material3.NavigationDrawerItemGlow glow, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+  }
+
   @SuppressCompatibility @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class NavigationDrawerItemScale {
     ctor public NavigationDrawerItemScale(@FloatRange(from=0.0) float scale, @FloatRange(from=0.0) float focusedScale, @FloatRange(from=0.0) float pressedScale, @FloatRange(from=0.0) float selectedScale, @FloatRange(from=0.0) float disabledScale, @FloatRange(from=0.0) float focusedSelectedScale, @FloatRange(from=0.0) float focusedDisabledScale, @FloatRange(from=0.0) float pressedSelectedScale);
     method public float getDisabledScale();
@@ -737,14 +741,14 @@
   }
 
   public final class NavigationDrawerKt {
-    method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void ModalNavigationDrawer(kotlin.jvm.functions.Function1<? super androidx.tv.material3.DrawerValue,kotlin.Unit> drawerContent, optional androidx.compose.ui.Modifier modifier, optional androidx.tv.material3.DrawerState drawerState, optional androidx.compose.ui.graphics.Brush scrimBrush, kotlin.jvm.functions.Function0<kotlin.Unit> content);
-    method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void NavigationDrawer(kotlin.jvm.functions.Function1<? super androidx.tv.material3.DrawerValue,kotlin.Unit> drawerContent, optional androidx.compose.ui.Modifier modifier, optional androidx.tv.material3.DrawerState drawerState, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void ModalNavigationDrawer(kotlin.jvm.functions.Function2<? super androidx.tv.material3.NavigationDrawerScope,? super androidx.tv.material3.DrawerValue,kotlin.Unit> drawerContent, optional androidx.compose.ui.Modifier modifier, optional androidx.tv.material3.DrawerState drawerState, optional androidx.compose.ui.graphics.Brush scrimBrush, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void NavigationDrawer(kotlin.jvm.functions.Function2<? super androidx.tv.material3.NavigationDrawerScope,? super androidx.tv.material3.DrawerValue,kotlin.Unit> drawerContent, optional androidx.compose.ui.Modifier modifier, optional androidx.tv.material3.DrawerState drawerState, kotlin.jvm.functions.Function0<kotlin.Unit> content);
     method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static androidx.tv.material3.DrawerState rememberDrawerState(androidx.tv.material3.DrawerValue initialValue);
   }
 
   @SuppressCompatibility @androidx.tv.material3.ExperimentalTvMaterial3Api public interface NavigationDrawerScope {
-    method public boolean isActivated();
-    property public abstract boolean isActivated;
+    method public boolean getDoesNavigationDrawerHaveFocus();
+    property public abstract boolean doesNavigationDrawerHaveFocus;
   }
 
   @SuppressCompatibility @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class NonInteractiveSurfaceColors {
diff --git a/tv/tv-material/api/restricted_current.txt b/tv/tv-material/api/restricted_current.txt
index 1ea43bf..dcdfda26 100644
--- a/tv/tv-material/api/restricted_current.txt
+++ b/tv/tv-material/api/restricted_current.txt
@@ -690,6 +690,10 @@
     property public final androidx.tv.material3.Glow selectedGlow;
   }
 
+  public final class NavigationDrawerItemKt {
+    method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void NavigationDrawerItem(androidx.tv.material3.NavigationDrawerScope, boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> leadingContent, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingContent, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingContent, optional float tonalElevation, optional androidx.tv.material3.NavigationDrawerItemShape shape, optional androidx.tv.material3.NavigationDrawerItemColors colors, optional androidx.tv.material3.NavigationDrawerItemScale scale, optional androidx.tv.material3.NavigationDrawerItemBorder border, optional androidx.tv.material3.NavigationDrawerItemGlow glow, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+  }
+
   @SuppressCompatibility @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class NavigationDrawerItemScale {
     ctor public NavigationDrawerItemScale(@FloatRange(from=0.0) float scale, @FloatRange(from=0.0) float focusedScale, @FloatRange(from=0.0) float pressedScale, @FloatRange(from=0.0) float selectedScale, @FloatRange(from=0.0) float disabledScale, @FloatRange(from=0.0) float focusedSelectedScale, @FloatRange(from=0.0) float focusedDisabledScale, @FloatRange(from=0.0) float pressedSelectedScale);
     method public float getDisabledScale();
@@ -737,14 +741,14 @@
   }
 
   public final class NavigationDrawerKt {
-    method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void ModalNavigationDrawer(kotlin.jvm.functions.Function1<? super androidx.tv.material3.DrawerValue,kotlin.Unit> drawerContent, optional androidx.compose.ui.Modifier modifier, optional androidx.tv.material3.DrawerState drawerState, optional androidx.compose.ui.graphics.Brush scrimBrush, kotlin.jvm.functions.Function0<kotlin.Unit> content);
-    method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void NavigationDrawer(kotlin.jvm.functions.Function1<? super androidx.tv.material3.DrawerValue,kotlin.Unit> drawerContent, optional androidx.compose.ui.Modifier modifier, optional androidx.tv.material3.DrawerState drawerState, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void ModalNavigationDrawer(kotlin.jvm.functions.Function2<? super androidx.tv.material3.NavigationDrawerScope,? super androidx.tv.material3.DrawerValue,kotlin.Unit> drawerContent, optional androidx.compose.ui.Modifier modifier, optional androidx.tv.material3.DrawerState drawerState, optional androidx.compose.ui.graphics.Brush scrimBrush, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void NavigationDrawer(kotlin.jvm.functions.Function2<? super androidx.tv.material3.NavigationDrawerScope,? super androidx.tv.material3.DrawerValue,kotlin.Unit> drawerContent, optional androidx.compose.ui.Modifier modifier, optional androidx.tv.material3.DrawerState drawerState, kotlin.jvm.functions.Function0<kotlin.Unit> content);
     method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static androidx.tv.material3.DrawerState rememberDrawerState(androidx.tv.material3.DrawerValue initialValue);
   }
 
   @SuppressCompatibility @androidx.tv.material3.ExperimentalTvMaterial3Api public interface NavigationDrawerScope {
-    method public boolean isActivated();
-    property public abstract boolean isActivated;
+    method public boolean getDoesNavigationDrawerHaveFocus();
+    property public abstract boolean doesNavigationDrawerHaveFocus;
   }
 
   @SuppressCompatibility @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class NonInteractiveSurfaceColors {
diff --git a/tv/tv-material/src/androidTest/java/androidx/tv/material3/NavigationDrawerItemScreenshotTest.kt b/tv/tv-material/src/androidTest/java/androidx/tv/material3/NavigationDrawerItemScreenshotTest.kt
new file mode 100644
index 0000000..e98dd07
--- /dev/null
+++ b/tv/tv-material/src/androidTest/java/androidx/tv/material3/NavigationDrawerItemScreenshotTest.kt
@@ -0,0 +1,379 @@
+/*
+ * Copyright 2023 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.tv.material3
+
+import android.os.Build
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Favorite
+import androidx.compose.runtime.Composable
+import androidx.compose.testutils.assertAgainstGolden
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.test.captureToImage
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onChild
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.requestFocus
+import androidx.compose.ui.unit.dp
+import androidx.test.filters.LargeTest
+import androidx.test.filters.SdkSuppress
+import androidx.test.screenshot.AndroidXScreenshotTestRule
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+@LargeTest
+@RunWith(Parameterized::class)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+@OptIn(ExperimentalTvMaterial3Api::class)
+class NavigationDrawerItemScreenshotTest(private val scheme: ColorSchemeWrapper) {
+    @get:Rule
+    val rule = createComposeRule()
+
+    @get:Rule
+    val screenshotRule = AndroidXScreenshotTestRule(TV_GOLDEN_MATERIAL3)
+
+    val wrapperModifier = Modifier
+        .testTag(NavigationDrawerItemWrapperTag)
+        .background(scheme.colorScheme.surface)
+        .padding(20.dp)
+
+    @Test
+    fun navigationDrawerItem_customColor() {
+        rule.setMaterialContent(scheme.colorScheme) {
+            DrawerScope {
+                NavigationDrawerItem(
+                    selected = false,
+                    onClick = {},
+                    leadingContent = {
+                        Icon(
+                            imageVector = Icons.Filled.Favorite,
+                            contentDescription = null,
+                            modifier = Modifier.size(NavigationDrawerItemDefaults.IconSize)
+                        )
+                    },
+                    colors = NavigationDrawerItemDefaults.colors(containerColor = Color.Red)
+                ) {
+                    Text("Favourite")
+                }
+            }
+        }
+
+        assertAgainstGolden("navigationDrawerItem_${scheme.name}_customColor")
+    }
+
+    @Test
+    fun navigationDrawerItem_oneLine() {
+        rule.setMaterialContent(scheme.colorScheme) {
+            DrawerScope {
+                NavigationDrawerItem(
+                    selected = false,
+                    onClick = {},
+                    leadingContent = {
+                        Icon(
+                            imageVector = Icons.Filled.Favorite,
+                            contentDescription = null,
+                            modifier = Modifier.size(NavigationDrawerItemDefaults.IconSize)
+                        )
+                    }
+                ) {
+                    Text("Favourite")
+                }
+            }
+        }
+
+        assertAgainstGolden("navigationDrawerItem_${scheme.name}_oneLine")
+    }
+
+    @Test
+    fun navigationDrawerItem_twoLine() {
+        rule.setMaterialContent(scheme.colorScheme) {
+            DrawerScope {
+                NavigationDrawerItem(
+                    selected = false,
+                    onClick = {},
+                    leadingContent = {
+                        Icon(
+                            imageVector = Icons.Filled.Favorite,
+                            contentDescription = null,
+                            modifier = Modifier.size(NavigationDrawerItemDefaults.IconSize)
+                        )
+                    },
+                    supportingContent = { Text("You like this") }
+                ) {
+                    Text("Favourite")
+                }
+            }
+        }
+
+        assertAgainstGolden("navigationDrawerItem_${scheme.name}_twoLine")
+    }
+
+    @Test
+    fun navigationDrawerItem_twoLine_focused() {
+        rule.setMaterialContent(scheme.colorScheme) {
+            DrawerScope {
+                NavigationDrawerItem(
+                    selected = false,
+                    onClick = {},
+                    leadingContent = {
+                        Icon(
+                            imageVector = Icons.Filled.Favorite,
+                            contentDescription = null,
+                            modifier = Modifier.size(NavigationDrawerItemDefaults.IconSize)
+                        )
+                    },
+                    supportingContent = { Text("You like this") }
+                ) {
+                    Text("Favourite")
+                }
+            }
+        }
+
+        rule.onNodeWithTag(NavigationDrawerItemWrapperTag)
+            .onChild()
+            .requestFocus()
+        rule.waitForIdle()
+
+        assertAgainstGolden("navigationDrawerItem_${scheme.name}_twoLine_focused")
+    }
+
+    @Test
+    fun navigationDrawerItem_twoLine_disabled() {
+        rule.setMaterialContent(scheme.colorScheme) {
+            DrawerScope {
+                NavigationDrawerItem(
+                    selected = false,
+                    onClick = {},
+                    enabled = false,
+                    leadingContent = {
+                        Icon(
+                            imageVector = Icons.Filled.Favorite,
+                            contentDescription = null,
+                            modifier = Modifier.size(NavigationDrawerItemDefaults.IconSize)
+                        )
+                    },
+                    supportingContent = { Text("You like this") }
+                ) {
+                    Text("Favourite")
+                }
+            }
+        }
+
+        assertAgainstGolden("navigationDrawerItem_${scheme.name}_twoLine_disabled")
+    }
+
+    @Test
+    fun navigationDrawerItem_twoLine_focusedDisabled() {
+        rule.setMaterialContent(scheme.colorScheme) {
+            DrawerScope {
+                NavigationDrawerItem(
+                    selected = false,
+                    onClick = {},
+                    enabled = false,
+                    leadingContent = {
+                        Icon(
+                            imageVector = Icons.Filled.Favorite,
+                            contentDescription = null,
+                            modifier = Modifier.size(NavigationDrawerItemDefaults.IconSize)
+                        )
+                    },
+                    supportingContent = { Text("You like this") }
+                ) {
+                    Text("Favourite")
+                }
+            }
+        }
+
+        rule.onNodeWithTag(NavigationDrawerItemWrapperTag)
+            .onChild()
+            .requestFocus()
+        rule.waitForIdle()
+
+        assertAgainstGolden("navigationDrawerItem_${scheme.name}_twoLine_focusedDisabled")
+    }
+
+    @Test
+    fun navigationDrawerItem_twoLine_selected() {
+        rule.setMaterialContent(scheme.colorScheme) {
+            DrawerScope {
+                NavigationDrawerItem(
+                    selected = true,
+                    onClick = {},
+                    leadingContent = {
+                        Icon(
+                            imageVector = Icons.Filled.Favorite,
+                            contentDescription = null,
+                            modifier = Modifier.size(NavigationDrawerItemDefaults.IconSize)
+                        )
+                    },
+                    supportingContent = { Text("You like this") }
+                ) {
+                    Text("Favourite")
+                }
+            }
+        }
+
+        assertAgainstGolden("navigationDrawerItem_${scheme.name}_twoLine_selected")
+    }
+
+    @Test
+    fun navigationDrawerItem_twoLine_focusedSelected() {
+        rule.setMaterialContent(scheme.colorScheme) {
+            DrawerScope {
+                NavigationDrawerItem(
+                    selected = true,
+                    onClick = {},
+                    leadingContent = {
+                        Icon(
+                            imageVector = Icons.Filled.Favorite,
+                            contentDescription = null,
+                            modifier = Modifier.size(NavigationDrawerItemDefaults.IconSize)
+                        )
+                    },
+                    supportingContent = { Text("You like this") }
+                ) {
+                    Text("Favourite")
+                }
+            }
+        }
+
+        rule.onNodeWithTag(NavigationDrawerItemWrapperTag)
+            .onChild()
+            .requestFocus()
+        rule.waitForIdle()
+
+        assertAgainstGolden("navigationDrawerItem_${scheme.name}_twoLine_focusedSelected")
+    }
+
+    @Test
+    fun navigationDrawerItem_inactive() {
+        rule.setMaterialContent(scheme.colorScheme) {
+            DrawerScope(false) {
+                NavigationDrawerItem(
+                    selected = false,
+                    onClick = {},
+                    leadingContent = {
+                        Icon(
+                            imageVector = Icons.Filled.Favorite,
+                            contentDescription = null,
+                            modifier = Modifier.size(NavigationDrawerItemDefaults.IconSize)
+                        )
+                    },
+                ) {
+                    Text("Favourite")
+                }
+            }
+        }
+
+        assertAgainstGolden("navigationDrawerItem_${scheme.name}_inactive")
+    }
+
+    @Test
+    fun navigationDrawerItem_inactive_selected() {
+        rule.setMaterialContent(scheme.colorScheme) {
+            DrawerScope(false) {
+                NavigationDrawerItem(
+                    selected = true,
+                    onClick = {},
+                    leadingContent = {
+                        Icon(
+                            imageVector = Icons.Filled.Favorite,
+                            contentDescription = null,
+                            modifier = Modifier.size(NavigationDrawerItemDefaults.IconSize)
+                        )
+                    },
+                ) {
+                    Text("Favourite")
+                }
+            }
+        }
+
+        assertAgainstGolden("navigationDrawerItem_${scheme.name}_inactive_selected")
+    }
+
+    @Test
+    fun navigationDrawerItem_twoLine_withTrailingContent() {
+        rule.setMaterialContent(scheme.colorScheme) {
+            DrawerScope {
+                NavigationDrawerItem(
+                    selected = false,
+                    onClick = {},
+                    leadingContent = {
+                        Icon(
+                            imageVector = Icons.Filled.Favorite,
+                            contentDescription = null,
+                            modifier = Modifier.size(NavigationDrawerItemDefaults.IconSize)
+                        )
+                    },
+                    supportingContent = { Text("You like this") },
+                    trailingContent = {
+                        NavigationDrawerItemDefaults.TrailingBadge("NEW")
+                    }
+                ) {
+                    Text("Favourite")
+                }
+            }
+        }
+
+        assertAgainstGolden("navigationDrawerItem_${scheme.name}_twoLine_withTrailingContent")
+    }
+
+    private fun assertAgainstGolden(goldenName: String) {
+        rule.onNodeWithTag(NavigationDrawerItemWrapperTag)
+            .captureToImage()
+            .assertAgainstGolden(screenshotRule, goldenName)
+    }
+
+    // Provide the ColorScheme and their name parameter in a ColorSchemeWrapper.
+    // This makes sure that the default method name and the initial Scuba image generated
+    // name is as expected.
+    companion object {
+        @Parameterized.Parameters(name = "{0}")
+        @JvmStatic
+        fun parameters() = arrayOf(
+            ColorSchemeWrapper("lightTheme", lightColorScheme()),
+            ColorSchemeWrapper("darkTheme", darkColorScheme()),
+        )
+    }
+
+    class ColorSchemeWrapper constructor(val name: String, val colorScheme: ColorScheme) {
+        override fun toString(): String {
+            return name
+        }
+    }
+
+    @Composable
+    private fun DrawerScope(
+        doesNavigationDrawerHaveFocus: Boolean = true,
+        content: @Composable NavigationDrawerScope.() -> Unit
+    ) {
+        Box(wrapperModifier) {
+            NavigationDrawerScopeImpl(doesNavigationDrawerHaveFocus).apply {
+                content()
+            }
+        }
+    }
+}
+
+private const val NavigationDrawerItemWrapperTag = "navigationDrawerItem_wrapper"
diff --git a/tv/tv-material/src/androidTest/java/androidx/tv/material3/NavigationDrawerItemTest.kt b/tv/tv-material/src/androidTest/java/androidx/tv/material3/NavigationDrawerItemTest.kt
new file mode 100644
index 0000000..74d9ee4
--- /dev/null
+++ b/tv/tv-material/src/androidTest/java/androidx/tv/material3/NavigationDrawerItemTest.kt
@@ -0,0 +1,443 @@
+/*
+ * Copyright 2023 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.tv.material3
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.border
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.size
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.input.key.Key
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.semantics.SemanticsActions
+import androidx.compose.ui.semantics.SemanticsProperties
+import androidx.compose.ui.test.ExperimentalTestApi
+import androidx.compose.ui.test.SemanticsMatcher
+import androidx.compose.ui.test.assert
+import androidx.compose.ui.test.assertHasClickAction
+import androidx.compose.ui.test.assertHeightIsEqualTo
+import androidx.compose.ui.test.assertIsEnabled
+import androidx.compose.ui.test.assertIsEqualTo
+import androidx.compose.ui.test.assertIsNotEnabled
+import androidx.compose.ui.test.assertWidthIsEqualTo
+import androidx.compose.ui.test.getUnclippedBoundsInRoot
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.onRoot
+import androidx.compose.ui.test.performKeyInput
+import androidx.compose.ui.test.pressKey
+import androidx.compose.ui.test.requestFocus
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.width
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
+import com.google.common.truth.Truth
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(
+    ExperimentalTestApi::class,
+    ExperimentalTvMaterial3Api::class
+)
+@LargeTest
+@RunWith(AndroidJUnit4::class)
+class NavigationDrawerItemTest {
+    @get:Rule
+    val rule = createComposeRule()
+
+    @Test
+    fun navigationDrawerItem_findByTagAndClick() {
+        var counter = 0
+        val onClick: () -> Unit = { ++counter }
+
+        rule.setContent {
+            DrawerScope {
+                NavigationDrawerItem(
+                    selected = false,
+                    onClick = onClick,
+                    leadingContent = { },
+                    modifier = Modifier.testTag(NavigationDrawerItemTag),
+                ) {
+                    Text(text = "Test Text")
+                }
+            }
+        }
+
+        rule.onNodeWithTag(NavigationDrawerItemTag)
+            .requestFocus()
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+        rule.runOnIdle {
+            Truth.assertThat(counter).isEqualTo(1)
+        }
+    }
+
+    @Test
+    fun navigationDrawerItem_clickIsIndependentBetweenItems() {
+        var openItemClickCounter = 0
+        val openItemOnClick: () -> Unit = { ++openItemClickCounter }
+        val openItemTag = "OpenItem"
+
+        var closeItemClickCounter = 0
+        val closeItemOnClick: () -> Unit = { ++closeItemClickCounter }
+        val closeItemTag = "CloseItem"
+
+        rule.setContent {
+            DrawerScope {
+                Column {
+                    NavigationDrawerItem(
+                        selected = false,
+                        onClick = openItemOnClick,
+                        leadingContent = { },
+                        modifier = Modifier.testTag(openItemTag),
+                    ) {
+                        Text(text = "Test Text")
+                    }
+                    NavigationDrawerItem(
+                        selected = false,
+                        onClick = closeItemOnClick,
+                        leadingContent = { },
+                        modifier = Modifier.testTag(closeItemTag),
+                    ) {
+                        Text(text = "Test Text")
+                    }
+                }
+            }
+        }
+
+        rule.onNodeWithTag(openItemTag)
+            .requestFocus()
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+
+        rule.runOnIdle {
+            Truth.assertThat(openItemClickCounter).isEqualTo(1)
+            Truth.assertThat(closeItemClickCounter).isEqualTo(0)
+        }
+
+        rule.onNodeWithTag(closeItemTag)
+            .requestFocus()
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+
+        rule.runOnIdle {
+            Truth.assertThat(openItemClickCounter).isEqualTo(1)
+            Truth.assertThat(closeItemClickCounter).isEqualTo(1)
+        }
+    }
+
+    @Test
+    fun navigationDrawerItem_longClickAction() {
+        var counter = 0
+        val onLongClick: () -> Unit = { ++counter }
+
+        rule.setContent {
+            DrawerScope {
+                NavigationDrawerItem(
+                    selected = false,
+                    onClick = { },
+                    onLongClick = onLongClick,
+                    leadingContent = { },
+                    modifier = Modifier.testTag(NavigationDrawerItemTag),
+                ) {
+                    Text(text = "Test Text")
+                }
+            }
+        }
+
+        rule.onNodeWithTag(NavigationDrawerItemTag)
+            .requestFocus()
+            .performLongKeyPress(rule, Key.DirectionCenter)
+        rule.runOnIdle {
+            Truth.assertThat(counter).isEqualTo(1)
+        }
+
+        rule.onNodeWithTag(NavigationDrawerItemTag)
+            .requestFocus()
+            .performLongKeyPress(rule, Key.DirectionCenter, count = 2)
+        rule.runOnIdle {
+            Truth.assertThat(counter).isEqualTo(3)
+        }
+    }
+
+    @Test
+    fun navigationDrawerItem_findByTagAndStateChangeCheck() {
+        var checkedState by mutableStateOf(true)
+        val onClick: () -> Unit = { checkedState = !checkedState }
+
+        rule.setContent {
+            DrawerScope {
+                NavigationDrawerItem(
+                    selected = checkedState,
+                    onClick = onClick,
+                    leadingContent = { },
+                    modifier = Modifier.testTag(NavigationDrawerItemTag),
+                ) {
+                    Text(text = "Test Text")
+                }
+            }
+        }
+
+        rule.onNodeWithTag(NavigationDrawerItemTag)
+            .requestFocus()
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+        rule.runOnIdle {
+            Truth.assertThat(!checkedState)
+        }
+    }
+
+    @Test
+    fun navigationDrawerItem_trailingContentPadding() {
+        val testTrailingContentTag = "TrailingIconTag"
+
+        rule.setContent {
+            DrawerScope {
+                NavigationDrawerItem(
+                    selected = false,
+                    onClick = {},
+                    trailingContent = {
+                        Box(
+                            modifier = Modifier
+                                .size(NavigationDrawerItemDefaults.IconSize)
+                                .background(Color.Red)
+                                .testTag(testTrailingContentTag)
+                        )
+                    },
+                    leadingContent = { },
+                    modifier = Modifier
+                        .testTag(NavigationDrawerItemTag)
+                        .border(1.dp, Color.Blue),
+                ) {
+                    Text(
+                        text = "Test Text",
+                        modifier = Modifier
+                            .testTag(NavigationDrawerItemTextTag)
+                            .fillMaxWidth()
+                    )
+                }
+            }
+        }
+
+        rule.waitForIdle()
+
+        val itemBounds = rule.onNodeWithTag(NavigationDrawerItemTag).getUnclippedBoundsInRoot()
+        val textBounds = rule.onNodeWithTag(
+            NavigationDrawerItemTextTag,
+            useUnmergedTree = true
+        ).getUnclippedBoundsInRoot()
+        val trailingContentBounds = rule
+            .onNodeWithTag(testTrailingContentTag, useUnmergedTree = true)
+            .getUnclippedBoundsInRoot()
+
+        (itemBounds.bottom - trailingContentBounds.bottom).assertIsEqualTo(
+            16.dp,
+            "padding between the bottom of the trailing content and the bottom of the nav " +
+                "drawer item"
+        )
+
+        (itemBounds.right - trailingContentBounds.right).assertIsEqualTo(
+            16.dp,
+            "padding between the end of the trailing content and the end of the nav drawer item"
+        )
+
+        (trailingContentBounds.left - textBounds.right).assertIsEqualTo(
+            8.dp,
+            "padding between the start of the trailing content and the end of the text."
+        )
+    }
+
+    @Test
+    fun navigationDrawerItem_semantics() {
+        var selected by mutableStateOf(false)
+        rule.setContent {
+            DrawerScope {
+                NavigationDrawerItem(
+                    selected = selected,
+                    onClick = { selected = !selected },
+                    leadingContent = { },
+                    modifier = Modifier.testTag(NavigationDrawerItemTag),
+                ) {
+                    Text(text = "Test Text")
+                }
+            }
+        }
+
+        rule.onNodeWithTag(NavigationDrawerItemTag)
+            .assertHasClickAction()
+            .assert(SemanticsMatcher.keyIsDefined(SemanticsProperties.Selected))
+            .assert(SemanticsMatcher.expectValue(SemanticsProperties.Selected, false))
+            .requestFocus()
+            .assertIsEnabled()
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+            .assert(SemanticsMatcher.expectValue(SemanticsProperties.Selected, true))
+        Truth.assertThat(selected).isEqualTo(true)
+    }
+
+    @Test
+    fun navigationDrawerItem_longClickSemantics() {
+        var selected by mutableStateOf(false)
+        rule.setContent {
+            DrawerScope {
+                NavigationDrawerItem(
+                    selected = selected,
+                    onClick = {},
+                    onLongClick = { selected = !selected },
+                    leadingContent = { },
+                    modifier = Modifier.testTag(NavigationDrawerItemTag),
+                ) {
+                    Text(text = "Test Text")
+                }
+            }
+        }
+
+        rule.onNodeWithTag(NavigationDrawerItemTag)
+            .assertHasClickAction()
+            .assert(SemanticsMatcher.keyIsDefined(SemanticsActions.OnLongClick))
+            .assert(SemanticsMatcher.keyIsDefined(SemanticsProperties.Selected))
+            .assert(SemanticsMatcher.expectValue(SemanticsProperties.Selected, false))
+            .requestFocus()
+            .assertIsEnabled()
+            .performLongKeyPress(rule, Key.DirectionCenter)
+            .assert(SemanticsMatcher.expectValue(SemanticsProperties.Selected, true))
+        Truth.assertThat(selected).isEqualTo(true)
+    }
+
+    @Test
+    fun navigationDrawerItem_disabledSemantics() {
+        rule.setContent {
+            DrawerScope {
+                NavigationDrawerItem(
+                    selected = false,
+                    onClick = {},
+                    enabled = false,
+                    leadingContent = { },
+                    modifier = Modifier.testTag(NavigationDrawerItemTag),
+                ) {
+                    Text(text = "Test Text")
+                }
+            }
+        }
+
+        rule.onNodeWithTag(NavigationDrawerItemTag)
+            .assertIsNotEnabled()
+    }
+
+    @Test
+    fun navigationDrawerItem_canBeDisabled() {
+        rule.setContent {
+            var enabled by remember { mutableStateOf(true) }
+            DrawerScope {
+                NavigationDrawerItem(
+                    selected = false,
+                    onClick = { enabled = false },
+                    leadingContent = { },
+                    enabled = enabled,
+                    modifier = Modifier.testTag(NavigationDrawerItemTag),
+                ) {
+                    Text(text = "Test Text")
+                }
+            }
+        }
+        rule.onNodeWithTag(NavigationDrawerItemTag)
+            // Confirm the button starts off enabled, with a click action
+            .assertHasClickAction()
+            .assertIsEnabled()
+            .requestFocus()
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+            // Then confirm it's disabled with click action after clicking it
+            .assertHasClickAction()
+            .assertIsNotEnabled()
+    }
+
+    @Test
+    fun navigationDrawerItem_oneLineHeight() {
+        val expectedHeightNoIcon = 56.dp
+
+        rule.setContent {
+            DrawerScope {
+                NavigationDrawerItem(
+                    selected = false,
+                    onClick = {},
+                    leadingContent = { },
+                    modifier = Modifier.testTag(NavigationDrawerItemTag),
+                ) {
+                    Text(text = "Test Text")
+                }
+            }
+        }
+
+        rule.onNodeWithTag(NavigationDrawerItemTag).assertHeightIsEqualTo(expectedHeightNoIcon)
+    }
+
+    @Test
+    fun navigationDrawerItem_width() {
+        rule.setContent {
+            DrawerScope {
+                NavigationDrawerItem(
+                    selected = false,
+                    onClick = { },
+                    leadingContent = { },
+                    modifier = Modifier.testTag(NavigationDrawerItemTag),
+                ) {
+                    Text(text = "Test Text")
+                }
+            }
+        }
+        rule.onNodeWithTag(NavigationDrawerItemTag)
+            .assertWidthIsEqualTo(rule.onRoot().getUnclippedBoundsInRoot().width)
+    }
+
+    @Test
+    fun navigationDrawerItem_widthInInactiveState() {
+        rule.setContent {
+            DrawerScope(false) {
+                NavigationDrawerItem(
+                    selected = false,
+                    onClick = { },
+                    leadingContent = { },
+                    modifier = Modifier.testTag(NavigationDrawerItemTag),
+                ) {
+                    Text(text = "Test Text")
+                }
+            }
+        }
+        rule.onNodeWithTag(NavigationDrawerItemTag)
+            .assertWidthIsEqualTo(56.dp)
+    }
+}
+
+@OptIn(ExperimentalTvMaterial3Api::class)
+@Composable
+private fun DrawerScope(
+    isActivated: Boolean = true,
+    content: @Composable NavigationDrawerScope.() -> Unit
+) {
+    Box {
+        NavigationDrawerScopeImpl(isActivated).apply {
+            content()
+        }
+    }
+}
+
+private const val NavigationDrawerItemTag = "NavigationDrawerItem"
+private const val NavigationDrawerItemTextTag = "NavigationDrawerItemText"
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/NavigationDrawer.kt b/tv/tv-material/src/main/java/androidx/tv/material3/NavigationDrawer.kt
index 049ddf1..320fe9e 100644
--- a/tv/tv-material/src/main/java/androidx/tv/material3/NavigationDrawer.kt
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/NavigationDrawer.kt
@@ -79,7 +79,7 @@
 @ExperimentalTvMaterial3Api
 @Composable
 fun ModalNavigationDrawer(
-    drawerContent: @Composable (DrawerValue) -> Unit,
+    drawerContent: @Composable NavigationDrawerScope.(DrawerValue) -> Unit,
     modifier: Modifier = Modifier,
     drawerState: DrawerState = rememberDrawerState(DrawerValue.Closed),
     scrimBrush: Brush = SolidColor(LocalColorScheme.current.scrim.copy(alpha = 0.5f)),
@@ -155,7 +155,7 @@
 @ExperimentalTvMaterial3Api
 @Composable
 fun NavigationDrawer(
-    drawerContent: @Composable (DrawerValue) -> Unit,
+    drawerContent: @Composable NavigationDrawerScope.(DrawerValue) -> Unit,
     modifier: Modifier = Modifier,
     drawerState: DrawerState = rememberDrawerState(DrawerValue.Closed),
     content: @Composable () -> Unit
@@ -237,7 +237,7 @@
     modifier: Modifier = Modifier,
     drawerState: DrawerState = remember { DrawerState() },
     sizeAnimationFinishedListener: ((initialValue: IntSize, targetValue: IntSize) -> Unit)? = null,
-    content: @Composable (DrawerValue) -> Unit
+    content: @Composable NavigationDrawerScope.(DrawerValue) -> Unit
 ) {
     // indicates that the drawer has been set to its initial state and has grabbed focus if
     // necessary. Controls whether focus is used to decide the state of the drawer going forward.
@@ -269,7 +269,11 @@
             }
             .focusGroup()
 
-    Box(modifier = internalModifier) { content.invoke(drawerState.currentValue) }
+    Box(modifier = internalModifier) {
+        NavigationDrawerScopeImpl(drawerState.currentValue == DrawerValue.Open).apply {
+            content(drawerState.currentValue)
+        }
+    }
 }
 
 private const val ClosedDrawerWidth = 80
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/NavigationDrawerItem.kt b/tv/tv-material/src/main/java/androidx/tv/material3/NavigationDrawerItem.kt
new file mode 100644
index 0000000..967d1c2f
--- /dev/null
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/NavigationDrawerItem.kt
@@ -0,0 +1,241 @@
+/*
+ * Copyright 2023 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.tv.material3
+
+import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.animation.core.animateDpAsState
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.size
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.layout.layout
+import androidx.compose.ui.unit.Dp
+
+/**
+ * TV Material Design navigation drawer item.
+ *
+ * A [NavigationDrawerItem] represents a destination within drawers, either [NavigationDrawer] or
+ * [ModalNavigationDrawer]
+ *
+ * @sample androidx.tv.samples.SampleNavigationDrawer
+ * @sample androidx.tv.samples.SampleModalNavigationDrawerWithSolidScrim
+ * @sample androidx.tv.samples.SampleModalNavigationDrawerWithGradientScrim
+ *
+ * @param selected defines whether this composable is selected or not
+ * @param onClick called when this composable is clicked
+ * @param leadingContent the leading content of the list item
+ * @param modifier to be applied to the list item
+ * @param enabled controls the enabled state of this composable. When `false`, this component will
+ * not respond to user input, and it will appear visually disabled and disabled to accessibility
+ * services
+ * @param onLongClick called when this composable is long clicked (long-pressed)
+ * @param supportingContent the content displayed below the headline content
+ * @param trailingContent the trailing meta badge or icon
+ * @param tonalElevation the tonal elevation of this composable
+ * @param shape defines the shape of Composable's container in different interaction states
+ * @param colors defines the background and content colors used in the composable
+ * for different interaction states
+ * @param scale defines the size of the composable relative to its original size in
+ * different interaction states
+ * @param border defines a border around the composable in different interaction states
+ * @param glow defines a shadow to be shown behind the composable for different interaction states
+ * @param interactionSource the [MutableInteractionSource] representing the stream of
+ * [Interaction]s for this component. You can create and pass in your own [remember]ed instance
+ * to observe [Interaction]s and customize the appearance / behavior of this composable in different
+ * states
+ * @param content main content of this composable
+ */
+@ExperimentalTvMaterial3Api // TODO (b/263353219): Remove this before launching beta
+@Composable
+fun NavigationDrawerScope.NavigationDrawerItem(
+    selected: Boolean,
+    onClick: () -> Unit,
+    leadingContent: @Composable () -> Unit,
+    modifier: Modifier = Modifier,
+    enabled: Boolean = true,
+    onLongClick: (() -> Unit)? = null,
+    supportingContent: (@Composable () -> Unit)? = null,
+    trailingContent: (@Composable () -> Unit)? = null,
+    tonalElevation: Dp = NavigationDrawerItemDefaults.NavigationDrawerItemElevation,
+    shape: NavigationDrawerItemShape = NavigationDrawerItemDefaults.shape(),
+    colors: NavigationDrawerItemColors = NavigationDrawerItemDefaults.colors(),
+    scale: NavigationDrawerItemScale = NavigationDrawerItemScale.None,
+    border: NavigationDrawerItemBorder = NavigationDrawerItemDefaults.border(),
+    glow: NavigationDrawerItemGlow = NavigationDrawerItemDefaults.glow(),
+    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
+    content: @Composable () -> Unit,
+) {
+    val animatedWidth by animateDpAsState(
+        targetValue = if (doesNavigationDrawerHaveFocus) {
+            NavigationDrawerItemDefaults.ExpandedDrawerItemWidth
+        } else {
+            NavigationDrawerItemDefaults.CollapsedDrawerItemWidth
+        },
+        label = "NavigationDrawerItem width open/closed state of the drawer item"
+    )
+    val navDrawerItemHeight = if (supportingContent == null) {
+        NavigationDrawerItemDefaults.ContainerHeightOneLine
+    } else {
+        NavigationDrawerItemDefaults.ContainerHeightTwoLine
+    }
+    ListItem(
+        selected = selected,
+        onClick = onClick,
+        headlineContent = {
+            AnimatedVisibility(
+                visible = doesNavigationDrawerHaveFocus,
+                enter = NavigationDrawerItemDefaults.ContentAnimationEnter,
+                exit = NavigationDrawerItemDefaults.ContentAnimationExit,
+            ) {
+                content()
+            }
+        },
+        leadingContent = {
+            Box(Modifier.size(NavigationDrawerItemDefaults.IconSize)) {
+                leadingContent()
+            }
+        },
+        trailingContent = if (trailingContent == null) null else {
+            {
+                AnimatedVisibility(
+                    visible = doesNavigationDrawerHaveFocus,
+                    enter = NavigationDrawerItemDefaults.ContentAnimationEnter,
+                    exit = NavigationDrawerItemDefaults.ContentAnimationExit,
+                ) {
+                    trailingContent()
+                }
+            }
+        },
+        supportingContent = if (supportingContent == null) null else {
+            {
+                AnimatedVisibility(
+                    visible = doesNavigationDrawerHaveFocus,
+                    enter = NavigationDrawerItemDefaults.ContentAnimationEnter,
+                    exit = NavigationDrawerItemDefaults.ContentAnimationExit,
+                ) {
+                    supportingContent()
+                }
+            }
+        },
+        modifier = modifier
+            .layout { measurable, constraints ->
+                val width = animatedWidth.roundToPx()
+                val height = navDrawerItemHeight.roundToPx()
+                val placeable = measurable.measure(
+                    constraints.copy(
+                        minWidth = width,
+                        maxWidth = width,
+                        minHeight = height,
+                        maxHeight = height,
+                    )
+                )
+                layout(placeable.width, placeable.height) {
+                    placeable.place(0, 0)
+                }
+            },
+        enabled = enabled,
+        onLongClick = onLongClick,
+        tonalElevation = tonalElevation,
+        shape = shape.toToggleableListItemShape(),
+        colors = colors.toToggleableListItemColors(doesNavigationDrawerHaveFocus),
+        scale = scale.toToggleableListItemScale(),
+        border = border.toToggleableListItemBorder(),
+        glow = glow.toToggleableListItemGlow(),
+        interactionSource = interactionSource,
+    )
+}
+
+@OptIn(ExperimentalTvMaterial3Api::class)
+@Composable
+private fun NavigationDrawerItemShape.toToggleableListItemShape() =
+    ListItemDefaults.shape(
+        shape = shape,
+        focusedShape = focusedShape,
+        pressedShape = pressedShape,
+        selectedShape = selectedShape,
+        disabledShape = disabledShape,
+        focusedSelectedShape = focusedSelectedShape,
+        focusedDisabledShape = focusedDisabledShape,
+        pressedSelectedShape = pressedSelectedShape,
+    )
+
+@OptIn(ExperimentalTvMaterial3Api::class)
+@Composable
+private fun NavigationDrawerItemColors.toToggleableListItemColors(
+    doesNavigationDrawerHaveFocus: Boolean
+) =
+    ListItemDefaults.colors(
+        containerColor = containerColor,
+        contentColor = if (doesNavigationDrawerHaveFocus) contentColor else inactiveContentColor,
+        focusedContainerColor = focusedContainerColor,
+        focusedContentColor = focusedContentColor,
+        pressedContainerColor = pressedContainerColor,
+        pressedContentColor = pressedContentColor,
+        selectedContainerColor = selectedContainerColor,
+        selectedContentColor = selectedContentColor,
+        disabledContainerColor = disabledContainerColor,
+        disabledContentColor =
+        if (doesNavigationDrawerHaveFocus) disabledContentColor else disabledInactiveContentColor,
+        focusedSelectedContainerColor = focusedSelectedContainerColor,
+        focusedSelectedContentColor = focusedSelectedContentColor,
+        pressedSelectedContainerColor = pressedSelectedContainerColor,
+        pressedSelectedContentColor = pressedSelectedContentColor,
+    )
+
+@OptIn(ExperimentalTvMaterial3Api::class)
+@Composable
+private fun NavigationDrawerItemScale.toToggleableListItemScale() =
+    ListItemDefaults.scale(
+        scale = scale,
+        focusedScale = focusedScale,
+        pressedScale = pressedScale,
+        selectedScale = selectedScale,
+        disabledScale = disabledScale,
+        focusedSelectedScale = focusedSelectedScale,
+        focusedDisabledScale = focusedDisabledScale,
+        pressedSelectedScale = pressedSelectedScale,
+    )
+
+@OptIn(ExperimentalTvMaterial3Api::class)
+@Composable
+private fun NavigationDrawerItemBorder.toToggleableListItemBorder() =
+    ListItemDefaults.border(
+        border = border,
+        focusedBorder = focusedBorder,
+        pressedBorder = pressedBorder,
+        selectedBorder = selectedBorder,
+        disabledBorder = disabledBorder,
+        focusedSelectedBorder = focusedSelectedBorder,
+        focusedDisabledBorder = focusedDisabledBorder,
+        pressedSelectedBorder = pressedSelectedBorder,
+    )
+
+@OptIn(ExperimentalTvMaterial3Api::class)
+@Composable
+private fun NavigationDrawerItemGlow.toToggleableListItemGlow() =
+    ListItemDefaults.glow(
+        glow = glow,
+        focusedGlow = focusedGlow,
+        pressedGlow = pressedGlow,
+        selectedGlow = selectedGlow,
+        focusedSelectedGlow = focusedSelectedGlow,
+        pressedSelectedGlow = pressedSelectedGlow,
+    )
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/NavigationDrawerScope.kt b/tv/tv-material/src/main/java/androidx/tv/material3/NavigationDrawerScope.kt
index ccdcec7..27dccf0 100644
--- a/tv/tv-material/src/main/java/androidx/tv/material3/NavigationDrawerScope.kt
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/NavigationDrawerScope.kt
@@ -25,10 +25,10 @@
     /**
      * Whether any item within the [NavigationDrawer] or [ModalNavigationDrawer] is focused
      */
-    val isActivated: Boolean
+    val doesNavigationDrawerHaveFocus: Boolean
 }
 
 @OptIn(ExperimentalTvMaterial3Api::class)
-internal class NavigationDrawerScopeImpl constructor(
-    override val isActivated: Boolean
+internal class NavigationDrawerScopeImpl(
+    override val doesNavigationDrawerHaveFocus: Boolean
 ) : NavigationDrawerScope
diff --git a/wear/compose/compose-foundation/src/main/baseline-prof.txt b/wear/compose/compose-foundation/src/main/baseline-prof.txt
index 00329b5..edfde2d 100644
--- a/wear/compose/compose-foundation/src/main/baseline-prof.txt
+++ b/wear/compose/compose-foundation/src/main/baseline-prof.txt
@@ -30,21 +30,28 @@
 SPLandroidx/wear/compose/foundation/ExpandableItemsDefaults;->**(**)**
 HSPLandroidx/wear/compose/foundation/ExpandableKt**->**(**)**
 HSPLandroidx/wear/compose/foundation/ExpandableState;->**(**)**
-PLandroidx/wear/compose/foundation/FocusNode;->**(**)**
-HPLandroidx/wear/compose/foundation/HierarchicalFocusCoordinatorKt**->**(**)**
-PLandroidx/wear/compose/foundation/InternalMutatorMutex;->**(**)**
+SPLandroidx/wear/compose/foundation/FocusNode;->**(**)**
+HSPLandroidx/wear/compose/foundation/HierarchicalFocusCoordinatorKt**->**(**)**
+SPLandroidx/wear/compose/foundation/InternalMutatorMutex;->**(**)**
+HSPLandroidx/wear/compose/foundation/Modifiers;->**(**)**
 HSPLandroidx/wear/compose/foundation/PaddingWrapper;->**(**)**
 HSPLandroidx/wear/compose/foundation/PartialLayoutInfo;->**(**)**
 Landroidx/wear/compose/foundation/ReduceMotion;
+HSPLandroidx/wear/compose/foundation/ResourcesKt**->**(**)**
+PLandroidx/wear/compose/foundation/RevealActionType;->**(**)**
 HPLandroidx/wear/compose/foundation/RevealScopeImpl;->**(**)**
 HPLandroidx/wear/compose/foundation/RevealState;->**(**)**
 HPLandroidx/wear/compose/foundation/RevealValue;->**(**)**
-HPLandroidx/wear/compose/foundation/SwipeAnchorsModifier;->**(**)**
+HSPLandroidx/wear/compose/foundation/SwipeAnchorsModifier;->**(**)**
+HSPLandroidx/wear/compose/foundation/SwipeToDismissBoxKt**->**(**)**
+HSPLandroidx/wear/compose/foundation/SwipeToDismissBoxState;->**(**)**
+SPLandroidx/wear/compose/foundation/SwipeToDismissKeys;->**(**)**
+SPLandroidx/wear/compose/foundation/SwipeToDismissValue;->**(**)**
 PLandroidx/wear/compose/foundation/SwipeToRevealDefaults;->**(**)**
 HPLandroidx/wear/compose/foundation/SwipeToRevealKt**->**(**)**
-PLandroidx/wear/compose/foundation/SwipeableV2Defaults;->**(**)**
-HPLandroidx/wear/compose/foundation/SwipeableV2Kt**->**(**)**
-HPLandroidx/wear/compose/foundation/SwipeableV2State;->**(**)**
+SPLandroidx/wear/compose/foundation/SwipeableV2Defaults;->**(**)**
+HSPLandroidx/wear/compose/foundation/SwipeableV2Kt**->**(**)**
+HSPLandroidx/wear/compose/foundation/SwipeableV2State;->**(**)**
 SPLandroidx/wear/compose/foundation/lazy/AutoCenteringParams;->**(**)**
 HSPLandroidx/wear/compose/foundation/lazy/CombinedPaddingValues;->**(**)**
 HSPLandroidx/wear/compose/foundation/lazy/DefaultScalingLazyListItemInfo;->**(**)**
diff --git a/wear/compose/compose-material/src/androidTest/kotlin/androidx/wear/compose/material/MaterialTest.kt b/wear/compose/compose-material/src/androidTest/kotlin/androidx/wear/compose/material/MaterialTest.kt
index 3cd42b0..8e2e2bc 100644
--- a/wear/compose/compose-material/src/androidTest/kotlin/androidx/wear/compose/material/MaterialTest.kt
+++ b/wear/compose/compose-material/src/androidTest/kotlin/androidx/wear/compose/material/MaterialTest.kt
@@ -16,7 +16,9 @@
 package androidx.wear.compose.material
 
 import android.graphics.Bitmap
+import android.os.Build
 import android.util.Log
+import androidx.annotation.RequiresApi
 import androidx.compose.foundation.Image
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.BoxScope
@@ -25,6 +27,8 @@
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.outlined.Add
 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.geometry.Rect
@@ -33,10 +37,12 @@
 import androidx.compose.ui.graphics.asAndroidBitmap
 import androidx.compose.ui.graphics.toPixelMap
 import androidx.compose.ui.layout.ContentScale
+import androidx.compose.ui.platform.LocalLayoutDirection
 import androidx.compose.ui.platform.testTag
 import androidx.compose.ui.semantics.SemanticsActions
 import androidx.compose.ui.semantics.SemanticsNode
 import androidx.compose.ui.test.SemanticsNodeInteraction
+import androidx.compose.ui.test.captureToImage
 import androidx.compose.ui.test.junit4.ComposeContentTestRule
 import androidx.compose.ui.test.onNodeWithTag
 import androidx.compose.ui.test.onNodeWithText
@@ -45,11 +51,13 @@
 import androidx.compose.ui.text.TextStyle
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.DpRect
+import androidx.compose.ui.unit.LayoutDirection
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.height
 import androidx.compose.ui.unit.isUnspecified
 import androidx.compose.ui.unit.toSize
 import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.screenshot.AndroidXScreenshotTestRule
 import java.io.File
 import java.io.FileOutputStream
 import java.io.IOException
@@ -209,6 +217,25 @@
     return this
 }
 
+@RequiresApi(Build.VERSION_CODES.O)
+internal fun ComposeContentTestRule.verifyScreenshot(
+    screenshotRule: AndroidXScreenshotTestRule,
+    methodName: String,
+    testTag: String = TEST_TAG,
+    layoutDirection: LayoutDirection = LayoutDirection.Ltr,
+    content: @Composable () -> Unit
+) {
+    setContentWithTheme {
+        CompositionLocalProvider(LocalLayoutDirection provides layoutDirection) {
+            content()
+        }
+    }
+
+    onNodeWithTag(testTag)
+        .captureToImage()
+        .assertAgainstGolden(screenshotRule, methodName)
+}
+
 /**
  * Asserts that the layout of this node has height equal to [expectedHeight].
  *
diff --git a/wear/compose/compose-material/src/androidTest/kotlin/androidx/wear/compose/material/SwipeToRevealScreenshotTest.kt b/wear/compose/compose-material/src/androidTest/kotlin/androidx/wear/compose/material/SwipeToRevealScreenshotTest.kt
new file mode 100644
index 0000000..9622c31
--- /dev/null
+++ b/wear/compose/compose-material/src/androidTest/kotlin/androidx/wear/compose/material/SwipeToRevealScreenshotTest.kt
@@ -0,0 +1,234 @@
+/*
+ * Copyright 2023 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.annotation.RequiresApi
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import androidx.test.screenshot.AndroidXScreenshotTestRule
+import androidx.wear.compose.foundation.ExperimentalWearFoundationApi
+import androidx.wear.compose.foundation.RevealActionType
+import androidx.wear.compose.foundation.RevealState
+import androidx.wear.compose.foundation.RevealValue
+import androidx.wear.compose.foundation.rememberRevealState
+import kotlinx.coroutines.launch
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TestName
+import org.junit.runner.RunWith
+
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+@RequiresApi(Build.VERSION_CODES.O)
+@OptIn(ExperimentalWearMaterialApi::class, ExperimentalWearFoundationApi::class)
+class SwipeToRevealScreenshotTest {
+    @get:Rule
+    val rule = createComposeRule()
+
+    @get:Rule
+    val screenshotRule = AndroidXScreenshotTestRule(SCREENSHOT_GOLDEN_PATH)
+
+    @get:Rule
+    val testName = TestName()
+
+    @Test
+    fun swipeToRevealCard_singleAction() {
+        rule.verifyScreenshot(
+            screenshotRule = screenshotRule,
+            methodName = testName.methodName
+        ) {
+            swipeToRevealCard(
+                revealState = rememberRevealState(initialValue = RevealValue.Revealing),
+                secondaryAction = null
+            )
+        }
+    }
+
+    @Test
+    fun swipeToRevealChip_singleAction() {
+        rule.verifyScreenshot(
+            screenshotRule = screenshotRule,
+            methodName = testName.methodName
+        ) {
+            swipeToRevealChip(
+                revealState = rememberRevealState(initialValue = RevealValue.Revealing),
+                secondaryAction = null
+            )
+        }
+    }
+
+    @Test
+    fun swipeToRevealCard_twoActions() {
+        rule.verifyScreenshot(
+            screenshotRule = screenshotRule,
+            methodName = testName.methodName
+        ) {
+            swipeToRevealCard(
+                revealState = rememberRevealState(initialValue = RevealValue.Revealing)
+            )
+        }
+    }
+
+    @Test
+    fun swipeToRevealChip_twoActions() {
+        rule.verifyScreenshot(
+            screenshotRule = screenshotRule,
+            methodName = testName.methodName
+        ) {
+            swipeToRevealChip(
+                revealState = rememberRevealState(initialValue = RevealValue.Revealing)
+            )
+        }
+    }
+
+    @Test
+    fun swipeToRevealChip_undoPrimaryAction() {
+        rule.verifyScreenshot(
+            screenshotRule = screenshotRule,
+            methodName = testName.methodName
+        ) {
+            swipeToRevealChip(
+                revealState = rememberRevealState(initialValue = RevealValue.Revealed)
+            )
+        }
+    }
+
+    @Test
+    fun swipeToRevealCard_undoPrimaryAction() {
+        rule.verifyScreenshot(
+            screenshotRule = screenshotRule,
+            methodName = testName.methodName
+        ) {
+            swipeToRevealCard(
+                revealState = rememberRevealState(initialValue = RevealValue.Revealed)
+            )
+        }
+    }
+
+    @Test
+    fun swipeToRevealChip_undoSecondaryAction() {
+        rule.verifyScreenshot(
+            screenshotRule = screenshotRule,
+            methodName = testName.methodName
+        ) {
+            val revealState = rememberRevealState()
+            val coroutineScope = rememberCoroutineScope()
+            coroutineScope.launch { revealState.animateTo(RevealValue.Revealed) }
+            revealState.lastActionType = RevealActionType.SecondaryAction
+            swipeToRevealChip(
+                revealState = revealState
+            )
+        }
+    }
+
+    @Test
+    fun swipeToRevealCard_undoSecondaryAction() {
+        rule.verifyScreenshot(
+            screenshotRule = screenshotRule,
+            methodName = testName.methodName
+        ) {
+            val revealState = rememberRevealState()
+            val coroutineScope = rememberCoroutineScope()
+            coroutineScope.launch { revealState.animateTo(RevealValue.Revealed) }
+            revealState.lastActionType = RevealActionType.SecondaryAction
+            swipeToRevealCard(
+                revealState = revealState
+            )
+        }
+    }
+
+    @Composable
+    private fun swipeToRevealCard(
+        revealState: RevealState = rememberRevealState(),
+        secondaryAction: SwipeToRevealAction? = SwipeToRevealDefaults.secondaryAction(
+            icon = { Icon(SwipeToRevealDefaults.MoreOptions, "More Options") }
+        ),
+        undoPrimaryAction: SwipeToRevealAction? = SwipeToRevealDefaults.undoAction(
+            label = { Text("Undo") }
+        ),
+        undoSecondaryAction: SwipeToRevealAction? = SwipeToRevealDefaults.undoAction(
+            label = { Text("Undo") }
+        )
+    ) {
+        Box(modifier = Modifier.fillMaxSize().background(MaterialTheme.colors.background)) {
+            SwipeToRevealCard(
+                modifier = Modifier.testTag(TEST_TAG),
+                primaryAction = SwipeToRevealDefaults.primaryAction(
+                    icon = { Icon(SwipeToRevealDefaults.Delete, "Delete") },
+                    label = { Text("Delete") }
+                ),
+                secondaryAction = secondaryAction,
+                undoPrimaryAction = undoPrimaryAction,
+                undoSecondaryAction = undoSecondaryAction,
+                revealState = revealState
+            ) {
+                TitleCard(
+                    onClick = { /*TODO*/ },
+                    title = { Text("Title of card") },
+                    time = { Text("now") },
+                ) {
+                    Text("Swipe To Reveal - Card")
+                }
+            }
+        }
+    }
+
+    @Composable
+    private fun swipeToRevealChip(
+        revealState: RevealState = rememberRevealState(),
+        secondaryAction: SwipeToRevealAction? = SwipeToRevealDefaults.secondaryAction(
+            icon = { Icon(SwipeToRevealDefaults.MoreOptions, "More Options") }
+        ),
+        undoPrimaryAction: SwipeToRevealAction? = SwipeToRevealDefaults.undoAction(
+            label = { Text("Undo") }
+        ),
+        undoSecondaryAction: SwipeToRevealAction? = SwipeToRevealDefaults.undoAction(
+            label = { Text("Undo") }
+        )
+    ) {
+        Box(modifier = Modifier.fillMaxSize().background(MaterialTheme.colors.background)) {
+            SwipeToRevealChip(
+                modifier = Modifier.testTag(TEST_TAG),
+                primaryAction = SwipeToRevealDefaults.primaryAction(
+                    icon = { Icon(SwipeToRevealDefaults.Delete, "Delete") },
+                    label = { Text("Delete") }
+                ),
+                secondaryAction = secondaryAction,
+                undoPrimaryAction = undoPrimaryAction,
+                undoSecondaryAction = undoSecondaryAction,
+                revealState = revealState
+            ) {
+                Chip(
+                    onClick = { /* onClick handler for chip */ },
+                    colors = ChipDefaults.primaryChipColors(),
+                    border = ChipDefaults.outlinedChipBorder()
+                ) {
+                    Text("Swipe To Reveal - Chip")
+                }
+            }
+        }
+    }
+}
diff --git a/wear/compose/compose-material/src/main/baseline-prof.txt b/wear/compose/compose-material/src/main/baseline-prof.txt
index de41148..8c7b94c 100644
--- a/wear/compose/compose-material/src/main/baseline-prof.txt
+++ b/wear/compose/compose-material/src/main/baseline-prof.txt
@@ -67,7 +67,7 @@
 HPLandroidx/wear/compose/material/PlaceholderKt**->**(**)**
 PLandroidx/wear/compose/material/PlaceholderModifier;->**(**)**
 HPLandroidx/wear/compose/material/PlaceholderShimmerModifier;->**(**)**
-PLandroidx/wear/compose/material/PlaceholderStage;->**(**)**
+HPLandroidx/wear/compose/material/PlaceholderStage;->**(**)**
 HPLandroidx/wear/compose/material/PlaceholderState;->**(**)**
 HSPLandroidx/wear/compose/material/PositionIndicatorAlignment;->**(**)**
 HSPLandroidx/wear/compose/material/PositionIndicatorKt**->**(**)**
@@ -146,7 +146,12 @@
 HSPLandroidx/wear/compose/materialcore/IconKt**->**(**)**
 HPLandroidx/wear/compose/materialcore/RangeDefaults;->**(**)**
 PLandroidx/wear/compose/materialcore/RangeIcons;->**(**)**
+HPLandroidx/wear/compose/materialcore/RepeatableClickableKt**->**(**)**
+HSPLandroidx/wear/compose/materialcore/ResourcesKt**->**(**)**
+HPLandroidx/wear/compose/materialcore/SelectionControlsKt**->**(**)**
+PLandroidx/wear/compose/materialcore/SelectionStage;->**(**)**
 HPLandroidx/wear/compose/materialcore/SliderKt**->**(**)**
 PLandroidx/wear/compose/materialcore/StepperDefaults;->**(**)**
 HPLandroidx/wear/compose/materialcore/StepperKt**->**(**)**
 HSPLandroidx/wear/compose/materialcore/TextKt**->**(**)**
+HSPLandroidx/wear/compose/materialcore/ToggleButtonKt**->**(**)**
diff --git a/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/IconToggleButtonTest.kt b/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/IconToggleButtonTest.kt
index 0c068d7..e8d1930 100644
--- a/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/IconToggleButtonTest.kt
+++ b/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/IconToggleButtonTest.kt
@@ -425,8 +425,8 @@
             status = Status.Disabled,
             checked = false,
             colors = { IconButtonDefaults.iconToggleButtonColors() },
-            containerColor = { MaterialTheme.colorScheme.surface },
-            contentColor = { MaterialTheme.colorScheme.onSurfaceVariant }
+            containerColor = { MaterialTheme.colorScheme.surface.toDisabledColor() },
+            contentColor = { MaterialTheme.colorScheme.onSurfaceVariant.toDisabledColor() }
         )
 
     @RequiresApi(Build.VERSION_CODES.O)
@@ -436,8 +436,8 @@
             status = Status.Disabled,
             checked = true,
             colors = { IconButtonDefaults.iconToggleButtonColors() },
-            containerColor = { MaterialTheme.colorScheme.primary },
-            contentColor = { MaterialTheme.colorScheme.onPrimary },
+            containerColor = { MaterialTheme.colorScheme.primary.toDisabledColor() },
+            contentColor = { MaterialTheme.colorScheme.onPrimary.toDisabledColor() },
         )
 
     @RequiresApi(Build.VERSION_CODES.O)
@@ -523,11 +523,11 @@
             colors = {
                 IconButtonDefaults.iconToggleButtonColors(
                     // Apply the content color override for the content alpha to be applied
-                    checkedContainerColor = overrideColor
+                    disabledCheckedContainerColor = overrideColor
                 )
             },
             containerColor = { overrideColor },
-            contentColor = { MaterialTheme.colorScheme.onPrimary }
+            contentColor = { MaterialTheme.colorScheme.onPrimary.toDisabledColor() }
         )
     }
 
@@ -542,10 +542,10 @@
             colors = {
                 IconButtonDefaults.iconToggleButtonColors(
                     // Apply the content color override for the content alpha to be applied
-                    checkedContentColor = overrideColor
+                    disabledCheckedContentColor = overrideColor
                 )
             },
-            containerColor = { MaterialTheme.colorScheme.primary },
+            containerColor = { MaterialTheme.colorScheme.primary.toDisabledColor() },
             contentColor = { overrideColor }
         )
     }
@@ -561,11 +561,11 @@
             colors = {
                 IconButtonDefaults.iconToggleButtonColors(
                     // Apply the content color override for the content alpha to be applied
-                    uncheckedContainerColor = overrideColor
+                    disabledUncheckedContainerColor = overrideColor
                 )
             },
             containerColor = { overrideColor },
-            contentColor = { MaterialTheme.colorScheme.onSurfaceVariant }
+            contentColor = { MaterialTheme.colorScheme.onSurfaceVariant.toDisabledColor() }
         )
     }
 
@@ -580,11 +580,11 @@
             colors = {
                 IconButtonDefaults.iconToggleButtonColors(
                     // Apply the content color override for the content alpha to be applied
-                    uncheckedContentColor = overrideColor
+                    disabledUncheckedContentColor = overrideColor
                 )
             },
             contentColor = { overrideColor },
-            containerColor = { MaterialTheme.colorScheme.surface }
+            containerColor = { MaterialTheme.colorScheme.surface.toDisabledColor() }
         )
     }
 
@@ -618,7 +618,9 @@
                 onCheckedChange = {},
                 enabled = false,
                 content = { TestImage() },
-                modifier = Modifier.testTag(TEST_TAG).semantics { role = overrideRole }
+                modifier = Modifier
+                    .testTag(TEST_TAG)
+                    .semantics { role = overrideRole }
             )
         }
 
@@ -639,7 +641,6 @@
         contentColor: @Composable () -> Color,
     ) {
         verifyColors(
-            status = status,
             expectedContainerColor = containerColor,
             expectedContentColor = contentColor,
             content = {
@@ -705,10 +706,8 @@
 
     @RequiresApi(Build.VERSION_CODES.O)
     private fun ComposeContentTestRule.verifyColors(
-        status: Status,
         expectedContainerColor: @Composable () -> Color,
         expectedContentColor: @Composable () -> Color,
-        applyAlphaForDisabled: Boolean = true,
         content: @Composable () -> Color
     ) {
         val testBackgroundColor = Color.White
@@ -717,17 +716,8 @@
         var actualContentColor = Color.Transparent
         setContentWithTheme {
             finalExpectedContainerColor =
-                if (status.enabled() || !applyAlphaForDisabled) {
-                    expectedContainerColor()
-                } else {
-                    expectedContainerColor().copy(ContentAlpha.disabled)
-                }.compositeOver(testBackgroundColor)
-            finalExpectedContent =
-                if (status.enabled() || !applyAlphaForDisabled) {
-                    expectedContentColor()
-                } else {
-                    expectedContentColor().copy(ContentAlpha.disabled)
-                }
+                expectedContainerColor().compositeOver(testBackgroundColor)
+            finalExpectedContent = expectedContentColor()
             Box(
                 Modifier
                     .fillMaxSize()
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/IconButton.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/IconButton.kt
index 71aee71..8755ede 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/IconButton.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/IconButton.kt
@@ -33,6 +33,7 @@
 import androidx.wear.compose.material3.tokens.FilledIconButtonTokens
 import androidx.wear.compose.material3.tokens.FilledTonalIconButtonTokens
 import androidx.wear.compose.material3.tokens.IconButtonTokens
+import androidx.wear.compose.material3.tokens.IconToggleButtonTokens
 import androidx.wear.compose.material3.tokens.OutlinedIconButtonTokens
 
 /**
@@ -317,7 +318,6 @@
         shape = shape,
         content = provideScopeContent(
             colors.contentColor(enabled = enabled, checked = checked),
-            MaterialTheme.typography.labelMedium,
             content
         )
     )
@@ -475,14 +475,19 @@
      */
     @Composable
     fun iconToggleButtonColors(
-        checkedContainerColor: Color = MaterialTheme.colorScheme.primary,
-        checkedContentColor: Color = MaterialTheme.colorScheme.onPrimary,
-        uncheckedContainerColor: Color = MaterialTheme.colorScheme.surface,
-        uncheckedContentColor: Color = MaterialTheme.colorScheme.onSurfaceVariant,
-        disabledCheckedContainerColor: Color = checkedContainerColor.toDisabledColor(),
-        disabledCheckedContentColor: Color = checkedContentColor.toDisabledColor(),
-        disabledUncheckedContainerColor: Color = uncheckedContainerColor.toDisabledColor(),
-        disabledUncheckedContentColor: Color = uncheckedContentColor.toDisabledColor(),
+        checkedContainerColor: Color = IconToggleButtonTokens.CheckedContainerColor.value,
+        checkedContentColor: Color = IconToggleButtonTokens.CheckedContentColor.value,
+        uncheckedContainerColor: Color = IconToggleButtonTokens.UncheckedContainerColor.value,
+        uncheckedContentColor: Color = IconToggleButtonTokens.UncheckedContentColor.value,
+        disabledCheckedContainerColor: Color = IconToggleButtonTokens.DisabledCheckedContainerColor
+            .value.toDisabledColor(IconToggleButtonTokens.DisabledCheckedContainerOpacity),
+        disabledCheckedContentColor: Color = IconToggleButtonTokens.DisabledCheckedContentColor
+            .value.toDisabledColor(IconToggleButtonTokens.DisabledCheckedContentOpacity),
+        disabledUncheckedContainerColor: Color = IconToggleButtonTokens
+            .DisabledUncheckedContainerColor.value
+            .toDisabledColor(IconToggleButtonTokens.DisabledUncheckedContainerOpacity),
+        disabledUncheckedContentColor: Color = IconToggleButtonTokens.DisabledUncheckedContentColor
+            .value.toDisabledColor(IconToggleButtonTokens.DisabledUncheckedContentOpacity),
     ): ToggleButtonColors {
         return ToggleButtonColors(
             checkedContainerColor = checkedContainerColor,
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/IconToggleButtonTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/IconToggleButtonTokens.kt
new file mode 100644
index 0000000..b6ae374
--- /dev/null
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/IconToggleButtonTokens.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// VERSION: v0_16
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+package androidx.wear.compose.material3.tokens
+
+internal object IconToggleButtonTokens {
+    val CheckedContainerColor = ColorSchemeKeyTokens.Primary
+    val CheckedContentColor = ColorSchemeKeyTokens.OnPrimary
+    val DisabledCheckedContainerColor = ColorSchemeKeyTokens.Primary
+    val DisabledCheckedContainerOpacity = 0.38f
+    val DisabledCheckedContentColor = ColorSchemeKeyTokens.OnPrimary
+    val DisabledCheckedContentOpacity = 0.38f
+    val DisabledUncheckedContainerColor = ColorSchemeKeyTokens.Surface
+    val DisabledUncheckedContainerOpacity = 0.38f
+    val DisabledUncheckedContentColor = ColorSchemeKeyTokens.OnSurfaceVariant
+    val DisabledUncheckedContentOpacity = 0.38f
+    val UncheckedContainerColor = ColorSchemeKeyTokens.Surface
+    val UncheckedContentColor = ColorSchemeKeyTokens.OnSurfaceVariant
+}
diff --git a/wear/compose/integration-tests/macrobenchmark-target/build.gradle b/wear/compose/integration-tests/macrobenchmark-target/build.gradle
index af518ce..5ed6e31 100644
--- a/wear/compose/integration-tests/macrobenchmark-target/build.gradle
+++ b/wear/compose/integration-tests/macrobenchmark-target/build.gradle
@@ -44,7 +44,7 @@
     implementation(project(":compose:runtime:runtime"))
     implementation(project(":compose:ui:ui-tooling"))
     implementation(project(":compose:material:material-icons-core"))
-    implementation("androidx.activity:activity-compose:1.3.1")
+    implementation(project(":activity:activity-compose"))
     implementation(project(":profileinstaller:profileinstaller"))
     implementation project(path: ':wear:compose:compose-foundation')
     implementation project(path: ':wear:compose:compose-material')
diff --git a/wear/compose/integration-tests/macrobenchmark/build.gradle b/wear/compose/integration-tests/macrobenchmark/build.gradle
index 61090b4..1b3a97c 100644
--- a/wear/compose/integration-tests/macrobenchmark/build.gradle
+++ b/wear/compose/integration-tests/macrobenchmark/build.gradle
@@ -23,7 +23,6 @@
 android {
     defaultConfig {
         minSdkVersion 29
-        testInstrumentationRunnerArguments["androidx.benchmark.fullTracing.enable"] = "true"
     }
     namespace "androidx.wear.compose.integration.macrobenchmark"
     targetProjectPath = ":wear:compose:integration-tests:macrobenchmark-target"
diff --git a/wear/compose/integration-tests/macrobenchmark/src/main/java/androidx/wear/compose/integration/macrobenchmark/SwipeBenchmark.kt b/wear/compose/integration-tests/macrobenchmark/src/main/java/androidx/wear/compose/integration/macrobenchmark/SwipeBenchmark.kt
index c9871fe..25d3741 100644
--- a/wear/compose/integration-tests/macrobenchmark/src/main/java/androidx/wear/compose/integration/macrobenchmark/SwipeBenchmark.kt
+++ b/wear/compose/integration-tests/macrobenchmark/src/main/java/androidx/wear/compose/integration/macrobenchmark/SwipeBenchmark.kt
@@ -40,8 +40,6 @@
     @get:Rule
     val benchmarkRule = MacrobenchmarkRule()
 
-    private lateinit var device: UiDevice
-
     @Before
     fun setUp() {
         val instrumentation = InstrumentationRegistry.getInstrumentation()
@@ -64,8 +62,8 @@
             val swipeToDismissBox = device.findObject(By.desc(CONTENT_DESCRIPTION))
             // Setting a gesture margin is important otherwise gesture nav is triggered.
             swipeToDismissBox.setGestureMargin(device.displayWidth / 5)
-            repeat(10) {
-                swipeToDismissBox.swipe(Direction.RIGHT, 0.75f)
+            repeat(3) {
+                swipeToDismissBox.swipe(Direction.RIGHT, 0.75f, SWIPE_SPEED)
                 device.waitForIdle()
             }
         }
@@ -80,4 +78,7 @@
         @JvmStatic
         fun parameters() = createCompilationParams()
     }
+
+    private lateinit var device: UiDevice
+    private val SWIPE_SPEED = 500
 }
diff --git a/wear/watchface/watchface/src/main/java/androidx/wear/watchface/ComplicationSlot.kt b/wear/watchface/watchface/src/main/java/androidx/wear/watchface/ComplicationSlot.kt
index c36b80e..e8f57d7 100644
--- a/wear/watchface/watchface/src/main/java/androidx/wear/watchface/ComplicationSlot.kt
+++ b/wear/watchface/watchface/src/main/java/androidx/wear/watchface/ComplicationSlot.kt
@@ -28,6 +28,7 @@
 import androidx.annotation.Px
 import androidx.annotation.RestrictTo
 import androidx.annotation.UiThread
+import androidx.annotation.VisibleForTesting
 import androidx.annotation.WorkerThread
 import androidx.wear.watchface.RenderParameters.HighlightedElement
 import androidx.wear.watchface.complications.ComplicationSlotBounds
@@ -243,8 +244,8 @@
     public const val ROUND_RECT: Int = 0
 
     /**
-     * For a full screen image complication slot drawn behind the watch face. Note you can only
-     * have a single background complication slot.
+     * For a full screen image complication slot drawn behind the watch face. Note you can only have
+     * a single background complication slot.
      */
     public const val BACKGROUND: Int = 1
 
@@ -342,21 +343,6 @@
  * expanded by [ComplicationSlotBounds.perComplicationTypeMargins]. Expanded bounds can overlap so
  * the [ComplicationSlot] with the lowest id that intersects the coordinates, if any, is selected.
  *
- * @param accessibilityTraversalIndex Used to sort Complications when generating accessibility
- *   content description labels.
- * @param bounds The complication slot's [ComplicationSlotBounds].
- * @param supportedTypes The list of [ComplicationType]s accepted by this complication slot, must be
- *   non-empty. During complication data source selection, each item in this list is compared in
- *   turn with entries from a data source's data source's supported types. The first matching entry
- *   from `supportedTypes` is chosen. If there are no matches then that data source is not eligible
- *   to be selected in this slot.
- * @param defaultPolicy The [DefaultComplicationDataSourcePolicy] which controls the initial
- *   complication data source when the watch face is first installed.
- * @param defaultDataSourceType The default [ComplicationType] for the default complication data
- *   source.
- * @param configExtras Extras to be merged into the Intent sent when invoking the complication data
- *   source chooser activity. This features is intended for OEM watch faces where they have elements
- *   that behave like a complication but are in fact entirely watch face specific.
  * @property id The Watch Face's ID for the complication slot.
  * @property boundsType The [ComplicationSlotBoundsTypeIntDef] of the complication slot.
  * @property canvasComplicationFactory The [CanvasComplicationFactory] used to generate a
@@ -373,6 +359,25 @@
  *   complication slot.
  */
 public class ComplicationSlot
+/**
+ * Constructs a [ComplicationSlot].
+ *
+ * @param accessibilityTraversalIndex Used to sort Complications when generating accessibility
+ *   content description labels.
+ * @param bounds The complication slot's [ComplicationSlotBounds].
+ * @param supportedTypes The list of [ComplicationType]s accepted by this complication slot, must be
+ *   non-empty. During complication data source selection, each item in this list is compared in
+ *   turn with entries from a data source's data source's supported types. The first matching entry
+ *   from `supportedTypes` is chosen. If there are no matches then that data source is not eligible
+ *   to be selected in this slot.
+ * @param defaultPolicy The [DefaultComplicationDataSourcePolicy] which controls the initial
+ *   complication data source when the watch face is first installed.
+ * @param defaultDataSourceType The default [ComplicationType] for the default complication data
+ *   source.
+ * @param configExtras Extras to be merged into the Intent sent when invoking the complication data
+ *   source chooser activity. This features is intended for OEM watch faces where they have elements
+ *   that behave like a complication but are in fact entirely watch face specific.
+ */
 @ComplicationExperimental
 internal constructor(
     public val id: Int,
@@ -391,8 +396,7 @@
     screenReaderNameResourceId: Int?,
     // TODO(b/230364881): This should really be public but some metalava bug is preventing
     // @ComplicationExperimental from working on the getter so it's currently hidden.
-    @get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-    public val boundingArc: BoundingArc?
+    @get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public val boundingArc: BoundingArc?
 ) {
     /**
      * The [ComplicationSlotsManager] this is attached to. Only set after the
@@ -430,7 +434,8 @@
 
     private var lastComplicationUpdate = Instant.EPOCH
 
-    private class ComplicationDataHistoryEntry(
+    @VisibleForTesting
+    internal class ComplicationDataHistoryEntry(
         val complicationData: ComplicationData,
         val time: Instant
     )
@@ -439,7 +444,8 @@
      * There doesn't seem to be a convenient ring buffer in the standard library so implement our
      * own one.
      */
-    private class RingBuffer(val size: Int) : Iterable<ComplicationDataHistoryEntry> {
+    @VisibleForTesting
+    internal class RingBuffer(val size: Int) : Iterable<ComplicationDataHistoryEntry> {
         private val entries = arrayOfNulls<ComplicationDataHistoryEntry>(size)
         private var readIndex = 0
         private var writeIndex = 0
@@ -467,9 +473,11 @@
 
     /**
      * In userdebug builds maintain a history of the last [MAX_COMPLICATION_HISTORY_ENTRIES]-1
-     * complications, which is logged in dumpsys to help debug complication issues.
+     * complications sent by the system, which is logged in dumpsys to help debug complication
+     * issues.
      */
-    private val complicationHistory =
+    @VisibleForTesting
+    internal val complicationHistory =
         if (Build.TYPE.equals("userdebug")) {
             RingBuffer(MAX_COMPLICATION_HISTORY_ENTRIES)
         } else {
@@ -666,8 +674,11 @@
             )
     }
 
+    /** Builder for constructing [ComplicationSlot]s. */
+    @OptIn(ComplicationExperimental::class)
+    public class Builder
     /**
-     * Builder for constructing [ComplicationSlot]s.
+     * Constructs a [Builder].
      *
      * @param id The watch face's ID for this complication. Can be any integer but should be unique
      *   within the watch face.
@@ -683,8 +694,6 @@
      * @param complicationTapFilter The [ComplicationTapFilter] used to perform hit testing for this
      *   complication.
      */
-    @OptIn(ComplicationExperimental::class)
-    public class Builder
     internal constructor(
         private val id: Int,
         private val canvasComplicationFactory: CanvasComplicationFactory,
@@ -1010,18 +1019,38 @@
 
     /**
      * Sets the current [ComplicationData] and if it's a timeline, the correct override for
-     * [instant] is chosen.
+     * [instant] is chosen. Any images associated with the complication are loaded asynchronously
+     * and the complication history is updated.
      */
-    internal fun setComplicationData(
-        complicationData: ComplicationData,
-        loadDrawablesAsynchronous: Boolean,
-        instant: Instant
-    ) {
+    internal fun setComplicationData(complicationData: ComplicationData, instant: Instant) {
         lastComplicationUpdate = instant
         complicationHistory?.push(ComplicationDataHistoryEntry(complicationData, instant))
         timelineComplicationData = complicationData
         timelineEntries = complicationData.asWireComplicationData().timelineEntries?.toList()
-        selectComplicationDataForInstant(instant, loadDrawablesAsynchronous, true)
+        selectComplicationDataForInstant(
+            instant,
+            loadDrawablesAsynchronous = true,
+            forceUpdate = true
+        )
+    }
+
+    /**
+     * Sets the current [ComplicationData] and if it's a timeline, the correct override for
+     * [instant] is chosen. Any images are loaded synchronously. The complication history is not
+     * updated.
+     */
+    internal fun setComplicationDataForScreenshot(
+        complicationData: ComplicationData,
+        instant: Instant
+    ) {
+        lastComplicationUpdate = instant
+        timelineComplicationData = complicationData
+        timelineEntries = complicationData.asWireComplicationData().timelineEntries?.toList()
+        selectComplicationDataForInstant(
+            instant,
+            loadDrawablesAsynchronous = false,
+            forceUpdate = true
+        )
     }
 
     /**
diff --git a/wear/watchface/watchface/src/main/java/androidx/wear/watchface/ComplicationSlotsManager.kt b/wear/watchface/watchface/src/main/java/androidx/wear/watchface/ComplicationSlotsManager.kt
index d9cdbd9..22d34a0 100644
--- a/wear/watchface/watchface/src/main/java/androidx/wear/watchface/ComplicationSlotsManager.kt
+++ b/wear/watchface/watchface/src/main/java/androidx/wear/watchface/ComplicationSlotsManager.kt
@@ -327,14 +327,14 @@
             return
         }
         complication.dataDirty = complication.dataDirty || (complication.renderer.getData() != data)
-        complication.setComplicationData(data, true, instant)
+        complication.setComplicationData(data, instant)
     }
 
     /**
      * For use by screen shot code which will reset the data afterwards, hence dirty bit not set.
      */
     @UiThread
-    internal fun setComplicationDataUpdateSync(
+    internal fun setComplicationDataUpdateForScreenshot(
         complicationSlotId: Int,
         data: ComplicationData,
         instant: Instant
@@ -348,7 +348,7 @@
             )
             return
         }
-        complication.setComplicationData(data, false, instant)
+        complication.setComplicationDataForScreenshot(data, instant)
     }
 
     /**
diff --git a/wear/watchface/watchface/src/main/java/androidx/wear/watchface/WatchFace.kt b/wear/watchface/watchface/src/main/java/androidx/wear/watchface/WatchFace.kt
index b2e238e..568894e 100644
--- a/wear/watchface/watchface/src/main/java/androidx/wear/watchface/WatchFace.kt
+++ b/wear/watchface/watchface/src/main/java/androidx/wear/watchface/WatchFace.kt
@@ -252,8 +252,9 @@
                     }
                     .apply { setContext(context) }
 
-            val engine = watchFaceService.createHeadlessEngine(componentName)
-                as WatchFaceService.EngineWrapper
+            val engine =
+                watchFaceService.createHeadlessEngine(componentName)
+                    as WatchFaceService.EngineWrapper
             val headlessWatchFaceImpl = engine.createHeadlessInstance(params)
             return engine.deferredWatchFaceImpl.await().WFEditorDelegate(headlessWatchFaceImpl)
         }
@@ -472,10 +473,7 @@
         }
     }
 
-    /**
-     * The [OverlayStyle]. This feature is unimplemented on any platform, and will be
-     * removed.
-     */
+    /** The [OverlayStyle]. This feature is unimplemented on any platform, and will be removed. */
     @Deprecated("OverlayStyle will be removed in a future release.")
     @Suppress("Deprecation")
     public var overlayStyle: OverlayStyle = OverlayStyle()
@@ -655,8 +653,7 @@
     private val tapListener = watchface.tapListener
     internal var complicationDeniedDialogIntent = watchface.complicationDeniedDialogIntent
     internal var complicationRationaleDialogIntent = watchface.complicationRationaleDialogIntent
-    @Suppress("Deprecation")
-    internal var overlayStyle = watchface.overlayStyle
+    @Suppress("Deprecation") internal var overlayStyle = watchface.overlayStyle
 
     private var mockTime = MockTime(1.0, 0, Long.MAX_VALUE)
 
@@ -671,27 +668,25 @@
 
     init {
         val context = watchFaceHostApi.getContext()
-        val displayManager =
-                context.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
+        val displayManager = context.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
         displayManager.registerDisplayListener(
-                object : DisplayManager.DisplayListener {
-                    override fun onDisplayAdded(displayId: Int) {}
+            object : DisplayManager.DisplayListener {
+                override fun onDisplayAdded(displayId: Int) {}
 
-                    override fun onDisplayChanged(displayId: Int) {
-                        val display = displayManager.getDisplay(Display.DEFAULT_DISPLAY)!!
-                        if (display.state == Display.STATE_OFF &&
-                                watchState.isVisible.value == false) {
-                            // We want to avoid a glimpse of a stale time when transitioning from
-                            // hidden to visible, so we render two black frames to clear the buffers
-                            // when the display has been turned off and the watch is not visible.
-                            renderer.renderBlackFrame()
-                            renderer.renderBlackFrame()
-                        }
+                override fun onDisplayChanged(displayId: Int) {
+                    val display = displayManager.getDisplay(Display.DEFAULT_DISPLAY)!!
+                    if (display.state == Display.STATE_OFF && watchState.isVisible.value == false) {
+                        // We want to avoid a glimpse of a stale time when transitioning from
+                        // hidden to visible, so we render two black frames to clear the buffers
+                        // when the display has been turned off and the watch is not visible.
+                        renderer.renderBlackFrame()
+                        renderer.renderBlackFrame()
                     }
+                }
 
-                    override fun onDisplayRemoved(displayId: Int) {}
-                },
-                watchFaceHostApi.getUiThreadHandler()
+                override fun onDisplayRemoved(displayId: Int) {}
+            },
+            watchFaceHostApi.getUiThreadHandler()
         )
     }
 
@@ -893,8 +888,11 @@
             get() = watchFaceHostApi.getComplicationRationaleIntent()
 
         override var editorObscuresWatchFace: Boolean
-            get() = InteractiveInstanceManager
-                .getCurrentInteractiveInstance()?.engine?.editorObscuresWatchFace ?: false
+            get() =
+                InteractiveInstanceManager.getCurrentInteractiveInstance()
+                    ?.engine
+                    ?.editorObscuresWatchFace
+                    ?: false
             set(value) {
                 InteractiveInstanceManager.getCurrentInteractiveInstance()?.engine?.let {
                     it.editorObscuresWatchFace = value
@@ -915,7 +913,7 @@
 
                 slotIdToComplicationData?.let {
                     for ((id, complicationData) in it) {
-                        complicationSlotsManager.setComplicationDataUpdateSync(
+                        complicationSlotsManager.setComplicationDataUpdateForScreenshot(
                             id,
                             complicationData,
                             instant
@@ -930,7 +928,7 @@
                 slotIdToComplicationData?.let {
                     val now = getNow()
                     for ((id, complicationData) in oldComplicationData) {
-                        complicationSlotsManager.setComplicationDataUpdateSync(
+                        complicationSlotsManager.setComplicationDataUpdateForScreenshot(
                             id,
                             complicationData,
                             now
@@ -994,8 +992,11 @@
         // Separate calls are issued to deliver the state of isAmbient and isVisible, so during init
         // we might not yet know the state of both (which is required by the shouldAnimate logic).
         // If the editor is obscuring the watch face, there's no need to schedule a frame.
-        if (!watchState.isAmbient.hasValue() || !watchState.isVisible.hasValue() ||
-            editorObscuresWatchFace) {
+        if (
+            !watchState.isAmbient.hasValue() ||
+                !watchState.isVisible.hasValue() ||
+                editorObscuresWatchFace
+        ) {
             return
         }
 
@@ -1194,7 +1195,7 @@
 
             params.idAndComplicationDatumWireFormats?.let {
                 for (idAndData in it) {
-                    complicationSlotsManager.setComplicationDataUpdateSync(
+                    complicationSlotsManager.setComplicationDataUpdateForScreenshot(
                         idAndData.id,
                         idAndData.complicationData.toApiComplicationData(),
                         instant
@@ -1218,7 +1219,7 @@
                 if (params.idAndComplicationDatumWireFormats != null) {
                     val now = getNow()
                     for ((id, complicationData) in oldComplicationData) {
-                        complicationSlotsManager.setComplicationDataUpdateSync(
+                        complicationSlotsManager.setComplicationDataUpdateForScreenshot(
                             id,
                             complicationData,
                             now
@@ -1272,20 +1273,21 @@
 
                 // Compute the bounds of the complication based on the display rather than
                 // the headless renderer (which may be smaller).
-                val bounds = it.computeBounds(
-                    Rect(
-                    0,
-                    0,
-                        Resources.getSystem().displayMetrics.widthPixels,
-                        Resources.getSystem().displayMetrics.heightPixels
+                val bounds =
+                    it.computeBounds(
+                        Rect(
+                            0,
+                            0,
+                            Resources.getSystem().displayMetrics.widthPixels,
+                            Resources.getSystem().displayMetrics.heightPixels
+                        )
                     )
-                )
 
                 var prevData: ComplicationData? = null
                 val screenshotComplicationData = params.complicationData
                 if (screenshotComplicationData != null) {
                     prevData = it.renderer.getData()
-                    complicationSlotsManager.setComplicationDataUpdateSync(
+                    complicationSlotsManager.setComplicationDataUpdateForScreenshot(
                         params.complicationSlotId,
                         screenshotComplicationData.toApiComplicationData(),
                         instant
@@ -1303,12 +1305,13 @@
                         params.complicationSlotId
                     )
                     picture.endRecording()
-                    complicationBitmap = Api28CreateBitmapHelper.createBitmap(
-                        picture,
-                        bounds.width(),
-                        bounds.height(),
-                        Bitmap.Config.ARGB_8888
-                    )
+                    complicationBitmap =
+                        Api28CreateBitmapHelper.createBitmap(
+                            picture,
+                            bounds.width(),
+                            bounds.height(),
+                            Bitmap.Config.ARGB_8888
+                        )
                 } else {
                     complicationBitmap =
                         Bitmap.createBitmap(
@@ -1330,7 +1333,7 @@
                     // Restore previous ComplicationData & style if required.
                     if (prevData != null) {
                         val now = getNow()
-                        complicationSlotsManager.setComplicationDataUpdateSync(
+                        complicationSlotsManager.setComplicationDataUpdateForScreenshot(
                             params.complicationSlotId,
                             prevData,
                             now
@@ -1421,7 +1424,7 @@
 
             params.idAndComplicationDatumWireFormats?.let {
                 for (idAndData in it) {
-                    watchFaceImpl.complicationSlotsManager.setComplicationDataUpdateSync(
+                    watchFaceImpl.complicationSlotsManager.setComplicationDataUpdateForScreenshot(
                         idAndData.id,
                         idAndData.complicationData.toApiComplicationData(),
                         instant
@@ -1443,7 +1446,7 @@
             if (params.idAndComplicationDatumWireFormats != null) {
                 val now = watchFaceImpl.getNow()
                 for ((id, complicationData) in oldComplicationData) {
-                    watchFaceImpl.complicationSlotsManager.setComplicationDataUpdateSync(
+                    watchFaceImpl.complicationSlotsManager.setComplicationDataUpdateForScreenshot(
                         id,
                         complicationData,
                         now
diff --git a/wear/watchface/watchface/src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt b/wear/watchface/watchface/src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt
index 3a6c4ec..f131d12 100644
--- a/wear/watchface/watchface/src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt
+++ b/wear/watchface/watchface/src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt
@@ -70,6 +70,7 @@
 import androidx.wear.watchface.complications.data.ShortTextComplicationData
 import androidx.wear.watchface.complications.data.TimeDifferenceComplicationText
 import androidx.wear.watchface.complications.data.TimeDifferenceStyle
+import androidx.wear.watchface.complications.data.toApiComplicationData
 import androidx.wear.watchface.complications.rendering.CanvasComplicationDrawable
 import androidx.wear.watchface.complications.rendering.ComplicationDrawable
 import androidx.wear.watchface.control.HeadlessWatchFaceImpl
@@ -142,6 +143,7 @@
 import org.mockito.kotlin.verifyNoMoreInteractions
 import org.robolectric.Shadows.shadowOf
 import org.robolectric.annotation.Config
+import org.robolectric.shadows.ShadowBuild
 
 private const val INTERACTIVE_UPDATE_RATE_MS = 16L
 private const val LEFT_COMPLICATION_ID = 1000
@@ -728,6 +730,7 @@
 
     @Before
     public fun setUp() {
+        ShadowBuild.setType("userdebug")
         Assume.assumeTrue("This test suite assumes API 26", Build.VERSION.SDK_INT >= 26)
 
         `when`(handler.getLooper()).thenReturn(Looper.myLooper())
@@ -758,9 +761,11 @@
                  (TODO: b/264994539) - Explicitly releasing the mSurfaceControl field,
                  accessed via reflection. Remove when a proper fix is found
                 */
-                val mSurfaceControlObject: Field = WatchFaceService.EngineWrapper::class
-                    .java.superclass // android.service.wallpaper.WallpaperService$Engine
-                    .getDeclaredField("mSurfaceControl")
+                val mSurfaceControlObject: Field =
+                    WatchFaceService.EngineWrapper::class
+                        .java
+                        .superclass // android.service.wallpaper.WallpaperService$Engine
+                        .getDeclaredField("mSurfaceControl")
                 mSurfaceControlObject.isAccessible = true
                 (mSurfaceControlObject.get(engineWrapper) as SurfaceControl).release()
             }
@@ -1317,11 +1322,7 @@
                 null
             )
         verify(tapListener)
-            .onTapEvent(
-                TapType.UP,
-                TapEvent(10, 200, Instant.ofEpochMilli(looperTimeMillis)),
-                null
-            )
+            .onTapEvent(TapType.UP, TapEvent(10, 200, Instant.ofEpochMilli(looperTimeMillis)), null)
     }
 
     @Test
@@ -2858,6 +2859,48 @@
 
     @Test
     @Config(sdk = [Build.VERSION_CODES.O_MR1])
+    public fun updateComplicationData_appendsToHistory() {
+        initWallpaperInteractiveWatchFaceInstance(
+            complicationSlots = listOf(leftComplication)
+        )
+        // Validate that the history is initially empty.
+        assertThat(leftComplication.complicationHistory!!.iterator().asSequence().toList())
+            .isEmpty()
+        val longTextComplication =
+            WireComplicationData.Builder(WireComplicationData.TYPE_LONG_TEXT)
+                .setLongText(WireComplicationText.plainText("TYPE_LONG_TEXT"))
+                .build()
+
+        interactiveWatchFaceInstance.updateComplicationData(
+            listOf(IdAndComplicationDataWireFormat(LEFT_COMPLICATION_ID, longTextComplication))
+        )
+
+        assertThat(leftComplication.complicationHistory.toList().map { it.complicationData })
+            .containsExactly(longTextComplication.toApiComplicationData())
+    }
+
+    @Test
+    @Config(sdk = [Build.VERSION_CODES.O_MR1])
+    public fun setComplicationDataUpdateForScreenshot_doesNotAppendToHistory() {
+        initWallpaperInteractiveWatchFaceInstance(
+            complicationSlots = listOf(leftComplication)
+        )
+
+        complicationSlotsManager.setComplicationDataUpdateForScreenshot(
+            LEFT_COMPLICATION_ID,
+            WireComplicationData.Builder(WireComplicationData.TYPE_LONG_TEXT)
+                .setLongText(WireComplicationText.plainText("TYPE_LONG_TEXT"))
+                .build()
+                .toApiComplicationData(),
+            Instant.now()
+        )
+
+        assertThat(leftComplication.complicationHistory!!.iterator().asSequence().toList())
+            .isEmpty()
+    }
+
+    @Test
+    @Config(sdk = [Build.VERSION_CODES.O_MR1])
     public fun complicationCache() {
         val complicationCache = HashMap<String, ByteArray>()
         val instanceParams =
diff --git a/window/extensions/extensions/src/main/java/androidx/window/extensions/WindowExtensions.java b/window/extensions/extensions/src/main/java/androidx/window/extensions/WindowExtensions.java
index 676d286..74163e6 100644
--- a/window/extensions/extensions/src/main/java/androidx/window/extensions/WindowExtensions.java
+++ b/window/extensions/extensions/src/main/java/androidx/window/extensions/WindowExtensions.java
@@ -18,12 +18,15 @@
 
 import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 
+import android.app.Activity;
 import android.app.ActivityOptions;
+import android.content.Context;
 import android.os.IBinder;
 
 import androidx.annotation.Nullable;
 import androidx.annotation.RestrictTo;
 import androidx.window.extensions.area.WindowAreaComponent;
+import androidx.window.extensions.core.util.function.Consumer;
 import androidx.window.extensions.embedding.ActivityEmbeddingComponent;
 import androidx.window.extensions.embedding.ActivityStack;
 import androidx.window.extensions.embedding.SplitAttributes;
@@ -75,10 +78,13 @@
      * block.
      * The added APIs for Vendor API level 2 are:
      * <ul>
+     *     <li>{@link WindowAreaComponent#addRearDisplayStatusListener(Consumer)}</li>
+     *     <li>{@link WindowAreaComponent#startRearDisplaySession(Activity, Consumer)}</li>
      *     <li>{@link androidx.window.extensions.embedding.SplitPlaceholderRule.Builder#setFinishPrimaryWithPlaceholder(int)}</li>
      *     <li>{@link androidx.window.extensions.embedding.SplitAttributes}</li>
      *     <li>{@link ActivityEmbeddingComponent#setSplitAttributesCalculator(
      *      androidx.window.extensions.core.util.function.Function)}</li>
+     *     <li>{@link WindowLayoutComponent#addWindowLayoutInfoListener(Context, Consumer)}</li>
      * </ul>
      */
     @RestrictTo(LIBRARY_GROUP)
@@ -99,7 +105,11 @@
      *     <li>{@link ActivityEmbeddingComponent#updateSplitAttributes(IBinder, SplitAttributes)}
      *     </li>
      *     <li>{@link ActivityEmbeddingComponent#finishActivityStacks(Set)}</li>
-     *     <li>{@link androidx.window.extensions.area.WindowAreaComponent} APIs</li>
+     *     <li>{@link WindowAreaComponent#addRearDisplayPresentationStatusListener(Consumer)}</li>
+     *     <li>{@link WindowAreaComponent#startRearDisplayPresentationSession(Activity, Consumer)}
+     *     </li>
+     *     <li>{@link WindowAreaComponent#getRearDisplayMetrics()}</li>
+     *     <li>{@link WindowAreaComponent#getRearDisplayPresentation()}</li>
      * </ul>
      * </p>
      */
diff --git a/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/ExampleWindowInitializer.kt b/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/ExampleWindowInitializer.kt
index f9d8303..55425fa 100644
--- a/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/ExampleWindowInitializer.kt
+++ b/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/ExampleWindowInitializer.kt
@@ -18,6 +18,7 @@
 
 import android.content.Context
 import androidx.startup.Initializer
+import androidx.window.WindowSdkExtensions
 import androidx.window.demo.R
 import androidx.window.demo.embedding.SplitAttributesToggleMainActivity.Companion.PREFIX_FULLSCREEN_TOGGLE
 import androidx.window.demo.embedding.SplitAttributesToggleMainActivity.Companion.PREFIX_PLACEHOLDER
@@ -55,7 +56,7 @@
 
     override fun create(context: Context): RuleController {
         SplitController.getInstance(context).apply {
-            if (isSplitAttributesCalculatorSupported()) {
+            if (WindowSdkExtensions.getInstance().extensionVersion >= 2) {
                 setSplitAttributesCalculator(::sampleSplitAttributesCalculator)
             }
         }
diff --git a/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/SplitActivityBase.java b/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/SplitActivityBase.java
index faf792e..aaa751e 100644
--- a/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/SplitActivityBase.java
+++ b/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/SplitActivityBase.java
@@ -39,6 +39,7 @@
 import androidx.annotation.Nullable;
 import androidx.appcompat.app.AppCompatActivity;
 import androidx.core.util.Consumer;
+import androidx.window.WindowSdkExtensions;
 import androidx.window.demo.R;
 import androidx.window.demo.databinding.ActivitySplitActivityLayoutBinding;
 import androidx.window.embedding.ActivityEmbeddingController;
@@ -111,8 +112,7 @@
             }
             startActivity(new Intent(this, SplitActivityE.class), bundle);
         });
-        if (!ActivityEmbeddingOptions.isSetLaunchingActivityStackSupported(
-                ActivityOptions.makeBasic())) {
+        if (WindowSdkExtensions.getInstance().getExtensionVersion() < 3) {
             mViewBinding.setLaunchingEInActivityStack.setEnabled(false);
         }
         mViewBinding.launchF.setOnClickListener((View v) ->
diff --git a/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/SplitAttributesToggleMainActivity.kt b/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/SplitAttributesToggleMainActivity.kt
index 1021af3..d74e64d 100644
--- a/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/SplitAttributesToggleMainActivity.kt
+++ b/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/SplitAttributesToggleMainActivity.kt
@@ -28,6 +28,7 @@
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.lifecycleScope
 import androidx.lifecycle.repeatOnLifecycle
+import androidx.window.WindowSdkExtensions
 import androidx.window.core.ExperimentalWindowApi
 import androidx.window.demo.R
 import androidx.window.demo.databinding.ActivitySplitAttributesTogglePrimaryActivityBinding
@@ -70,7 +71,7 @@
 
         activityEmbeddingController = ActivityEmbeddingController.getInstance(this)
 
-        if (!splitController.isSplitAttributesCalculatorSupported()) {
+        if (WindowSdkExtensions.getInstance().extensionVersion < 2) {
             placeholderFoldingAwareAttrsRadioButton.isEnabled = false
             viewBinding.placeholderUseCustomizedSplitAttributes.isEnabled = false
             splitRuleFoldingAwareAttrsRadioButton.isEnabled = false
@@ -212,11 +213,13 @@
 
     private suspend fun updateWarningMessages() {
         val warningMessages = StringBuilder().apply {
-            if (!splitController.isSplitAttributesCalculatorSupported()) {
+            val apiLevel = WindowSdkExtensions.getInstance().extensionVersion
+
+            if (apiLevel < 2) {
                 append(resources.getString(R.string.split_attributes_calculator_not_supported))
                 append("\n")
             }
-            if (!activityEmbeddingController.isFinishingActivityStacksSupported()) {
+            if (apiLevel < 3) {
                 append("Finishing secondary activities is not supported on this device!\n")
             }
             if (viewBinding.finishSecondaryActivitiesButton.isEnabled &&
diff --git a/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/SplitAttributesTogglePrimaryActivity.kt b/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/SplitAttributesTogglePrimaryActivity.kt
index 097da84..e7c62cd 100644
--- a/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/SplitAttributesTogglePrimaryActivity.kt
+++ b/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/SplitAttributesTogglePrimaryActivity.kt
@@ -24,6 +24,7 @@
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.lifecycleScope
 import androidx.lifecycle.repeatOnLifecycle
+import androidx.window.WindowSdkExtensions
 import androidx.window.core.ExperimentalWindowApi
 import androidx.window.demo.R
 import androidx.window.embedding.ActivityStack
@@ -43,8 +44,7 @@
 
         viewBinding.rootSplitActivityLayout.setBackgroundColor(Color.parseColor("#e8f5e9"))
 
-        val isRuntimeApiSupported = activityEmbeddingController
-            .isFinishingActivityStacksSupported()
+        val isRuntimeApiSupported = WindowSdkExtensions.getInstance().extensionVersion >= 3
 
         secondaryActivityIntent = Intent(
             this,
diff --git a/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/SplitAttributesToggleSecondaryActivity.kt b/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/SplitAttributesToggleSecondaryActivity.kt
index eac978a..01104cb 100644
--- a/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/SplitAttributesToggleSecondaryActivity.kt
+++ b/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/SplitAttributesToggleSecondaryActivity.kt
@@ -24,6 +24,7 @@
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.lifecycleScope
 import androidx.lifecycle.repeatOnLifecycle
+import androidx.window.WindowSdkExtensions
 import androidx.window.core.ExperimentalWindowApi
 import androidx.window.demo.R
 import androidx.window.demo.databinding.ActivitySplitAttributesToggleSecondaryActivityBinding
@@ -63,10 +64,8 @@
         activityEmbeddingController = ActivityEmbeddingController.getInstance(this)
         val splitAttributesCustomizationEnabled = demoActivityEmbeddingController
             .splitAttributesCustomizationEnabled.get()
-        splitAttributesUpdatesSupported =
-            splitController.isInvalidatingTopVisibleSplitAttributesSupported() &&
-                splitController.isUpdatingSplitAttributesSupported() &&
-                !splitAttributesCustomizationEnabled
+        splitAttributesUpdatesSupported = WindowSdkExtensions.getInstance().extensionVersion >= 3 &&
+            !splitAttributesCustomizationEnabled
 
         fullscreenToggleButton.apply {
             // Disable the toggle fullscreen feature if the device doesn't support runtime
diff --git a/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/SplitDeviceStateActivityBase.kt b/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/SplitDeviceStateActivityBase.kt
index 16aad4f..fcb0ddb 100644
--- a/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/SplitDeviceStateActivityBase.kt
+++ b/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/SplitDeviceStateActivityBase.kt
@@ -28,6 +28,7 @@
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.lifecycleScope
 import androidx.lifecycle.repeatOnLifecycle
+import androidx.window.WindowSdkExtensions
 import androidx.window.demo.R
 import androidx.window.demo.databinding.ActivitySplitDeviceStateLayoutBinding
 import androidx.window.embedding.EmbeddingRule
@@ -63,6 +64,8 @@
     /** The last selected split rule id. */
     private var lastCheckedRuleId = 0
 
+    private val isCallbackSupported = WindowSdkExtensions.getInstance().extensionVersion >= 2
+
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
         viewBinding = ActivitySplitDeviceStateLayoutBinding.inflate(layoutInflater)
@@ -103,7 +106,6 @@
         viewBinding.swapPrimarySecondaryPositionCheckBox.setOnCheckedChangeListener(this)
         viewBinding.launchActivityToSide.setOnClickListener(this)
 
-        val isCallbackSupported = splitController.isSplitAttributesCalculatorSupported()
         if (!isCallbackSupported) {
             // Disable the radioButtons that use SplitAttributesCalculator
             viewBinding.showFullscreenInPortraitRadioButton.isEnabled = false
@@ -295,7 +297,7 @@
             .setSplitType(SPLIT_TYPE_EXPAND)
             .build()
         var suggestToFinishItself = false
-        val isCallbackSupported = splitController.isSplitAttributesCalculatorSupported()
+
         // Traverse SplitInfos from the end because last SplitInfo has the highest z-order.
         for (info in newSplitInfos.reversed()) {
             if (info.contains(this@SplitDeviceStateActivityBase)) {
diff --git a/window/window-testing/src/main/java/androidx/window/testing/embedding/StubEmbeddingBackend.kt b/window/window-testing/src/main/java/androidx/window/testing/embedding/StubEmbeddingBackend.kt
index 78aca27..758b6d0 100644
--- a/window/window-testing/src/main/java/androidx/window/testing/embedding/StubEmbeddingBackend.kt
+++ b/window/window-testing/src/main/java/androidx/window/testing/embedding/StubEmbeddingBackend.kt
@@ -159,10 +159,6 @@
         TODO("Not yet implemented")
     }
 
-    override fun isSplitAttributesCalculatorSupported(): Boolean {
-        TODO("Not yet implemented")
-    }
-
     override fun getActivityStack(activity: Activity): ActivityStack? {
         TODO("Not yet implemented")
     }
@@ -178,10 +174,6 @@
         TODO("Not yet implemented")
     }
 
-    override fun isFinishActivityStacksSupported(): Boolean {
-        TODO("Not yet implemented")
-    }
-
     override fun invalidateTopVisibleSplitAttributes() {
         TODO("Not yet implemented")
     }
@@ -190,10 +182,6 @@
         TODO("Not yet implemented")
     }
 
-    override fun areSplitAttributesUpdatesSupported(): Boolean {
-        TODO("Not yet implemented")
-    }
-
     private fun validateRules(rules: Set<EmbeddingRule>) {
         val tags = HashSet<String>()
         rules.forEach { rule ->
diff --git a/window/window/api/1.2.0-beta03.txt b/window/window/api/1.2.0-beta03.txt
index 1930a35..4241d96 100644
--- a/window/window/api/1.2.0-beta03.txt
+++ b/window/window/api/1.2.0-beta03.txt
@@ -1,6 +1,11 @@
 // Signature format: 4.0
 package androidx.window {
 
+  @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.CONSTRUCTOR, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.PROPERTY}) public @interface RequiresWindowSdkExtension {
+    method public abstract int version();
+    property public abstract int version;
+  }
+
   public final class WindowProperties {
     field public static final androidx.window.WindowProperties INSTANCE;
     field public static final String PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE = "android.window.PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE";
@@ -10,6 +15,17 @@
     field public static final String PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES = "android.window.PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES";
   }
 
+  public abstract class WindowSdkExtensions {
+    method @IntRange(from=0L) public int getExtensionVersion();
+    method public static final androidx.window.WindowSdkExtensions getInstance();
+    property @IntRange(from=0L) public int extensionVersion;
+    field public static final androidx.window.WindowSdkExtensions.Companion Companion;
+  }
+
+  public static final class WindowSdkExtensions.Companion {
+    method public androidx.window.WindowSdkExtensions getInstance();
+  }
+
 }
 
 package androidx.window.area {
@@ -107,11 +123,10 @@
 package androidx.window.embedding {
 
   public final class ActivityEmbeddingController {
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public void finishActivityStacks(java.util.Set<androidx.window.embedding.ActivityStack> activityStacks);
+    method @SuppressCompatibility @androidx.window.RequiresWindowSdkExtension(version=3) @androidx.window.core.ExperimentalWindowApi public void finishActivityStacks(java.util.Set<androidx.window.embedding.ActivityStack> activityStacks);
     method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public androidx.window.embedding.ActivityStack? getActivityStack(android.app.Activity activity);
     method public static androidx.window.embedding.ActivityEmbeddingController getInstance(android.content.Context context);
     method public boolean isActivityEmbedded(android.app.Activity activity);
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public boolean isFinishingActivityStacksSupported();
     field public static final androidx.window.embedding.ActivityEmbeddingController.Companion Companion;
   }
 
@@ -120,9 +135,8 @@
   }
 
   public final class ActivityEmbeddingOptions {
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public static boolean isSetLaunchingActivityStackSupported(android.app.ActivityOptions);
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public static android.app.ActivityOptions setLaunchingActivityStack(android.app.ActivityOptions, android.app.Activity activity);
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public static android.app.ActivityOptions setLaunchingActivityStack(android.app.ActivityOptions, android.content.Context context, androidx.window.embedding.ActivityStack activityStack);
+    method @SuppressCompatibility @androidx.window.RequiresWindowSdkExtension(version=3) @androidx.window.core.ExperimentalWindowApi public static android.app.ActivityOptions setLaunchingActivityStack(android.app.ActivityOptions, android.app.Activity activity);
+    method @SuppressCompatibility @androidx.window.RequiresWindowSdkExtension(version=3) @androidx.window.core.ExperimentalWindowApi public static android.app.ActivityOptions setLaunchingActivityStack(android.app.ActivityOptions, android.content.Context context, androidx.window.embedding.ActivityStack activityStack);
   }
 
   public final class ActivityFilter {
@@ -245,16 +259,13 @@
   }
 
   public final class SplitController {
-    method public void clearSplitAttributesCalculator();
+    method @androidx.window.RequiresWindowSdkExtension(version=2) public void clearSplitAttributesCalculator();
     method public static androidx.window.embedding.SplitController getInstance(android.content.Context context);
     method public androidx.window.embedding.SplitController.SplitSupportStatus getSplitSupportStatus();
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public void invalidateTopVisibleSplitAttributes();
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public boolean isInvalidatingTopVisibleSplitAttributesSupported();
-    method public boolean isSplitAttributesCalculatorSupported();
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public boolean isUpdatingSplitAttributesSupported();
-    method public void setSplitAttributesCalculator(kotlin.jvm.functions.Function1<? super androidx.window.embedding.SplitAttributesCalculatorParams,androidx.window.embedding.SplitAttributes> calculator);
+    method @SuppressCompatibility @androidx.window.RequiresWindowSdkExtension(version=3) @androidx.window.core.ExperimentalWindowApi public void invalidateTopVisibleSplitAttributes();
+    method @androidx.window.RequiresWindowSdkExtension(version=2) public void setSplitAttributesCalculator(kotlin.jvm.functions.Function1<? super androidx.window.embedding.SplitAttributesCalculatorParams,androidx.window.embedding.SplitAttributes> calculator);
     method public kotlinx.coroutines.flow.Flow<java.util.List<androidx.window.embedding.SplitInfo>> splitInfoList(android.app.Activity activity);
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public void updateSplitAttributes(androidx.window.embedding.SplitInfo splitInfo, androidx.window.embedding.SplitAttributes splitAttributes);
+    method @SuppressCompatibility @androidx.window.RequiresWindowSdkExtension(version=3) @androidx.window.core.ExperimentalWindowApi public void updateSplitAttributes(androidx.window.embedding.SplitInfo splitInfo, androidx.window.embedding.SplitAttributes splitAttributes);
     property public final androidx.window.embedding.SplitController.SplitSupportStatus splitSupportStatus;
     field public static final androidx.window.embedding.SplitController.Companion Companion;
   }
diff --git a/window/window/api/current.ignore b/window/window/api/current.ignore
deleted file mode 100644
index 2b9500cb..0000000
--- a/window/window/api/current.ignore
+++ /dev/null
@@ -1,7 +0,0 @@
-// Baseline format: 1.0
-AddedMethod: androidx.window.embedding.SplitAttributesCalculatorParams#areDefaultConstraintsSatisfied():
-    Added method androidx.window.embedding.SplitAttributesCalculatorParams.areDefaultConstraintsSatisfied()
-
-
-RemovedMethod: androidx.window.embedding.SplitAttributesCalculatorParams#getAreDefaultConstraintsSatisfied():
-    Removed method androidx.window.embedding.SplitAttributesCalculatorParams.getAreDefaultConstraintsSatisfied()
diff --git a/window/window/api/current.txt b/window/window/api/current.txt
index 1930a35..4241d96 100644
--- a/window/window/api/current.txt
+++ b/window/window/api/current.txt
@@ -1,6 +1,11 @@
 // Signature format: 4.0
 package androidx.window {
 
+  @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.CONSTRUCTOR, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.PROPERTY}) public @interface RequiresWindowSdkExtension {
+    method public abstract int version();
+    property public abstract int version;
+  }
+
   public final class WindowProperties {
     field public static final androidx.window.WindowProperties INSTANCE;
     field public static final String PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE = "android.window.PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE";
@@ -10,6 +15,17 @@
     field public static final String PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES = "android.window.PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES";
   }
 
+  public abstract class WindowSdkExtensions {
+    method @IntRange(from=0L) public int getExtensionVersion();
+    method public static final androidx.window.WindowSdkExtensions getInstance();
+    property @IntRange(from=0L) public int extensionVersion;
+    field public static final androidx.window.WindowSdkExtensions.Companion Companion;
+  }
+
+  public static final class WindowSdkExtensions.Companion {
+    method public androidx.window.WindowSdkExtensions getInstance();
+  }
+
 }
 
 package androidx.window.area {
@@ -107,11 +123,10 @@
 package androidx.window.embedding {
 
   public final class ActivityEmbeddingController {
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public void finishActivityStacks(java.util.Set<androidx.window.embedding.ActivityStack> activityStacks);
+    method @SuppressCompatibility @androidx.window.RequiresWindowSdkExtension(version=3) @androidx.window.core.ExperimentalWindowApi public void finishActivityStacks(java.util.Set<androidx.window.embedding.ActivityStack> activityStacks);
     method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public androidx.window.embedding.ActivityStack? getActivityStack(android.app.Activity activity);
     method public static androidx.window.embedding.ActivityEmbeddingController getInstance(android.content.Context context);
     method public boolean isActivityEmbedded(android.app.Activity activity);
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public boolean isFinishingActivityStacksSupported();
     field public static final androidx.window.embedding.ActivityEmbeddingController.Companion Companion;
   }
 
@@ -120,9 +135,8 @@
   }
 
   public final class ActivityEmbeddingOptions {
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public static boolean isSetLaunchingActivityStackSupported(android.app.ActivityOptions);
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public static android.app.ActivityOptions setLaunchingActivityStack(android.app.ActivityOptions, android.app.Activity activity);
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public static android.app.ActivityOptions setLaunchingActivityStack(android.app.ActivityOptions, android.content.Context context, androidx.window.embedding.ActivityStack activityStack);
+    method @SuppressCompatibility @androidx.window.RequiresWindowSdkExtension(version=3) @androidx.window.core.ExperimentalWindowApi public static android.app.ActivityOptions setLaunchingActivityStack(android.app.ActivityOptions, android.app.Activity activity);
+    method @SuppressCompatibility @androidx.window.RequiresWindowSdkExtension(version=3) @androidx.window.core.ExperimentalWindowApi public static android.app.ActivityOptions setLaunchingActivityStack(android.app.ActivityOptions, android.content.Context context, androidx.window.embedding.ActivityStack activityStack);
   }
 
   public final class ActivityFilter {
@@ -245,16 +259,13 @@
   }
 
   public final class SplitController {
-    method public void clearSplitAttributesCalculator();
+    method @androidx.window.RequiresWindowSdkExtension(version=2) public void clearSplitAttributesCalculator();
     method public static androidx.window.embedding.SplitController getInstance(android.content.Context context);
     method public androidx.window.embedding.SplitController.SplitSupportStatus getSplitSupportStatus();
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public void invalidateTopVisibleSplitAttributes();
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public boolean isInvalidatingTopVisibleSplitAttributesSupported();
-    method public boolean isSplitAttributesCalculatorSupported();
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public boolean isUpdatingSplitAttributesSupported();
-    method public void setSplitAttributesCalculator(kotlin.jvm.functions.Function1<? super androidx.window.embedding.SplitAttributesCalculatorParams,androidx.window.embedding.SplitAttributes> calculator);
+    method @SuppressCompatibility @androidx.window.RequiresWindowSdkExtension(version=3) @androidx.window.core.ExperimentalWindowApi public void invalidateTopVisibleSplitAttributes();
+    method @androidx.window.RequiresWindowSdkExtension(version=2) public void setSplitAttributesCalculator(kotlin.jvm.functions.Function1<? super androidx.window.embedding.SplitAttributesCalculatorParams,androidx.window.embedding.SplitAttributes> calculator);
     method public kotlinx.coroutines.flow.Flow<java.util.List<androidx.window.embedding.SplitInfo>> splitInfoList(android.app.Activity activity);
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public void updateSplitAttributes(androidx.window.embedding.SplitInfo splitInfo, androidx.window.embedding.SplitAttributes splitAttributes);
+    method @SuppressCompatibility @androidx.window.RequiresWindowSdkExtension(version=3) @androidx.window.core.ExperimentalWindowApi public void updateSplitAttributes(androidx.window.embedding.SplitInfo splitInfo, androidx.window.embedding.SplitAttributes splitAttributes);
     property public final androidx.window.embedding.SplitController.SplitSupportStatus splitSupportStatus;
     field public static final androidx.window.embedding.SplitController.Companion Companion;
   }
diff --git a/window/window/api/restricted_1.2.0-beta03.txt b/window/window/api/restricted_1.2.0-beta03.txt
index 1930a35..4241d96 100644
--- a/window/window/api/restricted_1.2.0-beta03.txt
+++ b/window/window/api/restricted_1.2.0-beta03.txt
@@ -1,6 +1,11 @@
 // Signature format: 4.0
 package androidx.window {
 
+  @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.CONSTRUCTOR, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.PROPERTY}) public @interface RequiresWindowSdkExtension {
+    method public abstract int version();
+    property public abstract int version;
+  }
+
   public final class WindowProperties {
     field public static final androidx.window.WindowProperties INSTANCE;
     field public static final String PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE = "android.window.PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE";
@@ -10,6 +15,17 @@
     field public static final String PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES = "android.window.PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES";
   }
 
+  public abstract class WindowSdkExtensions {
+    method @IntRange(from=0L) public int getExtensionVersion();
+    method public static final androidx.window.WindowSdkExtensions getInstance();
+    property @IntRange(from=0L) public int extensionVersion;
+    field public static final androidx.window.WindowSdkExtensions.Companion Companion;
+  }
+
+  public static final class WindowSdkExtensions.Companion {
+    method public androidx.window.WindowSdkExtensions getInstance();
+  }
+
 }
 
 package androidx.window.area {
@@ -107,11 +123,10 @@
 package androidx.window.embedding {
 
   public final class ActivityEmbeddingController {
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public void finishActivityStacks(java.util.Set<androidx.window.embedding.ActivityStack> activityStacks);
+    method @SuppressCompatibility @androidx.window.RequiresWindowSdkExtension(version=3) @androidx.window.core.ExperimentalWindowApi public void finishActivityStacks(java.util.Set<androidx.window.embedding.ActivityStack> activityStacks);
     method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public androidx.window.embedding.ActivityStack? getActivityStack(android.app.Activity activity);
     method public static androidx.window.embedding.ActivityEmbeddingController getInstance(android.content.Context context);
     method public boolean isActivityEmbedded(android.app.Activity activity);
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public boolean isFinishingActivityStacksSupported();
     field public static final androidx.window.embedding.ActivityEmbeddingController.Companion Companion;
   }
 
@@ -120,9 +135,8 @@
   }
 
   public final class ActivityEmbeddingOptions {
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public static boolean isSetLaunchingActivityStackSupported(android.app.ActivityOptions);
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public static android.app.ActivityOptions setLaunchingActivityStack(android.app.ActivityOptions, android.app.Activity activity);
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public static android.app.ActivityOptions setLaunchingActivityStack(android.app.ActivityOptions, android.content.Context context, androidx.window.embedding.ActivityStack activityStack);
+    method @SuppressCompatibility @androidx.window.RequiresWindowSdkExtension(version=3) @androidx.window.core.ExperimentalWindowApi public static android.app.ActivityOptions setLaunchingActivityStack(android.app.ActivityOptions, android.app.Activity activity);
+    method @SuppressCompatibility @androidx.window.RequiresWindowSdkExtension(version=3) @androidx.window.core.ExperimentalWindowApi public static android.app.ActivityOptions setLaunchingActivityStack(android.app.ActivityOptions, android.content.Context context, androidx.window.embedding.ActivityStack activityStack);
   }
 
   public final class ActivityFilter {
@@ -245,16 +259,13 @@
   }
 
   public final class SplitController {
-    method public void clearSplitAttributesCalculator();
+    method @androidx.window.RequiresWindowSdkExtension(version=2) public void clearSplitAttributesCalculator();
     method public static androidx.window.embedding.SplitController getInstance(android.content.Context context);
     method public androidx.window.embedding.SplitController.SplitSupportStatus getSplitSupportStatus();
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public void invalidateTopVisibleSplitAttributes();
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public boolean isInvalidatingTopVisibleSplitAttributesSupported();
-    method public boolean isSplitAttributesCalculatorSupported();
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public boolean isUpdatingSplitAttributesSupported();
-    method public void setSplitAttributesCalculator(kotlin.jvm.functions.Function1<? super androidx.window.embedding.SplitAttributesCalculatorParams,androidx.window.embedding.SplitAttributes> calculator);
+    method @SuppressCompatibility @androidx.window.RequiresWindowSdkExtension(version=3) @androidx.window.core.ExperimentalWindowApi public void invalidateTopVisibleSplitAttributes();
+    method @androidx.window.RequiresWindowSdkExtension(version=2) public void setSplitAttributesCalculator(kotlin.jvm.functions.Function1<? super androidx.window.embedding.SplitAttributesCalculatorParams,androidx.window.embedding.SplitAttributes> calculator);
     method public kotlinx.coroutines.flow.Flow<java.util.List<androidx.window.embedding.SplitInfo>> splitInfoList(android.app.Activity activity);
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public void updateSplitAttributes(androidx.window.embedding.SplitInfo splitInfo, androidx.window.embedding.SplitAttributes splitAttributes);
+    method @SuppressCompatibility @androidx.window.RequiresWindowSdkExtension(version=3) @androidx.window.core.ExperimentalWindowApi public void updateSplitAttributes(androidx.window.embedding.SplitInfo splitInfo, androidx.window.embedding.SplitAttributes splitAttributes);
     property public final androidx.window.embedding.SplitController.SplitSupportStatus splitSupportStatus;
     field public static final androidx.window.embedding.SplitController.Companion Companion;
   }
diff --git a/window/window/api/restricted_current.ignore b/window/window/api/restricted_current.ignore
deleted file mode 100644
index 2b9500cb..0000000
--- a/window/window/api/restricted_current.ignore
+++ /dev/null
@@ -1,7 +0,0 @@
-// Baseline format: 1.0
-AddedMethod: androidx.window.embedding.SplitAttributesCalculatorParams#areDefaultConstraintsSatisfied():
-    Added method androidx.window.embedding.SplitAttributesCalculatorParams.areDefaultConstraintsSatisfied()
-
-
-RemovedMethod: androidx.window.embedding.SplitAttributesCalculatorParams#getAreDefaultConstraintsSatisfied():
-    Removed method androidx.window.embedding.SplitAttributesCalculatorParams.getAreDefaultConstraintsSatisfied()
diff --git a/window/window/api/restricted_current.txt b/window/window/api/restricted_current.txt
index 1930a35..4241d96 100644
--- a/window/window/api/restricted_current.txt
+++ b/window/window/api/restricted_current.txt
@@ -1,6 +1,11 @@
 // Signature format: 4.0
 package androidx.window {
 
+  @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.CONSTRUCTOR, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.PROPERTY}) public @interface RequiresWindowSdkExtension {
+    method public abstract int version();
+    property public abstract int version;
+  }
+
   public final class WindowProperties {
     field public static final androidx.window.WindowProperties INSTANCE;
     field public static final String PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE = "android.window.PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE";
@@ -10,6 +15,17 @@
     field public static final String PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES = "android.window.PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES";
   }
 
+  public abstract class WindowSdkExtensions {
+    method @IntRange(from=0L) public int getExtensionVersion();
+    method public static final androidx.window.WindowSdkExtensions getInstance();
+    property @IntRange(from=0L) public int extensionVersion;
+    field public static final androidx.window.WindowSdkExtensions.Companion Companion;
+  }
+
+  public static final class WindowSdkExtensions.Companion {
+    method public androidx.window.WindowSdkExtensions getInstance();
+  }
+
 }
 
 package androidx.window.area {
@@ -107,11 +123,10 @@
 package androidx.window.embedding {
 
   public final class ActivityEmbeddingController {
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public void finishActivityStacks(java.util.Set<androidx.window.embedding.ActivityStack> activityStacks);
+    method @SuppressCompatibility @androidx.window.RequiresWindowSdkExtension(version=3) @androidx.window.core.ExperimentalWindowApi public void finishActivityStacks(java.util.Set<androidx.window.embedding.ActivityStack> activityStacks);
     method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public androidx.window.embedding.ActivityStack? getActivityStack(android.app.Activity activity);
     method public static androidx.window.embedding.ActivityEmbeddingController getInstance(android.content.Context context);
     method public boolean isActivityEmbedded(android.app.Activity activity);
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public boolean isFinishingActivityStacksSupported();
     field public static final androidx.window.embedding.ActivityEmbeddingController.Companion Companion;
   }
 
@@ -120,9 +135,8 @@
   }
 
   public final class ActivityEmbeddingOptions {
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public static boolean isSetLaunchingActivityStackSupported(android.app.ActivityOptions);
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public static android.app.ActivityOptions setLaunchingActivityStack(android.app.ActivityOptions, android.app.Activity activity);
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public static android.app.ActivityOptions setLaunchingActivityStack(android.app.ActivityOptions, android.content.Context context, androidx.window.embedding.ActivityStack activityStack);
+    method @SuppressCompatibility @androidx.window.RequiresWindowSdkExtension(version=3) @androidx.window.core.ExperimentalWindowApi public static android.app.ActivityOptions setLaunchingActivityStack(android.app.ActivityOptions, android.app.Activity activity);
+    method @SuppressCompatibility @androidx.window.RequiresWindowSdkExtension(version=3) @androidx.window.core.ExperimentalWindowApi public static android.app.ActivityOptions setLaunchingActivityStack(android.app.ActivityOptions, android.content.Context context, androidx.window.embedding.ActivityStack activityStack);
   }
 
   public final class ActivityFilter {
@@ -245,16 +259,13 @@
   }
 
   public final class SplitController {
-    method public void clearSplitAttributesCalculator();
+    method @androidx.window.RequiresWindowSdkExtension(version=2) public void clearSplitAttributesCalculator();
     method public static androidx.window.embedding.SplitController getInstance(android.content.Context context);
     method public androidx.window.embedding.SplitController.SplitSupportStatus getSplitSupportStatus();
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public void invalidateTopVisibleSplitAttributes();
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public boolean isInvalidatingTopVisibleSplitAttributesSupported();
-    method public boolean isSplitAttributesCalculatorSupported();
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public boolean isUpdatingSplitAttributesSupported();
-    method public void setSplitAttributesCalculator(kotlin.jvm.functions.Function1<? super androidx.window.embedding.SplitAttributesCalculatorParams,androidx.window.embedding.SplitAttributes> calculator);
+    method @SuppressCompatibility @androidx.window.RequiresWindowSdkExtension(version=3) @androidx.window.core.ExperimentalWindowApi public void invalidateTopVisibleSplitAttributes();
+    method @androidx.window.RequiresWindowSdkExtension(version=2) public void setSplitAttributesCalculator(kotlin.jvm.functions.Function1<? super androidx.window.embedding.SplitAttributesCalculatorParams,androidx.window.embedding.SplitAttributes> calculator);
     method public kotlinx.coroutines.flow.Flow<java.util.List<androidx.window.embedding.SplitInfo>> splitInfoList(android.app.Activity activity);
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public void updateSplitAttributes(androidx.window.embedding.SplitInfo splitInfo, androidx.window.embedding.SplitAttributes splitAttributes);
+    method @SuppressCompatibility @androidx.window.RequiresWindowSdkExtension(version=3) @androidx.window.core.ExperimentalWindowApi public void updateSplitAttributes(androidx.window.embedding.SplitInfo splitInfo, androidx.window.embedding.SplitAttributes splitAttributes);
     property public final androidx.window.embedding.SplitController.SplitSupportStatus splitSupportStatus;
     field public static final androidx.window.embedding.SplitController.Companion Companion;
   }
diff --git a/window/window/samples/src/main/java/androidx.window.samples/WindowSdkExtensionsSamples.kt b/window/window/samples/src/main/java/androidx.window.samples/WindowSdkExtensionsSamples.kt
new file mode 100644
index 0000000..f4049d1
--- /dev/null
+++ b/window/window/samples/src/main/java/androidx.window.samples/WindowSdkExtensionsSamples.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2023 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.window.samples
+
+import androidx.annotation.Sampled
+import androidx.window.RequiresWindowSdkExtension
+import androidx.window.WindowSdkExtensions
+import androidx.window.embedding.SplitAttributes
+import androidx.window.embedding.SplitAttributesCalculatorParams
+import androidx.window.embedding.SplitController
+import androidx.window.samples.embedding.context
+
+@Sampled
+fun checkWindowSdkExtensionsVersion() {
+    // For example, SplitController#setSplitAttributesCalculator requires extension version 2.
+    // Callers must check the current extension version before invoking the API, or exception will
+    // be thrown.
+    if (WindowSdkExtensions.getInstance().extensionVersion >= 2) {
+        SplitController.getInstance(context).setSplitAttributesCalculator(splitAttributesCalculator)
+    }
+}
+
+val splitAttributesCalculator = { _: SplitAttributesCalculatorParams ->
+    SplitAttributes.Builder().build()
+}
+
+@Sampled
+fun annotateRequiresWindowSdkExtension() {
+    // Given that there's an API required Window SDK Extension version 3
+    @RequiresWindowSdkExtension(3)
+    fun coolFeature() {}
+
+    // Developers can use @RequiresWindowSdkExtension to annotate their own functions to document
+    // the required minimum API level.
+    @RequiresWindowSdkExtension(3)
+    fun useCoolFeatureNoCheck() {
+        coolFeature()
+    }
+
+    // Then users know they should wrap the function with version check
+    if (WindowSdkExtensions.getInstance().extensionVersion >= 3) {
+        useCoolFeatureNoCheck()
+    }
+}
diff --git a/window/window/src/main/java/androidx/window/RequiresWindowSdkExtension.kt b/window/window/src/main/java/androidx/window/RequiresWindowSdkExtension.kt
new file mode 100644
index 0000000..d112c94
--- /dev/null
+++ b/window/window/src/main/java/androidx/window/RequiresWindowSdkExtension.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2023 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.window
+
+import androidx.annotation.IntRange
+
+// TODO(b/292738295): Provide lint checks for RequiresWindowSdkExtension
+/**
+ * Denotes that the annotated element must only be used if
+ * [WindowSdkExtensions.extensionVersion] is greater than or equal to the given [version].
+ * Please see code sample linked below for usages.
+ *
+ * Calling the API that requires a higher level than the device's current level may lead to
+ * exceptions or unexpected results.
+ *
+ * @param version the minimum required [WindowSdkExtensions] version of the denoted target
+ *
+ * @sample androidx.window.samples.annotateRequiresWindowSdkExtension
+ */
+@MustBeDocumented
+@Retention(value = AnnotationRetention.BINARY)
+@Target(
+    AnnotationTarget.CLASS,
+    AnnotationTarget.FUNCTION,
+    AnnotationTarget.PROPERTY_GETTER,
+    AnnotationTarget.PROPERTY_SETTER,
+    AnnotationTarget.CONSTRUCTOR,
+    AnnotationTarget.FIELD,
+    AnnotationTarget.PROPERTY,
+)
+annotation class RequiresWindowSdkExtension(
+    /** The minimum required [WindowSdkExtensions] version of the denoted target */
+    @IntRange(from = 1)
+    val version: Int
+)
diff --git a/window/window/src/main/java/androidx/window/WindowSdkExtensions.kt b/window/window/src/main/java/androidx/window/WindowSdkExtensions.kt
new file mode 100644
index 0000000..26f0a6d
--- /dev/null
+++ b/window/window/src/main/java/androidx/window/WindowSdkExtensions.kt
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2023 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.window
+
+import androidx.annotation.IntRange
+import androidx.window.core.ExtensionsUtil
+
+/**
+ * This class provides information about the extension SDK versions for window features present on
+ * this device. Use [extensionVersion] to get the version of the extension. The extension version
+ * advances as the platform evolves and new APIs are added, so is suitable to use for determining
+ * API availability at runtime.
+ *
+ * Window Manager Jetpack APIs that require window SDK extensions support are denoted with
+ * [RequiresWindowSdkExtension]. The caller must check whether the device's extension version is
+ * greater than or equal to the minimum level reported in [RequiresWindowSdkExtension].
+ *
+ * @sample androidx.window.samples.checkWindowSdkExtensionsVersion
+ */
+abstract class WindowSdkExtensions internal constructor() {
+
+    /**
+     * Reports the device's extension version
+     *
+     * When Window SDK Extensions is not present on the device, the extension version will be 0.
+     */
+    @get: IntRange(from = 0)
+    open val extensionVersion: Int = ExtensionsUtil.safeVendorApiLevel
+
+    /**
+     * Checks the [extensionVersion] and throws [UnsupportedOperationException] if the minimum
+     * [version] is not satisfied.
+     *
+     * @param version The minimum required extension version of the targeting API.
+     * @throws UnsupportedOperationException if the minimum [version] is not satisfied.
+     */
+    internal fun requireExtensionVersion(@IntRange(from = 1) version: Int) {
+        if (extensionVersion < version) {
+            throw UnsupportedOperationException("This API requires extension version " +
+                "$version, but the device is on $extensionVersion")
+        }
+    }
+
+    companion object {
+        /** Returns a [WindowSdkExtensions] instance. */
+        @JvmStatic
+        fun getInstance(): WindowSdkExtensions {
+            return decorator.decorate(object : WindowSdkExtensions() {})
+        }
+
+        private var decorator: WindowSdkExtensionsDecorator = EmptyDecoratorWindowSdk
+
+        internal fun overrideDecorator(overridingDecorator: WindowSdkExtensionsDecorator) {
+            decorator = overridingDecorator
+        }
+
+        internal fun reset() {
+            decorator = EmptyDecoratorWindowSdk
+        }
+    }
+}
+
+internal interface WindowSdkExtensionsDecorator {
+    /** Returns a [WindowSdkExtensions] instance. */
+    fun decorate(windowSdkExtensions: WindowSdkExtensions): WindowSdkExtensions
+}
+
+private object EmptyDecoratorWindowSdk : WindowSdkExtensionsDecorator {
+    override fun decorate(windowSdkExtensions: WindowSdkExtensions): WindowSdkExtensions =
+        windowSdkExtensions
+}
diff --git a/window/window/src/main/java/androidx/window/area/WindowAreaController.kt b/window/window/src/main/java/androidx/window/area/WindowAreaController.kt
index ae2500c..d671726 100644
--- a/window/window/src/main/java/androidx/window/area/WindowAreaController.kt
+++ b/window/window/src/main/java/androidx/window/area/WindowAreaController.kt
@@ -21,6 +21,7 @@
 import android.os.Build
 import android.util.Log
 import androidx.annotation.RestrictTo
+import androidx.window.WindowSdkExtensions
 import androidx.window.area.WindowAreaInfo.Type.Companion.TYPE_REAR_FACING
 import androidx.window.area.utils.DeviceUtils
 import androidx.window.core.BuildConfig
@@ -41,6 +42,9 @@
     /**
      * [Flow] of the list of current [WindowAreaInfo]s that are currently available to be interacted
      * with.
+     *
+     * If [WindowSdkExtensions.extensionVersion] is less than 2,  the flow will return
+     * empty [WindowAreaInfo] list flow.
      */
     val windowAreaInfos: Flow<List<WindowAreaInfo>>
 
diff --git a/window/window/src/main/java/androidx/window/core/ExtensionsUtil.kt b/window/window/src/main/java/androidx/window/core/ExtensionsUtil.kt
index d12062c..ec92f1e 100644
--- a/window/window/src/main/java/androidx/window/core/ExtensionsUtil.kt
+++ b/window/window/src/main/java/androidx/window/core/ExtensionsUtil.kt
@@ -17,20 +17,19 @@
 package androidx.window.core
 
 import android.util.Log
-import androidx.annotation.VisibleForTesting
+import androidx.annotation.IntRange
 import androidx.window.core.VerificationMode.LOG
 import androidx.window.extensions.WindowExtensionsProvider
 
 internal object ExtensionsUtil {
 
     private val TAG = ExtensionsUtil::class.simpleName
-    private var overrideVendorApiLevel: Int? = null
 
+    @get:IntRange(from = 0)
     val safeVendorApiLevel: Int
         get() {
             return try {
-                overrideVendorApiLevel
-                    ?: WindowExtensionsProvider.getWindowExtensions().vendorApiLevel
+                WindowExtensionsProvider.getWindowExtensions().vendorApiLevel
             } catch (e: NoClassDefFoundError) {
                 if (BuildConfig.verificationMode == LOG) {
                     Log.d(TAG, "Embedding extension version not found")
@@ -43,14 +42,4 @@
                 0
             }
         }
-
-    @VisibleForTesting
-    internal fun setOverrideVendorApiLevel(apiLevel: Int) {
-        overrideVendorApiLevel = apiLevel
-    }
-
-    @VisibleForTesting
-    internal fun resetOverrideVendorApiLevel() {
-        overrideVendorApiLevel = null
-    }
 }
diff --git a/window/window/src/main/java/androidx/window/embedding/ActivityEmbeddingController.kt b/window/window/src/main/java/androidx/window/embedding/ActivityEmbeddingController.kt
index 8adffae..bbbd045 100644
--- a/window/window/src/main/java/androidx/window/embedding/ActivityEmbeddingController.kt
+++ b/window/window/src/main/java/androidx/window/embedding/ActivityEmbeddingController.kt
@@ -20,9 +20,13 @@
 import android.app.ActivityOptions
 import android.content.Context
 import android.os.IBinder
+import androidx.window.RequiresWindowSdkExtension
+import androidx.window.WindowSdkExtensions
 import androidx.window.core.ExperimentalWindowApi
 
-/** The controller that allows checking the current [Activity] embedding status. */
+/**
+ * The controller that allows checking the current [Activity] embedding status.
+ */
 class ActivityEmbeddingController internal constructor(private val backend: EmbeddingBackend) {
     /**
      * Checks if the [activity] is embedded and its presentation may be customized by the host
@@ -41,7 +45,7 @@
      *
      * @param activity The [Activity] to check.
      * @return the [ActivityStack] that this [activity] is part of, or `null` if there is no such
-     *   [ActivityStack].
+     * [ActivityStack].
      */
     @ExperimentalWindowApi
     fun getActivityStack(activity: Activity): ActivityStack? =
@@ -53,6 +57,7 @@
      * @param options The [android.app.ActivityOptions] to be updated.
      * @param token The token of the [ActivityStack] to be set.
      */
+    @RequiresWindowSdkExtension(3)
     internal fun setLaunchingActivityStack(
         options: ActivityOptions,
         token: IBinder
@@ -73,28 +78,20 @@
      * will be expanded to fill the parent task container. This is useful to expand the primary
      * container as the sample linked below shows.
      *
-     * **Note** that it's caller's responsibility to check whether this API is supported by calling
-     * [isFinishingActivityStacksSupported]. If not, an alternative approach to finishing all
-     * containers above a particular activity can be to launch it again with flag
-     * [android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP].
+     * **Note** that it's caller's responsibility to check whether this API is supported by checking
+     * [WindowSdkExtensions.extensionVersion] is greater than or equal to 3. If not, an alternative
+     * approach to finishing all containers above a particular activity can be to launch it again
+     * with flag [android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP].
      *
      * @param activityStacks The set of [ActivityStack] to be finished.
-     * @throws UnsupportedOperationException if this device doesn't support this API and
-     * [isFinishingActivityStacksSupported] returns `false`.
+     * @throws UnsupportedOperationException if extension version is less than 3.
      * @sample androidx.window.samples.embedding.expandPrimaryContainer
      */
     @ExperimentalWindowApi
-    fun finishActivityStacks(activityStacks: Set<ActivityStack>) =
+    @RequiresWindowSdkExtension(3)
+    fun finishActivityStacks(activityStacks: Set<ActivityStack>) {
         backend.finishActivityStacks(activityStacks)
-
-    /**
-     * Checks whether [finishActivityStacks] is supported.
-     *
-     * @return `true` if [finishActivityStacks] is supported on the device, `false` otherwise.
-     */
-    @ExperimentalWindowApi
-    fun isFinishingActivityStacksSupported(): Boolean =
-        backend.isFinishActivityStacksSupported()
+    }
 
     companion object {
         /**
diff --git a/window/window/src/main/java/androidx/window/embedding/ActivityEmbeddingOptions.kt b/window/window/src/main/java/androidx/window/embedding/ActivityEmbeddingOptions.kt
index 190ffa3..8f5b66b 100644
--- a/window/window/src/main/java/androidx/window/embedding/ActivityEmbeddingOptions.kt
+++ b/window/window/src/main/java/androidx/window/embedding/ActivityEmbeddingOptions.kt
@@ -20,34 +20,29 @@
 import android.app.Activity
 import android.app.ActivityOptions
 import android.content.Context
+import androidx.window.RequiresWindowSdkExtension
+import androidx.window.WindowSdkExtensions
 import androidx.window.core.ExperimentalWindowApi
-import androidx.window.core.ExtensionsUtil
-import androidx.window.extensions.WindowExtensions
 
 /**
  * Sets the launching [ActivityStack] to the given [android.app.ActivityOptions].
  *
  * If the device doesn't support setting launching, [UnsupportedOperationException] will be thrown.
- * @see isSetLaunchingActivityStackSupported
  *
  * @param context The [android.content.Context] that is going to be used for launching
  * activity with this [android.app.ActivityOptions], which is usually be the [android.app.Activity]
  * of the app that hosts the task.
  * @param activityStack The target [ActivityStack] for launching.
- * @throws UnsupportedOperationException if this device doesn't support this API.
+ * @throws UnsupportedOperationException if [WindowSdkExtensions.extensionVersion] is less than 3.
  */
 @ExperimentalWindowApi
+@RequiresWindowSdkExtension(3)
 fun ActivityOptions.setLaunchingActivityStack(
     context: Context,
     activityStack: ActivityStack
 ): ActivityOptions = let {
-    if (!isSetLaunchingActivityStackSupported()) {
-        throw UnsupportedOperationException("#setLaunchingActivityStack is not " +
-            "supported on the device.")
-    } else {
-        ActivityEmbeddingController.getInstance(context)
-            .setLaunchingActivityStack(this, activityStack.token)
-    }
+    ActivityEmbeddingController.getInstance(context)
+        .setLaunchingActivityStack(this, activityStack.token)
 }
 
 /**
@@ -57,13 +52,12 @@
  *
  * If the device doesn't support setting launching or no available [ActivityStack]
  * can be found from the given [activity], [UnsupportedOperationException] will be thrown.
- * @see isSetLaunchingActivityStackSupported
  *
  * @param activity The existing [android.app.Activity] on the target [ActivityStack].
- * @throws UnsupportedOperationException if this device doesn't support this API or no
- * available [ActivityStack] can be found.
+ * @throws UnsupportedOperationException if [WindowSdkExtensions.extensionVersion] is less than 3.
  */
 @ExperimentalWindowApi
+@RequiresWindowSdkExtension(3)
 fun ActivityOptions.setLaunchingActivityStack(activity: Activity): ActivityOptions {
     val activityStack =
         ActivityEmbeddingController.getInstance(activity).getActivityStack(activity)
@@ -74,12 +68,3 @@
             "The given activity may not be embedded.")
     }
 }
-
-/**
- * Return `true` if the [setLaunchingActivityStack] APIs is supported and can be used
- * to set the launching [ActivityStack]. Otherwise, return `false`.
- */
-@ExperimentalWindowApi
-fun ActivityOptions.isSetLaunchingActivityStackSupported(): Boolean {
-    return ExtensionsUtil.safeVendorApiLevel >= WindowExtensions.VENDOR_API_LEVEL_3
-}
diff --git a/window/window/src/main/java/androidx/window/embedding/EmbeddingAdapter.kt b/window/window/src/main/java/androidx/window/embedding/EmbeddingAdapter.kt
index ce56396..2462f83 100644
--- a/window/window/src/main/java/androidx/window/embedding/EmbeddingAdapter.kt
+++ b/window/window/src/main/java/androidx/window/embedding/EmbeddingAdapter.kt
@@ -24,7 +24,7 @@
 import android.util.LayoutDirection
 import android.util.Pair as AndroidPair
 import android.view.WindowMetrics
-import androidx.window.core.ExtensionsUtil
+import androidx.window.WindowSdkExtensions
 import androidx.window.core.PredicateAdapter
 import androidx.window.embedding.SplitAttributes.LayoutDirection.Companion.BOTTOM_TO_TOP
 import androidx.window.embedding.SplitAttributes.LayoutDirection.Companion.LEFT_TO_RIGHT
@@ -36,7 +36,6 @@
 import androidx.window.embedding.SplitAttributes.SplitType.Companion.SPLIT_TYPE_EXPAND
 import androidx.window.embedding.SplitAttributes.SplitType.Companion.SPLIT_TYPE_HINGE
 import androidx.window.embedding.SplitAttributes.SplitType.Companion.ratio
-import androidx.window.extensions.WindowExtensions
 import androidx.window.extensions.core.util.function.Function
 import androidx.window.extensions.core.util.function.Predicate
 import androidx.window.extensions.embedding.ActivityRule as OEMActivityRule
@@ -63,7 +62,8 @@
 internal class EmbeddingAdapter(
     private val predicateAdapter: PredicateAdapter
 ) {
-    private val vendorApiLevel = ExtensionsUtil.safeVendorApiLevel
+    private val vendorApiLevel
+        get() = WindowSdkExtensions.getInstance().extensionVersion
     private val api1Impl = VendorApiLevel1Impl(predicateAdapter)
     private val api2Impl = VendorApiLevel2Impl()
 
@@ -73,8 +73,8 @@
 
     private fun translate(splitInfo: OEMSplitInfo): SplitInfo {
         return when (vendorApiLevel) {
-            WindowExtensions.VENDOR_API_LEVEL_1 -> api1Impl.translateCompat(splitInfo)
-            WindowExtensions.VENDOR_API_LEVEL_2 -> api2Impl.translateCompat(splitInfo)
+            1 -> api1Impl.translateCompat(splitInfo)
+            2 -> api2Impl.translateCompat(splitInfo)
             else -> {
                 val primaryActivityStack = splitInfo.primaryActivityStack
                 val secondaryActivityStack = splitInfo.secondaryActivityStack
@@ -152,7 +152,7 @@
         rule: SplitPairRule,
         predicateClass: Class<*>
     ): OEMSplitPairRule {
-        if (vendorApiLevel < WindowExtensions.VENDOR_API_LEVEL_2) {
+        if (vendorApiLevel < 2) {
             return api1Impl.translateSplitPairRuleCompat(context, rule, predicateClass)
         } else {
             val activitiesPairPredicate =
@@ -194,7 +194,7 @@
     }
 
     fun translateSplitAttributes(splitAttributes: SplitAttributes): OEMSplitAttributes {
-        require(vendorApiLevel >= WindowExtensions.VENDOR_API_LEVEL_2)
+        require(vendorApiLevel >= 2)
         // To workaround the "unused" error in ktlint. It is necessary to translate SplitAttributes
         // from WM Jetpack version to WM extension version.
         return androidx.window.extensions.embedding.SplitAttributes.Builder()
@@ -215,7 +215,7 @@
     }
 
     private fun translateSplitType(splitType: SplitType): OEMSplitType {
-        require(vendorApiLevel >= WindowExtensions.VENDOR_API_LEVEL_2)
+        require(vendorApiLevel >= 2)
         return when (splitType) {
             SPLIT_TYPE_HINGE -> OEMSplitType.HingeSplitType(
                 translateSplitType(SPLIT_TYPE_EQUAL)
@@ -238,7 +238,7 @@
         rule: SplitPlaceholderRule,
         predicateClass: Class<*>
     ): OEMSplitPlaceholderRule {
-        if (vendorApiLevel < WindowExtensions.VENDOR_API_LEVEL_2) {
+        if (vendorApiLevel < 2) {
             return api1Impl.translateSplitPlaceholderRuleCompat(
                 context,
                 rule,
@@ -285,7 +285,7 @@
         rule: ActivityRule,
         predicateClass: Class<*>
     ): OEMActivityRule {
-        if (vendorApiLevel < WindowExtensions.VENDOR_API_LEVEL_2) {
+        if (vendorApiLevel < 2) {
             return api1Impl.translateActivityRuleCompat(rule, predicateClass)
         } else {
             val activityPredicate = Predicate<Activity> { activity ->
@@ -317,6 +317,7 @@
         }.toSet()
     }
 
+    /** Provides backward compatibility for Window extensions with API level 2 */
     private inner class VendorApiLevel2Impl {
         fun translateCompat(splitInfo: OEMSplitInfo): SplitInfo {
             val primaryActivityStack = splitInfo.primaryActivityStack
@@ -342,15 +343,13 @@
     }
 
     /**
-     * Provides backward compatibility for Window extensions with
-     * [WindowExtensions.VENDOR_API_LEVEL_1]
-     * @see WindowExtensions.getVendorApiLevel
+     * Provides backward compatibility for [WindowSdkExtensions] version 1
      */
     // Suppress deprecation because this object is to provide backward compatibility.
     @Suppress("DEPRECATION")
     private inner class VendorApiLevel1Impl(val predicateAdapter: PredicateAdapter) {
         /**
-         * Obtains [SplitAttributes] from [OEMSplitInfo] with [WindowExtensions.VENDOR_API_LEVEL_1]
+         * Obtains [SplitAttributes] from [OEMSplitInfo] with [WindowSdkExtensions] version 1
          */
         fun getSplitAttributesCompat(splitInfo: OEMSplitInfo): SplitAttributes =
             SplitAttributes.Builder()
@@ -472,9 +471,8 @@
             }
 
         /**
-         * Returns `true` if `attrs` is compatible with [WindowExtensions.VENDOR_API_LEVEL_1] and
-         * doesn't use the new features introduced in [WindowExtensions.VENDOR_API_LEVEL_2] or
-         * higher.
+         * Returns `true` if `attrs` is compatible with vendor API level 1 and
+         * doesn't use the new features introduced in vendor API level 2 or higher.
          */
         private fun isSplitAttributesSupported(attrs: SplitAttributes) =
             attrs.splitType.value in 0.0..1.0 && attrs.splitType.value != 1.0f &&
@@ -519,12 +517,12 @@
     internal companion object {
         /**
          * The default token of [SplitInfo], which provides compatibility for device prior to
-         * [WindowExtensions.VENDOR_API_LEVEL_3]
+         * vendor API level 3
          */
         val INVALID_SPLIT_INFO_TOKEN = Binder()
         /**
          * The default token of [ActivityStack], which provides compatibility for device prior to
-         * [WindowExtensions.VENDOR_API_LEVEL_3]
+         * vendor API level 3
          */
         val INVALID_ACTIVITY_STACK_TOKEN = Binder()
     }
diff --git a/window/window/src/main/java/androidx/window/embedding/EmbeddingBackend.kt b/window/window/src/main/java/androidx/window/embedding/EmbeddingBackend.kt
index 22b6333..c1b09d0 100644
--- a/window/window/src/main/java/androidx/window/embedding/EmbeddingBackend.kt
+++ b/window/window/src/main/java/androidx/window/embedding/EmbeddingBackend.kt
@@ -22,6 +22,7 @@
 import android.os.IBinder
 import androidx.annotation.RestrictTo
 import androidx.core.util.Consumer
+import androidx.window.RequiresWindowSdkExtension
 import java.util.concurrent.Executor
 
 /**
@@ -50,28 +51,28 @@
 
     fun isActivityEmbedded(activity: Activity): Boolean
 
+    @RequiresWindowSdkExtension(2)
     fun setSplitAttributesCalculator(
         calculator: (SplitAttributesCalculatorParams) -> SplitAttributes
     )
 
+    @RequiresWindowSdkExtension(2)
     fun clearSplitAttributesCalculator()
 
-    fun isSplitAttributesCalculatorSupported(): Boolean
-
     fun getActivityStack(activity: Activity): ActivityStack?
 
+    @RequiresWindowSdkExtension(3)
     fun setLaunchingActivityStack(options: ActivityOptions, token: IBinder): ActivityOptions
 
+    @RequiresWindowSdkExtension(3)
     fun finishActivityStacks(activityStacks: Set<ActivityStack>)
 
-    fun isFinishActivityStacksSupported(): Boolean
-
+    @RequiresWindowSdkExtension(3)
     fun invalidateTopVisibleSplitAttributes()
 
+    @RequiresWindowSdkExtension(3)
     fun updateSplitAttributes(splitInfo: SplitInfo, splitAttributes: SplitAttributes)
 
-    fun areSplitAttributesUpdatesSupported(): Boolean
-
     companion object {
 
         private var decorator: (EmbeddingBackend) -> EmbeddingBackend =
diff --git a/window/window/src/main/java/androidx/window/embedding/EmbeddingCompat.kt b/window/window/src/main/java/androidx/window/embedding/EmbeddingCompat.kt
index 2c543f3..a4b7166 100644
--- a/window/window/src/main/java/androidx/window/embedding/EmbeddingCompat.kt
+++ b/window/window/src/main/java/androidx/window/embedding/EmbeddingCompat.kt
@@ -21,6 +21,8 @@
 import android.content.Context
 import android.os.IBinder
 import android.util.Log
+import androidx.window.RequiresWindowSdkExtension
+import androidx.window.WindowSdkExtensions
 import androidx.window.core.BuildConfig
 import androidx.window.core.ConsumerAdapter
 import androidx.window.core.ExtensionsUtil
@@ -28,7 +30,6 @@
 import androidx.window.embedding.EmbeddingInterfaceCompat.EmbeddingCallbackInterface
 import androidx.window.embedding.SplitController.SplitSupportStatus.Companion.SPLIT_AVAILABLE
 import androidx.window.extensions.WindowExtensions.VENDOR_API_LEVEL_2
-import androidx.window.extensions.WindowExtensions.VENDOR_API_LEVEL_3
 import androidx.window.extensions.WindowExtensionsProvider
 import androidx.window.extensions.core.util.function.Consumer
 import androidx.window.extensions.embedding.ActivityEmbeddingComponent
@@ -39,7 +40,7 @@
  * Adapter implementation for different historical versions of activity embedding OEM interface in
  * [ActivityEmbeddingComponent]. Only supports the single current version in this implementation.
  */
-internal class EmbeddingCompat constructor(
+internal class EmbeddingCompat(
     private val embeddingExtension: ActivityEmbeddingComponent,
     private val adapter: EmbeddingAdapter,
     private val consumerAdapter: ConsumerAdapter,
@@ -92,70 +93,59 @@
         return embeddingExtension.isActivityEmbedded(activity)
     }
 
+    @RequiresWindowSdkExtension(2)
     override fun setSplitAttributesCalculator(
         calculator: (SplitAttributesCalculatorParams) -> SplitAttributes
     ) {
-        if (!isSplitAttributesCalculatorSupported()) {
-            throw UnsupportedOperationException("#setSplitAttributesCalculator is not supported " +
-                "on the device.")
-        }
+        WindowSdkExtensions.getInstance().requireExtensionVersion(2)
+
         embeddingExtension.setSplitAttributesCalculator(
             adapter.translateSplitAttributesCalculator(calculator)
         )
     }
 
+    @RequiresWindowSdkExtension(2)
     override fun clearSplitAttributesCalculator() {
-        if (!isSplitAttributesCalculatorSupported()) {
-            throw UnsupportedOperationException("#clearSplitAttributesCalculator is not " +
-                "supported on the device.")
-        }
+        WindowSdkExtensions.getInstance().requireExtensionVersion(2)
+
         embeddingExtension.clearSplitAttributesCalculator()
     }
 
-    override fun isSplitAttributesCalculatorSupported(): Boolean =
-        ExtensionsUtil.safeVendorApiLevel >= VENDOR_API_LEVEL_2
-
+    @RequiresWindowSdkExtension(3)
     override fun finishActivityStacks(activityStacks: Set<ActivityStack>) {
-        if (!isFinishActivityStacksSupported()) {
-            throw UnsupportedOperationException("#finishActivityStacks is not " +
-                "supported on the device.")
-        }
+        WindowSdkExtensions.getInstance().requireExtensionVersion(3)
+
         val stackTokens = activityStacks.mapTo(mutableSetOf()) { it.token }
         embeddingExtension.finishActivityStacks(stackTokens)
     }
 
-    override fun isFinishActivityStacksSupported(): Boolean =
-        ExtensionsUtil.safeVendorApiLevel >= VENDOR_API_LEVEL_3
-
+    @RequiresWindowSdkExtension(3)
     override fun invalidateTopVisibleSplitAttributes() {
-        if (!areSplitAttributesUpdatesSupported()) {
-            throw UnsupportedOperationException("#invalidateTopVisibleSplitAttributes is not " +
-                "supported on the device.")
-        }
+        WindowSdkExtensions.getInstance().requireExtensionVersion(3)
+
         embeddingExtension.invalidateTopVisibleSplitAttributes()
     }
 
+    @RequiresWindowSdkExtension(3)
     override fun updateSplitAttributes(
         splitInfo: SplitInfo,
         splitAttributes: SplitAttributes
     ) {
-        if (!areSplitAttributesUpdatesSupported()) {
-            throw UnsupportedOperationException("#updateSplitAttributes is not supported on the " +
-                "device.")
-        }
+        WindowSdkExtensions.getInstance().requireExtensionVersion(3)
+
         embeddingExtension.updateSplitAttributes(
             splitInfo.token,
             adapter.translateSplitAttributes(splitAttributes)
         )
     }
 
-    override fun areSplitAttributesUpdatesSupported(): Boolean =
-        ExtensionsUtil.safeVendorApiLevel >= VENDOR_API_LEVEL_3
-
+    @RequiresWindowSdkExtension(3)
     override fun setLaunchingActivityStack(
         options: ActivityOptions,
         token: IBinder
     ): ActivityOptions {
+        WindowSdkExtensions.getInstance().requireExtensionVersion(3)
+
         return embeddingExtension.setLaunchingActivityStack(options, token)
     }
 
diff --git a/window/window/src/main/java/androidx/window/embedding/EmbeddingInterfaceCompat.kt b/window/window/src/main/java/androidx/window/embedding/EmbeddingInterfaceCompat.kt
index ccfba1d..e176a02 100644
--- a/window/window/src/main/java/androidx/window/embedding/EmbeddingInterfaceCompat.kt
+++ b/window/window/src/main/java/androidx/window/embedding/EmbeddingInterfaceCompat.kt
@@ -19,6 +19,7 @@
 import android.app.Activity
 import android.app.ActivityOptions
 import android.os.IBinder
+import androidx.window.RequiresWindowSdkExtension
 import androidx.window.extensions.embedding.ActivityEmbeddingComponent
 
 /**
@@ -37,23 +38,23 @@
 
     fun isActivityEmbedded(activity: Activity): Boolean
 
+    @RequiresWindowSdkExtension(2)
     fun setSplitAttributesCalculator(
         calculator: (SplitAttributesCalculatorParams) -> SplitAttributes
     )
 
+    @RequiresWindowSdkExtension(2)
     fun clearSplitAttributesCalculator()
 
-    fun isSplitAttributesCalculatorSupported(): Boolean
-
+    @RequiresWindowSdkExtension(3)
     fun setLaunchingActivityStack(options: ActivityOptions, token: IBinder): ActivityOptions
 
+    @RequiresWindowSdkExtension(3)
     fun finishActivityStacks(activityStacks: Set<ActivityStack>)
 
-    fun isFinishActivityStacksSupported(): Boolean
-
+    @RequiresWindowSdkExtension(3)
     fun invalidateTopVisibleSplitAttributes()
 
+    @RequiresWindowSdkExtension(3)
     fun updateSplitAttributes(splitInfo: SplitInfo, splitAttributes: SplitAttributes)
-
-    fun areSplitAttributesUpdatesSupported(): Boolean
 }
diff --git a/window/window/src/main/java/androidx/window/embedding/ExtensionEmbeddingBackend.kt b/window/window/src/main/java/androidx/window/embedding/ExtensionEmbeddingBackend.kt
index c7f4c3b..a53a98c 100644
--- a/window/window/src/main/java/androidx/window/embedding/ExtensionEmbeddingBackend.kt
+++ b/window/window/src/main/java/androidx/window/embedding/ExtensionEmbeddingBackend.kt
@@ -29,6 +29,7 @@
 import androidx.annotation.VisibleForTesting
 import androidx.collection.ArraySet
 import androidx.core.util.Consumer
+import androidx.window.RequiresWindowSdkExtension
 import androidx.window.WindowProperties
 import androidx.window.core.BuildConfig
 import androidx.window.core.ConsumerAdapter
@@ -336,6 +337,7 @@
         return embeddingExtension?.isActivityEmbedded(activity) ?: false
     }
 
+    @RequiresWindowSdkExtension(2)
     override fun setSplitAttributesCalculator(
         calculator: (SplitAttributesCalculatorParams) -> SplitAttributes
     ) {
@@ -344,15 +346,13 @@
         }
     }
 
+    @RequiresWindowSdkExtension(2)
     override fun clearSplitAttributesCalculator() {
         globalLock.withLock {
             embeddingExtension?.clearSplitAttributesCalculator()
         }
     }
 
-    override fun isSplitAttributesCalculatorSupported(): Boolean =
-        embeddingExtension?.isSplitAttributesCalculatorSupported() ?: false
-
     override fun getActivityStack(activity: Activity): ActivityStack? {
         globalLock.withLock {
             val lastInfo: List<SplitInfo> = splitInfoEmbeddingCallback.lastInfo ?: return null
@@ -371,22 +371,23 @@
         }
     }
 
+    @RequiresWindowSdkExtension(3)
     override fun setLaunchingActivityStack(
         options: ActivityOptions,
         token: IBinder
     ): ActivityOptions = embeddingExtension?.setLaunchingActivityStack(options, token) ?: options
 
+    @RequiresWindowSdkExtension(3)
     override fun finishActivityStacks(activityStacks: Set<ActivityStack>) {
         embeddingExtension?.finishActivityStacks(activityStacks)
     }
 
-    override fun isFinishActivityStacksSupported(): Boolean =
-        embeddingExtension?.isFinishActivityStacksSupported() ?: false
-
+    @RequiresWindowSdkExtension(3)
     override fun invalidateTopVisibleSplitAttributes() {
         embeddingExtension?.invalidateTopVisibleSplitAttributes()
     }
 
+    @RequiresWindowSdkExtension(3)
     override fun updateSplitAttributes(
         splitInfo: SplitInfo,
         splitAttributes: SplitAttributes
@@ -394,8 +395,6 @@
         embeddingExtension?.updateSplitAttributes(splitInfo, splitAttributes)
     }
 
-    override fun areSplitAttributesUpdatesSupported(): Boolean =
-        embeddingExtension?.areSplitAttributesUpdatesSupported() ?: false
     @RequiresApi(31)
     private object Api31Impl {
         @DoNotInline
diff --git a/window/window/src/main/java/androidx/window/embedding/RuleController.kt b/window/window/src/main/java/androidx/window/embedding/RuleController.kt
index 192f3ec..8943726 100644
--- a/window/window/src/main/java/androidx/window/embedding/RuleController.kt
+++ b/window/window/src/main/java/androidx/window/embedding/RuleController.kt
@@ -27,6 +27,7 @@
  * - [setRules]
  * - [parseRules]
  * - [clearRules]
+ * - [getRules]
  *
  * **Note** that this class is recommended to be configured in [androidx.startup.Initializer] or
  * [android.app.Application.onCreate], so that the rules are applied early in the application
diff --git a/window/window/src/main/java/androidx/window/embedding/SplitAttributes.kt b/window/window/src/main/java/androidx/window/embedding/SplitAttributes.kt
index 3e22b1a..ac627fc 100644
--- a/window/window/src/main/java/androidx/window/embedding/SplitAttributes.kt
+++ b/window/window/src/main/java/androidx/window/embedding/SplitAttributes.kt
@@ -21,6 +21,7 @@
 import androidx.annotation.IntRange
 import androidx.annotation.RestrictTo
 import androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP
+import androidx.window.WindowSdkExtensions
 import androidx.window.core.SpecificationComputer.Companion.startSpecification
 import androidx.window.core.VerificationMode
 import androidx.window.embedding.SplitAttributes.LayoutDirection.Companion.LOCALE
@@ -307,7 +308,8 @@
              * <img width="70%" height="70%" src="/images/guide/topics/large-screens/activity-embedding/reference-docs/a_to_a_b_ttb.png" alt="Activity A starts activity B to the bottom."/>
              *
              * If the horizontal layout direction is not supported on the
-             * device, layout direction falls back to `LOCALE`.
+             * device that [WindowSdkExtensions.extensionVersion] is less than 2, layout direction
+             * falls back to `LOCALE`.
              *
              * See also [layoutDirection].
              */
@@ -323,7 +325,8 @@
              * <img width="70%" height="70%" src="/images/guide/topics/large-screens/activity-embedding/reference-docs/a_to_a_b_btt.png" alt="Activity A starts activity B to the top."/>
              *
              * If the horizontal layout direction is not supported on the
-             * device, layout direction falls back to `LOCALE`.
+             * device that [WindowSdkExtensions.extensionVersion] is less than 2, layout direction
+             * falls back to `LOCALE`.
              *
              * See also [layoutDirection].
              */
diff --git a/window/window/src/main/java/androidx/window/embedding/SplitController.kt b/window/window/src/main/java/androidx/window/embedding/SplitController.kt
index e478ff7..063bc0c 100644
--- a/window/window/src/main/java/androidx/window/embedding/SplitController.kt
+++ b/window/window/src/main/java/androidx/window/embedding/SplitController.kt
@@ -19,7 +19,9 @@
 import android.app.Activity
 import android.content.Context
 import androidx.core.util.Consumer
+import androidx.window.RequiresWindowSdkExtension
 import androidx.window.WindowProperties
+import androidx.window.WindowSdkExtensions
 import androidx.window.core.ExperimentalWindowApi
 import androidx.window.layout.WindowMetrics
 import kotlinx.coroutines.channels.awaitClose
@@ -27,17 +29,17 @@
 import kotlinx.coroutines.flow.callbackFlow
 
 /**
-* The controller class that gets information about the currently active activity
-* splits and provides interaction points to customize the splits and form new
-* splits.
-*
-* A split is a pair of containers that host activities in the same or different
-* processes, combined under the same parent window of the hosting task.
-*
-* A pair of activities can be put into a split by providing a static or runtime
-* split rule and then launching the activities in the same task using
-* [Activity.startActivity()][android.app.Activity.startActivity].
-*/
+ * The controller class that gets information about the currently active activity
+ * splits and provides interaction points to customize the splits and form new
+ * splits.
+ *
+ * A split is a pair of containers that host activities in the same or different
+ * processes, combined under the same parent window of the hosting task.
+ *
+ * A pair of activities can be put into a split by providing a static or runtime
+ * split rule and then launching the activities in the same task using
+ * [Activity.startActivity()][android.app.Activity.startActivity].
+ */
 class SplitController internal constructor(private val embeddingBackend: EmbeddingBackend) {
 
     /**
@@ -86,8 +88,8 @@
     /**
      * Sets or replaces the previously registered [SplitAttributes] calculator.
      *
-     * **Note** that it's callers' responsibility to check if this API is supported by calling
-     * [isSplitAttributesCalculatorSupported] before using the this API. It is suggested to always
+     * **Note** that it's callers' responsibility to check if this API is supported by checking
+     * [WindowSdkExtensions.extensionVersion] before using the this API. It is suggested to always
      * set meaningful [SplitRule.defaultSplitAttributes] in case this API is not supported on some
      * devices.
      *
@@ -124,9 +126,10 @@
      * @sample androidx.window.samples.embedding.splitAttributesCalculatorSample
      * @param calculator the function to calculate [SplitAttributes] based on the
      * [SplitAttributesCalculatorParams]. It will replace the previously set if it exists.
-     * @throws UnsupportedOperationException if [isSplitAttributesCalculatorSupported] reports
-     * `false`
+     * @throws UnsupportedOperationException if [WindowSdkExtensions.extensionVersion]
+     *                                       is less than 2.
      */
+    @RequiresWindowSdkExtension(2)
     fun setSplitAttributesCalculator(
         calculator: (SplitAttributesCalculatorParams) -> SplitAttributes
     ) {
@@ -135,19 +138,17 @@
 
     /**
      * Clears the callback previously set by [setSplitAttributesCalculator].
-     * The caller **must** make sure [isSplitAttributesCalculatorSupported] before invoking.
+     * The caller **must** make sure if [WindowSdkExtensions.extensionVersion] is greater than
+     * or equal to 2.
      *
-     * @throws UnsupportedOperationException if [isSplitAttributesCalculatorSupported] reports
-     * `false`
+     * @throws UnsupportedOperationException if [WindowSdkExtensions.extensionVersion]
+     *                                       is less than 2.
      */
+    @RequiresWindowSdkExtension(2)
     fun clearSplitAttributesCalculator() {
         embeddingBackend.clearSplitAttributesCalculator()
     }
 
-    /** Returns whether [setSplitAttributesCalculator] is supported or not. */
-    fun isSplitAttributesCalculatorSupported(): Boolean =
-        embeddingBackend.isSplitAttributesCalculatorSupported()
-
     /**
      * Triggers a [SplitAttributes] update callback for the current topmost and visible split layout
      * if there is one. This method can be used when a change to the split presentation originates
@@ -160,23 +161,14 @@
      *
      * The call will be ignored if there is no visible split.
      *
-     * @throws UnsupportedOperationException if the device doesn't support this API.
+     * @throws UnsupportedOperationException if [WindowSdkExtensions.extensionVersion]
+     *                                       is less than 3.
      */
     @ExperimentalWindowApi
-    fun invalidateTopVisibleSplitAttributes() =
+    @RequiresWindowSdkExtension(3)
+    fun invalidateTopVisibleSplitAttributes() {
         embeddingBackend.invalidateTopVisibleSplitAttributes()
-
-    /**
-     * Checks whether [invalidateTopVisibleSplitAttributes] is supported on the device.
-     *
-     * Invoking these APIs if the feature is not supported would trigger an
-     * [UnsupportedOperationException].
-     * @return `true` if the runtime APIs to update [SplitAttributes] are supported and can be
-     * called safely, `false` otherwise.
-     */
-    @ExperimentalWindowApi
-    fun isInvalidatingTopVisibleSplitAttributesSupported(): Boolean =
-        embeddingBackend.areSplitAttributesUpdatesSupported()
+    }
 
     /**
      * Updates the [SplitAttributes] of a split pair. This is an alternative to using
@@ -198,23 +190,14 @@
      *
      * @param splitInfo the split pair to update
      * @param splitAttributes the [SplitAttributes] to be applied
-     * @throws UnsupportedOperationException if this device doesn't support this API
+     * @throws UnsupportedOperationException if [WindowSdkExtensions.extensionVersion]
+     *                                       is less than 3.
      */
     @ExperimentalWindowApi
-    fun updateSplitAttributes(splitInfo: SplitInfo, splitAttributes: SplitAttributes) =
+    @RequiresWindowSdkExtension(3)
+    fun updateSplitAttributes(splitInfo: SplitInfo, splitAttributes: SplitAttributes) {
         embeddingBackend.updateSplitAttributes(splitInfo, splitAttributes)
-
-    /**
-     * Checks whether [updateSplitAttributes] is supported on the device.
-     *
-     * Invoking these APIs if the feature is not supported would trigger an
-     * [UnsupportedOperationException].
-     * @return `true` if the runtime APIs to update [SplitAttributes] are supported and can be
-     * called safely, `false` otherwise.
-     */
-    @ExperimentalWindowApi
-    fun isUpdatingSplitAttributesSupported(): Boolean =
-        embeddingBackend.areSplitAttributesUpdatesSupported()
+    }
 
     /**
      * A class to determine if activity splits with Activity Embedding are currently available.
diff --git a/window/window/src/main/java/androidx/window/layout/WindowInfoTracker.kt b/window/window/src/main/java/androidx/window/layout/WindowInfoTracker.kt
index 60eb71e..06ca64f 100644
--- a/window/window/src/main/java/androidx/window/layout/WindowInfoTracker.kt
+++ b/window/window/src/main/java/androidx/window/layout/WindowInfoTracker.kt
@@ -23,6 +23,7 @@
 import androidx.annotation.RestrictTo
 import androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP
 import androidx.annotation.UiContext
+import androidx.window.WindowSdkExtensions
 import androidx.window.core.ConsumerAdapter
 import androidx.window.layout.adapter.WindowBackend
 import androidx.window.layout.adapter.extensions.ExtensionWindowBackend
@@ -53,6 +54,9 @@
      * Obtaining a [WindowInfoTracker] through [WindowInfoTracker.getOrCreate] guarantees having a
      * default implementation for this method.
      *
+     * If the passed [context] is not an [Activity] and [WindowSdkExtensions.extensionVersion]
+     * is less than 2, the flow will return empty [WindowLayoutInfo] list flow.
+     *
      * @param context a [UiContext] such as an [Activity], an [InputMethodService], or an instance
      * created via [Context.createWindowContext] that listens to configuration changes.
      * @see WindowLayoutInfo
diff --git a/window/window/src/test/java/androidx/window/StubWindowSdkExtensions.kt b/window/window/src/test/java/androidx/window/StubWindowSdkExtensions.kt
new file mode 100644
index 0000000..3ffe46f
--- /dev/null
+++ b/window/window/src/test/java/androidx/window/StubWindowSdkExtensions.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2023 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.window
+
+import androidx.annotation.IntRange
+
+internal class StubWindowSdkExtensions : WindowSdkExtensions() {
+    override val extensionVersion: Int
+        get() = overrideVersion
+
+    private var overrideVersion: Int = 0
+
+    internal fun overrideExtensionVersion(@IntRange(from = 0) version: Int) {
+        overrideVersion = version
+    }
+}
diff --git a/window/window/src/test/java/androidx/window/WindowSdkExtensionsRule.kt b/window/window/src/test/java/androidx/window/WindowSdkExtensionsRule.kt
new file mode 100644
index 0000000..a2826e2
--- /dev/null
+++ b/window/window/src/test/java/androidx/window/WindowSdkExtensionsRule.kt
@@ -0,0 +1,67 @@
+/**
+*
+* Copyright 2023 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.window
+
+import androidx.annotation.IntRange
+import org.junit.rules.TestRule
+import org.junit.runner.Description
+import org.junit.runners.model.Statement
+
+/**
+ * Test rule for overriding [WindowSdkExtensions] properties.
+ *
+ * This should mainly be used for validating the behavior with a simplified version of
+ * [WindowSdkExtensions] in unit tests.
+ * For on-device Android tests, it's highly suggested to respect
+ * the device's [WindowSdkExtensions.extensionVersion]. Overriding the real device's is error-prone,
+ * and may lead to unexpected behavior.
+ */
+class WindowSdkExtensionsRule : TestRule {
+
+    private val mStubWindowSdkExtensions = StubWindowSdkExtensions()
+
+    override fun apply(
+        @Suppress("InvalidNullabilityOverride") // JUnit missing annotations
+        base: Statement,
+        @Suppress("InvalidNullabilityOverride") // JUnit missing annotations
+        description: Description
+    ): Statement {
+        return object : Statement() {
+            override fun evaluate() {
+                WindowSdkExtensions.overrideDecorator(object : WindowSdkExtensionsDecorator {
+                    override fun decorate(windowSdkExtensions: WindowSdkExtensions):
+                        WindowSdkExtensions = mStubWindowSdkExtensions
+                })
+                try {
+                    base.evaluate()
+                } finally {
+                    WindowSdkExtensions.reset()
+                }
+            }
+        }
+    }
+
+    /**
+     * Overrides [WindowSdkExtensions.extensionVersion] for testing.
+     *
+     * @param version The extension version to override
+     */
+    fun overrideExtensionVersion(@IntRange(from = 0) version: Int) {
+        mStubWindowSdkExtensions.overrideExtensionVersion(version)
+    }
+}
diff --git a/window/window/src/test/java/androidx/window/embedding/ActivityEmbeddingControllerTest.kt b/window/window/src/test/java/androidx/window/embedding/ActivityEmbeddingControllerTest.kt
index c4cf0b5..6d950f6 100644
--- a/window/window/src/test/java/androidx/window/embedding/ActivityEmbeddingControllerTest.kt
+++ b/window/window/src/test/java/androidx/window/embedding/ActivityEmbeddingControllerTest.kt
@@ -19,6 +19,7 @@
 import android.app.Activity
 import android.content.Context
 import android.os.Binder
+import androidx.window.core.ExperimentalWindowApi
 import org.junit.Assert.assertEquals
 import org.junit.Assert.assertFalse
 import org.junit.Assert.assertTrue
@@ -61,7 +62,7 @@
     }
 
     @Test
-    @OptIn(androidx.window.core.ExperimentalWindowApi::class)
+    @OptIn(ExperimentalWindowApi::class)
     fun testGetActivityStack() {
         val activityStack = ActivityStack(listOf(), true, Binder())
         whenever(mockEmbeddingBackend.getActivityStack(mockActivity)).thenReturn(activityStack)
@@ -70,19 +71,7 @@
     }
 
     @Test
-    @OptIn(androidx.window.core.ExperimentalWindowApi::class)
-    fun testIsFinishingActivityStacksSupported() {
-        whenever(mockEmbeddingBackend.isFinishActivityStacksSupported()).thenReturn(true)
-
-        assertTrue(activityEmbeddingController.isFinishingActivityStacksSupported())
-
-        whenever(mockEmbeddingBackend.isFinishActivityStacksSupported()).thenReturn(false)
-
-        assertFalse(activityEmbeddingController.isFinishingActivityStacksSupported())
-    }
-
-    @Test
-    @OptIn(androidx.window.core.ExperimentalWindowApi::class)
+    @OptIn(ExperimentalWindowApi::class)
     fun testFinishActivityStacks() {
         val activityStacks: Set<ActivityStack> = mock()
         activityEmbeddingController.finishActivityStacks(activityStacks)
@@ -91,7 +80,7 @@
     }
 
     @Test
-    @OptIn(androidx.window.core.ExperimentalWindowApi::class)
+    @OptIn(ExperimentalWindowApi::class)
     fun testGetInstance() {
         EmbeddingBackend.overrideDecorator(object : EmbeddingBackendDecorator {
             override fun decorate(embeddingBackend: EmbeddingBackend): EmbeddingBackend =
diff --git a/window/window/src/test/java/androidx/window/embedding/ActivityEmbeddingOptionsTest.kt b/window/window/src/test/java/androidx/window/embedding/ActivityEmbeddingOptionsTest.kt
index d9c2127..aea6821 100644
--- a/window/window/src/test/java/androidx/window/embedding/ActivityEmbeddingOptionsTest.kt
+++ b/window/window/src/test/java/androidx/window/embedding/ActivityEmbeddingOptionsTest.kt
@@ -19,18 +19,12 @@
 import android.app.Activity
 import android.app.ActivityOptions
 import android.content.Context
-import androidx.window.core.ExtensionsUtil
-import androidx.window.extensions.WindowExtensions
+import androidx.window.core.ExperimentalWindowApi
 import org.junit.After
-import org.junit.Assert.assertFalse
-import org.junit.Assert.assertThrows
-import org.junit.Assert.assertTrue
 import org.junit.Before
 import org.junit.Test
-import org.mockito.kotlin.any
 import org.mockito.kotlin.doReturn
 import org.mockito.kotlin.mock
-import org.mockito.kotlin.never
 import org.mockito.kotlin.verify
 import org.mockito.kotlin.whenever
 
@@ -38,9 +32,8 @@
  * The unit tests for activity embedding extension functions to [ActivityOptions]
  *
  * @see [ActivityOptions.setLaunchingActivityStack]
- * @see [ActivityOptions.isSetLaunchingActivityStackSupported]
  */
-@OptIn(androidx.window.core.ExperimentalWindowApi::class)
+@OptIn(ExperimentalWindowApi::class)
 class ActivityEmbeddingOptionsTest {
 
     private lateinit var mockEmbeddingBackend: EmbeddingBackend
@@ -64,15 +57,11 @@
             override fun decorate(embeddingBackend: EmbeddingBackend): EmbeddingBackend =
                 mockEmbeddingBackend
         })
-
-        // ActivityEmbeddingOptions is only supported since level 3
-        ExtensionsUtil.setOverrideVendorApiLevel(WindowExtensions.VENDOR_API_LEVEL_3)
     }
 
     @After
     fun tearDown() {
         EmbeddingBackend.reset()
-        ExtensionsUtil.resetOverrideVendorApiLevel()
     }
 
     @Test
@@ -90,25 +79,4 @@
         verify(mockEmbeddingBackend).setLaunchingActivityStack(
             mockActivityOptions, mockActivityStack.token)
     }
-
-    @Test
-    fun testSetLaunchingActivityStack_unsupportedApiLevel() {
-        ExtensionsUtil.setOverrideVendorApiLevel(WindowExtensions.VENDOR_API_LEVEL_2)
-
-        assertThrows(UnsupportedOperationException::class.java) {
-            mockActivityOptions.setLaunchingActivityStack(mockActivity, mockActivityStack)
-        }
-        verify(mockEmbeddingBackend, never()).setLaunchingActivityStack(any(), any())
-    }
-
-    @Test
-    fun testIsSetLaunchingActivityStackSupported() {
-        ExtensionsUtil.setOverrideVendorApiLevel(WindowExtensions.VENDOR_API_LEVEL_2)
-
-        assertFalse(mockActivityOptions.isSetLaunchingActivityStackSupported())
-
-        ExtensionsUtil.setOverrideVendorApiLevel(WindowExtensions.VENDOR_API_LEVEL_3)
-
-        assertTrue(mockActivityOptions.isSetLaunchingActivityStackSupported())
-    }
 }
diff --git a/window/window/src/test/java/androidx/window/embedding/RequiresWindowSdkExtensionTests.kt b/window/window/src/test/java/androidx/window/embedding/RequiresWindowSdkExtensionTests.kt
new file mode 100644
index 0000000..7b0b830
--- /dev/null
+++ b/window/window/src/test/java/androidx/window/embedding/RequiresWindowSdkExtensionTests.kt
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2023 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.window.embedding
+
+import android.app.ActivityOptions
+import android.content.Context
+import android.os.Binder
+import android.os.Build
+import androidx.annotation.RequiresApi
+import androidx.window.RequiresWindowSdkExtension
+import androidx.window.WindowSdkExtensions
+import androidx.window.WindowSdkExtensionsRule
+import androidx.window.core.ConsumerAdapter
+import androidx.window.core.PredicateAdapter
+import androidx.window.embedding.EmbeddingAdapter.Companion.INVALID_ACTIVITY_STACK_TOKEN
+import androidx.window.embedding.EmbeddingAdapter.Companion.INVALID_SPLIT_INFO_TOKEN
+import androidx.window.extensions.core.util.function.Function
+import androidx.window.extensions.embedding.ActivityEmbeddingComponent
+import androidx.window.extensions.embedding.SplitAttributes as OemSplitAttributes
+import androidx.window.extensions.embedding.SplitAttributesCalculatorParams as OemSplitAttributesCalculatorParams
+import org.junit.After
+import org.junit.Assert.assertThrows
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.any
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.never
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+/**
+ * Verifies the behavior of [RequiresWindowSdkExtension]
+ * - If the [WindowSdkExtensions.extensionVersion] is greater than or equal to the minimum required
+ *   version denoted in [RequiresWindowSdkExtension.version], the denoted API must be called
+ *   successfully
+ * - Otherwise, [UnsupportedOperationException] must be thrown.
+ */
+@RequiresApi(Build.VERSION_CODES.M) // To call ActivityOptions.makeBasic()
+class RequiresWindowSdkExtensionTests {
+
+    @get:Rule
+    val testRule = WindowSdkExtensionsRule()
+
+    @Mock
+    private lateinit var embeddingExtension: ActivityEmbeddingComponent
+    @Mock
+    private lateinit var classLoader: ClassLoader
+    @Mock
+    private lateinit var applicationContext: Context
+    @Mock
+    private lateinit var activityOptions: ActivityOptions
+
+    private lateinit var mockAnnotations: AutoCloseable
+    private lateinit var embeddingCompat: EmbeddingCompat
+
+    @Before
+    fun setUp() {
+        mockAnnotations = MockitoAnnotations.openMocks(this)
+        embeddingCompat = EmbeddingCompat(
+            embeddingExtension,
+            EmbeddingAdapter(PredicateAdapter(classLoader)),
+            ConsumerAdapter(classLoader),
+            applicationContext
+        )
+
+        doReturn(activityOptions).whenever(embeddingExtension).setLaunchingActivityStack(
+            activityOptions,
+            INVALID_ACTIVITY_STACK_TOKEN
+        )
+    }
+
+    @After
+    fun tearDown() {
+        mockAnnotations.close()
+    }
+
+    @Test
+    fun testVendorApiLevel1() {
+        testRule.overrideExtensionVersion(1)
+
+        assertThrows(UnsupportedOperationException::class.java) {
+            embeddingCompat.setSplitAttributesCalculator { _ -> TEST_SPLIT_ATTRIBUTES }
+        }
+        verify(embeddingExtension, never()).setSplitAttributesCalculator(any())
+
+        assertThrows(UnsupportedOperationException::class.java) {
+            embeddingCompat.clearSplitAttributesCalculator()
+        }
+        verify(embeddingExtension, never()).clearSplitAttributesCalculator()
+
+        assertThrows(UnsupportedOperationException::class.java) {
+            embeddingCompat.setLaunchingActivityStack(activityOptions, Binder())
+        }
+        verify(embeddingExtension, never()).setLaunchingActivityStack(any(), any())
+
+        assertThrows(UnsupportedOperationException::class.java) {
+            embeddingCompat.finishActivityStacks(emptySet())
+        }
+        verify(embeddingExtension, never()).finishActivityStacks(any())
+
+        assertThrows(UnsupportedOperationException::class.java) {
+            embeddingCompat.updateSplitAttributes(TEST_SPLIT_INFO, TEST_SPLIT_ATTRIBUTES)
+        }
+        verify(embeddingExtension, never()).updateSplitAttributes(any(), any())
+
+        assertThrows(UnsupportedOperationException::class.java) {
+            embeddingCompat.invalidateTopVisibleSplitAttributes()
+        }
+        verify(embeddingExtension, never()).invalidateTopVisibleSplitAttributes()
+    }
+
+    @Test
+    fun testVendorApiLevel2() {
+        testRule.overrideExtensionVersion(2)
+
+        embeddingCompat.setSplitAttributesCalculator { _ -> TEST_SPLIT_ATTRIBUTES }
+        verify(embeddingExtension).setSplitAttributesCalculator(
+            any<Function<OemSplitAttributesCalculatorParams, OemSplitAttributes>>()
+        )
+
+        embeddingCompat.clearSplitAttributesCalculator()
+        verify(embeddingExtension).clearSplitAttributesCalculator()
+
+        assertThrows(UnsupportedOperationException::class.java) {
+            embeddingCompat.setLaunchingActivityStack(activityOptions, INVALID_ACTIVITY_STACK_TOKEN)
+        }
+        verify(embeddingExtension, never()).setLaunchingActivityStack(any(), any())
+
+        assertThrows(UnsupportedOperationException::class.java) {
+            embeddingCompat.finishActivityStacks(emptySet())
+        }
+        verify(embeddingExtension, never()).finishActivityStacks(any())
+
+        assertThrows(UnsupportedOperationException::class.java) {
+            embeddingCompat.updateSplitAttributes(TEST_SPLIT_INFO, TEST_SPLIT_ATTRIBUTES)
+        }
+        verify(embeddingExtension, never()).updateSplitAttributes(any(), any())
+
+        assertThrows(UnsupportedOperationException::class.java) {
+            embeddingCompat.invalidateTopVisibleSplitAttributes()
+        }
+        verify(embeddingExtension, never()).invalidateTopVisibleSplitAttributes()
+    }
+
+    @Test
+    fun testVendorApiLevel3() {
+        testRule.overrideExtensionVersion(3)
+
+        embeddingCompat.setSplitAttributesCalculator { _ -> TEST_SPLIT_ATTRIBUTES }
+        verify(embeddingExtension).setSplitAttributesCalculator(
+            any<Function<OemSplitAttributesCalculatorParams, OemSplitAttributes>>()
+        )
+
+        embeddingCompat.clearSplitAttributesCalculator()
+        verify(embeddingExtension).clearSplitAttributesCalculator()
+
+        embeddingCompat.setLaunchingActivityStack(activityOptions, INVALID_ACTIVITY_STACK_TOKEN)
+
+        verify(embeddingExtension).setLaunchingActivityStack(
+            activityOptions,
+            INVALID_ACTIVITY_STACK_TOKEN
+        )
+
+        embeddingCompat.finishActivityStacks(emptySet())
+        verify(embeddingExtension).finishActivityStacks(emptySet())
+
+        embeddingCompat.updateSplitAttributes(TEST_SPLIT_INFO, TEST_SPLIT_ATTRIBUTES)
+        verify(embeddingExtension).updateSplitAttributes(
+            INVALID_SPLIT_INFO_TOKEN,
+            OemSplitAttributes.Builder().build()
+        )
+
+        embeddingCompat.invalidateTopVisibleSplitAttributes()
+        verify(embeddingExtension).invalidateTopVisibleSplitAttributes()
+    }
+
+    companion object {
+        private val TEST_SPLIT_INFO = SplitInfo(
+            ActivityStack(emptyList(), isEmpty = true, INVALID_ACTIVITY_STACK_TOKEN),
+            ActivityStack(emptyList(), isEmpty = true, INVALID_ACTIVITY_STACK_TOKEN),
+            SplitAttributes.Builder().build(),
+            INVALID_SPLIT_INFO_TOKEN,
+        )
+
+        private val TEST_SPLIT_ATTRIBUTES = SplitAttributes.Builder().build()
+    }
+}
diff --git a/window/window/src/test/java/androidx/window/embedding/SplitControllerTest.kt b/window/window/src/test/java/androidx/window/embedding/SplitControllerTest.kt
index 2188e0e..390c681 100644
--- a/window/window/src/test/java/androidx/window/embedding/SplitControllerTest.kt
+++ b/window/window/src/test/java/androidx/window/embedding/SplitControllerTest.kt
@@ -26,7 +26,6 @@
 import kotlinx.coroutines.test.UnconfinedTestDispatcher
 import kotlinx.coroutines.test.runTest
 import org.junit.Assert.assertEquals
-import org.junit.Assert.assertTrue
 import org.junit.Test
 import org.mockito.kotlin.any
 import org.mockito.kotlin.doAnswer
@@ -78,9 +77,6 @@
     fun test_splitAttributesCalculator_delegates() {
         val mockCalculator = mock<(SplitAttributesCalculatorParams) -> SplitAttributes>()
 
-        whenever(mockBackend.isSplitAttributesCalculatorSupported()).thenReturn(true)
-        assertTrue(splitController.isSplitAttributesCalculatorSupported())
-
         splitController.setSplitAttributesCalculator(mockCalculator)
         verify(mockBackend).setSplitAttributesCalculator(mockCalculator)
 
@@ -90,9 +86,6 @@
 
     @Test
     fun test_updateSplitAttribute_delegates() {
-        whenever(mockBackend.areSplitAttributesUpdatesSupported()).thenReturn(true)
-        assertTrue(splitController.isUpdatingSplitAttributesSupported())
-
         val mockSplitAttributes = SplitAttributes()
         val mockSplitInfo = SplitInfo(
             ActivityStack(emptyList(), true, mock()),
@@ -106,9 +99,6 @@
 
     @Test
     fun test_invalidateTopVisibleSplitAttributes_delegates() {
-        whenever(mockBackend.areSplitAttributesUpdatesSupported()).thenReturn(true)
-        assertTrue(splitController.isInvalidatingTopVisibleSplitAttributesSupported())
-
         splitController.invalidateTopVisibleSplitAttributes()
         verify(mockBackend).invalidateTopVisibleSplitAttributes()
     }