Merge "Update Material3 demos" into androidx-main
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/ast/operators/ComparatorNodeCtsTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/ast/operators/ComparatorNodeCtsTest.java
index 16fd0d6..4098926 100644
--- a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/ast/operators/ComparatorNodeCtsTest.java
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/ast/operators/ComparatorNodeCtsTest.java
@@ -138,4 +138,79 @@
                 () -> new ComparatorNode(ComparatorNode.LESS_EQUALS, propertyPath, value)
                         .setPropertyPath(null));
     }
+
+    @Test
+    public void testToString_equals_returnsCorrectString() {
+        List<PropertyPath.PathSegment> pathSegmentList = List.of(
+                PropertyPath.PathSegment.create("example"),
+                PropertyPath.PathSegment.create("property"),
+                PropertyPath.PathSegment.create("path"));
+        PropertyPath propertyPath = new PropertyPath(pathSegmentList);
+        int value = 0;
+
+        ComparatorNode comparatorNode = new ComparatorNode(ComparatorNode.EQUALS, propertyPath,
+                value);
+
+        assertThat(comparatorNode.toString()).isEqualTo("(example.property.path == 0)");
+    }
+
+    @Test
+    public void testToString_lessThan_returnsCorrectString() {
+        List<PropertyPath.PathSegment> pathSegmentList = List.of(
+                PropertyPath.PathSegment.create("example"),
+                PropertyPath.PathSegment.create("property"),
+                PropertyPath.PathSegment.create("path"));
+        PropertyPath propertyPath = new PropertyPath(pathSegmentList);
+        int value = 0;
+
+        ComparatorNode comparatorNode = new ComparatorNode(ComparatorNode.LESS_THAN, propertyPath,
+                value);
+
+        assertThat(comparatorNode.toString()).isEqualTo("(example.property.path < 0)");
+    }
+
+    @Test
+    public void testToString_lessEquals_returnsCorrectString() {
+        List<PropertyPath.PathSegment> pathSegmentList = List.of(
+                PropertyPath.PathSegment.create("example"),
+                PropertyPath.PathSegment.create("property"),
+                PropertyPath.PathSegment.create("path"));
+        PropertyPath propertyPath = new PropertyPath(pathSegmentList);
+        int value = 0;
+
+        ComparatorNode comparatorNode = new ComparatorNode(ComparatorNode.LESS_EQUALS, propertyPath,
+                value);
+
+        assertThat(comparatorNode.toString()).isEqualTo("(example.property.path <= 0)");
+    }
+
+    @Test
+    public void testToString_greaterThan_returnsCorrectString() {
+        List<PropertyPath.PathSegment> pathSegmentList = List.of(
+                PropertyPath.PathSegment.create("example"),
+                PropertyPath.PathSegment.create("property"),
+                PropertyPath.PathSegment.create("path"));
+        PropertyPath propertyPath = new PropertyPath(pathSegmentList);
+        int value = 0;
+
+        ComparatorNode comparatorNode = new ComparatorNode(ComparatorNode.GREATER_THAN,
+                propertyPath, value);
+
+        assertThat(comparatorNode.toString()).isEqualTo("(example.property.path > 0)");
+    }
+
+    @Test
+    public void testToString_greaterEquals_returnsCorrectString() {
+        List<PropertyPath.PathSegment> pathSegmentList = List.of(
+                PropertyPath.PathSegment.create("example"),
+                PropertyPath.PathSegment.create("property"),
+                PropertyPath.PathSegment.create("path"));
+        PropertyPath propertyPath = new PropertyPath(pathSegmentList);
+        int value = 0;
+
+        ComparatorNode comparatorNode = new ComparatorNode(ComparatorNode.GREATER_EQUALS,
+                propertyPath, value);
+
+        assertThat(comparatorNode.toString()).isEqualTo("(example.property.path >= 0)");
+    }
 }
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/ast/operators/PropertyRestrictNodeTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/ast/operators/PropertyRestrictNodeTest.java
index 204dca1..f78abb9 100644
--- a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/ast/operators/PropertyRestrictNodeTest.java
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/ast/operators/PropertyRestrictNodeTest.java
@@ -134,4 +134,21 @@
 
         assertThrows(NullPointerException.class, () -> propertyRestrictNode.setChild(null));
     }
+
+    @Test
+    public void testToString_returnsCorrectString() {
+        List<PropertyPath.PathSegment> pathSegmentList =
+                List.of(PropertyPath.PathSegment.create("example"),
+                        PropertyPath.PathSegment.create("property"),
+                        PropertyPath.PathSegment.create("segment"));
+        PropertyPath propertyPath = new PropertyPath(pathSegmentList);
+
+        TextNode textNode = new TextNode("foo");
+
+        PropertyRestrictNode propertyRestrictNode = new PropertyRestrictNode(propertyPath,
+                textNode);
+
+        assertThat(propertyRestrictNode.toString())
+                .isEqualTo("(example.property.segment:(foo))");
+    }
 }
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/ast/searchtest/AbstractSyntaxTreeSearchCtsTestBase.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/ast/searchtest/AbstractSyntaxTreeSearchCtsTestBase.java
index d2d110d..540841f7 100644
--- a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/ast/searchtest/AbstractSyntaxTreeSearchCtsTestBase.java
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/ast/searchtest/AbstractSyntaxTreeSearchCtsTestBase.java
@@ -23,10 +23,12 @@
 
 import androidx.annotation.NonNull;
 import androidx.appsearch.app.AppSearchSchema;
+import androidx.appsearch.app.AppSearchSchema.LongPropertyConfig;
 import androidx.appsearch.app.AppSearchSchema.PropertyConfig;
 import androidx.appsearch.app.AppSearchSchema.StringPropertyConfig;
 import androidx.appsearch.app.AppSearchSession;
 import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.app.PropertyPath;
 import androidx.appsearch.app.PutDocumentsRequest;
 import androidx.appsearch.app.SearchResults;
 import androidx.appsearch.app.SearchSpec;
@@ -34,7 +36,9 @@
 import androidx.appsearch.ast.NegationNode;
 import androidx.appsearch.ast.TextNode;
 import androidx.appsearch.ast.operators.AndNode;
+import androidx.appsearch.ast.operators.ComparatorNode;
 import androidx.appsearch.ast.operators.OrNode;
+import androidx.appsearch.ast.operators.PropertyRestrictNode;
 import androidx.appsearch.flags.CheckFlagsRule;
 import androidx.appsearch.flags.DeviceFlagsValueProvider;
 import androidx.appsearch.flags.Flags;
@@ -453,4 +457,91 @@
         List<GenericDocument> documents = convertSearchResultsToDocuments(searchResults);
         assertThat(documents).containsExactly(fooBarEmail, fooBazEmail, bazEmail);
     }
+
+    @Test
+    public void testComparatorNode_toString_doesNumericSearch() throws Exception {
+        // Schema registration
+        AppSearchSchema transactionSchema =
+                new AppSearchSchema.Builder("transaction")
+                        .addProperty(
+                                new LongPropertyConfig.Builder("price")
+                                        .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+                                        .setIndexingType(LongPropertyConfig.INDEXING_TYPE_RANGE)
+                                        .build())
+                        .addProperty(
+                                new LongPropertyConfig.Builder("cost")
+                                        .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+                                        .setIndexingType(LongPropertyConfig.INDEXING_TYPE_RANGE)
+                                        .build())
+                        .build();
+        mDb1.setSchemaAsync(new SetSchemaRequest.Builder()
+                .addSchemas(transactionSchema)
+                .build()
+            ).get();
+
+        // Index some documents
+        GenericDocument doc1 =
+                new GenericDocument.Builder<>("namespace", "id1", "transaction")
+                        .setPropertyLong("price", 10)
+                        .build();
+        GenericDocument doc2 =
+                new GenericDocument.Builder<>("namespace", "id2", "transaction")
+                        .setPropertyLong("price", 25)
+                        .build();
+        GenericDocument doc3 =
+                new GenericDocument.Builder<>("namespace", "id3", "transaction")
+                        .setPropertyLong("cost", 2)
+                        .build();
+        checkIsBatchResultSuccess(
+                mDb1.putAsync(
+                        new PutDocumentsRequest.Builder()
+                                .addGenericDocuments(doc1, doc2, doc3)
+                                .build()));
+
+        // Query for the document.
+        PropertyPath pricePath = new PropertyPath("price");
+        ComparatorNode comparatorNode = new ComparatorNode(ComparatorNode.LESS_THAN, pricePath, 20);
+
+        SearchResults searchResults = mDb1.search(comparatorNode.toString(),
+                new SearchSpec.Builder()
+                        .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+                        .setNumericSearchEnabled(true)
+                        .build());
+        List<GenericDocument> documents = convertSearchResultsToDocuments(searchResults);
+        assertThat(documents).containsExactly(doc1);
+    }
+
+    @Test
+    public void testPropertyRestrict_toString_restrictsByProperty() throws Exception {
+        mDb1.setSchemaAsync(
+                new SetSchemaRequest.Builder().addSchemas(AppSearchEmail.SCHEMA).build()).get();
+
+        AppSearchEmail fooFromEmail = new AppSearchEmail.Builder("namespace", "id1")
+                .setFrom("foo")
+                .setBody("bar")
+                .build();
+        AppSearchEmail fooBodyEmail = new AppSearchEmail.Builder("namespace", "id2")
+                .setBody("foo")
+                .build();
+
+        checkIsBatchResultSuccess(mDb1.putAsync(
+                new PutDocumentsRequest.Builder()
+                        .addGenericDocuments(fooFromEmail, fooBodyEmail)
+                        .build()
+            )
+        );
+
+        // Query for the document.
+        TextNode foo = new TextNode("foo");
+        PropertyRestrictNode propertyRestrictNode = new PropertyRestrictNode(
+                new PropertyPath("body"), foo);
+
+        SearchResults searchResults = mDb1.search(propertyRestrictNode.toString(),
+                new SearchSpec.Builder()
+                .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+                .setListFilterQueryLanguageEnabled(true)
+                .build());
+        List<GenericDocument> documents = convertSearchResultsToDocuments(searchResults);
+        assertThat(documents).containsExactly(fooBodyEmail);
+    }
 }
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/ast/operators/ComparatorNode.java b/appsearch/appsearch/src/main/java/androidx/appsearch/ast/operators/ComparatorNode.java
index 6d6b6e0..1ac28c5 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/ast/operators/ComparatorNode.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/ast/operators/ComparatorNode.java
@@ -138,4 +138,36 @@
     public void setValue(long value) {
         mValue = value;
     }
+
+    /**
+     * Get the query string representation of {@link ComparatorNode}.
+     *
+     * <p>The string representation is the string representation of the property path joined from
+     * the left to the value being compared with the string representation of the
+     * {@link Comparator}.
+     */
+    @NonNull
+    @Override
+    public String toString() {
+        String comparatorString = "";
+        switch (mComparator) {
+            case ComparatorNode.EQUALS:
+                comparatorString = "==";
+                break;
+            case ComparatorNode.LESS_THAN:
+                comparatorString = "<";
+                break;
+            case ComparatorNode.LESS_EQUALS:
+                comparatorString = "<=";
+                break;
+            case ComparatorNode.GREATER_THAN:
+                comparatorString = ">";
+                break;
+            case ComparatorNode.GREATER_EQUALS:
+                comparatorString = ">=";
+        }
+        // Equivalent in behavior but more efficient than
+        // String.format("(%s %s %s)", mPropertyPath, comparatorString, mValue);
+        return "(" + mPropertyPath + " " + comparatorString + " " + mValue + ")";
+    }
 }
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/ast/operators/PropertyRestrictNode.java b/appsearch/appsearch/src/main/java/androidx/appsearch/ast/operators/PropertyRestrictNode.java
index ba87da6..42c7902 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/ast/operators/PropertyRestrictNode.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/ast/operators/PropertyRestrictNode.java
@@ -102,4 +102,17 @@
     public void setChild(@NonNull Node childNode) {
         mChildren.set(0, Preconditions.checkNotNull(childNode));
     }
+
+    /**
+     * Get the query string representation of {@link PropertyRestrictNode}.
+     *
+     * <p>The string representation is the string representation of the property path joined from
+     * the left to the query sub expression surrounded in parentheses with the property restrict
+     * symbol (":").
+     */
+    @NonNull
+    @Override
+    public String toString() {
+        return "(" + mProperty + ":" + getChild() + ")";
+    }
 }
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/VirtualFile.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/VirtualFile.kt
index f57ca90..2d5e28c 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/VirtualFile.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/VirtualFile.kt
@@ -164,7 +164,7 @@
 
     override fun executeCommand(block: (String) -> String): String {
         val cmd = block(absolutePath)
-        return trace("UserFile#executeCommand $cmd") {
+        return trace("UserFile#executeCommand $cmd".take(127)) {
             DataInputStream(Runtime.getRuntime().exec(cmd).inputStream)
                 .bufferedReader()
                 .use { it.readText() }
@@ -222,7 +222,7 @@
         var counterOs: CounterOutputStream? = null
 
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
-            trace("ShellFile#useOutputStream $cmd") {
+            trace("ShellFile#useOutputStream $cmd".take(127)) {
                 val (_, inDescriptor, errDescriptor) = uiAutomation.executeShellCommandRwe(cmd)
                 ParcelFileDescriptor.AutoCloseOutputStream(inDescriptor).use {
                     counterOs = CounterOutputStream(it)
@@ -231,7 +231,7 @@
                 checkErr(errDescriptor)
             }
         } else {
-            trace("ShellFile#useOutputStream $cmd") {
+            trace("ShellFile#useOutputStream $cmd".take(127)) {
                 val (_, inDescriptor) = uiAutomation.executeShellCommandRw(cmd)
                 ParcelFileDescriptor.AutoCloseOutputStream(inDescriptor).use {
                     counterOs = CounterOutputStream(it)
@@ -268,7 +268,7 @@
     override fun executeCommand(block: (String) -> String): String {
         val cmd = rootState.maybeRootify(block(absolutePath))
         val output =
-            trace("ShellFile#executeCommand $cmd") {
+            trace("ShellFile#executeCommand $cmd".take(127)) {
                 uiAutomation.executeShellCommand(cmd).fullyReadInputStream()
             }
         return output.trim()
diff --git a/benchmark/benchmark-macro-junit4/src/main/java/androidx/benchmark/macro/junit4/MacrobenchmarkRule.kt b/benchmark/benchmark-macro-junit4/src/main/java/androidx/benchmark/macro/junit4/MacrobenchmarkRule.kt
index 7825418..da3cf49 100644
--- a/benchmark/benchmark-macro-junit4/src/main/java/androidx/benchmark/macro/junit4/MacrobenchmarkRule.kt
+++ b/benchmark/benchmark-macro-junit4/src/main/java/androidx/benchmark/macro/junit4/MacrobenchmarkRule.kt
@@ -16,7 +16,6 @@
 
 package androidx.benchmark.macro.junit4
 
-import android.Manifest
 import androidx.annotation.IntRange
 import androidx.benchmark.Arguments
 import androidx.benchmark.ExperimentalBenchmarkConfigApi
@@ -27,9 +26,7 @@
 import androidx.benchmark.macro.StartupMode
 import androidx.benchmark.macro.macrobenchmarkWithStartupMode
 import androidx.benchmark.perfetto.PerfettoConfig
-import androidx.test.rule.GrantPermissionRule
 import org.junit.Assume.assumeTrue
-import org.junit.rules.RuleChain
 import org.junit.rules.TestRule
 import org.junit.runner.Description
 import org.junit.runners.model.Statement
@@ -226,16 +223,7 @@
             measureBlock
         )
 
-    override fun apply(base: Statement, description: Description): Statement {
-        // Grant external storage, as it may be needed for test output directory.
-        return RuleChain.outerRule(
-                GrantPermissionRule.grant(Manifest.permission.WRITE_EXTERNAL_STORAGE)
-            )
-            .around(::applyInternal)
-            .apply(base, description)
-    }
-
-    private fun applyInternal(base: Statement, description: Description) =
+    override fun apply(base: Statement, description: Description): Statement =
         object : Statement() {
             override fun evaluate() {
                 assumeTrue(Arguments.RuleType.Macrobenchmark in Arguments.enabledRules)
diff --git a/biometric/biometric/src/main/res/values-fa/strings.xml b/biometric/biometric/src/main/res/values-fa/strings.xml
index 6e9482f..563ced0 100644
--- a/biometric/biometric/src/main/res/values-fa/strings.xml
+++ b/biometric/biometric/src/main/res/values-fa/strings.xml
@@ -23,7 +23,7 @@
     <string name="fingerprint_error_no_fingerprints" msgid="7520712796891883488">"اثر انگشتی ثبت نشده است."</string>
     <string name="fingerprint_error_hw_not_present" msgid="6306988885793029438">"این دستگاه حسگر اثر انگشت ندارد"</string>
     <string name="fingerprint_error_user_canceled" msgid="7627716295344353987">"کاربر عملیات اثر انگشت را لغو کرد"</string>
-    <string name="fingerprint_error_lockout" msgid="7291787166416782245">"تعداد تلاش‌ها بیش از حد مجاز است. لطفاً بعداً دوباره امتحان کنید."</string>
+    <string name="fingerprint_error_lockout" msgid="7291787166416782245">"تلاش‌های بسیار زیاد ناموفق. لطفاً بعداً دوباره امتحان کنید."</string>
     <string name="default_error_msg" msgid="4776854077120974966">"خطای ناشناس"</string>
     <string name="generic_error_user_canceled" msgid="7309881387583143581">"کاربر اصالت‌سنجی را لغو کرد."</string>
     <string name="confirm_device_credential_password" msgid="5912733858573823945">"استفاده از گذرواژه"</string>
diff --git a/buildSrc/lint.xml b/buildSrc/lint.xml
index 78d7c83..98fbf34 100644
--- a/buildSrc/lint.xml
+++ b/buildSrc/lint.xml
@@ -32,6 +32,7 @@
         <ignore path="**/src/androidUnitTest/**" />
         <ignore path="**/src/jvmTest/**" />
         <ignore path="**/src/commonTest/**" />
+        <ignore path="**/src/nonEmulatorJvmTest/**" />
         <!-- Required for AppSearch icing tests. -->
         <ignore path="**/java/tests/**" />
     </issue>
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/clang/KonanCinteropExt.kt b/buildSrc/private/src/main/kotlin/androidx/build/clang/KonanCinteropExt.kt
index 6d1f6f7..74652f7 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/clang/KonanCinteropExt.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/clang/KonanCinteropExt.kt
@@ -55,7 +55,6 @@
             cinteropName = cinteropName
         )
     registerCInterop(
-        project,
         kotlinNativeCompilation,
         cinteropName,
         createDefFileTask,
@@ -89,7 +88,7 @@
                 project.layout.file(archiveConfiguration.elements.map { it.single().asFile }),
             cinteropName = archiveConfiguration.name
         )
-    registerCInterop(project, kotlinNativeCompilation, archiveConfiguration.name, createDefFileTask)
+    registerCInterop(kotlinNativeCompilation, archiveConfiguration.name, createDefFileTask)
 }
 
 private fun registerCreateDefFileTask(
@@ -116,7 +115,6 @@
     }
 
 private fun registerCInterop(
-    project: Project,
     kotlinNativeCompilation: KotlinNativeCompilation,
     cinteropName: String,
     createDefFileTask: TaskProvider<CreateDefFileWithLibraryPathTask>,
@@ -131,9 +129,5 @@
                     .map { it.clangParameters.includes }
             )
         }
-        // TODO KT-62795 We shouldn't need this dependency once that issue is fixed.
-        project.tasks.named(cInteropSettings.interopProcessingTaskName).configure {
-            it.dependsOn(createDefFileTask)
-        }
     }
 }
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/sources/ValidateMultiplatformSourceSetNaming.kt b/buildSrc/private/src/main/kotlin/androidx/build/sources/ValidateMultiplatformSourceSetNaming.kt
index 74da1e8..7e117bc 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/sources/ValidateMultiplatformSourceSetNaming.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/sources/ValidateMultiplatformSourceSetNaming.kt
@@ -91,8 +91,8 @@
             project.files(
                 target.compilations
                     .filterNot { compilation ->
-                        // Don't enforce suffixes for test source sets.
-                        compilation.name == "test" || compilation.name.endsWith("Test")
+                        // Don't enforce suffixes for test source sets. Names can be e.g. testOnJvm
+                        compilation.name.startsWith("test") || compilation.name.endsWith("Test")
                     }
                     .flatMap { compilation -> compilation.kotlinSourceSets }
                     .map { kotlinSourceSet -> kotlinSourceSet.kotlin.sourceDirectories }
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManager.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManager.kt
index d65cef9..619a198 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManager.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManager.kt
@@ -1140,6 +1140,7 @@
                 closeCameraDeviceOnClose = shouldCloseCameraDeviceOnClose,
                 finalizeSessionOnCloseBehavior = shouldFinalizeSessionOnCloseBehavior,
                 disableGraphLevelSurfaceTracking = shouldDisableGraphLevelSurfaceTracking,
+                enableRestartDelays = true,
             )
         }
     }
diff --git a/camera/camera-camera2-pipe-testing/src/main/java/androidx/camera/camera2/pipe/testing/CameraControllerSimulator.kt b/camera/camera-camera2-pipe-testing/src/main/java/androidx/camera/camera2/pipe/testing/CameraControllerSimulator.kt
index 35386c3..a1d8f5f 100644
--- a/camera/camera-camera2-pipe-testing/src/main/java/androidx/camera/camera2/pipe/testing/CameraControllerSimulator.kt
+++ b/camera/camera-camera2-pipe-testing/src/main/java/androidx/camera/camera2/pipe/testing/CameraControllerSimulator.kt
@@ -22,7 +22,6 @@
 import androidx.camera.camera2.pipe.CameraGraph
 import androidx.camera.camera2.pipe.CameraGraphId
 import androidx.camera.camera2.pipe.CameraId
-import androidx.camera.camera2.pipe.CameraStatusMonitor
 import androidx.camera.camera2.pipe.GraphState.GraphStateError
 import androidx.camera.camera2.pipe.StreamGraph
 import androidx.camera.camera2.pipe.StreamId
@@ -172,14 +171,6 @@
         }
     }
 
-    override fun onCameraStatusChanged(cameraStatus: CameraStatusMonitor.CameraStatus) {
-        synchronized(lock) {
-            check(!closed) { "Attempted to invoke restart after close." }
-            stop()
-            start()
-        }
-    }
-
     override fun close() {
         synchronized(lock) {
             closed = true
diff --git a/camera/camera-camera2-pipe-testing/src/main/java/androidx/camera/camera2/pipe/testing/FakeCameraBackend.kt b/camera/camera-camera2-pipe-testing/src/main/java/androidx/camera/camera2/pipe/testing/FakeCameraBackend.kt
index 56f4beb..f624b2b5a 100644
--- a/camera/camera-camera2-pipe-testing/src/main/java/androidx/camera/camera2/pipe/testing/FakeCameraBackend.kt
+++ b/camera/camera-camera2-pipe-testing/src/main/java/androidx/camera/camera2/pipe/testing/FakeCameraBackend.kt
@@ -24,13 +24,10 @@
 import androidx.camera.camera2.pipe.CameraGraphId
 import androidx.camera.camera2.pipe.CameraId
 import androidx.camera.camera2.pipe.CameraMetadata
-import androidx.camera.camera2.pipe.CameraStatusMonitor
 import androidx.camera.camera2.pipe.StreamGraph
 import androidx.camera.camera2.pipe.graph.GraphListener
 import kotlinx.coroutines.CompletableDeferred
 import kotlinx.coroutines.Deferred
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableSharedFlow
 
 /** The FakeCameraBackend implements [CameraBackend] and creates [CameraControllerSimulator]s. */
 public class FakeCameraBackend(private val fakeCameras: Map<CameraId, CameraMetadata>) :
@@ -45,9 +42,6 @@
     override val id: CameraBackendId
         get() = FAKE_CAMERA_BACKEND_ID
 
-    override val cameraStatus: Flow<CameraStatusMonitor.CameraStatus>
-        get() = MutableSharedFlow()
-
     override fun awaitCameraIds(): List<CameraId> = fakeCameraIds
 
     override fun awaitConcurrentCameraIds(): Set<Set<CameraId>> = emptySet()
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraBackend.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraBackend.kt
index 2d6dbf6..19859af 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraBackend.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraBackend.kt
@@ -18,7 +18,6 @@
 import androidx.annotation.RestrictTo
 import androidx.camera.camera2.pipe.graph.GraphListener
 import kotlinx.coroutines.Deferred
-import kotlinx.coroutines.flow.Flow
 
 /** This is used to uniquely identify a specific backend implementation. */
 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@@ -26,30 +25,6 @@
 public value class CameraBackendId(public val value: String)
 
 /**
- * A CameraStatusMonitors monitors the status of the cameras, and emits updates when the status of
- * cameras changes, for instance when the camera access priorities have changed or when a particular
- * camera has become available.
- */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public interface CameraStatusMonitor {
-    public val cameraStatus: Flow<CameraStatus>
-
-    public abstract class CameraStatus internal constructor() {
-        public object CameraPrioritiesChanged : CameraStatus() {
-            override fun toString(): String = "CameraPrioritiesChanged"
-        }
-
-        public class CameraAvailable(public val cameraId: CameraId) : CameraStatus() {
-            override fun toString(): String = "CameraAvailable(camera=$cameraId)"
-        }
-
-        public class CameraUnavailable(public val cameraId: CameraId) : CameraStatus() {
-            override fun toString(): String = "CameraUnavailable(camera=$cameraId)"
-        }
-    }
-}
-
-/**
  * A CameraBackend is used by [CameraPipe] to abstract out the lifecycle, state, and interactions
  * with a set of camera devices in a standard way.
  *
@@ -67,12 +42,6 @@
     public val id: CameraBackendId
 
     /**
-     * A flow of camera statuses that provide camera status updates such as when the camera access
-     * priorities have changed, or a certain camera has become available.
-     */
-    public val cameraStatus: Flow<CameraStatusMonitor.CameraStatus>
-
-    /**
      * Read out a list of _openable_ [CameraId]s for this backend. The backend may be able to report
      * Metadata for non-openable cameras. However, these cameras should not appear the list of
      * cameras returned by [getCameraIds].
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraController.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraController.kt
index 4f39a94..7422678 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraController.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraController.kt
@@ -64,13 +64,6 @@
     public fun stop()
 
     /**
-     * Restart the current session. This should basically perform stop() then start(). However, the
-     * implementation should handle its internal states correctly, and only restart under the right
-     * [CameraStatusMonitor.CameraStatus] and [ControllerState].
-     */
-    public fun onCameraStatusChanged(cameraStatus: CameraStatusMonitor.CameraStatus)
-
-    /**
      * Close this instance. [start] and [stop] should not be invoked, and any additional calls will
      * be ignored once this method returns. Depending on implementation the underlying camera
      * connection may not be terminated immediately, depending on the [CameraBackend]
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraGraph.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraGraph.kt
index fd51277..4d05f58 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraGraph.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraGraph.kt
@@ -399,7 +399,17 @@
          * - Device(s): LEGACY camera hardware level
          * - API levels: 23 or LEGACY hardware level.
          */
-        val disableGraphLevelSurfaceTracking: Boolean = false
+        val disableGraphLevelSurfaceTracking: Boolean = false,
+
+        /**
+         * Flag to enable CameraGraph to restart its internal camera controller(s) with a delay. The
+         * delay might be needed during Activity switching, to allow time for the preceding Activity
+         * to close its CameraGraphs to allow for the succeeding Activity to acquire the same
+         * camera.
+         * - Bug(s): b/344752133, b/153714651
+         * - Device(s): CameraX users
+         */
+        val enableRestartDelays: Boolean = false
     ) {
 
         @JvmInline
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2Backend.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2Backend.kt
index 67a2ed2..b7eb8bb 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2Backend.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2Backend.kt
@@ -24,35 +24,27 @@
 import androidx.camera.camera2.pipe.CameraGraphId
 import androidx.camera.camera2.pipe.CameraId
 import androidx.camera.camera2.pipe.CameraMetadata
-import androidx.camera.camera2.pipe.CameraStatusMonitor.CameraStatus
 import androidx.camera.camera2.pipe.StreamGraph
 import androidx.camera.camera2.pipe.config.Camera2ControllerComponent
 import androidx.camera.camera2.pipe.config.Camera2ControllerConfig
-import androidx.camera.camera2.pipe.core.Threads
 import androidx.camera.camera2.pipe.graph.GraphListener
 import androidx.camera.camera2.pipe.graph.StreamGraphImpl
 import javax.inject.Inject
 import kotlinx.coroutines.CompletableDeferred
 import kotlinx.coroutines.Deferred
-import kotlinx.coroutines.flow.Flow
 
 /** This is the default [CameraBackend] implementation for CameraPipe based on Camera2. */
 internal class Camera2Backend
 @Inject
 constructor(
-    private val threads: Threads,
     private val camera2DeviceCache: Camera2DeviceCache,
     private val camera2MetadataCache: Camera2MetadataCache,
     private val virtualCameraManager: VirtualCameraManager,
     private val camera2CameraControllerComponent: Camera2ControllerComponent.Builder,
-    private val camera2CameraStatusMonitor: Camera2CameraStatusMonitor,
 ) : CameraBackend {
     override val id: CameraBackendId
         get() = CameraBackendId("CXCP-Camera2")
 
-    override val cameraStatus: Flow<CameraStatus>
-        get() = camera2CameraStatusMonitor.cameraStatus
-
     override suspend fun getCameraIds(): List<CameraId> = camera2DeviceCache.getCameraIds()
 
     override fun awaitCameraIds(): List<CameraId>? = camera2DeviceCache.awaitCameraIds()
@@ -111,7 +103,7 @@
                         graphId,
                         graphConfig,
                         graphListener,
-                        streamGraph as StreamGraphImpl
+                        streamGraph as StreamGraphImpl,
                     )
                 )
                 .build()
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2CameraController.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2CameraController.kt
index 2c7d2ec..fd75f74 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2CameraController.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2CameraController.kt
@@ -25,7 +25,6 @@
 import androidx.camera.camera2.pipe.CameraGraph
 import androidx.camera.camera2.pipe.CameraGraphId
 import androidx.camera.camera2.pipe.CameraId
-import androidx.camera.camera2.pipe.CameraStatusMonitor.CameraStatus
 import androidx.camera.camera2.pipe.CameraSurfaceManager
 import androidx.camera.camera2.pipe.GraphState
 import androidx.camera.camera2.pipe.StreamGraph
@@ -36,10 +35,13 @@
 import androidx.camera.camera2.pipe.core.Threads
 import androidx.camera.camera2.pipe.core.TimeSource
 import androidx.camera.camera2.pipe.graph.GraphListener
+import androidx.camera.camera2.pipe.internal.CameraStatusMonitor
+import androidx.camera.camera2.pipe.internal.CameraStatusMonitor.CameraStatus
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Job
 import kotlinx.coroutines.async
+import kotlinx.coroutines.delay
 import kotlinx.coroutines.launch
 
 /**
@@ -59,6 +61,7 @@
     private val threads: Threads,
     private val graphConfig: CameraGraph.Config,
     private val graphListener: GraphListener,
+    private val cameraStatusMonitor: CameraStatusMonitor,
     private val captureSessionFactory: CaptureSessionFactory,
     private val captureSequenceProcessorFactory: Camera2CaptureSequenceProcessorFactory,
     private val virtualCameraManager: VirtualCameraManager,
@@ -84,126 +87,185 @@
 
     @GuardedBy("lock") private var lastCameraError: CameraError? = null
 
+    @GuardedBy("lock") private var restartJob: Job? = null
+
     private var currentCamera: VirtualCamera? = null
     private var currentSession: CaptureSessionState? = null
     private var currentSurfaceMap: Map<StreamId, Surface>? = null
 
     private var currentCameraStateJob: Job? = null
+    private var cameraAvailabilityJob: Job? = null
+    private var cameraPrioritiesJob: Job? = null
 
-    override fun start(): Unit =
-        synchronized(lock) {
-            if (controllerState == ControllerState.CLOSED) {
-                Log.info { "Ignoring start(): Camera2CameraController is already closed" }
-                return
-            } else if (controllerState == ControllerState.STARTED) {
-                Log.warn { "Ignoring start(): Camera2CameraController is already started" }
-                return
-            }
-            lastCameraError = null
-            val camera =
-                virtualCameraManager.open(
-                    graphConfig.camera,
-                    graphConfig.sharedCameraIds,
-                    graphListener,
-                ) { _ ->
-                    isForeground
-                }
-            if (camera == null) {
-                Log.error {
-                    "Failed to start Camera2CameraController: Open request submission failed"
-                }
-                return
-            }
-
-            check(currentCamera == null)
-            check(currentSession == null)
-
-            currentCamera = camera
-            val session =
-                CaptureSessionState(
-                    graphListener,
-                    captureSessionFactory,
-                    captureSequenceProcessorFactory,
-                    cameraSurfaceManager,
-                    timeSource,
-                    graphConfig.flags,
-                    scope
-                )
-            currentSession = session
-
-            val surfaces: Map<StreamId, Surface>? = currentSurfaceMap
-            if (surfaces != null) {
-                session.configureSurfaceMap(surfaces)
-            }
-
-            controllerState = ControllerState.STARTED
-            Log.debug { "Started Camera2CameraController" }
-            currentCameraStateJob?.cancel()
-            currentCameraStateJob = scope.launch { bindSessionToCamera() }
-        }
-
-    override fun stop(): Unit =
-        synchronized(lock) {
-            if (controllerState == ControllerState.CLOSED) {
-                Log.warn { "Ignoring stop(): Camera2CameraController is already closed" }
-                return
-            } else if (
-                controllerState == ControllerState.STOPPING ||
-                    controllerState == ControllerState.STOPPED
-            ) {
-                Log.warn { "Ignoring stop(): CameraController already stopping or stopped" }
-                return
-            }
-
-            val camera = currentCamera
-            val session = currentSession
-
-            currentCamera = null
-            currentSession = null
-
-            controllerState = ControllerState.STOPPING
-            Log.debug { "Stopping Camera2CameraController" }
-            disconnectSessionAndCamera(session, camera)
-        }
-
-    override fun onCameraStatusChanged(cameraStatus: CameraStatus): Unit =
-        synchronized(lock) {
-            Log.debug { "$this ($cameraId) camera status changed to $cameraStatus" }
-            if (
-                cameraStatus is CameraStatus.CameraAvailable ||
-                    cameraStatus is CameraStatus.CameraUnavailable
-            ) {
-                this@Camera2CameraController.cameraStatus = cameraStatus
-            }
-
-            var shouldRestart = false
-            when (controllerState) {
-                ControllerState.DISCONNECTED ->
-                    if (
-                        cameraStatus is CameraStatus.CameraAvailable ||
-                            cameraStatus is CameraStatus.CameraPrioritiesChanged
-                    ) {
-                        shouldRestart = true
+    init {
+        cameraAvailabilityJob =
+            scope.launch {
+                cameraStatusMonitor.cameraAvailability.collect { cameraStatus ->
+                    when (cameraStatus) {
+                        is CameraStatus.CameraAvailable -> {
+                            check(cameraStatus.cameraId == cameraId)
+                            onCameraStatusChanged(cameraStatus)
+                        }
+                        is CameraStatus.CameraUnavailable -> {
+                            check(cameraStatus.cameraId == cameraId)
+                            onCameraStatusChanged(cameraStatus)
+                        }
                     }
-                ControllerState.ERROR ->
-                    if (
-                        cameraStatus is CameraStatus.CameraAvailable &&
-                            lastCameraError != CameraError.ERROR_GRAPH_CONFIG
-                    ) {
-                        shouldRestart = true
-                    }
-            }
-            if (!shouldRestart) {
-                Log.debug {
-                    "Camera status changed but not restarting: " +
-                        "Controller state = $controllerState, camera status = $cameraStatus."
                 }
-                return
             }
-            Log.debug { "Restarting Camera2CameraController" }
-            stop()
-            start()
+
+        cameraPrioritiesJob =
+            scope.launch {
+                cameraStatusMonitor.cameraPriorities.collect {
+                    onCameraStatusChanged(CameraStatus.CameraPrioritiesChanged)
+                }
+            }
+    }
+
+    override fun start() {
+        synchronized(lock) { startLocked() }
+    }
+
+    override fun stop() {
+        synchronized(lock) { stopLocked() }
+    }
+
+    private fun restart(delayMs: Long) {
+        synchronized(lock) {
+            restartJob?.cancel()
+            restartJob =
+                scope.launch {
+                    delay(delayMs)
+                    synchronized(lock) {
+                        if (
+                            controllerState != ControllerState.CLOSED &&
+                                controllerState != ControllerState.STOPPING &&
+                                controllerState != ControllerState.STOPPED
+                        ) {
+                            controllerState
+                            stopLocked()
+                            startLocked()
+                        }
+                    }
+                }
         }
+    }
+
+    @GuardedBy("lock")
+    private fun startLocked() {
+        if (controllerState == ControllerState.CLOSED) {
+            Log.info { "Ignoring start(): Camera2CameraController is already closed" }
+            return
+        } else if (controllerState == ControllerState.STARTED) {
+            Log.warn { "Ignoring start(): Camera2CameraController is already started" }
+            return
+        }
+        lastCameraError = null
+        val camera =
+            virtualCameraManager.open(
+                graphConfig.camera,
+                graphConfig.sharedCameraIds,
+                graphListener,
+            ) { _ ->
+                isForeground
+            }
+        if (camera == null) {
+            Log.error { "Failed to start Camera2CameraController: Open request submission failed" }
+            return
+        }
+
+        check(currentCamera == null)
+        check(currentSession == null)
+
+        currentCamera = camera
+        val session =
+            CaptureSessionState(
+                graphListener,
+                captureSessionFactory,
+                captureSequenceProcessorFactory,
+                cameraSurfaceManager,
+                timeSource,
+                graphConfig.flags,
+                scope
+            )
+        currentSession = session
+
+        val surfaces: Map<StreamId, Surface>? = currentSurfaceMap
+        if (surfaces != null) {
+            session.configureSurfaceMap(surfaces)
+        }
+
+        controllerState = ControllerState.STARTED
+        Log.debug { "Started Camera2CameraController" }
+        currentCameraStateJob?.cancel()
+        currentCameraStateJob = scope.launch { bindSessionToCamera() }
+    }
+
+    @GuardedBy("lock")
+    private fun stopLocked() {
+        if (controllerState == ControllerState.CLOSED) {
+            Log.warn { "Ignoring stop(): Camera2CameraController is already closed" }
+            return
+        } else if (
+            controllerState == ControllerState.STOPPING ||
+                controllerState == ControllerState.STOPPED
+        ) {
+            Log.warn { "Ignoring stop(): CameraController already stopping or stopped" }
+            return
+        }
+
+        val camera = currentCamera
+        val session = currentSession
+
+        currentCamera = null
+        currentSession = null
+
+        controllerState = ControllerState.STOPPING
+        Log.debug { "Stopping Camera2CameraController" }
+        disconnectSessionAndCamera(session, camera)
+    }
+
+    private fun onCameraStatusChanged(cameraStatus: CameraStatus) {
+        val shouldRestart =
+            synchronized(lock) {
+                Log.debug { "$this ($cameraId) camera status changed to $cameraStatus" }
+                if (
+                    cameraStatus is CameraStatus.CameraAvailable ||
+                        cameraStatus is CameraStatus.CameraUnavailable
+                ) {
+                    this@Camera2CameraController.cameraStatus = cameraStatus
+                }
+
+                var shouldRestart = false
+                when (controllerState) {
+                    ControllerState.DISCONNECTED ->
+                        if (
+                            cameraStatus is CameraStatus.CameraAvailable ||
+                                cameraStatus is CameraStatus.CameraPrioritiesChanged
+                        ) {
+                            shouldRestart = true
+                        }
+                    ControllerState.ERROR ->
+                        if (
+                            cameraStatus is CameraStatus.CameraAvailable &&
+                                lastCameraError != CameraError.ERROR_GRAPH_CONFIG
+                        ) {
+                            shouldRestart = true
+                        }
+                }
+                shouldRestart
+            }
+        if (!shouldRestart) {
+            Log.debug {
+                "Camera status changed but not restarting: " +
+                    "Controller state = $controllerState, camera status = $cameraStatus."
+            }
+            return
+        }
+        Log.debug { "Restarting Camera2CameraController" }
+        val delayMs = if (graphConfig.flags.enableRestartDelays) 700L else 0L
+        restart(delayMs)
+    }
 
     override fun close(): Unit =
         synchronized(lock) {
@@ -221,6 +283,11 @@
 
             currentCameraStateJob?.cancel()
             currentCameraStateJob = null
+            cameraAvailabilityJob?.cancel()
+            cameraAvailabilityJob = null
+            cameraPrioritiesJob?.cancel()
+            cameraPrioritiesJob = null
+            cameraStatusMonitor.close()
 
             disconnectSessionAndCamera(session, camera)
             if (graphConfig.flags.closeCameraDeviceOnClose) {
@@ -347,6 +414,8 @@
             }
                 ?: run {
                     Log.warn { "Timeout when disconnecting session and camera for $session" }
+                    Log.info { "Force finalizing current capture session" }
+                    session?.finalizeSession(delayMs = 0)
                     graphListener.onGraphError(
                         GraphState.GraphStateError(
                             CameraError.ERROR_CAMERA_DEVICE,
@@ -358,7 +427,7 @@
     }
 
     companion object {
-        private const val DISCONNECT_TIMEOUT_MS = 3_000L // 3s
+        private const val DISCONNECT_TIMEOUT_MS = 5000L // 5s
         private const val MS_TO_NS = 1_000_000
     }
 }
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2CameraStatusMonitor.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2CameraStatusMonitor.kt
index d49ccd1..2f4c9a3 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2CameraStatusMonitor.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2CameraStatusMonitor.kt
@@ -19,24 +19,58 @@
 import android.hardware.camera2.CameraManager
 import android.os.Build
 import androidx.camera.camera2.pipe.CameraId
-import androidx.camera.camera2.pipe.CameraStatusMonitor
-import androidx.camera.camera2.pipe.CameraStatusMonitor.CameraStatus
 import androidx.camera.camera2.pipe.core.Log
 import androidx.camera.camera2.pipe.core.Threads
-import javax.inject.Inject
+import androidx.camera.camera2.pipe.internal.CameraStatusMonitor
+import androidx.camera.camera2.pipe.internal.CameraStatusMonitor.CameraStatus
 import javax.inject.Provider
-import javax.inject.Singleton
+import kotlinx.atomicfu.atomic
+import kotlinx.coroutines.CoroutineName
+import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.channels.awaitClose
 import kotlinx.coroutines.channels.onFailure
 import kotlinx.coroutines.channels.trySendBlocking
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharedFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asSharedFlow
+import kotlinx.coroutines.flow.asStateFlow
 import kotlinx.coroutines.flow.callbackFlow
+import kotlinx.coroutines.launch
 
-@Singleton
-internal class Camera2CameraStatusMonitor
-@Inject
-constructor(cameraManager: Provider<CameraManager>, threads: Threads) : CameraStatusMonitor {
-    override val cameraStatus = callbackFlow {
-        val manager = cameraManager.get()
+internal class Camera2CameraStatusMonitor(
+    cameraManager: Provider<CameraManager>,
+    private val threads: Threads,
+    private val cameraId: CameraId,
+) : CameraStatusMonitor {
+    private val manager = cameraManager.get()
+    private val scope =
+        CoroutineScope(
+            threads.lightweightDispatcher.plus(CoroutineName("CXCP-CameraStatusMonitor"))
+        )
+
+    private val closed = atomic(false)
+
+    private val _cameraAvailability = MutableStateFlow<CameraStatus>(CameraStatus.Unknown)
+    override val cameraAvailability: StateFlow<CameraStatus> = _cameraAvailability.asStateFlow()
+
+    private val _cameraPriorities = MutableSharedFlow<Unit>()
+    override val cameraPriorities: SharedFlow<Unit> = _cameraPriorities.asSharedFlow()
+
+    private val cameraStatus = cameraStatusFlow()
+    private val cameraStatusJob =
+        scope.launch {
+            cameraStatus.collect { cameraStatus ->
+                when (cameraStatus) {
+                    is CameraStatus.CameraAvailable -> _cameraAvailability.emit(cameraStatus)
+                    is CameraStatus.CameraUnavailable -> _cameraAvailability.emit(cameraStatus)
+                    is CameraStatus.CameraPrioritiesChanged -> _cameraPriorities.emit(Unit)
+                }
+            }
+        }
+
+    private fun cameraStatusFlow() = callbackFlow {
         val availabilityCallback =
             object : CameraManager.AvailabilityCallback() {
                 override fun onCameraAccessPrioritiesChanged() {
@@ -47,12 +81,14 @@
                 }
 
                 override fun onCameraAvailable(cameraId: String) {
+                    if (cameraId != this@Camera2CameraStatusMonitor.cameraId.value) return
                     Log.debug { "Camera $cameraId has become available" }
                     trySendBlocking(CameraStatus.CameraAvailable(CameraId.fromCamera2Id(cameraId)))
                         .onFailure { Log.warn { "Failed to emit CameraAvailable($cameraId)" } }
                 }
 
                 override fun onCameraUnavailable(cameraId: String) {
+                    if (cameraId != this@Camera2CameraStatusMonitor.cameraId.value) return
                     Log.debug { "Camera $cameraId has become unavailable" }
                     trySendBlocking(
                             CameraStatus.CameraUnavailable(CameraId.fromCamera2Id(cameraId))
@@ -72,4 +108,10 @@
 
         awaitClose { manager.unregisterAvailabilityCallback(availabilityCallback) }
     }
+
+    override fun close() {
+        if (closed.compareAndSet(expect = false, update = true)) {
+            cameraStatusJob.cancel()
+        }
+    }
 }
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/CaptureSessionState.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/CaptureSessionState.kt
index 8a69c5d..99a6f15 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/CaptureSessionState.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/CaptureSessionState.kt
@@ -367,7 +367,7 @@
         }
     }
 
-    private fun finalizeSession(delayMs: Long = 0L) {
+    internal fun finalizeSession(delayMs: Long = 0L) {
         if (delayMs != 0L) {
             scope.launch {
                 Log.debug { "Finalizing $this in $delayMs ms" }
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/ExternalRequestProcessor.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/ExternalRequestProcessor.kt
index 818ace31..a329318 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/ExternalRequestProcessor.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/ExternalRequestProcessor.kt
@@ -24,7 +24,6 @@
 import androidx.camera.camera2.pipe.CameraGraph
 import androidx.camera.camera2.pipe.CameraGraphId
 import androidx.camera.camera2.pipe.CameraId
-import androidx.camera.camera2.pipe.CameraStatusMonitor
 import androidx.camera.camera2.pipe.CaptureSequence
 import androidx.camera.camera2.pipe.CaptureSequenceProcessor
 import androidx.camera.camera2.pipe.Metadata
@@ -73,11 +72,6 @@
         }
     }
 
-    override fun onCameraStatusChanged(cameraStatus: CameraStatusMonitor.CameraStatus) {
-        // This is intentionally made a no-op for now as CameraPipe external doesn't support
-        // camera status monitoring and camera controller restart.
-    }
-
     override fun close() {
         // TODO: ExternalRequestProcessor will be deprecated. This is a temporary patch to allow
         //   graphProcessor to have a suspending shutdown function.
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/config/Camera2Component.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/config/Camera2Component.kt
index 589e929..7f403c5 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/config/Camera2Component.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/config/Camera2Component.kt
@@ -16,11 +16,11 @@
 
 package androidx.camera.camera2.pipe.config
 
+import android.hardware.camera2.CameraManager
 import androidx.camera.camera2.pipe.CameraBackend
 import androidx.camera.camera2.pipe.CameraController
 import androidx.camera.camera2.pipe.CameraGraph
 import androidx.camera.camera2.pipe.CameraGraphId
-import androidx.camera.camera2.pipe.CameraStatusMonitor
 import androidx.camera.camera2.pipe.StreamGraph
 import androidx.camera.camera2.pipe.compat.AudioRestrictionController
 import androidx.camera.camera2.pipe.compat.AudioRestrictionControllerImpl
@@ -43,10 +43,12 @@
 import androidx.camera.camera2.pipe.graph.GraphListener
 import androidx.camera.camera2.pipe.graph.StreamGraphImpl
 import androidx.camera.camera2.pipe.internal.CameraErrorListener
+import androidx.camera.camera2.pipe.internal.CameraStatusMonitor
 import dagger.Binds
 import dagger.Module
 import dagger.Provides
 import dagger.Subcomponent
+import javax.inject.Provider
 import javax.inject.Scope
 import kotlinx.coroutines.CoroutineName
 import kotlinx.coroutines.CoroutineScope
@@ -75,11 +77,6 @@
     ): CameraAvailabilityMonitor
 
     @Binds
-    abstract fun bindCameraStatusMonitor(
-        camera2CameraStatusMonitor: Camera2CameraStatusMonitor
-    ): CameraStatusMonitor
-
-    @Binds
     abstract fun bindCamera2DeviceCloser(
         camera2CameraDeviceCloser: Camera2DeviceCloserImpl
     ): Camera2DeviceCloser
@@ -151,5 +148,15 @@
                 threads.lightweightDispatcher.plus(CoroutineName("CXCP-Camera2Controller"))
             )
         }
+
+        @Camera2ControllerScope
+        @Provides
+        fun provideCameraStatusMonitor(
+            cameraManager: Provider<CameraManager>,
+            threads: Threads,
+            graphConfig: CameraGraph.Config
+        ): CameraStatusMonitor {
+            return Camera2CameraStatusMonitor(cameraManager, threads, graphConfig.camera)
+        }
     }
 }
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/config/CameraPipeComponent.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/config/CameraPipeComponent.kt
index e337f8e..e0d3b49 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/config/CameraPipeComponent.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/config/CameraPipeComponent.kt
@@ -54,8 +54,6 @@
 /** Qualifier for requesting the CameraPipe scoped Context object */
 @Qualifier internal annotation class CameraPipeContext
 
-@Qualifier internal annotation class ForGraphLifecycleManager
-
 @Singleton
 @Component(
     modules =
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/config/ExternalCameraGraphComponent.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/config/ExternalCameraGraphComponent.kt
index 4035977..7089a3b 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/config/ExternalCameraGraphComponent.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/config/ExternalCameraGraphComponent.kt
@@ -26,7 +26,6 @@
 import androidx.camera.camera2.pipe.CameraGraphId
 import androidx.camera.camera2.pipe.CameraId
 import androidx.camera.camera2.pipe.CameraMetadata
-import androidx.camera.camera2.pipe.CameraStatusMonitor
 import androidx.camera.camera2.pipe.RequestProcessor
 import androidx.camera.camera2.pipe.StreamGraph
 import androidx.camera.camera2.pipe.compat.ExternalCameraController
@@ -35,8 +34,6 @@
 import dagger.Provides
 import dagger.Subcomponent
 import kotlinx.coroutines.Deferred
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableSharedFlow
 
 @CameraGraphScope
 @Subcomponent(modules = [SharedCameraGraphModules::class, ExternalCameraGraphConfigModule::class])
@@ -62,9 +59,6 @@
             override val id: CameraBackendId
                 get() = CameraBackendId("External")
 
-            override val cameraStatus: Flow<CameraStatusMonitor.CameraStatus>
-                get() = MutableSharedFlow()
-
             override suspend fun getCameraIds(): List<CameraId>? {
                 throwUnsupportedOperationException()
             }
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/config/ThreadConfigModule.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/config/ThreadConfigModule.kt
index 1e3d6cf..ec923aa 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/config/ThreadConfigModule.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/config/ThreadConfigModule.kt
@@ -43,7 +43,7 @@
     // Lightweight executors are for CPU bound work that should take less than ~10ms to operate and
     // do not block the calling thread.
     private val lightweightThreadCount: Int =
-        maxOf(2, Runtime.getRuntime().availableProcessors() - 2)
+        maxOf(4, Runtime.getRuntime().availableProcessors() - 2)
 
     // Background thread count is for operations that are not latency sensitive and may take more
     // than a few milliseconds to run.
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/graph/CameraGraphImpl.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/graph/CameraGraphImpl.kt
index ad0de5a..e7ee3477 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/graph/CameraGraphImpl.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/graph/CameraGraphImpl.kt
@@ -19,7 +19,6 @@
 import android.os.Build
 import android.view.Surface
 import androidx.camera.camera2.pipe.AudioRestrictionMode
-import androidx.camera.camera2.pipe.CameraBackend
 import androidx.camera.camera2.pipe.CameraController
 import androidx.camera.camera2.pipe.CameraGraph
 import androidx.camera.camera2.pipe.CameraGraphId
@@ -37,7 +36,6 @@
 import androidx.camera.camera2.pipe.core.tryAcquireToken
 import androidx.camera.camera2.pipe.internal.FrameCaptureQueue
 import androidx.camera.camera2.pipe.internal.FrameDistributor
-import androidx.camera.camera2.pipe.internal.GraphLifecycleManager
 import javax.inject.Inject
 import kotlinx.atomicfu.atomic
 import kotlinx.coroutines.CoroutineScope
@@ -56,12 +54,10 @@
 constructor(
     graphConfig: CameraGraph.Config,
     metadata: CameraMetadata,
-    private val graphLifecycleManager: GraphLifecycleManager,
     private val graphProcessor: GraphProcessor,
     private val graphListener: GraphListener,
     private val streamGraph: StreamGraphImpl,
     private val surfaceGraph: SurfaceGraph,
-    private val cameraBackend: CameraBackend,
     private val cameraController: CameraController,
     private val graphState3A: GraphState3A,
     private val listener3A: Listener3A,
@@ -135,7 +131,7 @@
         Debug.traceStart { "$this#start" }
         Log.info { "Starting $this" }
         graphListener.onGraphStarting()
-        graphLifecycleManager.monitorAndStart(cameraBackend, cameraController)
+        cameraController.start()
         Debug.traceStop()
     }
 
@@ -145,7 +141,7 @@
         Debug.traceStart { "$this#stop" }
         Log.info { "Stopping $this" }
         graphListener.onGraphStopping()
-        graphLifecycleManager.monitorAndStop(cameraBackend, cameraController)
+        cameraController.stop()
         Debug.traceStop()
     }
 
@@ -211,7 +207,7 @@
             Debug.traceStart { "$this#close" }
             Log.info { "Closing $this" }
             graphProcessor.close()
-            graphLifecycleManager.monitorAndClose(cameraBackend, cameraController)
+            cameraController.close()
             frameDistributor.close()
             frameCaptureQueue.close()
             surfaceGraph.close()
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/internal/CameraStatusMonitor.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/internal/CameraStatusMonitor.kt
new file mode 100644
index 0000000..869f506e
--- /dev/null
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/internal/CameraStatusMonitor.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2024 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.pipe.internal
+
+import androidx.annotation.RestrictTo
+import androidx.camera.camera2.pipe.CameraId
+import kotlinx.coroutines.flow.SharedFlow
+import kotlinx.coroutines.flow.StateFlow
+
+/**
+ * A CameraStatusMonitor monitors the status of the cameras, and emits updates when the status of
+ * cameras changes, for instance when the camera access priorities have changed or when a particular
+ * camera has become available.
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+internal interface CameraStatusMonitor : AutoCloseable {
+
+    /** Gets the state flow of the availability of the current camera. */
+    val cameraAvailability: StateFlow<CameraStatus>
+
+    /** A shared flow that emits when camera access priorities have changed. */
+    val cameraPriorities: SharedFlow<Unit>
+
+    abstract class CameraStatus internal constructor() {
+        object Unknown : CameraStatus() {
+            override fun toString(): String = "UnknownCameraStatus"
+        }
+
+        object CameraPrioritiesChanged : CameraStatus() {
+            override fun toString(): String = "CameraPrioritiesChanged"
+        }
+
+        class CameraAvailable(val cameraId: CameraId) : CameraStatus() {
+            override fun toString(): String = "CameraAvailable(camera=$cameraId)"
+        }
+
+        class CameraUnavailable(val cameraId: CameraId) : CameraStatus() {
+            override fun toString(): String = "CameraUnavailable(camera=$cameraId)"
+        }
+    }
+}
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/internal/GraphLifecycleManager.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/internal/GraphLifecycleManager.kt
deleted file mode 100644
index f56d3aa..0000000
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/internal/GraphLifecycleManager.kt
+++ /dev/null
@@ -1,153 +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.camera.camera2.pipe.internal
-
-import androidx.annotation.GuardedBy
-import androidx.camera.camera2.pipe.CameraBackend
-import androidx.camera.camera2.pipe.CameraBackendId
-import androidx.camera.camera2.pipe.CameraController
-import androidx.camera.camera2.pipe.CameraId
-import androidx.camera.camera2.pipe.CameraStatusMonitor
-import androidx.camera.camera2.pipe.CameraStatusMonitor.CameraStatus
-import androidx.camera.camera2.pipe.core.Threads
-import javax.inject.Inject
-import javax.inject.Singleton
-import kotlinx.coroutines.CoroutineName
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Job
-import kotlinx.coroutines.launch
-
-/**
- * GraphLifecycleManager is a CameraPipe-level lifecycle manager that does the following:
- * - Oversees and executes the operations of [CameraController]`s. This means it will make sure the
- *   operations are atomic, and executed based on permissible state transitions.
- * - Subscribe to [CameraStatusMonitor]s for camera status changes, basically “can attempt to
- *   restart signals”, from the respective camera backends, and then only restart
- *   [CameraController]s when the conditions are right.
- * - Once we've determined that we can restart [CameraController]s, select the “suitable”
- *   [CameraController] to restart.
- */
-@Singleton
-internal class GraphLifecycleManager @Inject constructor(val threads: Threads) {
-    private val lock = Any()
-
-    private val scope =
-        CoroutineScope(
-            threads.lightweightDispatcher.plus(CoroutineName("CXCP-GraphLifecycleManager"))
-        )
-
-    @GuardedBy("lock")
-    private val backendControllerMap =
-        mutableMapOf<CameraBackendId, LinkedHashSet<CameraController>>()
-
-    @GuardedBy("lock")
-    private val backendCameraStatusMap =
-        mutableMapOf<CameraBackendId, MutableMap<CameraId, CameraStatus>>()
-
-    @GuardedBy("lock") private val backendStatusCollectJobMap = mutableMapOf<CameraBackendId, Job>()
-
-    internal fun monitorAndStart(cameraBackend: CameraBackend, cameraController: CameraController) =
-        synchronized(lock) {
-            startMonitoring(cameraBackend, cameraController)
-            cameraController.start()
-        }
-
-    internal fun monitorAndStop(cameraBackend: CameraBackend, cameraController: CameraController) =
-        synchronized(lock) {
-            cameraController.stop()
-            stopMonitoring(cameraBackend, cameraController)
-        }
-
-    internal fun monitorAndClose(cameraBackend: CameraBackend, cameraController: CameraController) =
-        synchronized(lock) {
-            cameraController.close()
-            stopMonitoring(cameraBackend, cameraController)
-        }
-
-    @GuardedBy("lock")
-    private fun startMonitoring(cameraBackend: CameraBackend, cameraController: CameraController) {
-        // Update this camera controller with the latest camera status, if exist.
-        backendCameraStatusMap[cameraBackend.id]?.get(cameraController.cameraId)?.let { status ->
-            cameraController.onCameraStatusChanged(status)
-        }
-
-        if (backendControllerMap.containsKey(cameraBackend.id)) {
-            backendControllerMap[cameraBackend.id]?.add(cameraController)
-            return
-        }
-        backendControllerMap[cameraBackend.id] = linkedSetOf(cameraController)
-        backendStatusCollectJobMap[cameraBackend.id] =
-            scope.launch {
-                cameraBackend.cameraStatus.collect { cameraStatus ->
-                    when (cameraStatus) {
-                        is CameraStatus.CameraPrioritiesChanged ->
-                            onCameraStatusChanged(cameraBackend, cameraStatus)
-                        is CameraStatus.CameraAvailable ->
-                            onCameraStatusChanged(
-                                cameraBackend,
-                                cameraStatus,
-                                cameraStatus.cameraId,
-                            )
-                        is CameraStatus.CameraUnavailable ->
-                            onCameraStatusChanged(
-                                cameraBackend,
-                                cameraStatus,
-                                cameraStatus.cameraId,
-                            )
-                    }
-                }
-            }
-    }
-
-    @GuardedBy("lock")
-    private fun stopMonitoring(cameraBackend: CameraBackend, cameraController: CameraController) {
-        if (backendControllerMap.containsKey(cameraBackend.id)) {
-            val controllerSet = backendControllerMap[cameraBackend.id]
-            controllerSet?.remove(cameraController)
-            if (controllerSet?.size == 0) {
-                backendControllerMap.remove(cameraBackend.id)
-                backendStatusCollectJobMap[cameraBackend.id]?.cancel()
-                backendStatusCollectJobMap.remove(cameraBackend.id)
-            }
-        }
-    }
-
-    private fun onCameraStatusChanged(
-        cameraBackend: CameraBackend,
-        cameraStatus: CameraStatus,
-        cameraId: CameraId? = null,
-    ) =
-        synchronized(lock) {
-            if (cameraId != null) {
-                val cameraStatusMap =
-                    backendCameraStatusMap.getOrPut(cameraBackend.id) { mutableMapOf() }
-                cameraStatusMap[cameraId] = cameraStatus
-            }
-            // Restart the last CameraController being tracked in each backend. The last
-            // CameraController would be the latest one being tracked, and should thus take priority
-            // over previous CameraControllers.
-            backendControllerMap[cameraBackend.id]
-                ?.findLast {
-                    if (cameraId != null) {
-                        it.cameraId == cameraId
-                    } else {
-                        true
-                    }
-                }
-                ?.onCameraStatusChanged(cameraStatus)
-        }
-}
diff --git a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/graph/CameraGraphImplTest.kt b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/graph/CameraGraphImplTest.kt
index fb91e7d..8fd32cc 100644
--- a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/graph/CameraGraphImplTest.kt
+++ b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/graph/CameraGraphImplTest.kt
@@ -34,7 +34,6 @@
 import androidx.camera.camera2.pipe.internal.CameraGraphParametersImpl
 import androidx.camera.camera2.pipe.internal.FrameCaptureQueue
 import androidx.camera.camera2.pipe.internal.FrameDistributor
-import androidx.camera.camera2.pipe.internal.GraphLifecycleManager
 import androidx.camera.camera2.pipe.internal.ImageSourceMap
 import androidx.camera.camera2.pipe.media.ImageReaderImageSources
 import androidx.camera.camera2.pipe.testing.CameraControllerSimulator
@@ -109,7 +108,6 @@
             threads
         )
     private val cameraContext = CameraBackendsImpl.CameraBackendContext(context, threads, backends)
-    private val graphLifecycleManager = GraphLifecycleManager(threads)
     private val imageSources = ImageReaderImageSources(threads)
     private val frameCaptureQueue = FrameCaptureQueue()
     private val cameraController =
@@ -134,12 +132,10 @@
         CameraGraphImpl(
             graphConfig,
             metadata,
-            graphLifecycleManager,
             fakeGraphProcessor,
             fakeGraphProcessor,
             streamGraph,
             surfaceGraph,
-            backend,
             cameraController,
             GraphState3A(),
             Listener3A(),
diff --git a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/testing/FakeCameraController.kt b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/testing/FakeCameraController.kt
index 1319fc0..f3a3e4a 100644
--- a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/testing/FakeCameraController.kt
+++ b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/testing/FakeCameraController.kt
@@ -20,7 +20,6 @@
 import androidx.camera.camera2.pipe.CameraController
 import androidx.camera.camera2.pipe.CameraGraphId
 import androidx.camera.camera2.pipe.CameraId
-import androidx.camera.camera2.pipe.CameraStatusMonitor
 import androidx.camera.camera2.pipe.StreamGraph
 import androidx.camera.camera2.pipe.StreamId
 
@@ -41,11 +40,6 @@
         started = false
     }
 
-    override fun onCameraStatusChanged(cameraStatus: CameraStatusMonitor.CameraStatus) {
-        stop()
-        start()
-    }
-
     override fun close() {
         closed = true
         started = false
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/CaptureSession.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/CaptureSession.java
index 70d6935..5838344 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/CaptureSession.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/CaptureSession.java
@@ -57,6 +57,7 @@
 import androidx.camera.core.impl.utils.futures.Futures;
 import androidx.concurrent.futures.CallbackToFutureAdapter;
 import androidx.core.util.Preconditions;
+import androidx.tracing.Trace;
 
 import com.google.common.util.concurrent.ListenableFuture;
 
@@ -106,6 +107,9 @@
     /** The list of DeferrableSurface used to notify surface detach events */
     @GuardedBy("mSessionLock")
     List<DeferrableSurface> mConfiguredDeferrableSurfaces = Collections.emptyList();
+    /** Maximum state this session achieved (for debugging) */
+    @GuardedBy("mSessionLock")
+    State mHighestState = State.UNINITIALIZED;
     /** Tracks the current state of the session. */
     @GuardedBy("mSessionLock")
     State mState = State.UNINITIALIZED;
@@ -136,7 +140,7 @@
      */
     CaptureSession(@NonNull DynamicRangesCompat dynamicRangesCompat,
             @NonNull Quirks cameraQuirks) {
-        mState = State.INITIALIZED;
+        setState(State.INITIALIZED);
         mDynamicRangesCompat = dynamicRangesCompat;
         mCaptureSessionStateCallback = new StateCallback();
         mRequestMonitor = new RequestMonitor(cameraQuirks.contains(CaptureNoResponseQuirk.class));
@@ -211,7 +215,7 @@
         synchronized (mSessionLock) {
             switch (mState) {
                 case INITIALIZED:
-                    mState = State.GET_SURFACE;
+                    setState(State.GET_SURFACE);
                     mConfiguredDeferrableSurfaces = new ArrayList<>(sessionConfig.getSurfaces());
                     mSessionOpener = opener;
                     ListenableFuture<Void> openFuture = FutureChain.from(
@@ -283,7 +287,7 @@
                                 configuredSurfaces.get(i));
                     }
 
-                    mState = State.OPENING;
+                    setState(State.OPENING);
                     Logger.d(TAG, "Opening capture session.");
                     SynchronizedCaptureSession.StateCallback callbacks =
                             SynchronizedCaptureSessionStateCallbacks.createComboCallback(
@@ -451,7 +455,7 @@
                     mSessionOpener.stop();
                     // Fall through
                 case INITIALIZED:
-                    mState = State.RELEASED;
+                    setState(State.RELEASED);
                     break;
                 case OPENED:
                     // Not break close flow. Fall through
@@ -459,7 +463,7 @@
                     Preconditions.checkNotNull(mSessionOpener,
                             "The Opener shouldn't null in state:" + mState);
                     mSessionOpener.stop();
-                    mState = State.CLOSED;
+                    setState(State.CLOSED);
                     mRequestMonitor.stop();
                     mSessionConfig = null;
 
@@ -500,7 +504,7 @@
                     }
                     // Fall through
                 case OPENING:
-                    mState = State.RELEASING;
+                    setState(State.RELEASING);
                     mRequestMonitor.stop();
                     Preconditions.checkNotNull(mSessionOpener,
                             "The Opener shouldn't null in state:" + mState);
@@ -531,7 +535,7 @@
                     mSessionOpener.stop();
                     // Fall through
                 case INITIALIZED:
-                    mState = State.RELEASED;
+                    setState(State.RELEASED);
                     // Fall through
                 case RELEASED:
                     break;
@@ -604,7 +608,7 @@
             return;
         }
 
-        mState = State.RELEASED;
+        setState(State.RELEASED);
         mSynchronizedCaptureSession = null;
 
         if (mReleaseCompleter != null) {
@@ -887,6 +891,22 @@
     }
 
     @GuardedBy("mSessionLock")
+    private void setState(@NonNull State state) {
+        if (state.ordinal() > mHighestState.ordinal()) {
+            mHighestState = state;
+        }
+        mState = state;
+        // Some sessions are created and immediately destroyed, so only trace those sessions
+        // that are actually used, which we distinguish by capture sessions that have gone to
+        // at least a GET_SURFACE state.
+        if (Trace.isEnabled() && mHighestState.ordinal() >= State.GET_SURFACE.ordinal()) {
+            String counterName = "CX:C2State[" + String.format("CaptureSession@%x", hashCode())
+                    + "]";
+            Trace.setCounter(counterName, state.ordinal());
+        }
+    }
+
+    @GuardedBy("mSessionLock")
     private CameraCaptureSession.CaptureCallback createCamera2CaptureCallback(
             List<CameraCaptureCallback> cameraCaptureCallbacks,
             CameraCaptureSession.CaptureCallback... additionalCallbacks) {
@@ -899,10 +919,18 @@
         return Camera2CaptureCallbacks.createComboCallback(camera2Callbacks);
     }
 
+    // Debugging note: these states are kept in ordinal order. Any additions or changes should try
+    // to maintain the same order such that the highest ordinal is the state of largest resource
+    // utilization.
     enum State {
         /** The default state of the session before construction. */
         UNINITIALIZED,
         /**
+         * Terminal state where the session has been cleaned up. At this point the session should
+         * not be used as nothing will happen in this state.
+         */
+        RELEASED,
+        /**
          * Stable state once the session has been constructed, but prior to the {@link
          * CameraCaptureSession} being opened.
          */
@@ -912,6 +940,15 @@
          * surfaces is ready, we can create the {@link CameraCaptureSession}.
          */
         GET_SURFACE,
+        /** Transitional state where the resources are being cleaned up. */
+        RELEASING,
+        /**
+         * Stable state where the session has been closed. However the {@link CameraCaptureSession}
+         * is still valid. It will remain valid until a new instance is opened at which point {@link
+         * CameraCaptureSession.StateCallback#onClosed(CameraCaptureSession)} will be called to do
+         * final cleanup.
+         */
+        CLOSED,
         /**
          * Transitional state when the {@link CameraCaptureSession} is in the process of being
          * opened.
@@ -922,21 +959,7 @@
          * this state if a valid {@link SessionConfig} has been set then the {@link
          * CaptureRequest} will be issued.
          */
-        OPENED,
-        /**
-         * Stable state where the session has been closed. However the {@link CameraCaptureSession}
-         * is still valid. It will remain valid until a new instance is opened at which point {@link
-         * CameraCaptureSession.StateCallback#onClosed(CameraCaptureSession)} will be called to do
-         * final cleanup.
-         */
-        CLOSED,
-        /** Transitional state where the resources are being cleaned up. */
-        RELEASING,
-        /**
-         * Terminal state where the session has been cleaned up. At this point the session should
-         * not be used as nothing will happen in this state.
-         */
-        RELEASED
+        OPENED
     }
 
     /**
@@ -964,7 +987,7 @@
                         throw new IllegalStateException(
                                 "onConfigured() should not be possible in state: " + mState);
                     case OPENING:
-                        mState = State.OPENED;
+                        setState(State.OPENED);
                         mSynchronizedCaptureSession = session;
                         Logger.d(TAG, "Attempting to send capture request onConfigured");
                         issueRepeatingCaptureRequests(mSessionConfig);
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/VirtualCameraControl.java b/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/VirtualCameraControl.java
index 947f25b..19bb708 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/VirtualCameraControl.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/VirtualCameraControl.java
@@ -15,6 +15,7 @@
  */
 package androidx.camera.core.streamsharing;
 
+import static androidx.camera.core.ImageCapture.FLASH_TYPE_USE_TORCH_AS_FLASH;
 import static androidx.core.util.Preconditions.checkArgument;
 
 import static java.util.Collections.singletonList;
@@ -58,8 +59,14 @@
             @ImageCapture.FlashType int flashType) {
         checkArgument(captureConfigs.size() == 1, "Only support one capture config.");
 
+        // FLASH_TYPE_USE_TORCH_AS_FLASH is used to ensure the flash is always on when capturing.
+        // Since we are using JPEG snapshot here, there is no way for the framework to know exactly
+        // when capture is invoked and thus torch as flash workaround is required. Note that this
+        // becomes an issue only when TEMPLATE_PREVIEW is used, usually due to quirk like
+        // PreviewUnderExposureQuirk right now, since TEMPLATE_RECORD would use torch as flash
+        // capture workaround anyway.
         ListenableFuture<CameraCapturePipeline> capturePipeline = getCameraCapturePipelineAsync(
-                captureMode, flashType);
+                captureMode, FLASH_TYPE_USE_TORCH_AS_FLASH);
 
         ListenableFuture<Void> captureFuture = FutureChain.from(
                 capturePipeline
diff --git a/camera/camera-video/src/androidTest/java/androidx/camera/video/VideoRecordingTest.kt b/camera/camera-video/src/androidTest/java/androidx/camera/video/VideoRecordingTest.kt
index ed807fd..7acbea7 100644
--- a/camera/camera-video/src/androidTest/java/androidx/camera/video/VideoRecordingTest.kt
+++ b/camera/camera-video/src/androidTest/java/androidx/camera/video/VideoRecordingTest.kt
@@ -793,7 +793,8 @@
     @Test
     fun updateVideoUsage_whenRecordingStartedPausedResumedStopped(): Unit = runBlocking {
         implName.ignoreTestForCameraPipe(
-            "TODO: b/339615736 - Enable when implemented at camera-pipe"
+            "TODO: b/339615736 - Enable when implemented at camera-pipe",
+            evenInLab = true,
         )
 
         checkAndBindUseCases(videoCapture, preview)
@@ -832,7 +833,8 @@
             assumeStopCodecAfterSurfaceRemovalCrashMediaServerQuirk()
 
             implName.ignoreTestForCameraPipe(
-                "TODO: b/339615736 - Enable when implemented at camera-pipe"
+                "TODO: b/339615736 - Enable when implemented at camera-pipe",
+                evenInLab = true,
             )
 
             checkAndBindUseCases(preview, videoCapture)
@@ -864,7 +866,8 @@
         assumeStopCodecAfterSurfaceRemovalCrashMediaServerQuirk()
 
         implName.ignoreTestForCameraPipe(
-            "TODO: b/339615736 - Enable when implemented at camera-pipe"
+            "TODO: b/339615736 - Enable when implemented at camera-pipe",
+            evenInLab = true,
         )
 
         checkAndBindUseCases(preview, videoCapture)
@@ -888,7 +891,8 @@
         )
 
         implName.ignoreTestForCameraPipe(
-            "TODO: b/339615736 - Enable when implemented at camera-pipe"
+            "TODO: b/339615736 - Enable when implemented at camera-pipe",
+            evenInLab = true,
         )
 
         checkAndBindUseCases(preview, videoCapture)
@@ -922,7 +926,8 @@
         )
 
         implName.ignoreTestForCameraPipe(
-            "TODO: b/339615736 - Enable when implemented at camera-pipe"
+            "TODO: b/339615736 - Enable when implemented at camera-pipe",
+            evenInLab = true,
         )
 
         checkAndBindUseCases(preview, videoCapture)
@@ -956,7 +961,8 @@
         )
 
         implName.ignoreTestForCameraPipe(
-            "TODO: b/339615736 - Enable when implemented at camera-pipe"
+            "TODO: b/339615736 - Enable when implemented at camera-pipe",
+            evenInLab = true,
         )
 
         checkAndBindUseCases(preview, videoCapture)
diff --git a/camera/camera-view/api/current.txt b/camera/camera-view/api/current.txt
index 3b66417..d2fd422d 100644
--- a/camera/camera-view/api/current.txt
+++ b/camera/camera-view/api/current.txt
@@ -85,9 +85,6 @@
     field @Deprecated public static final int UNASSIGNED_ASPECT_RATIO = -1; // 0xffffffff
   }
 
-  @SuppressCompatibility @RequiresOptIn @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ExperimentalPreviewViewScreenFlash {
-  }
-
   public final class LifecycleCameraController extends androidx.camera.view.CameraController {
     ctor public LifecycleCameraController(android.content.Context);
     method @MainThread public void bindToLifecycle(androidx.lifecycle.LifecycleOwner);
@@ -106,7 +103,7 @@
     method @SuppressCompatibility public androidx.camera.view.transform.OutputTransform? getOutputTransform();
     method public androidx.lifecycle.LiveData<androidx.camera.view.PreviewView.StreamState!> getPreviewStreamState();
     method @UiThread public androidx.camera.view.PreviewView.ScaleType getScaleType();
-    method @SuppressCompatibility @UiThread @androidx.camera.view.ExperimentalPreviewViewScreenFlash public androidx.camera.core.ImageCapture.ScreenFlash? getScreenFlash();
+    method @UiThread public androidx.camera.core.ImageCapture.ScreenFlash? getScreenFlash();
     method @UiThread public android.graphics.Matrix? getSensorToViewTransform();
     method @UiThread public androidx.camera.core.Preview.SurfaceProvider getSurfaceProvider();
     method @UiThread public androidx.camera.core.ViewPort? getViewPort();
@@ -114,7 +111,7 @@
     method @UiThread public void setController(androidx.camera.view.CameraController?);
     method @UiThread public void setImplementationMode(androidx.camera.view.PreviewView.ImplementationMode);
     method @UiThread public void setScaleType(androidx.camera.view.PreviewView.ScaleType);
-    method @SuppressCompatibility @androidx.camera.view.ExperimentalPreviewViewScreenFlash public void setScreenFlashOverlayColor(@ColorInt int);
+    method public void setScreenFlashOverlayColor(@ColorInt int);
     method @UiThread public void setScreenFlashWindow(android.view.Window?);
   }
 
diff --git a/camera/camera-view/api/restricted_current.txt b/camera/camera-view/api/restricted_current.txt
index 3b66417..d2fd422d 100644
--- a/camera/camera-view/api/restricted_current.txt
+++ b/camera/camera-view/api/restricted_current.txt
@@ -85,9 +85,6 @@
     field @Deprecated public static final int UNASSIGNED_ASPECT_RATIO = -1; // 0xffffffff
   }
 
-  @SuppressCompatibility @RequiresOptIn @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ExperimentalPreviewViewScreenFlash {
-  }
-
   public final class LifecycleCameraController extends androidx.camera.view.CameraController {
     ctor public LifecycleCameraController(android.content.Context);
     method @MainThread public void bindToLifecycle(androidx.lifecycle.LifecycleOwner);
@@ -106,7 +103,7 @@
     method @SuppressCompatibility public androidx.camera.view.transform.OutputTransform? getOutputTransform();
     method public androidx.lifecycle.LiveData<androidx.camera.view.PreviewView.StreamState!> getPreviewStreamState();
     method @UiThread public androidx.camera.view.PreviewView.ScaleType getScaleType();
-    method @SuppressCompatibility @UiThread @androidx.camera.view.ExperimentalPreviewViewScreenFlash public androidx.camera.core.ImageCapture.ScreenFlash? getScreenFlash();
+    method @UiThread public androidx.camera.core.ImageCapture.ScreenFlash? getScreenFlash();
     method @UiThread public android.graphics.Matrix? getSensorToViewTransform();
     method @UiThread public androidx.camera.core.Preview.SurfaceProvider getSurfaceProvider();
     method @UiThread public androidx.camera.core.ViewPort? getViewPort();
@@ -114,7 +111,7 @@
     method @UiThread public void setController(androidx.camera.view.CameraController?);
     method @UiThread public void setImplementationMode(androidx.camera.view.PreviewView.ImplementationMode);
     method @UiThread public void setScaleType(androidx.camera.view.PreviewView.ScaleType);
-    method @SuppressCompatibility @androidx.camera.view.ExperimentalPreviewViewScreenFlash public void setScreenFlashOverlayColor(@ColorInt int);
+    method public void setScreenFlashOverlayColor(@ColorInt int);
     method @UiThread public void setScreenFlashWindow(android.view.Window?);
   }
 
diff --git a/camera/camera-view/src/main/java/androidx/camera/view/ExperimentalPreviewViewScreenFlash.java b/camera/camera-view/src/main/java/androidx/camera/view/ExperimentalPreviewViewScreenFlash.java
deleted file mode 100644
index df9117e..0000000
--- a/camera/camera-view/src/main/java/androidx/camera/view/ExperimentalPreviewViewScreenFlash.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2024 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.view;
-
-import static java.lang.annotation.RetentionPolicy.CLASS;
-
-import androidx.annotation.RequiresOptIn;
-
-import java.lang.annotation.Retention;
-
-/**
- * Denotes that the annotated API is designed to be experimental for the screen flash feature and
- * may change in a future release.
- */
-@Retention(CLASS)
-@RequiresOptIn
-public @interface ExperimentalPreviewViewScreenFlash {
-}
diff --git a/camera/camera-view/src/main/java/androidx/camera/view/PreviewView.java b/camera/camera-view/src/main/java/androidx/camera/view/PreviewView.java
index d128e54..5af22bf 100644
--- a/camera/camera-view/src/main/java/androidx/camera/view/PreviewView.java
+++ b/camera/camera-view/src/main/java/androidx/camera/view/PreviewView.java
@@ -1179,7 +1179,6 @@
      * @see ScreenFlashView#getScreenFlash()
      * @see ImageCapture#FLASH_MODE_SCREEN
      */
-    @ExperimentalPreviewViewScreenFlash
     @UiThread
     @Nullable
     public ImageCapture.ScreenFlash getScreenFlash() {
@@ -1194,7 +1193,6 @@
      * @see #getScreenFlash()
      * @see ImageCapture#FLASH_MODE_SCREEN
      */
-    @ExperimentalPreviewViewScreenFlash
     public void setScreenFlashOverlayColor(@ColorInt int color) {
         mScreenFlashView.setBackgroundColor(color);
     }
diff --git a/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/CameraPipeActivity.kt b/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/CameraPipeActivity.kt
index ece3c3d..75727d7a 100644
--- a/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/CameraPipeActivity.kt
+++ b/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/CameraPipeActivity.kt
@@ -137,7 +137,7 @@
         var cameras = currentCameras
         cameras?.let {
             for (camera in it) {
-                camera.stop()
+                camera.close()
             }
         }
         Trace.endSection()
diff --git a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/FlashTest.kt b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/FlashTest.kt
index 527aeae..2e8fc9a 100644
--- a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/FlashTest.kt
+++ b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/FlashTest.kt
@@ -209,13 +209,16 @@
     fun flashEnabledInRequest_whenCapturedWithFlashOnAndSharedEffect() {
         verifyRequestAeOrFlashModeForFlashModeCapture(
             ImageCapture.FLASH_MODE_ON,
-            addSharedEffect = true
+            addSharedEffect = true,
+            // In this test, torch as flash workaround should always be used
+            expectedAeMode = CONTROL_AE_MODE_ON,
         )
     }
 
     private fun verifyRequestAeOrFlashModeForFlashModeCapture(
         @ImageCapture.FlashMode flashMode: Int,
         addSharedEffect: Boolean = false,
+        expectedAeMode: Int? = null,
     ) {
         Assume.assumeFalse(
             "Cuttlefish API 29 has AE mode availability issue for flash enabled modes." +
@@ -234,11 +237,12 @@
                 @Volatile var isAeModeExpected = true
 
                 private val expectedAeMode =
-                    when (flashMode) {
-                        ImageCapture.FLASH_MODE_ON -> CONTROL_AE_MODE_ON_ALWAYS_FLASH
-                        ImageCapture.FLASH_MODE_AUTO -> CONTROL_AE_MODE_ON_AUTO_FLASH
-                        else -> CONTROL_AE_MODE_ON
-                    }
+                    expectedAeMode
+                        ?: when (flashMode) {
+                            ImageCapture.FLASH_MODE_ON -> CONTROL_AE_MODE_ON_ALWAYS_FLASH
+                            ImageCapture.FLASH_MODE_AUTO -> CONTROL_AE_MODE_ON_AUTO_FLASH
+                            else -> CONTROL_AE_MODE_ON
+                        }
 
                 override fun onCaptureCompleted(
                     session: CameraCaptureSession,
@@ -251,7 +255,7 @@
                         isFlashModeSet = true
                     }
 
-                    if (request[CONTROL_AE_MODE] != expectedAeMode) {
+                    if (request[CONTROL_AE_MODE] != this.expectedAeMode) {
                         isAeModeExpected = false
                     }
                 }
diff --git a/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/camera2extensions/Camera2ExtensionsActivityTest.kt b/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/camera2extensions/Camera2ExtensionsActivityTest.kt
index c933712..7ef19fa 100644
--- a/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/camera2extensions/Camera2ExtensionsActivityTest.kt
+++ b/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/camera2extensions/Camera2ExtensionsActivityTest.kt
@@ -42,6 +42,7 @@
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.rule.GrantPermissionRule
 import androidx.test.uiautomator.UiDevice
+import androidx.testutils.withActivity
 import org.junit.After
 import org.junit.Assume
 import org.junit.Assume.assumeTrue
@@ -200,4 +201,21 @@
 
         return activityScenario
     }
+
+    @Test
+    fun checkPreviewUpdated_afterSwitchCamera() {
+        val activityScenario =
+            launchCamera2ExtensionsActivityAndWaitForCaptureSessionConfigured(config)
+        with(activityScenario) { // Launches activity
+            use { // Ensures that ActivityScenario is cleaned up properly
+                // Waits for preview to receive enough frames for its IdlingResource to idle.
+                waitForPreviewIdle()
+
+                withActivity { switchCamera() }
+
+                // Waits for preview to receive enough frames again after switching camera
+                waitForPreviewIdle()
+            }
+        }
+    }
 }
diff --git a/camera/integration-tests/extensionstestapp/src/main/java/androidx/camera/integration/extensions/Camera2ExtensionsActivity.kt b/camera/integration-tests/extensionstestapp/src/main/java/androidx/camera/integration/extensions/Camera2ExtensionsActivity.kt
index 5ca6d34..c9c78a7 100644
--- a/camera/integration-tests/extensionstestapp/src/main/java/androidx/camera/integration/extensions/Camera2ExtensionsActivity.kt
+++ b/camera/integration-tests/extensionstestapp/src/main/java/androidx/camera/integration/extensions/Camera2ExtensionsActivity.kt
@@ -620,24 +620,7 @@
         }
 
         val cameraSwitchButton = findViewById<Button>(R.id.Switch)
-        cameraSwitchButton.setOnClickListener {
-            val newCameraId = if (currentCameraId == backCameraId) frontCameraId else backCameraId
-
-            if (!isCameraSupportExtensions(newCameraId)) {
-                Toast.makeText(
-                        this,
-                        "Camera of the other lens facing doesn't support Camera2 extensions.",
-                        Toast.LENGTH_SHORT
-                    )
-                    .show()
-                return@setOnClickListener
-            }
-
-            enableUiControl(false)
-            currentCameraId = newCameraId
-            restartCamera = true
-            closeCaptureSessionAndCameraAsync()
-        }
+        cameraSwitchButton.setOnClickListener { switchCamera() }
 
         val captureButton = findViewById<Button>(R.id.Picture)
         captureButton.setOnClickListener {
@@ -647,6 +630,26 @@
         }
     }
 
+    @VisibleForTesting
+    fun switchCamera() {
+        val newCameraId = if (currentCameraId == backCameraId) frontCameraId else backCameraId
+
+        if (!isCameraSupportExtensions(newCameraId)) {
+            Toast.makeText(
+                    this,
+                    "Camera of the other lens facing doesn't support Camera2 extensions.",
+                    Toast.LENGTH_SHORT
+                )
+                .show()
+            return
+        }
+
+        enableUiControl(false)
+        currentCameraId = newCameraId
+        restartCamera = true
+        closeCaptureSessionAndCameraAsync()
+    }
+
     override fun onStart() {
         super.onStart()
         Log.d(TAG, "onStart()")
@@ -769,7 +772,7 @@
                         if (!oldCaptureSessionClosedDeferred.isCompleted) {
                             oldCaptureSessionClosedDeferred.complete(Unit)
                         }
-                        if (!keepCamera && synchronized(lock) { activityStopped }) {
+                        if (!keepCamera || synchronized(lock) { activityStopped }) {
                             Log.d(TAG, "Close camera++")
                             cameraDevice?.close()
                             cameraDevice = null
diff --git a/car/app/app-samples/showcase/common/src/main/res/values-ca/strings.xml b/car/app/app-samples/showcase/common/src/main/res/values-ca/strings.xml
index 400f759..d70e320 100644
--- a/car/app/app-samples/showcase/common/src/main/res/values-ca/strings.xml
+++ b/car/app/app-samples/showcase/common/src/main/res/values-ca/strings.xml
@@ -81,8 +81,8 @@
     <string name="dial" msgid="3145707439707628311">"Marca"</string>
     <string name="address" msgid="9010635942573581302">"Adreça"</string>
     <string name="phone" msgid="2504766809811627577">"Telèfon"</string>
-    <string name="fail_start_nav" msgid="6921321606009212189">"S\'ha produït un error en iniciar la navegació"</string>
-    <string name="fail_start_dialer" msgid="1471602619507306261">"S\'ha produït un error en iniciar el telèfon"</string>
+    <string name="fail_start_nav" msgid="6921321606009212189">"Hi ha hagut un error en iniciar la navegació"</string>
+    <string name="fail_start_dialer" msgid="1471602619507306261">"Hi ha hagut un error en iniciar el telèfon"</string>
     <string name="car_hardware_demo_title" msgid="3679106197233262689">"Demostració del maquinari del cotxe"</string>
     <string name="car_hardware_info" msgid="1244783247616395012">"Informació sobre el maquinari del cotxe"</string>
     <string name="model_info" msgid="494224423025683030">"Informació del model"</string>
diff --git a/car/app/app-samples/showcase/common/src/main/res/values-fa/strings.xml b/car/app/app-samples/showcase/common/src/main/res/values-fa/strings.xml
index e50341f..0d07cf6 100644
--- a/car/app/app-samples/showcase/common/src/main/res/values-fa/strings.xml
+++ b/car/app/app-samples/showcase/common/src/main/res/values-fa/strings.xml
@@ -94,7 +94,7 @@
     <string name="no_energy_profile_permission" msgid="4662285713731308888">"اجازه نمایه سوخت اعطا نشده است."</string>
     <string name="fuel_types" msgid="6811375173343218212">"انواع سوخت"</string>
     <string name="unavailable" msgid="3636401138255192934">"دردسترس نیست"</string>
-    <string name="ev_connector_types" msgid="735458637011996125">"انواع رابط‌های خودروی برقی"</string>
+    <string name="ev_connector_types" msgid="735458637011996125">"انواع رابط‌های خودرو برقی"</string>
     <string name="example_title" msgid="530257630320010494">"‏نمونه %d"</string>
     <string name="example_1_text" msgid="8631503055894800688">"رنگ این نوشتار "<annotation color="red">"قرمز"</annotation>" است"</string>
     <string name="example_2_text" msgid="1359373957397219102">"رنگ این نوشتار "<annotation color="green">"سبز"</annotation>" است"</string>
@@ -181,7 +181,7 @@
     <string name="no_energy_level_permission" msgid="1684773185095107825">"اجازه میزان سوخت اعطا نشده است."</string>
     <string name="no_speed_permission" msgid="5812532480922675390">"اجازه سرعت اعطا نشده است."</string>
     <string name="no_mileage_permission" msgid="4074779840599589847">"اجازه مسافت طی‌شده اعطا نشده است."</string>
-    <string name="no_ev_status_permission" msgid="933075402821938973">"اجازه وضعیت خودروی برقی اعطا نشده است."</string>
+    <string name="no_ev_status_permission" msgid="933075402821938973">"اجازه وضعیت خودرو برقی اعطا نشده است."</string>
     <string name="no_accelerometer_permission" msgid="896914448469117234">"اجازه شتاب‌سنج اعطا نشده است."</string>
     <string name="no_gyroscope_permission" msgid="665293140266771569">"اجازه ژیروسکوپ اعطا نشده است."</string>
     <string name="no_compass_permission" msgid="5162304489577567125">"اجازه قطب‌نما اعطا نشده است."</string>
@@ -190,7 +190,7 @@
     <string name="fetch_energy_level" msgid="1773415471137542832">"درحال واکشی میزان سوخت."</string>
     <string name="fetch_speed" msgid="7333830984597189627">"درحال واکشی سرعت."</string>
     <string name="fetch_mileage" msgid="7490131687788025123">"درحال واکشی مسافت طی‌شده."</string>
-    <string name="fetch_ev_status" msgid="2798910410830567052">"درحال واکشی وضعیت خودروی برقی."</string>
+    <string name="fetch_ev_status" msgid="2798910410830567052">"درحال واکشی وضعیت خودرو برقی."</string>
     <string name="fetch_accelerometer" msgid="697750041126810911">"درحال واکشی شتاب‌سنج."</string>
     <string name="fetch_gyroscope" msgid="7153155318827188539">"درحال واکشی ژیروسکوپ."</string>
     <string name="fetch_compass" msgid="7316188117590056717">"درحال واکشی قطب‌نما."</string>
@@ -204,8 +204,8 @@
     <string name="raw_speed" msgid="7295910214088983967">"سرعت اولیه"</string>
     <string name="unit" msgid="7697521583928135171">"واحد"</string>
     <string name="odometer" msgid="3925174645651546591">"مسافت‌شمار"</string>
-    <string name="ev_connected" msgid="2277845607662494696">"درگاه شارژ خودروی برقی متصل شد"</string>
-    <string name="ev_open" msgid="4916704450914519643">"درگاه شارژ خودروی برقی باز است"</string>
+    <string name="ev_connected" msgid="2277845607662494696">"درگاه شارژ خودرو برقی متصل شد"</string>
+    <string name="ev_open" msgid="4916704450914519643">"درگاه شارژ خودرو برقی باز است"</string>
     <string name="accelerometer" msgid="2084026313768299185">"شتاب‌سنج"</string>
     <string name="gyroscope" msgid="3428075828014504651">"ژیروسکوپ"</string>
     <string name="compass" msgid="7037367764762441245">"قطب‌نما"</string>
diff --git a/compose/animation/animation-core/build.gradle b/compose/animation/animation-core/build.gradle
index fac6444..4a6cdf1 100644
--- a/compose/animation/animation-core/build.gradle
+++ b/compose/animation/animation-core/build.gradle
@@ -29,12 +29,30 @@
 
 plugins {
     id("AndroidXPlugin")
-    id("com.android.library")
     id("AndroidXComposePlugin")
 }
 
 androidXMultiplatform {
-    android()
+    androidLibrary {
+        namespace = "androidx.compose.animation.core"
+        withAndroidTestOnDeviceBuilder {
+            it.compilationName = "instrumentedTest"
+            it.defaultSourceSetName = "androidInstrumentedTest"
+            it.sourceSetTreeName = "test"
+        }
+        withAndroidTestOnJvmBuilder {
+            it.defaultSourceSetName = "androidUnitTest"
+        }
+        optimization {
+            it.consumerKeepRules.publish = true
+            it.consumerKeepRules.files.add(
+                    new File(project.projectDir, "proguard-rules.pro")
+            )
+        }
+
+        compileSdk = 35
+        aarMetadata.minCompileSdk = 35
+    }
     jvmStubs()
     linuxX64Stubs()
 
@@ -132,10 +150,3 @@
     kotlinTarget = KotlinTarget.KOTLIN_1_9
 }
 
-android {
-    compileSdk 35
-    namespace "androidx.compose.animation.core"
-    buildTypes.configureEach {
-        consumerProguardFiles("proguard-rules.pro")
-    }
-}
diff --git a/compose/animation/animation/build.gradle b/compose/animation/animation/build.gradle
index fdc6664..56fd517 100644
--- a/compose/animation/animation/build.gradle
+++ b/compose/animation/animation/build.gradle
@@ -29,12 +29,24 @@
 
 plugins {
     id("AndroidXPlugin")
-    id("com.android.library")
     id("AndroidXComposePlugin")
 }
 
 androidXMultiplatform {
-    android()
+    androidLibrary {
+        namespace = "androidx.compose.animation"
+        withAndroidTestOnDeviceBuilder {
+            it.compilationName = "instrumentedTest"
+            it.defaultSourceSetName = "androidInstrumentedTest"
+            it.sourceSetTreeName = "test"
+        }
+        withAndroidTestOnJvmBuilder {
+            it.defaultSourceSetName = "androidUnitTest"
+        }
+
+        compileSdk = 35
+        aarMetadata.minCompileSdk = 35
+    }
     jvmStubs()
     linuxX64Stubs()
 
@@ -130,7 +142,3 @@
     kotlinTarget = KotlinTarget.KOTLIN_1_9
 }
 
-android {
-    compileSdk 35
-    namespace "androidx.compose.animation"
-}
diff --git a/compose/foundation/foundation-layout/build.gradle b/compose/foundation/foundation-layout/build.gradle
index a90bb95..54dd48b 100644
--- a/compose/foundation/foundation-layout/build.gradle
+++ b/compose/foundation/foundation-layout/build.gradle
@@ -28,12 +28,31 @@
 
 plugins {
     id("AndroidXPlugin")
-    id("com.android.library")
     id("AndroidXComposePlugin")
 }
 
 androidXMultiplatform {
-    android()
+    androidLibrary {
+        namespace = "androidx.compose.foundation.layout"
+        withAndroidTestOnDeviceBuilder {
+            it.compilationName = "instrumentedTest"
+            it.defaultSourceSetName = "androidInstrumentedTest"
+            it.sourceSetTreeName = "test"
+        }
+        withAndroidTestOnJvmBuilder {
+            it.defaultSourceSetName = "androidUnitTest"
+        }
+
+        compileSdk = 35
+        aarMetadata.minCompileSdk = 35
+
+        optimization {
+            it.consumerKeepRules.publish = true
+            it.consumerKeepRules.files.add(
+                new File(project.projectDir, "proguard-rules.pro")
+            )
+        }
+    }
     jvmStubs()
     linuxX64Stubs()
 
@@ -122,10 +141,3 @@
     kotlinTarget = KotlinTarget.KOTLIN_1_9
 }
 
-android {
-    compileSdk 35
-    namespace "androidx.compose.foundation.layout"
-    buildTypes.configureEach {
-        consumerProguardFiles("proguard-rules.pro")
-    }
-}
diff --git a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/BasicTextFieldDemos.kt b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/BasicTextFieldDemos.kt
index fc672cd..d037b31 100644
--- a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/BasicTextFieldDemos.kt
+++ b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/BasicTextFieldDemos.kt
@@ -28,6 +28,7 @@
 import androidx.compose.foundation.text.BasicTextField
 import androidx.compose.foundation.text.input.TextFieldLineLimits
 import androidx.compose.foundation.text.input.TextFieldState
+import androidx.compose.foundation.text.input.delete
 import androidx.compose.foundation.verticalScroll
 import androidx.compose.material.Button
 import androidx.compose.material.Checkbox
@@ -81,6 +82,9 @@
 
         TagLine(tag = "BasicTextField Edit Controls")
         BasicTextFieldEditControls()
+
+        TagLine(tag = "BasicTextField Programmatic Edit")
+        BasicTextFieldProgrammaticEdit()
     }
 }
 
@@ -183,3 +187,35 @@
         )
     }
 }
+
+@Composable
+fun BasicTextFieldProgrammaticEdit() {
+    val state = remember { TextFieldState() }
+    Column {
+        Row {
+            Button(onClick = { state.edit { replace(selection.start, selection.end, "A") } }) {
+                Text("A")
+            }
+            Button(onClick = { state.edit { replace(selection.start, selection.end, "B") } }) {
+                Text("B")
+            }
+            Button(
+                onClick = {
+                    state.edit {
+                        if (selection.collapsed) {
+                            delete((selection.min - 1).coerceAtLeast(0), selection.min)
+                        } else {
+                            delete(selection.start, selection.end)
+                        }
+                    }
+                }
+            ) {
+                Text("Backspace")
+            }
+        }
+        BasicTextField(
+            state = state,
+            modifier = demoTextFieldModifiers,
+        )
+    }
+}
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text/input/internal/AndroidTextInputSession.android.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text/input/internal/AndroidTextInputSession.android.kt
index 27bfefa3..4535283 100644
--- a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text/input/internal/AndroidTextInputSession.android.kt
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text/input/internal/AndroidTextInputSession.android.kt
@@ -83,22 +83,15 @@
 ): Nothing {
     coroutineScope {
         launch(start = CoroutineStart.UNDISPATCHED) {
-            state.collectImeNotifications { oldValue, newValue, restartImeIfContentChanges ->
+            state.collectImeNotifications { oldValue, newValue, restartIme ->
                 val oldSelection = oldValue.selection
-                val newSelection = newValue.selection
                 val oldComposition = oldValue.composition
+                val newSelection = newValue.selection
                 val newComposition = newValue.composition
 
-                // No need to restart the IME if there wasn't a composing region. This is useful
-                // to not unnecessarily restart filtered digit only, or password fields.
-                if (
-                    restartImeIfContentChanges &&
-                        oldValue.composition != null &&
-                        !oldValue.contentEquals(newValue)
-                ) {
+                if (restartIme) {
                     composeImm.restartInput()
                 } else if (oldSelection != newSelection || oldComposition != newComposition) {
-                    // Don't call updateSelection if input is going to be restarted anyway
                     composeImm.updateSelection(
                         selectionStart = newSelection.min,
                         selectionEnd = newSelection.max,
diff --git a/compose/foundation/foundation/src/androidUnitTest/kotlin/androidx/compose/foundation/text/input/TextFieldStateTest.kt b/compose/foundation/foundation/src/androidUnitTest/kotlin/androidx/compose/foundation/text/input/TextFieldStateTest.kt
index 52f27c4..9aab5b0 100644
--- a/compose/foundation/foundation/src/androidUnitTest/kotlin/androidx/compose/foundation/text/input/TextFieldStateTest.kt
+++ b/compose/foundation/foundation/src/androidUnitTest/kotlin/androidx/compose/foundation/text/input/TextFieldStateTest.kt
@@ -17,6 +17,8 @@
 package androidx.compose.foundation.text.input
 
 import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.text.input.internal.DefaultImeEditCommandScope
+import androidx.compose.foundation.text.input.internal.TransformedTextFieldState
 import androidx.compose.foundation.text.input.internal.setComposingText
 import androidx.compose.foundation.text.input.internal.withImeScope
 import androidx.compose.runtime.snapshotFlow
@@ -672,6 +674,145 @@
         assertThat(state.composition).isNull()
     }
 
+    @Test
+    fun notifyImeListener_firesAfterProgrammaticEdit() {
+        val state = TextFieldState("Hello")
+        var oldValueCalled: TextFieldCharSequence? = null
+        var newValueCalled: TextFieldCharSequence? = null
+        var restartImeCalled: Boolean? = null
+        val listener =
+            TextFieldState.NotifyImeListener { oldValue, newValue, restartIme ->
+                oldValueCalled = oldValue
+                newValueCalled = newValue
+                restartImeCalled = restartIme
+            }
+        state.addNotifyImeListener(listener)
+
+        state.edit { append(" World") }
+
+        assertThat(oldValueCalled.toString()).isEqualTo("Hello")
+        assertThat(newValueCalled.toString()).isEqualTo("Hello World")
+        assertThat(restartImeCalled).isFalse()
+    }
+
+    @Test
+    fun notifyImeListener_firesAfterProgrammaticEdit_restartsImeIfComposing() {
+        val state = TextFieldState("Hello")
+        // We need a composing region to fire restartIme
+        state.editAsUser(null) { setComposition(0, 5) }
+        var oldValueCalled: TextFieldCharSequence? = null
+        var newValueCalled: TextFieldCharSequence? = null
+        var restartImeCalled: Boolean? = null
+        val listener =
+            TextFieldState.NotifyImeListener { oldValue, newValue, restartIme ->
+                oldValueCalled = oldValue
+                newValueCalled = newValue
+                restartImeCalled = restartIme
+            }
+        state.addNotifyImeListener(listener)
+
+        state.edit { append(" World") }
+
+        assertThat(oldValueCalled.toString()).isEqualTo("Hello")
+        assertThat(newValueCalled.toString()).isEqualTo("Hello World")
+        assertThat(restartImeCalled).isTrue()
+    }
+
+    @Test
+    fun notifyImeListener_firesAfterProgrammaticEdit_doesNotRestartIfContentIsSame() {
+        val state = TextFieldState("Hello")
+        // We need a composing region to fire restartIme
+        state.editAsUser(null) { setComposition(0, 5) }
+        var oldValueCalled: TextFieldCharSequence? = null
+        var newValueCalled: TextFieldCharSequence? = null
+        var restartImeCalled: Boolean? = null
+        val listener =
+            TextFieldState.NotifyImeListener { oldValue, newValue, restartIme ->
+                oldValueCalled = oldValue
+                newValueCalled = newValue
+                restartImeCalled = restartIme
+            }
+        state.addNotifyImeListener(listener)
+
+        state.edit {
+            // this ends up being no-op
+            append(" World")
+            delete(5, length)
+        }
+
+        assertThat(oldValueCalled.toString()).isEqualTo("Hello")
+        assertThat(newValueCalled.toString()).isEqualTo("Hello")
+        assertThat(restartImeCalled).isFalse()
+    }
+
+    @Test
+    fun notifyImeListener_firesAfterUserEdit() {
+        val state = TextFieldState("Hello")
+        // We need a composing region for restartIme to be true. It's not going to be but let's
+        // cover all corners
+        state.editAsUser(null) { setComposition(0, 5) }
+        var oldValueCalled: TextFieldCharSequence? = null
+        var newValueCalled: TextFieldCharSequence? = null
+        var restartImeCalled: Boolean? = null
+        val listener =
+            TextFieldState.NotifyImeListener { oldValue, newValue, restartIme ->
+                oldValueCalled = oldValue
+                newValueCalled = newValue
+                restartImeCalled = restartIme
+            }
+        state.addNotifyImeListener(listener)
+
+        DefaultImeEditCommandScope(TransformedTextFieldState(state)).setComposingText("World", 1)
+
+        assertThat(oldValueCalled.toString()).isEqualTo("Hello")
+        assertThat(newValueCalled.toString()).isEqualTo("World")
+        // Even though content changes and there was a composing region, IME is not restarted
+        assertThat(restartImeCalled).isFalse()
+    }
+
+    @Test
+    fun notifyImeListener_firesAfterUndoRedo() {
+        val state = TextFieldState("Hello")
+        state.editAsUser(null) { append(" World") }
+        var oldValueCalled: TextFieldCharSequence? = null
+        var newValueCalled: TextFieldCharSequence? = null
+        var restartImeCalled: Boolean? = null
+        val listener =
+            TextFieldState.NotifyImeListener { oldValue, newValue, restartIme ->
+                oldValueCalled = oldValue
+                newValueCalled = newValue
+                restartImeCalled = restartIme
+            }
+        state.addNotifyImeListener(listener)
+
+        state.undoState.undo() // should remove " World"
+
+        assertThat(oldValueCalled.toString()).isEqualTo("Hello World")
+        assertThat(newValueCalled.toString()).isEqualTo("Hello")
+        assertThat(restartImeCalled).isFalse()
+    }
+
+    @Test
+    fun notifyImeListener_restartImeIsFalse_ifOnlySelectionIsChanged() {
+        val state = TextFieldState("Hello", TextRange(3))
+        var oldValueCalled: TextFieldCharSequence? = null
+        var newValueCalled: TextFieldCharSequence? = null
+        var restartImeCalled: Boolean? = null
+        val listener =
+            TextFieldState.NotifyImeListener { oldValue, newValue, restartIme ->
+                oldValueCalled = oldValue
+                newValueCalled = newValue
+                restartImeCalled = restartIme
+            }
+        state.addNotifyImeListener(listener)
+
+        state.editAsUser(null, restartImeIfContentChanges = true) { selection = TextRange.Zero }
+
+        assertThat(oldValueCalled?.selection).isEqualTo(TextRange(3))
+        assertThat(newValueCalled?.selection).isEqualTo(TextRange(0))
+        assertThat(restartImeCalled).isFalse()
+    }
+
     private fun runTestWithSnapshotsThenCancelChildren(testBody: suspend TestScope.() -> Unit) {
         val globalWriteObserverHandle =
             Snapshot.registerGlobalWriteObserver {
diff --git a/compose/foundation/foundation/src/androidUnitTest/kotlin/androidx/compose/foundation/text/input/internal/TextFieldStateInternalBufferTest.kt b/compose/foundation/foundation/src/androidUnitTest/kotlin/androidx/compose/foundation/text/input/internal/TextFieldStateInternalBufferTest.kt
index 54f6830..d3f54dc 100644
--- a/compose/foundation/foundation/src/androidUnitTest/kotlin/androidx/compose/foundation/text/input/internal/TextFieldStateInternalBufferTest.kt
+++ b/compose/foundation/foundation/src/androidUnitTest/kotlin/androidx/compose/foundation/text/input/internal/TextFieldStateInternalBufferTest.kt
@@ -89,9 +89,6 @@
 
         var resetCalled = 0
         var selectionCalled = 0
-        state.addImeContentListener { _, _, restart ->
-            if (restart) resetCalled++ else selectionCalled++
-        }
 
         val initialBuffer = state.mainBuffer
         state.syncMainBufferToTemporaryBuffer(
@@ -100,13 +97,17 @@
         assertThat(state.mainBuffer).isNotSameInstanceAs(initialBuffer)
 
         val updatedBuffer = state.mainBuffer
+
+        state.addImeContentListener { _, _, restart ->
+            if (restart) resetCalled++ else selectionCalled++
+        }
         state.syncMainBufferToTemporaryBuffer(
             TextFieldCharSequence("qwerty", TextRange.Zero, TextRange.Zero)
         )
         assertThat(state.mainBuffer).isSameInstanceAs(updatedBuffer)
 
-        assertThat(resetCalled).isEqualTo(2)
-        assertThat(selectionCalled).isEqualTo(0)
+        assertThat(resetCalled).isEqualTo(0)
+        assertThat(selectionCalled).isEqualTo(1)
     }
 
     @Test
@@ -127,8 +128,9 @@
         state.syncMainBufferToTemporaryBuffer(newTextFieldValue)
 
         assertThat(state.mainBuffer).isNotSameInstanceAs(initialBuffer)
-        assertThat(resetCalled).isEqualTo(2)
-        assertThat(selectionCalled).isEqualTo(0)
+        // no composing region, reset shouldn't be called
+        assertThat(resetCalled).isEqualTo(0)
+        assertThat(selectionCalled).isEqualTo(2)
     }
 
     @Test
@@ -137,22 +139,22 @@
 
         var resetCalled = 0
         var selectionCalled = 0
-        state.addImeContentListener { _, _, restart ->
-            if (restart) resetCalled++ else selectionCalled++
-        }
 
         val textFieldValue = TextFieldCharSequence("qwerty", TextRange.Zero, TextRange.Zero)
         state.syncMainBufferToTemporaryBuffer(textFieldValue)
         val initialBuffer = state.mainBuffer
 
+        state.addImeContentListener { _, _, restart ->
+            if (restart) resetCalled++ else selectionCalled++
+        }
         val newTextFieldValue = TextFieldCharSequence(textFieldValue, selection = TextRange(1))
         state.syncMainBufferToTemporaryBuffer(newTextFieldValue)
 
         assertThat(state.mainBuffer).isSameInstanceAs(initialBuffer)
         assertThat(newTextFieldValue.selection.start).isEqualTo(state.mainBuffer.selection.start)
         assertThat(newTextFieldValue.selection.end).isEqualTo(state.mainBuffer.selection.end)
-        assertThat(resetCalled).isEqualTo(2)
-        assertThat(selectionCalled).isEqualTo(0)
+        assertThat(resetCalled).isEqualTo(0)
+        assertThat(selectionCalled).isEqualTo(1)
     }
 
     @Test
@@ -161,25 +163,24 @@
 
         var resetCalled = 0
         var selectionCalled = 0
-        state.addImeContentListener { _, _, restart ->
-            if (restart) resetCalled++ else selectionCalled++
-        }
 
         val textFieldValue = TextFieldCharSequence("qwerty", TextRange.Zero, TextRange(1))
         state.syncMainBufferToTemporaryBuffer(textFieldValue)
         val initialBuffer = state.mainBuffer
 
+        state.addImeContentListener { _, _, restart ->
+            if (restart) resetCalled++ else selectionCalled++
+        }
         // composition can not be set from app, IME owns it.
         assertThat(initialBuffer.composition).isNull()
 
-        val newTextFieldValue =
-            TextFieldCharSequence(textFieldValue, textFieldValue.selection, composition = null)
+        val newTextFieldValue = TextFieldCharSequence("qwerty", TextRange.Zero, composition = null)
         state.syncMainBufferToTemporaryBuffer(newTextFieldValue)
 
         assertThat(state.mainBuffer).isSameInstanceAs(initialBuffer)
         assertThat(state.mainBuffer.composition).isNull()
-        assertThat(resetCalled).isEqualTo(2)
-        assertThat(selectionCalled).isEqualTo(0)
+        assertThat(resetCalled).isEqualTo(0)
+        assertThat(selectionCalled).isEqualTo(1)
     }
 
     @Test
@@ -207,8 +208,9 @@
         assertThat(state.mainBuffer).isSameInstanceAs(initialBuffer)
         assertThat(updatedSelection.start).isEqualTo(initialBuffer.selection.start)
         assertThat(updatedSelection.end).isEqualTo(initialBuffer.selection.end)
-        assertThat(resetCalled).isEqualTo(1)
-        assertThat(selectionCalled).isEqualTo(0)
+        // content does not change so restart input is unexpected
+        assertThat(resetCalled).isEqualTo(0)
+        assertThat(selectionCalled).isEqualTo(1)
     }
 
     @Test
diff --git a/compose/foundation/foundation/src/androidUnitTest/kotlin/androidx/compose/foundation/text/input/internal/TransformedTextFieldStateTest.kt b/compose/foundation/foundation/src/androidUnitTest/kotlin/androidx/compose/foundation/text/input/internal/TransformedTextFieldStateTest.kt
index a8fd56a..01cb362 100644
--- a/compose/foundation/foundation/src/androidUnitTest/kotlin/androidx/compose/foundation/text/input/internal/TransformedTextFieldStateTest.kt
+++ b/compose/foundation/foundation/src/androidUnitTest/kotlin/androidx/compose/foundation/text/input/internal/TransformedTextFieldStateTest.kt
@@ -18,6 +18,7 @@
 
 import androidx.compose.foundation.text.input.OutputTransformation
 import androidx.compose.foundation.text.input.PlacedAnnotation
+import androidx.compose.foundation.text.input.TextFieldCharSequence
 import androidx.compose.foundation.text.input.TextFieldState
 import androidx.compose.foundation.text.input.delete
 import androidx.compose.foundation.text.input.insert
@@ -26,6 +27,8 @@
 import androidx.compose.ui.text.SpanStyle
 import androidx.compose.ui.text.TextRange
 import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.runTest
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
@@ -234,4 +237,96 @@
         assertThat(transformedState.outputText.selection).isEqualTo(TextRange(0, 4))
         // Rest of indices and wedge affinity are covered by mapToTransformed tests.
     }
+
+    @Test
+    fun collectImeNotifications_usesVisualText() = runTest {
+        val state = TextFieldState("hello")
+        val outputTransformation = OutputTransformation {
+            insert(0, "a")
+            insert(length, "a")
+        }
+        val transformedState =
+            TransformedTextFieldState(
+                textFieldState = state,
+                outputTransformation = outputTransformation
+            )
+
+        val collectedOldValues = mutableListOf<TextFieldCharSequence>()
+        val collectedNewValues = mutableListOf<TextFieldCharSequence>()
+        val collectedRestartImes = mutableListOf<Boolean>()
+        val job = launch {
+            transformedState.collectImeNotifications { oldValue, newValue, restartIme ->
+                collectedOldValues += oldValue
+                collectedNewValues += newValue
+                collectedRestartImes += restartIme
+            }
+        }
+
+        testScheduler.advanceUntilIdle()
+
+        transformedState.editUntransformedTextAsUser(restartImeIfContentChanges = false) {
+            append(" world")
+        }
+
+        testScheduler.advanceUntilIdle()
+
+        assertThat(collectedOldValues)
+            .containsExactly(TextFieldCharSequence("ahelloa", selection = TextRange(6)))
+        assertThat(collectedNewValues)
+            .containsExactly(TextFieldCharSequence("ahello worlda", selection = TextRange(12)))
+        assertThat(collectedRestartImes).containsExactly(false)
+        job.cancel()
+    }
+
+    @Test
+    fun collectImeNotifications_carriesRestartImeUnchanged() = runTest {
+        val state = TextFieldState("hello").apply { editAsUser(null) { setComposition(0, 5) } }
+        val outputTransformation = OutputTransformation {
+            insert(0, "a")
+            insert(length, "a")
+        }
+        val transformedState =
+            TransformedTextFieldState(
+                textFieldState = state,
+                outputTransformation = outputTransformation
+            )
+
+        val collectedOldValues = mutableListOf<TextFieldCharSequence>()
+        val collectedNewValues = mutableListOf<TextFieldCharSequence>()
+        val collectedRestartImes = mutableListOf<Boolean>()
+        val job = launch {
+            transformedState.collectImeNotifications { oldValue, newValue, restartIme ->
+                collectedOldValues += oldValue
+                collectedNewValues += newValue
+                collectedRestartImes += restartIme
+            }
+        }
+
+        testScheduler.advanceUntilIdle()
+
+        transformedState.editUntransformedTextAsUser(restartImeIfContentChanges = true) {
+            append(" world")
+        }
+
+        testScheduler.advanceUntilIdle()
+
+        assertThat(collectedOldValues)
+            .containsExactly(
+                TextFieldCharSequence(
+                    "ahelloa",
+                    selection = TextRange(6),
+                    composition = TextRange(0, 7)
+                )
+            )
+        assertThat(collectedNewValues)
+            .containsExactly(
+                TextFieldCharSequence(
+                    "ahello worlda",
+                    selection = TextRange(12),
+                    composition = TextRange(0, 6)
+                )
+            )
+        assertThat(collectedRestartImes).containsExactly(true)
+        job.cancel()
+    }
 }
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/input/TextFieldBuffer.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/input/TextFieldBuffer.kt
index 6022683..4a68df3 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/input/TextFieldBuffer.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/input/TextFieldBuffer.kt
@@ -448,7 +448,8 @@
     internal fun toTextFieldCharSequence(
         selection: TextRange = this.selection,
         composition: TextRange? = this.composition,
-        composingAnnotations: List<PlacedAnnotation>? = this.composingAnnotations?.asMutableList(),
+        composingAnnotations: List<PlacedAnnotation>? =
+            this.composingAnnotations?.asMutableList()?.takeIf { it.isNotEmpty() },
     ): TextFieldCharSequence =
         TextFieldCharSequence(
             text = buffer.toString(),
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/input/TextFieldState.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/input/TextFieldState.kt
index 2864629..771c234 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/input/TextFieldState.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/input/TextFieldState.kt
@@ -335,8 +335,17 @@
             return
         }
 
-        // There's a meaningful change to the buffer, let's run the full logic.
-        // first take a _snapshot_ of current state of the mainBuffer after changes are applied.
+        // Eventually we may need to run a string equality check between old value and the new value
+        // This is an O(n) operation, meaning that it gets as expensive as the text length.
+        // Therefore we create this flag to remind ourselves whether the original changes may have
+        // caused a content difference. This value being false is a strong indicator that the
+        // content definitely hasn't changed. However this being true only introduces a possibility.
+        // The content change may have been an exact string replacement like "ab" => "ab".
+        val contentMayHaveChanged = mainBuffer.changeTracker.changeCount != 0
+
+        // There's a meaningful change to the buffer, either content or selection. We need to run
+        // the full logic including InputTransformation. But F=first take a _snapshot_ of current
+        // state of the mainBuffer after changes are applied.
         val afterEditValue =
             TextFieldCharSequence(
                 text = mainBuffer.toString(),
@@ -355,7 +364,11 @@
             updateValueAndNotifyListeners(
                 oldValue = beforeEditValue,
                 newValue = afterEditValue,
-                restartImeIfContentChanges = restartImeIfContentChanges
+                // updateValueAndNotifyListeners use restartImeIfContentChanges flag to possibly
+                // skip doing string equality check. Here we add our own flag to indicate the
+                // possibility of content changing. Since false value is a string indicator,
+                // this added logic works.
+                restartImeIfContentChanges = contentMayHaveChanged && restartImeIfContentChanges
             )
             recordEditForUndo(
                 previousValue = beforeEditValue,
@@ -431,7 +444,19 @@
         value = newValue
         finishEditing()
 
-        notifyImeListeners.forEach { it.onChange(oldValue, newValue, restartImeIfContentChanges) }
+        notifyImeListeners.forEach {
+            it.onChange(
+                oldValue = oldValue,
+                newValue = newValue,
+                restartIme =
+                    restartImeIfContentChanges &&
+                        !oldValue.contentEquals(newValue)
+                        // No need to restart the IME if there wasn't a composing region. This is
+                        // useful to not unnecessarily restart digit only, or password fields.
+                        &&
+                        oldValue.composition != null
+            )
+        }
     }
 
     /**
@@ -481,23 +506,31 @@
      *
      * State in [TextFieldState] can change through various means but categorically there are two
      * sources; Developer([TextFieldState.edit]) and User([TextFieldState.editAsUser]). Only
-     * non-InputTransformed IME sourced changes can skip updating the IME. Otherwise, all changes
+     * non-InputTransformed, IME sourced changes can skip updating the IME. Otherwise, all changes
      * must be sent to the IME to let it synchronize its state with the [TextFieldState]. Such a
-     * communication channel is established by the IME registering a [NotifyImeListener] on a
-     * [TextFieldState].
+     * communication channel is established by the text input session registering a
+     * [NotifyImeListener] on a [TextFieldState].
      */
     internal fun interface NotifyImeListener {
 
         /**
-         * Called when the value in [TextFieldState] changes via any source. The
-         * [restartImeIfContentChanges] flag determines whether a text change between [oldValue] and
-         * [newValue] should restart the ongoing input connection. Selection changes never require a
-         * restart.
+         * Called when the value in [TextFieldState] changes via any source. The [restartIme] flag
+         * determines whether the ongoing input connection should be restarted. Selection or
+         * Composition range changes never require a restart.
+         *
+         * @param oldValue The previous value of the [TextFieldState] before the latest changes are
+         *   applied with one exception. If an [InputTransformation] is applied on the changes
+         *   coming from the IME, we use the value after user changes are applied but before
+         *   [InputTransformation]. This is essentially the last known state to the IME.
+         * @param newValue Current state of the [TextFieldState]. This is always equal to the
+         *   [TextFieldState.value] at the time of calling this function.
+         * @param restartIme Whether to ignore other parameters and basically restart the input
+         *   session with new configuration.
          */
         fun onChange(
             oldValue: TextFieldCharSequence,
             newValue: TextFieldCharSequence,
-            restartImeIfContentChanges: Boolean
+            restartIme: Boolean
         )
     }
 
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/input/internal/TransformedTextFieldState.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/input/internal/TransformedTextFieldState.kt
index 789d2ab4..77bdfe3 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/input/internal/TransformedTextFieldState.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/input/internal/TransformedTextFieldState.kt
@@ -402,16 +402,44 @@
 
     // TODO(b/296583846) Get rid of this.
     /**
-     * Adds [notifyImeListener] to the underlying [TextFieldState] and then suspends until
-     * cancelled, removing the listener before continuing.
+     * Adds a [TextFieldState.NotifyImeListener] to the underlying [TextFieldState] and then
+     * suspends until cancelled, removing the listener before continuing.
+     *
+     * This listener is responsible for updating the IME about the latest changes to the underlying
+     * [TextFieldState]. Please note that the IME should be aware of the [outputText], rather than
+     * [untransformedText] since users mainly interact with the output representation.
+     *
+     * The real challenge comes from the fact that IME doesn't need updates if its commands are not
+     * interfered with. That's why [TextFieldState.NotifyImeListener] actually sends the latest
+     * synced value from IME, rather than the previous value inside the [TextFieldState] before the
+     * changes are applied. In the existence of [OutputTransformation], we have to transform these
+     * values once more before updating the IME.
      */
     suspend fun collectImeNotifications(
         notifyImeListener: TextFieldState.NotifyImeListener
     ): Nothing {
+        val transformedNotifyImeListener =
+            if (outputTransformation != null) {
+                TextFieldState.NotifyImeListener { oldValue, _, restartIme ->
+                    notifyImeListener.onChange(
+                        oldValue =
+                            calculateTransformedText(
+                                    untransformedValue = oldValue,
+                                    outputTransformation = outputTransformation,
+                                    wedgeAffinity = selectionWedgeAffinity
+                                )
+                                ?.text ?: oldValue,
+                        newValue = visualText,
+                        restartIme = restartIme
+                    )
+                }
+            } else {
+                notifyImeListener
+            }
         suspendCancellableCoroutine<Nothing> { continuation ->
-            textFieldState.addNotifyImeListener(notifyImeListener)
+            textFieldState.addNotifyImeListener(transformedNotifyImeListener)
             continuation.invokeOnCancellation {
-                textFieldState.removeNotifyImeListener(notifyImeListener)
+                textFieldState.removeNotifyImeListener(transformedNotifyImeListener)
             }
         }
     }
diff --git a/compose/material/material-ripple/build.gradle b/compose/material/material-ripple/build.gradle
index b6d5e76..9385d8d 100644
--- a/compose/material/material-ripple/build.gradle
+++ b/compose/material/material-ripple/build.gradle
@@ -28,12 +28,24 @@
 
 plugins {
     id("AndroidXPlugin")
-    id("com.android.library")
     id("AndroidXComposePlugin")
 }
 
 androidXMultiplatform {
-    android()
+    androidLibrary {
+        namespace = "androidx.compose.material.ripple"
+        withAndroidTestOnDeviceBuilder {
+            it.compilationName = "instrumentedTest"
+            it.defaultSourceSetName = "androidInstrumentedTest"
+            it.sourceSetTreeName = "test"
+        }
+        withAndroidTestOnJvmBuilder {
+            it.defaultSourceSetName = "androidUnitTest"
+        }
+
+        compileSdk = 35
+        aarMetadata.minCompileSdk = 35
+    }
     jvmStubs()
     linuxX64Stubs()
 
@@ -116,7 +128,3 @@
     kotlinTarget = KotlinTarget.KOTLIN_1_9
 }
 
-android {
-    compileSdk 35
-    namespace "androidx.compose.material.ripple"
-}
diff --git a/compose/material3/benchmark/src/androidTest/java/androidx/compose/material3/benchmark/TooltipBenchmark.kt b/compose/material3/benchmark/src/androidTest/java/androidx/compose/material3/benchmark/TooltipBenchmark.kt
index f33e079..31c5ed8 100644
--- a/compose/material3/benchmark/src/androidTest/java/androidx/compose/material3/benchmark/TooltipBenchmark.kt
+++ b/compose/material3/benchmark/src/androidTest/java/androidx/compose/material3/benchmark/TooltipBenchmark.kt
@@ -89,11 +89,11 @@
         when (tooltipType) {
             TooltipType.Plain -> {
                 tooltip = { PlainTooltipTest() }
-                positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider()
+                positionProvider = TooltipDefaults.rememberTooltipPositionProvider()
             }
             TooltipType.Rich -> {
                 tooltip = { RichTooltipTest() }
-                positionProvider = TooltipDefaults.rememberRichTooltipPositionProvider()
+                positionProvider = TooltipDefaults.rememberTooltipPositionProvider()
             }
         }
 
diff --git a/compose/material3/integration-tests/macrobenchmark-target/src/main/java/androidx/compose/material3/integration/macrobenchmark/target/TooltipActivity.kt b/compose/material3/integration-tests/macrobenchmark-target/src/main/java/androidx/compose/material3/integration/macrobenchmark/target/TooltipActivity.kt
index bf222cbc..a2f6eb1 100644
--- a/compose/material3/integration-tests/macrobenchmark-target/src/main/java/androidx/compose/material3/integration/macrobenchmark/target/TooltipActivity.kt
+++ b/compose/material3/integration-tests/macrobenchmark-target/src/main/java/androidx/compose/material3/integration/macrobenchmark/target/TooltipActivity.kt
@@ -37,7 +37,7 @@
         super.onCreate(savedInstanceState)
         setContent {
             TooltipBox(
-                positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(),
+                positionProvider = TooltipDefaults.rememberTooltipPositionProvider(),
                 tooltip = {
                     PlainTooltip(caretSize = TooltipDefaults.caretSize) {
                         Text("Tooltip Description")
diff --git a/compose/material3/material3-adaptive-navigation-suite/build.gradle b/compose/material3/material3-adaptive-navigation-suite/build.gradle
index 8871853..65c3958 100644
--- a/compose/material3/material3-adaptive-navigation-suite/build.gradle
+++ b/compose/material3/material3-adaptive-navigation-suite/build.gradle
@@ -29,12 +29,24 @@
 
 plugins {
     id("AndroidXPlugin")
-    id("com.android.library")
     id("AndroidXComposePlugin")
 }
 
 androidXMultiplatform {
-    android()
+    androidLibrary {
+        namespace = "androidx.compose.material3.adaptive.navigationsuite"
+        withAndroidTestOnDeviceBuilder {
+            it.compilationName = "instrumentedTest"
+            it.defaultSourceSetName = "androidInstrumentedTest"
+            it.sourceSetTreeName = "test"
+        }
+        withAndroidTestOnJvmBuilder {
+            it.defaultSourceSetName = "androidUnitTest"
+        }
+
+        compileSdk = 35
+        aarMetadata.minCompileSdk = 35
+    }
     jvmStubs()
 
     defaultPlatform(PlatformIdentifier.ANDROID)
@@ -97,10 +109,6 @@
     }
 }
 
-android {
-    compileSdk 35
-    namespace "androidx.compose.material3.adaptive.navigationsuite"
-}
 
 androidx {
     name = "Material Adaptive Navigation Suite"
diff --git a/compose/material3/material3-common/build.gradle b/compose/material3/material3-common/build.gradle
index 0572958..3eac2d7 100644
--- a/compose/material3/material3-common/build.gradle
+++ b/compose/material3/material3-common/build.gradle
@@ -31,11 +31,23 @@
 plugins {
     id("AndroidXPlugin")
     id("AndroidXComposePlugin")
-    id("com.android.library")
 }
 
 androidXMultiplatform {
-    android()
+    androidLibrary {
+        namespace = "androidx.compose.material3.common"
+        withAndroidTestOnDeviceBuilder {
+            it.compilationName = "instrumentedTest"
+            it.defaultSourceSetName = "androidInstrumentedTest"
+            it.sourceSetTreeName = "test"
+        }
+        withAndroidTestOnJvmBuilder {
+            it.defaultSourceSetName = "androidUnitTest"
+        }
+
+        compileSdk = 35
+        aarMetadata.minCompileSdk = 35
+    }
     jvmStubs()
     linuxX64Stubs()
 
@@ -99,10 +111,6 @@
     }
 }
 
-android {
-    compileSdk 35
-    namespace "androidx.compose.material3.common"
-}
 
 androidx {
     name = "Compose Material 3 Common"
diff --git a/compose/material3/material3-window-size-class/build.gradle b/compose/material3/material3-window-size-class/build.gradle
index a943601..46fb47e 100644
--- a/compose/material3/material3-window-size-class/build.gradle
+++ b/compose/material3/material3-window-size-class/build.gradle
@@ -28,12 +28,24 @@
 
 plugins {
     id("AndroidXPlugin")
-    id("com.android.library")
     id("AndroidXComposePlugin")
 }
 
 androidXMultiplatform {
-    android()
+    androidLibrary {
+        namespace = "androidx.compose.material3.windowsizeclass"
+        withAndroidTestOnDeviceBuilder {
+            it.compilationName = "instrumentedTest"
+            it.defaultSourceSetName = "androidInstrumentedTest"
+            it.sourceSetTreeName = "test"
+        }
+        withAndroidTestOnJvmBuilder {
+            it.defaultSourceSetName = "androidUnitTest"
+        }
+
+        compileSdk = 35
+        aarMetadata.minCompileSdk = 35
+    }
     jvmStubs()
     linuxX64Stubs()
 
@@ -114,7 +126,3 @@
     kotlinTarget = KotlinTarget.KOTLIN_1_9
 }
 
-android {
-    compileSdk 35
-    namespace "androidx.compose.material3.windowsizeclass"
-}
diff --git a/compose/material3/material3/api/current.txt b/compose/material3/material3/api/current.txt
index a43c6e0..28407dd 100644
--- a/compose/material3/material3/api/current.txt
+++ b/compose/material3/material3/api/current.txt
@@ -1929,7 +1929,8 @@
   }
 
   @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public final class SheetState {
-    ctor public SheetState(boolean skipPartiallyExpanded, androidx.compose.ui.unit.Density density, optional androidx.compose.material3.SheetValue initialValue, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SheetValue,java.lang.Boolean> confirmValueChange, optional boolean skipHiddenState);
+    ctor @Deprecated public SheetState(boolean skipPartiallyExpanded, androidx.compose.ui.unit.Density density, optional androidx.compose.material3.SheetValue initialValue, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SheetValue,java.lang.Boolean> confirmValueChange, optional boolean skipHiddenState);
+    ctor public SheetState(boolean skipPartiallyExpanded, kotlin.jvm.functions.Function0<java.lang.Float> positionalThreshold, kotlin.jvm.functions.Function0<java.lang.Float> velocityThreshold, optional androidx.compose.material3.SheetValue initialValue, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SheetValue,java.lang.Boolean> confirmValueChange, optional boolean skipHiddenState);
     method public suspend Object? expand(kotlin.coroutines.Continuation<? super kotlin.Unit>);
     method public androidx.compose.material3.SheetValue getCurrentValue();
     method public boolean getHasExpandedState();
@@ -1951,7 +1952,8 @@
   }
 
   public static final class SheetState.Companion {
-    method public androidx.compose.runtime.saveable.Saver<androidx.compose.material3.SheetState,androidx.compose.material3.SheetValue> Saver(boolean skipPartiallyExpanded, kotlin.jvm.functions.Function1<? super androidx.compose.material3.SheetValue,java.lang.Boolean> confirmValueChange, androidx.compose.ui.unit.Density density, boolean skipHiddenState);
+    method public androidx.compose.runtime.saveable.Saver<androidx.compose.material3.SheetState,androidx.compose.material3.SheetValue> Saver(boolean skipPartiallyExpanded, kotlin.jvm.functions.Function0<java.lang.Float> positionalThreshold, kotlin.jvm.functions.Function0<java.lang.Float> velocityThreshold, kotlin.jvm.functions.Function1<? super androidx.compose.material3.SheetValue,java.lang.Boolean> confirmValueChange, boolean skipHiddenState);
+    method @Deprecated public androidx.compose.runtime.saveable.Saver<androidx.compose.material3.SheetState,androidx.compose.material3.SheetValue> Saver(boolean skipPartiallyExpanded, kotlin.jvm.functions.Function1<? super androidx.compose.material3.SheetValue,java.lang.Boolean> confirmValueChange, androidx.compose.ui.unit.Density density, boolean skipHiddenState);
   }
 
   @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public enum SheetValue {
@@ -2691,8 +2693,9 @@
     method public float getPlainTooltipMaxWidth();
     method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getRichTooltipContainerShape();
     method public float getRichTooltipMaxWidth();
-    method @androidx.compose.runtime.Composable public androidx.compose.ui.window.PopupPositionProvider rememberPlainTooltipPositionProvider(optional float spacingBetweenTooltipAndAnchor);
-    method @androidx.compose.runtime.Composable public androidx.compose.ui.window.PopupPositionProvider rememberRichTooltipPositionProvider(optional float spacingBetweenTooltipAndAnchor);
+    method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.ui.window.PopupPositionProvider rememberPlainTooltipPositionProvider(optional float spacingBetweenTooltipAndAnchor);
+    method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.ui.window.PopupPositionProvider rememberRichTooltipPositionProvider(optional float spacingBetweenTooltipAndAnchor);
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.window.PopupPositionProvider rememberTooltipPositionProvider(optional float spacingBetweenTooltipAndAnchor);
     method @androidx.compose.runtime.Composable public androidx.compose.material3.RichTooltipColors richTooltipColors();
     method @androidx.compose.runtime.Composable public androidx.compose.material3.RichTooltipColors richTooltipColors(optional long containerColor, optional long contentColor, optional long titleContentColor, optional long actionContentColor);
     property public final long caretSize;
diff --git a/compose/material3/material3/api/restricted_current.txt b/compose/material3/material3/api/restricted_current.txt
index a43c6e0..28407dd 100644
--- a/compose/material3/material3/api/restricted_current.txt
+++ b/compose/material3/material3/api/restricted_current.txt
@@ -1929,7 +1929,8 @@
   }
 
   @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public final class SheetState {
-    ctor public SheetState(boolean skipPartiallyExpanded, androidx.compose.ui.unit.Density density, optional androidx.compose.material3.SheetValue initialValue, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SheetValue,java.lang.Boolean> confirmValueChange, optional boolean skipHiddenState);
+    ctor @Deprecated public SheetState(boolean skipPartiallyExpanded, androidx.compose.ui.unit.Density density, optional androidx.compose.material3.SheetValue initialValue, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SheetValue,java.lang.Boolean> confirmValueChange, optional boolean skipHiddenState);
+    ctor public SheetState(boolean skipPartiallyExpanded, kotlin.jvm.functions.Function0<java.lang.Float> positionalThreshold, kotlin.jvm.functions.Function0<java.lang.Float> velocityThreshold, optional androidx.compose.material3.SheetValue initialValue, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SheetValue,java.lang.Boolean> confirmValueChange, optional boolean skipHiddenState);
     method public suspend Object? expand(kotlin.coroutines.Continuation<? super kotlin.Unit>);
     method public androidx.compose.material3.SheetValue getCurrentValue();
     method public boolean getHasExpandedState();
@@ -1951,7 +1952,8 @@
   }
 
   public static final class SheetState.Companion {
-    method public androidx.compose.runtime.saveable.Saver<androidx.compose.material3.SheetState,androidx.compose.material3.SheetValue> Saver(boolean skipPartiallyExpanded, kotlin.jvm.functions.Function1<? super androidx.compose.material3.SheetValue,java.lang.Boolean> confirmValueChange, androidx.compose.ui.unit.Density density, boolean skipHiddenState);
+    method public androidx.compose.runtime.saveable.Saver<androidx.compose.material3.SheetState,androidx.compose.material3.SheetValue> Saver(boolean skipPartiallyExpanded, kotlin.jvm.functions.Function0<java.lang.Float> positionalThreshold, kotlin.jvm.functions.Function0<java.lang.Float> velocityThreshold, kotlin.jvm.functions.Function1<? super androidx.compose.material3.SheetValue,java.lang.Boolean> confirmValueChange, boolean skipHiddenState);
+    method @Deprecated public androidx.compose.runtime.saveable.Saver<androidx.compose.material3.SheetState,androidx.compose.material3.SheetValue> Saver(boolean skipPartiallyExpanded, kotlin.jvm.functions.Function1<? super androidx.compose.material3.SheetValue,java.lang.Boolean> confirmValueChange, androidx.compose.ui.unit.Density density, boolean skipHiddenState);
   }
 
   @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public enum SheetValue {
@@ -2691,8 +2693,9 @@
     method public float getPlainTooltipMaxWidth();
     method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getRichTooltipContainerShape();
     method public float getRichTooltipMaxWidth();
-    method @androidx.compose.runtime.Composable public androidx.compose.ui.window.PopupPositionProvider rememberPlainTooltipPositionProvider(optional float spacingBetweenTooltipAndAnchor);
-    method @androidx.compose.runtime.Composable public androidx.compose.ui.window.PopupPositionProvider rememberRichTooltipPositionProvider(optional float spacingBetweenTooltipAndAnchor);
+    method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.ui.window.PopupPositionProvider rememberPlainTooltipPositionProvider(optional float spacingBetweenTooltipAndAnchor);
+    method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.ui.window.PopupPositionProvider rememberRichTooltipPositionProvider(optional float spacingBetweenTooltipAndAnchor);
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.window.PopupPositionProvider rememberTooltipPositionProvider(optional float spacingBetweenTooltipAndAnchor);
     method @androidx.compose.runtime.Composable public androidx.compose.material3.RichTooltipColors richTooltipColors();
     method @androidx.compose.runtime.Composable public androidx.compose.material3.RichTooltipColors richTooltipColors(optional long containerColor, optional long contentColor, optional long titleContentColor, optional long actionContentColor);
     property public final long caretSize;
diff --git a/compose/material3/material3/integration-tests/material3-demos/src/main/java/androidx/compose/material3/demos/TooltipDemo.kt b/compose/material3/material3/integration-tests/material3-demos/src/main/java/androidx/compose/material3/demos/TooltipDemo.kt
index ec5eede..9e4c440 100644
--- a/compose/material3/material3/integration-tests/material3-demos/src/main/java/androidx/compose/material3/demos/TooltipDemo.kt
+++ b/compose/material3/material3/integration-tests/material3-demos/src/main/java/androidx/compose/material3/demos/TooltipDemo.kt
@@ -65,7 +65,7 @@
             val textFieldTooltipState = rememberTooltipState()
             val scope = rememberCoroutineScope()
             TooltipBox(
-                positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(),
+                positionProvider = TooltipDefaults.rememberTooltipPositionProvider(),
                 tooltip = { PlainTooltip { Text(textFieldTooltipText) } },
                 state = textFieldTooltipState
             ) {
@@ -96,7 +96,7 @@
         LazyColumn(verticalArrangement = Arrangement.spacedBy(4.dp)) {
             items(listData) { item ->
                 TooltipBox(
-                    positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(),
+                    positionProvider = TooltipDefaults.rememberTooltipPositionProvider(),
                     tooltip = { PlainTooltip { Text("${item.itemName} added to list") } },
                     state = item.addedTooltipState
                 ) {
@@ -115,7 +115,7 @@
             headlineContent = { Text(itemName) },
             trailingContent = {
                 TooltipBox(
-                    positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(),
+                    positionProvider = TooltipDefaults.rememberTooltipPositionProvider(),
                     tooltip = { PlainTooltip { Text("Delete $itemName") } },
                     state = rememberTooltipState(),
                     enableUserInput = true
diff --git a/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/TooltipSamples.kt b/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/TooltipSamples.kt
index bd37b75..1d8809e 100644
--- a/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/TooltipSamples.kt
+++ b/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/TooltipSamples.kt
@@ -50,7 +50,7 @@
 @Composable
 fun PlainTooltipSample() {
     TooltipBox(
-        positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(),
+        positionProvider = TooltipDefaults.rememberTooltipPositionProvider(),
         tooltip = { PlainTooltip { Text("Add to favorites") } },
         state = rememberTooltipState()
     ) {
@@ -69,7 +69,7 @@
     val scope = rememberCoroutineScope()
     Column(horizontalAlignment = Alignment.CenterHorizontally) {
         TooltipBox(
-            positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(),
+            positionProvider = TooltipDefaults.rememberTooltipPositionProvider(),
             tooltip = { PlainTooltip { Text("Add to list") } },
             state = tooltipState
         ) {
@@ -87,7 +87,7 @@
 @Composable
 fun PlainTooltipWithCaret() {
     TooltipBox(
-        positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(),
+        positionProvider = TooltipDefaults.rememberTooltipPositionProvider(),
         tooltip = {
             PlainTooltip(caretSize = TooltipDefaults.caretSize) { Text("Add to favorites") }
         },
@@ -104,7 +104,7 @@
 @Composable
 fun PlainTooltipWithCustomCaret() {
     TooltipBox(
-        positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(),
+        positionProvider = TooltipDefaults.rememberTooltipPositionProvider(),
         tooltip = { PlainTooltip(caretSize = DpSize(24.dp, 12.dp)) { Text("Add to favorites") } },
         state = rememberTooltipState()
     ) {
@@ -121,7 +121,7 @@
     val tooltipState = rememberTooltipState(isPersistent = true)
     val scope = rememberCoroutineScope()
     TooltipBox(
-        positionProvider = TooltipDefaults.rememberRichTooltipPositionProvider(),
+        positionProvider = TooltipDefaults.rememberTooltipPositionProvider(),
         tooltip = {
             RichTooltip(
                 title = { Text(richTooltipSubheadText) },
@@ -150,7 +150,7 @@
     val scope = rememberCoroutineScope()
     Column(horizontalAlignment = Alignment.CenterHorizontally) {
         TooltipBox(
-            positionProvider = TooltipDefaults.rememberRichTooltipPositionProvider(),
+            positionProvider = TooltipDefaults.rememberTooltipPositionProvider(),
             tooltip = {
                 RichTooltip(
                     title = { Text(richTooltipSubheadText) },
@@ -181,7 +181,7 @@
     val tooltipState = rememberTooltipState(isPersistent = true)
     val scope = rememberCoroutineScope()
     TooltipBox(
-        positionProvider = TooltipDefaults.rememberRichTooltipPositionProvider(),
+        positionProvider = TooltipDefaults.rememberTooltipPositionProvider(),
         tooltip = {
             RichTooltip(
                 title = { Text(richTooltipSubheadText) },
@@ -210,7 +210,7 @@
     val tooltipState = rememberTooltipState(isPersistent = true)
     val scope = rememberCoroutineScope()
     TooltipBox(
-        positionProvider = TooltipDefaults.rememberRichTooltipPositionProvider(),
+        positionProvider = TooltipDefaults.rememberTooltipPositionProvider(),
         tooltip = {
             RichTooltip(
                 title = { Text(richTooltipSubheadText) },
diff --git a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/BottomSheetScaffoldTest.kt b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/BottomSheetScaffoldTest.kt
index 40418e9..16a6375 100644
--- a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/BottomSheetScaffoldTest.kt
+++ b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/BottomSheetScaffoldTest.kt
@@ -252,7 +252,12 @@
                 skipPartiallyExpanded = false,
                 skipHiddenState = true,
                 initialValue = SheetValue.PartiallyExpanded,
-                density = rule.density
+                positionalThreshold = {
+                    with(rule.density) { BottomSheetDefaults.PositionalThreshold.toPx() }
+                },
+                velocityThreshold = {
+                    with(rule.density) { BottomSheetDefaults.VelocityThreshold.toPx() }
+                },
             )
         rule.setContent {
             scope = rememberCoroutineScope()
@@ -923,7 +928,16 @@
             )
         var sheetCoords: LayoutCoordinates? = null
         var rootCoords: LayoutCoordinates? = null
-        val state = SheetState(false, density = Density(1f))
+        val state =
+            SheetState(
+                skipPartiallyExpanded = false,
+                positionalThreshold = {
+                    with(rule.density) { BottomSheetDefaults.PositionalThreshold.toPx() }
+                },
+                velocityThreshold = {
+                    with(rule.density) { BottomSheetDefaults.VelocityThreshold.toPx() }
+                },
+            )
         var sheetValue by mutableStateOf(SheetValue.Hidden)
         rule.setContent {
             Box(Modifier.onGloballyPositioned { rootCoords = it }.offset { offset }) {
@@ -983,7 +997,16 @@
                 IntOffset(100, 10),
             )
         var sheetCoords: LayoutCoordinates? = null
-        val state = SheetState(false, density = Density(1f))
+        val state =
+            SheetState(
+                skipPartiallyExpanded = false,
+                positionalThreshold = {
+                    with(rule.density) { BottomSheetDefaults.PositionalThreshold.toPx() }
+                },
+                velocityThreshold = {
+                    with(rule.density) { BottomSheetDefaults.VelocityThreshold.toPx() }
+                },
+            )
         var sheetValue by mutableStateOf(SheetValue.Hidden)
         rule.setContent {
             LaunchedEffect(sheetValue) {
diff --git a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/ExposedDropdownMenuTest.kt b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/ExposedDropdownMenuTest.kt
index 6453fe4..a6dc9a7 100644
--- a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/ExposedDropdownMenuTest.kt
+++ b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/ExposedDropdownMenuTest.kt
@@ -84,6 +84,7 @@
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.runBlocking
 import org.junit.Assume.assumeNotNull
+import org.junit.Ignore
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -187,7 +188,11 @@
         rule.onNodeWithTag(EDMTag).assertIsDisplayed()
         rule.onNodeWithTag(MenuItemTag).assertIsDisplayed()
 
-        UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()).pressBack()
+        val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
+        // First back closes keyboard
+        device.pressBack()
+        // Second back closes menu
+        device.pressBack()
 
         rule.onNodeWithTag(TFTag).assertIsDisplayed()
         rule.onNodeWithTag(MenuItemTag).assertDoesNotExist()
@@ -261,6 +266,7 @@
         rule.onNodeWithTag(MenuItemTag).assertDoesNotExist()
     }
 
+    @Ignore("b/374850853")
     @Test
     fun edm_editable_collapsesOnEscapePress() {
         rule.setMaterialContent(lightColorScheme()) {
@@ -531,6 +537,46 @@
     }
 
     @Test
+    fun edm_anchorTypeIsUpdated_evenIfTextFieldIsNotClicked() {
+        var expanded by mutableStateOf(false)
+        var type: ExposedDropdownMenuAnchorType? = null
+        rule.setMaterialContent(lightColorScheme()) {
+            ExposedDropdownMenuBox(
+                expanded = expanded,
+                onExpandedChange = { expanded = it },
+            ) {
+                TextField(
+                    modifier = Modifier.menuAnchor(ExposedDropdownMenuAnchorType.PrimaryEditable),
+                    state = rememberTextFieldState(),
+                    lineLimits = TextFieldLineLimits.SingleLine,
+                    label = { Text("Label") },
+                    trailingIcon = {
+                        ExposedDropdownMenuDefaults.TrailingIcon(
+                            expanded = expanded,
+                            modifier =
+                                Modifier.menuAnchor(
+                                    ExposedDropdownMenuAnchorType.SecondaryEditable
+                                ),
+                        )
+                    }
+                )
+                ExposedDropdownMenu(
+                    expanded = expanded,
+                    onDismissRequest = { expanded = false },
+                ) {
+                    DropdownMenuItem(
+                        text = { Text(OptionName) },
+                        onClick = {},
+                    )
+                }
+                SideEffect { type = anchorType }
+            }
+        }
+        rule.runOnIdle { expanded = true }
+        assertThat(type).isEqualTo(ExposedDropdownMenuAnchorType.PrimaryEditable)
+    }
+
+    @Test
     fun edm_widthMatchesTextFieldWidth() {
         var textFieldBounds by mutableStateOf(Rect.Zero)
         var menuBounds by mutableStateOf(Rect.Zero)
diff --git a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/ModalBottomSheetTest.kt b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/ModalBottomSheetTest.kt
index 8fc3131..1293b79 100644
--- a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/ModalBottomSheetTest.kt
+++ b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/ModalBottomSheetTest.kt
@@ -125,9 +125,20 @@
     @Test
     fun modalBottomSheet_isDismissedOnTapOutside() {
         var showBottomSheet by mutableStateOf(true)
-        val sheetState = SheetState(skipPartiallyExpanded = false, density = rule.density)
+        lateinit var sheetState: SheetState
 
         rule.setContent {
+            val density = LocalDensity.current
+            sheetState =
+                SheetState(
+                    skipPartiallyExpanded = false,
+                    positionalThreshold = {
+                        with(density) { BottomSheetDefaults.PositionalThreshold.toPx() }
+                    },
+                    velocityThreshold = {
+                        with(density) { BottomSheetDefaults.VelocityThreshold.toPx() }
+                    },
+                )
             if (showBottomSheet) {
                 ModalBottomSheet(
                     sheetState = sheetState,
@@ -160,8 +171,16 @@
     @Test
     fun modalBottomSheet_isDismissedOnSwipeDown() {
         var showBottomSheet by mutableStateOf(true)
-        val sheetState = SheetState(skipPartiallyExpanded = false, density = rule.density)
-
+        val sheetState =
+            SheetState(
+                skipPartiallyExpanded = false,
+                positionalThreshold = {
+                    with(rule.density) { BottomSheetDefaults.PositionalThreshold.toPx() }
+                },
+                velocityThreshold = {
+                    with(rule.density) { BottomSheetDefaults.VelocityThreshold.toPx() }
+                },
+            )
         rule.setContent {
             if (showBottomSheet) {
                 ModalBottomSheet(
@@ -362,9 +381,20 @@
     @Test
     fun modalBottomSheet_shortSheet_isDismissedOnBackPress() {
         var showBottomSheet by mutableStateOf(true)
-        val sheetState = SheetState(skipPartiallyExpanded = true, density = rule.density)
+        lateinit var sheetState: SheetState
 
         rule.setContent {
+            val density = LocalDensity.current
+            sheetState =
+                SheetState(
+                    skipPartiallyExpanded = true,
+                    positionalThreshold = {
+                        with(density) { BottomSheetDefaults.PositionalThreshold.toPx() }
+                    },
+                    velocityThreshold = {
+                        with(density) { BottomSheetDefaults.VelocityThreshold.toPx() }
+                    },
+                )
             val dispatcher = LocalOnBackPressedDispatcherOwner.current!!.onBackPressedDispatcher
             if (showBottomSheet) {
                 ModalBottomSheet(
@@ -395,9 +425,20 @@
     @Test
     fun modalBottomSheet_tallSheet_isDismissedOnBackPress() {
         var showBottomSheet by mutableStateOf(true)
-        val sheetState = SheetState(skipPartiallyExpanded = false, density = rule.density)
+        lateinit var sheetState: SheetState
 
         rule.setContent {
+            val density = LocalDensity.current
+            sheetState =
+                SheetState(
+                    skipPartiallyExpanded = false,
+                    positionalThreshold = {
+                        with(density) { BottomSheetDefaults.PositionalThreshold.toPx() }
+                    },
+                    velocityThreshold = {
+                        with(density) { BottomSheetDefaults.VelocityThreshold.toPx() }
+                    },
+                )
             val dispatcher = LocalOnBackPressedDispatcherOwner.current!!.onBackPressedDispatcher
             if (showBottomSheet) {
                 ModalBottomSheet(
@@ -611,10 +652,21 @@
     fun modalBottomSheet_missingAnchors_findsClosest() {
         val topTag = "ModalBottomSheetLayout"
         var showShortContent by mutableStateOf(false)
-        val sheetState = SheetState(skipPartiallyExpanded = false, density = rule.density)
+        lateinit var sheetState: SheetState
         lateinit var scope: CoroutineScope
 
         rule.setContent {
+            val density = LocalDensity.current
+            sheetState =
+                SheetState(
+                    skipPartiallyExpanded = false,
+                    positionalThreshold = {
+                        with(density) { BottomSheetDefaults.PositionalThreshold.toPx() }
+                    },
+                    velocityThreshold = {
+                        with(density) { BottomSheetDefaults.VelocityThreshold.toPx() }
+                    },
+                )
             scope = rememberCoroutineScope()
             ModalBottomSheet(
                 onDismissRequest = {},
@@ -790,8 +842,20 @@
     @Test
     fun modalBottomSheet_testParialExpandReturnsIllegalStateException_whenSkipPartialExpanded() {
         lateinit var scope: CoroutineScope
-        val bottomSheetState = SheetState(skipPartiallyExpanded = true, density = rule.density)
+        lateinit var bottomSheetState: SheetState
+
         rule.setContent {
+            val density = LocalDensity.current
+            bottomSheetState =
+                SheetState(
+                    skipPartiallyExpanded = true,
+                    positionalThreshold = {
+                        with(density) { BottomSheetDefaults.PositionalThreshold.toPx() }
+                    },
+                    velocityThreshold = {
+                        with(density) { BottomSheetDefaults.VelocityThreshold.toPx() }
+                    },
+                )
             scope = rememberCoroutineScope()
             ModalBottomSheet(
                 onDismissRequest = {},
@@ -931,10 +995,22 @@
 
     @Test
     fun modalBottomSheet_shortSheet_anchorChangeHandler_previousTargetNotInAnchors_reconciles() {
-        val sheetState = SheetState(skipPartiallyExpanded = false, density = rule.density)
         var hasSheetContent by mutableStateOf(false) // Start out with empty sheet content
         lateinit var scope: CoroutineScope
+        lateinit var sheetState: SheetState
+
         rule.setContent {
+            val density = LocalDensity.current
+            sheetState =
+                SheetState(
+                    skipPartiallyExpanded = false,
+                    positionalThreshold = {
+                        with(density) { BottomSheetDefaults.PositionalThreshold.toPx() }
+                    },
+                    velocityThreshold = {
+                        with(density) { BottomSheetDefaults.VelocityThreshold.toPx() }
+                    },
+                )
             scope = rememberCoroutineScope()
 
             ModalBottomSheet(
@@ -968,10 +1044,22 @@
 
     @Test
     fun modalBottomSheet_tallSheet_anchorChangeHandler_previousTargetNotInAnchors_reconciles() {
-        val sheetState = SheetState(skipPartiallyExpanded = false, density = rule.density)
         var hasSheetContent by mutableStateOf(false) // Start out with empty sheet content
         lateinit var scope: CoroutineScope
+        lateinit var sheetState: SheetState
+
         rule.setContent {
+            val density = LocalDensity.current
+            sheetState =
+                SheetState(
+                    skipPartiallyExpanded = false,
+                    positionalThreshold = {
+                        with(density) { BottomSheetDefaults.PositionalThreshold.toPx() }
+                    },
+                    velocityThreshold = {
+                        with(density) { BottomSheetDefaults.VelocityThreshold.toPx() }
+                    },
+                )
             scope = rememberCoroutineScope()
             ModalBottomSheet(
                 onDismissRequest = {},
@@ -1006,8 +1094,6 @@
     fun modalBottomSheet_callsOnDismissRequest_onNestedScrollFling() {
         var callCount by mutableStateOf(0)
         val expectedCallCount = 1
-        val sheetState = SheetState(skipPartiallyExpanded = true, density = rule.density)
-
         val nestedScrollDispatcher = NestedScrollDispatcher()
         val nestedScrollConnection =
             object : NestedScrollConnection {
@@ -1015,7 +1101,20 @@
             }
         lateinit var scope: CoroutineScope
 
+        lateinit var sheetState: SheetState
+
         rule.setContent {
+            val density = LocalDensity.current
+            sheetState =
+                SheetState(
+                    skipPartiallyExpanded = true,
+                    positionalThreshold = {
+                        with(density) { BottomSheetDefaults.PositionalThreshold.toPx() }
+                    },
+                    velocityThreshold = {
+                        with(density) { BottomSheetDefaults.VelocityThreshold.toPx() }
+                    },
+                )
             scope = rememberCoroutineScope()
             ModalBottomSheet(
                 onDismissRequest = { callCount += 1 },
diff --git a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/TooltipScreenshotTest.kt b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/TooltipScreenshotTest.kt
index feb118a..f2b416d 100644
--- a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/TooltipScreenshotTest.kt
+++ b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/TooltipScreenshotTest.kt
@@ -120,7 +120,7 @@
     private fun PlainTooltipTest() {
         val tooltipState = rememberTooltipState()
         TooltipBox(
-            positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(),
+            positionProvider = TooltipDefaults.rememberTooltipPositionProvider(),
             tooltip = {
                 PlainTooltip(modifier = Modifier.testTag(TooltipTestTag)) {
                     Text("Tooltip Description")
@@ -137,7 +137,7 @@
     private fun RichTooltipTest() {
         val tooltipState = rememberTooltipState(isPersistent = true)
         TooltipBox(
-            positionProvider = TooltipDefaults.rememberRichTooltipPositionProvider(),
+            positionProvider = TooltipDefaults.rememberTooltipPositionProvider(),
             tooltip = {
                 RichTooltip(
                     title = { Text("Title") },
diff --git a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/TooltipTest.kt b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/TooltipTest.kt
index 0cfc573..fccc9c2 100644
--- a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/TooltipTest.kt
+++ b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/TooltipTest.kt
@@ -465,9 +465,7 @@
 
         // Plain tooltip positioning
         lateinit var positionProvider: PopupPositionProvider
-        rule.setContent {
-            positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider()
-        }
+        rule.setContent { positionProvider = TooltipDefaults.rememberTooltipPositionProvider() }
 
         val tooltipPosition =
             positionProvider.calculatePosition(
@@ -500,7 +498,7 @@
 
         // Rich tooltip positioning
         lateinit var positionProvider: PopupPositionProvider
-        rule.setContent { positionProvider = TooltipDefaults.rememberRichTooltipPositionProvider() }
+        rule.setContent { positionProvider = TooltipDefaults.rememberTooltipPositionProvider() }
 
         val tooltipPosition =
             positionProvider.calculatePosition(
@@ -521,7 +519,7 @@
         var anchorBounds = Rect.Zero
         rule.setContent {
             TooltipBox(
-                positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(),
+                positionProvider = TooltipDefaults.rememberTooltipPositionProvider(),
                 state = rememberTooltipState(initialIsVisible = true, isPersistent = true),
                 tooltip = {
                     PlainTooltip(
@@ -565,7 +563,7 @@
         var anchorBounds = Rect.Zero
         rule.setContent {
             TooltipBox(
-                positionProvider = TooltipDefaults.rememberRichTooltipPositionProvider(),
+                positionProvider = TooltipDefaults.rememberTooltipPositionProvider(),
                 state = rememberTooltipState(initialIsVisible = true, isPersistent = true),
                 tooltip = {
                     RichTooltip(
@@ -615,7 +613,7 @@
             topState = rememberTooltipState(isPersistent = true)
             bottomState = rememberTooltipState(isPersistent = true)
             TooltipBox(
-                positionProvider = TooltipDefaults.rememberRichTooltipPositionProvider(),
+                positionProvider = TooltipDefaults.rememberTooltipPositionProvider(),
                 tooltip = {
                     RichTooltip(
                         title = {
@@ -636,7 +634,7 @@
             scope.launch { topState.show() }
 
             TooltipBox(
-                positionProvider = TooltipDefaults.rememberRichTooltipPositionProvider(),
+                positionProvider = TooltipDefaults.rememberTooltipPositionProvider(),
                 tooltip = {
                     RichTooltip(
                         title = {
@@ -679,7 +677,7 @@
             val scope = rememberCoroutineScope()
             topState = rememberTooltipState(isPersistent = true, mutatorMutex = MutatorMutex())
             TooltipBox(
-                positionProvider = TooltipDefaults.rememberRichTooltipPositionProvider(),
+                positionProvider = TooltipDefaults.rememberTooltipPositionProvider(),
                 tooltip = {
                     RichTooltip(
                         title = {
@@ -701,7 +699,7 @@
 
             bottomState = rememberTooltipState(isPersistent = true, mutatorMutex = MutatorMutex())
             TooltipBox(
-                positionProvider = TooltipDefaults.rememberRichTooltipPositionProvider(),
+                positionProvider = TooltipDefaults.rememberTooltipPositionProvider(),
                 tooltip = {
                     RichTooltip(
                         title = {
@@ -741,7 +739,7 @@
         tooltipState: TooltipState = rememberTooltipState(),
     ) {
         TooltipBox(
-            positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(),
+            positionProvider = TooltipDefaults.rememberTooltipPositionProvider(),
             tooltip = {
                 PlainTooltip(
                     modifier = modifier.testTag(ContainerTestTag),
@@ -763,7 +761,7 @@
         tooltipState: TooltipState = rememberTooltipState(action != null),
     ) {
         TooltipBox(
-            positionProvider = TooltipDefaults.rememberRichTooltipPositionProvider(),
+            positionProvider = TooltipDefaults.rememberTooltipPositionProvider(),
             tooltip = {
                 RichTooltip(
                     title = title,
@@ -782,7 +780,7 @@
     fun plainTooltip_withClickable_hasCorrectSemantics() {
         rule.setMaterialContent(lightColorScheme()) {
             TooltipBox(
-                positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(),
+                positionProvider = TooltipDefaults.rememberTooltipPositionProvider(),
                 tooltip = {
                     PlainTooltip(
                         modifier = Modifier.testTag(ContainerTestTag),
diff --git a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/WavyProgressIndicatorTest.kt b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/WavyProgressIndicatorTest.kt
index b4fa43b..edfc828 100644
--- a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/WavyProgressIndicatorTest.kt
+++ b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/WavyProgressIndicatorTest.kt
@@ -161,21 +161,29 @@
     fun determinateLinearWavyProgressIndicator_sizeModifier() {
         val expectedWidth = 100.dp
         val expectedHeight = 10.dp
-        val expectedSize =
-            with(rule.density) { IntSize(expectedWidth.roundToPx(), expectedHeight.roundToPx()) }
         val tag = "linear"
-        var trackColor = Color.Unspecified
-        var progressColor = Color.Unspecified
-        rule.setContent {
-            trackColor = ProgressIndicatorDefaults.linearTrackColor
-            progressColor = ProgressIndicatorDefaults.linearColor
-
-            Box(Modifier.testTag(tag)) {
+        val contentToTest =
+            rule.setMaterialContentForSizeAssertions {
                 LinearWavyProgressIndicator(
-                    modifier = Modifier.size(expectedWidth, expectedHeight),
+                    modifier = Modifier.size(expectedWidth, expectedHeight).testTag(tag),
                     progress = { 0.5f }
                 )
             }
+
+        contentToTest.assertWidthIsEqualTo(expectedWidth).assertHeightIsEqualTo(expectedHeight)
+    }
+
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+    @Test
+    fun determinateLinearWavyProgressIndicator_colors() {
+        val tag = "linear"
+        var trackColor = Color.Unspecified
+        var progressColor = Color.Unspecified
+        rule.setMaterialContentForSizeAssertions {
+            trackColor = ProgressIndicatorDefaults.linearTrackColor
+            progressColor = ProgressIndicatorDefaults.linearColor
+
+            Box(Modifier.testTag(tag)) { LinearWavyProgressIndicator(progress = { 0.5f }) }
         }
 
         rule
@@ -183,11 +191,6 @@
             .captureToImage()
             .assertContainsColor(trackColor)
             .assertContainsColor(progressColor)
-            .toPixelMap()
-            .let {
-                assertEquals(expectedSize.width, it.width)
-                assertEquals(expectedSize.height, it.height)
-            }
     }
 
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
@@ -195,24 +198,29 @@
     fun indeterminateLinearWavyProgressIndicator_sizeModifier() {
         val expectedWidth = 100.dp
         val expectedHeight = 10.dp
-        val expectedSize =
-            with(rule.density) { IntSize(expectedWidth.roundToPx(), expectedHeight.roundToPx()) }
-        rule.mainClock.autoAdvance = false
         val tag = "linear"
-        rule.setContent {
-            Box(Modifier.testTag(tag)) {
+        val contentToTest =
+            rule.setMaterialContentForSizeAssertions {
                 LinearWavyProgressIndicator(
-                    modifier = Modifier.size(expectedWidth, expectedHeight),
-                    color = Color.Blue
+                    modifier = Modifier.size(expectedWidth, expectedHeight).testTag(tag),
                 )
             }
+
+        contentToTest.assertWidthIsEqualTo(expectedWidth).assertHeightIsEqualTo(expectedHeight)
+    }
+
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+    @Test
+    fun indeterminateLinearWavyProgressIndicator_colors() {
+        rule.mainClock.autoAdvance = false
+        val tag = "linear"
+        rule.setMaterialContentForSizeAssertions {
+            Box(Modifier.testTag(tag)) { LinearWavyProgressIndicator(color = Color.Blue) }
         }
 
         rule.mainClock.advanceTimeBy(300)
 
         rule.onNodeWithTag(tag).captureToImage().toPixelMap().let {
-            assertEquals(expectedSize.width, it.width)
-            assertEquals(expectedSize.height, it.height)
             // Assert that a center pixel relatively at the start of the path has the right
             // progress color.
             it.assertPixelColor(Color.Blue, 5, it.height / 2)
diff --git a/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/ExposedDropdownMenu.android.kt b/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/ExposedDropdownMenu.android.kt
index 9c9a97b..d67fed8 100644
--- a/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/ExposedDropdownMenu.android.kt
+++ b/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/ExposedDropdownMenu.android.kt
@@ -68,6 +68,8 @@
 import androidx.compose.ui.layout.layout
 import androidx.compose.ui.layout.onGloballyPositioned
 import androidx.compose.ui.layout.positionInWindow
+import androidx.compose.ui.node.ModifierNodeElement
+import androidx.compose.ui.platform.InspectorInfo
 import androidx.compose.ui.platform.LocalConfiguration
 import androidx.compose.ui.platform.LocalDensity
 import androidx.compose.ui.platform.LocalSoftwareKeyboardController
@@ -168,6 +170,13 @@
                 ): Modifier =
                     this.focusRequester(focusRequester)
                         .then(
+                            ExposedDropdownMenuAnchorElement {
+                                if (type.hasGreaterOrEqualPriorityThan(anchorTypeState.value)) {
+                                    anchorTypeState.value = type
+                                }
+                            }
+                        )
+                        .then(
                             if (!enabled) Modifier
                             else
                                 Modifier.expandable(
@@ -516,6 +525,17 @@
     override fun toString(): String = name
 }
 
+private fun ExposedDropdownMenuAnchorType.hasGreaterOrEqualPriorityThan(
+    that: ExposedDropdownMenuAnchorType
+): Boolean =
+    when (this) {
+        ExposedDropdownMenuAnchorType.PrimaryNotEditable,
+        ExposedDropdownMenuAnchorType.PrimaryEditable -> true
+        ExposedDropdownMenuAnchorType.SecondaryEditable ->
+            that == ExposedDropdownMenuAnchorType.SecondaryEditable
+        else -> false
+    }
+
 @Deprecated(
     message = "Renamed to ExposedDropdownMenuAnchorType",
     replaceWith = ReplaceWith("ExposedDropdownMenuAnchorType"),
@@ -1434,6 +1454,29 @@
     }
 }
 
+private data class ExposedDropdownMenuAnchorElement(
+    val updateStateOnAttach: () -> Unit,
+) : ModifierNodeElement<ExposedDropdownMenuAnchorNode>() {
+    override fun create() = ExposedDropdownMenuAnchorNode(updateStateOnAttach)
+
+    override fun update(node: ExposedDropdownMenuAnchorNode) {
+        node.updateStateOnAttach = updateStateOnAttach
+    }
+
+    override fun InspectorInfo.inspectableProperties() {
+        name = "exposedDropdownMenuAnchorType"
+        properties["updateStateOnAttach"] = updateStateOnAttach
+    }
+}
+
+private class ExposedDropdownMenuAnchorNode(
+    var updateStateOnAttach: () -> Unit,
+) : Modifier.Node() {
+    override fun onAttach() {
+        updateStateOnAttach()
+    }
+}
+
 private fun Modifier.expandable(
     expanded: Boolean,
     onExpandedChange: () -> Unit,
diff --git a/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/Tooltip.android.kt b/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/Tooltip.android.kt
index c2c9412..ffa265c 100644
--- a/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/Tooltip.android.kt
+++ b/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/Tooltip.android.kt
@@ -125,7 +125,6 @@
             val configuration = LocalConfiguration.current
             Modifier.drawCaret { anchorLayoutCoordinates ->
                     drawCaretWithPath(
-                        CaretType.Plain,
                         density,
                         configuration,
                         containerColor,
@@ -253,7 +252,6 @@
             val configuration = LocalConfiguration.current
             Modifier.drawCaret { anchorLayoutCoordinates ->
                     drawCaretWithPath(
-                        CaretType.Rich,
                         density,
                         configuration,
                         elevatedColor,
@@ -315,7 +313,6 @@
 
 @ExperimentalMaterial3Api
 private fun CacheDrawScope.drawCaretWithPath(
-    caretType: CaretType,
     density: Density,
     configuration: Configuration,
     containerColor: Color,
@@ -351,42 +348,27 @@
                 tooltipHeight
             }
 
-        val position: Offset
-        if (caretType == CaretType.Plain) {
-            position =
-                if (anchorMid + tooltipWidth / 2 > screenWidthPx) {
-                    // Caret needs to be near the right
-                    val anchorMidFromRightScreenEdge = screenWidthPx - anchorMid
-                    val caretX = tooltipWidth - anchorMidFromRightScreenEdge
-                    Offset(caretX, caretY)
-                } else {
-                    // Caret needs to be near the left
-                    val tooltipLeft = anchorLeft - (this.size.width / 2 - anchorWidth / 2)
-                    val caretX = anchorMid - maxOf(tooltipLeft, 0f)
-                    Offset(caretX, caretY)
-                }
-        } else {
-            // Default the caret to the left
-            var preferredPosition = Offset(anchorMid - anchorLeft, caretY)
-            if (anchorLeft + tooltipWidth > screenWidthPx) {
-                // Need to move the caret to the right
-                preferredPosition = Offset(anchorMid - (anchorRight - tooltipWidth), caretY)
-                if (anchorRight - tooltipWidth < 0) {
-                    // Need to center the caret
-                    // Caret might need to be offset depending on where
-                    // the tooltip is placed relative to the anchor
-                    if (anchorLeft - tooltipWidth / 2 + anchorWidth / 2 <= 0) {
-                        preferredPosition = Offset(anchorMid, caretY)
-                    } else if (anchorRight + tooltipWidth / 2 - anchorWidth / 2 >= screenWidthPx) {
-                        val anchorMidFromRightScreenEdge = screenWidthPx - anchorMid
-                        val caretX = tooltipWidth - anchorMidFromRightScreenEdge
-                        preferredPosition = Offset(caretX, caretY)
-                    } else {
-                        preferredPosition = Offset(tooltipWidth / 2, caretY)
-                    }
-                }
+        // Default the caret to be in the middle
+        // caret might need to be offset depending on where
+        // the tooltip is placed relative to the anchor
+        var position: Offset =
+            if (anchorLeft - tooltipWidth / 2 + anchorWidth / 2 <= 0) {
+                Offset(anchorMid, caretY)
+            } else if (anchorRight + tooltipWidth / 2 - anchorWidth / 2 >= screenWidthPx) {
+                val anchorMidFromRightScreenEdge = screenWidthPx - anchorMid
+                val caretX = tooltipWidth - anchorMidFromRightScreenEdge
+                Offset(caretX, caretY)
+            } else {
+                Offset(tooltipWidth / 2, caretY)
             }
-            position = preferredPosition
+        if (anchorMid - tooltipWidth / 2 < 0) {
+            // The tooltip needs to be start aligned if it would collide with the left side of
+            // screen.
+            position = Offset(anchorMid - anchorLeft, caretY)
+        } else if (anchorMid + tooltipWidth / 2 > screenWidthPx) {
+            // The tooltip needs to be end aligned if it would collide with the right side of the
+            // screen.
+            position = Offset(anchorMid - (anchorRight - tooltipWidth), caretY)
         }
 
         if (isCaretTop) {
@@ -415,9 +397,3 @@
         }
     }
 }
-
-@ExperimentalMaterial3Api
-private enum class CaretType {
-    Plain,
-    Rich
-}
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/DragHandle.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/DragHandle.kt
new file mode 100644
index 0000000..da5127e
--- /dev/null
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/DragHandle.kt
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2024 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.gestures.PressGestureScope
+import androidx.compose.foundation.gestures.detectTapGestures
+import androidx.compose.foundation.hoverable
+import androidx.compose.foundation.indication
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.interaction.collectIsDraggedAsState
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.DragHandleDefaults.dragHandleColors
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.Immutable
+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.draw.drawBehind
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.Shape
+import androidx.compose.ui.graphics.graphicsLayer
+import androidx.compose.ui.graphics.isSpecified
+import androidx.compose.ui.input.pointer.pointerInput
+import androidx.compose.ui.layout.layout
+import androidx.compose.ui.unit.Constraints
+import androidx.compose.ui.unit.DpSize
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.util.fastRoundToInt
+
+@Composable
+internal fun VerticalDragHandle(
+    modifier: Modifier = Modifier,
+    sizes: DragHandleSizes = DragHandleDefaults.DefaultDragHandleSizes,
+    colors: DragHandleColors = MaterialTheme.colorScheme.dragHandleColors(),
+    shapes: DragHandleShapes = DragHandleDefaults.DefaultDragHandleShapes,
+    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
+) {
+    val isDragged by interactionSource.collectIsDraggedAsState()
+    var isPressed by remember { mutableStateOf(false) }
+    Box(
+        modifier =
+            modifier
+                .minimumInteractiveComponentSize()
+                .hoverable(interactionSource)
+                .pressable(interactionSource) { _ ->
+                    isPressed = true
+                    tryAwaitRelease()
+                    isPressed = false
+                }
+                .graphicsLayer {
+                    shape = if (isDragged || isPressed) shapes.pressedShape else shapes.defaultShape
+                    clip = true
+                }
+                .layout { measurable, _ ->
+                    val dragHandleSize =
+                        if (isDragged || isPressed) {
+                                sizes.pressedSize
+                            } else {
+                                sizes.defaultSize
+                            }
+                            .toSize()
+                    // set constraints here to be the size needed
+                    val placeable =
+                        measurable.measure(
+                            Constraints.fixed(
+                                dragHandleSize.width.fastRoundToInt(),
+                                dragHandleSize.height.fastRoundToInt()
+                            )
+                        )
+                    layout(placeable.width, placeable.height) { placeable.placeRelative(0, 0) }
+                }
+                .drawBehind {
+                    drawRect(
+                        if (isDragged || isPressed) colors.pressedColor else colors.defaultColor
+                    )
+                }
+                .indication(interactionSource, ripple())
+    )
+}
+
+@Immutable
+internal class DragHandleColors(val defaultColor: Color, val pressedColor: Color) {
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other == null || other !is DragHandleColors) return false
+        if (defaultColor != other.defaultColor) return false
+        if (pressedColor != other.pressedColor) return false
+        return true
+    }
+
+    override fun hashCode(): Int {
+        var result = defaultColor.hashCode()
+        result = 31 * result + pressedColor.hashCode()
+        return result
+    }
+}
+
+@Immutable
+internal class DragHandleShapes(val defaultShape: Shape, val pressedShape: Shape) {
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other == null || other !is DragHandleShapes) return false
+        if (defaultShape != other.defaultShape) return false
+        if (pressedShape != other.pressedShape) return false
+        return true
+    }
+
+    override fun hashCode(): Int {
+        var result = defaultShape.hashCode()
+        result = 31 * result + pressedShape.hashCode()
+        return result
+    }
+}
+
+@Immutable
+internal class DragHandleSizes(val defaultSize: DpSize, val pressedSize: DpSize) {
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other == null || other !is DragHandleSizes) return false
+        if (defaultSize != other.defaultSize) return false
+        if (pressedSize != other.pressedSize) return false
+        return true
+    }
+
+    override fun hashCode(): Int {
+        var result = defaultSize.hashCode()
+        result = 31 * result + pressedSize.hashCode()
+        return result
+    }
+}
+
+// TODO(b/343194663): Introduce tokens and theming
+internal object DragHandleDefaults {
+    @Composable
+    fun dragHandleColors(
+        defaultColor: Color = Color.Unspecified,
+        pressedColor: Color = Color.Unspecified
+    ): DragHandleColors = MaterialTheme.colorScheme.dragHandleColors(defaultColor, pressedColor)
+
+    fun dragHandleShapes(
+        defaultShape: Shape = CircleShape,
+        pressedShape: Shape = RoundedCornerShape(12.dp)
+    ): DragHandleShapes = DragHandleShapes(defaultShape, pressedShape)
+
+    fun dragHandleSizes(
+        defaultSize: DpSize = DpSize(4.dp, 48.dp),
+        pressedSize: DpSize = DpSize(12.dp, 52.dp)
+    ): DragHandleSizes = DragHandleSizes(defaultSize, pressedSize)
+
+    internal fun ColorScheme.dragHandleColors(
+        defaultColor: Color = Color.Unspecified,
+        pressedColor: Color = Color.Unspecified
+    ): DragHandleColors =
+        DragHandleColors(
+            if (defaultColor.isSpecified) defaultColor else outline,
+            if (pressedColor.isSpecified) pressedColor else onSurface
+        )
+
+    internal val DefaultDragHandleShapes = dragHandleShapes()
+
+    internal val DefaultDragHandleSizes = dragHandleSizes()
+}
+
+private fun Modifier.pressable(
+    interactionSource: MutableInteractionSource,
+    onPress: suspend PressGestureScope.(Offset) -> Unit,
+): Modifier = pointerInput(interactionSource) { detectTapGestures(onPress = onPress) }
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
index 27ac94b..b3a8bee 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Label.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Label.kt
@@ -41,7 +41,7 @@
 
 /**
  * Label component that will append a [label] to [content]. The positioning logic uses
- * [TooltipDefaults.rememberPlainTooltipPositionProvider].
+ * [TooltipDefaults.rememberTooltipPositionProvider].
  *
  * Label appended to thumbs of Slider:
  *
@@ -71,7 +71,7 @@
     @Suppress("NAME_SHADOWING")
     val interactionSource = interactionSource ?: remember { MutableInteractionSource() }
     // Has the same positioning logic as PlainTooltips
-    val positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider()
+    val positionProvider = TooltipDefaults.rememberTooltipPositionProvider()
     val state =
         if (isPersistent) remember { LabelStateImpl() }
         else rememberBasicTooltipState(mutatorMutex = MutatorMutex())
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/SheetDefaults.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/SheetDefaults.kt
index 12620b9..66d3d8d 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/SheetDefaults.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/SheetDefaults.kt
@@ -69,8 +69,15 @@
  *   should be skipped. If true, the sheet will always expand to the [Expanded] state and move to
  *   the [Hidden] state if available when hiding the sheet, either programmatically or by user
  *   interaction.
+ * @param positionalThreshold The positional threshold, in px, to be used when calculating the
+ *   target state while a drag is in progress and when settling after the drag ends. This is the
+ *   distance from the start of a transition. It will be, depending on the direction of the
+ *   interaction, added or subtracted from/to the origin offset. It should always be a positive
+ *   value.
+ * @param velocityThreshold The velocity threshold (in px per second) that the end velocity has to
+ *   exceed in order to animate to the next state, even if the [positionalThreshold] has not been
+ *   reached.
  * @param initialValue The initial value of the state.
- * @param density The density that this state can use to convert values to and from dp.
  * @param confirmValueChange Optional callback invoked to confirm or veto a pending state change.
  * @param skipHiddenState Whether the hidden state should be skipped. If true, the sheet will always
  *   expand to the [Expanded] state and move to the [PartiallyExpanded] if available, either
@@ -80,11 +87,13 @@
 @ExperimentalMaterial3Api
 class SheetState(
     internal val skipPartiallyExpanded: Boolean,
-    density: Density,
+    positionalThreshold: () -> Float,
+    velocityThreshold: () -> Float,
     initialValue: SheetValue = Hidden,
     confirmValueChange: (SheetValue) -> Boolean = { true },
     internal val skipHiddenState: Boolean = false,
 ) {
+
     init {
         if (skipPartiallyExpanded) {
             require(initialValue != PartiallyExpanded) {
@@ -270,8 +279,8 @@
             initialValue = initialValue,
             animationSpec = { anchoredDraggableMotionSpec },
             confirmValueChange = confirmValueChange,
-            positionalThreshold = { with(density) { 56.dp.toPx() } },
-            velocityThreshold = { with(density) { 125.dp.toPx() } },
+            positionalThreshold = { positionalThreshold() },
+            velocityThreshold = velocityThreshold,
         )
 
     internal val offset: Float
@@ -285,8 +294,9 @@
         /** The default [Saver] implementation for [SheetState]. */
         fun Saver(
             skipPartiallyExpanded: Boolean,
+            positionalThreshold: () -> Float,
+            velocityThreshold: () -> Float,
             confirmValueChange: (SheetValue) -> Boolean,
-            density: Density,
             skipHiddenState: Boolean,
         ) =
             Saver<SheetState, SheetValue>(
@@ -294,14 +304,53 @@
                 restore = { savedValue ->
                     SheetState(
                         skipPartiallyExpanded,
-                        density,
+                        positionalThreshold,
+                        velocityThreshold,
                         savedValue,
                         confirmValueChange,
                         skipHiddenState,
                     )
                 }
             )
+
+        @Deprecated(
+            level = DeprecationLevel.HIDDEN,
+            message = "Maintained for binary compatibility."
+        )
+        fun Saver(
+            skipPartiallyExpanded: Boolean,
+            confirmValueChange: (SheetValue) -> Boolean,
+            density: Density,
+            skipHiddenState: Boolean,
+        ) =
+            Saver(
+                skipPartiallyExpanded = skipPartiallyExpanded,
+                confirmValueChange = confirmValueChange,
+                skipHiddenState = skipHiddenState,
+                positionalThreshold = {
+                    with(density) { BottomSheetDefaults.PositionalThreshold.toPx() }
+                },
+                velocityThreshold = {
+                    with(density) { BottomSheetDefaults.VelocityThreshold.toPx() }
+                }
+            )
     }
+
+    @Deprecated(level = DeprecationLevel.HIDDEN, message = "Maintained for binary compatibility.")
+    constructor(
+        skipPartiallyExpanded: Boolean,
+        density: Density,
+        initialValue: SheetValue = Hidden,
+        confirmValueChange: (SheetValue) -> Boolean = { true },
+        skipHiddenState: Boolean = false,
+    ) : this(
+        skipPartiallyExpanded = skipPartiallyExpanded,
+        positionalThreshold = { with(density) { BottomSheetDefaults.PositionalThreshold.toPx() } },
+        velocityThreshold = { with(density) { BottomSheetDefaults.VelocityThreshold.toPx() } },
+        initialValue = initialValue,
+        confirmValueChange = confirmValueChange,
+        skipHiddenState = skipHiddenState,
+    )
 }
 
 /** Possible values of [SheetState]. */
@@ -350,6 +399,10 @@
     val windowInsets: WindowInsets
         @Composable get() = WindowInsets.safeDrawing.only(WindowInsetsSides.Bottom)
 
+    internal val PositionalThreshold = 56.dp
+
+    internal val VelocityThreshold = 125.dp
+
     /** The optional visual marker placed on top of a bottom sheet to indicate it may be dragged. */
     @Composable
     fun DragHandle(
@@ -439,8 +492,12 @@
     confirmValueChange: (SheetValue) -> Boolean = { true },
     initialValue: SheetValue = Hidden,
     skipHiddenState: Boolean = false,
+    positionalThreshold: Dp = BottomSheetDefaults.PositionalThreshold,
+    velocityThreshold: Dp = BottomSheetDefaults.VelocityThreshold,
 ): SheetState {
     val density = LocalDensity.current
+    val positionalThresholdToPx = { with(density) { positionalThreshold.toPx() } }
+    val velocityThresholdToPx = { with(density) { velocityThreshold.toPx() } }
     return rememberSaveable(
         skipPartiallyExpanded,
         confirmValueChange,
@@ -448,14 +505,16 @@
         saver =
             SheetState.Saver(
                 skipPartiallyExpanded = skipPartiallyExpanded,
+                positionalThreshold = positionalThresholdToPx,
+                velocityThreshold = velocityThresholdToPx,
                 confirmValueChange = confirmValueChange,
-                density = density,
                 skipHiddenState = skipHiddenState,
             )
     ) {
         SheetState(
             skipPartiallyExpanded,
-            density,
+            positionalThresholdToPx,
+            velocityThresholdToPx,
             initialValue,
             confirmValueChange,
             skipHiddenState,
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 c345413..0784a16 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
@@ -374,6 +374,12 @@
      *
      * @param spacingBetweenTooltipAndAnchor the spacing between the tooltip and the anchor content.
      */
+    @Deprecated(
+        "Deprecated in favor of rememberTooltipPositionProvider API.",
+        replaceWith =
+            ReplaceWith("rememberTooltipPositionProvider(spacingBetweenTooltipAndAnchor)"),
+        level = DeprecationLevel.HIDDEN
+    )
     @Composable
     fun rememberPlainTooltipPositionProvider(
         spacingBetweenTooltipAndAnchor: Dp = SpacingBetweenTooltipAndAnchor
@@ -407,6 +413,12 @@
      *
      * @param spacingBetweenTooltipAndAnchor the spacing between the tooltip and the anchor content.
      */
+    @Deprecated(
+        "Deprecated in favor of rememberTooltipPositionProvider API.",
+        replaceWith =
+            ReplaceWith("rememberTooltipPositionProvider(spacingBetweenTooltipAndAnchor)"),
+        level = DeprecationLevel.HIDDEN
+    )
     @Composable
     fun rememberRichTooltipPositionProvider(
         spacingBetweenTooltipAndAnchor: Dp = SpacingBetweenTooltipAndAnchor
@@ -443,6 +455,53 @@
             }
         }
     }
+
+    /**
+     * [PopupPositionProvider] that should be used with either [RichTooltip] or [PlainTooltip]. It
+     * correctly positions the tooltip in respect to the anchor content.
+     *
+     * @param spacingBetweenTooltipAndAnchor the spacing between the tooltip and the anchor content.
+     */
+    @Composable
+    fun rememberTooltipPositionProvider(
+        spacingBetweenTooltipAndAnchor: Dp = SpacingBetweenTooltipAndAnchor
+    ): PopupPositionProvider {
+        val tooltipAnchorSpacing =
+            with(LocalDensity.current) { spacingBetweenTooltipAndAnchor.roundToPx() }
+        return remember(tooltipAnchorSpacing) {
+            object : PopupPositionProvider {
+                override fun calculatePosition(
+                    anchorBounds: IntRect,
+                    windowSize: IntSize,
+                    layoutDirection: LayoutDirection,
+                    popupContentSize: IntSize
+                ): IntOffset {
+                    // Horizontal alignment preference: middle -> start -> end
+                    // Vertical preference: above -> below
+
+                    // Tooltip prefers to be center aligned horizontally.
+                    var x = anchorBounds.left + (anchorBounds.width - popupContentSize.width) / 2
+
+                    if (x < 0) {
+                        // Make tooltip start aligned if colliding with the
+                        // left side of the screen
+                        x = anchorBounds.left
+                    } else if (x + popupContentSize.width > windowSize.width) {
+                        // Make tooltip end aligned if colliding with the
+                        // right side of the screen
+                        x = anchorBounds.right - popupContentSize.width
+                    }
+
+                    // Tooltip prefers to be above the anchor,
+                    // but if this causes the tooltip to overlap with the anchor
+                    // then we place it below the anchor
+                    var y = anchorBounds.top - popupContentSize.height - tooltipAnchorSpacing
+                    if (y < 0) y = anchorBounds.bottom + tooltipAnchorSpacing
+                    return IntOffset(x, y)
+                }
+            }
+        }
+    }
 }
 
 @Stable
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/WavyProgressIndicator.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/WavyProgressIndicator.kt
index 70fea23..3debdfc 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/WavyProgressIndicator.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/WavyProgressIndicator.kt
@@ -30,7 +30,6 @@
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Spacer
 import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.requiredSizeIn
 import androidx.compose.foundation.layout.size
 import androidx.compose.foundation.progressSemantics
 import androidx.compose.material3.internal.IncreaseVerticalSemanticsBounds
@@ -185,7 +184,6 @@
             .semantics(mergeDescendants = true) {
                 progressBarRangeInfo = ProgressBarRangeInfo(coercedProgress(), 0f..1f)
             }
-            .requiredSizeIn(minWidth = LinearContainerMinWidth)
             .size(
                 width = WavyProgressIndicatorDefaults.LinearContainerWidth,
                 height = WavyProgressIndicatorDefaults.LinearContainerHeight
@@ -373,7 +371,6 @@
         modifier
             .then(IncreaseVerticalSemanticsBounds)
             .progressSemantics()
-            .requiredSizeIn(minWidth = LinearContainerMinWidth)
             .size(
                 WavyProgressIndicatorDefaults.LinearContainerWidth,
                 WavyProgressIndicatorDefaults.LinearContainerHeight
diff --git a/compose/runtime/runtime-test-utils/build.gradle b/compose/runtime/runtime-test-utils/build.gradle
index f5ee280..f9f82e1 100644
--- a/compose/runtime/runtime-test-utils/build.gradle
+++ b/compose/runtime/runtime-test-utils/build.gradle
@@ -19,12 +19,21 @@
 
 plugins {
     id("AndroidXPlugin")
-    id("com.android.library")
     id("AndroidXComposePlugin")
 }
 
 androidXMultiplatform {
-    android()
+    androidLibrary {
+        namespace = "androidx.compose.runtime.testutils"
+        withAndroidTestOnDeviceBuilder {
+            it.compilationName = "instrumentedTest"
+            it.defaultSourceSetName = "androidInstrumentedTest"
+            it.sourceSetTreeName = "test"
+        }
+        withAndroidTestOnJvmBuilder {
+            it.defaultSourceSetName = "androidUnitTest"
+        }
+    }
     jvmStubs()
     linuxX64Stubs()
 
@@ -73,6 +82,3 @@
     description = "Compose runtime test utils shared between runtime and compiler tests."
 }
 
-android {
-    namespace "androidx.compose.runtime.testutils"
-}
diff --git a/compose/runtime/runtime/integration-tests/build.gradle b/compose/runtime/runtime/integration-tests/build.gradle
index 233a8eb..791773c 100644
--- a/compose/runtime/runtime/integration-tests/build.gradle
+++ b/compose/runtime/runtime/integration-tests/build.gradle
@@ -25,12 +25,24 @@
 
 plugins {
     id("AndroidXPlugin")
-    id("com.android.library")
     id("AndroidXComposePlugin")
 }
 
 androidXMultiplatform {
-    android()
+    androidLibrary {
+        namespace = "androidx.compose.runtime.integrationtests"
+        withAndroidTestOnDeviceBuilder {
+            it.compilationName = "instrumentedTest"
+            it.defaultSourceSetName = "androidInstrumentedTest"
+            it.sourceSetTreeName = "test"
+        }
+        withAndroidTestOnJvmBuilder {
+            it.defaultSourceSetName = "androidUnitTest"
+        }
+
+        compileSdk = 35
+        aarMetadata.minCompileSdk = 35
+    }
 
     sourceSets {
         commonMain {
@@ -92,10 +104,6 @@
     }
 }
 
-android {
-    compileSdk 35
-    namespace "androidx.compose.runtime.integrationtests"
-}
 
 tasks.withType(KotlinCompile).configureEach {
     kotlinOptions {
@@ -109,7 +117,7 @@
 }
 
 public File findFile() {
-    project.file("src/androidAndroidTest/kotlin/androidx/compose/runtime/GroupSizeTests.kt")
+    project.file("src/androidInstrumentedTest/kotlin/androidx/compose/runtime/GroupSizeTests.kt")
 }
 
 class UpdateExpectedGroupSizes extends DefaultTask {
diff --git a/compose/ui/ui-geometry/build.gradle b/compose/ui/ui-geometry/build.gradle
index 552d9fb..b9b102b 100644
--- a/compose/ui/ui-geometry/build.gradle
+++ b/compose/ui/ui-geometry/build.gradle
@@ -28,13 +28,21 @@
 
 plugins {
     id("AndroidXPlugin")
-    id("com.android.library")
     id("AndroidXComposePlugin")
 }
 
-
 androidXMultiplatform {
-    android()
+    androidLibrary {
+        namespace = "androidx.compose.ui.geometry"
+        withAndroidTestOnDeviceBuilder {
+            it.compilationName = "instrumentedTest"
+            it.defaultSourceSetName = "androidInstrumentedTest"
+            it.sourceSetTreeName = "test"
+        }
+        withAndroidTestOnJvmBuilder {
+            it.defaultSourceSetName = "androidUnitTest"
+        }
+    }
     jvmStubs()
     linuxX64Stubs()
 
@@ -103,6 +111,3 @@
     kotlinTarget = KotlinTarget.KOTLIN_1_9
 }
 
-android {
-    namespace "androidx.compose.ui.geometry"
-}
diff --git a/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/AlternateViewHelper.kt b/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/AlternateViewHelper.kt
new file mode 100644
index 0000000..5952212
--- /dev/null
+++ b/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/AlternateViewHelper.kt
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2024 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.inspection
+
+import android.annotation.SuppressLint
+import android.app.Activity
+import android.os.Build
+import android.view.SurfaceControlViewHost
+import android.view.View
+import androidx.annotation.RequiresApi
+import androidx.inspection.InspectorEnvironment
+import java.lang.reflect.Field
+import java.lang.reflect.Method
+
+private const val PANEL_ENTITY_CLASS = "com.google.vr.androidx.xr.core.PanelEntity"
+private const val PANEL_ENTITY_IMPL_CLASS =
+    "com.google.vr.realitycore.runtime.androidxr.PanelEntityImpl"
+private const val JXR_CORE_SESSION_CLASS = "com.google.vr.androidx.xr.core.Session"
+
+private const val GET_ENTITIES_OF_TYPE_METHOD = "getEntitiesOfType"
+private const val IS_HIDDEN_METHOD = "isHidden"
+
+private const val SURFACE_CONTROL_VIEW_HOST_FIELD = "surfaceControlViewHost"
+private const val RT_PANEL_ENTITY_FIELD = "rtPanelEntity"
+
+class AlternateViewHelper(private val environment: InspectorEnvironment) {
+    private val activity = environment.artTooling().findInstances(Activity::class.java).first()
+
+    fun getAlternateViews(): List<View> {
+        return try {
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) getExtraViewsImpl() else emptyList()
+        } catch (ex: Exception) {
+            emptyList()
+        }
+    }
+
+    @RequiresApi(Build.VERSION_CODES.R)
+    private fun getExtraViewsImpl(): List<View> {
+        val sessionClass = loadClass(JXR_CORE_SESSION_CLASS)
+        val xrSessions = environment.artTooling().findInstances(sessionClass)
+        return xrSessions.flatMap { getSessionViews(it) }
+    }
+
+    @RequiresApi(Build.VERSION_CODES.R)
+    @SuppressLint("BanUncheckedReflection")
+    private fun getSessionViews(session: Any): List<View> {
+        val entitiesFun =
+            loadMethod(session.javaClass, GET_ENTITIES_OF_TYPE_METHOD, Class::class.java)
+        val entityClass = loadClass(PANEL_ENTITY_CLASS)
+        val entities = entitiesFun.invoke(session, entityClass) as List<*>
+        return entities.mapNotNull { entity -> entity?.let { getView(it) } }
+    }
+
+    @RequiresApi(Build.VERSION_CODES.R)
+    private fun getView(entity: Any): View? {
+        if (isHidden(entity)) {
+            return null
+        }
+        return entity
+            .mapAllFields { field ->
+                if (field.name == RT_PANEL_ENTITY_FIELD) {
+                    getRuntimeEntityView(field.get(entity)!!)
+                } else {
+                    null
+                }
+            }
+            .filterNotNull()
+            .firstOrNull()
+    }
+
+    @SuppressLint("BanUncheckedReflection")
+    private fun isHidden(instance: Any): Boolean {
+        var isHidden = false
+
+        runCatching {
+            instance.mapAllMethods { method ->
+                if (method.name == IS_HIDDEN_METHOD) {
+                    isHidden = method.invoke(instance, true) as Boolean
+                    return@mapAllMethods
+                }
+            }
+        }
+
+        return isHidden
+    }
+
+    @RequiresApi(Build.VERSION_CODES.R)
+    private fun getRuntimeEntityView(instance: Any): View? {
+        val clazz = instance.javaClass
+        if (clazz.name != PANEL_ENTITY_IMPL_CLASS) {
+            return null
+        }
+        val surfaceControlViewHostField = loadField(clazz, SURFACE_CONTROL_VIEW_HOST_FIELD)
+        if (surfaceControlViewHostField != null) {
+            surfaceControlViewHostField.isAccessible = true
+            val surfaceControlViewHost =
+                surfaceControlViewHostField.get(instance) as SurfaceControlViewHost
+            return surfaceControlViewHost.view
+        } else {
+            return null
+        }
+    }
+
+    @Suppress("UnnecessaryLambdaCreation")
+    private fun <T> Any.mapAllFields(block: (filed: Field) -> T): List<T> {
+        var clazz: Class<*>? = javaClass
+        val results = mutableListOf<T>()
+
+        while (clazz != Any::class.java && clazz != null) {
+            results.addAll(loadFields(clazz).map { block(it) })
+
+            // Move to the superclass
+            clazz = clazz.superclass
+        }
+
+        return results
+    }
+
+    @Suppress("UnnecessaryLambdaCreation")
+    private fun <T> Any.mapAllMethods(block: (method: Method) -> T): List<T> {
+        var clazz: Class<*>? = javaClass
+        val results = mutableListOf<T>()
+
+        while (clazz != Any::class.java && clazz != null) {
+            results.addAll(loadMethods(clazz).map { block(it) })
+
+            // Move to the superclass
+            clazz = clazz.superclass
+        }
+
+        return results
+    }
+
+    private fun loadClass(name: String): Class<*> = activity.classLoader.loadClass(name)
+
+    private fun loadMethod(cls: Class<*>, name: String, vararg args: Class<*>): Method =
+        cls.getDeclaredMethod(name, *args).apply { isAccessible = true }
+
+    private fun loadMethods(cls: Class<*>): List<Method> =
+        cls.declaredMethods.map { it.apply { isAccessible = true } }
+
+    private fun loadField(cls: Class<*>, name: String): Field? =
+        runCatching { cls.getDeclaredField(name).apply { isAccessible = true } }.getOrNull()
+
+    private fun loadFields(cls: Class<*>): List<Field> =
+        cls.declaredFields.map { it.apply { it.isAccessible = true } }
+}
diff --git a/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/ComposeLayoutInspector.kt b/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/ComposeLayoutInspector.kt
index e5a9a65..9364f6e 100644
--- a/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/ComposeLayoutInspector.kt
+++ b/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/ComposeLayoutInspector.kt
@@ -18,7 +18,6 @@
 
 import android.util.Log
 import android.view.View
-import android.view.inspector.WindowInspector
 import androidx.collection.LongList
 import androidx.collection.LongObjectMap
 import androidx.collection.MutableLongObjectMap
@@ -116,6 +115,7 @@
         val viewsToSkip: LongList
     )
 
+    private val rootsDetector = RootsDetector(environment)
     private val layoutInspectorTree = LayoutInspectorTree()
     private val recompositionHandler = RecompositionHandler(environment.artTooling())
     private var delayParameterExtractions = false
@@ -472,7 +472,7 @@
         ThreadUtils.assertOnMainThread()
 
         val roots =
-            WindowInspector.getGlobalWindowViews().asSequence().filter { root ->
+            rootsDetector.getRoots().asSequence().filter { root ->
                 root.visibility == View.VISIBLE &&
                     root.isAttachedToWindow &&
                     (generation > 0 || root.uniqueDrawingId == rootViewId)
@@ -516,7 +516,7 @@
     /** Add a slot table to all AndroidComposeViews that doesn't already have one. */
     private fun addSlotTableToComposeViews() =
         ThreadUtils.runOnMainThread {
-                val roots = WindowInspector.getGlobalWindowViews()
+                val roots = rootsDetector.getRoots()
                 val composeViews =
                     roots.flatMap { it.flatten() }.filter { it.isAndroidComposeView() }
 
@@ -524,8 +524,7 @@
                     val slotTablesAdded = composeViews.sumOf { it.addSlotTable() }
                     if (slotTablesAdded > 0) {
                         // The slot tables added to existing views will be empty until the
-                        // composables
-                        // are reloaded. Do that now:
+                        // composables are reloaded. Do that now:
                         hotReload()
                     }
                 }
diff --git a/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/RootsDetector.kt b/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/RootsDetector.kt
new file mode 100644
index 0000000..5619d3c
--- /dev/null
+++ b/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/RootsDetector.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2024 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.inspection
+
+import android.view.View
+import android.view.inspector.WindowInspector
+import androidx.compose.ui.inspection.util.ThreadUtils
+import androidx.inspection.InspectorEnvironment
+
+class RootsDetector(environment: InspectorEnvironment) {
+    private val alternateViewHelper = AlternateViewHelper(environment)
+
+    fun getRoots(): List<View> {
+        val alternateViews = alternateViewHelper.getAlternateViews()
+        return alternateViews.ifEmpty { getAndroidViews() }
+    }
+
+    private fun getAndroidViews(): List<View> {
+        ThreadUtils.assertOnMainThread()
+        val views = WindowInspector.getGlobalWindowViews()
+        return views
+    }
+}
diff --git a/compose/ui/ui-tooling-data/build.gradle b/compose/ui/ui-tooling-data/build.gradle
index f3ac046..472e819 100644
--- a/compose/ui/ui-tooling-data/build.gradle
+++ b/compose/ui/ui-tooling-data/build.gradle
@@ -28,12 +28,24 @@
 
 plugins {
     id("AndroidXPlugin")
-    id("com.android.library")
     id("AndroidXComposePlugin")
 }
 
 androidXMultiplatform {
-    android()
+    androidLibrary {
+        namespace = "androidx.compose.ui.tooling.data"
+        withAndroidTestOnDeviceBuilder {
+            it.compilationName = "instrumentedTest"
+            it.defaultSourceSetName = "androidInstrumentedTest"
+            it.sourceSetTreeName = "test"
+        }
+        withAndroidTestOnJvmBuilder {
+            it.defaultSourceSetName = "androidUnitTest"
+        }
+
+        compileSdk = 35
+        aarMetadata.minCompileSdk = 35
+    }
     jvmStubs()
 
     defaultPlatform(PlatformIdentifier.ANDROID)
@@ -111,7 +123,3 @@
     kotlinTarget = KotlinTarget.KOTLIN_1_9
 }
 
-android {
-    compileSdk 35
-    namespace "androidx.compose.ui.tooling.data"
-}
diff --git a/compose/ui/ui-tooling-preview/build.gradle b/compose/ui/ui-tooling-preview/build.gradle
index 8293248..2ea5618 100644
--- a/compose/ui/ui-tooling-preview/build.gradle
+++ b/compose/ui/ui-tooling-preview/build.gradle
@@ -27,11 +27,20 @@
 plugins {
     id("AndroidXPlugin")
     id("AndroidXComposePlugin")
-    id("com.android.library")
 }
 
 androidXMultiplatform {
-    android()
+    androidLibrary {
+        namespace = "androidx.compose.ui.tooling.preview"
+        withAndroidTestOnDeviceBuilder {
+            it.compilationName = "instrumentedTest"
+            it.defaultSourceSetName = "androidInstrumentedTest"
+            it.sourceSetTreeName = "test"
+        }
+        withAndroidTestOnJvmBuilder {
+            it.defaultSourceSetName = "androidUnitTest"
+        }
+    }
     jvmStubs()
 
     defaultPlatform(PlatformIdentifier.ANDROID)
@@ -93,6 +102,3 @@
     metalavaK2UastEnabled = false
 }
 
-android {
-    namespace "androidx.compose.ui.tooling.preview"
-}
diff --git a/compose/ui/ui-unit/build.gradle b/compose/ui/ui-unit/build.gradle
index 9cd6331..ce761f72 100644
--- a/compose/ui/ui-unit/build.gradle
+++ b/compose/ui/ui-unit/build.gradle
@@ -28,12 +28,27 @@
 
 plugins {
     id("AndroidXPlugin")
-    id("com.android.library")
     id("AndroidXComposePlugin")
 }
 
 androidXMultiplatform {
-    android()
+    androidLibrary {
+        namespace = "androidx.compose.ui.unit"
+        withAndroidTestOnDeviceBuilder {
+            it.compilationName = "instrumentedTest"
+            it.defaultSourceSetName = "androidInstrumentedTest"
+            it.sourceSetTreeName = "test"
+        }
+        withAndroidTestOnJvmBuilder {
+            it.defaultSourceSetName = "androidUnitTest"
+        }
+        optimization {
+            it.consumerKeepRules.publish = true
+            it.consumerKeepRules.files.add(
+                    new File(project.projectDir, "proguard-rules.pro")
+            )
+        }
+    }
     jvmStubs()
     linuxX64Stubs()
 
@@ -116,9 +131,3 @@
     kotlinTarget = KotlinTarget.KOTLIN_1_9
 }
 
-android {
-    namespace "androidx.compose.ui.unit"
-    buildTypes.configureEach {
-        consumerProguardFiles("proguard-rules.pro")
-    }
-}
diff --git a/compose/ui/ui-util/build.gradle b/compose/ui/ui-util/build.gradle
index b1788829..f6ee5c2 100644
--- a/compose/ui/ui-util/build.gradle
+++ b/compose/ui/ui-util/build.gradle
@@ -27,12 +27,27 @@
 
 plugins {
     id("AndroidXPlugin")
-    id("com.android.library")
     id("AndroidXComposePlugin")
 }
 
 androidXMultiplatform {
-    android()
+    androidLibrary {
+        namespace = "androidx.compose.ui.util"
+        withAndroidTestOnDeviceBuilder {
+            it.compilationName = "instrumentedTest"
+            it.defaultSourceSetName = "androidInstrumentedTest"
+            it.sourceSetTreeName = "test"
+        }
+        withAndroidTestOnJvmBuilder {
+            it.defaultSourceSetName = "androidUnitTest"
+        }
+        optimization {
+            it.consumerKeepRules.publish = true
+            it.consumerKeepRules.files.add(
+                    new File(project.projectDir, "proguard-rules.pro")
+            )
+        }
+    }
     jvmStubs()
     linuxX64Stubs()
 
@@ -105,9 +120,3 @@
     composeCompilerPluginEnabled = false
 }
 
-android {
-    namespace "androidx.compose.ui.util"
-    buildTypes.configureEach {
-        consumerProguardFiles("proguard-rules.pro")
-    }
-}
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/ComposeView.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/ComposeView.android.kt
index d2ab361..0b66d5d 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/ComposeView.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/ComposeView.android.kt
@@ -60,6 +60,7 @@
     init {
         clipChildren = false
         clipToPadding = false
+        importantForAccessibility = IMPORTANT_FOR_ACCESSIBILITY_YES
     }
 
     /**
diff --git a/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/CallSessionLegacyTest.kt b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/CallSessionLegacyTest.kt
index 45eb092..5925c55 100644
--- a/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/CallSessionLegacyTest.kt
+++ b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/CallSessionLegacyTest.kt
@@ -38,6 +38,7 @@
 import kotlinx.coroutines.runBlocking
 import org.junit.After
 import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNotNull
 import org.junit.Test
 import org.junit.runner.RunWith
 
@@ -91,6 +92,40 @@
         }
     }
 
+    /**
+     * Ensure that if the platform returns a null active bluetooth device, the jetpack layer does
+     * not crash the client application or destroy the call session
+     */
+    @SmallTest
+    @Test
+    fun testOnCallAudioStateChangedWithNullActiveDevice() {
+        setUpBackwardsCompatTest()
+        runBlocking {
+            val callSession =
+                initCallSessionLegacy(
+                    coroutineContext,
+                    null,
+                )
+
+            val supportedRouteMask =
+                CallAudioState.ROUTE_BLUETOOTH or
+                    CallAudioState.ROUTE_WIRED_HEADSET or
+                    CallAudioState.ROUTE_SPEAKER
+
+            val cas = CallAudioState(false, CallAudioState.ROUTE_BLUETOOTH, supportedRouteMask)
+
+            callSession.onCallAudioStateChanged(cas)
+
+            val currentCallEndpoint = callSession.getCurrentCallEndpointForSession()
+            assertNotNull(currentCallEndpoint)
+            assertEquals(CallEndpointCompat.TYPE_BLUETOOTH, currentCallEndpoint!!.type)
+            assertEquals(
+                EndpointUtils.endpointTypeToString(CallEndpointCompat.TYPE_BLUETOOTH),
+                currentCallEndpoint.name
+            )
+        }
+    }
+
     private fun initCallSessionLegacy(
         coroutineContext: CoroutineContext,
         preferredStartingEndpoint: CallEndpointCompat?,
diff --git a/core/core-telecom/src/main/java/androidx/core/telecom/internal/CallSessionLegacy.kt b/core/core-telecom/src/main/java/androidx/core/telecom/internal/CallSessionLegacy.kt
index 42a10f8..dcbc391 100644
--- a/core/core-telecom/src/main/java/androidx/core/telecom/internal/CallSessionLegacy.kt
+++ b/core/core-telecom/src/main/java/androidx/core/telecom/internal/CallSessionLegacy.kt
@@ -83,6 +83,10 @@
         }
     }
 
+    fun getCurrentCallEndpointForSession(): CallEndpointCompat? {
+        return mCurrentCallEndpoint
+    }
+
     companion object {
         private const val WAIT_FOR_BT_TO_CONNECT_TIMEOUT: Long = 1000L
         // TODO:: b/369153472 , remove delay and instead wait until onCallEndpointChanged
@@ -158,26 +162,34 @@
         if (Build.VERSION.SDK_INT >= VERSION_CODES.P) {
             Api28PlusImpl.refreshBluetoothDeviceCache(mCachedBluetoothDevices, state)
         }
-        setCurrentCallEndpoint(state)
-        setAvailableCallEndpoints(state)
-        callChannels.isMutedChannel.trySend(state.isMuted).getOrThrow()
-        CoroutineScope(coroutineContext).launch {
-            if (state.isMuted) {
-                onStateChangedCallback.emit(CallStateEvent.GLOBAL_MUTED)
-            } else {
-                onStateChangedCallback.emit(CallStateEvent.GLOBAL_UNMUTE)
+        try {
+            setCurrentCallEndpoint(state)
+            setAvailableCallEndpoints(state)
+            callChannels.isMutedChannel.trySend(state.isMuted).getOrThrow()
+            CoroutineScope(coroutineContext).launch {
+                if (state.isMuted) {
+                    onStateChangedCallback.emit(CallStateEvent.GLOBAL_MUTED)
+                } else {
+                    onStateChangedCallback.emit(CallStateEvent.GLOBAL_UNMUTE)
+                }
             }
+            // On the first call audio state change, determine if the platform started on the
+            // correct audio route.  Otherwise, request an endpoint switch.
+            if (mAvailableCallEndpoints != null) {
+                switchStartingCallEndpointOnCallStart(mAvailableCallEndpoints!!)
+            }
+            // In the event the users headset disconnects, they will likely want to continue the
+            // call via the speakerphone
+            if (mCurrentCallEndpoint != null && mAvailableCallEndpoints != null) {
+                maybeSwitchToSpeakerOnHeadsetDisconnect(
+                    mCurrentCallEndpoint!!,
+                    mPreviousCallEndpoint,
+                    mAvailableCallEndpoints!!,
+                )
+            }
+        } catch (e: Exception) {
+            Log.e(TAG, "onCallAudioStateChanged: caught=[${e.stackTraceToString()}", e)
         }
-        // On the first call audio state change, determine if the platform started on the correct
-        // audio route.  Otherwise, request an endpoint switch.
-        switchStartingCallEndpointOnCallStart(mAvailableCallEndpoints!!)
-        // In the event the users headset disconnects, they will likely want to continue the call
-        // via the speakerphone
-        maybeSwitchToSpeakerOnHeadsetDisconnect(
-            mCurrentCallEndpoint!!,
-            mPreviousCallEndpoint,
-            mAvailableCallEndpoints!!,
-        )
         // clear out the last user requested CallEndpoint. It's only used to determine if the
         // change in current endpoints was intentional.
         if (mLastClientRequestedEndpoint?.type == mCurrentCallEndpoint?.type) {
diff --git a/core/core-telecom/src/main/java/androidx/core/telecom/internal/utils/EndpointUtils.kt b/core/core-telecom/src/main/java/androidx/core/telecom/internal/utils/EndpointUtils.kt
index 1588a2e..f868af5 100644
--- a/core/core-telecom/src/main/java/androidx/core/telecom/internal/utils/EndpointUtils.kt
+++ b/core/core-telecom/src/main/java/androidx/core/telecom/internal/utils/EndpointUtils.kt
@@ -166,13 +166,28 @@
 
         fun toCallEndpointCompat(state: CallAudioState, sessionId: Int): CallEndpointCompat {
             val type: Int = mapRouteToType(state.route)
-            return if (type == CallEndpointCompat.TYPE_BLUETOOTH && SDK_INT >= P) {
+            return if (
+                isBluetoothType(type) && buildIsAtLeastP() && hasActiveBluetoothDevice(state)
+            ) {
                 BluetoothApi28PlusImpl.getCallEndpointFromAudioState(state, sessionId)
             } else {
                 CallEndpointCompat(endpointTypeToString(type), type, getUuid(sessionId, type))
             }
         }
 
+        private fun isBluetoothType(type: Int): Boolean {
+            return type == CallEndpointCompat.TYPE_BLUETOOTH
+        }
+
+        private fun buildIsAtLeastP(): Boolean {
+            return SDK_INT >= P
+        }
+
+        @RequiresApi(P)
+        private fun hasActiveBluetoothDevice(state: CallAudioState): Boolean {
+            return state.activeBluetoothDevice != null
+        }
+
         fun toCallEndpointsCompat(state: CallAudioState, sessionId: Int): List<CallEndpointCompat> {
             val endpoints: ArrayList<CallEndpointCompat> = ArrayList()
             val bitMask = state.supportedRouteMask
@@ -278,7 +293,7 @@
         fun endpointTypeToString(endpointType: Int): String {
             return when (endpointType) {
                 CallEndpointCompat.TYPE_EARPIECE -> "EARPIECE"
-                CallEndpointCompat.TYPE_BLUETOOTH -> "BLUETOOTH"
+                CallEndpointCompat.TYPE_BLUETOOTH -> BLUETOOTH_DEVICE_DEFAULT_NAME
                 CallEndpointCompat.TYPE_WIRED_HEADSET -> "WIRED_HEADSET"
                 CallEndpointCompat.TYPE_SPEAKER -> "SPEAKER"
                 CallEndpointCompat.TYPE_STREAMING -> "EXTERNAL"
diff --git a/datastore/datastore-preferences/build.gradle b/datastore/datastore-preferences/build.gradle
index 9fb7310..47d0108 100644
--- a/datastore/datastore-preferences/build.gradle
+++ b/datastore/datastore-preferences/build.gradle
@@ -28,12 +28,8 @@
 
 plugins {
     id("AndroidXPlugin")
-    id("com.android.library")
 }
 
-android{
-    namespace "androidx.datastore.preferences"
-}
 androidXMultiplatform {
     jvm()
     mac()
@@ -41,7 +37,17 @@
     ios()
     watchos()
     tvos()
-    android()
+    androidLibrary {
+        namespace = "androidx.datastore.preferences"
+        withAndroidTestOnDeviceBuilder {
+            it.compilationName = "instrumentedTest"
+            it.defaultSourceSetName = "androidInstrumentedTest"
+            it.sourceSetTreeName = "test"
+        }
+        withAndroidTestOnJvmBuilder {
+            it.defaultSourceSetName = "androidUnitTest"
+        }
+    }
 
     defaultPlatform(PlatformIdentifier.ANDROID)
 
@@ -93,7 +99,6 @@
     }
 }
 
-
 androidx {
     name = "Preferences DataStore"
     type = LibraryType.PUBLISHED_LIBRARY
diff --git a/datastore/datastore/build.gradle b/datastore/datastore/build.gradle
index 0933373..80d4bbd6 100644
--- a/datastore/datastore/build.gradle
+++ b/datastore/datastore/build.gradle
@@ -27,12 +27,8 @@
 
 plugins {
     id("AndroidXPlugin")
-    id("com.android.library")
 }
 
-android {
-    namespace "androidx.datastore.datastore"
-}
 
 androidXMultiplatform {
     jvm()
@@ -41,7 +37,17 @@
     watchos()
     tvos()
     linux()
-    android()
+    androidLibrary {
+        namespace = "androidx.datastore.datastore"
+        withAndroidTestOnDeviceBuilder {
+            it.compilationName = "instrumentedTest"
+            it.defaultSourceSetName = "androidInstrumentedTest"
+            it.sourceSetTreeName = "test"
+        }
+        withAndroidTestOnJvmBuilder {
+            it.defaultSourceSetName = "androidUnitTest"
+        }
+    }
 
     defaultPlatform(PlatformIdentifier.ANDROID)
 
diff --git a/development/project-creator/compose-template/groupId/artifactId/build.gradle b/development/project-creator/compose-template/groupId/artifactId/build.gradle
index 9cde1b1..83fd2fb 100644
--- a/development/project-creator/compose-template/groupId/artifactId/build.gradle
+++ b/development/project-creator/compose-template/groupId/artifactId/build.gradle
@@ -28,11 +28,20 @@
 plugins {
     id("AndroidXPlugin")
     id("AndroidXComposePlugin")
-    id("com.android.library")
 }
 
 androidXMultiplatform {
-    android()
+    androidLibrary {
+        namespace = "<PACKAGE>"
+        withAndroidTestOnDeviceBuilder {
+            it.compilationName = "instrumentedTest"
+            it.defaultSourceSetName = "androidInstrumentedTest"
+            it.sourceSetTreeName = "test"
+        }
+        withAndroidTestOnJvmBuilder {
+            it.defaultSourceSetName = "androidUnitTest"
+        }
+    }
     jvmStubs()
     linuxX64Stubs()
 
@@ -97,9 +106,6 @@
     }
 }
 
-android {
-    namespace "<PACKAGE>"
-}
 
 androidx {
     name = "<NAME>"
diff --git a/docs/api_guidelines/dependencies.md b/docs/api_guidelines/dependencies.md
index 74b88cd..c6f1576 100644
--- a/docs/api_guidelines/dependencies.md
+++ b/docs/api_guidelines/dependencies.md
@@ -236,15 +236,19 @@
 }
 ```
 
-### System health {#dependencies-health}
+### Dependency considerations {#dependencies-health}
 
 Generally, Jetpack libraries should avoid dependencies that negatively impact
 developers without providing substantial benefit. Libraries should consider the
-system health implications of their dependencies, including:
+implications of their dependencies, including:
 
 -   Large dependencies where only a small portion is needed (e.g. APK bloat)
 -   Dependencies that slow down build times through annotation processing or
     compiler overhead
+-   Dependencies which do not maintain binary compatibility and conflict with
+    semantic versioning guarantees
+-   Dependencies that are intended for server environments and don't interact
+    well with the Android build toolchain (e.g. R8) or runtime (e.g. ART)
 
 #### Kotlin {#dependencies-kotlin}
 
@@ -281,6 +285,12 @@
 }
 ```
 
+#### GSON {#dependencies-gson}
+
+GSON relies heavily on reflection and interacts poorly with app optimization
+tools like R8. Instead, consider using `org.json` which is included in the
+Android platform SDK.
+
 #### Guava {#dependencies-guava}
 
 The full Guava library is very large and should only be used in cases where
diff --git a/graphics/graphics-shapes/build.gradle b/graphics/graphics-shapes/build.gradle
index 7212f00..000cc74 100644
--- a/graphics/graphics-shapes/build.gradle
+++ b/graphics/graphics-shapes/build.gradle
@@ -26,12 +26,20 @@
 
 plugins {
     id("AndroidXPlugin")
-    id("com.android.library")
 }
 
-
 androidXMultiplatform {
-    android()
+    androidLibrary {
+        namespace = "androidx.graphics.shapes"
+        withAndroidTestOnDeviceBuilder {
+            it.compilationName = "instrumentedTest"
+            it.defaultSourceSetName = "androidInstrumentedTest"
+            it.sourceSetTreeName = "test"
+        }
+        withAndroidTestOnJvmBuilder {
+            it.defaultSourceSetName = "androidUnitTest"
+        }
+    }
     desktop()
     linux()
     ios()
@@ -99,9 +107,6 @@
     }
 }
 
-android {
-    namespace "androidx.graphics.shapes"
-}
 
 androidx {
     name = "Graphics Shapes"
diff --git a/libraryversions.toml b/libraryversions.toml
index 225bd0f..5bb21b8 100644
--- a/libraryversions.toml
+++ b/libraryversions.toml
@@ -21,8 +21,8 @@
 CAR_APP = "1.7.0-beta02"
 COLLECTION = "1.5.0-alpha05"
 COMPOSE = "1.8.0-alpha05"
-COMPOSE_MATERIAL3 = "1.4.0-alpha02"
-COMPOSE_MATERIAL3_ADAPTIVE = "1.1.0-alpha05"
+COMPOSE_MATERIAL3 = "1.4.0-alpha03"
+COMPOSE_MATERIAL3_ADAPTIVE = "1.1.0-alpha06"
 COMPOSE_MATERIAL3_COMMON = "1.0.0-alpha01"
 COMPOSE_RUNTIME = "1.8.0-alpha05"
 CONSTRAINTLAYOUT = "2.2.0-beta01"
diff --git a/lifecycle/lifecycle-runtime-compose/build.gradle b/lifecycle/lifecycle-runtime-compose/build.gradle
index a802e2f..7a93d89 100644
--- a/lifecycle/lifecycle-runtime-compose/build.gradle
+++ b/lifecycle/lifecycle-runtime-compose/build.gradle
@@ -27,12 +27,31 @@
 
 plugins {
     id("AndroidXPlugin")
-    id("com.android.library")
     id("AndroidXComposePlugin")
 }
 
 androidXMultiplatform {
-    android()
+    androidLibrary {
+        namespace = "androidx.lifecycle.runtime.compose"
+        withAndroidTestOnDeviceBuilder {
+            it.compilationName = "instrumentedTest"
+            it.defaultSourceSetName = "androidInstrumentedTest"
+            it.sourceSetTreeName = "test"
+        }
+        withAndroidTestOnJvmBuilder {
+            it.defaultSourceSetName = "androidUnitTest"
+        }
+
+        compileSdk = 35
+        aarMetadata.minCompileSdk = 35
+
+        optimization {
+            it.consumerKeepRules.publish = true
+            it.consumerKeepRules.files.add(
+                new File(project.projectDir, "proguard-rules.pro")
+            )
+        }
+    }
     jvmStubs()
     linuxX64Stubs()
 
@@ -94,12 +113,3 @@
     samples(project(":lifecycle:lifecycle-runtime-compose:lifecycle-runtime-compose-samples"))
 }
 
-android {
-    compileSdk 35
-    
-    buildTypes.configureEach {
-        consumerProguardFiles "proguard-rules.pro"
-    }
-
-    namespace "androidx.lifecycle.runtime.compose"
-}
diff --git a/lifecycle/lifecycle-runtime-ktx/build.gradle b/lifecycle/lifecycle-runtime-ktx/build.gradle
index e660299..049067d 100644
--- a/lifecycle/lifecycle-runtime-ktx/build.gradle
+++ b/lifecycle/lifecycle-runtime-ktx/build.gradle
@@ -27,11 +27,20 @@
 
 plugins {
     id("AndroidXPlugin")
-    id("com.android.library")
 }
 
 androidXMultiplatform {
-    android()
+    androidLibrary {
+        namespace = "androidx.lifecycle.ktx"
+        withAndroidTestOnDeviceBuilder {
+            it.compilationName = "instrumentedTest"
+            it.defaultSourceSetName = "androidInstrumentedTest"
+            it.sourceSetTreeName = "test"
+        }
+        withAndroidTestOnJvmBuilder {
+            it.defaultSourceSetName = "androidUnitTest"
+        }
+    }
 
     defaultPlatform(PlatformIdentifier.ANDROID)
 
@@ -60,6 +69,3 @@
     description = "Kotlin extensions for 'lifecycle' artifact"
 }
 
-android {
-    namespace "androidx.lifecycle.ktx"
-}
diff --git a/lifecycle/lifecycle-runtime-testing/build.gradle b/lifecycle/lifecycle-runtime-testing/build.gradle
index 430b902..89a61a8 100644
--- a/lifecycle/lifecycle-runtime-testing/build.gradle
+++ b/lifecycle/lifecycle-runtime-testing/build.gradle
@@ -27,11 +27,20 @@
 
 plugins {
     id("AndroidXPlugin")
-    id("com.android.library")
 }
 
 androidXMultiplatform {
-    android()
+    androidLibrary {
+        namespace = "androidx.lifecycle.testing"
+        withAndroidTestOnDeviceBuilder {
+            it.compilationName = "instrumentedTest"
+            it.defaultSourceSetName = "androidInstrumentedTest"
+            it.sourceSetTreeName = "test"
+        }
+        withAndroidTestOnJvmBuilder {
+            it.defaultSourceSetName = "androidUnitTest"
+        }
+    }
     desktop()
     mac()
     linux()
@@ -73,13 +82,10 @@
 
 androidx {
     name = "Lifecycle Runtime Testing"
-    type = LibraryType.PUBLISHED_LIBRARY
+    type = LibraryType.PUBLISHED_TEST_LIBRARY
     inceptionYear = "2019"
     description = "Testing utilities for 'lifecycle' artifact"
     legacyDisableKotlinStrictApiMode = true
     metalavaK2UastEnabled = false
 }
 
-android {
-    namespace "androidx.lifecycle.testing"
-}
diff --git a/lifecycle/lifecycle-viewmodel-testing/build.gradle b/lifecycle/lifecycle-viewmodel-testing/build.gradle
index bd1b11a..919a73e 100644
--- a/lifecycle/lifecycle-viewmodel-testing/build.gradle
+++ b/lifecycle/lifecycle-viewmodel-testing/build.gradle
@@ -29,11 +29,20 @@
 
 plugins {
     id("AndroidXPlugin")
-    id("com.android.library")
 }
 
 androidXMultiplatform {
-    android()
+    androidLibrary {
+        namespace = "androidx.lifecycle.viewmodel.testing"
+        withAndroidTestOnDeviceBuilder {
+            it.compilationName = "instrumentedTest"
+            it.defaultSourceSetName = "androidInstrumentedTest"
+            it.sourceSetTreeName = "test"
+        }
+        withAndroidTestOnJvmBuilder {
+            it.defaultSourceSetName = "androidUnitTest"
+        }
+    }
     desktop()
     mac()
     linux()
@@ -108,6 +117,3 @@
     metalavaK2UastEnabled = false
 }
 
-android {
-    namespace "androidx.lifecycle.viewmodel.testing"
-}
diff --git a/navigation/navigation-runtime/api/current.txt b/navigation/navigation-runtime/api/current.txt
index b801964..a4cc6458 100644
--- a/navigation/navigation-runtime/api/current.txt
+++ b/navigation/navigation-runtime/api/current.txt
@@ -113,6 +113,7 @@
     method public androidx.lifecycle.ViewModelStoreOwner getViewModelStoreOwner(@IdRes int navGraphId);
     method public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> getVisibleEntries();
     method @MainThread public boolean handleDeepLink(android.content.Intent? intent);
+    method @MainThread public final boolean handleDeepLink(androidx.navigation.NavDeepLinkRequest request);
     method @MainThread public void navigate(android.net.Uri deepLink);
     method @MainThread public void navigate(android.net.Uri deepLink, androidx.navigation.NavOptions? navOptions);
     method @MainThread public void navigate(android.net.Uri deepLink, androidx.navigation.NavOptions? navOptions, androidx.navigation.Navigator.Extras? navigatorExtras);
diff --git a/navigation/navigation-runtime/api/restricted_current.txt b/navigation/navigation-runtime/api/restricted_current.txt
index b801964..a4cc6458 100644
--- a/navigation/navigation-runtime/api/restricted_current.txt
+++ b/navigation/navigation-runtime/api/restricted_current.txt
@@ -113,6 +113,7 @@
     method public androidx.lifecycle.ViewModelStoreOwner getViewModelStoreOwner(@IdRes int navGraphId);
     method public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> getVisibleEntries();
     method @MainThread public boolean handleDeepLink(android.content.Intent? intent);
+    method @MainThread public final boolean handleDeepLink(androidx.navigation.NavDeepLinkRequest request);
     method @MainThread public void navigate(android.net.Uri deepLink);
     method @MainThread public void navigate(android.net.Uri deepLink, androidx.navigation.NavOptions? navOptions);
     method @MainThread public void navigate(android.net.Uri deepLink, androidx.navigation.NavOptions? navOptions, androidx.navigation.Navigator.Extras? navigatorExtras);
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerTest.kt b/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerTest.kt
index 1fbe388d..95a9f20 100644
--- a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerTest.kt
+++ b/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerTest.kt
@@ -3331,6 +3331,66 @@
 
     @UiThreadTest
     @Test
+    fun testHandleDeepLinkAsUri() {
+        val navController = createNavController()
+        val navigator = navController.navigatorProvider.getNavigator(TestNavigator::class.java)
+        navController.setGraph(R.navigation.nav_simple)
+
+        val deepLink = Uri.parse("test-app://test/333")
+        val request = NavDeepLinkRequest.Builder.fromUri(deepLink).build()
+        assertWithMessage("NavController should handle deep links to its own graph")
+            .that(navController.handleDeepLink(request))
+            .isTrue()
+        // Verify that we navigated down to the deep link
+        assertThat(navigator.backStack.map { it.destination.id })
+            .containsExactly(R.id.start_test, R.id.nonNullableArg_test)
+            .inOrder()
+
+        val destination = navController.currentDestination
+        assertThat(destination?.id ?: 0).isEqualTo(R.id.nonNullableArg_test)
+    }
+
+    @UiThreadTest
+    @Test
+    fun testHandleDeepLink_InvalidUri() {
+        val navController = createNavController()
+        navController.setGraph(R.navigation.nav_simple)
+
+        val deepLink = Uri.parse("test-app://invalid/uri")
+        val request = NavDeepLinkRequest.Builder.fromUri(deepLink).build()
+        assertWithMessage("NavController should not match with any deeplink due to invalid uri")
+            .that(navController.handleDeepLink(request))
+            .isFalse()
+    }
+
+    @UiThreadTest
+    @Test
+    fun testHandleDeepLink_MimeType() {
+        val navController = createNavController()
+        navController.setGraph(R.navigation.nav_simple)
+        val navigator = navController.navigatorProvider.getNavigator(TestNavigator::class.java)
+        val deepLink = NavDeepLinkRequest(Uri.parse("invalidDeepLink.com"), null, "type/test")
+
+        navController.handleDeepLink(deepLink)
+        assertThat(navController.currentDestination?.id ?: 0).isEqualTo(R.id.second_test)
+        assertThat(navigator.backStack.size).isEqualTo(2)
+    }
+
+    @UiThreadTest
+    @Test
+    fun testHandleDeepLink_Action() {
+        val navController = createNavController()
+        navController.setGraph(R.navigation.nav_simple)
+        val navigator = navController.navigatorProvider.getNavigator(TestNavigator::class.java)
+        val deepLink = NavDeepLinkRequest(null, "test.action", null)
+
+        navController.handleDeepLink(deepLink)
+        assertThat(navController.currentDestination?.id ?: 0).isEqualTo(R.id.second_test)
+        assertThat(navigator.backStack.size).isEqualTo(2)
+    }
+
+    @UiThreadTest
+    @Test
     fun testHandleDeepLinkActionMissingURI_nonNullableArg() {
         val navController = createNavController()
         navController.setGraph(R.navigation.nav_simple)
diff --git a/navigation/navigation-runtime/src/main/java/androidx/navigation/NavController.kt b/navigation/navigation-runtime/src/main/java/androidx/navigation/NavController.kt
index ab95516..8efc3e2 100644
--- a/navigation/navigation-runtime/src/main/java/androidx/navigation/NavController.kt
+++ b/navigation/navigation-runtime/src/main/java/androidx/navigation/NavController.kt
@@ -1539,7 +1539,55 @@
             }
             return true
         }
-        if (flags and Intent.FLAG_ACTIVITY_NEW_TASK != 0) {
+        return handleDeepLink(deepLink, args, flags and Intent.FLAG_ACTIVITY_NEW_TASK != 0)
+    }
+
+    /**
+     * Checks the given NavDeepLinkRequest for a Navigation deep link and navigates to the
+     * destination if present.
+     *
+     * The [navigation graph][graph] should be set before calling this method.
+     *
+     * @param request The request that contains a valid deep link, an action or a mimeType.
+     * @return True if the navigation controller found a valid deep link and navigated to it.
+     * @throws IllegalStateException if deep link cannot be accessed from the current destination
+     * @see NavDestination.addDeepLink
+     */
+    @MainThread
+    public fun handleDeepLink(request: NavDeepLinkRequest): Boolean {
+        val currGraph = backQueue.getTopGraph()
+        val matchingDeepLink =
+            currGraph.matchDeepLinkComprehensive(
+                navDeepLinkRequest = request,
+                searchChildren = true,
+                searchParent = true,
+                lastVisited = currGraph
+            )
+        if (matchingDeepLink != null) {
+            val destination = matchingDeepLink.destination
+            val deepLink = destination.buildDeepLinkIds()
+            val globalArgs = Bundle()
+            val destinationArgs = destination.addInDefaultArgs(matchingDeepLink.matchingArgs)
+            if (destinationArgs != null) {
+                globalArgs.putAll(destinationArgs)
+            }
+            val args = arrayOfNulls<Bundle>(deepLink.size)
+            for (index in args.indices) {
+                val arguments = Bundle()
+                arguments.putAll(globalArgs)
+                args[index] = arguments
+            }
+            return handleDeepLink(deepLink, args, true)
+        }
+        return false
+    }
+
+    private fun handleDeepLink(
+        deepLink: IntArray,
+        args: Array<Bundle?>,
+        newTask: Boolean
+    ): Boolean {
+        if (newTask) {
             // Start with a cleared task starting at our root when we're on our own task
             if (!backQueue.isEmpty()) {
                 popBackStackInternal(_graph!!.id, true)
diff --git a/pdf/pdf-viewer/src/main/res/values-af/strings.xml b/pdf/pdf-viewer/src/main/res/values-af/strings.xml
index f62de4d..344991a 100644
--- a/pdf/pdf-viewer/src/main/res/values-af/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-af/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"Volgende"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Maak toe"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"Geen passende resultate nie"</string>
     <string name="action_edit" msgid="5882082700509010966">"Wysig lêer"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Voer wagwoord in om te ontsluit"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-am/strings.xml b/pdf/pdf-viewer/src/main/res/values-am/strings.xml
index 9251d8b..7db9b5a 100644
--- a/pdf/pdf-viewer/src/main/res/values-am/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-am/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"ቀጣይ"</string>
     <string name="close_button_description" msgid="7379823906921067675">"ዝጋ"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"ምንም የሚመሳሰሉ ውጤቶች የሉም"</string>
     <string name="action_edit" msgid="5882082700509010966">"ፋይል አርትዕ"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"ለመክፈት የይለፍ ቃል ያስገቡ"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-ar/strings.xml b/pdf/pdf-viewer/src/main/res/values-ar/strings.xml
index 7477408..f88ddb3 100644
--- a/pdf/pdf-viewer/src/main/res/values-ar/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ar/strings.xml
@@ -47,6 +47,7 @@
     <string name="next_button_description" msgid="4702699322249103693">"التالي"</string>
     <string name="close_button_description" msgid="7379823906921067675">"إغلاق"</string>
     <string name="message_match_status" msgid="6288242289981639727">"‫<xliff:g id="POSITION">%1$d</xliff:g> من أصل <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="match_status_description" msgid="4996847358326345288">"‫<xliff:g id="POSITION">%1$d</xliff:g> من إجمالي <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="message_no_match_status" msgid="5929387004361286433">"ما مِن نتائج مطابقة"</string>
     <string name="action_edit" msgid="5882082700509010966">"تعديل الملف"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"يجب إدخال كلمة المرور لفتح القفل"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-as/strings.xml b/pdf/pdf-viewer/src/main/res/values-as/strings.xml
index 575762e..c5fbb0d 100644
--- a/pdf/pdf-viewer/src/main/res/values-as/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-as/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"পৰৱৰ্তী"</string>
     <string name="close_button_description" msgid="7379823906921067675">"বন্ধ কৰক"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"কোনো মিল থকা ফলাফল নাই"</string>
     <string name="action_edit" msgid="5882082700509010966">"ফাইল সম্পাদনা কৰক"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"আনলক কৰিবলৈ পাছৱৰ্ড দিয়ক"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-az/strings.xml b/pdf/pdf-viewer/src/main/res/values-az/strings.xml
index 56f789c3c..f058531 100644
--- a/pdf/pdf-viewer/src/main/res/values-az/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-az/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"Növbəti"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Bağlayın"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"Uyğun gələn nəticə yoxdur"</string>
     <string name="action_edit" msgid="5882082700509010966">"Faylı redaktə edin"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Kiliddən çıxarmaq üçün parol daxil edin"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-b+sr+Latn/strings.xml b/pdf/pdf-viewer/src/main/res/values-b+sr+Latn/strings.xml
index 98c7f5b..e43a0da 100644
--- a/pdf/pdf-viewer/src/main/res/values-b+sr+Latn/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-b+sr+Latn/strings.xml
@@ -47,6 +47,7 @@
     <string name="next_button_description" msgid="4702699322249103693">"Dalje"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Zatvori"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="match_status_description" msgid="4996847358326345288">"<xliff:g id="POSITION">%1$d</xliff:g> od <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="message_no_match_status" msgid="5929387004361286433">"Nema podudarnih rezultata"</string>
     <string name="action_edit" msgid="5882082700509010966">"Izmeni fajl"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Unesite lozinku za otključavanje"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-be/strings.xml b/pdf/pdf-viewer/src/main/res/values-be/strings.xml
index e5246b7..0d565d7 100644
--- a/pdf/pdf-viewer/src/main/res/values-be/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-be/strings.xml
@@ -47,6 +47,7 @@
     <string name="next_button_description" msgid="4702699322249103693">"Далей"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Закрыць"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g> з <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="match_status_description" msgid="4996847358326345288">"<xliff:g id="POSITION">%1$d</xliff:g> з <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="message_no_match_status" msgid="5929387004361286433">"Супадзенняў няма"</string>
     <string name="action_edit" msgid="5882082700509010966">"Рэдагаваць файл"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Увядзіце пароль для разблакіроўкі"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-bg/strings.xml b/pdf/pdf-viewer/src/main/res/values-bg/strings.xml
index 1963288..3af4c32 100644
--- a/pdf/pdf-viewer/src/main/res/values-bg/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-bg/strings.xml
@@ -47,6 +47,7 @@
     <string name="next_button_description" msgid="4702699322249103693">"Напред"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Затваряне"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="match_status_description" msgid="4996847358326345288">"<xliff:g id="POSITION">%1$d</xliff:g> от <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="message_no_match_status" msgid="5929387004361286433">"Няма съответстващи резултати"</string>
     <string name="action_edit" msgid="5882082700509010966">"Редактиране на файла"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Въведете паролата, за да отключите"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-bn/strings.xml b/pdf/pdf-viewer/src/main/res/values-bn/strings.xml
index 7e9b6a8..523615d 100644
--- a/pdf/pdf-viewer/src/main/res/values-bn/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-bn/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"পরবর্তী"</string>
     <string name="close_button_description" msgid="7379823906921067675">"বন্ধ করুন"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"কোনও ফলাফল মিলছে না"</string>
     <string name="action_edit" msgid="5882082700509010966">"ফাইল এডিট করুন"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"আনলক করতে পাসওয়ার্ড লিখুন"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-bs/strings.xml b/pdf/pdf-viewer/src/main/res/values-bs/strings.xml
index 6e2be84..58cb55b 100644
--- a/pdf/pdf-viewer/src/main/res/values-bs/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-bs/strings.xml
@@ -47,6 +47,7 @@
     <string name="next_button_description" msgid="4702699322249103693">"Naprijed"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Zatvaranje"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="match_status_description" msgid="4996847358326345288">"<xliff:g id="POSITION">%1$d</xliff:g> od <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="message_no_match_status" msgid="5929387004361286433">"Nema podudarnih rezultata"</string>
     <string name="action_edit" msgid="5882082700509010966">"Uredite fajl"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Unesite lozinku da otključate fajl"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-ca/strings.xml b/pdf/pdf-viewer/src/main/res/values-ca/strings.xml
index e5237f2..e006cd2 100644
--- a/pdf/pdf-viewer/src/main/res/values-ca/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ca/strings.xml
@@ -47,6 +47,7 @@
     <string name="next_button_description" msgid="4702699322249103693">"Següent"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Tanca"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="match_status_description" msgid="4996847358326345288">"<xliff:g id="POSITION">%1$d</xliff:g> de <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="message_no_match_status" msgid="5929387004361286433">"No hi ha cap resultat coincident"</string>
     <string name="action_edit" msgid="5882082700509010966">"Edita el fitxer"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Introdueix la contrasenya per desbloquejar-lo"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-cs/strings.xml b/pdf/pdf-viewer/src/main/res/values-cs/strings.xml
index bb042a7..93a108c 100644
--- a/pdf/pdf-viewer/src/main/res/values-cs/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-cs/strings.xml
@@ -47,6 +47,7 @@
     <string name="next_button_description" msgid="4702699322249103693">"Další"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Zavřít"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="match_status_description" msgid="4996847358326345288">"<xliff:g id="POSITION">%1$d</xliff:g> z <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="message_no_match_status" msgid="5929387004361286433">"Žádné výsledky neodpovídají"</string>
     <string name="action_edit" msgid="5882082700509010966">"Upravit soubor"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"K odemknutí zadejte heslo"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-da/strings.xml b/pdf/pdf-viewer/src/main/res/values-da/strings.xml
index 120231b..5a5ac17 100644
--- a/pdf/pdf-viewer/src/main/res/values-da/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-da/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"Næste"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Luk"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"Ingen matchende resultater"</string>
     <string name="action_edit" msgid="5882082700509010966">"Rediger fil"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Angiv adgangskode for at låse op"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-de/strings.xml b/pdf/pdf-viewer/src/main/res/values-de/strings.xml
index 8af7f80..15c0a75 100644
--- a/pdf/pdf-viewer/src/main/res/values-de/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-de/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"Weiter"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Schließen"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"Keine passenden Ergebnisse"</string>
     <string name="action_edit" msgid="5882082700509010966">"Datei bearbeiten"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Gib zum Entsperren ein Passwort ein"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-el/strings.xml b/pdf/pdf-viewer/src/main/res/values-el/strings.xml
index 7f833eb..83efcf5 100644
--- a/pdf/pdf-viewer/src/main/res/values-el/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-el/strings.xml
@@ -47,6 +47,7 @@
     <string name="next_button_description" msgid="4702699322249103693">"Επόμενο"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Κλείσιμο"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="match_status_description" msgid="4996847358326345288">"<xliff:g id="POSITION">%1$d</xliff:g> από <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="message_no_match_status" msgid="5929387004361286433">"Δεν υπάρχουν αντίστοιχα αποτελέσματα"</string>
     <string name="action_edit" msgid="5882082700509010966">"Επεξεργασία αρχείου"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Εισαγάγετε τον κωδικό πρόσβασης για ξεκλείδωμα"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-en-rAU/strings.xml b/pdf/pdf-viewer/src/main/res/values-en-rAU/strings.xml
index b4f73b8..e3344f7 100644
--- a/pdf/pdf-viewer/src/main/res/values-en-rAU/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-en-rAU/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"Next"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Close"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"No matching results"</string>
     <string name="action_edit" msgid="5882082700509010966">"Edit file"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Enter password to unlock"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-en-rCA/strings.xml b/pdf/pdf-viewer/src/main/res/values-en-rCA/strings.xml
index 74126a3..f9bb660 100644
--- a/pdf/pdf-viewer/src/main/res/values-en-rCA/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-en-rCA/strings.xml
@@ -47,6 +47,7 @@
     <string name="next_button_description" msgid="4702699322249103693">"Next"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Close"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="match_status_description" msgid="4996847358326345288">"<xliff:g id="POSITION">%1$d</xliff:g> of <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="message_no_match_status" msgid="5929387004361286433">"No matching results"</string>
     <string name="action_edit" msgid="5882082700509010966">"Edit file"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Enter password to unlock"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-en-rGB/strings.xml b/pdf/pdf-viewer/src/main/res/values-en-rGB/strings.xml
index b4f73b8..e3344f7 100644
--- a/pdf/pdf-viewer/src/main/res/values-en-rGB/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-en-rGB/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"Next"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Close"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"No matching results"</string>
     <string name="action_edit" msgid="5882082700509010966">"Edit file"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Enter password to unlock"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-en-rIN/strings.xml b/pdf/pdf-viewer/src/main/res/values-en-rIN/strings.xml
index b4f73b8..e3344f7 100644
--- a/pdf/pdf-viewer/src/main/res/values-en-rIN/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-en-rIN/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"Next"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Close"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"No matching results"</string>
     <string name="action_edit" msgid="5882082700509010966">"Edit file"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Enter password to unlock"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-es-rUS/strings.xml b/pdf/pdf-viewer/src/main/res/values-es-rUS/strings.xml
index ecf2f42..ac55757a 100644
--- a/pdf/pdf-viewer/src/main/res/values-es-rUS/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-es-rUS/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"Siguiente"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Cerrar"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"No hay resultados que coincidan"</string>
     <string name="action_edit" msgid="5882082700509010966">"Editar el archivo"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Ingresa la contraseña para desbloquear"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-es/strings.xml b/pdf/pdf-viewer/src/main/res/values-es/strings.xml
index 48a146f..a8395fb 100644
--- a/pdf/pdf-viewer/src/main/res/values-es/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-es/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"Siguiente"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Cerrar"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"No hay coincidencias"</string>
     <string name="action_edit" msgid="5882082700509010966">"Editar archivo"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Introduce la contraseña para desbloquear"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-et/strings.xml b/pdf/pdf-viewer/src/main/res/values-et/strings.xml
index e23221de..a57f96c 100644
--- a/pdf/pdf-viewer/src/main/res/values-et/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-et/strings.xml
@@ -47,6 +47,7 @@
     <string name="next_button_description" msgid="4702699322249103693">"Järgmine"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Sule"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="match_status_description" msgid="4996847358326345288">"<xliff:g id="POSITION">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="message_no_match_status" msgid="5929387004361286433">"Päringule vastavaid tulemusi pole"</string>
     <string name="action_edit" msgid="5882082700509010966">"Faili muutmine"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Avamiseks sisestage parool"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-eu/strings.xml b/pdf/pdf-viewer/src/main/res/values-eu/strings.xml
index c408c2b..e46c3a2 100644
--- a/pdf/pdf-viewer/src/main/res/values-eu/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-eu/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"Hurrengoa"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Itxi"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"Ez dago bat datorren emaitzarik"</string>
     <string name="action_edit" msgid="5882082700509010966">"Editatu fitxategia"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Idatzi pasahitza desblokeatzeko"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-fa/strings.xml b/pdf/pdf-viewer/src/main/res/values-fa/strings.xml
index e017f32..9fe5557 100644
--- a/pdf/pdf-viewer/src/main/res/values-fa/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-fa/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"بعدی"</string>
     <string name="close_button_description" msgid="7379823906921067675">"بستن"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"نتیجه منطبقی پیدا نشد"</string>
     <string name="action_edit" msgid="5882082700509010966">"ویرایش فایل"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"گذرواژه را برای بازگشایی قفل وارد کنید"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-fi/strings.xml b/pdf/pdf-viewer/src/main/res/values-fi/strings.xml
index 9b9eb0a..e9e243ac 100644
--- a/pdf/pdf-viewer/src/main/res/values-fi/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-fi/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"Seuraava"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Sulje"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"Ei tuloksia"</string>
     <string name="action_edit" msgid="5882082700509010966">"Muokkaa tiedostoa"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Poista lukitus lisäämällä salasana"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-fr-rCA/strings.xml b/pdf/pdf-viewer/src/main/res/values-fr-rCA/strings.xml
index 564ac9f..462595c 100644
--- a/pdf/pdf-viewer/src/main/res/values-fr-rCA/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-fr-rCA/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"Suivant"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Fermer"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"Aucun résultat correspondant"</string>
     <string name="action_edit" msgid="5882082700509010966">"Modifier le fichier"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Entrez le mot de passe pour déverrouiller le fichier"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-fr/strings.xml b/pdf/pdf-viewer/src/main/res/values-fr/strings.xml
index f8067f1..7b5333c 100644
--- a/pdf/pdf-viewer/src/main/res/values-fr/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-fr/strings.xml
@@ -47,6 +47,7 @@
     <string name="next_button_description" msgid="4702699322249103693">"Suivant"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Fermer"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="match_status_description" msgid="4996847358326345288">"<xliff:g id="POSITION">%1$d</xliff:g> sur <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="message_no_match_status" msgid="5929387004361286433">"Aucun résultat"</string>
     <string name="action_edit" msgid="5882082700509010966">"Modifier le fichier"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Saisissez le mot de passe pour procéder au déverrouillage"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-gl/strings.xml b/pdf/pdf-viewer/src/main/res/values-gl/strings.xml
index e9996c3..f44eedd 100644
--- a/pdf/pdf-viewer/src/main/res/values-gl/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-gl/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"Seguinte"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Pechar"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"Non hai ningún resultado que coincida"</string>
     <string name="action_edit" msgid="5882082700509010966">"Editar o ficheiro"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Introduce o contrasinal para desbloquear o ficheiro"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-gu/strings.xml b/pdf/pdf-viewer/src/main/res/values-gu/strings.xml
index a976158..3a6a1fe 100644
--- a/pdf/pdf-viewer/src/main/res/values-gu/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-gu/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"આગળ"</string>
     <string name="close_button_description" msgid="7379823906921067675">"બંધ કરો"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"કોઈ મેળ ખાતું પરિણામ નથી"</string>
     <string name="action_edit" msgid="5882082700509010966">"ફાઇલમાં ફેરફાર કરો"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"અનલૉક કરવા માટે પાસવર્ડ દાખલ કરો"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-hi/strings.xml b/pdf/pdf-viewer/src/main/res/values-hi/strings.xml
index 1904222..d7febf7 100644
--- a/pdf/pdf-viewer/src/main/res/values-hi/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-hi/strings.xml
@@ -47,6 +47,7 @@
     <string name="next_button_description" msgid="4702699322249103693">"आगे बढ़ें"</string>
     <string name="close_button_description" msgid="7379823906921067675">"बंद करें"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="match_status_description" msgid="4996847358326345288">"<xliff:g id="TOTAL">%2$d</xliff:g> में से <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="message_no_match_status" msgid="5929387004361286433">"कोई मिलता-जुलता नतीजा नहीं मिला"</string>
     <string name="action_edit" msgid="5882082700509010966">"फ़ाइल में बदलाव करें"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"अनलॉक करने के लिए पासवर्ड डालें"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-hr/strings.xml b/pdf/pdf-viewer/src/main/res/values-hr/strings.xml
index d2be613..69663f2 100644
--- a/pdf/pdf-viewer/src/main/res/values-hr/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-hr/strings.xml
@@ -47,6 +47,7 @@
     <string name="next_button_description" msgid="4702699322249103693">"Sljedeće"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Zatvori"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="match_status_description" msgid="4996847358326345288">"<xliff:g id="POSITION">%1$d</xliff:g> od <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="message_no_match_status" msgid="5929387004361286433">"Nema podudarnih rezultata"</string>
     <string name="action_edit" msgid="5882082700509010966">"Uređivanje datoteke"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Unesite zaporku za otključavanje"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-hu/strings.xml b/pdf/pdf-viewer/src/main/res/values-hu/strings.xml
index 13cefe9..746c393 100644
--- a/pdf/pdf-viewer/src/main/res/values-hu/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-hu/strings.xml
@@ -47,6 +47,7 @@
     <string name="next_button_description" msgid="4702699322249103693">"Következő"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Bezárás"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="TOTAL">%2$d</xliff:g>/<xliff:g id="POSITION">%1$d</xliff:g>."</string>
+    <string name="match_status_description" msgid="4996847358326345288">"<xliff:g id="TOTAL">%2$d</xliff:g>/<xliff:g id="POSITION">%1$d</xliff:g>."</string>
     <string name="message_no_match_status" msgid="5929387004361286433">"Nincs találat"</string>
     <string name="action_edit" msgid="5882082700509010966">"Fájl szerkesztése"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"A feloldáshoz írja be a jelszót"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-hy/strings.xml b/pdf/pdf-viewer/src/main/res/values-hy/strings.xml
index 53b5c63..0930a77 100644
--- a/pdf/pdf-viewer/src/main/res/values-hy/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-hy/strings.xml
@@ -47,6 +47,7 @@
     <string name="next_button_description" msgid="4702699322249103693">"Հաջորդը"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Փակել"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="match_status_description" msgid="4996847358326345288">"<xliff:g id="POSITION">%1$d</xliff:g>՝ <xliff:g id="TOTAL">%2$d</xliff:g>-ից"</string>
     <string name="message_no_match_status" msgid="5929387004361286433">"Համապատասխանող արդյունքներ չկան"</string>
     <string name="action_edit" msgid="5882082700509010966">"Փոփոխել ֆայլը"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Մուտքագրեք գաղտնաբառը՝ ապակողպելու համար"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-in/strings.xml b/pdf/pdf-viewer/src/main/res/values-in/strings.xml
index d1c6170b..3b84829 100644
--- a/pdf/pdf-viewer/src/main/res/values-in/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-in/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"Berikutnya"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Tutup"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"Tidak ada hasil yang cocok"</string>
     <string name="action_edit" msgid="5882082700509010966">"Edit file"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Masukkan sandi untuk membuka kunci"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-is/strings.xml b/pdf/pdf-viewer/src/main/res/values-is/strings.xml
index 845c448..84ae8bb 100644
--- a/pdf/pdf-viewer/src/main/res/values-is/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-is/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"Næsta"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Loka"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"Engar samsvarandi niðurstöður fundust"</string>
     <string name="action_edit" msgid="5882082700509010966">"Breyta skrá"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Sláðu inn aðgangsorð til að opna"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-it/strings.xml b/pdf/pdf-viewer/src/main/res/values-it/strings.xml
index bea8957..b566885 100644
--- a/pdf/pdf-viewer/src/main/res/values-it/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-it/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"Avanti"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Chiudi"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"Nessun risultato corrispondente"</string>
     <string name="action_edit" msgid="5882082700509010966">"Modifica file"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Inserisci la password per sbloccare il file"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-iw/strings.xml b/pdf/pdf-viewer/src/main/res/values-iw/strings.xml
index e7adcaa3..08eb4b5 100644
--- a/pdf/pdf-viewer/src/main/res/values-iw/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-iw/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"הבא"</string>
     <string name="close_button_description" msgid="7379823906921067675">"סגירה"</string>
     <string name="message_match_status" msgid="6288242289981639727">"‫<xliff:g id="POSITION">%1$d</xliff:g> מתוך <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"לא נמצאו תוצאות תואמות"</string>
     <string name="action_edit" msgid="5882082700509010966">"עריכת הקובץ"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"צריך להזין סיסמה לביטול הנעילה"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-ja/strings.xml b/pdf/pdf-viewer/src/main/res/values-ja/strings.xml
index e2161ea..09692f7 100644
--- a/pdf/pdf-viewer/src/main/res/values-ja/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ja/strings.xml
@@ -47,6 +47,7 @@
     <string name="next_button_description" msgid="4702699322249103693">"次へ"</string>
     <string name="close_button_description" msgid="7379823906921067675">"閉じる"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="match_status_description" msgid="4996847358326345288">"<xliff:g id="POSITION">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="message_no_match_status" msgid="5929387004361286433">"一致する結果がありません"</string>
     <string name="action_edit" msgid="5882082700509010966">"ファイルを編集"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"ロックを解除するには、パスワードを入力してください"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-ka/strings.xml b/pdf/pdf-viewer/src/main/res/values-ka/strings.xml
index 1d76eda..e131512 100644
--- a/pdf/pdf-viewer/src/main/res/values-ka/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ka/strings.xml
@@ -47,6 +47,7 @@
     <string name="next_button_description" msgid="4702699322249103693">"შემდეგი"</string>
     <string name="close_button_description" msgid="7379823906921067675">"დახურვა"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="match_status_description" msgid="4996847358326345288">"<xliff:g id="TOTAL">%2$d</xliff:g>-დან <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="message_no_match_status" msgid="5929387004361286433">"შედეგებში არ არის დამთხვევა"</string>
     <string name="action_edit" msgid="5882082700509010966">"ფაილის რედაქტირება"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"პაროლის შეყვანა განბლოკვისთვის"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-kk/strings.xml b/pdf/pdf-viewer/src/main/res/values-kk/strings.xml
index 6640153..31e081d 100644
--- a/pdf/pdf-viewer/src/main/res/values-kk/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-kk/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"Келесі"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Жабу"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"Сәйкес нәтижелер табылмады."</string>
     <string name="action_edit" msgid="5882082700509010966">"Файлды өңдеу"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Құлыпты ашу үшін құпия сөзді енгізіңіз."</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-km/strings.xml b/pdf/pdf-viewer/src/main/res/values-km/strings.xml
index 11cd884..5ce58c9 100644
--- a/pdf/pdf-viewer/src/main/res/values-km/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-km/strings.xml
@@ -47,6 +47,7 @@
     <string name="next_button_description" msgid="4702699322249103693">"បន្ទាប់"</string>
     <string name="close_button_description" msgid="7379823906921067675">"បិទ"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="match_status_description" msgid="4996847358326345288">"<xliff:g id="POSITION">%1$d</xliff:g> នៃ <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="message_no_match_status" msgid="5929387004361286433">"គ្មានលទ្ធផល​ត្រូវគ្នាទេ"</string>
     <string name="action_edit" msgid="5882082700509010966">"កែ​ឯកសារ"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"បញ្ចូល​ពាក្យ​សម្ងាត់ ដើម្បី​ដោះ​សោ"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-kn/strings.xml b/pdf/pdf-viewer/src/main/res/values-kn/strings.xml
index 65e39a0..a94de26 100644
--- a/pdf/pdf-viewer/src/main/res/values-kn/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-kn/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"ಮುಂದಿನದು"</string>
     <string name="close_button_description" msgid="7379823906921067675">"ಮುಚ್ಚಿರಿ"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"ಯಾವುದೇ ಹೊಂದಾಣಿಕೆಯ ಫಲಿತಾಂಶಗಳಿಲ್ಲ"</string>
     <string name="action_edit" msgid="5882082700509010966">"ಫೈಲ್ ಎಡಿಟ್‌ ಮಾಡಿ"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"ಅನ್‌ಲಾಕ್‌ ಮಾಡಲು ಪಾಸವರ್ಡ್‌ ಅನ್ನು ನಮೂದಿಸಿ"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-ko/strings.xml b/pdf/pdf-viewer/src/main/res/values-ko/strings.xml
index 0726b77..2dc42f3 100644
--- a/pdf/pdf-viewer/src/main/res/values-ko/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ko/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"다음"</string>
     <string name="close_button_description" msgid="7379823906921067675">"닫기"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"일치하는 결과 없음"</string>
     <string name="action_edit" msgid="5882082700509010966">"파일 수정"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"잠금 해제하려면 비밀번호 입력"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-ky/strings.xml b/pdf/pdf-viewer/src/main/res/values-ky/strings.xml
index 1a2783b..d88a930 100644
--- a/pdf/pdf-viewer/src/main/res/values-ky/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ky/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"Кийинки"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Жабуу"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"Эч нерсе табылган жок"</string>
     <string name="action_edit" msgid="5882082700509010966">"Файлды түзөтүү"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Кулпусун ачуу үчүн сырсөздү териңиз"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-lo/strings.xml b/pdf/pdf-viewer/src/main/res/values-lo/strings.xml
index 6eee324..4f4a7379 100644
--- a/pdf/pdf-viewer/src/main/res/values-lo/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-lo/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"ຕໍ່ໄປ"</string>
     <string name="close_button_description" msgid="7379823906921067675">"ປິດ"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"ບໍ່ມີຜົນໄດ້ຮັບທີ່ກົງກັນ"</string>
     <string name="action_edit" msgid="5882082700509010966">"ແກ້ໄຂໄຟລ໌"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"ໃສ່ລະຫັດເພື່ອປົດລັອກ"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-lt/strings.xml b/pdf/pdf-viewer/src/main/res/values-lt/strings.xml
index 44ef381..aea04bf 100644
--- a/pdf/pdf-viewer/src/main/res/values-lt/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-lt/strings.xml
@@ -47,6 +47,7 @@
     <string name="next_button_description" msgid="4702699322249103693">"Kitas"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Uždaryti"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="match_status_description" msgid="4996847358326345288">"<xliff:g id="POSITION">%1$d</xliff:g> iš <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="message_no_match_status" msgid="5929387004361286433">"Atitikusių rezultatų nerasta"</string>
     <string name="action_edit" msgid="5882082700509010966">"Redaguoti failą"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Įveskite slaptažodį, kad atrakintumėte"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-lv/strings.xml b/pdf/pdf-viewer/src/main/res/values-lv/strings.xml
index 62b43d2..8e489b8 100644
--- a/pdf/pdf-viewer/src/main/res/values-lv/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-lv/strings.xml
@@ -47,6 +47,7 @@
     <string name="next_button_description" msgid="4702699322249103693">"Tālāk"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Aizvērt"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="match_status_description" msgid="4996847358326345288">"numur <xliff:g id="POSITION">%1$d</xliff:g>, kopējais skaits ir <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="message_no_match_status" msgid="5929387004361286433">"Nav atbilstošu rezultātu."</string>
     <string name="action_edit" msgid="5882082700509010966">"Rediģēt failu"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Lai atbloķētu, ievadiet paroli."</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-mk/strings.xml b/pdf/pdf-viewer/src/main/res/values-mk/strings.xml
index 86424ba..f7b0a43 100644
--- a/pdf/pdf-viewer/src/main/res/values-mk/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-mk/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"Следно"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Затвори"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"Нема резултати што се совпаѓаат"</string>
     <string name="action_edit" msgid="5882082700509010966">"Изменете ја датотеката"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Внесете лозинка за да отклучите"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-ml/strings.xml b/pdf/pdf-viewer/src/main/res/values-ml/strings.xml
index e1c7e401..18dda28 100644
--- a/pdf/pdf-viewer/src/main/res/values-ml/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ml/strings.xml
@@ -47,6 +47,7 @@
     <string name="next_button_description" msgid="4702699322249103693">"അടുത്തത്"</string>
     <string name="close_button_description" msgid="7379823906921067675">"അടയ്ക്കുക"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="match_status_description" msgid="4996847358326345288">"<xliff:g id="TOTAL">%2$d</xliff:g>-ൽ <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="message_no_match_status" msgid="5929387004361286433">"പൊരുത്തപ്പെടുന്ന ഫലങ്ങളൊന്നുമില്ല"</string>
     <string name="action_edit" msgid="5882082700509010966">"ഫയൽ എഡിറ്റ് ചെയ്യുക"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"അൺലോക്ക് ചെയ്യാൻ പാസ്‌വേഡ് നൽകുക"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-mn/strings.xml b/pdf/pdf-viewer/src/main/res/values-mn/strings.xml
index eee4b83..5a406cd 100644
--- a/pdf/pdf-viewer/src/main/res/values-mn/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-mn/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"Дараах"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Хаах"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"Ямар ч тохирох илэрц байхгүй"</string>
     <string name="action_edit" msgid="5882082700509010966">"Файлыг засах"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Түгжээг тайлахын тулд нууц үг оруулна уу"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-mr/strings.xml b/pdf/pdf-viewer/src/main/res/values-mr/strings.xml
index 73892fc..663888f 100644
--- a/pdf/pdf-viewer/src/main/res/values-mr/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-mr/strings.xml
@@ -47,6 +47,7 @@
     <string name="next_button_description" msgid="4702699322249103693">"पुढील"</string>
     <string name="close_button_description" msgid="7379823906921067675">"बंद करा"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="match_status_description" msgid="4996847358326345288">"<xliff:g id="TOTAL">%2$d</xliff:g> पैकी <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="message_no_match_status" msgid="5929387004361286433">"कोणतेही जुळणारे परिणाम नाहीत"</string>
     <string name="action_edit" msgid="5882082700509010966">"फाइल संपादित करा"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"अनलॉक करण्यासाठी पासवर्ड एंटर करा"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-ms/strings.xml b/pdf/pdf-viewer/src/main/res/values-ms/strings.xml
index 7d642d7..c4565f0 100644
--- a/pdf/pdf-viewer/src/main/res/values-ms/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ms/strings.xml
@@ -47,6 +47,7 @@
     <string name="next_button_description" msgid="4702699322249103693">"Seterusnya"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Tutup"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="match_status_description" msgid="4996847358326345288">"<xliff:g id="POSITION">%1$d</xliff:g> daripada <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="message_no_match_status" msgid="5929387004361286433">"Tiada hasil carian yang sepadan"</string>
     <string name="action_edit" msgid="5882082700509010966">"Edit fail"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Masukkan kata laluan untuk membuka kunci"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-my/strings.xml b/pdf/pdf-viewer/src/main/res/values-my/strings.xml
index e642765..09ff37e 100644
--- a/pdf/pdf-viewer/src/main/res/values-my/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-my/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"ရှေ့သို့"</string>
     <string name="close_button_description" msgid="7379823906921067675">"ပိတ်ရန်"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"ကိုက်ညီသောရလဒ် မရှိပါ"</string>
     <string name="action_edit" msgid="5882082700509010966">"ဖိုင် တည်းဖြတ်ရန်"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"ဖွင့်ရန် စကားဝှက်ထည့်ပါ"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-nb/strings.xml b/pdf/pdf-viewer/src/main/res/values-nb/strings.xml
index 163e356..cb39104 100644
--- a/pdf/pdf-viewer/src/main/res/values-nb/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-nb/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"Neste"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Lukk"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"Ingen treff"</string>
     <string name="action_edit" msgid="5882082700509010966">"Endre filen"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Skriv inn passordet for å låse opp"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-ne/strings.xml b/pdf/pdf-viewer/src/main/res/values-ne/strings.xml
index 4530550..5ef47e9 100644
--- a/pdf/pdf-viewer/src/main/res/values-ne/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ne/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"अर्को"</string>
     <string name="close_button_description" msgid="7379823906921067675">"बन्द गर्नुहोस्"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"कुनै पनि मिल्दोजुल्दो परिणाम भेटिएन"</string>
     <string name="action_edit" msgid="5882082700509010966">"फाइल सम्पादन गर्नुहोस्"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"अनलक गर्न पासवर्ड हाल्नुहोस्"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-nl/strings.xml b/pdf/pdf-viewer/src/main/res/values-nl/strings.xml
index 1ddbf68..25fe496 100644
--- a/pdf/pdf-viewer/src/main/res/values-nl/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-nl/strings.xml
@@ -47,6 +47,7 @@
     <string name="next_button_description" msgid="4702699322249103693">"Volgende"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Sluiten"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="match_status_description" msgid="4996847358326345288">"<xliff:g id="POSITION">%1$d</xliff:g> van <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="message_no_match_status" msgid="5929387004361286433">"Geen overeenkomende resultaten"</string>
     <string name="action_edit" msgid="5882082700509010966">"Bestand bewerken"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Voer het wachtwoord in om te ontgrendelen"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-or/strings.xml b/pdf/pdf-viewer/src/main/res/values-or/strings.xml
index 4b08b7b..e67a2f5 100644
--- a/pdf/pdf-viewer/src/main/res/values-or/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-or/strings.xml
@@ -47,6 +47,7 @@
     <string name="next_button_description" msgid="4702699322249103693">"ପରବର୍ତ୍ତୀ"</string>
     <string name="close_button_description" msgid="7379823906921067675">"ବନ୍ଦ କରନ୍ତୁ"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="match_status_description" msgid="4996847358326345288">"<xliff:g id="TOTAL">%2$d</xliff:g>ର <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="message_no_match_status" msgid="5929387004361286433">"ମେଳ ହେଉଥିବା କୌଣସି ଫଳାଫଳ ନାହିଁ"</string>
     <string name="action_edit" msgid="5882082700509010966">"ଫାଇଲକୁ ଏଡିଟ କରନ୍ତୁ"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"ଅନଲକ କରିବା ପାଇଁ ପାସୱାର୍ଡ ଲେଖନ୍ତୁ"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-pa/strings.xml b/pdf/pdf-viewer/src/main/res/values-pa/strings.xml
index e68fbfa..b4845ba 100644
--- a/pdf/pdf-viewer/src/main/res/values-pa/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-pa/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"ਅੱਗੇ"</string>
     <string name="close_button_description" msgid="7379823906921067675">"ਬੰਦ ਕਰੋ"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"ਕੋਈ ਮੇਲ ਖਾਂਦਾ ਨਤੀਜਾ ਨਹੀਂ"</string>
     <string name="action_edit" msgid="5882082700509010966">"ਫ਼ਾਈਲ ਦਾ ਸੰਪਾਦਨ ਕਰੋ"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"ਅਣਲਾਕ ਕਰਨ ਲਈ ਪਾਸਵਰਡ ਦਾਖਲ ਕਰੋ"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-pl/strings.xml b/pdf/pdf-viewer/src/main/res/values-pl/strings.xml
index 3d52bbc..848f550 100644
--- a/pdf/pdf-viewer/src/main/res/values-pl/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-pl/strings.xml
@@ -47,6 +47,7 @@
     <string name="next_button_description" msgid="4702699322249103693">"Dalej"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Zamknij"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="match_status_description" msgid="4996847358326345288">"<xliff:g id="POSITION">%1$d</xliff:g> z <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="message_no_match_status" msgid="5929387004361286433">"Brak pasujących wyników"</string>
     <string name="action_edit" msgid="5882082700509010966">"Edytuj plik"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Podaj hasło, aby odblokować"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-pt-rBR/strings.xml b/pdf/pdf-viewer/src/main/res/values-pt-rBR/strings.xml
index 57583b90..642730e 100644
--- a/pdf/pdf-viewer/src/main/res/values-pt-rBR/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-pt-rBR/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"Próxima"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Fechar"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"Nenhum resultado encontrado"</string>
     <string name="action_edit" msgid="5882082700509010966">"Editar arquivo"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Digite a senha para desbloquear"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-pt-rPT/strings.xml b/pdf/pdf-viewer/src/main/res/values-pt-rPT/strings.xml
index 17901b0..667143f 100644
--- a/pdf/pdf-viewer/src/main/res/values-pt-rPT/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-pt-rPT/strings.xml
@@ -47,6 +47,7 @@
     <string name="next_button_description" msgid="4702699322249103693">"Seguinte"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Fechar"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="match_status_description" msgid="4996847358326345288">"<xliff:g id="POSITION">%1$d</xliff:g> de <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="message_no_match_status" msgid="5929387004361286433">"Sem resultados correspondentes"</string>
     <string name="action_edit" msgid="5882082700509010966">"Editar ficheiro"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Introduza a palavra-passe para desbloquear"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-pt/strings.xml b/pdf/pdf-viewer/src/main/res/values-pt/strings.xml
index 57583b90..642730e 100644
--- a/pdf/pdf-viewer/src/main/res/values-pt/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-pt/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"Próxima"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Fechar"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"Nenhum resultado encontrado"</string>
     <string name="action_edit" msgid="5882082700509010966">"Editar arquivo"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Digite a senha para desbloquear"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-ro/strings.xml b/pdf/pdf-viewer/src/main/res/values-ro/strings.xml
index f33ce79..ea88bec 100644
--- a/pdf/pdf-viewer/src/main/res/values-ro/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ro/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"Înainte"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Închide"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"Niciun rezultat"</string>
     <string name="action_edit" msgid="5882082700509010966">"Editează fișierul"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Introdu parola pentru a debloca"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-ru/strings.xml b/pdf/pdf-viewer/src/main/res/values-ru/strings.xml
index b3bed54..d062234 100644
--- a/pdf/pdf-viewer/src/main/res/values-ru/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ru/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"Далее"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Закрыть"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g> из <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"Ничего не найдено."</string>
     <string name="action_edit" msgid="5882082700509010966">"Редактировать файл"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Введите пароль для разблокировки."</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-si/strings.xml b/pdf/pdf-viewer/src/main/res/values-si/strings.xml
index 7aeb8c8..3c22ba7 100644
--- a/pdf/pdf-viewer/src/main/res/values-si/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-si/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"මීළඟ"</string>
     <string name="close_button_description" msgid="7379823906921067675">"වසන්න"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"ගැළපෙන ප්‍රතිඵල නැත"</string>
     <string name="action_edit" msgid="5882082700509010966">"ගොනුව සංස්කරණ කරන්න"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"අගුලු හැරීමට මුරපදය ඇතුළත් කරන්න"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-sk/strings.xml b/pdf/pdf-viewer/src/main/res/values-sk/strings.xml
index 2c4e7b4..8fdcc4c 100644
--- a/pdf/pdf-viewer/src/main/res/values-sk/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-sk/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"Ďalej"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Zavrieť"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"Žiadne zodpovedajúce výsledky"</string>
     <string name="action_edit" msgid="5882082700509010966">"Upraviť súbor"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Zadajte heslo na odomknutie"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-sl/strings.xml b/pdf/pdf-viewer/src/main/res/values-sl/strings.xml
index 5ff5caa..e43931d 100644
--- a/pdf/pdf-viewer/src/main/res/values-sl/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-sl/strings.xml
@@ -47,6 +47,7 @@
     <string name="next_button_description" msgid="4702699322249103693">"Naprej"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Zapri"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="match_status_description" msgid="4996847358326345288">"<xliff:g id="POSITION">%1$d</xliff:g> od <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="message_no_match_status" msgid="5929387004361286433">"Ni ustreznih rezultatov"</string>
     <string name="action_edit" msgid="5882082700509010966">"Urejanje datoteke"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Vnesite geslo za odklepanje"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-sq/strings.xml b/pdf/pdf-viewer/src/main/res/values-sq/strings.xml
index a78b08a..482261d 100644
--- a/pdf/pdf-viewer/src/main/res/values-sq/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-sq/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"Para"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Mbyll"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"Nuk përputhet asnjë rezultat"</string>
     <string name="action_edit" msgid="5882082700509010966">"Modifiko skedarin"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Fut fjalëkalimin për ta shkyçur"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-sr/strings.xml b/pdf/pdf-viewer/src/main/res/values-sr/strings.xml
index 61074fd..ccd521a 100644
--- a/pdf/pdf-viewer/src/main/res/values-sr/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-sr/strings.xml
@@ -47,6 +47,7 @@
     <string name="next_button_description" msgid="4702699322249103693">"Даље"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Затвори"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="match_status_description" msgid="4996847358326345288">"<xliff:g id="POSITION">%1$d</xliff:g> од <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="message_no_match_status" msgid="5929387004361286433">"Нема подударних резултата"</string>
     <string name="action_edit" msgid="5882082700509010966">"Измени фајл"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Унесите лозинку за откључавање"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-sv/strings.xml b/pdf/pdf-viewer/src/main/res/values-sv/strings.xml
index e756be8..edbbf58 100644
--- a/pdf/pdf-viewer/src/main/res/values-sv/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-sv/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"Nästa"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Stäng"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"Det finns inga matchande resultat"</string>
     <string name="action_edit" msgid="5882082700509010966">"Redigera fil"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Ange lösenord för att låsa upp"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-sw/strings.xml b/pdf/pdf-viewer/src/main/res/values-sw/strings.xml
index 9f50a92a..f26bdf5 100644
--- a/pdf/pdf-viewer/src/main/res/values-sw/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-sw/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"Endelea"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Funga"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g> kati ya <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"Hakuna matokeo yanayolingana"</string>
     <string name="action_edit" msgid="5882082700509010966">"Badilisha faili"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Weka nenosiri ili ufungue"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-ta/strings.xml b/pdf/pdf-viewer/src/main/res/values-ta/strings.xml
index 3c329ca..56321e0 100644
--- a/pdf/pdf-viewer/src/main/res/values-ta/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ta/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"அடுத்ததற்குச் செல்லும்"</string>
     <string name="close_button_description" msgid="7379823906921067675">"மூடும்"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"பொருந்தும் முடிவுகள் எதுவுமில்லை"</string>
     <string name="action_edit" msgid="5882082700509010966">"ஃபைலைத் திருத்து"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"அன்லாக் செய்ய கடவுச்சொல்லை டைப் செய்யவும்"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-te/strings.xml b/pdf/pdf-viewer/src/main/res/values-te/strings.xml
index 1b0c0d8..3cc15c5 100644
--- a/pdf/pdf-viewer/src/main/res/values-te/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-te/strings.xml
@@ -47,6 +47,7 @@
     <string name="next_button_description" msgid="4702699322249103693">"తర్వాత"</string>
     <string name="close_button_description" msgid="7379823906921067675">"మూసివేయండి"</string>
     <string name="message_match_status" msgid="6288242289981639727">"మొత్తం <xliff:g id="TOTAL">%2$d</xliff:g>లో <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="match_status_description" msgid="4996847358326345288">"<xliff:g id="TOTAL">%2$d</xliff:g>లో <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="message_no_match_status" msgid="5929387004361286433">"మ్యాచ్ అయ్యే ఫలితాలు ఏవీ లేవు"</string>
     <string name="action_edit" msgid="5882082700509010966">"ఫైల్‌ను ఎడిట్ చేయండి"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"అన్‌లాక్ చేయడానికి పాస్‌వర్డ్‌ను నమోదు చేయండి"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-th/strings.xml b/pdf/pdf-viewer/src/main/res/values-th/strings.xml
index 17236b8..3f4cacb 100644
--- a/pdf/pdf-viewer/src/main/res/values-th/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-th/strings.xml
@@ -47,6 +47,7 @@
     <string name="next_button_description" msgid="4702699322249103693">"ถัดไป"</string>
     <string name="close_button_description" msgid="7379823906921067675">"ปิด"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="match_status_description" msgid="4996847358326345288">"<xliff:g id="POSITION">%1$d</xliff:g> จาก <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="message_no_match_status" msgid="5929387004361286433">"ไม่มีผลลัพธ์ที่ตรงกัน"</string>
     <string name="action_edit" msgid="5882082700509010966">"แก้ไขไฟล์"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"ป้อนรหัสผ่านเพื่อปลดล็อก"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-tl/strings.xml b/pdf/pdf-viewer/src/main/res/values-tl/strings.xml
index 1daaa55..8dded5f 100644
--- a/pdf/pdf-viewer/src/main/res/values-tl/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-tl/strings.xml
@@ -47,6 +47,7 @@
     <string name="next_button_description" msgid="4702699322249103693">"Susunod"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Isara"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="match_status_description" msgid="4996847358326345288">"<xliff:g id="POSITION">%1$d</xliff:g> sa <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="message_no_match_status" msgid="5929387004361286433">"Walang tumutugmang resulta"</string>
     <string name="action_edit" msgid="5882082700509010966">"I-edit ang file"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Ilagay ang password para i-unlock"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-tr/strings.xml b/pdf/pdf-viewer/src/main/res/values-tr/strings.xml
index c378486..d247153 100644
--- a/pdf/pdf-viewer/src/main/res/values-tr/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-tr/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"Sonraki"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Kapat"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"Eşleşen sonuç yok"</string>
     <string name="action_edit" msgid="5882082700509010966">"Dosyayı düzenle"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Kilidi açmak için şifreyi girin"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-uk/strings.xml b/pdf/pdf-viewer/src/main/res/values-uk/strings.xml
index 358244d..11c4ecf 100644
--- a/pdf/pdf-viewer/src/main/res/values-uk/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-uk/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"Далі"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Закрити"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"Немає результатів"</string>
     <string name="action_edit" msgid="5882082700509010966">"Редагувати файл"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Введіть пароль, щоб розблокувати"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-ur/strings.xml b/pdf/pdf-viewer/src/main/res/values-ur/strings.xml
index 97c7973..12ccee6 100644
--- a/pdf/pdf-viewer/src/main/res/values-ur/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ur/strings.xml
@@ -47,6 +47,7 @@
     <string name="next_button_description" msgid="4702699322249103693">"اگلا"</string>
     <string name="close_button_description" msgid="7379823906921067675">"بند کریں"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="TOTAL">%2$d</xliff:g> / <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="match_status_description" msgid="4996847358326345288">"<xliff:g id="POSITION">%1$d</xliff:g> از <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="message_no_match_status" msgid="5929387004361286433">"کوئی مماثل نتائج نہیں ہیں"</string>
     <string name="action_edit" msgid="5882082700509010966">"فائل میں ترمیم کریں"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"غیر مقفل کرنے کیلئے پاس ورڈ درج کریں"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-uz/strings.xml b/pdf/pdf-viewer/src/main/res/values-uz/strings.xml
index eaea88b..82dd413 100644
--- a/pdf/pdf-viewer/src/main/res/values-uz/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-uz/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"Keyingisi"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Yopish"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"Mos keladigani topilmadi"</string>
     <string name="action_edit" msgid="5882082700509010966">"Faylni tahrirlash"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Ochish uchun parolni kiriting"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-vi/strings.xml b/pdf/pdf-viewer/src/main/res/values-vi/strings.xml
index 1960c80..42e04e9 100644
--- a/pdf/pdf-viewer/src/main/res/values-vi/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-vi/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"Tiếp theo"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Đóng"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"Không có kết quả phù hợp"</string>
     <string name="action_edit" msgid="5882082700509010966">"Chỉnh sửa tệp"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Nhập mật khẩu để mở khoá"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-zh-rCN/strings.xml b/pdf/pdf-viewer/src/main/res/values-zh-rCN/strings.xml
index cf29a52..343768c 100644
--- a/pdf/pdf-viewer/src/main/res/values-zh-rCN/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-zh-rCN/strings.xml
@@ -47,6 +47,7 @@
     <string name="next_button_description" msgid="4702699322249103693">"下一页"</string>
     <string name="close_button_description" msgid="7379823906921067675">"关闭"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="match_status_description" msgid="4996847358326345288">"第 <xliff:g id="POSITION">%1$d</xliff:g> 个(共 <xliff:g id="TOTAL">%2$d</xliff:g> 个)"</string>
     <string name="message_no_match_status" msgid="5929387004361286433">"没有符合条件的结果"</string>
     <string name="action_edit" msgid="5882082700509010966">"编辑文件"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"请输入密码进行解锁"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-zh-rHK/strings.xml b/pdf/pdf-viewer/src/main/res/values-zh-rHK/strings.xml
index 06c8e92..984fbe1 100644
--- a/pdf/pdf-viewer/src/main/res/values-zh-rHK/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-zh-rHK/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"下一個"</string>
     <string name="close_button_description" msgid="7379823906921067675">"閂"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"找不到相符的結果"</string>
     <string name="action_edit" msgid="5882082700509010966">"編輯檔案"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"輸入密碼即可解鎖"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-zh-rTW/strings.xml b/pdf/pdf-viewer/src/main/res/values-zh-rTW/strings.xml
index 12b583f..915cd4a 100644
--- a/pdf/pdf-viewer/src/main/res/values-zh-rTW/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-zh-rTW/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"下一個"</string>
     <string name="close_button_description" msgid="7379823906921067675">"關閉"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"找不到相符的結果"</string>
     <string name="action_edit" msgid="5882082700509010966">"編輯檔案"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"輸入密碼即可解鎖"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-zu/strings.xml b/pdf/pdf-viewer/src/main/res/values-zu/strings.xml
index a3ad158..23f95f7 100644
--- a/pdf/pdf-viewer/src/main/res/values-zu/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-zu/strings.xml
@@ -47,6 +47,8 @@
     <string name="next_button_description" msgid="4702699322249103693">"Okulandelayo"</string>
     <string name="close_button_description" msgid="7379823906921067675">"Vala"</string>
     <string name="message_match_status" msgid="6288242289981639727">"<xliff:g id="POSITION">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <!-- no translation found for match_status_description (4996847358326345288) -->
+    <skip />
     <string name="message_no_match_status" msgid="5929387004361286433">"Ayikho imiphumela efanayo"</string>
     <string name="action_edit" msgid="5882082700509010966">"Hlela ifayela"</string>
     <string name="password_not_entered" msgid="8875370870743585303">"Faka iphasiwedi ukuvula"</string>
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/ext/xelement_ext.kt b/room/room-compiler/src/main/kotlin/androidx/room/ext/xelement_ext.kt
index bf4537a..28f9f0c 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/ext/xelement_ext.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/ext/xelement_ext.kt
@@ -16,10 +16,8 @@
 
 package androidx.room.ext
 
-import androidx.room.compiler.processing.XConstructorElement
 import androidx.room.compiler.processing.XElement
 import androidx.room.compiler.processing.XExecutableParameterElement
-import androidx.room.compiler.processing.XFieldElement
 import androidx.room.compiler.processing.XTypeElement
 import kotlin.contracts.contract
 
@@ -28,7 +26,7 @@
     return this.hasAnnotation(androidx.room.Entity::class)
 }
 
-fun XTypeElement.getValueClassUnderlyingInfo(): ValueClassInfo {
+fun XTypeElement.getValueClassUnderlyingElement(): XExecutableParameterElement {
     check(this.isValueClass()) {
         "Can't get value class property, type element '$this' is not a value class"
     }
@@ -36,21 +34,12 @@
     // * Primary constructor is required for value class
     // * Value class must have exactly one primary constructor parameter
     // * Value class primary constructor must only have final read-only (val) property parameter
-    val constructor =
-        checkNotNull(this.findPrimaryConstructor()) {
+    return checkNotNull(this.findPrimaryConstructor()) {
             "Couldn't find primary constructor for value class."
         }
-    val param = constructor.parameters.first()
-    val field = getDeclaredFields().first { it.name == param.name }
-    return ValueClassInfo(constructor, param, field)
+        .parameters
+        .single()
 }
 
-/** Store information about the underlying value property of a Kotlin value class */
-class ValueClassInfo(
-    val constructor: XConstructorElement,
-    val parameter: XExecutableParameterElement,
-    val field: XFieldElement,
-)
-
 /** Suffix of the Kotlin synthetic class created interface method implementations. */
 const val DEFAULT_IMPLS_CLASS_NAME = "DefaultImpls"
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/TypeAdapterStore.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/TypeAdapterStore.kt
index 86c5e95..798bfeb 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/TypeAdapterStore.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/TypeAdapterStore.kt
@@ -28,7 +28,7 @@
 import androidx.room.ext.CollectionTypeNames.LONG_SPARSE_ARRAY
 import androidx.room.ext.CommonTypeNames
 import androidx.room.ext.GuavaTypeNames
-import androidx.room.ext.getValueClassUnderlyingInfo
+import androidx.room.ext.getValueClassUnderlyingElement
 import androidx.room.ext.isByteBuffer
 import androidx.room.ext.isEntityElement
 import androidx.room.ext.isNotByte
@@ -377,15 +377,12 @@
         val typeElement = type.typeElement
         if (typeElement?.isValueClass() == true) {
             // Extract the type value of the Value class element
-            val underlyingInfo = typeElement.getValueClassUnderlyingInfo()
-            if (underlyingInfo.constructor.isPrivate() || underlyingInfo.field.getter == null) {
-                return null
-            }
+            val underlyingProperty = typeElement.getValueClassUnderlyingElement()
             val underlyingTypeColumnAdapter =
                 findColumnTypeAdapter(
                     // Find an adapter for the non-null underlying type, nullability will be handled
                     // by the value class adapter.
-                    out = underlyingInfo.parameter.asMemberOf(type).makeNonNullable(),
+                    out = underlyingProperty.asMemberOf(type).makeNonNullable(),
                     affinity = affinity,
                     skipDefaultConverter = false
                 ) ?: return null
@@ -394,7 +391,7 @@
                 valueTypeColumnAdapter = underlyingTypeColumnAdapter,
                 affinity = underlyingTypeColumnAdapter.typeAffinity,
                 out = type,
-                valuePropertyName = underlyingInfo.parameter.name
+                valuePropertyName = underlyingProperty.name
             )
         }
         return when {
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/ext/ElementExtTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/ext/ElementExtTest.kt
index db835d4..1e314bf 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/ext/ElementExtTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/ext/ElementExtTest.kt
@@ -24,7 +24,7 @@
 import androidx.room.compiler.processing.util.Source
 import androidx.room.compiler.processing.util.XTestInvocation
 import androidx.room.compiler.processing.util.compileFiles
-import androidx.room.compiler.processing.util.runKspTest
+import androidx.room.runKspTestWithK1
 import androidx.room.runProcessorTestWithK1
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -225,44 +225,25 @@
                 """
             package foo
             class Subject {
-              fun uLongFunction(): ULong = TODO()
-              fun durationFunction(): kotlin.time.Duration = TODO()
+              fun makeULong(): ULong {
+                TODO()
+              }
             }
             """
                     .trimIndent()
             )
-        runKspTest(
+        runKspTestWithK1(
             sources = listOf(src),
             config =
                 XProcessingEnvConfig.DEFAULT.copy(excludeMethodsWithInvalidJvmSourceNames = false)
         ) { invocation ->
             val subject = invocation.processingEnv.requireTypeElement("foo.Subject")
-            subject
-                .getDeclaredMethods()
-                .first { it.name == "uLongFunction" }
-                .let { uLongFunction ->
-                    val returnType = uLongFunction.returnType
-                    val info = checkNotNull(returnType.typeElement).getValueClassUnderlyingInfo()
-                    assertThat(info.parameter.name).isEqualTo("data")
-                    assertThat(info.field.name).isEqualTo("data")
-                    assertThat(info.parameter.type)
-                        .isEqualTo(invocation.processingEnv.requireType(XTypeName.PRIMITIVE_LONG))
-                    assertThat(info.field.type)
-                        .isEqualTo(invocation.processingEnv.requireType(XTypeName.PRIMITIVE_LONG))
-                }
-            subject
-                .getDeclaredMethods()
-                .first { it.name == "durationFunction" }
-                .let { durationFunction ->
-                    val returnType = durationFunction.returnType
-                    val info = checkNotNull(returnType.typeElement).getValueClassUnderlyingInfo()
-                    assertThat(info.parameter.name).isEqualTo("rawValue")
-                    assertThat(info.field.name).isEqualTo("rawValue")
-                    assertThat(info.parameter.type)
-                        .isEqualTo(invocation.processingEnv.requireType(XTypeName.PRIMITIVE_LONG))
-                    assertThat(info.field.type)
-                        .isEqualTo(invocation.processingEnv.requireType(XTypeName.PRIMITIVE_LONG))
-                }
+            val returnType =
+                subject.getDeclaredMethods().single { it.name == "makeULong" }.returnType
+            val prop = checkNotNull(returnType.typeElement).getValueClassUnderlyingElement()
+            assertThat(prop.name).isEqualTo("data")
+            assertThat(prop.type)
+                .isEqualTo(invocation.processingEnv.requireType(XTypeName.PRIMITIVE_LONG))
         }
     }
 
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/solver/TypeAdapterStoreTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/solver/TypeAdapterStoreTest.kt
index d43a813..29cbd79 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/solver/TypeAdapterStoreTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/solver/TypeAdapterStoreTest.kt
@@ -30,7 +30,6 @@
 import androidx.room.compiler.processing.util.Source
 import androidx.room.compiler.processing.util.XTestInvocation
 import androidx.room.compiler.processing.util.compileFiles
-import androidx.room.compiler.processing.util.runKspTest
 import androidx.room.compiler.processing.util.runProcessorTest
 import androidx.room.ext.CommonTypeNames
 import androidx.room.ext.GuavaUtilConcurrentTypeNames
@@ -196,6 +195,7 @@
             Source.java(
                 "foo.bar.Fruit",
                 """ package foo.bar;
+                import androidx.room.*;
                 enum Fruit {
                     APPLE,
                     BANANA,
@@ -222,6 +222,7 @@
             Source.kotlin(
                 "Foo.kt",
                 """
+            import androidx.room.*
             @JvmInline
             value class IntValueClass(val data: Int)
             @JvmInline
@@ -281,6 +282,7 @@
             Source.kotlin(
                 "Foo.kt",
                 """
+            import androidx.room.*
             @JvmInline
             value class Foo(val value : Int) {
                 val double
@@ -290,78 +292,15 @@
                     .trimIndent()
             )
 
-        runKspTest(sources = listOf(source)) { invocation ->
-            val store =
-                TypeAdapterStore.create(
-                    context = invocation.context,
-                    builtInConverterFlags = BuiltInConverterFlags.DEFAULT
-                )
-            val typeElement = invocation.processingEnv.requireTypeElement("Foo")
-            val result =
-                store.findColumnTypeAdapter(
-                    out = typeElement.type,
-                    affinity = null,
-                    skipDefaultConverter = false
-                )
-            assertThat(result).isInstanceOf<ValueClassConverterWrapper>()
-        }
-    }
-
-    @Test
-    fun testValueClassWithPrivateVal() {
-        val source =
-            Source.kotlin(
-                "Foo.kt",
-                """
-            @JvmInline
-            value class Foo(private val value : Int)
-            """
-                    .trimIndent()
+        runProcessorTestWithK1(sources = listOf(source)) { invocation ->
+            TypeAdapterStore.create(
+                context = invocation.context,
+                builtInConverterFlags = BuiltInConverterFlags.DEFAULT
             )
-
-        runKspTest(sources = listOf(source)) { invocation ->
-            val store =
-                TypeAdapterStore.create(
-                    context = invocation.context,
-                    builtInConverterFlags = BuiltInConverterFlags.DEFAULT
-                )
             val typeElement = invocation.processingEnv.requireTypeElement("Foo")
-            val result =
-                store.findColumnTypeAdapter(
-                    out = typeElement.type,
-                    affinity = null,
-                    skipDefaultConverter = false
-                )
-            assertThat(result).isNull()
-        }
-    }
-
-    @Test
-    fun testValueClassWithPrivateConstructor() {
-        val source =
-            Source.kotlin(
-                "Foo.kt",
-                """
-            @JvmInline
-            value class Foo private constructor(val value : Int)
-            """
-                    .trimIndent()
-            )
-
-        runKspTest(sources = listOf(source)) { invocation ->
-            val store =
-                TypeAdapterStore.create(
-                    context = invocation.context,
-                    builtInConverterFlags = BuiltInConverterFlags.DEFAULT
-                )
-            val typeElement = invocation.processingEnv.requireTypeElement("Foo")
-            val result =
-                store.findColumnTypeAdapter(
-                    out = typeElement.type,
-                    affinity = null,
-                    skipDefaultConverter = false
-                )
-            assertThat(result).isNull()
+            assertThat(typeElement.getDeclaredFields()).hasSize(1)
+            assertThat(typeElement.getDeclaredFields().single().type.asTypeName())
+                .isEqualTo(PRIMITIVE_INT)
         }
     }
 
diff --git a/room/room-testing/build.gradle b/room/room-testing/build.gradle
index 14a4823..4678633 100644
--- a/room/room-testing/build.gradle
+++ b/room/room-testing/build.gradle
@@ -22,7 +22,6 @@
  * modifying its settings.
  */
 
-
 import androidx.build.KotlinTarget
 import androidx.build.PlatformIdentifier
 import androidx.build.LibraryType
@@ -30,11 +29,20 @@
 
 plugins {
     id("AndroidXPlugin")
-    id("com.android.library")
 }
 
 androidXMultiplatform {
-    android()
+    androidLibrary {
+        namespace = "androidx.room.testing"
+        withAndroidTestOnDeviceBuilder {
+            it.compilationName = "instrumentedTest"
+            it.defaultSourceSetName = "androidInstrumentedTest"
+            it.sourceSetTreeName = "test"
+        }
+        withAndroidTestOnJvmBuilder {
+            it.defaultSourceSetName = "androidUnitTest"
+        }
+    }
     ios()
     jvm()
     linux()
@@ -88,9 +96,6 @@
     }
 }
 
-android {
-    namespace "androidx.room.testing"
-}
 
 androidx {
     name = "Room Testing"
diff --git a/savedstate/savedstate/api/current.txt b/savedstate/savedstate/api/current.txt
index fe1c8f0..89289e4 100644
--- a/savedstate/savedstate/api/current.txt
+++ b/savedstate/savedstate/api/current.txt
@@ -13,6 +13,7 @@
   @kotlin.jvm.JvmInline public final value class SavedStateReader {
     ctor public SavedStateReader(android.os.Bundle source);
     method public inline operator boolean contains(String key);
+    method public boolean contentDeepEquals(android.os.Bundle other);
     method public inline boolean getBoolean(String key);
     method public inline boolean getBooleanOrElse(String key, kotlin.jvm.functions.Function0<java.lang.Boolean> defaultValue);
     method public inline double getDouble(String key);
@@ -99,7 +100,7 @@
   }
 
   public final class SavedState_androidKt {
-    method public static inline android.os.Bundle savedState(optional kotlin.jvm.functions.Function1<? super androidx.savedstate.SavedStateWriter,kotlin.Unit> block);
+    method public static inline android.os.Bundle savedState(optional java.util.Map<java.lang.String,?> initialState, optional kotlin.jvm.functions.Function1<? super androidx.savedstate.SavedStateWriter,kotlin.Unit> builderAction);
   }
 
   public final class ViewKt {
diff --git a/savedstate/savedstate/api/restricted_current.txt b/savedstate/savedstate/api/restricted_current.txt
index 47dcf78..a7d6580 100644
--- a/savedstate/savedstate/api/restricted_current.txt
+++ b/savedstate/savedstate/api/restricted_current.txt
@@ -13,6 +13,7 @@
   @kotlin.jvm.JvmInline public final value class SavedStateReader {
     ctor public SavedStateReader(android.os.Bundle source);
     method public inline operator boolean contains(String key);
+    method public boolean contentDeepEquals(android.os.Bundle other);
     method public inline boolean getBoolean(String key);
     method public inline boolean getBooleanOrElse(String key, kotlin.jvm.functions.Function0<java.lang.Boolean> defaultValue);
     method public inline double getDouble(String key);
@@ -45,6 +46,10 @@
     property public final android.os.Bundle source;
   }
 
+  public final class SavedStateReader_androidKt {
+    method @kotlin.PublishedApi internal static boolean contentDeepEquals(android.os.Bundle, android.os.Bundle other);
+  }
+
   public final class SavedStateRegistry {
     method @MainThread public android.os.Bundle? consumeRestoredStateForKey(String key);
     method public androidx.savedstate.SavedStateRegistry.SavedStateProvider? getSavedStateProvider(String key);
@@ -104,7 +109,7 @@
   }
 
   public final class SavedState_androidKt {
-    method public static inline android.os.Bundle savedState(optional kotlin.jvm.functions.Function1<? super androidx.savedstate.SavedStateWriter,kotlin.Unit> block);
+    method public static inline android.os.Bundle savedState(optional java.util.Map<java.lang.String,?> initialState, optional kotlin.jvm.functions.Function1<? super androidx.savedstate.SavedStateWriter,kotlin.Unit> builderAction);
   }
 
   public final class ViewKt {
diff --git a/savedstate/savedstate/bcv/native/current.txt b/savedstate/savedstate/bcv/native/current.txt
index 1a70510..8cad989 100644
--- a/savedstate/savedstate/bcv/native/current.txt
+++ b/savedstate/savedstate/bcv/native/current.txt
@@ -51,6 +51,7 @@
     final val source // androidx.savedstate/SavedStateReader.source|{}source[0]
         final fun <get-source>(): androidx.savedstate/SavedState // androidx.savedstate/SavedStateReader.source.<get-source>|<get-source>(){}[0]
 
+    final fun contentDeepEquals(androidx.savedstate/SavedState): kotlin/Boolean // androidx.savedstate/SavedStateReader.contentDeepEquals|contentDeepEquals(androidx.savedstate.SavedState){}[0]
     final fun equals(kotlin/Any?): kotlin/Boolean // androidx.savedstate/SavedStateReader.equals|equals(kotlin.Any?){}[0]
     final fun hashCode(): kotlin/Int // androidx.savedstate/SavedStateReader.hashCode|hashCode(){}[0]
     final fun toString(): kotlin/String // androidx.savedstate/SavedStateReader.toString|toString(){}[0]
@@ -126,4 +127,4 @@
 final inline fun <#A: kotlin/Any?> (androidx.savedstate/SavedState).androidx.savedstate/write(kotlin/Function1<androidx.savedstate/SavedStateWriter, #A>): #A // androidx.savedstate/write|write@androidx.savedstate.SavedState(kotlin.Function1<androidx.savedstate.SavedStateWriter,0:0>){0§<kotlin.Any?>}[0]
 final inline fun <#A: kotlin/Any?> (androidx.savedstate/SavedStateReader).androidx.savedstate/write(kotlin/Function1<androidx.savedstate/SavedStateWriter, #A>): #A // androidx.savedstate/write|write@androidx.savedstate.SavedStateReader(kotlin.Function1<androidx.savedstate.SavedStateWriter,0:0>){0§<kotlin.Any?>}[0]
 final inline fun <#A: kotlin/Any?> (androidx.savedstate/SavedStateWriter).androidx.savedstate/read(kotlin/Function1<androidx.savedstate/SavedStateReader, #A>): #A // androidx.savedstate/read|read@androidx.savedstate.SavedStateWriter(kotlin.Function1<androidx.savedstate.SavedStateReader,0:0>){0§<kotlin.Any?>}[0]
-final inline fun androidx.savedstate/savedState(kotlin/Function1<androidx.savedstate/SavedStateWriter, kotlin/Unit> = ...): androidx.savedstate/SavedState // androidx.savedstate/savedState|savedState(kotlin.Function1<androidx.savedstate.SavedStateWriter,kotlin.Unit>){}[0]
+final inline fun androidx.savedstate/savedState(kotlin.collections/Map<kotlin/String, kotlin/Any> = ..., kotlin/Function1<androidx.savedstate/SavedStateWriter, kotlin/Unit> = ...): androidx.savedstate/SavedState // androidx.savedstate/savedState|savedState(kotlin.collections.Map<kotlin.String,kotlin.Any>;kotlin.Function1<androidx.savedstate.SavedStateWriter,kotlin.Unit>){}[0]
diff --git a/savedstate/savedstate/src/androidMain/kotlin/androidx/savedstate/SavedState.android.kt b/savedstate/savedstate/src/androidMain/kotlin/androidx/savedstate/SavedState.android.kt
index 6d51126..6d339bc 100644
--- a/savedstate/savedstate/src/androidMain/kotlin/androidx/savedstate/SavedState.android.kt
+++ b/savedstate/savedstate/src/androidMain/kotlin/androidx/savedstate/SavedState.android.kt
@@ -14,9 +14,23 @@
  * limitations under the License.
  */
 
+@file:Suppress("NOTHING_TO_INLINE")
+
 package androidx.savedstate
 
+import androidx.core.os.bundleOf
+
 public actual typealias SavedState = android.os.Bundle
 
-public actual inline fun savedState(block: SavedStateWriter.() -> Unit): SavedState =
-    SavedState().apply { write(block) }
+public actual inline fun savedState(
+    initialState: Map<String, Any>,
+    builderAction: SavedStateWriter.() -> Unit,
+): SavedState {
+    val pairs =
+        if (initialState.isEmpty()) {
+            emptyArray()
+        } else {
+            initialState.map { (key, value) -> key to value }.toTypedArray()
+        }
+    return bundleOf(*pairs).apply { write(builderAction) }
+}
diff --git a/savedstate/savedstate/src/androidMain/kotlin/androidx/savedstate/SavedStateReader.android.kt b/savedstate/savedstate/src/androidMain/kotlin/androidx/savedstate/SavedStateReader.android.kt
index c17f0fa..f14a7d4 100644
--- a/savedstate/savedstate/src/androidMain/kotlin/androidx/savedstate/SavedStateReader.android.kt
+++ b/savedstate/savedstate/src/androidMain/kotlin/androidx/savedstate/SavedStateReader.android.kt
@@ -33,7 +33,7 @@
     }
 
     actual inline fun getBooleanOrElse(key: String, defaultValue: () -> Boolean): Boolean {
-        return getSingleResultOrElse(key, defaultValue) { source.getBoolean(key) }
+        return getSingleResultOrElse(key, defaultValue) { source.getBoolean(key, defaultValue()) }
     }
 
     actual inline fun getDouble(key: String): Double {
@@ -41,7 +41,7 @@
     }
 
     actual inline fun getDoubleOrElse(key: String, defaultValue: () -> Double): Double {
-        return getSingleResultOrElse(key, defaultValue) { source.getDouble(key) }
+        return getSingleResultOrElse(key, defaultValue) { source.getDouble(key, defaultValue()) }
     }
 
     actual inline fun getFloat(key: String): Float {
@@ -49,7 +49,7 @@
     }
 
     actual inline fun getFloatOrElse(key: String, defaultValue: () -> Float): Float {
-        return getSingleResultOrElse(key, defaultValue) { source.getFloat(key) }
+        return getSingleResultOrElse(key, defaultValue) { source.getFloat(key, defaultValue()) }
     }
 
     actual inline fun getInt(key: String): Int {
@@ -57,15 +57,15 @@
     }
 
     actual inline fun getIntOrElse(key: String, defaultValue: () -> Int): Int {
-        return getSingleResultOrElse(key, defaultValue) { source.getInt(key) }
+        return getSingleResultOrElse(key, defaultValue) { source.getInt(key, defaultValue()) }
     }
 
     actual inline fun getLong(key: String): Long {
-        return getSingleResultOrThrow(key) { source.getLong(key) }
+        return getSingleResultOrThrow(key) { source.getLong(key, SavedStateUtils.DEFAULT_LONG) }
     }
 
     actual inline fun getLongOrElse(key: String, defaultValue: () -> Long): Long {
-        return getSingleResultOrElse(key, defaultValue) { source.getLong(key) }
+        return getSingleResultOrElse(key, defaultValue) { source.getLong(key, defaultValue()) }
     }
 
     /**
@@ -102,7 +102,7 @@
     }
 
     actual inline fun getStringOrElse(key: String, defaultValue: () -> String): String {
-        return getSingleResultOrElse(key, defaultValue) { source.getString(key) }
+        return getSingleResultOrElse(key, defaultValue) { source.getString(key, defaultValue()) }
     }
 
     actual inline fun getIntList(key: String): List<Int> {
@@ -171,6 +171,8 @@
 
     actual inline operator fun contains(key: String): Boolean = source.containsKey(key)
 
+    actual fun contentDeepEquals(other: SavedState): Boolean = source.contentDeepEquals(other)
+
     @PublishedApi
     internal inline fun <reified T> getSingleResultOrThrow(
         key: String,
@@ -221,3 +223,23 @@
             defaultValue = { defaultValue() },
         )
 }
+
+@PublishedApi
+internal fun SavedState.contentDeepEquals(other: SavedState): Boolean {
+    if (this === other) return true
+    if (this.size() != other.size()) return false
+
+    for (k in this.keySet()) {
+        @Suppress("DEPRECATION") val v1 = this[k]
+        @Suppress("DEPRECATION") val v2 = other[k]
+
+        when {
+            v1 === v2 -> continue
+            v1 == null || v2 == null -> return false
+            v1 is SavedState && v2 is SavedState -> if (!v1.contentDeepEquals(v2)) return false
+            v1 is Array<*> && v2 is Array<*> -> if (!v1.contentDeepEquals(v2)) return false
+            else -> if (v1 != v2) return false
+        }
+    }
+    return true
+}
diff --git a/savedstate/savedstate/src/androidUnitTest/kotlin/androidx/savedstate/ParcelableSavedStateTest.android.kt b/savedstate/savedstate/src/androidUnitTest/kotlin/androidx/savedstate/ParcelableSavedStateTest.android.kt
index 48f76bf..73d9c8d 100644
--- a/savedstate/savedstate/src/androidUnitTest/kotlin/androidx/savedstate/ParcelableSavedStateTest.android.kt
+++ b/savedstate/savedstate/src/androidUnitTest/kotlin/androidx/savedstate/ParcelableSavedStateTest.android.kt
@@ -64,6 +64,14 @@
     }
 
     @Test
+    fun getParcelableOrElse_whenSet_differentType_returnsDefault() {
+        val underTest = savedState { putInt(KEY_1, Int.MAX_VALUE) }
+        val actual = underTest.read { getParcelableOrElse(KEY_1) { PARCELABLE_VALUE_1 } }
+
+        assertThat(actual).isEqualTo(PARCELABLE_VALUE_1)
+    }
+
+    @Test
     fun getParcelableList_whenSet_returns() {
         val expected = List(size = 5) { idx -> TestParcelable(idx) }
 
@@ -81,7 +89,7 @@
     }
 
     @Test
-    fun getListofParcelable_whenSet_differentType_throws() {
+    fun getList_whenSet_differentType_throws() {
         val underTest = savedState { putInt(KEY_1, Int.MAX_VALUE) }
 
         assertThrows<IllegalStateException> {
@@ -108,6 +116,14 @@
         assertThat(actual).isEqualTo(emptyList<TestParcelable>())
     }
 
+    @Test
+    fun getListOrElse_whenSet_differentType_throws() {
+        val underTest = savedState { putInt(KEY_1, Int.MAX_VALUE) }
+        val actual = underTest.read { getParcelableListOrElse(KEY_1) { emptyList() } }
+
+        assertThat(actual).isEqualTo(emptyList<Parcelable>())
+    }
+
     private companion object {
         const val KEY_1 = "KEY_1"
         val PARCELABLE_VALUE_1 = TestParcelable(value = Int.MIN_VALUE)
diff --git a/savedstate/savedstate/src/commonMain/kotlin/androidx/savedstate/SavedState.kt b/savedstate/savedstate/src/commonMain/kotlin/androidx/savedstate/SavedState.kt
index 710bdd0..dbfb175 100644
--- a/savedstate/savedstate/src/commonMain/kotlin/androidx/savedstate/SavedState.kt
+++ b/savedstate/savedstate/src/commonMain/kotlin/androidx/savedstate/SavedState.kt
@@ -31,8 +31,24 @@
  */
 public expect class SavedState
 
-/** Constructs an empty [SavedState] instance. */
-public expect inline fun savedState(block: SavedStateWriter.() -> Unit = {}): SavedState
+/**
+ * Builds a new [SavedState] with the specified [initialState], given as a [Map] of [String] keys
+ * and [Any] value.
+ *
+ * Allows further modification of the state using the [builderAction].
+ *
+ * **IMPORTANT:** The [SavedStateWriter] passed as a receiver to the [builderAction] is valid only
+ * inside that function. Using it outside of the function may produce an unspecified behavior.
+ *
+ * @param initialState An initial map of key-value pairs to populate the state. Defaults to an empty
+ *   map.
+ * @param builderAction A lambda function with a [SavedStateWriter] receiver to modify the state.
+ * @return A [SavedState] instance containing the initialized key-value pairs.
+ */
+public expect inline fun savedState(
+    initialState: Map<String, Any> = emptyMap(),
+    builderAction: SavedStateWriter.() -> Unit = {},
+): SavedState
 
 /** Creates a new [SavedStateReader] for the [SavedState]. */
 public fun SavedState.reader(): SavedStateReader = SavedStateReader(source = this)
diff --git a/savedstate/savedstate/src/commonMain/kotlin/androidx/savedstate/SavedStateReader.kt b/savedstate/savedstate/src/commonMain/kotlin/androidx/savedstate/SavedStateReader.kt
index e3f37ac..611d5d8 100644
--- a/savedstate/savedstate/src/commonMain/kotlin/androidx/savedstate/SavedStateReader.kt
+++ b/savedstate/savedstate/src/commonMain/kotlin/androidx/savedstate/SavedStateReader.kt
@@ -245,4 +245,16 @@
      * @return `true` if the [SavedState] contains the [key], `false` otherwise.
      */
     public inline operator fun contains(key: String): Boolean
+
+    /**
+     * Checks if the two specified [SavedState] are *deeply* equal to one another.
+     *
+     * Two [SavedState] are considered deeply equal if they have the same size, and elements at
+     * corresponding keys are deeply equal. That is, if two corresponding elements are nested
+     * [SavedState], they are also compared deeply.
+     *
+     * @param other the object to compare deeply with this.
+     * @return `true` if the two are deeply equal, `false` otherwise.
+     */
+    public fun contentDeepEquals(other: SavedState): Boolean
 }
diff --git a/savedstate/savedstate/src/commonTest/kotlin/androidx/savedstate/SavedStateTest.kt b/savedstate/savedstate/src/commonTest/kotlin/androidx/savedstate/SavedStateTest.kt
index b40f557..f7d2380 100644
--- a/savedstate/savedstate/src/commonTest/kotlin/androidx/savedstate/SavedStateTest.kt
+++ b/savedstate/savedstate/src/commonTest/kotlin/androidx/savedstate/SavedStateTest.kt
@@ -95,6 +95,89 @@
         assertThat(underTest.read { isEmpty() }).isTrue()
     }
 
+    @Test
+    fun contentDeepEquals_withEqualContent_returnsTrue() {
+        val sharedState = savedState {
+            putInt(KEY_1, Int.MAX_VALUE)
+            putInt(KEY_2, Int.MAX_VALUE)
+        }
+        val state1 = savedState {
+            putInt(KEY_1, Int.MAX_VALUE)
+            putInt(KEY_2, Int.MAX_VALUE)
+            putSavedState(KEY_3, sharedState)
+        }
+        val state2 = savedState {
+            putInt(KEY_1, Int.MAX_VALUE)
+            putInt(KEY_2, Int.MAX_VALUE)
+            putSavedState(KEY_3, sharedState)
+        }
+
+        val contentDeepEquals = state1.read { contentDeepEquals(state2) }
+
+        assertThat(contentDeepEquals).isTrue()
+    }
+
+    @Test
+    fun contentDeepEquals_withMissingKey_returnsFalse() {
+        val sharedState = savedState {
+            putInt(KEY_1, Int.MAX_VALUE)
+            putInt(KEY_2, Int.MAX_VALUE)
+        }
+        val state1 = savedState {
+            putInt(KEY_1, Int.MAX_VALUE)
+            putInt(KEY_2, Int.MAX_VALUE)
+            putSavedState(KEY_3, sharedState)
+        }
+        val state2 = savedState {
+            putInt(KEY_1, Int.MAX_VALUE)
+            putSavedState(KEY_3, sharedState)
+        }
+
+        val contentDeepEquals = state1.read { contentDeepEquals(state2) }
+
+        assertThat(contentDeepEquals).isFalse()
+    }
+
+    @Test
+    fun contentDeepEquals_withDifferentContent_returnsFalse() {
+        val sharedState = savedState {
+            putInt(KEY_1, Int.MAX_VALUE)
+            putInt(KEY_2, Int.MAX_VALUE)
+        }
+        val state1 = savedState {
+            putInt(KEY_1, Int.MAX_VALUE)
+            putInt(KEY_2, Int.MAX_VALUE)
+            putSavedState(KEY_3, sharedState)
+        }
+        val state2 = savedState {
+            putFloat(KEY_1, Float.MAX_VALUE)
+            putFloat(KEY_2, Float.MAX_VALUE)
+            putSavedState(KEY_3, sharedState)
+        }
+
+        val contentDeepEquals = state1.read { contentDeepEquals(state2) }
+
+        assertThat(contentDeepEquals).isFalse()
+    }
+
+    @Test
+    fun contentDeepEquals_withEmptyContent_returnsFalse() {
+        val sharedState = savedState {
+            putInt(KEY_1, Int.MAX_VALUE)
+            putInt(KEY_2, Int.MAX_VALUE)
+        }
+        val state1 = savedState {
+            putInt(KEY_1, Int.MAX_VALUE)
+            putInt(KEY_2, Int.MAX_VALUE)
+            putSavedState(KEY_3, sharedState)
+        }
+        val state2 = savedState()
+
+        val contentDeepEquals = state1.read { contentDeepEquals(state2) }
+
+        assertThat(contentDeepEquals).isFalse()
+    }
+
     // region getters and setters
     @Test
     fun getBoolean_whenSet_returns() {
@@ -131,9 +214,17 @@
 
     @Test
     fun getBooleanOrElse_whenNotSet_returnsElse() {
-        val actual = savedState().read { getBooleanOrElse(KEY_1) { false } }
+        val actual = savedState().read { getBooleanOrElse(KEY_1) { true } }
 
-        assertThat(actual).isFalse()
+        assertThat(actual).isTrue()
+    }
+
+    @Test
+    fun getBooleanOrElse_whenSet_differentType_returnsElse() {
+        val underTest = savedState { putInt(KEY_1, Int.MAX_VALUE) }
+        val actual = underTest.read { getBooleanOrElse(KEY_1) { true } }
+
+        assertThat(actual).isTrue()
     }
 
     @Test
@@ -173,6 +264,14 @@
     }
 
     @Test
+    fun getDoubleOrElse_whenSet_differentType_returnsElse() {
+        val underTest = savedState { putInt(KEY_1, Int.MAX_VALUE) }
+        val actual = underTest.read { getDoubleOrElse(KEY_1) { Double.MIN_VALUE } }
+
+        assertThat(actual).isEqualTo(Double.MIN_VALUE)
+    }
+
+    @Test
     fun getFloat_whenSet_returns() {
         val underTest = savedState { putFloat(KEY_1, Float.MAX_VALUE) }
         val actual = underTest.read { getFloat(KEY_1) }
@@ -209,6 +308,14 @@
     }
 
     @Test
+    fun getFloatOrElse_whenSet_differentType_returnsElse() {
+        val underTest = savedState { putInt(KEY_1, Int.MAX_VALUE) }
+        val actual = underTest.read { getFloatOrElse(KEY_1) { Float.MIN_VALUE } }
+
+        assertThat(actual).isEqualTo(Float.MIN_VALUE)
+    }
+
+    @Test
     fun getInt_whenSet_returns() {
         val underTest = savedState { putInt(KEY_1, Int.MAX_VALUE) }
         val actual = underTest.read { getInt(KEY_1) }
@@ -245,6 +352,14 @@
     }
 
     @Test
+    fun getIntOrElse_whenSet_differentType_returnsElse() {
+        val underTest = savedState { putBoolean(KEY_1, false) }
+        val actual = underTest.read { getIntOrElse(KEY_1) { Int.MIN_VALUE } }
+
+        assertThat(actual).isEqualTo(Int.MIN_VALUE)
+    }
+
+    @Test
     fun getLong_whenSet_returns() {
         val underTest = savedState { putLong(KEY_1, Long.MAX_VALUE) }
         val actual = underTest.read { getLong(KEY_1) }
@@ -281,6 +396,14 @@
     }
 
     @Test
+    fun getLongOrElse_whenSet_differentType_returnsElse() {
+        val underTest = savedState { putBoolean(KEY_1, false) }
+        val actual = underTest.read { getLongOrElse(KEY_1) { Long.MIN_VALUE } }
+
+        assertThat(actual).isEqualTo(Long.MIN_VALUE)
+    }
+
+    @Test
     fun getString_whenSet_returns() {
         val underTest = savedState { putString(KEY_1, STRING_VALUE) }
         val actual = underTest.read { getString(KEY_1) }
@@ -316,6 +439,15 @@
     }
 
     @Test
+    fun getStringOrElse_whenSet_differentType_returnsElse() {
+        val underTest = savedState { putInt(KEY_1, Int.MAX_VALUE) }
+
+        val actual = underTest.read { getStringOrElse(KEY_1) { STRING_VALUE } }
+
+        assertThat(actual).isEqualTo(STRING_VALUE)
+    }
+
+    @Test
     fun getIntList_whenSet_returns() {
         val expected = List(size = 5) { idx -> idx }
 
@@ -355,6 +487,16 @@
     }
 
     @Test
+    fun getIntOrElseList_whenSet_differentType_returnsElse() {
+        val expected = Int.MAX_VALUE
+
+        val underTest = savedState { putInt(KEY_1, expected) }
+        val actual = underTest.read { getIntListOrElse(KEY_1) { emptyList() } }
+
+        assertThat(actual).isEqualTo(emptyList<Int>())
+    }
+
+    @Test
     fun getStringList_whenSet_returns() {
         val underTest = savedState { putStringList(KEY_1, LIST_STRING_VALUE) }
         val actual = underTest.read { getStringList(KEY_1) }
@@ -392,6 +534,16 @@
     }
 
     @Test
+    fun getStringListOrElse_whenSet_differentType_returnsElse() {
+        val expected = Int.MAX_VALUE
+
+        val underTest = savedState { putInt(KEY_1, expected) }
+        val actual = underTest.read { getStringListOrElse(KEY_1) { emptyList() } }
+
+        assertThat(actual).isEqualTo(emptyList<String>())
+    }
+
+    @Test
     fun getSavedState_whenSet_returns() {
         val underTest = savedState { putSavedState(KEY_1, SAVED_STATE_VALUE) }
         val actual = underTest.read { getSavedState(KEY_1) }
@@ -405,6 +557,13 @@
     }
 
     @Test
+    fun getSavedState_whenSet_differentType_throws() {
+        val underTest = savedState { putInt(KEY_1, Int.MAX_VALUE) }
+
+        assertThrows<IllegalStateException> { underTest.read { getSavedState(KEY_1) } }
+    }
+
+    @Test
     fun getSavedStateOrElse_whenSet_returns() {
         val underTest = savedState { putSavedState(KEY_1, SAVED_STATE_VALUE) }
         val actual = underTest.read { getSavedStateOrElse(KEY_1) { savedState() } }
@@ -422,6 +581,16 @@
     }
 
     @Test
+    fun getSavedStateOrElse_whenSet_differentType_returnsElse() {
+        val expected = savedState()
+
+        val underTest = savedState { putInt(KEY_1, Int.MAX_VALUE) }
+        val actual = underTest.read { getSavedStateOrElse(KEY_1) { expected } }
+
+        assertThat(actual).isEqualTo(expected)
+    }
+
+    @Test
     fun putAll() {
         val previousState = savedState { putInt(KEY_1, Int.MAX_VALUE) }
 
@@ -436,6 +605,7 @@
     private companion object {
         const val KEY_1 = "KEY_1"
         const val KEY_2 = "KEY_2"
+        const val KEY_3 = "KEY_3"
         const val STRING_VALUE = "string-value"
         val LIST_INT_VALUE = List(size = 5) { idx -> idx }
         val LIST_STRING_VALUE = List(size = 5) { idx -> "index=$idx" }
diff --git a/savedstate/savedstate/src/nonAndroidMain/kotlin/androidx/savedstate/SavedState.nonAndroid.kt b/savedstate/savedstate/src/nonAndroidMain/kotlin/androidx/savedstate/SavedState.nonAndroid.kt
index 127e516..78417b8 100644
--- a/savedstate/savedstate/src/nonAndroidMain/kotlin/androidx/savedstate/SavedState.nonAndroid.kt
+++ b/savedstate/savedstate/src/nonAndroidMain/kotlin/androidx/savedstate/SavedState.nonAndroid.kt
@@ -14,11 +14,15 @@
  * limitations under the License.
  */
 
+@file:Suppress("NOTHING_TO_INLINE")
+
 package androidx.savedstate
 
 public actual class SavedState
 @PublishedApi
 internal constructor(@PublishedApi internal val map: MutableMap<String, Any> = mutableMapOf())
 
-actual inline fun savedState(block: SavedStateWriter.() -> Unit): SavedState =
-    SavedState().apply { write(block) }
+actual inline fun savedState(
+    initialState: Map<String, Any>,
+    builderAction: SavedStateWriter.() -> Unit,
+): SavedState = SavedState(initialState.toMutableMap()).apply { write(builderAction) }
diff --git a/savedstate/savedstate/src/nonAndroidMain/kotlin/androidx/savedstate/SavedStateReader.nonAndroid.kt b/savedstate/savedstate/src/nonAndroidMain/kotlin/androidx/savedstate/SavedStateReader.nonAndroid.kt
index 01e3cd9..cec009a 100644
--- a/savedstate/savedstate/src/nonAndroidMain/kotlin/androidx/savedstate/SavedStateReader.nonAndroid.kt
+++ b/savedstate/savedstate/src/nonAndroidMain/kotlin/androidx/savedstate/SavedStateReader.nonAndroid.kt
@@ -31,41 +31,31 @@
         }
 
     actual inline fun getBooleanOrElse(key: String, defaultValue: () -> Boolean): Boolean =
-        getSingleResultOrElse(key, defaultValue) {
-            source.map[key] as? Boolean ?: SavedStateUtils.DEFAULT_BOOLEAN
-        }
+        getSingleResultOrElse(key, defaultValue) { source.map[key] as? Boolean }
 
     actual inline fun getDouble(key: String): Double =
         getSingleResultOrThrow(key) { source.map[key] as? Double ?: SavedStateUtils.DEFAULT_DOUBLE }
 
     actual inline fun getDoubleOrElse(key: String, defaultValue: () -> Double): Double =
-        getSingleResultOrElse(key, defaultValue) {
-            source.map[key] as? Double ?: SavedStateUtils.DEFAULT_DOUBLE
-        }
+        getSingleResultOrElse(key, defaultValue) { source.map[key] as? Double }
 
     actual inline fun getFloat(key: String): Float =
         getSingleResultOrThrow(key) { source.map[key] as? Float ?: SavedStateUtils.DEFAULT_FLOAT }
 
     actual inline fun getFloatOrElse(key: String, defaultValue: () -> Float): Float =
-        getSingleResultOrElse(key, defaultValue) {
-            source.map[key] as? Float ?: SavedStateUtils.DEFAULT_FLOAT
-        }
+        getSingleResultOrElse(key, defaultValue) { source.map[key] as? Float }
 
     actual inline fun getInt(key: String): Int =
         getSingleResultOrThrow(key) { source.map[key] as? Int ?: SavedStateUtils.DEFAULT_INT }
 
     actual inline fun getIntOrElse(key: String, defaultValue: () -> Int): Int =
-        getSingleResultOrElse(key, defaultValue) {
-            source.map[key] as? Int ?: SavedStateUtils.DEFAULT_INT
-        }
+        getSingleResultOrElse(key, defaultValue) { source.map[key] as? Int }
 
     actual inline fun getLong(key: String): Long =
         getSingleResultOrThrow(key) { source.map[key] as? Long ?: SavedStateUtils.DEFAULT_LONG }
 
     actual inline fun getLongOrElse(key: String, defaultValue: () -> Long): Long =
-        getSingleResultOrElse(key, defaultValue) {
-            source.map[key] as? Long ?: SavedStateUtils.DEFAULT_LONG
-        }
+        getSingleResultOrElse(key, defaultValue) { source.map[key] as? Long }
 
     actual inline fun getString(key: String): String =
         getSingleResultOrThrow(key) { source.map[key] as? String }
@@ -163,4 +153,9 @@
             currentValue = { currentValue() },
             defaultValue = { defaultValue() },
         )
+
+    actual fun contentDeepEquals(other: SavedState): Boolean {
+        // Map implements `equals` as a content deep, there is no need to do anything else.
+        return source.map == other.map
+    }
 }
diff --git a/security/security-state/api/current.txt b/security/security-state/api/current.txt
index 4424adf..7f6c944 100644
--- a/security/security-state/api/current.txt
+++ b/security/security-state/api/current.txt
@@ -19,7 +19,6 @@
     field public static final String COMPONENT_KERNEL = "KERNEL";
     field public static final String COMPONENT_SYSTEM = "SYSTEM";
     field public static final String COMPONENT_SYSTEM_MODULES = "SYSTEM_MODULES";
-    field public static final String COMPONENT_VENDOR = "VENDOR";
     field public static final androidx.security.state.SecurityPatchState.Companion Companion;
     field public static final java.util.List<java.lang.String> DEFAULT_SYSTEM_MODULES;
     field public static final String DEFAULT_VULNERABILITY_REPORTS_URL = "https://storage.googleapis.com/osv-android-api";
diff --git a/security/security-state/api/restricted_current.txt b/security/security-state/api/restricted_current.txt
index 4424adf..7f6c944 100644
--- a/security/security-state/api/restricted_current.txt
+++ b/security/security-state/api/restricted_current.txt
@@ -19,7 +19,6 @@
     field public static final String COMPONENT_KERNEL = "KERNEL";
     field public static final String COMPONENT_SYSTEM = "SYSTEM";
     field public static final String COMPONENT_SYSTEM_MODULES = "SYSTEM_MODULES";
-    field public static final String COMPONENT_VENDOR = "VENDOR";
     field public static final androidx.security.state.SecurityPatchState.Companion Companion;
     field public static final java.util.List<java.lang.String> DEFAULT_SYSTEM_MODULES;
     field public static final String DEFAULT_VULNERABILITY_REPORTS_URL = "https://storage.googleapis.com/osv-android-api";
diff --git a/security/security-state/src/androidTest/java/androidx/security/state/SecurityStateManagerTest.kt b/security/security-state/src/androidTest/java/androidx/security/state/SecurityStateManagerTest.kt
index d0852df..73796ac 100644
--- a/security/security-state/src/androidTest/java/androidx/security/state/SecurityStateManagerTest.kt
+++ b/security/security-state/src/androidTest/java/androidx/security/state/SecurityStateManagerTest.kt
@@ -86,7 +86,6 @@
     fun testGetGlobalSecurityState_sdkAbove29() {
         val bundle = securityStateManager.getGlobalSecurityState()
         assertTrue(matchesDateFormat(bundle.getString("system_spl")!!))
-        assertTrue(matchesDateFormat(bundle.getString("vendor_spl")!!))
         assertTrue(matchesKernelFormat(bundle.getString("kernel_version")!!))
         assertTrue(containsModuleMetadataPackage(bundle))
         assertTrue(containsWebViewPackage(bundle))
@@ -97,7 +96,6 @@
     fun testGetGlobalSecurityState_sdkAbove25Below29_doesNotContainModuleMetadata() {
         val bundle = securityStateManager.getGlobalSecurityState()
         assertTrue(matchesDateFormat(bundle.getString("system_spl")!!))
-        assertTrue(matchesDateFormat(bundle.getString("vendor_spl")!!))
         assertTrue(matchesKernelFormat(bundle.getString("kernel_version")!!))
         assertTrue(containsWebViewPackage(bundle))
         assertFalse(containsModuleMetadataPackage(bundle))
@@ -108,7 +106,6 @@
     fun testGetGlobalSecurityState_sdkAbove22Below26_doesNotContainModuleMetadataOrWebView() {
         val bundle = securityStateManager.getGlobalSecurityState()
         assertTrue(matchesDateFormat(bundle.getString("system_spl")!!))
-        assertTrue(matchesDateFormat(bundle.getString("vendor_spl")!!))
         assertTrue(matchesKernelFormat(bundle.getString("kernel_version")!!))
         assertFalse(containsModuleMetadataPackage(bundle))
         assertFalse(containsWebViewPackage(bundle))
@@ -127,4 +124,20 @@
         assertFalse(containsModuleMetadataPackage(bundle))
         assertFalse(containsWebViewPackage(bundle))
     }
+
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.M)
+    @Test
+    fun testGetGlobalSecurityState_whenVendorIsEnabled_containsVendorSpl() {
+        SecurityPatchState.Companion.USE_VENDOR_SPL = true
+        val bundle = securityStateManager.getGlobalSecurityState()
+        assertTrue(bundle.containsKey("vendor_spl"))
+    }
+
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.M)
+    @Test
+    fun testGetGlobalSecurityState_whenVendorIsDisabled_doesNotContainVendorSpl() {
+        SecurityPatchState.Companion.USE_VENDOR_SPL = false
+        val bundle = securityStateManager.getGlobalSecurityState()
+        assertFalse(bundle.containsKey("vendor_spl"))
+    }
 }
diff --git a/security/security-state/src/main/java/androidx/security/state/SecurityPatchState.kt b/security/security-state/src/main/java/androidx/security/state/SecurityPatchState.kt
index 07bb133..bc317cf 100644
--- a/security/security-state/src/main/java/androidx/security/state/SecurityPatchState.kt
+++ b/security/security-state/src/main/java/androidx/security/state/SecurityPatchState.kt
@@ -91,16 +91,19 @@
         /** System modules component providing DateBasedSpl of system modules patch level. */
         public const val COMPONENT_SYSTEM_MODULES: String = "SYSTEM_MODULES"
 
-        /**
-         * Vendor component providing ro.vendor.build.security_patch property value as DateBasedSpl.
-         */
-        public const val COMPONENT_VENDOR: String = "VENDOR"
-
         /** Kernel component providing kernel version as VersionedSpl. */
         public const val COMPONENT_KERNEL: String = "KERNEL"
 
         /** WebView component providing default WebView provider version as VersionedSpl. */
         internal const val COMPONENT_WEBVIEW: String = "WEBVIEW"
+
+        /**
+         * Vendor component providing ro.vendor.build.security_patch property value as DateBasedSpl.
+         */
+        internal const val COMPONENT_VENDOR: String = "VENDOR"
+
+        /** Disabled until Android provides sufficient guidelines for the usage of Vendor SPL. */
+        internal var USE_VENDOR_SPL = false
     }
 
     /** Annotation for defining the component to use. */
@@ -598,9 +601,13 @@
             COMPONENT_SYSTEM_MODULES -> listOf(getSystemModulesPublishedSecurityPatchLevel())
             COMPONENT_SYSTEM,
             COMPONENT_VENDOR -> {
+                val exception = IllegalStateException("SPL data not available: $component")
+                if (component == COMPONENT_VENDOR && !USE_VENDOR_SPL) {
+                    throw exception
+                }
                 listOf(
                     getMaxComponentSecurityPatchLevel(componentToString(component))
-                        ?: throw IllegalStateException("SPL data not available.")
+                        ?: throw exception
                 )
             }
             COMPONENT_KERNEL -> getPublishedKernelVersions()
@@ -691,8 +698,16 @@
         spl: SecurityPatchLevel
     ): Map<Severity, Set<String>> {
         // Check if the component is valid for this operation
-        if (component !in listOf(COMPONENT_SYSTEM, COMPONENT_VENDOR, COMPONENT_SYSTEM_MODULES)) {
-            throw IllegalArgumentException("Component must be SYSTEM, VENDOR, or SYSTEM_MODULES")
+        val validComponents =
+            listOfNotNull(
+                COMPONENT_SYSTEM,
+                if (USE_VENDOR_SPL) COMPONENT_VENDOR else null,
+                COMPONENT_SYSTEM_MODULES
+            )
+        if (component !in validComponents) {
+            throw IllegalArgumentException(
+                "Component must be one of $validComponents but was $component"
+            )
         }
         checkVulnerabilityReport()
 
@@ -736,10 +751,14 @@
         @Component component: String,
         securityPatchLevel: String
     ): SecurityPatchLevel {
+        val exception = IllegalArgumentException("Unknown component: $component")
         return when (component) {
             COMPONENT_SYSTEM,
             COMPONENT_SYSTEM_MODULES,
             COMPONENT_VENDOR -> {
+                if (component == COMPONENT_VENDOR && !USE_VENDOR_SPL) {
+                    throw exception
+                }
                 // These components are expected to use DateBasedSpl
                 DateBasedSecurityPatchLevel.fromString(securityPatchLevel)
             }
@@ -748,7 +767,7 @@
                 // These components are expected to use VersionedSpl
                 VersionedSecurityPatchLevel.fromString(securityPatchLevel)
             }
-            else -> throw IllegalArgumentException("Unknown component: $component")
+            else -> throw exception
         }
     }
 
@@ -826,6 +845,7 @@
             )
 
         components.forEach { component ->
+            if (component == COMPONENT_VENDOR && !USE_VENDOR_SPL) return@forEach
             // TODO(musashi): Unblock once support for WebView is present.
             if (component == COMPONENT_WEBVIEW) return@forEach
             val deviceSpl =
@@ -877,7 +897,12 @@
      * @return true if all provided CVEs are patched, false otherwise.
      */
     public fun areCvesPatched(cveList: List<String>): Boolean {
-        val componentsToCheck = listOf(COMPONENT_SYSTEM, COMPONENT_VENDOR, COMPONENT_SYSTEM_MODULES)
+        val componentsToCheck =
+            listOfNotNull(
+                COMPONENT_SYSTEM,
+                if (USE_VENDOR_SPL) COMPONENT_VENDOR else null,
+                COMPONENT_SYSTEM_MODULES
+            )
         val allPatchedCves = mutableSetOf<String>()
 
         // Aggregate all CVEs from security fixes across necessary components
diff --git a/security/security-state/src/main/java/androidx/security/state/SecurityStateManager.kt b/security/security-state/src/main/java/androidx/security/state/SecurityStateManager.kt
index 9329c9b..2676d6c 100644
--- a/security/security-state/src/main/java/androidx/security/state/SecurityStateManager.kt
+++ b/security/security-state/src/main/java/androidx/security/state/SecurityStateManager.kt
@@ -23,6 +23,7 @@
 import android.os.Bundle
 import android.system.Os
 import androidx.annotation.RequiresApi
+import androidx.security.state.SecurityPatchState.Companion.USE_VENDOR_SPL
 import androidx.webkit.WebViewCompat
 import java.util.regex.Pattern
 
@@ -87,13 +88,8 @@
         return Bundle().apply {
             if (getAndroidSdkInt() >= Build.VERSION_CODES.M) {
                 putString(KEY_SYSTEM_SPL, Build.VERSION.SECURITY_PATCH)
-
-                val vendorSpl = getVendorSpl()
-                if (vendorSpl.isNotEmpty()) {
-                    putString(KEY_VENDOR_SPL, vendorSpl)
-                } else {
-                    // Assume vendor SPL == system SPL
-                    putString(KEY_VENDOR_SPL, Build.VERSION.SECURITY_PATCH)
+                if (USE_VENDOR_SPL) {
+                    putString(KEY_VENDOR_SPL, getVendorSpl())
                 }
             }
             if (getAndroidSdkInt() >= Build.VERSION_CODES.Q) {
@@ -128,13 +124,8 @@
             context.getSystemService(Context.SECURITY_STATE_SERVICE)
                 as android.os.SecurityStateManager
         val globalSecurityState = securityStateManagerService.globalSecurityState
-        val vendorSpl = globalSecurityState.getString(KEY_VENDOR_SPL, "")
-        if (vendorSpl.isEmpty()) {
-            // Assume vendor SPL == system SPL
-            globalSecurityState.putString(
-                KEY_VENDOR_SPL,
-                globalSecurityState.getString(KEY_SYSTEM_SPL)
-            )
+        if (!USE_VENDOR_SPL) {
+            globalSecurityState.remove(KEY_VENDOR_SPL)
         }
         return globalSecurityState
     }
diff --git a/security/security-state/src/test/java/androidx/security/state/SecurityPatchStateTest.kt b/security/security-state/src/test/java/androidx/security/state/SecurityPatchStateTest.kt
index 29177c4..6e22fe3 100644
--- a/security/security-state/src/test/java/androidx/security/state/SecurityPatchStateTest.kt
+++ b/security/security-state/src/test/java/androidx/security/state/SecurityPatchStateTest.kt
@@ -120,7 +120,7 @@
     }
 
     @Test
-    fun testGetSecurityPatchLevelWithDateBasedComponent() {
+    fun testGetComponentSecurityPatchLevel_withSystemComponent_returnsDateBasedSpl() {
         val spl =
             securityState.getComponentSecurityPatchLevel(
                 SecurityPatchState.COMPONENT_SYSTEM,
@@ -131,7 +131,29 @@
     }
 
     @Test
-    fun testGetSecurityPatchLevelWithVersionedComponent() {
+    fun testGetComponentSecurityPatchLevel_withVendorComponent_whenVendorIsEnabled_returnsDateBasedSpl() {
+        SecurityPatchState.Companion.USE_VENDOR_SPL = true
+        val spl =
+            securityState.getComponentSecurityPatchLevel(
+                SecurityPatchState.COMPONENT_VENDOR,
+                "2022-01-01"
+            )
+        assertTrue(spl is SecurityPatchState.DateBasedSecurityPatchLevel)
+        assertEquals("2022-01-01", spl.toString())
+    }
+
+    @Test(expected = IllegalArgumentException::class)
+    fun testGetComponentSecurityPatchLevel_withVendorComponent_whenVendorIsDisabled_throwsException() {
+        SecurityPatchState.Companion.USE_VENDOR_SPL = false
+
+        securityState.getComponentSecurityPatchLevel(
+            SecurityPatchState.COMPONENT_VENDOR,
+            "2022-01-01"
+        )
+    }
+
+    @Test
+    fun testGetComponentSecurityPatchLevel_withKernelComponent_returnsVersionedSpl() {
         val spl =
             securityState.getComponentSecurityPatchLevel(
                 SecurityPatchState.COMPONENT_KERNEL,
@@ -142,7 +164,7 @@
     }
 
     @Test(expected = IllegalArgumentException::class)
-    fun testGetSecurityPatchLevelWithInvalidDateBasedInput() {
+    fun testGetComponentSecurityPatchLevel_withInvalidDateBasedInput_throwsException() {
         securityState.getComponentSecurityPatchLevel(
             SecurityPatchState.COMPONENT_SYSTEM,
             "invalid-date"
@@ -150,7 +172,7 @@
     }
 
     @Test(expected = IllegalArgumentException::class)
-    fun testGetSecurityPatchLevelWithInvalidVersionedInput() {
+    fun testGetComponentSecurityPatchLevel_withInvalidVersionedInput_throwsException() {
         securityState.getComponentSecurityPatchLevel(
             SecurityPatchState.COMPONENT_KERNEL,
             "invalid-version"
@@ -191,16 +213,16 @@
         """
         securityState.loadVulnerabilityReport(jsonString)
 
-        val fixes =
+        val cves =
             securityState.getPatchedCves(
                 SecurityPatchState.COMPONENT_SYSTEM,
                 SecurityPatchState.DateBasedSecurityPatchLevel(2022, 1, 1)
             )
 
-        assertEquals(1, fixes[SecurityPatchState.Severity.HIGH]?.size)
-        assertEquals(1, fixes[SecurityPatchState.Severity.MODERATE]?.size)
-        assertEquals(setOf("CVE-2020-1234"), fixes[SecurityPatchState.Severity.HIGH])
-        assertEquals(setOf("CVE-2020-5678"), fixes[SecurityPatchState.Severity.MODERATE])
+        assertEquals(1, cves[SecurityPatchState.Severity.HIGH]?.size)
+        assertEquals(1, cves[SecurityPatchState.Severity.MODERATE]?.size)
+        assertEquals(setOf("CVE-2020-1234"), cves[SecurityPatchState.Severity.HIGH])
+        assertEquals(setOf("CVE-2020-5678"), cves[SecurityPatchState.Severity.MODERATE])
     }
 
     @Test(expected = IllegalArgumentException::class)
@@ -358,7 +380,8 @@
     }
 
     @Test
-    fun testGetPublishedSpl_ReturnsCorrectSplForVendor() {
+    fun testGetPublishedSpl_withVendorComponent_whenVendorIsEnabled_returnsCorrectSpl() {
+        SecurityPatchState.Companion.USE_VENDOR_SPL = true
         val jsonInput =
             """
             {
@@ -386,6 +409,29 @@
         assertEquals(15, spl.getDay())
     }
 
+    @Test(expected = IllegalStateException::class)
+    fun testGetPublishedSpl_withVendorComponent_whenVendorIsDisabled_throwsException() {
+        SecurityPatchState.Companion.USE_VENDOR_SPL = false
+        val jsonInput =
+            """
+            {
+                "vulnerabilities": {
+                    "2023-05-15": [{
+                        "cve_identifiers": ["CVE-5678-1234"],
+                        "asb_identifiers": ["ASB-A-2024222"],
+                        "severity": "critical",
+                        "components": ["vendor"]
+                    }]
+                },
+                "kernel_lts_versions": {}
+            }
+        """
+                .trimIndent()
+
+        securityState.loadVulnerabilityReport(jsonInput)
+        securityState.getPublishedSecurityPatchLevel(SecurityPatchState.COMPONENT_VENDOR)
+    }
+
     @Test
     fun testGetPublishedKernelVersions_ReturnsCorrectVersions_DifferentVersionsSameSpl() {
         val jsonInput =
@@ -558,28 +604,28 @@
     }
 
     @Test
-    fun testGetSecurityFixes_ReturnsNoFixes() {
-        securityState.loadVulnerabilityReport(generateMockReport("vendor", "2023-01-01"))
+    fun testGetPatchedCves_ReturnsNoCves() {
+        securityState.loadVulnerabilityReport(generateMockReport("system", "2023-01-01"))
 
         val spl = SecurityPatchState.DateBasedSecurityPatchLevel.fromString("2023-01-01")
-        val fixes = securityState.getPatchedCves(SecurityPatchState.COMPONENT_SYSTEM, spl)
+        val cves = securityState.getPatchedCves(SecurityPatchState.COMPONENT_SYSTEM_MODULES, spl)
 
-        assertEquals(null, fixes[SecurityPatchState.Severity.CRITICAL])
-        assertEquals(null, fixes[SecurityPatchState.Severity.HIGH])
-        assertEquals(null, fixes[SecurityPatchState.Severity.MODERATE])
-        assertEquals(null, fixes[SecurityPatchState.Severity.LOW])
+        assertEquals(null, cves[SecurityPatchState.Severity.CRITICAL])
+        assertEquals(null, cves[SecurityPatchState.Severity.HIGH])
+        assertEquals(null, cves[SecurityPatchState.Severity.MODERATE])
+        assertEquals(null, cves[SecurityPatchState.Severity.LOW])
 
         val spl2 = SecurityPatchState.DateBasedSecurityPatchLevel.fromString("2022-01-01")
-        val fixes2 = securityState.getPatchedCves(SecurityPatchState.COMPONENT_VENDOR, spl2)
+        val cves2 = securityState.getPatchedCves(SecurityPatchState.COMPONENT_SYSTEM, spl2)
 
-        assertEquals(null, fixes2[SecurityPatchState.Severity.CRITICAL])
-        assertEquals(null, fixes2[SecurityPatchState.Severity.HIGH])
-        assertEquals(null, fixes2[SecurityPatchState.Severity.MODERATE])
-        assertEquals(null, fixes2[SecurityPatchState.Severity.LOW])
+        assertEquals(null, cves2[SecurityPatchState.Severity.CRITICAL])
+        assertEquals(null, cves2[SecurityPatchState.Severity.HIGH])
+        assertEquals(null, cves2[SecurityPatchState.Severity.MODERATE])
+        assertEquals(null, cves2[SecurityPatchState.Severity.LOW])
     }
 
     @Test
-    fun testGetSecurityFixes_ReturnsCorrectFixesCategorizedBySeverity() {
+    fun testGetPatchedCves_withSystemComponent_returnsCorrectCvesCategorizedBySeverity() {
         val spl = SecurityPatchState.DateBasedSecurityPatchLevel.fromString("2023-01-01")
         val jsonInput =
             """
@@ -604,19 +650,62 @@
                 .trimIndent()
         securityState.loadVulnerabilityReport(jsonInput)
 
-        val fixes = securityState.getPatchedCves(SecurityPatchState.COMPONENT_SYSTEM, spl)
+        val cves = securityState.getPatchedCves(SecurityPatchState.COMPONENT_SYSTEM, spl)
 
-        assertEquals(2, fixes[SecurityPatchState.Severity.HIGH]?.size)
+        assertEquals(2, cves[SecurityPatchState.Severity.HIGH]?.size)
         assertEquals(
             setOf("CVE-2023-0001", "CVE-2023-0002"),
-            fixes[SecurityPatchState.Severity.HIGH]
+            cves[SecurityPatchState.Severity.HIGH]
         )
 
-        assertEquals(null, fixes[SecurityPatchState.Severity.MODERATE])
+        assertEquals(null, cves[SecurityPatchState.Severity.MODERATE])
+    }
+
+    @Test
+    fun testGetPatchedCves_withVendorComponent_whenVendorIsEnabled_returnsCorrectCvesCategorizedBySeverity() {
+        SecurityPatchState.Companion.USE_VENDOR_SPL = true
+        val spl = SecurityPatchState.DateBasedSecurityPatchLevel.fromString("2023-01-15")
+        val jsonInput =
+            """
+            {
+                "vulnerabilities": {
+                    "2023-01-01": [{
+                        "cve_identifiers": ["CVE-2023-0001", "CVE-2023-0002"],
+                        "asb_identifiers": ["ASB-A-2023011"],
+                        "severity": "high",
+                        "components": ["system"]
+                    }],
+                    "2023-01-15": [{
+                        "cve_identifiers": ["CVE-2023-0010"],
+                        "asb_identifiers": ["ASB-A-2023022"],
+                        "severity": "moderate",
+                        "components": ["vendor"]
+                    }]
+                },
+                "kernel_lts_versions": {}
+            }
+        """
+                .trimIndent()
+        securityState.loadVulnerabilityReport(jsonInput)
+
+        val cves = securityState.getPatchedCves(SecurityPatchState.COMPONENT_VENDOR, spl)
+
+        assertEquals(1, cves[SecurityPatchState.Severity.MODERATE]?.size)
+        assertEquals(setOf("CVE-2023-0010"), cves[SecurityPatchState.Severity.MODERATE])
+
+        assertEquals(null, cves[SecurityPatchState.Severity.HIGH])
     }
 
     @Test(expected = IllegalArgumentException::class)
-    fun testGetSecurityFixes_ThrowsExceptionForInvalidComponent() {
+    fun testGetPatchedCves_withVendorComponent_whenVendorIsDisabled_throwsException() {
+        SecurityPatchState.Companion.USE_VENDOR_SPL = false
+        val spl = SecurityPatchState.DateBasedSecurityPatchLevel.fromString("2022-01-01")
+
+        securityState.getPatchedCves(SecurityPatchState.COMPONENT_VENDOR, spl)
+    }
+
+    @Test(expected = IllegalArgumentException::class)
+    fun testGetPatchedCves_ThrowsExceptionForInvalidComponent() {
         val spl = SecurityPatchState.DateBasedSecurityPatchLevel.fromString("2023-01-01")
 
         securityState.getPatchedCves(SecurityPatchState.COMPONENT_WEBVIEW, spl)
@@ -769,7 +858,7 @@
     }
 
     @Test
-    fun testIsDeviceFullyUpdated_returnsTrue() {
+    fun testIsDeviceFullyUpdated_withUpdatedSpl_returnsTrue() {
         val bundle = Bundle()
         bundle.putString("system_spl", "2023-01-01")
         bundle.putString("vendor_spl", "2023-02-01")
@@ -813,7 +902,97 @@
     }
 
     @Test
-    fun testIsDeviceFullyUpdated_returnsFalse() {
+    fun testIsDeviceFullyUpdated_withOutdatedVendorSpl_whenVendorIsEnabled_returnsFalse() {
+        SecurityPatchState.Companion.USE_VENDOR_SPL = true
+        val bundle = Bundle()
+        bundle.putString("system_spl", "2023-01-01")
+        bundle.putString("vendor_spl", "2020-01-01")
+        bundle.putString("kernel_version", "5.4.123")
+        bundle.putString("com.google.android.modulemetadata", "2023-10-05")
+
+        `when`(mockSecurityStateManager.getGlobalSecurityState(anyString())).thenReturn(bundle)
+        doReturn("2023-10-05").`when`(mockSecurityStateManager).getPackageVersion(anyString())
+
+        val jsonInput =
+            """
+            {
+                "vulnerabilities": {
+                    "2023-05-01": [{
+                        "cve_identifiers": ["CVE-1234-4321"],
+                        "asb_identifiers": ["ASB-A-2023111"],
+                        "severity": "high",
+                        "components": ["com.google.android.modulemetadata"]
+                    }],
+                    "2023-01-01": [{
+                        "cve_identifiers": ["CVE-1234-1321"],
+                        "asb_identifiers": ["ASB-A-2023121"],
+                        "severity": "critical",
+                        "components": ["system"]
+                    }],
+                    "2023-02-01": [{
+                        "cve_identifiers": ["CVE-1234-3321"],
+                        "asb_identifiers": ["ASB-A-2023151"],
+                        "severity": "moderate",
+                        "components": ["vendor"]
+                    }]
+                },
+                "kernel_lts_versions": { "2023-05-01": [ "5.4.123", "6.1.234.25" ] }
+            }
+        """
+                .trimIndent()
+
+        securityState.loadVulnerabilityReport(jsonInput)
+
+        assertFalse(securityState.isDeviceFullyUpdated())
+    }
+
+    @Test
+    fun testIsDeviceFullyUpdated_withOutdatedVendorSpl_whenVendorIsDisabled_returnsTrue() {
+        SecurityPatchState.Companion.USE_VENDOR_SPL = false
+        val bundle = Bundle()
+        bundle.putString("system_spl", "2023-01-01")
+        bundle.putString("vendor_spl", "2020-01-01")
+        bundle.putString("kernel_version", "5.4.123")
+        bundle.putString("com.google.android.modulemetadata", "2023-10-05")
+
+        `when`(mockSecurityStateManager.getGlobalSecurityState(anyString())).thenReturn(bundle)
+        doReturn("2023-10-05").`when`(mockSecurityStateManager).getPackageVersion(anyString())
+
+        val jsonInput =
+            """
+            {
+                "vulnerabilities": {
+                    "2023-05-01": [{
+                        "cve_identifiers": ["CVE-1234-4321"],
+                        "asb_identifiers": ["ASB-A-2023111"],
+                        "severity": "high",
+                        "components": ["com.google.android.modulemetadata"]
+                    }],
+                    "2023-01-01": [{
+                        "cve_identifiers": ["CVE-1234-1321"],
+                        "asb_identifiers": ["ASB-A-2023121"],
+                        "severity": "critical",
+                        "components": ["system"]
+                    }],
+                    "2023-02-01": [{
+                        "cve_identifiers": ["CVE-1234-3321"],
+                        "asb_identifiers": ["ASB-A-2023151"],
+                        "severity": "moderate",
+                        "components": ["vendor"]
+                    }]
+                },
+                "kernel_lts_versions": { "2023-05-01": [ "5.4.123", "6.1.234.25" ] }
+            }
+        """
+                .trimIndent()
+
+        securityState.loadVulnerabilityReport(jsonInput)
+
+        assertTrue(securityState.isDeviceFullyUpdated())
+    }
+
+    @Test
+    fun testIsDeviceFullyUpdated_withOutdatedSpl_returnsFalse() {
         val bundle = Bundle()
         bundle.putString("system_spl", "2022-01-01")
         bundle.putString("com.google.android.modulemetadata", "2023-10-05")
@@ -894,9 +1073,7 @@
         `when`(mockSecurityStateManager.getGlobalSecurityState(anyString())).thenReturn(bundle)
         doReturn(systemSpl).`when`(mockSecurityStateManager).getPackageVersion(Mockito.anyString())
 
-        assertTrue(
-            securityState.areCvesPatched(listOf("CVE-2023-0010", "CVE-2023-0001", "CVE-2023-0002"))
-        )
+        assertTrue(securityState.areCvesPatched(listOf("CVE-2023-0001", "CVE-2023-0002")))
     }
 
     @Test
@@ -988,4 +1165,92 @@
             securityState.areCvesPatched(listOf("CVE-2024-1010", "CVE-2023-0001", "CVE-2023-0002"))
         )
     }
+
+    @Test
+    fun testAreCvesPatched_withVendorCve_whenVendorIsEnabled_returnsTrue() {
+        SecurityPatchState.Companion.USE_VENDOR_SPL = true
+        val jsonInput =
+            """
+            {
+                "vulnerabilities": {
+                    "2021-05-01": [{
+                        "cve_identifiers": ["CVE-1234-4321"],
+                        "asb_identifiers": ["ASB-A-2023111"],
+                        "severity": "high",
+                        "components": ["com.google.android.modulemetadata"]
+                    }],
+                    "2022-01-01": [{
+                        "cve_identifiers": ["CVE-2023-0001", "CVE-2023-0002"],
+                        "asb_identifiers": ["ASB-A-2023011"],
+                        "severity": "high",
+                        "components": ["system"]
+                    }],
+                    "2021-01-15": [{
+                        "cve_identifiers": ["CVE-2023-0010"],
+                        "asb_identifiers": ["ASB-A-2023022"],
+                        "severity": "moderate",
+                        "components": ["vendor"]
+                    }]
+                },
+                "kernel_lts_versions": {}
+            }
+        """
+                .trimIndent()
+        securityState.loadVulnerabilityReport(jsonInput)
+
+        val systemSpl = "2023-01-01"
+        val bundle = Bundle()
+        bundle.putString("system_spl", systemSpl)
+        bundle.putString("vendor_spl", systemSpl)
+        bundle.putString("com.google.android.modulemetadata", systemSpl)
+
+        `when`(mockSecurityStateManager.getGlobalSecurityState(anyString())).thenReturn(bundle)
+        doReturn(systemSpl).`when`(mockSecurityStateManager).getPackageVersion(Mockito.anyString())
+
+        assertTrue(securityState.areCvesPatched(listOf("CVE-2023-0010")))
+    }
+
+    @Test
+    fun testAreCvesPatched_withVendorCve_whenVendorIsDisabled_returnsFalse() {
+        SecurityPatchState.Companion.USE_VENDOR_SPL = false
+        val jsonInput =
+            """
+            {
+                "vulnerabilities": {
+                    "2021-05-01": [{
+                        "cve_identifiers": ["CVE-1234-4321"],
+                        "asb_identifiers": ["ASB-A-2023111"],
+                        "severity": "high",
+                        "components": ["com.google.android.modulemetadata"]
+                    }],
+                    "2022-01-01": [{
+                        "cve_identifiers": ["CVE-2023-0001", "CVE-2023-0002"],
+                        "asb_identifiers": ["ASB-A-2023011"],
+                        "severity": "high",
+                        "components": ["system"]
+                    }],
+                    "2021-01-15": [{
+                        "cve_identifiers": ["CVE-2023-0010"],
+                        "asb_identifiers": ["ASB-A-2023022"],
+                        "severity": "moderate",
+                        "components": ["vendor"]
+                    }]
+                },
+                "kernel_lts_versions": {}
+            }
+        """
+                .trimIndent()
+        securityState.loadVulnerabilityReport(jsonInput)
+
+        val systemSpl = "2023-01-01"
+        val bundle = Bundle()
+        bundle.putString("system_spl", systemSpl)
+        bundle.putString("vendor_spl", systemSpl)
+        bundle.putString("com.google.android.modulemetadata", systemSpl)
+
+        `when`(mockSecurityStateManager.getGlobalSecurityState(anyString())).thenReturn(bundle)
+        doReturn(systemSpl).`when`(mockSecurityStateManager).getPackageVersion(Mockito.anyString())
+
+        assertFalse(securityState.areCvesPatched(listOf("CVE-2023-0010")))
+    }
 }
diff --git a/sqlite/integration-tests/driver-conformance-test/build.gradle b/sqlite/integration-tests/driver-conformance-test/build.gradle
index fd7b912..a2dc3f9 100644
--- a/sqlite/integration-tests/driver-conformance-test/build.gradle
+++ b/sqlite/integration-tests/driver-conformance-test/build.gradle
@@ -26,11 +26,20 @@
 
 plugins {
     id("AndroidXPlugin")
-    id("com.android.library")
 }
 
 androidXMultiplatform {
-    android()
+    androidLibrary {
+        namespace = "androidx.sqlite.driver.test"
+        withAndroidTestOnDeviceBuilder {
+            it.compilationName = "instrumentedTest"
+            it.defaultSourceSetName = "androidInstrumentedTest"
+            it.sourceSetTreeName = "test"
+        }
+        withAndroidTestOnJvmBuilder {
+            it.defaultSourceSetName = "androidUnitTest"
+        }
+    }
     ios()
     jvm()
     linux()
@@ -78,9 +87,6 @@
     }
 }
 
-android {
-    namespace "androidx.sqlite.driver.test"
-}
 
 androidx {
     name = "SQLite Driver Coformance Base Tests"
diff --git a/sqlite/sqlite-framework/build.gradle b/sqlite/sqlite-framework/build.gradle
index 411b332f..c9fff30 100644
--- a/sqlite/sqlite-framework/build.gradle
+++ b/sqlite/sqlite-framework/build.gradle
@@ -29,10 +29,8 @@
 
 plugins {
     id("AndroidXPlugin")
-    id("com.android.library")
 }
 
-
 configurations {
     // Configuration for resolving shared archive file of androidx's SQLite compilation
     sqliteSharedArchive {
@@ -53,7 +51,17 @@
 }
 
 androidXMultiplatform {
-    android()
+    androidLibrary {
+        namespace = "androidx.sqlite.db.framework"
+        withAndroidTestOnDeviceBuilder {
+            it.compilationName = "instrumentedTest"
+            it.defaultSourceSetName = "androidInstrumentedTest"
+            it.sourceSetTreeName = "test"
+        }
+        withAndroidTestOnJvmBuilder {
+            it.defaultSourceSetName = "androidUnitTest"
+        }
+    }
     ios() {
         // Link to sqlite3 available in iOS
         binaries.configureEach {
@@ -148,6 +156,3 @@
     description = "The implementation of SQLite library using the framework code."
 }
 
-android {
-    namespace "androidx.sqlite.db.framework"
-}
diff --git a/sqlite/sqlite/build.gradle b/sqlite/sqlite/build.gradle
index 3c4a438..43cf644 100644
--- a/sqlite/sqlite/build.gradle
+++ b/sqlite/sqlite/build.gradle
@@ -28,12 +28,20 @@
 
 plugins {
     id("AndroidXPlugin")
-    id("com.android.library")
 }
 
-
 androidXMultiplatform {
-    android()
+    androidLibrary {
+        namespace = "androidx.sqlite.db"
+        withAndroidTestOnDeviceBuilder {
+            it.compilationName = "instrumentedTest"
+            it.defaultSourceSetName = "androidInstrumentedTest"
+            it.sourceSetTreeName = "test"
+        }
+        withAndroidTestOnJvmBuilder {
+            it.defaultSourceSetName = "androidUnitTest"
+        }
+    }
     ios()
     jvm()
     linux()
@@ -81,9 +89,6 @@
     }
 }
 
-android {
-    namespace "androidx.sqlite.db"
-}
 
 androidx {
     name = "SQLite"
diff --git a/testutils/testutils-lifecycle/build.gradle b/testutils/testutils-lifecycle/build.gradle
index 9d088a1..4408879 100644
--- a/testutils/testutils-lifecycle/build.gradle
+++ b/testutils/testutils-lifecycle/build.gradle
@@ -27,11 +27,20 @@
 
 plugins {
     id("AndroidXPlugin")
-    id("com.android.library")
 }
 
 androidXMultiplatform {
-    android()
+    androidLibrary {
+        namespace = "androidx.testutils.lifecycle"
+        withAndroidTestOnDeviceBuilder {
+            it.compilationName = "instrumentedTest"
+            it.defaultSourceSetName = "androidInstrumentedTest"
+            it.sourceSetTreeName = "test"
+        }
+        withAndroidTestOnJvmBuilder {
+            it.defaultSourceSetName = "androidUnitTest"
+        }
+    }
     desktop()
     mac()
     linux()
@@ -66,9 +75,6 @@
     }
 }
 
-android {
-    namespace "androidx.testutils.lifecycle"
-}
 
 androidx {
     type = LibraryType.INTERNAL_TEST_LIBRARY
diff --git a/wear/compose/compose-foundation/src/main/baseline-prof.txt b/wear/compose/compose-foundation/src/main/baseline-prof.txt
index 55e69e6..4fbef96 100644
--- a/wear/compose/compose-foundation/src/main/baseline-prof.txt
+++ b/wear/compose/compose-foundation/src/main/baseline-prof.txt
@@ -1,15 +1,19 @@
 HSPLandroidx/wear/compose/foundation/AnchorType;->**(**)**
+SPLandroidx/wear/compose/foundation/AngularWidthSizeWrapper;->**(**)**
 Landroidx/wear/compose/foundation/ArcPaddingValues;
 HSPLandroidx/wear/compose/foundation/ArcPaddingValuesImpl;->**(**)**
 HSPLandroidx/wear/compose/foundation/BaseCurvedChildWrapper;->**(**)**
 HSPLandroidx/wear/compose/foundation/BasicCurvedTextKt**->**(**)**
+HSPLandroidx/wear/compose/foundation/BaseSizeWrapper;->**(**)**
 HSPLandroidx/wear/compose/foundation/BasicSwipeToDismissBoxKt**->**(**)**
 SPLandroidx/wear/compose/foundation/ComposableSingletons;->**(**)**
 HSPLandroidx/wear/compose/foundation/CompositionLocalsKt**->**(**)**
 HSPLandroidx/wear/compose/foundation/ContainerChild;->**(**)**
 Landroidx/wear/compose/foundation/CurvedAlignment;
+HSPLandroidx/wear/compose/foundation/CurvedBoxChild;->**(**)**
 HSPLandroidx/wear/compose/foundation/CurvedChild;->**(**)**
 HSPLandroidx/wear/compose/foundation/CurvedComposableKt**->**(**)**
+HSPLandroidx/wear/compose/foundation/CurvedDrawKt**->**(**)**
 HSPLandroidx/wear/compose/foundation/CurvedLayoutDirection;->**(**)**
 HSPLandroidx/wear/compose/foundation/CurvedLayoutInfo;->**(**)**
 HSPLandroidx/wear/compose/foundation/CurvedLayoutKt**->**(**)**
@@ -19,10 +23,14 @@
 SPLandroidx/wear/compose/foundation/CurvedPaddingKt**->**(**)**
 HSPLandroidx/wear/compose/foundation/CurvedRowChild;->**(**)**
 HSPLandroidx/wear/compose/foundation/CurvedScope;->**(**)**
+Landroidx/wear/compose/foundation/CurvedScopeParentData;
+HSPLandroidx/wear/compose/foundation/CurvedSizeKt**->**(**)**
 HSPLandroidx/wear/compose/foundation/CurvedTextChild;->**(**)**
 HSPLandroidx/wear/compose/foundation/CurvedTextDelegate;->**(**)**
 HSPLandroidx/wear/compose/foundation/CurvedTextStyle;->**(**)**
 SPLandroidx/wear/compose/foundation/CurvedTextStyleKt**->**(**)**
+HSPLandroidx/wear/compose/foundation/DrawWrapper;->**(**)**
+Landroidx/wear/compose/foundation/Element;
 SPLandroidx/wear/compose/foundation/ExpandableItemsDefaults;->**(**)**
 HSPLandroidx/wear/compose/foundation/ExpandableKt**->**(**)**
 HSPLandroidx/wear/compose/foundation/ExpandableState;->**(**)**
@@ -30,10 +38,14 @@
 HSPLandroidx/wear/compose/foundation/HierarchicalFocusCoordinatorKt**->**(**)**
 SPLandroidx/wear/compose/foundation/InternalMutatorMutex;->**(**)**
 HSPLandroidx/wear/compose/foundation/PaddingWrapper;->**(**)**
+SPLandroidx/wear/compose/foundation/ParentDataWrapper;->**(**)**
+HSPLandroidx/wear/compose/foundation/PartialLayoutInfo;->**(**)**
 PLandroidx/wear/compose/foundation/RevealActionType;->**(**)**
 PLandroidx/wear/compose/foundation/RevealScopeImpl;->**(**)**
 PLandroidx/wear/compose/foundation/RevealState;->**(**)**
 PLandroidx/wear/compose/foundation/RevealValue;->**(**)**
+Landroidx/wear/compose/foundation/ScrollInfoProvider;
+HSPLandroidx/wear/compose/foundation/SweepSizeWrapper;->**(**)**
 PLandroidx/wear/compose/foundation/SwipeAnchorsModifier;->**(**)**
 SPLandroidx/wear/compose/foundation/SwipeToDismissBoxState;->**(**)**
 SPLandroidx/wear/compose/foundation/SwipeToDismissKeys;->**(**)**
@@ -43,12 +55,15 @@
 SPLandroidx/wear/compose/foundation/SwipeableV2Defaults;->**(**)**
 HSPLandroidx/wear/compose/foundation/SwipeableV2Kt**->**(**)**
 HSPLandroidx/wear/compose/foundation/SwipeableV2State;->**(**)**
+HSPLandroidx/wear/compose/foundation/TransformingLazyColumnStateScrollInfoProvider;->**(**)**
 SPLandroidx/wear/compose/foundation/lazy/AutoCenteringParams;->**(**)**
 SPLandroidx/wear/compose/foundation/lazy/CombinedPaddingValues;->**(**)**
 HSPLandroidx/wear/compose/foundation/lazy/DefaultScalingLazyListItemInfo;->**(**)**
 HSPLandroidx/wear/compose/foundation/lazy/DefaultScalingLazyListLayoutInfo;->**(**)**
 SPLandroidx/wear/compose/foundation/lazy/DefaultScalingParams;->**(**)**
 SPLandroidx/wear/compose/foundation/lazy/EmptyScalingLazyListLayoutInfo;->**(**)**
+SPLandroidx/wear/compose/foundation/lazy/HeightProviderParentData;->**(**)**
+HSPLandroidx/wear/compose/foundation/lazy/NearestRangeKeyIndexMap;->**(**)**
 HSPLandroidx/wear/compose/foundation/lazy/ScalingLazyColumnKt**->**(**)**
 PLandroidx/wear/compose/foundation/lazy/ScalingLazyColumnSnapFlingBehavior;->**(**)**
 SPLandroidx/wear/compose/foundation/lazy/ScalingLazyListItemScopeImpl;->**(**)**
@@ -57,6 +72,26 @@
 HSPLandroidx/wear/compose/foundation/lazy/ScalingLazyListState;->**(**)**
 SPLandroidx/wear/compose/foundation/lazy/ScalingLazyListStateKt**->**(**)**
 Landroidx/wear/compose/foundation/lazy/ScalingParams;
+HSPLandroidx/wear/compose/foundation/lazy/TransformingLazyColumnContentPaddingMeasurementStrategy;->**(**)**
+HSPLandroidx/wear/compose/foundation/lazy/TransformingLazyColumnInterval;->**(**)**
+HSPLandroidx/wear/compose/foundation/lazy/TransformingLazyColumnItemProvider;->**(**)**
+HSPLandroidx/wear/compose/foundation/lazy/TransformingLazyColumnItemScopeImpl;->**(**)**
+HSPLandroidx/wear/compose/foundation/lazy/TransformingLazyColumnItemScrollProgress;->**(**)**
+HSPLandroidx/wear/compose/foundation/lazy/TransformingLazyColumnKt**->**(**)**
+HSPLandroidx/wear/compose/foundation/lazy/TransformingLazyColumnMeasureResult;->**(**)**
+HSPLandroidx/wear/compose/foundation/lazy/TransformingLazyColumnMeasuredItem;->**(**)**
+HSPLandroidx/wear/compose/foundation/lazy/TransformingLazyColumnMeasurementKt**->**(**)**
+Landroidx/wear/compose/foundation/lazy/TransformingLazyColumnMeasurementStrategy;
+HSPLandroidx/wear/compose/foundation/lazy/TransformingLazyColumnMeasurementStrategyKt**->**(**)**
+Landroidx/wear/compose/foundation/lazy/TransformingLazyColumnScope;
+HSPLandroidx/wear/compose/foundation/lazy/TransformingLazyColumnScopeImpl;->**(**)**
+HSPLandroidx/wear/compose/foundation/lazy/TransformingLazyColumnState;->**(**)**
+SPLandroidx/wear/compose/foundation/lazy/TransformingLazyColumnStateKt**->**(**)**
+Landroidx/wear/compose/foundation/lazy/TransformingLazyColumnVisibleItemInfo;
+SPLandroidx/wear/compose/foundation/pager/CustomTouchSlop;->**(**)**
+HSPLandroidx/wear/compose/foundation/pager/DefaultPagerState;->**(**)**
+HSPLandroidx/wear/compose/foundation/pager/PagerKt**->**(**)**
+Landroidx/wear/compose/foundation/pager/PagerState;
 SPLandroidx/wear/compose/foundation/rotary/BaseRotaryScrollableBehavior;->**(**)**
 SPLandroidx/wear/compose/foundation/rotary/CustomRotaryHapticHandler;->**(**)**
 SPLandroidx/wear/compose/foundation/rotary/FlingRotaryScrollableBehavior;->**(**)**
diff --git a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/BasicSwipeToDismissBox.kt b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/BasicSwipeToDismissBox.kt
index 78cdb6f..4ef9228 100644
--- a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/BasicSwipeToDismissBox.kt
+++ b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/BasicSwipeToDismissBox.kt
@@ -351,14 +351,13 @@
             edgeSwipeState: State<EdgeSwipeState>
         ): NestedScrollConnection =
             object : NestedScrollConnection {
-                @Suppress("DEPRECATION") // b/327155912
                 override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
                     val delta = available.x
                     // If swipeState = SwipeState.SWIPING_TO_DISMISS - perform swipeToDismiss
                     // drag and consume everything
                     return if (
                         edgeSwipeState.value == EdgeSwipeState.SwipingToDismiss &&
-                            source == NestedScrollSource.Drag
+                            source == NestedScrollSource.UserInput
                     ) {
                         dispatchRawDelta(delta)
                         available
diff --git a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/SwipeableV2.kt b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/SwipeableV2.kt
index c4ffe24..2f5c10d 100644
--- a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/SwipeableV2.kt
+++ b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/SwipeableV2.kt
@@ -477,7 +477,6 @@
      *
      * @return The delta the consumed by the [SwipeableV2State]
      */
-    @Suppress("DEPRECATION") // b/327155912
     fun dispatchRawDelta(delta: Float): Float {
         var remainingDelta = delta
 
@@ -486,7 +485,7 @@
             val consumedByParent =
                 nestedScrollDispatcher.dispatchPreScroll(
                     available = offsetWithOrientation(remainingDelta),
-                    source = NestedScrollSource.Drag
+                    source = NestedScrollSource.UserInput
                 )
             remainingDelta -= (consumedByParent.x + consumedByParent.y)
         }
@@ -503,7 +502,7 @@
                 nestedScrollDispatcher.dispatchPostScroll(
                     consumed = offsetWithOrientation(deltaToConsume),
                     available = offsetWithOrientation(delta - deltaToConsume),
-                    source = NestedScrollSource.Drag
+                    source = NestedScrollSource.UserInput
                 )
             remainingDelta -= (deltaToConsume + consumedDelta.x + consumedDelta.y)
         }
diff --git a/wear/compose/compose-material-core/src/main/java/androidx/wear/compose/materialcore/SelectionControls.kt b/wear/compose/compose-material-core/src/main/java/androidx/wear/compose/materialcore/SelectionControls.kt
index aa1b486..988ad1c 100644
--- a/wear/compose/compose-material-core/src/main/java/androidx/wear/compose/materialcore/SelectionControls.kt
+++ b/wear/compose/compose-material-core/src/main/java/androidx/wear/compose/materialcore/SelectionControls.kt
@@ -20,6 +20,7 @@
 import androidx.compose.animation.animateColorAsState
 import androidx.compose.animation.core.AnimationSpec
 import androidx.compose.animation.core.CubicBezierEasing
+import androidx.compose.animation.core.FiniteAnimationSpec
 import androidx.compose.animation.core.Transition
 import androidx.compose.animation.core.TweenSpec
 import androidx.compose.animation.core.animateFloat
@@ -87,7 +88,7 @@
     enabled: Boolean,
     onCheckedChange: ((Boolean) -> Unit)?,
     interactionSource: MutableInteractionSource?,
-    progressAnimationSpec: TweenSpec<Float>,
+    progressAnimationSpec: FiniteAnimationSpec<Float>,
     drawBox: FunctionDrawBox,
     width: Dp,
     height: Dp,
@@ -274,6 +275,59 @@
     width: Dp,
     height: Dp,
     ripple: Indication
+) =
+    RadioButton(
+        modifier = modifier,
+        selected = selected,
+        enabled = enabled,
+        ringColor = ringColor,
+        dotColor = dotColor,
+        onClick = onClick,
+        interactionSource = interactionSource,
+        dotRadiusAnimationSpec = tween(dotRadiusProgressDuration(selected), 0, easing),
+        dotAlphaAnimationSpec = tween(dotAlphaProgressDuration, dotAlphaProgressDelay, easing),
+        width = width,
+        height = height,
+        ripple = ripple
+    )
+
+/**
+ * [RadioButton] provides an animated radio button for use in material APIs.
+ *
+ * @param modifier Modifier to be applied to the radio button. This can be used to provide a content
+ *   description for accessibility.
+ * @param selected Boolean flag indicating whether this radio button is currently toggled on.
+ * @param enabled Boolean flag indicating the enabled state of the [RadioButton] (affects the
+ *   color).
+ * @param ringColor Composable lambda from which the ring color of the radio button will be
+ *   obtained.
+ * @param dotColor Composable lambda from which the dot color of the radio button will be obtained.
+ * @param onClick Callback to be invoked when RadioButton is clicked. If null, then this is passive
+ *   and relies entirely on a higher-level component to control the state.
+ * @param interactionSource When also providing [onClick], the [MutableInteractionSource]
+ *   representing the stream of [Interaction]s for the "toggleable" tap area - can be used to
+ *   customise the appearance / behavior of the RadioButton.
+ * @param dotRadiusAnimationSpec Animation spec of the dot radius progress animation.
+ * @param dotAlphaAnimationSpec Animation spec of the dot alpha progress animation.
+ * @param width Width of the radio button.
+ * @param height Height of the radio button.
+ * @param ripple Ripple used for the radio button.
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+@Composable
+fun RadioButton(
+    modifier: Modifier,
+    selected: Boolean,
+    enabled: Boolean,
+    ringColor: @Composable (enabled: Boolean, checked: Boolean) -> State<Color>,
+    dotColor: @Composable (enabled: Boolean, checked: Boolean) -> State<Color>,
+    onClick: (() -> Unit)?,
+    interactionSource: MutableInteractionSource?,
+    dotRadiusAnimationSpec: FiniteAnimationSpec<Float>,
+    dotAlphaAnimationSpec: FiniteAnimationSpec<Float>,
+    width: Dp,
+    height: Dp,
+    ripple: Indication
 ) {
     val targetState = if (selected) SelectionStage.Checked else SelectionStage.Unchecked
     val transition = updateTransition(targetState)
@@ -286,7 +340,7 @@
         animateProgress(
             transition = transition,
             label = "dot-radius",
-            animationSpec = tween(dotRadiusProgressDuration(selected), 0, easing)
+            animationSpec = dotRadiusAnimationSpec
         )
     // Animation of the dot alpha only happens when toggling On to Off.
     val dotAlphaProgress =
@@ -294,7 +348,7 @@
             animateProgress(
                 transition = transition,
                 label = "dot-alpha",
-                animationSpec = tween(dotAlphaProgressDuration, dotAlphaProgressDelay, easing)
+                animationSpec = dotAlphaAnimationSpec
             )
         else null
 
@@ -426,7 +480,7 @@
 private fun animateProgress(
     transition: Transition<SelectionStage>,
     label: String,
-    animationSpec: TweenSpec<Float>,
+    animationSpec: FiniteAnimationSpec<Float>,
 ) =
     transition.animateFloat(transitionSpec = { animationSpec }, label = label) {
         when (it) {
diff --git a/wear/compose/compose-material/src/androidTest/kotlin/androidx/wear/compose/material/dialog/DialogTest.kt b/wear/compose/compose-material/src/androidTest/kotlin/androidx/wear/compose/material/dialog/DialogTest.kt
index f28182d..a2e882f 100644
--- a/wear/compose/compose-material/src/androidTest/kotlin/androidx/wear/compose/material/dialog/DialogTest.kt
+++ b/wear/compose/compose-material/src/androidTest/kotlin/androidx/wear/compose/material/dialog/DialogTest.kt
@@ -424,10 +424,11 @@
                         dismissCounter++
                         show.value = false
                     },
-                    durationMillis = 100
+                    durationMillis = 300
                 )
             }
         }
+        rule.waitForIdle()
         rule.waitUntilDoesNotExist(hasTestTag(TEST_TAG))
         assertEquals(1, dismissCounter)
     }
diff --git a/wear/compose/compose-material3/api/current.txt b/wear/compose/compose-material3/api/current.txt
index 551c115..178be84 100644
--- a/wear/compose/compose-material3/api/current.txt
+++ b/wear/compose/compose-material3/api/current.txt
@@ -27,6 +27,17 @@
     method @androidx.compose.runtime.Composable public static void AlertDialogContent(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> confirmButton, kotlin.jvm.functions.Function0<kotlin.Unit> title, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> dismissButton, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? text, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function1<? super androidx.wear.compose.foundation.lazy.ScalingLazyListScope,kotlin.Unit>? content);
   }
 
+  @kotlin.jvm.JvmInline public final value class AngularDirection {
+    field public static final androidx.wear.compose.material3.AngularDirection.Companion Companion;
+  }
+
+  public static final class AngularDirection.Companion {
+    method public int getClockwise();
+    method public int getCounterClockwise();
+    property public final int Clockwise;
+    property public final int CounterClockwise;
+  }
+
   @RequiresApi(31) public final class AnimatedTextDefaults {
     field public static final int CacheSize = 5; // 0x5
     field public static final androidx.wear.compose.material3.AnimatedTextDefaults INSTANCE;
@@ -45,6 +56,21 @@
     method @androidx.compose.runtime.Composable public static void AppScaffold(optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit> timeText, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
   }
 
+  public final class ArcProgressIndicatorDefaults {
+    method public float calculateRecommendedGapSize(float strokeWidth);
+    method public float getIndeterminateStrokeWidth();
+    method @androidx.compose.runtime.Composable public float getRecommendedIndeterminateDiameter();
+    property public final float IndeterminateStrokeWidth;
+    property @androidx.compose.runtime.Composable public final float recommendedIndeterminateDiameter;
+    field public static final androidx.wear.compose.material3.ArcProgressIndicatorDefaults INSTANCE;
+    field public static final float IndeterminateEndAngle = 118.0f;
+    field public static final float IndeterminateStartAngle = 62.0f;
+  }
+
+  public final class ArcProgressIndicatorKt {
+    method @androidx.compose.runtime.Composable public static void ArcProgressIndicator(optional float startAngle, optional float endAngle, optional androidx.compose.ui.Modifier modifier, optional int angularDirection, optional androidx.wear.compose.material3.ProgressIndicatorColors colors, optional float strokeWidth, optional float gapSize);
+  }
+
   @androidx.compose.runtime.Immutable public final class ButtonColors {
     ctor public ButtonColors(androidx.compose.ui.graphics.painter.Painter containerPainter, long contentColor, long secondaryContentColor, long iconColor, androidx.compose.ui.graphics.painter.Painter disabledContainerPainter, long disabledContentColor, long disabledSecondaryContentColor, long disabledIconColor);
     ctor public ButtonColors(long containerColor, long contentColor, long secondaryContentColor, long iconColor, long disabledContainerColor, long disabledContentColor, long disabledSecondaryContentColor, long disabledIconColor);
@@ -825,11 +851,11 @@
 
   public final class PlaceholderDefaults {
     method public androidx.compose.ui.graphics.Shape getShape();
-    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.painter.Painter painterWithPlaceholderOverlayBackgroundBrush(androidx.wear.compose.material3.PlaceholderState placeholderState, androidx.compose.ui.graphics.painter.Painter painter, optional long color);
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.painter.Painter painterWithPlaceholderOverlayBackgroundBrush(androidx.wear.compose.material3.PlaceholderState placeholderState, androidx.compose.ui.graphics.painter.Painter originalPainter, optional long color);
     method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.painter.Painter placeholderBackgroundBrush(androidx.wear.compose.material3.PlaceholderState placeholderState, optional long color);
     method @androidx.compose.runtime.Composable public androidx.wear.compose.material3.ButtonColors placeholderButtonColors(androidx.wear.compose.material3.ButtonColors originalButtonColors, androidx.wear.compose.material3.PlaceholderState placeholderState, optional long color);
     method @androidx.compose.runtime.Composable public androidx.wear.compose.material3.ButtonColors placeholderButtonColors(androidx.wear.compose.material3.PlaceholderState placeholderState, optional long color);
-    property public final androidx.compose.ui.graphics.Shape shape;
+    property public final androidx.compose.ui.graphics.Shape Shape;
     field public static final androidx.wear.compose.material3.PlaceholderDefaults INSTANCE;
   }
 
@@ -840,13 +866,11 @@
   }
 
   @androidx.compose.runtime.Stable public final class PlaceholderState {
-    method public float getPlaceholderProgression();
-    method public boolean isShowContent();
-    method public boolean isWipeOff();
-    method public suspend Object? startPlaceholderAnimation(kotlin.coroutines.Continuation<? super kotlin.Unit>);
-    property public final boolean isShowContent;
-    property public final boolean isWipeOff;
-    property public final float placeholderProgression;
+    method public suspend Object? animatePlaceholder(kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    method public boolean isHidden();
+    method public boolean isWipingOff();
+    property public final boolean isHidden;
+    property public final boolean isWipingOff;
   }
 
   public final class ProgressIndicatorColors {
diff --git a/wear/compose/compose-material3/api/restricted_current.txt b/wear/compose/compose-material3/api/restricted_current.txt
index 551c115..178be84 100644
--- a/wear/compose/compose-material3/api/restricted_current.txt
+++ b/wear/compose/compose-material3/api/restricted_current.txt
@@ -27,6 +27,17 @@
     method @androidx.compose.runtime.Composable public static void AlertDialogContent(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> confirmButton, kotlin.jvm.functions.Function0<kotlin.Unit> title, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> dismissButton, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? text, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function1<? super androidx.wear.compose.foundation.lazy.ScalingLazyListScope,kotlin.Unit>? content);
   }
 
+  @kotlin.jvm.JvmInline public final value class AngularDirection {
+    field public static final androidx.wear.compose.material3.AngularDirection.Companion Companion;
+  }
+
+  public static final class AngularDirection.Companion {
+    method public int getClockwise();
+    method public int getCounterClockwise();
+    property public final int Clockwise;
+    property public final int CounterClockwise;
+  }
+
   @RequiresApi(31) public final class AnimatedTextDefaults {
     field public static final int CacheSize = 5; // 0x5
     field public static final androidx.wear.compose.material3.AnimatedTextDefaults INSTANCE;
@@ -45,6 +56,21 @@
     method @androidx.compose.runtime.Composable public static void AppScaffold(optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit> timeText, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
   }
 
+  public final class ArcProgressIndicatorDefaults {
+    method public float calculateRecommendedGapSize(float strokeWidth);
+    method public float getIndeterminateStrokeWidth();
+    method @androidx.compose.runtime.Composable public float getRecommendedIndeterminateDiameter();
+    property public final float IndeterminateStrokeWidth;
+    property @androidx.compose.runtime.Composable public final float recommendedIndeterminateDiameter;
+    field public static final androidx.wear.compose.material3.ArcProgressIndicatorDefaults INSTANCE;
+    field public static final float IndeterminateEndAngle = 118.0f;
+    field public static final float IndeterminateStartAngle = 62.0f;
+  }
+
+  public final class ArcProgressIndicatorKt {
+    method @androidx.compose.runtime.Composable public static void ArcProgressIndicator(optional float startAngle, optional float endAngle, optional androidx.compose.ui.Modifier modifier, optional int angularDirection, optional androidx.wear.compose.material3.ProgressIndicatorColors colors, optional float strokeWidth, optional float gapSize);
+  }
+
   @androidx.compose.runtime.Immutable public final class ButtonColors {
     ctor public ButtonColors(androidx.compose.ui.graphics.painter.Painter containerPainter, long contentColor, long secondaryContentColor, long iconColor, androidx.compose.ui.graphics.painter.Painter disabledContainerPainter, long disabledContentColor, long disabledSecondaryContentColor, long disabledIconColor);
     ctor public ButtonColors(long containerColor, long contentColor, long secondaryContentColor, long iconColor, long disabledContainerColor, long disabledContentColor, long disabledSecondaryContentColor, long disabledIconColor);
@@ -825,11 +851,11 @@
 
   public final class PlaceholderDefaults {
     method public androidx.compose.ui.graphics.Shape getShape();
-    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.painter.Painter painterWithPlaceholderOverlayBackgroundBrush(androidx.wear.compose.material3.PlaceholderState placeholderState, androidx.compose.ui.graphics.painter.Painter painter, optional long color);
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.painter.Painter painterWithPlaceholderOverlayBackgroundBrush(androidx.wear.compose.material3.PlaceholderState placeholderState, androidx.compose.ui.graphics.painter.Painter originalPainter, optional long color);
     method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.painter.Painter placeholderBackgroundBrush(androidx.wear.compose.material3.PlaceholderState placeholderState, optional long color);
     method @androidx.compose.runtime.Composable public androidx.wear.compose.material3.ButtonColors placeholderButtonColors(androidx.wear.compose.material3.ButtonColors originalButtonColors, androidx.wear.compose.material3.PlaceholderState placeholderState, optional long color);
     method @androidx.compose.runtime.Composable public androidx.wear.compose.material3.ButtonColors placeholderButtonColors(androidx.wear.compose.material3.PlaceholderState placeholderState, optional long color);
-    property public final androidx.compose.ui.graphics.Shape shape;
+    property public final androidx.compose.ui.graphics.Shape Shape;
     field public static final androidx.wear.compose.material3.PlaceholderDefaults INSTANCE;
   }
 
@@ -840,13 +866,11 @@
   }
 
   @androidx.compose.runtime.Stable public final class PlaceholderState {
-    method public float getPlaceholderProgression();
-    method public boolean isShowContent();
-    method public boolean isWipeOff();
-    method public suspend Object? startPlaceholderAnimation(kotlin.coroutines.Continuation<? super kotlin.Unit>);
-    property public final boolean isShowContent;
-    property public final boolean isWipeOff;
-    property public final float placeholderProgression;
+    method public suspend Object? animatePlaceholder(kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    method public boolean isHidden();
+    method public boolean isWipingOff();
+    property public final boolean isHidden;
+    property public final boolean isWipingOff;
   }
 
   public final class ProgressIndicatorColors {
diff --git a/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/PlaceholderDemo.kt b/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/PlaceholderDemo.kt
index bf7184c..79493f9 100644
--- a/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/PlaceholderDemo.kt
+++ b/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/PlaceholderDemo.kt
@@ -405,7 +405,7 @@
                     placeholderState = buttonPlaceholderState
                 )
         )
-        if (!buttonPlaceholderState.isShowContent) {
+        if (!buttonPlaceholderState.isHidden) {
             Button(
                 modifier =
                     modifier
@@ -457,7 +457,7 @@
             )
         }
     }
-    LaunchedEffect(buttonPlaceholderState) { buttonPlaceholderState.startPlaceholderAnimation() }
+    LaunchedEffect(buttonPlaceholderState) { buttonPlaceholderState.animatePlaceholder() }
 }
 
 @Composable
@@ -532,7 +532,7 @@
                 placeholderState = buttonPlaceholderState
             )
     )
-    LaunchedEffect(buttonPlaceholderState) { buttonPlaceholderState.startPlaceholderAnimation() }
+    LaunchedEffect(buttonPlaceholderState) { buttonPlaceholderState.animatePlaceholder() }
 }
 
 @Composable
@@ -553,7 +553,7 @@
         ) {
             if (content != null) content()
         }
-        if (!cardPlaceholderState.isShowContent) {
+        if (!cardPlaceholderState.isHidden) {
             AppCard(
                 onClick = {},
                 appName = {
@@ -596,5 +596,5 @@
             }
         }
     }
-    LaunchedEffect(cardPlaceholderState) { cardPlaceholderState.startPlaceholderAnimation() }
+    LaunchedEffect(cardPlaceholderState) { cardPlaceholderState.animatePlaceholder() }
 }
diff --git a/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/ProgressIndicatorDemo.kt b/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/ProgressIndicatorDemo.kt
index 854b089..99e8400c 100644
--- a/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/ProgressIndicatorDemo.kt
+++ b/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/ProgressIndicatorDemo.kt
@@ -38,6 +38,9 @@
 import androidx.wear.compose.integration.demos.common.Centralize
 import androidx.wear.compose.integration.demos.common.ComposableDemo
 import androidx.wear.compose.integration.demos.common.Material3DemoCategory
+import androidx.wear.compose.material3.AngularDirection
+import androidx.wear.compose.material3.ArcProgressIndicator
+import androidx.wear.compose.material3.ArcProgressIndicatorDefaults
 import androidx.wear.compose.material3.Button
 import androidx.wear.compose.material3.CircularProgressIndicator
 import androidx.wear.compose.material3.CircularProgressIndicatorDefaults
@@ -51,6 +54,7 @@
 import androidx.wear.compose.material3.SwitchButton
 import androidx.wear.compose.material3.Text
 import androidx.wear.compose.material3.samples.FullScreenProgressIndicatorSample
+import androidx.wear.compose.material3.samples.IndeterminateProgressArcSample
 import androidx.wear.compose.material3.samples.IndeterminateProgressIndicatorSample
 import androidx.wear.compose.material3.samples.LinearProgressIndicatorSample
 import androidx.wear.compose.material3.samples.MediaButtonProgressIndicatorSample
@@ -126,11 +130,15 @@
                 },
             )
         ),
+        ComposableDemo("Linear progress") { Centralize { LinearProgressIndicatorSamples() } },
         Material3DemoCategory(
-            title = "Linear progress",
+            title = "Arc Progress Indicator",
             listOf(
-                ComposableDemo("Linear progress") {
-                    Centralize { LinearProgressIndicatorSamples() }
+                ComposableDemo("Indeterminate arc") {
+                    Centralize { IndeterminateProgressArcSample() }
+                },
+                ComposableDemo("Custom indeterminate arc") {
+                    Centralize { ArcProgressCustomisableFullScreenDemo() }
                 },
             )
         )
@@ -268,6 +276,60 @@
 }
 
 @Composable
+fun ArcProgressCustomisableFullScreenDemo() {
+    val startAngle = remember {
+        mutableFloatStateOf(ArcProgressIndicatorDefaults.IndeterminateStartAngle)
+    }
+    val endAngle = remember {
+        mutableFloatStateOf(ArcProgressIndicatorDefaults.IndeterminateEndAngle)
+    }
+    val defaultDiameter = ArcProgressIndicatorDefaults.recommendedIndeterminateDiameter
+    val diameter = remember { mutableFloatStateOf(defaultDiameter.value) }
+    val strokeWidth = remember {
+        mutableFloatStateOf(ArcProgressIndicatorDefaults.IndeterminateStrokeWidth.value)
+    }
+    val angularDirection = remember { mutableStateOf(AngularDirection.CounterClockwise) }
+    val hasCustomColors = remember { mutableStateOf(false) }
+    val colors =
+        if (hasCustomColors.value) {
+            ProgressIndicatorDefaults.colors(
+                indicatorColor = Color.Green,
+                trackColor = Color.Green.copy(alpha = 0.5f),
+                overflowTrackColor = Color.Green.copy(alpha = 0.7f),
+            )
+        } else {
+            ProgressIndicatorDefaults.colors()
+        }
+
+    Box(
+        modifier =
+            Modifier.background(MaterialTheme.colorScheme.background)
+                .padding(CircularProgressIndicatorDefaults.FullScreenPadding)
+                .fillMaxSize()
+    ) {
+        ArcIndicatorCustomizer(
+            startAngle = startAngle,
+            endAngle = endAngle,
+            diameter = diameter,
+            strokeWidth = strokeWidth,
+            angularDirection = angularDirection,
+            hasCustomColors = hasCustomColors,
+        )
+
+        Centralize {
+            ArcProgressIndicator(
+                startAngle = startAngle.floatValue,
+                endAngle = endAngle.floatValue,
+                strokeWidth = strokeWidth.floatValue.dp,
+                angularDirection = angularDirection.value,
+                colors = colors,
+                modifier = Modifier.size(diameter.floatValue.dp)
+            )
+        }
+    }
+}
+
+@Composable
 fun ProgressIndicatorCustomizer(
     progress: MutableState<Float>,
     startAngle: MutableState<Float>,
@@ -396,3 +458,95 @@
         )
     }
 }
+
+@Composable
+fun ArcIndicatorCustomizer(
+    startAngle: MutableState<Float>,
+    endAngle: MutableState<Float>,
+    diameter: MutableState<Float>,
+    strokeWidth: MutableState<Float>,
+    angularDirection: MutableState<AngularDirection>,
+    hasCustomColors: MutableState<Boolean>,
+) {
+    ScalingLazyColumn(
+        modifier = Modifier.fillMaxSize().padding(12.dp),
+        verticalArrangement = Arrangement.Center,
+        horizontalAlignment = Alignment.CenterHorizontally
+    ) {
+        item { Text("Start Angle: ${startAngle.value.toInt()}") }
+        item {
+            Slider(
+                value = startAngle.value,
+                onValueChange = { startAngle.value = it },
+                valueRange = 0f..360f,
+                steps = 35,
+                segmented = false,
+                colors =
+                    SliderDefaults.sliderColors(
+                        containerColor = MaterialTheme.colorScheme.background,
+                    ),
+            )
+        }
+        item { Text("End angle: ${endAngle.value.toInt()}") }
+        item {
+            Slider(
+                value = endAngle.value,
+                onValueChange = { endAngle.value = it },
+                valueRange = 0f..360f,
+                steps = 35,
+                segmented = false,
+                colors =
+                    SliderDefaults.sliderColors(
+                        containerColor = MaterialTheme.colorScheme.background,
+                    ),
+            )
+        }
+        item { Text("Diameter: ${diameter.value.toInt()}") }
+        item {
+            Slider(
+                value = diameter.value,
+                onValueChange = { diameter.value = it },
+                valueRange = 10f..400f,
+                steps = 38,
+                segmented = false,
+                colors =
+                    SliderDefaults.sliderColors(
+                        containerColor = MaterialTheme.colorScheme.background,
+                    ),
+            )
+        }
+        item { Text("StrokeWidth: ${strokeWidth.value}") }
+        item {
+            Slider(
+                value = strokeWidth.value,
+                onValueChange = { strokeWidth.value = it },
+                valueRange = 1f..20f,
+                steps = 18,
+                segmented = false,
+                colors =
+                    SliderDefaults.sliderColors(
+                        containerColor = MaterialTheme.colorScheme.background,
+                    ),
+            )
+        }
+        item {
+            SwitchButton(
+                modifier = Modifier.fillMaxWidth().padding(8.dp),
+                checked = angularDirection.value == AngularDirection.Clockwise,
+                onCheckedChange = {
+                    angularDirection.value =
+                        if (it) AngularDirection.Clockwise else AngularDirection.CounterClockwise
+                },
+                label = { Text("Clockwise") },
+            )
+        }
+        item {
+            SwitchButton(
+                modifier = Modifier.fillMaxWidth().padding(8.dp),
+                checked = hasCustomColors.value,
+                onCheckedChange = { hasCustomColors.value = it },
+                label = { Text("Custom colors") },
+            )
+        }
+    }
+}
diff --git a/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/WearMaterial3Demos.kt b/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/WearMaterial3Demos.kt
index b1a80cf..108dbdb 100644
--- a/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/WearMaterial3Demos.kt
+++ b/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/WearMaterial3Demos.kt
@@ -84,6 +84,7 @@
                     )
                 ),
                 Material3DemoCategory("ScrollAway", ScrollAwayDemos),
+                Material3DemoCategory(title = "Typography", TypographyDemos),
                 ComposableDemo("Compact Button") { CompactButtonDemo() },
                 ComposableDemo("Icon Button") { IconButtonDemo() },
                 ComposableDemo("Image Button") { ImageButtonDemo() },
@@ -171,7 +172,6 @@
                         }
                     )
                 ),
-                Material3DemoCategory(title = "Typography", TypographyDemos),
                 Material3DemoCategory(
                     "Animated Text",
                     if (Build.VERSION.SDK_INT > 31) {
diff --git a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/MacrobenchmarkScreen.kt b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/MacrobenchmarkScreen.kt
new file mode 100644
index 0000000..67330d5
--- /dev/null
+++ b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/MacrobenchmarkScreen.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2024 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.material3.macrobenchmark.common
+
+import androidx.benchmark.macro.MacrobenchmarkScope
+import androidx.compose.foundation.layout.BoxScope
+import androidx.compose.runtime.Composable
+
+/** Represents a screen that can be used in Macrobenchmark tests. */
+interface MacrobenchmarkScreen {
+    val content: @Composable BoxScope.() -> Unit
+    val exercise: MacrobenchmarkScope.() -> Unit
+        get() = { device.waitForIdle() }
+}
diff --git a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/TransformingLazyColumnBenchmark.kt b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/TransformingLazyColumnBenchmark.kt
new file mode 100644
index 0000000..ccf678d
--- /dev/null
+++ b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/TransformingLazyColumnBenchmark.kt
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2024 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.material3.macrobenchmark.common
+
+import android.graphics.Point
+import androidx.benchmark.macro.MacrobenchmarkScope
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.BoxScope
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.semantics.contentDescription
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.unit.dp
+import androidx.test.uiautomator.By
+import androidx.wear.compose.foundation.lazy.TransformingLazyColumn
+import androidx.wear.compose.foundation.lazy.rememberTransformingLazyColumnState
+import androidx.wear.compose.material3.AppScaffold
+import androidx.wear.compose.material3.EdgeButton
+import androidx.wear.compose.material3.EdgeButtonSize
+import androidx.wear.compose.material3.MaterialTheme
+import androidx.wear.compose.material3.ScreenScaffold
+import androidx.wear.compose.material3.ScreenScaffoldDefaults
+import androidx.wear.compose.material3.Text
+import androidx.wear.compose.material3.lazy.scrollTransform
+import kotlinx.coroutines.launch
+
+val TransformingLazyColumnBenchmark =
+    object : MacrobenchmarkScreen {
+        override val content: @Composable (BoxScope.() -> Unit)
+            get() = {
+                val state = rememberTransformingLazyColumnState()
+                val coroutineScope = rememberCoroutineScope()
+                AppScaffold {
+                    ScreenScaffold(
+                        state,
+                        edgeButton = {
+                            EdgeButton(
+                                onClick = { coroutineScope.launch { state.scrollToItem(1) } }
+                            ) {
+                                Text("To top")
+                            }
+                        }
+                    ) {
+                        TransformingLazyColumn(
+                            state = state,
+                            contentPadding =
+                                ScreenScaffoldDefaults.contentPaddingWithEdgeButton(
+                                    EdgeButtonSize.Small,
+                                    start = 10.dp,
+                                    end = 10.dp,
+                                    top = 20.dp,
+                                    extraBottom = 20.dp
+                                ),
+                            modifier =
+                                Modifier.background(MaterialTheme.colorScheme.background)
+                                    .semantics { contentDescription = CONTENT_DESCRIPTION }
+                        ) {
+                            items(5000) {
+                                Text(
+                                    "Item $it",
+                                    color = MaterialTheme.colorScheme.onSurface,
+                                    style = MaterialTheme.typography.bodyLarge,
+                                    modifier =
+                                        Modifier.fillMaxWidth()
+                                            // Apply Material 3 Motion transformations.
+                                            .scrollTransform(
+                                                this,
+                                                backgroundColor =
+                                                    MaterialTheme.colorScheme.surfaceContainer,
+                                                shape = MaterialTheme.shapes.small
+                                            )
+                                            .padding(10.dp)
+                                )
+                            }
+                        }
+                    }
+                }
+            }
+
+        override val exercise: MacrobenchmarkScope.() -> Unit
+            get() = {
+                val list = device.findObject(By.desc(CONTENT_DESCRIPTION))
+                // Setting a gesture margin is important otherwise gesture nav is triggered.
+                list.setGestureMargin(device.displayWidth / 5)
+                repeat(5) {
+                    list.drag(Point(list.visibleCenter.x, list.visibleCenter.y / 3))
+                    device.waitForIdle()
+                }
+            }
+    }
diff --git a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/Utils.kt b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/Utils.kt
index 1f54bb2..3cf03ed 100644
--- a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/Utils.kt
+++ b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/Utils.kt
@@ -18,7 +18,9 @@
 
 import androidx.test.uiautomator.UiDevice
 
-internal fun numberedContentDescription(n: Int) = "find-me-$n"
+internal val CONTENT_DESCRIPTION = "find-me"
+
+internal fun numberedContentDescription(n: Int) = "$CONTENT_DESCRIPTION-$n"
 
 internal fun UiDevice.scrollDown() {
     swipe(
diff --git a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/AlertDialogScreen.kt b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/AlertDialogScreen.kt
index 2b5adb3..762b883 100644
--- a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/AlertDialogScreen.kt
+++ b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/AlertDialogScreen.kt
@@ -46,10 +46,11 @@
 import androidx.wear.compose.material3.MaterialTheme
 import androidx.wear.compose.material3.Text
 import androidx.wear.compose.material3.macrobenchmark.common.FIND_OBJECT_TIMEOUT_MS
+import androidx.wear.compose.material3.macrobenchmark.common.MacrobenchmarkScreen
 import androidx.wear.compose.material3.macrobenchmark.common.R
 
 val AlertDialogScreen =
-    object : BaselineProfileScreen {
+    object : MacrobenchmarkScreen {
 
         override val content: @Composable BoxScope.() -> Unit
             get() = {
diff --git a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/AnimatedTextScreen.kt b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/AnimatedTextScreen.kt
index 6be0bfe..615f51c 100644
--- a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/AnimatedTextScreen.kt
+++ b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/AnimatedTextScreen.kt
@@ -49,12 +49,13 @@
 import androidx.wear.compose.material3.AnimatedText
 import androidx.wear.compose.material3.Text
 import androidx.wear.compose.material3.macrobenchmark.common.FIND_OBJECT_TIMEOUT_MS
+import androidx.wear.compose.material3.macrobenchmark.common.MacrobenchmarkScreen
 import androidx.wear.compose.material3.macrobenchmark.common.R
 import androidx.wear.compose.material3.rememberAnimatedTextFontRegistry
 import kotlinx.coroutines.launch
 
 val AnimatedTextScreen =
-    object : BaselineProfileScreen {
+    object : MacrobenchmarkScreen {
         override val content: @Composable BoxScope.() -> Unit
             get() = {
                 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
diff --git a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/BaselineProfileScreens.kt b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/BaselineProfileScreens.kt
index c50d169..e5b993a 100644
--- a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/BaselineProfileScreens.kt
+++ b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/BaselineProfileScreens.kt
@@ -16,10 +16,6 @@
 
 package androidx.wear.compose.material3.macrobenchmark.common.baselineprofile
 
-import androidx.benchmark.macro.MacrobenchmarkScope
-import androidx.compose.foundation.layout.BoxScope
-import androidx.compose.runtime.Composable
-
 val BaselineProfileScreens =
     listOf(
         AlertDialogScreen,
@@ -56,10 +52,3 @@
         TimePickerScreen,
         TransformingLazyColumnScreen,
     )
-
-/** Represents a screen used for generating a baseline profile. */
-interface BaselineProfileScreen {
-    val content: @Composable BoxScope.() -> Unit
-    val exercise: MacrobenchmarkScope.() -> Unit
-        get() = { device.waitForIdle() }
-}
diff --git a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/ButtonGroupScreen.kt b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/ButtonGroupScreen.kt
index 2125418..d7fc697 100644
--- a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/ButtonGroupScreen.kt
+++ b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/ButtonGroupScreen.kt
@@ -18,10 +18,11 @@
 
 import androidx.compose.foundation.layout.BoxScope
 import androidx.compose.runtime.Composable
+import androidx.wear.compose.material3.macrobenchmark.common.MacrobenchmarkScreen
 import androidx.wear.compose.material3.samples.ButtonGroupSample
 
 val ButtonGroupScreen =
-    object : BaselineProfileScreen {
+    object : MacrobenchmarkScreen {
         override val content: @Composable BoxScope.() -> Unit
             get() = { ButtonGroupSample() }
     }
diff --git a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/ButtonScreen.kt b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/ButtonScreen.kt
index 6274bc5..8766fc3 100644
--- a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/ButtonScreen.kt
+++ b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/ButtonScreen.kt
@@ -25,6 +25,7 @@
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.res.painterResource
 import androidx.wear.compose.material3.IconButtonDefaults
+import androidx.wear.compose.material3.macrobenchmark.common.MacrobenchmarkScreen
 import androidx.wear.compose.material3.macrobenchmark.common.R
 import androidx.wear.compose.material3.macrobenchmark.common.scrollDown
 import androidx.wear.compose.material3.samples.ButtonSample
@@ -38,7 +39,7 @@
 import androidx.wear.compose.material3.samples.OutlinedCompactButtonSample
 
 val ButtonScreen =
-    object : BaselineProfileScreen {
+    object : MacrobenchmarkScreen {
         override val content: @Composable BoxScope.() -> Unit
             get() = {
                 Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
diff --git a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/CardScreen.kt b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/CardScreen.kt
index 4e149a6..7fbf379 100644
--- a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/CardScreen.kt
+++ b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/CardScreen.kt
@@ -37,11 +37,12 @@
 import androidx.wear.compose.material3.OutlinedCard
 import androidx.wear.compose.material3.Text
 import androidx.wear.compose.material3.TitleCard
+import androidx.wear.compose.material3.macrobenchmark.common.MacrobenchmarkScreen
 import androidx.wear.compose.material3.macrobenchmark.common.R
 import androidx.wear.compose.material3.macrobenchmark.common.scrollDown
 
 val CardScreen =
-    object : BaselineProfileScreen {
+    object : MacrobenchmarkScreen {
         override val content: @Composable BoxScope.() -> Unit
             get() = {
                 Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
diff --git a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/CheckboxButtonScreen.kt b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/CheckboxButtonScreen.kt
index 8d8000a..69bf7b3 100644
--- a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/CheckboxButtonScreen.kt
+++ b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/CheckboxButtonScreen.kt
@@ -22,11 +22,12 @@
 import androidx.compose.foundation.verticalScroll
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
+import androidx.wear.compose.material3.macrobenchmark.common.MacrobenchmarkScreen
 import androidx.wear.compose.material3.samples.CheckboxButtonSample
 import androidx.wear.compose.material3.samples.SplitCheckboxButtonSample
 
 val CheckboxButtonScreen =
-    object : BaselineProfileScreen {
+    object : MacrobenchmarkScreen {
         override val content: @Composable BoxScope.() -> Unit
             get() = {
                 Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
diff --git a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/ColorSchemeScreen.kt b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/ColorSchemeScreen.kt
index f978ad6..a85413c 100644
--- a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/ColorSchemeScreen.kt
+++ b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/ColorSchemeScreen.kt
@@ -30,10 +30,11 @@
 import androidx.wear.compose.material3.ButtonDefaults
 import androidx.wear.compose.material3.MaterialTheme
 import androidx.wear.compose.material3.Text
+import androidx.wear.compose.material3.macrobenchmark.common.MacrobenchmarkScreen
 import androidx.wear.compose.material3.macrobenchmark.common.scrollDown
 
 val ColorSchemeScreen =
-    object : BaselineProfileScreen {
+    object : MacrobenchmarkScreen {
         override val content: @Composable BoxScope.() -> Unit
             get() = {
                 Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
diff --git a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/ConfirmationScreen.kt b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/ConfirmationScreen.kt
index 8796147..406042b 100644
--- a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/ConfirmationScreen.kt
+++ b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/ConfirmationScreen.kt
@@ -26,10 +26,8 @@
 import androidx.compose.foundation.verticalScroll
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.MutableState
-import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
-import androidx.compose.runtime.setValue
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.res.painterResource
@@ -45,11 +43,12 @@
 import androidx.wear.compose.material3.SuccessConfirmation
 import androidx.wear.compose.material3.Text
 import androidx.wear.compose.material3.macrobenchmark.common.FIND_OBJECT_TIMEOUT_MS
+import androidx.wear.compose.material3.macrobenchmark.common.MacrobenchmarkScreen
 import androidx.wear.compose.material3.macrobenchmark.common.R
 import androidx.wear.compose.material3.macrobenchmark.common.numberedContentDescription
 
 val ConfirmationScreen =
-    object : BaselineProfileScreen {
+    object : MacrobenchmarkScreen {
         override val content: @Composable BoxScope.() -> Unit
             get() = {
                 Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
diff --git a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/CurvedTextScreen.kt b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/CurvedTextScreen.kt
index e5f6508..f149ecb 100644
--- a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/CurvedTextScreen.kt
+++ b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/CurvedTextScreen.kt
@@ -18,11 +18,12 @@
 
 import androidx.compose.foundation.layout.BoxScope
 import androidx.compose.runtime.Composable
+import androidx.wear.compose.material3.macrobenchmark.common.MacrobenchmarkScreen
 import androidx.wear.compose.material3.samples.CurvedTextBottom
 import androidx.wear.compose.material3.samples.CurvedTextTop
 
 val CurvedTextScreen =
-    object : BaselineProfileScreen {
+    object : MacrobenchmarkScreen {
         override val content: @Composable BoxScope.() -> Unit
             get() = {
                 CurvedTextTop()
diff --git a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/DatePickerScreen.kt b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/DatePickerScreen.kt
index 97b1296..a42a4a9 100644
--- a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/DatePickerScreen.kt
+++ b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/DatePickerScreen.kt
@@ -21,10 +21,11 @@
 import androidx.compose.runtime.Composable
 import androidx.wear.compose.material3.DatePicker
 import androidx.wear.compose.material3.DatePickerType
+import androidx.wear.compose.material3.macrobenchmark.common.MacrobenchmarkScreen
 import java.time.LocalDate
 
 val DatePickerScreen =
-    object : BaselineProfileScreen {
+    object : MacrobenchmarkScreen {
         override val content: @Composable BoxScope.() -> Unit
             get() = {
                 if (Build.VERSION.SDK_INT >= 26) {
diff --git a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/EdgeButtonScreen.kt b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/EdgeButtonScreen.kt
index 910bac1..c2dc7ad 100644
--- a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/EdgeButtonScreen.kt
+++ b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/EdgeButtonScreen.kt
@@ -19,11 +19,12 @@
 import androidx.benchmark.macro.MacrobenchmarkScope
 import androidx.compose.foundation.layout.BoxScope
 import androidx.compose.runtime.Composable
+import androidx.wear.compose.material3.macrobenchmark.common.MacrobenchmarkScreen
 import androidx.wear.compose.material3.macrobenchmark.common.scrollDown
 import androidx.wear.compose.material3.samples.EdgeButtonSample
 
 val EdgeButtonScreen =
-    object : BaselineProfileScreen {
+    object : MacrobenchmarkScreen {
         override val content: @Composable BoxScope.() -> Unit
             get() = { EdgeButtonSample() }
 
diff --git a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/IconButtonScreen.kt b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/IconButtonScreen.kt
index 31d35a2..799e267 100644
--- a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/IconButtonScreen.kt
+++ b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/IconButtonScreen.kt
@@ -24,6 +24,7 @@
 import androidx.compose.foundation.verticalScroll
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
+import androidx.wear.compose.material3.macrobenchmark.common.MacrobenchmarkScreen
 import androidx.wear.compose.material3.samples.FilledIconButtonSample
 import androidx.wear.compose.material3.samples.FilledTonalIconButtonSample
 import androidx.wear.compose.material3.samples.FilledVariantIconButtonSample
@@ -34,7 +35,7 @@
 
 @OptIn(ExperimentalLayoutApi::class)
 val IconButtonScreen =
-    object : BaselineProfileScreen {
+    object : MacrobenchmarkScreen {
         override val content: @Composable() (BoxScope.() -> Unit)
             get() = {
                 Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
diff --git a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/IconToggleButtonScreen.kt b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/IconToggleButtonScreen.kt
index 2a170f3..d1b2bb1 100644
--- a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/IconToggleButtonScreen.kt
+++ b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/IconToggleButtonScreen.kt
@@ -36,13 +36,14 @@
 import androidx.wear.compose.material3.IconToggleButton
 import androidx.wear.compose.material3.IconToggleButtonDefaults
 import androidx.wear.compose.material3.macrobenchmark.common.FIND_OBJECT_TIMEOUT_MS
+import androidx.wear.compose.material3.macrobenchmark.common.MacrobenchmarkScreen
 import androidx.wear.compose.material3.macrobenchmark.common.R
 import androidx.wear.compose.material3.samples.IconToggleButtonSample
 import androidx.wear.compose.material3.samples.IconToggleButtonVariantSample
 
 @OptIn(ExperimentalLayoutApi::class)
 val IconToggleButtonScreen =
-    object : BaselineProfileScreen {
+    object : MacrobenchmarkScreen {
         override val content: @Composable (BoxScope.() -> Unit)
             get() = {
                 Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
diff --git a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/ListHeaderScreen.kt b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/ListHeaderScreen.kt
index 0cede8a..21a41e5 100644
--- a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/ListHeaderScreen.kt
+++ b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/ListHeaderScreen.kt
@@ -22,12 +22,13 @@
 import androidx.compose.foundation.verticalScroll
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
+import androidx.wear.compose.material3.macrobenchmark.common.MacrobenchmarkScreen
 import androidx.wear.compose.material3.samples.ListHeaderSample
 import androidx.wear.compose.material3.samples.ListSubHeaderSample
 import androidx.wear.compose.material3.samples.ListSubHeaderWithIconSample
 
 val ListHeaderScreen =
-    object : BaselineProfileScreen {
+    object : MacrobenchmarkScreen {
         override val content: @Composable BoxScope.() -> Unit
             get() = {
                 Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
diff --git a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/OpenOnPhoneDialogScreen.kt b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/OpenOnPhoneDialogScreen.kt
index 1515b55..de4901b 100644
--- a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/OpenOnPhoneDialogScreen.kt
+++ b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/OpenOnPhoneDialogScreen.kt
@@ -35,9 +35,10 @@
 import androidx.wear.compose.material3.FilledTonalButton
 import androidx.wear.compose.material3.OpenOnPhoneDialog
 import androidx.wear.compose.material3.Text
+import androidx.wear.compose.material3.macrobenchmark.common.MacrobenchmarkScreen
 
 val OpenOnPhoneDialogScreen =
-    object : BaselineProfileScreen {
+    object : MacrobenchmarkScreen {
         override val content: @Composable BoxScope.() -> Unit
             get() = {
                 Column {
diff --git a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/PageIndicatorScreen.kt b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/PageIndicatorScreen.kt
index 1c069dc..c7c67f4 100644
--- a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/PageIndicatorScreen.kt
+++ b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/PageIndicatorScreen.kt
@@ -18,10 +18,11 @@
 
 import androidx.compose.foundation.layout.BoxScope
 import androidx.compose.runtime.Composable
+import androidx.wear.compose.material3.macrobenchmark.common.MacrobenchmarkScreen
 import androidx.wear.compose.material3.samples.VerticalPageIndicatorWithPagerSample
 
 val PageIndicatorScreen =
-    object : BaselineProfileScreen {
+    object : MacrobenchmarkScreen {
         override val content: @Composable BoxScope.() -> Unit
             get() = { VerticalPageIndicatorWithPagerSample() }
     }
diff --git a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/PickerGroupScreen.kt b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/PickerGroupScreen.kt
index 037263f..4a31a18 100644
--- a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/PickerGroupScreen.kt
+++ b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/PickerGroupScreen.kt
@@ -18,10 +18,11 @@
 
 import androidx.compose.foundation.layout.BoxScope
 import androidx.compose.runtime.Composable
+import androidx.wear.compose.material3.macrobenchmark.common.MacrobenchmarkScreen
 import androidx.wear.compose.material3.samples.AutoCenteringPickerGroup
 
 val PickerGroupScreen =
-    object : BaselineProfileScreen {
+    object : MacrobenchmarkScreen {
         override val content: @Composable (BoxScope.() -> Unit)
             get() = { AutoCenteringPickerGroup() }
     }
diff --git a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/PickerScreen.kt b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/PickerScreen.kt
index ba68003..3b5c299 100644
--- a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/PickerScreen.kt
+++ b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/PickerScreen.kt
@@ -18,10 +18,11 @@
 
 import androidx.compose.foundation.layout.BoxScope
 import androidx.compose.runtime.Composable
+import androidx.wear.compose.material3.macrobenchmark.common.MacrobenchmarkScreen
 import androidx.wear.compose.material3.samples.PickerScrollToOption
 
 val PickerScreen =
-    object : BaselineProfileScreen {
+    object : MacrobenchmarkScreen {
         override val content: @Composable BoxScope.() -> Unit
             get() = { PickerScrollToOption() }
     }
diff --git a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/PlaceHolderScreen.kt b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/PlaceHolderScreen.kt
index 1dd1def..5af8a5a 100644
--- a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/PlaceHolderScreen.kt
+++ b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/PlaceHolderScreen.kt
@@ -22,12 +22,13 @@
 import androidx.compose.foundation.verticalScroll
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
+import androidx.wear.compose.material3.macrobenchmark.common.MacrobenchmarkScreen
 import androidx.wear.compose.material3.samples.ButtonWithIconAndLabelAndPlaceholders
 import androidx.wear.compose.material3.samples.ButtonWithIconAndLabelsAndOverlaidPlaceholder
 import androidx.wear.compose.material3.samples.TextPlaceholder
 
 val PlaceHolderScreen =
-    object : BaselineProfileScreen {
+    object : MacrobenchmarkScreen {
         override val content: @Composable BoxScope.() -> Unit
             get() = {
                 Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
diff --git a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/ProgressIndicatorScreen.kt b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/ProgressIndicatorScreen.kt
index 8c3a78b..c9c5b8e 100644
--- a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/ProgressIndicatorScreen.kt
+++ b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/ProgressIndicatorScreen.kt
@@ -18,6 +18,7 @@
 
 import androidx.compose.foundation.layout.BoxScope
 import androidx.compose.runtime.Composable
+import androidx.wear.compose.material3.macrobenchmark.common.MacrobenchmarkScreen
 import androidx.wear.compose.material3.samples.FullScreenProgressIndicatorSample
 import androidx.wear.compose.material3.samples.IndeterminateProgressIndicatorSample
 import androidx.wear.compose.material3.samples.MediaButtonProgressIndicatorSample
@@ -28,7 +29,7 @@
 import androidx.wear.compose.material3.samples.SmallValuesProgressIndicatorSample
 
 val ProgressIndicatorScreen =
-    object : BaselineProfileScreen {
+    object : MacrobenchmarkScreen {
         override val content: @Composable BoxScope.() -> Unit
             get() = {
                 FullScreenProgressIndicatorSample()
diff --git a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/RadioButtonScreen.kt b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/RadioButtonScreen.kt
index db6b300..bff77db 100644
--- a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/RadioButtonScreen.kt
+++ b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/RadioButtonScreen.kt
@@ -22,11 +22,12 @@
 import androidx.compose.foundation.verticalScroll
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
+import androidx.wear.compose.material3.macrobenchmark.common.MacrobenchmarkScreen
 import androidx.wear.compose.material3.samples.RadioButtonSample
 import androidx.wear.compose.material3.samples.SplitRadioButtonSample
 
 val RadioButtonScreen =
-    object : BaselineProfileScreen {
+    object : MacrobenchmarkScreen {
         override val content: @Composable BoxScope.() -> Unit
             get() = {
                 Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
diff --git a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/ScaffoldScreen.kt b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/ScaffoldScreen.kt
index 8a63b05..462a87f 100644
--- a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/ScaffoldScreen.kt
+++ b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/ScaffoldScreen.kt
@@ -18,10 +18,11 @@
 
 import androidx.compose.foundation.layout.BoxScope
 import androidx.compose.runtime.Composable
+import androidx.wear.compose.material3.macrobenchmark.common.MacrobenchmarkScreen
 import androidx.wear.compose.material3.samples.ScaffoldSample
 
 val ScaffoldScreen =
-    object : BaselineProfileScreen {
+    object : MacrobenchmarkScreen {
 
         override val content: @Composable BoxScope.() -> Unit
             get() = { ScaffoldSample() }
diff --git a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/ScrollIndicatorScreen.kt b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/ScrollIndicatorScreen.kt
index 3929d0e..088a27d 100644
--- a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/ScrollIndicatorScreen.kt
+++ b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/ScrollIndicatorScreen.kt
@@ -18,10 +18,11 @@
 
 import androidx.compose.foundation.layout.BoxScope
 import androidx.compose.runtime.Composable
+import androidx.wear.compose.material3.macrobenchmark.common.MacrobenchmarkScreen
 import androidx.wear.compose.material3.samples.ScrollIndicatorWithColumnSample
 
 val ScrollIndicatorScreen =
-    object : BaselineProfileScreen {
+    object : MacrobenchmarkScreen {
         override val content: @Composable BoxScope.() -> Unit
             get() = { ScrollIndicatorWithColumnSample() }
     }
diff --git a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/SliderScreen.kt b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/SliderScreen.kt
index 5d133de..c622a31 100644
--- a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/SliderScreen.kt
+++ b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/SliderScreen.kt
@@ -23,6 +23,7 @@
 import androidx.compose.foundation.verticalScroll
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
+import androidx.wear.compose.material3.macrobenchmark.common.MacrobenchmarkScreen
 import androidx.wear.compose.material3.macrobenchmark.common.scrollDown
 import androidx.wear.compose.material3.samples.ChangedSliderSample
 import androidx.wear.compose.material3.samples.SliderSample
@@ -30,7 +31,7 @@
 import androidx.wear.compose.material3.samples.SliderWithIntegerSample
 
 val SliderScreen =
-    object : BaselineProfileScreen {
+    object : MacrobenchmarkScreen {
         override val content: @Composable BoxScope.() -> Unit
             get() = {
                 Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
diff --git a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/StepperScreen.kt b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/StepperScreen.kt
index b262e91..6c89908 100644
--- a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/StepperScreen.kt
+++ b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/StepperScreen.kt
@@ -18,10 +18,11 @@
 
 import androidx.compose.foundation.layout.BoxScope
 import androidx.compose.runtime.Composable
+import androidx.wear.compose.material3.macrobenchmark.common.MacrobenchmarkScreen
 import androidx.wear.compose.material3.samples.StepperWithButtonSample
 
 val StepperScreen =
-    object : BaselineProfileScreen {
+    object : MacrobenchmarkScreen {
         override val content: @Composable BoxScope.() -> Unit
             get() = { StepperWithButtonSample() }
     }
diff --git a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/SwipeToDismissScreen.kt b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/SwipeToDismissScreen.kt
index 80fe730..482604e 100644
--- a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/SwipeToDismissScreen.kt
+++ b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/SwipeToDismissScreen.kt
@@ -18,10 +18,11 @@
 
 import androidx.compose.foundation.layout.BoxScope
 import androidx.compose.runtime.Composable
+import androidx.wear.compose.material3.macrobenchmark.common.MacrobenchmarkScreen
 import androidx.wear.compose.material3.samples.StatefulSwipeToDismissBox
 
 val SwipeToDismissScreen =
-    object : BaselineProfileScreen {
+    object : MacrobenchmarkScreen {
         override val content: @Composable BoxScope.() -> Unit
             get() = { StatefulSwipeToDismissBox() }
     }
diff --git a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/SwipeToRevealScreen.kt b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/SwipeToRevealScreen.kt
index 7356bc9..a940608 100644
--- a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/SwipeToRevealScreen.kt
+++ b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/SwipeToRevealScreen.kt
@@ -18,10 +18,11 @@
 
 import androidx.compose.foundation.layout.BoxScope
 import androidx.compose.runtime.Composable
+import androidx.wear.compose.material3.macrobenchmark.common.MacrobenchmarkScreen
 import androidx.wear.compose.material3.samples.SwipeToRevealSample
 
 val SwipeToRevealScreen =
-    object : BaselineProfileScreen {
+    object : MacrobenchmarkScreen {
         override val content: @Composable BoxScope.() -> Unit
             get() = { SwipeToRevealSample() }
     }
diff --git a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/SwitchButtonScreen.kt b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/SwitchButtonScreen.kt
index e9e98188..2e70194 100644
--- a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/SwitchButtonScreen.kt
+++ b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/SwitchButtonScreen.kt
@@ -22,11 +22,12 @@
 import androidx.compose.foundation.verticalScroll
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
+import androidx.wear.compose.material3.macrobenchmark.common.MacrobenchmarkScreen
 import androidx.wear.compose.material3.samples.SplitSwitchButtonSample
 import androidx.wear.compose.material3.samples.SwitchButtonSample
 
 val SwitchButtonScreen =
-    object : BaselineProfileScreen {
+    object : MacrobenchmarkScreen {
         override val content: @Composable BoxScope.() -> Unit
             get() = {
                 Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
diff --git a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/TextButtonScreen.kt b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/TextButtonScreen.kt
index b9b82e7..e1d202e 100644
--- a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/TextButtonScreen.kt
+++ b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/TextButtonScreen.kt
@@ -24,6 +24,7 @@
 import androidx.compose.foundation.verticalScroll
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
+import androidx.wear.compose.material3.macrobenchmark.common.MacrobenchmarkScreen
 import androidx.wear.compose.material3.samples.FilledTextButtonSample
 import androidx.wear.compose.material3.samples.FilledTonalTextButtonSample
 import androidx.wear.compose.material3.samples.FilledVariantTextButtonSample
@@ -34,7 +35,7 @@
 
 @OptIn(ExperimentalLayoutApi::class)
 val TextButtonScreen =
-    object : BaselineProfileScreen {
+    object : MacrobenchmarkScreen {
         override val content: @Composable (BoxScope.() -> Unit)
             get() = {
                 Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
diff --git a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/TextToggleButtonScreen.kt b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/TextToggleButtonScreen.kt
index 72a2aa4..833143d 100644
--- a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/TextToggleButtonScreen.kt
+++ b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/TextToggleButtonScreen.kt
@@ -35,12 +35,13 @@
 import androidx.wear.compose.material3.TextToggleButton
 import androidx.wear.compose.material3.TextToggleButtonDefaults
 import androidx.wear.compose.material3.macrobenchmark.common.FIND_OBJECT_TIMEOUT_MS
+import androidx.wear.compose.material3.macrobenchmark.common.MacrobenchmarkScreen
 import androidx.wear.compose.material3.samples.LargeTextToggleButtonSample
 import androidx.wear.compose.material3.samples.TextToggleButtonSample
 
 @OptIn(ExperimentalLayoutApi::class)
 val TextToggleButtonScreen =
-    object : BaselineProfileScreen {
+    object : MacrobenchmarkScreen {
         override val content: @Composable (BoxScope.() -> Unit)
             get() = {
                 Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
diff --git a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/TimePickerScreen.kt b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/TimePickerScreen.kt
index 8022686..f506e50 100644
--- a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/TimePickerScreen.kt
+++ b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/TimePickerScreen.kt
@@ -18,10 +18,11 @@
 
 import androidx.compose.foundation.layout.BoxScope
 import androidx.compose.runtime.Composable
+import androidx.wear.compose.material3.macrobenchmark.common.MacrobenchmarkScreen
 import androidx.wear.compose.material3.samples.TimePickerSample
 
 val TimePickerScreen =
-    object : BaselineProfileScreen {
+    object : MacrobenchmarkScreen {
         override val content: @Composable BoxScope.() -> Unit
             get() = { TimePickerSample() }
     }
diff --git a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/TimeTextScreen.kt b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/TimeTextScreen.kt
index e2b5bb9..5565366 100644
--- a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/TimeTextScreen.kt
+++ b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/TimeTextScreen.kt
@@ -18,10 +18,11 @@
 
 import androidx.compose.foundation.layout.BoxScope
 import androidx.compose.runtime.Composable
+import androidx.wear.compose.material3.macrobenchmark.common.MacrobenchmarkScreen
 import androidx.wear.compose.material3.samples.TimeTextWithStatus
 
 val TimeTextScreen =
-    object : BaselineProfileScreen {
+    object : MacrobenchmarkScreen {
         override val content: @Composable BoxScope.() -> Unit
             get() = { TimeTextWithStatus() }
     }
diff --git a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/TransformingLazyColumnScreen.kt b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/TransformingLazyColumnScreen.kt
index ffb08e1..71ba2d3 100644
--- a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/TransformingLazyColumnScreen.kt
+++ b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/baselineprofile/TransformingLazyColumnScreen.kt
@@ -18,10 +18,11 @@
 
 import androidx.compose.foundation.layout.BoxScope
 import androidx.compose.runtime.Composable
+import androidx.wear.compose.material3.macrobenchmark.common.MacrobenchmarkScreen
 import androidx.wear.compose.material3.samples.TransformingLazyColumnScalingMorphingEffectSample
 
 val TransformingLazyColumnScreen =
-    object : BaselineProfileScreen {
+    object : MacrobenchmarkScreen {
         override val content: @Composable BoxScope.() -> Unit
             get() = { TransformingLazyColumnScalingMorphingEffectSample() }
     }
diff --git a/wear/compose/compose-material3/macrobenchmark-target/src/main/AndroidManifest.xml b/wear/compose/compose-material3/macrobenchmark-target/src/main/AndroidManifest.xml
index 40010e2..9e2ee38 100644
--- a/wear/compose/compose-material3/macrobenchmark-target/src/main/AndroidManifest.xml
+++ b/wear/compose/compose-material3/macrobenchmark-target/src/main/AndroidManifest.xml
@@ -43,6 +43,17 @@
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
         </activity>
+
+        <activity
+            android:name=".TransformingLazyColumnActivity"
+            android:theme="@style/AppTheme"
+            android:exported="true">
+            <intent-filter>
+                <action android:name=
+                    "androidx.wear.compose.material3.macrobenchmark.target.TRANSFORMING_LAZY_COLUMN_ACTIVITY" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
     </application>
 
     <uses-permission android:name="android.permission.WAKE_LOCK" />
diff --git a/wear/compose/compose-material3/macrobenchmark-target/src/main/java/androidx/wear/compose/material3/macrobenchmark/target/TransformingLazyColumnActivity.kt b/wear/compose/compose-material3/macrobenchmark-target/src/main/java/androidx/wear/compose/material3/macrobenchmark/target/TransformingLazyColumnActivity.kt
new file mode 100644
index 0000000..7bdd7eb
--- /dev/null
+++ b/wear/compose/compose-material3/macrobenchmark-target/src/main/java/androidx/wear/compose/material3/macrobenchmark/target/TransformingLazyColumnActivity.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2024 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.material3.macrobenchmark.target
+
+import android.os.Bundle
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.wear.compose.material3.MaterialTheme
+import androidx.wear.compose.material3.macrobenchmark.common.TransformingLazyColumnBenchmark
+
+class TransformingLazyColumnActivity : ComponentActivity() {
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContent {
+            MaterialTheme {
+                Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
+                    TransformingLazyColumnBenchmark.content.invoke(this)
+                }
+            }
+        }
+    }
+}
diff --git a/wear/compose/compose-material3/macrobenchmark/src/main/java/androidx/wear/compose/material3/macrobenchmark/BaselineProfile.kt b/wear/compose/compose-material3/macrobenchmark/src/main/java/androidx/wear/compose/material3/macrobenchmark/BaselineProfile.kt
index 168f053..254e765 100644
--- a/wear/compose/compose-material3/macrobenchmark/src/main/java/androidx/wear/compose/material3/macrobenchmark/BaselineProfile.kt
+++ b/wear/compose/compose-material3/macrobenchmark/src/main/java/androidx/wear/compose/material3/macrobenchmark/BaselineProfile.kt
@@ -78,7 +78,6 @@
     }
 
     companion object {
-        private const val PACKAGE_NAME = "androidx.wear.compose.material3.macrobenchmark.target"
         private const val BASELINE_ACTIVITY = "$PACKAGE_NAME.BASELINE_ACTIVITY"
     }
 }
diff --git a/wear/compose/compose-material3/macrobenchmark/src/main/java/androidx/wear/compose/material3/macrobenchmark/Common.kt b/wear/compose/compose-material3/macrobenchmark/src/main/java/androidx/wear/compose/material3/macrobenchmark/Common.kt
new file mode 100644
index 0000000..0a9b71d
--- /dev/null
+++ b/wear/compose/compose-material3/macrobenchmark/src/main/java/androidx/wear/compose/material3/macrobenchmark/Common.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2024 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.material3.macrobenchmark
+
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+
+internal fun disableChargingExperience() {
+    val instrumentation = InstrumentationRegistry.getInstrumentation()
+    val device = UiDevice.getInstance(instrumentation)
+    device.executeShellCommand(
+        "am broadcast -a " +
+            "com.google.android.clockwork.sysui.charging.ENABLE_CHARGING_EXPERIENCE " +
+            "--ez value \"false\" com.google.android.wearable.sysui"
+    )
+}
+
+internal fun enableChargingExperience() {
+    val instrumentation = InstrumentationRegistry.getInstrumentation()
+    val device = UiDevice.getInstance(instrumentation)
+    device.executeShellCommand(
+        "am broadcast -a " +
+            "com.google.android.clockwork.sysui.charging.ENABLE_CHARGING_EXPERIENCE " +
+            "--ez value \"true\" com.google.android.wearable.sysui"
+    )
+}
+
+internal const val PACKAGE_NAME = "androidx.wear.compose.material3.macrobenchmark.target"
diff --git a/wear/compose/compose-material3/macrobenchmark/src/main/java/androidx/wear/compose/material3/macrobenchmark/TransformingLazyColumnBenchmark.kt b/wear/compose/compose-material3/macrobenchmark/src/main/java/androidx/wear/compose/material3/macrobenchmark/TransformingLazyColumnBenchmark.kt
new file mode 100644
index 0000000..1f82ab3
--- /dev/null
+++ b/wear/compose/compose-material3/macrobenchmark/src/main/java/androidx/wear/compose/material3/macrobenchmark/TransformingLazyColumnBenchmark.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2024 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.material3.macrobenchmark
+
+import android.content.Intent
+import androidx.benchmark.macro.CompilationMode
+import androidx.benchmark.macro.FrameTimingMetric
+import androidx.benchmark.macro.junit4.MacrobenchmarkRule
+import androidx.test.filters.LargeTest
+import androidx.testutils.createCompilationParams
+import androidx.wear.compose.material3.macrobenchmark.common.TransformingLazyColumnBenchmark
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+@LargeTest
+@RunWith(Parameterized::class)
+class TransformingLazyColumnBenchmark(private val compilationMode: CompilationMode) {
+    @get:Rule val benchmarkRule = MacrobenchmarkRule()
+
+    @Before
+    fun setUp() {
+        disableChargingExperience()
+    }
+
+    @After
+    fun destroy() {
+        enableChargingExperience()
+    }
+
+    @Test
+    fun start() {
+        benchmarkRule.measureRepeated(
+            packageName = PACKAGE_NAME,
+            metrics = listOf(FrameTimingMetric()),
+            compilationMode = compilationMode,
+            iterations = 10,
+            setupBlock = {
+                val intent = Intent()
+                intent.action = TRANSFORMING_LAZY_COLUMN_ACTIVITY
+                startActivityAndWait(intent)
+            }
+        ) {
+            TransformingLazyColumnBenchmark.exercise.invoke(this)
+        }
+    }
+
+    companion object {
+
+        private const val TRANSFORMING_LAZY_COLUMN_ACTIVITY =
+            "$PACKAGE_NAME.TRANSFORMING_LAZY_COLUMN_ACTIVITY"
+
+        @Parameterized.Parameters(name = "compilation={0}")
+        @JvmStatic
+        fun parameters() = createCompilationParams()
+    }
+}
diff --git a/wear/compose/compose-material3/samples/src/main/java/androidx/wear/compose/material3/samples/PlaceholderSample.kt b/wear/compose/compose-material3/samples/src/main/java/androidx/wear/compose/material3/samples/PlaceholderSample.kt
index fedc367..50aa05f 100644
--- a/wear/compose/compose-material3/samples/src/main/java/androidx/wear/compose/material3/samples/PlaceholderSample.kt
+++ b/wear/compose/compose-material3/samples/src/main/java/androidx/wear/compose/material3/samples/PlaceholderSample.kt
@@ -106,10 +106,8 @@
         delay(1000)
         labelText = "A label"
     }
-    if (!buttonPlaceholderState.isShowContent) {
-        LaunchedEffect(buttonPlaceholderState) {
-            buttonPlaceholderState.startPlaceholderAnimation()
-        }
+    if (!buttonPlaceholderState.isHidden) {
+        LaunchedEffect(buttonPlaceholderState) { buttonPlaceholderState.animatePlaceholder() }
     }
 }
 
@@ -135,7 +133,7 @@
         labelText.isNotEmpty() && secondaryLabelText.isNotEmpty() && imageVector != null
     }
     Box {
-        if (buttonPlaceholderState.isShowContent || buttonPlaceholderState.isWipeOff) {
+        if (buttonPlaceholderState.isHidden || buttonPlaceholderState.isWipingOff) {
             Button(
                 onClick = { /* Do something */ },
                 enabled = true,
@@ -171,7 +169,7 @@
                 modifier = Modifier.fillMaxWidth()
             )
         }
-        if (!buttonPlaceholderState.isShowContent) {
+        if (!buttonPlaceholderState.isHidden) {
             Button(
                 onClick = { /* Do something */ },
                 enabled = true,
@@ -220,10 +218,8 @@
         delay(500)
         labelText = "A label"
     }
-    if (!buttonPlaceholderState.isShowContent) {
-        LaunchedEffect(buttonPlaceholderState) {
-            buttonPlaceholderState.startPlaceholderAnimation()
-        }
+    if (!buttonPlaceholderState.isHidden) {
+        LaunchedEffect(buttonPlaceholderState) { buttonPlaceholderState.animatePlaceholder() }
     }
 }
 
@@ -255,9 +251,7 @@
         delay(3000)
         labelText = "A label"
     }
-    if (!buttonPlaceholderState.isShowContent) {
-        LaunchedEffect(buttonPlaceholderState) {
-            buttonPlaceholderState.startPlaceholderAnimation()
-        }
+    if (!buttonPlaceholderState.isHidden) {
+        LaunchedEffect(buttonPlaceholderState) { buttonPlaceholderState.animatePlaceholder() }
     }
 }
diff --git a/wear/compose/compose-material3/samples/src/main/java/androidx/wear/compose/material3/samples/ProgressIndicatorSample.kt b/wear/compose/compose-material3/samples/src/main/java/androidx/wear/compose/material3/samples/ProgressIndicatorSample.kt
index 8f82fcd2..83573a4 100644
--- a/wear/compose/compose-material3/samples/src/main/java/androidx/wear/compose/material3/samples/ProgressIndicatorSample.kt
+++ b/wear/compose/compose-material3/samples/src/main/java/androidx/wear/compose/material3/samples/ProgressIndicatorSample.kt
@@ -38,6 +38,8 @@
 import androidx.compose.ui.semantics.contentDescription
 import androidx.compose.ui.semantics.semantics
 import androidx.compose.ui.unit.dp
+import androidx.wear.compose.material3.ArcProgressIndicator
+import androidx.wear.compose.material3.ArcProgressIndicatorDefaults
 import androidx.wear.compose.material3.CircularProgressIndicator
 import androidx.wear.compose.material3.CircularProgressIndicatorDefaults
 import androidx.wear.compose.material3.Icon
@@ -161,6 +163,18 @@
 
 @Sampled
 @Composable
+fun IndeterminateProgressArcSample() {
+    Box(modifier = Modifier.fillMaxSize()) {
+        ArcProgressIndicator(
+            modifier =
+                Modifier.align(Alignment.Center)
+                    .size(ArcProgressIndicatorDefaults.recommendedIndeterminateDiameter),
+        )
+    }
+}
+
+@Sampled
+@Composable
 fun SegmentedProgressIndicatorSample() {
     Box(
         modifier =
diff --git a/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/ArcProgressIndicatorScreenshotTest.kt b/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/ArcProgressIndicatorScreenshotTest.kt
new file mode 100644
index 0000000..e31504f
--- /dev/null
+++ b/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/ArcProgressIndicatorScreenshotTest.kt
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2024 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.material3
+
+import android.os.Build
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.BoxScope
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.size
+import androidx.compose.runtime.Composable
+import androidx.compose.testutils.assertAgainstGolden
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.test.captureToImage
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.unit.dp
+import androidx.test.filters.MediumTest
+import androidx.test.filters.SdkSuppress
+import androidx.test.screenshot.AndroidXScreenshotTestRule
+import com.google.testing.junit.testparameterinjector.TestParameter
+import com.google.testing.junit.testparameterinjector.TestParameterInjector
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TestName
+import org.junit.runner.RunWith
+
+@MediumTest
+@RunWith(TestParameterInjector::class)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+class ArcProgressIndicatorScreenshotTest {
+
+    @get:Rule val rule = createComposeRule()
+
+    @get:Rule val screenshotRule = AndroidXScreenshotTestRule(SCREENSHOT_GOLDEN_PATH)
+
+    @get:Rule val testName = TestName()
+
+    @Test
+    fun arc_progress_indicator_starts_empty(@TestParameter screenSize: ScreenSize) {
+        verifyScreenshot(screenSize, 0L) {
+            ArcProgressIndicator(
+                modifier =
+                    Modifier.testTag(TEST_TAG)
+                        .align(Alignment.Center)
+                        .size(ArcProgressIndicatorDefaults.recommendedIndeterminateDiameter),
+            )
+        }
+    }
+
+    @Test
+    fun arc_progress_indicator_500ms(@TestParameter screenSize: ScreenSize) {
+        verifyScreenshot(screenSize, 500L) {
+            ArcProgressIndicator(
+                modifier =
+                    Modifier.testTag(TEST_TAG)
+                        .align(Alignment.Center)
+                        .size(ArcProgressIndicatorDefaults.recommendedIndeterminateDiameter),
+            )
+        }
+    }
+
+    @Test
+    fun arc_progress_indicator_500ms_clockwise(@TestParameter screenSize: ScreenSize) {
+        verifyScreenshot(screenSize, 500L) {
+            ArcProgressIndicator(
+                modifier =
+                    Modifier.testTag(TEST_TAG)
+                        .align(Alignment.Center)
+                        .size(ArcProgressIndicatorDefaults.recommendedIndeterminateDiameter),
+                angularDirection = AngularDirection.Clockwise
+            )
+        }
+    }
+
+    @Test
+    fun arc_progress_indicator_angles(@TestParameter screenSize: ScreenSize) {
+        verifyScreenshot(screenSize, 500L) {
+            ArcProgressIndicator(
+                modifier =
+                    Modifier.testTag(TEST_TAG)
+                        .align(Alignment.Center)
+                        .size(ArcProgressIndicatorDefaults.recommendedIndeterminateDiameter),
+                startAngle = 0f,
+                endAngle = 180f,
+            )
+        }
+    }
+
+    @Test
+    fun arc_progress_indicator_diameter(@TestParameter screenSize: ScreenSize) {
+        verifyScreenshot(screenSize, 500L) {
+            ArcProgressIndicator(
+                modifier =
+                    Modifier.testTag(TEST_TAG).align(Alignment.Center).size(screenSize.size.dp),
+            )
+        }
+    }
+
+    @Test
+    fun arc_progress_indicator_strokewidth() {
+        verifyScreenshot(ScreenSize.LARGE, 500L) {
+            ArcProgressIndicator(
+                modifier =
+                    Modifier.testTag(TEST_TAG)
+                        .align(Alignment.Center)
+                        .size(ArcProgressIndicatorDefaults.recommendedIndeterminateDiameter),
+                strokeWidth = ArcProgressIndicatorDefaults.IndeterminateStrokeWidth * 2
+            )
+        }
+    }
+
+    private fun verifyScreenshot(
+        screenSize: ScreenSize,
+        milliseconds: Long,
+        content: @Composable (BoxScope.() -> Unit)
+    ) {
+        rule.mainClock.autoAdvance = false
+
+        rule.setContentWithTheme(modifier = Modifier.background(Color.Black)) {
+            ScreenConfiguration(screenSize.size) {
+                Box(modifier = Modifier.fillMaxSize()) { content() }
+            }
+        }
+
+        rule.mainClock.advanceTimeBy(milliseconds)
+
+        rule
+            .onNodeWithTag(TEST_TAG)
+            .captureToImage()
+            .assertAgainstGolden(screenshotRule, testName.goldenIdentifier())
+    }
+}
diff --git a/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/ArcProgressIndicatorTest.kt b/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/ArcProgressIndicatorTest.kt
new file mode 100644
index 0000000..ca41d31
--- /dev/null
+++ b/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/ArcProgressIndicatorTest.kt
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2024 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.material3
+
+import android.os.Build
+import androidx.compose.foundation.layout.BoxScope
+import androidx.compose.foundation.layout.size
+import androidx.compose.runtime.Composable
+import androidx.compose.testutils.assertContainsColor
+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.onNodeWithTag
+import androidx.compose.ui.unit.dp
+import androidx.test.filters.SdkSuppress
+import org.junit.Rule
+import org.junit.Test
+
+class ArcProgressIndicatorTest {
+
+    @get:Rule val rule = createComposeRule()
+
+    @Test
+    fun indeterminate_arc_supports_testtag() {
+        setContentWithTheme { ArcProgressIndicator(modifier = Modifier.testTag(TEST_TAG)) }
+
+        rule.onNodeWithTag(TEST_TAG).assertExists()
+    }
+
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+    @Test
+    fun indeterminate_arc_contains_default_indicator_color() {
+        rule.mainClock.autoAdvance = false
+        var expectedColor = Color.Unspecified
+
+        setContentWithTheme {
+            ArcProgressIndicator(
+                modifier = Modifier.size(COMPONENT_SIZE).testTag(TEST_TAG),
+            )
+            expectedColor = MaterialTheme.colorScheme.primary
+        }
+
+        rule.mainClock.advanceTimeBy(250)
+
+        rule.onNodeWithTag(TEST_TAG).captureToImage().assertContainsColor(expectedColor)
+    }
+
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+    @Test
+    fun indeterminate_arc_contains_custom_indicator_color() {
+        rule.mainClock.autoAdvance = false
+        val customColor = Color.Yellow
+
+        setContentWithTheme {
+            ArcProgressIndicator(
+                modifier = Modifier.size(COMPONENT_SIZE).testTag(TEST_TAG),
+                colors = ProgressIndicatorDefaults.colors(indicatorColor = customColor)
+            )
+        }
+
+        rule.mainClock.advanceTimeBy(250)
+
+        rule.onNodeWithTag(TEST_TAG).captureToImage().assertContainsColor(customColor)
+    }
+
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+    @Test
+    fun indeterminate_arc_contains_default_track_color() {
+        rule.mainClock.autoAdvance = false
+        var expectedColor = Color.Unspecified
+
+        setContentWithTheme {
+            ArcProgressIndicator(
+                modifier = Modifier.size(COMPONENT_SIZE).testTag(TEST_TAG),
+            )
+            expectedColor = MaterialTheme.colorScheme.surfaceContainer
+        }
+
+        rule.mainClock.advanceTimeBy(250)
+
+        rule.onNodeWithTag(TEST_TAG).captureToImage().assertContainsColor(expectedColor)
+    }
+
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+    @Test
+    fun indeterminate_arc_contains_custom_track_color() {
+        rule.mainClock.autoAdvance = false
+        val customColor = Color.Yellow
+
+        setContentWithTheme {
+            ArcProgressIndicator(
+                modifier = Modifier.size(COMPONENT_SIZE).testTag(TEST_TAG),
+                colors = ProgressIndicatorDefaults.colors(trackColor = customColor)
+            )
+        }
+
+        rule.mainClock.advanceTimeBy(250)
+
+        rule.onNodeWithTag(TEST_TAG).captureToImage().assertContainsColor(customColor)
+    }
+
+    private fun setContentWithTheme(composable: @Composable BoxScope.() -> Unit) {
+        // Use constant size modifier to limit relative color percentage ranges.
+        rule.setContentWithTheme(modifier = Modifier.size(COMPONENT_SIZE)) {
+            ScreenConfiguration(SCREEN_SIZE_LARGE) { composable() }
+        }
+    }
+}
+
+private val COMPONENT_SIZE = 204.dp
diff --git a/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/IconButtonTest.kt b/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/IconButtonTest.kt
index 5e3ffa6..e13753d 100644
--- a/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/IconButtonTest.kt
+++ b/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/IconButtonTest.kt
@@ -317,6 +317,7 @@
             baseShape,
             pressedShape,
             0.75f,
+            8,
             color = { IconButtonDefaults.filledIconButtonColors().containerColor }
         ) { modifier ->
             FilledIconButton(
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 6c5c90e..cee8cc6 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
@@ -23,10 +23,13 @@
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
 import androidx.compose.testutils.assertContainsColor
 import androidx.compose.testutils.assertShape
 import androidx.compose.ui.Modifier
@@ -621,6 +624,90 @@
     }
 
     @RequiresApi(Build.VERSION_CODES.O)
+    @Test
+    fun animates_corners_to_75_percent_on_click() {
+        val uncheckedShape = RoundedCornerShape(20.dp)
+        val checkedShape = RoundedCornerShape(10.dp)
+        val pressedShape = RoundedCornerShape(0.dp)
+        // Ignore the color transition from unchecked to checked color
+        val colors =
+            IconToggleButtonColors(
+                Color.Black,
+                Color.Black,
+                Color.Black,
+                Color.Black,
+                Color.Black,
+                Color.Black,
+                Color.Black,
+                Color.Black
+            )
+
+        rule.verifyRoundedButtonTapAnimationEnd(
+            uncheckedShape,
+            pressedShape,
+            0.75f,
+            8,
+            color = { colors.checkedContainerColor }
+        ) { modifier ->
+            IconToggleButton(
+                checked = false,
+                onCheckedChange = {},
+                modifier = modifier,
+                shapes = IconToggleButtonShapes(uncheckedShape, checkedShape, pressedShape),
+                colors = colors
+            ) {}
+        }
+    }
+
+    @RequiresApi(Build.VERSION_CODES.O)
+    @Test
+    fun changes_unchecked_to_checked_shape_on_click() {
+        val uncheckedShape = RoundedCornerShape(20.dp)
+        val checkedShape = RoundedCornerShape(10.dp)
+        val pressedShape = RoundedCornerShape(0.dp)
+        rule.verifyRoundedButtonTapAnimationEnd(
+            uncheckedShape,
+            checkedShape,
+            1f,
+            100,
+            color = { IconToggleButtonDefaults.iconToggleButtonColors().checkedContainerColor },
+            antiAliasingGap = 4f,
+        ) { modifier ->
+            var checked by remember { mutableStateOf(false) }
+            IconToggleButton(
+                checked = checked,
+                onCheckedChange = { checked = !checked },
+                modifier = modifier,
+                shapes = IconToggleButtonShapes(uncheckedShape, checkedShape, pressedShape)
+            ) {}
+        }
+    }
+
+    @RequiresApi(Build.VERSION_CODES.O)
+    @Test
+    fun changes_checked_to_unchecked_shape_on_click() {
+        val uncheckedShape = RoundedCornerShape(10.dp)
+        val checkedShape = RoundedCornerShape(20.dp)
+        val pressedShape = RoundedCornerShape(0.dp)
+        rule.verifyRoundedButtonTapAnimationEnd(
+            checkedShape,
+            uncheckedShape,
+            1f,
+            100,
+            color = { IconToggleButtonDefaults.iconToggleButtonColors().uncheckedContainerColor },
+            antiAliasingGap = 4f,
+        ) { modifier ->
+            var checked by remember { mutableStateOf(true) }
+            IconToggleButton(
+                checked = checked,
+                onCheckedChange = { checked = !checked },
+                modifier = modifier,
+                shapes = IconToggleButtonShapes(uncheckedShape, checkedShape, pressedShape)
+            ) {}
+        }
+    }
+
+    @RequiresApi(Build.VERSION_CODES.O)
     private fun ComposeContentTestRule.verifyIconToggleButtonColors(
         status: Status,
         checked: Boolean,
diff --git a/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/Material3Test.kt b/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/Material3Test.kt
index f383b29..adb74f9 100644
--- a/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/Material3Test.kt
+++ b/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/Material3Test.kt
@@ -403,7 +403,9 @@
     baseShape: RoundedCornerShape,
     pressedShape: RoundedCornerShape,
     targetProgress: Float,
+    expectedFramesUntilTarget: Int,
     color: @Composable () -> Color,
+    antiAliasingGap: Float = 2f,
     content: @Composable (Modifier) -> Unit
 ) {
     val expectedAnimationEnd =
@@ -426,7 +428,7 @@
      * 2) rule.mainClock.waitUntil expects a condition. However, the shape validations for
      *    ImageBitMap only includes of assets
      */
-    repeat(8) { mainClock.advanceTimeByFrame() }
+    repeat(expectedFramesUntilTarget) { mainClock.advanceTimeByFrame() }
 
     onNodeWithTag(TEST_TAG)
         .captureToImage()
@@ -436,7 +438,7 @@
             verticalPadding = 0.dp,
             shapeColor = fillColor,
             backgroundColor = Color.Transparent,
-            antiAliasingGap = 2.0f,
+            antiAliasingGap = antiAliasingGap,
             shape = expectedAnimationEnd,
         )
 }
diff --git a/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/PlaceholderTest.kt b/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/PlaceholderTest.kt
index 9383e90..3234616 100644
--- a/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/PlaceholderTest.kt
+++ b/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/PlaceholderTest.kt
@@ -57,12 +57,12 @@
         }
 
         // For testing we need to manually manage the frame clock for the placeholder animation
-        placeholderState.initializeTestFrameMillis(PlaceholderStage.ShowContent)
+        placeholderState.initializeTestFrameMillis(PlaceholderStage.HidePlaceholder)
 
         // Advance placeholder clock without changing the content ready and confirm still in
         // ShowPlaceholder
         placeholderState.advanceToNextPlaceholderAnimationLoopAndCheckStage(
-            PlaceholderStage.ShowContent
+            PlaceholderStage.HidePlaceholder
         )
     }
 
@@ -92,7 +92,7 @@
         // Advance the clock by one cycle and check we have moved to ShowContent
         placeholderState.advanceFrameMillisAndCheckState(
             PLACEHOLDER_WIPE_OFF_PROGRESSION_DURATION_MS,
-            PlaceholderStage.ShowContent
+            PlaceholderStage.HidePlaceholder
         )
     }
 
@@ -112,12 +112,12 @@
         }
 
         // For testing we need to manually manage the frame clock for the placeholder animation
-        placeholderState.initializeTestFrameMillis(PlaceholderStage.ShowContent)
+        placeholderState.initializeTestFrameMillis(PlaceholderStage.HidePlaceholder)
 
         // Advance placeholder clock without changing the content ready and confirm still in
         // ShowPlaceholder
         placeholderState.advanceToNextPlaceholderAnimationLoopAndCheckStage(
-            PlaceholderStage.ShowContent
+            PlaceholderStage.HidePlaceholder
         )
 
         contentReady.value = false
@@ -182,7 +182,7 @@
         // Advance the clock by one cycle and check we have moved to ShowContent
         placeholderState.advanceFrameMillisAndCheckState(
             PLACEHOLDER_WIPE_OFF_PROGRESSION_DURATION_MS,
-            PlaceholderStage.ShowContent
+            PlaceholderStage.HidePlaceholder
         )
 
         rule.onNodeWithTag(TEST_TAG).captureToImage().assertContainsColor(expectedBackgroundColor)
@@ -240,7 +240,7 @@
         // Advance the clock by one cycle and check we have moved to ShowContent
         placeholderState.advanceFrameMillisAndCheckState(
             PLACEHOLDER_WIPE_OFF_PROGRESSION_DURATION_MS,
-            PlaceholderStage.ShowContent
+            PlaceholderStage.HidePlaceholder
         )
 
         // Check that the shimmer is no longer visible
@@ -317,7 +317,7 @@
         // Now move the end of the wipe-off and confirm that the proper button background is visible
         placeholderState.advanceFrameMillisAndCheckState(
             PLACEHOLDER_WIPE_OFF_PROGRESSION_DURATION_MS,
-            PlaceholderStage.ShowContent
+            PlaceholderStage.HidePlaceholder
         )
 
         // Check that normal button background is now visible
@@ -338,7 +338,7 @@
                     placeholderState = placeholderState,
                 ),
         )
-        LaunchedEffect(placeholderState) { placeholderState.startPlaceholderAnimation() }
+        LaunchedEffect(placeholderState) { placeholderState.animatePlaceholder() }
     }
 
     @Test
@@ -366,7 +366,7 @@
 
         placeholderState.value?.advanceFrameMillisAndCheckState(
             PLACEHOLDER_WIPE_OFF_PROGRESSION_DURATION_MS,
-            PlaceholderStage.ShowContent
+            PlaceholderStage.HidePlaceholder
         )
     }
 
@@ -392,7 +392,7 @@
                         placeholderState = placeholderState,
                     ),
             )
-            LaunchedEffect(placeholderState) { placeholderState.startPlaceholderAnimation() }
+            LaunchedEffect(placeholderState) { placeholderState.animatePlaceholder() }
         }
 
         placeholderState.initializeTestFrameMillis()
@@ -408,7 +408,7 @@
 
         placeholderState.advanceFrameMillisAndCheckState(
             PLACEHOLDER_WIPE_OFF_PROGRESSION_DURATION_MS,
-            PlaceholderStage.ShowContent
+            PlaceholderStage.HidePlaceholder
         )
 
         // Check the placeholder background has gone and that we can see the buttons background
diff --git a/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/TextButtonTest.kt b/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/TextButtonTest.kt
index 202c8b9..3a64620 100644
--- a/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/TextButtonTest.kt
+++ b/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/TextButtonTest.kt
@@ -536,6 +536,7 @@
             baseShape,
             pressedShape,
             0.75f,
+            8,
             color = { TextButtonDefaults.filledTextButtonColors().containerColor }
         ) { modifier ->
             TextButton(
diff --git a/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/TextToggleButtonTest.kt b/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/TextToggleButtonTest.kt
index 1455f333..2b3d35e 100644
--- a/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/TextToggleButtonTest.kt
+++ b/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/TextToggleButtonTest.kt
@@ -23,10 +23,13 @@
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
 import androidx.compose.testutils.assertContainsColor
 import androidx.compose.testutils.assertShape
 import androidx.compose.ui.Modifier
@@ -604,6 +607,90 @@
             .assert(SemanticsMatcher.expectValue(SemanticsProperties.Role, overrideRole))
     }
 
+    @RequiresApi(Build.VERSION_CODES.O)
+    @Test
+    fun animates_corners_to_75_percent_on_click() {
+        val uncheckedShape = RoundedCornerShape(20.dp)
+        val checkedShape = RoundedCornerShape(10.dp)
+        val pressedShape = RoundedCornerShape(0.dp)
+        // Ignore the color transition from unchecked to checked color
+        val colors =
+            TextToggleButtonColors(
+                Color.Black,
+                Color.Black,
+                Color.Black,
+                Color.Black,
+                Color.Black,
+                Color.Black,
+                Color.Black,
+                Color.Black
+            )
+
+        rule.verifyRoundedButtonTapAnimationEnd(
+            uncheckedShape,
+            pressedShape,
+            0.75f,
+            8,
+            color = { colors.checkedContainerColor }
+        ) { modifier ->
+            TextToggleButton(
+                checked = false,
+                onCheckedChange = {},
+                modifier = modifier,
+                shapes = TextToggleButtonShapes(uncheckedShape, checkedShape, pressedShape),
+                colors = colors
+            ) {}
+        }
+    }
+
+    @RequiresApi(Build.VERSION_CODES.O)
+    @Test
+    fun changes_unchecked_to_checked_shape_on_click() {
+        val uncheckedShape = RoundedCornerShape(20.dp)
+        val checkedShape = RoundedCornerShape(10.dp)
+        val pressedShape = RoundedCornerShape(0.dp)
+        rule.verifyRoundedButtonTapAnimationEnd(
+            uncheckedShape,
+            checkedShape,
+            1f,
+            100,
+            color = { TextToggleButtonDefaults.textToggleButtonColors().checkedContainerColor },
+            antiAliasingGap = 4f,
+        ) { modifier ->
+            var checked by remember { mutableStateOf(false) }
+            TextToggleButton(
+                checked = checked,
+                onCheckedChange = { checked = !checked },
+                modifier = modifier,
+                shapes = TextToggleButtonShapes(uncheckedShape, checkedShape, pressedShape)
+            ) {}
+        }
+    }
+
+    @RequiresApi(Build.VERSION_CODES.O)
+    @Test
+    fun changes_checked_to_unchecked_shape_on_click() {
+        val uncheckedShape = RoundedCornerShape(10.dp)
+        val checkedShape = RoundedCornerShape(20.dp)
+        val pressedShape = RoundedCornerShape(0.dp)
+        rule.verifyRoundedButtonTapAnimationEnd(
+            checkedShape,
+            uncheckedShape,
+            1f,
+            100,
+            color = { TextToggleButtonDefaults.textToggleButtonColors().uncheckedContainerColor },
+            antiAliasingGap = 4f,
+        ) { modifier ->
+            var checked by remember { mutableStateOf(true) }
+            TextToggleButton(
+                checked = checked,
+                onCheckedChange = { checked = !checked },
+                modifier = modifier,
+                shapes = TextToggleButtonShapes(uncheckedShape, checkedShape, pressedShape)
+            ) {}
+        }
+    }
+
     @Composable
     private fun shapeColor(): Color {
         return TextToggleButtonDefaults.textToggleButtonColors()
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/AnimatedToggleRoundedCornerShape.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/AnimatedToggleRoundedCornerShape.kt
index f660f8f..a4a8ebc 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/AnimatedToggleRoundedCornerShape.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/AnimatedToggleRoundedCornerShape.kt
@@ -16,49 +16,53 @@
 
 package androidx.wear.compose.material3
 
+import androidx.compose.animation.core.Animatable
 import androidx.compose.animation.core.FiniteAnimationSpec
-import androidx.compose.animation.core.animateFloat
-import androidx.compose.animation.core.updateTransition
 import androidx.compose.foundation.shape.CornerSize
-import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.MutableState
+import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.Stable
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.ui.geometry.RoundRect
 import androidx.compose.ui.geometry.Size
 import androidx.compose.ui.geometry.toRect
 import androidx.compose.ui.graphics.Outline
 import androidx.compose.ui.graphics.Shape
-import androidx.compose.ui.platform.LocalDensity
 import androidx.compose.ui.unit.Density
 import androidx.compose.ui.unit.LayoutDirection
+import kotlinx.coroutines.launch
 
 /**
- * A animated [RoundedCornerShape]. Animation is driven by changes to the [cornerSize] lambda.
- * [currentShapeSize] is provided as Size is received here, but must affect the animation.
+ * An implementation similar to RoundedCornerShape, but based on linear interpolation between a
+ * start and stop CornerSize, and an observable progress between 0.0 and 1.0.
  *
- * @param currentShapeSize MutableState coordinating the current size.
- * @param cornerSize a lambda resolving to the current Corner size.
+ * @param startCornerSize the corner size when progress is 0.0
+ * @param endCornerSize the corner size when progress is 1.0
+ * @param progress returns the current progress from start to stop.
  */
 @Stable
-internal class AnimatedToggleRoundedCornerShape(
-    private val currentShapeSize: MutableState<Size?>,
-    private val cornerSize: () -> CornerSize,
+private class AnimatedToggleRoundedCornerShape(
+    var startCornerSize: CornerSize,
+    var endCornerSize: CornerSize,
+    var progress: () -> Float,
 ) : Shape {
     override fun createOutline(
         size: Size,
         layoutDirection: LayoutDirection,
         density: Density,
     ): Outline {
-        val cornerRadius = cornerSize().toPx(size, density)
-
-        currentShapeSize.value = size
+        val animatedCornerSize = AnimatedCornerSize(startCornerSize, endCornerSize, progress)
+        val animatedCornerSizePx = animatedCornerSize.toPx(size, density)
 
         return Outline.Rounded(
             roundRect =
-                RoundRect(rect = size.toRect(), radiusX = cornerRadius, radiusY = cornerRadius)
+                RoundRect(
+                    rect = size.toRect(),
+                    radiusX = animatedCornerSizePx,
+                    radiusY = animatedCornerSizePx
+                )
         )
     }
 }
@@ -84,49 +88,41 @@
             else -> ToggleState.Unchecked
         }
 
-    val transition = updateTransition(toggleState, label = "Toggle State")
-    val density = LocalDensity.current
+    val previous = remember { mutableStateOf(toggleState) }
+    val scope = rememberCoroutineScope()
+    val progress = remember { Animatable(1f) }
 
-    val currentShapeSize = remember { mutableStateOf<Size?>(null) }
+    val toggledCornerSize =
+        toggleState.cornerSize(uncheckedCornerSize, checkedCornerSize, pressedCornerSize)
+    val animationSpec = if (pressed) onPressAnimationSpec else onReleaseAnimationSpec
 
-    val observedSize = currentShapeSize.value
+    val animatedShape = remember {
+        AnimatedToggleRoundedCornerShape(
+            startCornerSize = toggledCornerSize,
+            endCornerSize = toggledCornerSize,
+            progress = { progress.value },
+        )
+    }
 
-    if (observedSize != null) {
-        val sizePx =
-            transition.animateFloat(
-                label = "Corner Size",
-                transitionSpec = {
-                    when {
-                        targetState isTransitioningTo ToggleState.Pressed -> onPressAnimationSpec
-                        else -> onReleaseAnimationSpec
-                    }
-                },
-            ) { newState ->
-                newState
-                    .cornerSize(uncheckedCornerSize, checkedCornerSize, pressedCornerSize)
-                    .toPx(observedSize, density)
-            }
-
-        return remember(sizePx) {
-            AnimatedToggleRoundedCornerShape(
-                currentShapeSize = currentShapeSize,
-            ) {
-                CornerSize(sizePx.value)
-            }
+    LaunchedEffect(toggleState) {
+        // Allow the press up animation to finish its minimum duration before starting the next
+        if (!pressed) {
+            waitUntil { !progress.isRunning || progress.value > MIN_REQUIRED_ANIMATION_PROGRESS }
         }
-    } else {
-        return remember(toggleState, uncheckedCornerSize, checkedCornerSize, pressedCornerSize) {
-            AnimatedToggleRoundedCornerShape(
-                currentShapeSize = currentShapeSize,
-            ) {
-                toggleState.cornerSize(
-                    uncheckedCornerSize,
-                    checkedCornerSize,
-                    pressedCornerSize,
-                )
+
+        if (toggleState != previous.value) {
+            animatedShape.startCornerSize = animatedShape.endCornerSize
+            animatedShape.endCornerSize = toggledCornerSize
+            previous.value = toggleState
+
+            scope.launch {
+                progress.snapTo(1f - progress.value)
+                progress.animateTo(1f, animationSpec = animationSpec)
             }
         }
     }
+
+    return animatedShape
 }
 
 private fun ToggleState.cornerSize(
@@ -145,3 +141,5 @@
     Checked,
     Pressed,
 }
+
+private const val MIN_REQUIRED_ANIMATION_PROGRESS = 0.75f
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/AnimationSpecUtils.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/AnimationSpecUtils.kt
index 11dbdef..f28dd95 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/AnimationSpecUtils.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/AnimationSpecUtils.kt
@@ -26,6 +26,7 @@
 import androidx.compose.animation.core.SpringSpec
 import androidx.compose.animation.core.TwoWayConverter
 import androidx.compose.animation.core.VectorizedAnimationSpec
+import androidx.compose.runtime.withFrameMillis
 
 /**
  * Returns a new [AnimationSpec] that is a faster version of this one.
@@ -129,3 +130,14 @@
     }
         as T
 }
+
+internal suspend fun waitUntil(condition: () -> Boolean) {
+    val initialTimeMillis = withFrameMillis { it }
+    while (!condition()) {
+        val timeMillis = withFrameMillis { it }
+        if (timeMillis - initialTimeMillis > MAX_WAIT_TIME_MILLIS) return
+    }
+    return
+}
+
+private const val MAX_WAIT_TIME_MILLIS = 1_000L
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/ArcProgressIndicator.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/ArcProgressIndicator.kt
new file mode 100644
index 0000000..d38aad2
--- /dev/null
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/ArcProgressIndicator.kt
@@ -0,0 +1,222 @@
+/*
+ * Copyright 2024 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.material3
+
+import androidx.compose.animation.core.CubicBezierEasing
+import androidx.compose.animation.core.animateFloat
+import androidx.compose.animation.core.infiniteRepeatable
+import androidx.compose.animation.core.keyframes
+import androidx.compose.animation.core.rememberInfiniteTransition
+import androidx.compose.foundation.Canvas
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.StrokeCap
+import androidx.compose.ui.graphics.drawscope.Stroke
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+import androidx.wear.compose.materialcore.screenHeightDp
+import kotlin.math.PI
+import kotlin.math.asin
+
+/**
+ * Indeterminate Material Design arc progress indicator.
+ *
+ * Indeterminate progress indicator expresses an unspecified wait time and animates indefinitely.
+ * This overload provides a variation over the usual circular spinner by allowing the start and end
+ * angles to be specified.
+ *
+ * Example of indeterminate arc progress indicator:
+ *
+ * @sample androidx.wear.compose.material3.samples.IndeterminateProgressArcSample
+ * @param startAngle the start angle of this progress indicator arc (specified in degrees). It is
+ *   recommended to use [ArcProgressIndicatorDefaults.IndeterminateStartAngle]. Measured clockwise
+ *   from the three o'clock position.
+ * @param endAngle the end angle of this progress indicator arc (specified in degrees). It is
+ *   recommended to use [ArcProgressIndicatorDefaults.IndeterminateEndAngle]. Measured clockwise
+ *   from the three o'clock position.
+ * @param modifier Modifier to be applied to the ArcProgressIndicator.
+ * @param angularDirection Determines whether the animation is in the clockwise or counter-clockwise
+ *   direction.
+ * @param colors [ProgressIndicatorColors] that will be used to resolve the indicator and track
+ *   color for this progress indicator.
+ * @param strokeWidth The stroke width for the progress indicator. The recommended value is
+ *   [ArcProgressIndicatorDefaults.IndeterminateStrokeWidth].
+ * @param gapSize The size (in Dp) of the gap between the ends of the progress indicator and the
+ *   track. The stroke end caps are not included in this distance.
+ */
+@Composable
+fun ArcProgressIndicator(
+    startAngle: Float = ArcProgressIndicatorDefaults.IndeterminateStartAngle,
+    endAngle: Float = ArcProgressIndicatorDefaults.IndeterminateEndAngle,
+    modifier: Modifier = Modifier,
+    angularDirection: AngularDirection = AngularDirection.CounterClockwise,
+    colors: ProgressIndicatorColors = ProgressIndicatorDefaults.colors(),
+    strokeWidth: Dp = ArcProgressIndicatorDefaults.IndeterminateStrokeWidth,
+    gapSize: Dp = ArcProgressIndicatorDefaults.calculateRecommendedGapSize(strokeWidth),
+) {
+    val infiniteTransition = rememberInfiniteTransition()
+    val head =
+        infiniteTransition.animateFloat(
+            initialValue = 0f,
+            targetValue = 1f,
+            animationSpec = arcIndeterminateHeadAnimationSpec
+        )
+    val tail =
+        infiniteTransition.animateFloat(
+            initialValue = 0f,
+            targetValue = 1f,
+            animationSpec = arcIndeterminateTailAnimationSpec
+        )
+
+    val strokeWidthPx = with(LocalDensity.current) { strokeWidth.toPx() }
+    val stroke = Stroke(width = strokeWidthPx, cap = StrokeCap.Round)
+    val adjustedGapSize = gapSize + strokeWidth
+    val fullSweep = ((endAngle - startAngle) % 360 + 360) % 360
+
+    Canvas(modifier) {
+        val gapSizeSweep = asin(adjustedGapSize.toPx() / size.width) * 360f / PI.toFloat()
+
+        // Track before arc
+        val beforeTrackSweep =
+            if (tail.value >= 0.999f) (1 - head.value) * fullSweep
+            else (1 - head.value) * fullSweep - gapSizeSweep
+        if (beforeTrackSweep > 0) {
+            drawCircularIndicator(
+                startAngle =
+                    if (angularDirection == AngularDirection.CounterClockwise) startAngle
+                    else endAngle,
+                sweep =
+                    if (angularDirection == AngularDirection.CounterClockwise) beforeTrackSweep
+                    else -beforeTrackSweep,
+                colors.trackBrush,
+                stroke = stroke
+            )
+        }
+
+        // Arc
+        val arcStart =
+            if (angularDirection == AngularDirection.CounterClockwise)
+                endAngle - tail.value * fullSweep
+            else startAngle + tail.value * fullSweep
+        val arcSweep =
+            if (angularDirection == AngularDirection.CounterClockwise)
+                (tail.value - head.value) * fullSweep
+            else (head.value - tail.value) * fullSweep
+        drawCircularIndicator(
+            startAngle = arcStart,
+            sweep = arcSweep,
+            colors.indicatorBrush,
+            stroke = stroke
+        )
+
+        // Track after arc
+        val afterTrackSweep =
+            if (tail.value >= 0.999f) tail.value * fullSweep
+            else tail.value * fullSweep - gapSizeSweep
+        if (afterTrackSweep > 0) {
+            drawCircularIndicator(
+                startAngle =
+                    if (angularDirection == AngularDirection.CounterClockwise) endAngle
+                    else startAngle,
+                sweep =
+                    if (angularDirection == AngularDirection.CounterClockwise) -afterTrackSweep
+                    else afterTrackSweep,
+                colors.trackBrush,
+                stroke = stroke
+            )
+        }
+    }
+}
+
+/** Contains default values for [ArcProgressIndicator]. */
+object ArcProgressIndicatorDefaults {
+    /** The default start angle in degrees for an indeterminate arc progress indicator */
+    const val IndeterminateStartAngle = 62f
+
+    /** The default end angle in degrees for an indeterminate arc progress indicator */
+    const val IndeterminateEndAngle = 118f
+
+    /** Stroke width of the indeterminate arc progress indicator. */
+    val IndeterminateStrokeWidth = 8.dp
+
+    /**
+     * The recommended diameter of the indeterminate arc progress indicator, which leaves room for
+     * additional content such as a message above the indicator.
+     */
+    val recommendedIndeterminateDiameter: Dp
+        @Composable
+        get() {
+            // Calculate the recommended diameter as 76% of screen height.
+            val screenHeight = screenHeightDp()
+            return 0.76.dp * screenHeight.toFloat()
+        }
+
+    /**
+     * Returns recommended size of the gap based on `strokeWidth`.
+     *
+     * The absolute value can be customized with `gapSize` parameter on [CircularProgressIndicator].
+     */
+    fun calculateRecommendedGapSize(strokeWidth: Dp): Dp = strokeWidth / 3f
+}
+
+/** Class to define angular direction - Clockwise and Counter Clockwise. */
+@JvmInline
+value class AngularDirection internal constructor(internal val type: Int) {
+    companion object {
+        /** Clockwise is the standard direction for an analog clock. */
+        val Clockwise = AngularDirection(0)
+
+        /** CounterClockwise is the opposite direction to Clockwise */
+        val CounterClockwise = AngularDirection(1)
+    }
+}
+
+/** An animation spec for indeterminate arc progress indicator head position. */
+internal val arcIndeterminateHeadAnimationSpec =
+    infiniteRepeatable(
+        animation =
+            keyframes {
+                durationMillis = TotalArcAnimationDuration
+                0f at HeadDelay using ArcIndeterminateProgressEasing
+                1f at HeadDuration + HeadDelay
+            }
+    )
+
+/** An animation spec for indeterminate arc progress indicator tail position. */
+internal val arcIndeterminateTailAnimationSpec =
+    infiniteRepeatable(
+        animation =
+            keyframes {
+                durationMillis = TotalArcAnimationDuration
+                0f at TailDelay using ArcIndeterminateProgressEasing
+                1f at TailDuration + TailDelay
+            }
+    )
+
+// Total duration for one arc cycle
+internal const val TotalArcAnimationDuration = 2000 // extra-long4 * 2
+
+// Duration of the head and tail animations for the indeterminate arc indicator
+internal const val HeadDuration = 600 // long4
+internal const val TailDuration = 600 // long4
+
+// Delay before the start of the head and tail animations for the indeterminate arc indicator
+internal const val HeadDelay = 0
+internal const val TailDelay = 300 // medium2
+
+internal val ArcIndeterminateProgressEasing = CubicBezierEasing(0.3f, 0f, 0.7f, 1f)
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/CheckboxButton.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/CheckboxButton.kt
index 69996bc..86d0df6 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/CheckboxButton.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/CheckboxButton.kt
@@ -17,8 +17,7 @@
 package androidx.wear.compose.material3
 
 import androidx.compose.animation.core.AnimationSpec
-import androidx.compose.animation.core.TweenSpec
-import androidx.compose.animation.core.tween
+import androidx.compose.animation.core.FiniteAnimationSpec
 import androidx.compose.foundation.background
 import androidx.compose.foundation.clickable
 import androidx.compose.foundation.interaction.Interaction
@@ -63,7 +62,6 @@
 import androidx.compose.ui.text.style.TextOverflow
 import androidx.compose.ui.unit.dp
 import androidx.wear.compose.material3.tokens.CheckboxButtonTokens
-import androidx.wear.compose.material3.tokens.MotionTokens
 import androidx.wear.compose.material3.tokens.ShapeTokens
 import androidx.wear.compose.material3.tokens.SplitCheckboxButtonTokens
 import androidx.wear.compose.materialcore.animateSelectionColor
@@ -1526,7 +1524,7 @@
 private val SPLIT_MIN_WIDTH = 48.dp
 private val SPLIT_SECTIONS_SHAPE = ShapeTokens.CornerExtraSmall
 
-private val COLOR_ANIMATION_SPEC: AnimationSpec<Color> =
-    tween(MotionTokens.DurationMedium1, 0, MotionTokens.EasingStandardDecelerate)
-private val PROGRESS_ANIMATION_SPEC: TweenSpec<Float> =
-    tween(MotionTokens.DurationMedium1, 0, MotionTokens.EasingStandardDecelerate)
+private val COLOR_ANIMATION_SPEC: AnimationSpec<Color>
+    @Composable get() = MaterialTheme.motionScheme.slowEffectsSpec()
+private val PROGRESS_ANIMATION_SPEC: FiniteAnimationSpec<Float>
+    @Composable get() = MaterialTheme.motionScheme.fastEffectsSpec()
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/CircularProgressIndicator.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/CircularProgressIndicator.kt
index ee73aea..4b3f9c4 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/CircularProgressIndicator.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/CircularProgressIndicator.kt
@@ -37,11 +37,7 @@
 import androidx.compose.runtime.snapshotFlow
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.draw.drawWithCache
-import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.geometry.Size
-import androidx.compose.ui.graphics.Brush
 import androidx.compose.ui.graphics.StrokeCap
-import androidx.compose.ui.graphics.drawscope.DrawScope
 import androidx.compose.ui.graphics.drawscope.Stroke
 import androidx.compose.ui.graphics.drawscope.rotate
 import androidx.compose.ui.platform.LocalDensity
@@ -150,7 +146,7 @@
  *
  * Indeterminate progress indicator expresses an unspecified wait time and spins indefinitely.
  *
- * Example of indeterminate progress indicator:
+ * Example of indeterminate circular progress indicator:
  *
  * @sample androidx.wear.compose.material3.samples.IndeterminateProgressIndicatorSample
  * @param modifier Modifier to be applied to the CircularProgressIndicator.
@@ -462,27 +458,6 @@
     val IndeterminateStrokeWidth = 3.dp
 }
 
-private fun DrawScope.drawCircularIndicator(
-    startAngle: Float,
-    sweep: Float,
-    brush: Brush,
-    stroke: Stroke
-) {
-    // To draw this circle we need a rect with edges that line up with the midpoint of the stroke.
-    // To do this we need to remove half the stroke width from the total diameter for both sides.
-    val diameterOffset = stroke.width / 2
-    val arcDimen = size.width - 2 * diameterOffset
-    drawArc(
-        brush = brush,
-        startAngle = startAngle,
-        sweepAngle = sweep,
-        useCenter = false,
-        topLeft = Offset(diameterOffset, diameterOffset),
-        size = Size(arcDimen, arcDimen),
-        style = stroke
-    )
-}
-
 private fun coercedProgressWithGap(progress: Float, isFullCircle: Boolean): Float {
     val coercedProgress = progress.coerceIn(0f, 1f)
     return if (isFullCircle && coercedProgress == 1f) {
@@ -493,57 +468,6 @@
     }
 }
 
-/** A global animation spec for indeterminate circular progress indicator. */
-internal val circularIndeterminateGlobalRotationAnimationSpec
-    get() =
-        infiniteRepeatable<Float>(
-            animation = tween(CircularAnimationProgressDuration, easing = LinearEasing)
-        )
-
-/**
- * An animation spec for indeterminate circular progress indicators that infinitely rotates a 360
- * degrees.
- */
-internal val circularIndeterminateRotationAnimationSpec
-    get() =
-        infiniteRepeatable(
-            animation =
-                keyframes {
-                    durationMillis = CircularAnimationProgressDuration // 6000ms
-                    90f at
-                        CircularAnimationAdditionalRotationDuration using
-                        MotionTokens
-                            .EasingEmphasizedDecelerate // MotionTokens.EasingEmphasizedDecelerateCubicBezier // 300ms
-                    90f at CircularAnimationAdditionalRotationDelay // hold till 1500ms
-                    180f at
-                        CircularAnimationAdditionalRotationDuration +
-                            CircularAnimationAdditionalRotationDelay // 1800ms
-                    180f at CircularAnimationAdditionalRotationDelay * 2 // hold till 3000ms
-                    270f at
-                        CircularAnimationAdditionalRotationDuration +
-                            CircularAnimationAdditionalRotationDelay * 2 // 3300ms
-                    270f at CircularAnimationAdditionalRotationDelay * 3 // hold till 4500ms
-                    360f at
-                        CircularAnimationAdditionalRotationDuration +
-                            CircularAnimationAdditionalRotationDelay * 3 // 4800ms
-                    360f at CircularAnimationProgressDuration // hold till 6000ms
-                }
-        )
-
-/** An animation spec for indeterminate circular progress indicators progress motion. */
-internal val circularIndeterminateProgressAnimationSpec
-    get() =
-        infiniteRepeatable(
-            animation =
-                keyframes {
-                    durationMillis = CircularAnimationProgressDuration // 6000ms
-                    CircularIndeterminateMaxProgress at
-                        CircularAnimationProgressDuration / 2 using
-                        CircularProgressEasing // 3000ms
-                    CircularIndeterminateMinProgress at CircularAnimationProgressDuration
-                }
-        )
-
 // The indeterminate circular indicator easing constants for its motion
 internal val CircularProgressEasing = MotionTokens.EasingStandard
 internal const val CircularIndeterminateMinProgress = 0.1f
@@ -555,5 +479,53 @@
 internal const val CircularAdditionalRotationDegreesTarget = 360f
 internal const val CircularGlobalRotationDegreesTarget = 1080f
 
+/** A global animation spec for indeterminate circular progress indicator. */
+internal val circularIndeterminateGlobalRotationAnimationSpec =
+    infiniteRepeatable<Float>(
+        animation = tween(CircularAnimationProgressDuration, easing = LinearEasing)
+    )
+
+/**
+ * An animation spec for indeterminate circular progress indicators that infinitely rotates a 360
+ * degrees.
+ */
+internal val circularIndeterminateRotationAnimationSpec =
+    infiniteRepeatable(
+        animation =
+            keyframes {
+                durationMillis = CircularAnimationProgressDuration // 6000ms
+                90f at
+                    CircularAnimationAdditionalRotationDuration using
+                    MotionTokens
+                        .EasingEmphasizedDecelerate // MotionTokens.EasingEmphasizedDecelerateCubicBezier // 300ms
+                90f at CircularAnimationAdditionalRotationDelay // hold till 1500ms
+                180f at
+                    CircularAnimationAdditionalRotationDuration +
+                        CircularAnimationAdditionalRotationDelay // 1800ms
+                180f at CircularAnimationAdditionalRotationDelay * 2 // hold till 3000ms
+                270f at
+                    CircularAnimationAdditionalRotationDuration +
+                        CircularAnimationAdditionalRotationDelay * 2 // 3300ms
+                270f at CircularAnimationAdditionalRotationDelay * 3 // hold till 4500ms
+                360f at
+                    CircularAnimationAdditionalRotationDuration +
+                        CircularAnimationAdditionalRotationDelay * 3 // 4800ms
+                360f at CircularAnimationProgressDuration // hold till 6000ms
+            }
+    )
+
+/** An animation spec for indeterminate circular progress indicators progress motion. */
+internal val circularIndeterminateProgressAnimationSpec =
+    infiniteRepeatable(
+        animation =
+            keyframes {
+                durationMillis = CircularAnimationProgressDuration // 6000ms
+                CircularIndeterminateMaxProgress at
+                    CircularAnimationProgressDuration / 2 using
+                    CircularProgressEasing // 3000ms
+                CircularIndeterminateMinProgress at CircularAnimationProgressDuration
+            }
+    )
+
 // extra progress added for the gap merge animation
 internal const val GapExtraProgress = 0.05f
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/Placeholder.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/Placeholder.kt
index 8eef2be..cca2673 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/Placeholder.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/Placeholder.kt
@@ -100,7 +100,7 @@
 @Composable
 fun Modifier.placeholder(
     placeholderState: PlaceholderState,
-    shape: Shape = PlaceholderDefaults.shape,
+    shape: Shape = PlaceholderDefaults.Shape,
     color: Color =
         MaterialTheme.colorScheme.onSurface
             .copy(alpha = 0.1f)
@@ -152,7 +152,7 @@
 @Composable
 fun Modifier.placeholderShimmer(
     placeholderState: PlaceholderState,
-    shape: Shape = PlaceholderDefaults.shape,
+    shape: Shape = PlaceholderDefaults.Shape,
     color: Color = MaterialTheme.colorScheme.onSurface,
 ): Modifier =
     this.then(
@@ -175,8 +175,8 @@
     )
 
 /**
- * Creates a [PlaceholderState] that is remembered across compositions. To start placeholder
- * animations run [PlaceholderState.startPlaceholderAnimation].
+ * Creates a [PlaceholderState] that is remembered across compositions. To animate the placeholder
+ * depending on the state, run [PlaceholderState.animatePlaceholder].
  *
  * A [PlaceholderState] should be created for each component that has placeholder data. The state is
  * used to coordinate all of the different placeholder effects and animations.
@@ -222,15 +222,15 @@
 object PlaceholderDefaults {
 
     /** Default [Shape] for Placeholder. */
-    val shape: Shape = ShapeTokens.CornerFull
+    val Shape: Shape = ShapeTokens.CornerFull
 
     /**
      * Create a [ButtonColors] that can be used in placeholder mode. This will provide the
      * placeholder background effect that covers the normal button background with a solid
      * background of [color] when the [placeholderState] is set to show the placeholder and a wipe
      * off gradient brush when the state is in wipe-off mode. If the state is
-     * [PlaceholderState.isShowContent] then the normal background will be used. All other colors
-     * will be delegated to [originalButtonColors].
+     * [PlaceholderState.isHidden] then the normal background will be used. All other colors will be
+     * delegated to [originalButtonColors].
      *
      * Example of a [Button] with icon and a label that put placeholders over individual content
      * slots and then draws a placeholder shimmer over the result and draws over the [Button]s
@@ -248,7 +248,7 @@
         placeholderState: PlaceholderState,
         color: Color = MaterialTheme.colorScheme.surfaceContainer
     ): ButtonColors {
-        return if (!placeholderState.isShowContent) {
+        return if (!placeholderState.isHidden) {
             ButtonColors(
                 containerPainter =
                     PlaceholderBackgroundPainter(
@@ -318,37 +318,37 @@
 
     /**
      * Create a [Painter] that wraps another painter and overlays a placeholder background brush on
-     * top. If the [placeholderState] is [PlaceholderState.isShowContent] the original painter will
-     * be used. Otherwise the [painter] will be drawn and then a placeholder background will be
+     * top. If the [placeholderState] is [PlaceholderState.isHidden] the original painter will be
+     * used. Otherwise the [originalPainter] will be drawn and then a placeholder background will be
      * drawn over it or a wipe-off brush will be used to reveal the background when the state is
-     * [PlaceholderState.isWipeOff].
+     * [PlaceholderState.isWipingOff].
      *
      * @param placeholderState the state of the placeholder
-     * @param painter the original painter that will be drawn over when in placeholder mode.
+     * @param originalPainter the original painter that will be drawn over when in placeholder mode.
      * @param color the color to use for the placeholder background brush
      */
     @Composable
     fun painterWithPlaceholderOverlayBackgroundBrush(
         placeholderState: PlaceholderState,
-        painter: Painter,
+        originalPainter: Painter,
         color: Color = MaterialTheme.colorScheme.surfaceContainer,
     ): Painter {
-        return if (!placeholderState.isShowContent) {
+        return if (!placeholderState.isHidden) {
             PlaceholderBackgroundPainter(
-                painter = painter,
+                painter = originalPainter,
                 placeholderState = placeholderState,
                 color = color
             )
         } else {
-            painter
+            originalPainter
         }
     }
 
     /**
      * Create a [Painter] that paints with a placeholder background brush. If the [placeholderState]
-     * is [PlaceholderState.isShowContent] then a transparent background will be shown. Otherwise a
+     * is [PlaceholderState.isHidden] then a transparent background will be shown. Otherwise a
      * placeholder background will be drawn or a wipe-off brush will be used to reveal the content
-     * underneath when [PlaceholderState.isWipeOff] is true.
+     * underneath when [PlaceholderState.isWipingOff] is true.
      *
      * @param placeholderState the state of the placeholder
      * @param color the color to use for the placeholder background brush
@@ -418,8 +418,11 @@
      */
     internal var backgroundOffset: Offset = Offset.Zero
 
-    /** Start the animation of the placeholder state. */
-    suspend fun startPlaceholderAnimation() {
+    /**
+     * Animate the placeholder according to the placeholder state. Cancels when the placeholder
+     * becomes inactive.
+     */
+    suspend fun animatePlaceholder() {
         if (!isReduceMotionEnabled) {
             coroutineScope {
                 while (isActive) {
@@ -430,7 +433,7 @@
     }
 
     /**
-     * The current value of the placeholder wipe-off visual effect gradient progression. The
+     * The current value of the placeholder wipe-off visual effect gradient progression in Px. The
      * progression is a 45 degree angle sweep across the whole screen running from outside of the
      * Top|Left of the screen to Bottom|Right used as the anchor for wipe-off gradient effects.
      *
@@ -439,8 +442,7 @@
      * of height/width to create a 45 degree angle) * 1.75f and progress to the
      * maximumScreenDimension * 0.75f.
      *
-     * The time taken for this progression to reach the edge of visible screen is
-     * [PLACEHOLDER_WIPE_OFF_PROGRESSION_DURATION_MS]
+     * The time taken for this progression to reach the edge of visible screen is 300ms.
      */
     internal val placeholderWipeOffProgression: Float by derivedStateOf {
         val absoluteProgression =
@@ -461,7 +463,7 @@
      * gradient that flows across the screen. The progression will start at -maxScreenDimension (max
      * of height/width to create a 45 degree angle) and progress to the maximumScreenDimension.
      *
-     * The time taken for this progression is [PLACEHOLDER_WIPE_OFF_PROGRESSION_ALPHA_DURATION_MS]
+     * The time taken for this progression is 80ms.
      */
     internal val placeholderWipeOffAlpha: Float by derivedStateOf {
         val absoluteProgression =
@@ -475,12 +477,12 @@
     }
 
     /**
-     * The current value of the placeholder visual effect gradient progression. The progression
-     * gives the x coordinate to be applied to the placeholder gradient as it moves across the
-     * screen. Starting off screen to the left and progressing across the screen and finishing off
-     * the screen to the right after [PLACEHOLDER_SHIMMER_DURATION_MS].
+     * The current value of the placeholder visual effect gradient progression in Px. The
+     * progression gives the x coordinate to be applied to the placeholder gradient as it moves
+     * across the screen. Starting off screen to the left and progressing across the screen and
+     * finishing off the screen to the after 800ms.
      */
-    val placeholderProgression: Float by derivedStateOf {
+    internal val placeholderShimmerProgression: Float by derivedStateOf {
         val absoluteProgression =
             (frameMillis.longValue
                 .mod(PLACEHOLDER_SHIMMER_GAP_BETWEEN_ANIMATION_LOOPS_MS)
@@ -493,7 +495,7 @@
     /**
      * The current value of the placeholder visual effect gradient progression alpha/opacity. The
      * progression gives the alpha to apply during the period of the placeholder effect. This allows
-     * the effect to be faded in and then out during the [PLACEHOLDER_SHIMMER_DURATION_MS].
+     * the effect to be faded in and then out during 800ms.
      */
     internal val placeholderShimmerAlpha: Float by derivedStateOf {
         val absoluteProgression =
@@ -514,7 +516,7 @@
     /**
      * The current value of the placeholder visual effect gradient progression alpha/opacity during
      * the fade-in part of reset placeholder animation. This allows the effect to be faded in during
-     * the [PLACEHOLDER_RESET_ANIMATION_DURATION_MS].
+     * 450ms.
      */
     internal val resetPlaceholderFadeInAlpha: Float by derivedStateOf {
         val absoluteProgression =
@@ -534,7 +536,7 @@
     /**
      * The current value of the placeholder visual effect gradient progression alpha/opacity during
      * the fade-out part of reset placeholder animation. This allows the effect to be faded out
-     * during the [PLACEHOLDER_RESET_ANIMATION_DURATION_MS].
+     * during 450ms.
      */
     internal val resetPlaceholderFadeOutAlpha: Float by derivedStateOf {
         val absoluteProgression =
@@ -549,15 +551,13 @@
      * Returns true if the placeholder content should be shown with no placeholders effects and
      * false if either the placeholder or the wipe-off effect are being shown.
      */
-    val isShowContent: Boolean by derivedStateOf {
-        placeholderStage == PlaceholderStage.ShowContent
-    }
+    val isHidden: Boolean by derivedStateOf { placeholderStage == PlaceholderStage.HidePlaceholder }
 
     /**
-     * Should only be called when [isShowContent] is false. Returns true if the wipe-off effect that
-     * reveals content should be shown and false if the placeholder effect should be shown.
+     * Returns true if the wipe-off effect that reveals content is being shown and false if the
+     * placeholder effect should be shown.
      */
-    val isWipeOff: Boolean by derivedStateOf { placeholderStage == PlaceholderStage.WipeOff }
+    val isWipingOff: Boolean by derivedStateOf { placeholderStage == PlaceholderStage.WipeOff }
 
     /**
      * The width of the gradient to use for the placeholder shimmer and wipe-off effects. This is
@@ -567,7 +567,7 @@
     internal val gradientXYWidth: Float by derivedStateOf { maxScreenDimension * 2f.pow(1.5f) }
 
     internal var placeholderStage: PlaceholderStage =
-        if (isContentReady.value.invoke()) PlaceholderStage.ShowContent
+        if (isContentReady.value.invoke()) PlaceholderStage.HidePlaceholder
         else PlaceholderStage.ShowPlaceholder
         get() =
             derivedStateOf {
@@ -581,12 +581,12 @@
                                 (frameMillis.longValue - startOfWipeOffAnimation) >=
                                     PLACEHOLDER_WIPE_OFF_PROGRESSION_DURATION_MS
                             ) {
-                                field = PlaceholderStage.ShowContent
+                                field = PlaceholderStage.HidePlaceholder
                             }
                             // Placeholder
                         } else if (isContentReady.value()) {
                             if (isReduceMotionEnabled) {
-                                field = PlaceholderStage.ShowContent
+                                field = PlaceholderStage.HidePlaceholder
                             } else {
                                 startOfWipeOffAnimation = frameMillis.longValue
                                 field = PlaceholderStage.WipeOff
@@ -652,13 +652,14 @@
 
         /**
          * Indicates that placeholders no longer to be shown. Enter this stage from [WipeOff] in the
-         * loop after the wire-off animation.
+         * loop after the wipe-off animation.
          */
-        val ShowContent = PlaceholderStage(2)
+        val HidePlaceholder = PlaceholderStage(2)
 
         /**
          * Resets the component to remove the content and reinstate the placeholders so that new
-         * content can be loaded. Enter this stage from [ShowContent] and exit to [ShowPlaceholder].
+         * content can be loaded. Enter this stage from [HidePlaceholder] and exit to
+         * [ShowPlaceholder].
          */
         val ResetContent = PlaceholderStage(3)
     }
@@ -668,7 +669,7 @@
             ShowPlaceholder -> "PlaceholderStage.ShowPlaceholder"
             WipeOff -> "PlaceholderStage.WipeOff"
             ResetContent -> "PlaceholderStage.ResetContent"
-            else -> "PlaceholderStage.ShowContent"
+            else -> "PlaceholderStage.HidePlaceholder"
         }
     }
 }
@@ -992,13 +993,23 @@
             Brush.linearGradient(
                 start =
                     Offset(
-                        x = placeholderState.placeholderProgression - halfGradientWidth - offset.x,
-                        y = placeholderState.placeholderProgression - halfGradientWidth - offset.y
+                        x =
+                            placeholderState.placeholderShimmerProgression -
+                                halfGradientWidth -
+                                offset.x,
+                        y =
+                            placeholderState.placeholderShimmerProgression -
+                                halfGradientWidth -
+                                offset.y
                     ),
                 end =
                     Offset(
-                        x = placeholderState.placeholderProgression + halfGradientWidth - offset.x,
-                        y = placeholderState.placeholderProgression + halfGradientWidth - offset.y
+                        x =
+                            placeholderState.placeholderShimmerProgression + halfGradientWidth -
+                                offset.x,
+                        y =
+                            placeholderState.placeholderShimmerProgression + halfGradientWidth -
+                                offset.y
                     ),
                 colorStops =
                     listOf(
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/ProgressIndicator.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/ProgressIndicator.kt
index 9886984..8390137 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/ProgressIndicator.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/ProgressIndicator.kt
@@ -358,6 +358,27 @@
     return if (roundedFraction == 0.0f) 1.0f else roundedFraction
 }
 
+internal fun DrawScope.drawCircularIndicator(
+    startAngle: Float,
+    sweep: Float,
+    brush: Brush,
+    stroke: Stroke
+) {
+    // To draw this circle we need a rect with edges that line up with the midpoint of the stroke.
+    // To do this we need to remove half the stroke width from the total diameter for both sides.
+    val diameterOffset = stroke.width / 2
+    val arcDimen = size.width - 2 * diameterOffset
+    drawArc(
+        brush = brush,
+        startAngle = startAngle,
+        sweepAngle = sweep,
+        useCenter = false,
+        topLeft = Offset(diameterOffset, diameterOffset),
+        size = Size(arcDimen, arcDimen),
+        style = stroke
+    )
+}
+
 internal fun Float.isFullInt(): Boolean = (round(this) == this)
 
 internal fun Float.equalsWithTolerance(number: Float, tolerance: Float = 0.1f) =
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/RadioButton.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/RadioButton.kt
index b5f891f..e846a05 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/RadioButton.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/RadioButton.kt
@@ -17,7 +17,7 @@
 package androidx.wear.compose.material3
 
 import androidx.compose.animation.core.AnimationSpec
-import androidx.compose.animation.core.tween
+import androidx.compose.animation.core.FiniteAnimationSpec
 import androidx.compose.foundation.background
 import androidx.compose.foundation.clickable
 import androidx.compose.foundation.interaction.Interaction
@@ -57,7 +57,6 @@
 import androidx.compose.ui.text.style.TextAlign
 import androidx.compose.ui.text.style.TextOverflow
 import androidx.compose.ui.unit.dp
-import androidx.wear.compose.material3.tokens.MotionTokens
 import androidx.wear.compose.material3.tokens.RadioButtonTokens
 import androidx.wear.compose.material3.tokens.ShapeTokens
 import androidx.wear.compose.material3.tokens.SplitRadioButtonTokens
@@ -1418,12 +1417,8 @@
         dotColor = color,
         onClick = null,
         interactionSource = null,
-        dotRadiusProgressDuration = { isSelected ->
-            if (isSelected) MotionTokens.DurationMedium1 else MotionTokens.DurationShort3
-        },
-        dotAlphaProgressDuration = MotionTokens.DurationShort3,
-        dotAlphaProgressDelay = MotionTokens.DurationShort2,
-        easing = MotionTokens.EasingStandardDecelerate,
+        dotRadiusAnimationSpec = PROGRESS_ANIMATION_SPEC,
+        dotAlphaAnimationSpec = PROGRESS_ANIMATION_SPEC,
         width = CONTROL_WIDTH,
         height = CONTROL_HEIGHT,
         ripple = ripple()
@@ -1443,8 +1438,10 @@
     }
 }
 
-private val COLOR_ANIMATION_SPEC: AnimationSpec<Color> =
-    tween(MotionTokens.DurationMedium1, 0, MotionTokens.EasingStandardDecelerate)
+private val COLOR_ANIMATION_SPEC: AnimationSpec<Color>
+    @Composable get() = MaterialTheme.motionScheme.slowEffectsSpec()
+private val PROGRESS_ANIMATION_SPEC: FiniteAnimationSpec<Float>
+    @Composable get() = MaterialTheme.motionScheme.fastEffectsSpec()
 private val SELECTION_CONTROL_WIDTH = 32.dp
 private val SELECTION_CONTROL_HEIGHT = 24.dp
 private val SELECTION_CONTROL_SPACING = 6.dp
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/RoundButton.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/RoundButton.kt
index b2be46e..7a4cd99 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/RoundButton.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/RoundButton.kt
@@ -35,7 +35,6 @@
 import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.rememberCoroutineScope
-import androidx.compose.runtime.withFrameMillis
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.draw.clip
@@ -211,15 +210,4 @@
     }
 }
 
-private suspend fun waitUntil(condition: () -> Boolean) {
-    val initialTimeMillis = withFrameMillis { it }
-    while (!condition()) {
-        val timeMillis = withFrameMillis { it }
-        if (timeMillis - initialTimeMillis > MAX_WAIT_TIME_MILLIS) return
-    }
-    return
-}
-
-private const val MAX_WAIT_TIME_MILLIS = 1_000L
-
 private const val MIN_REQUIRED_ANIMATION_PROGRESS = 0.75f
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/SwitchButton.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/SwitchButton.kt
index cd792cf..dc91159 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/SwitchButton.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/SwitchButton.kt
@@ -17,9 +17,8 @@
 package androidx.wear.compose.material3
 
 import androidx.compose.animation.core.AnimationSpec
-import androidx.compose.animation.core.TweenSpec
+import androidx.compose.animation.core.FiniteAnimationSpec
 import androidx.compose.animation.core.animateFloat
-import androidx.compose.animation.core.tween
 import androidx.compose.animation.core.updateTransition
 import androidx.compose.foundation.background
 import androidx.compose.foundation.border
@@ -66,7 +65,6 @@
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.util.lerp
-import androidx.wear.compose.material3.tokens.MotionTokens
 import androidx.wear.compose.material3.tokens.ShapeTokens
 import androidx.wear.compose.material3.tokens.SplitSwitchButtonTokens
 import androidx.wear.compose.material3.tokens.SwitchButtonTokens
@@ -1940,7 +1938,7 @@
 private val SPLIT_MIN_WIDTH = 48.dp
 private val SPLIT_SECTIONS_SHAPE = ShapeTokens.CornerExtraSmall
 
-private val COLOR_ANIMATION_SPEC: AnimationSpec<Color> =
-    tween(MotionTokens.DurationMedium1, 0, MotionTokens.EasingStandardDecelerate)
-private val SWITCH_PROGRESS_ANIMATION_SPEC: TweenSpec<Float> =
-    tween(MotionTokens.DurationMedium2, 0, MotionTokens.EasingStandardDecelerate)
+private val COLOR_ANIMATION_SPEC: AnimationSpec<Color>
+    @Composable get() = MaterialTheme.motionScheme.slowEffectsSpec()
+private val SWITCH_PROGRESS_ANIMATION_SPEC: FiniteAnimationSpec<Float>
+    @Composable get() = MaterialTheme.motionScheme.fastEffectsSpec()
diff --git a/wear/compose/compose-material3/src/main/res/values-af/strings.xml b/wear/compose/compose-material3/src/main/res/values-af/strings.xml
index 3ab44cf..4d7a998 100644
--- a/wear/compose/compose-material3/src/main/res/values-af/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-af/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Vermeerder"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Verminder"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Vermeerder"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Het misluk"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Sukses"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Maak op foon oop"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-am/strings.xml b/wear/compose/compose-material3/src/main/res/values-am/strings.xml
index 8897e0b..d3c755b 100644
--- a/wear/compose/compose-material3/src/main/res/values-am/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-am/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"ጨምር"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"ቀንስ"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"ጨምር"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"አልተሳካም"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"ተሳክቷል"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"ስልክ ላይ ክፈት"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-ar/strings.xml b/wear/compose/compose-material3/src/main/res/values-ar/strings.xml
index da562e4..02c4b8d 100644
--- a/wear/compose/compose-material3/src/main/res/values-ar/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-ar/strings.xml
@@ -54,6 +54,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"زيادة"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"تقليل"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"زيادة"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"تعذر الإجراء"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"نجحَ الإجراء"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"فتح على الهاتف"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-as/strings.xml b/wear/compose/compose-material3/src/main/res/values-as/strings.xml
index 1a3d0b6..0b775bb 100644
--- a/wear/compose/compose-material3/src/main/res/values-as/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-as/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"বঢ়াওক"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"কমাওক"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"বঢ়াওক"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"বিফল হৈছে"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"সফল"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"ফ’নত খোলক"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-az/strings.xml b/wear/compose/compose-material3/src/main/res/values-az/strings.xml
index 2116d76..a649f33 100644
--- a/wear/compose/compose-material3/src/main/res/values-az/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-az/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Artırın"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Azaldın"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Artırın"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Alınmadı"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Alındı"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Telefonda aç"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-b+sr+Latn/strings.xml b/wear/compose/compose-material3/src/main/res/values-b+sr+Latn/strings.xml
index 83aaef1..cc50b58 100644
--- a/wear/compose/compose-material3/src/main/res/values-b+sr+Latn/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-b+sr+Latn/strings.xml
@@ -45,6 +45,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Povećaj"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Smanji"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Povećaj"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Nije uspelo"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Uspelo"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Na telefonu"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-be/strings.xml b/wear/compose/compose-material3/src/main/res/values-be/strings.xml
index 3504095cc..44a1d7a 100644
--- a/wear/compose/compose-material3/src/main/res/values-be/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-be/strings.xml
@@ -48,6 +48,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Павялічыць"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Паменшыць"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Павялічыць"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Памылка"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Выканана"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"На тэлефоне"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-bg/strings.xml b/wear/compose/compose-material3/src/main/res/values-bg/strings.xml
index a0d9411..5741a7c 100644
--- a/wear/compose/compose-material3/src/main/res/values-bg/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-bg/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Увеличаване"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Намаляване"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Увеличаване"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Неуспешно"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Успешно"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Отв. на тел."</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-bn/strings.xml b/wear/compose/compose-material3/src/main/res/values-bn/strings.xml
index af0fb65..9ee49c4 100644
--- a/wear/compose/compose-material3/src/main/res/values-bn/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-bn/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"বাড়ান"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"কমানো"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"বাড়ানো"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"সফল হয়নি"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"সফল হয়েছে"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"ফোনে খুলুন"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-bs/strings.xml b/wear/compose/compose-material3/src/main/res/values-bs/strings.xml
index 1c2416d..3f986f8 100644
--- a/wear/compose/compose-material3/src/main/res/values-bs/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-bs/strings.xml
@@ -45,6 +45,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Povećavanje"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Smanjenje"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Povećanje"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Neuspješno"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Uspješno"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Otvor. na tel."</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-ca/strings.xml b/wear/compose/compose-material3/src/main/res/values-ca/strings.xml
index 1376675..4f4240a 100644
--- a/wear/compose/compose-material3/src/main/res/values-ca/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-ca/strings.xml
@@ -45,6 +45,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Augmenta"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Disminueix"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Augmenta"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Ha fallat"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Correcte"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Obre al telèfon"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-cs/strings.xml b/wear/compose/compose-material3/src/main/res/values-cs/strings.xml
index a914697..33664db 100644
--- a/wear/compose/compose-material3/src/main/res/values-cs/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-cs/strings.xml
@@ -48,6 +48,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Zvýšit"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Snížit"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Zvýšit"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Nezdařilo se"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Hotovo"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Otevřít v telefonu"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-da/strings.xml b/wear/compose/compose-material3/src/main/res/values-da/strings.xml
index 5737e13..842214a 100644
--- a/wear/compose/compose-material3/src/main/res/values-da/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-da/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Øg"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Sænk"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Øg"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Mislykket"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Gennemført"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Åbn på telefon"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-de/strings.xml b/wear/compose/compose-material3/src/main/res/values-de/strings.xml
index b763f40..875685b 100644
--- a/wear/compose/compose-material3/src/main/res/values-de/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-de/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Erhöhen"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Verringern"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Erhöhen"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Fehlgeschlagen"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Abgeschlossen"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Auf Smartphone öffnen"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-el/strings.xml b/wear/compose/compose-material3/src/main/res/values-el/strings.xml
index e0be921..2fb649b 100644
--- a/wear/compose/compose-material3/src/main/res/values-el/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-el/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Αύξηση"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Μείωση"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Αύξηση"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Αποτυχία"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Επιτυχία"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Στο τηλέφωνο"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-en-rAU/strings.xml b/wear/compose/compose-material3/src/main/res/values-en-rAU/strings.xml
index 272e741..b83a6af3 100644
--- a/wear/compose/compose-material3/src/main/res/values-en-rAU/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-en-rAU/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Increase"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Decrease"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Increase"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Failed"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Success"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Open on phone"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-en-rCA/strings.xml b/wear/compose/compose-material3/src/main/res/values-en-rCA/strings.xml
index a1f8f19..33c33d5 100644
--- a/wear/compose/compose-material3/src/main/res/values-en-rCA/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-en-rCA/strings.xml
@@ -42,6 +42,8 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Increase"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Decrease"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Increase"</string>
+    <string name="wear_m3c_alert_dialog_content_description_confirm_button" msgid="7776845597891182382">"Confirm"</string>
+    <string name="wear_m3c_alert_dialog_content_description_dismiss_button" msgid="3572467833850785688">"Dismiss"</string>
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Failed"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Success"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Open on phone"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-en-rGB/strings.xml b/wear/compose/compose-material3/src/main/res/values-en-rGB/strings.xml
index 272e741..b83a6af3 100644
--- a/wear/compose/compose-material3/src/main/res/values-en-rGB/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-en-rGB/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Increase"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Decrease"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Increase"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Failed"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Success"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Open on phone"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-en-rIN/strings.xml b/wear/compose/compose-material3/src/main/res/values-en-rIN/strings.xml
index 272e741..b83a6af3 100644
--- a/wear/compose/compose-material3/src/main/res/values-en-rIN/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-en-rIN/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Increase"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Decrease"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Increase"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Failed"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Success"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Open on phone"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-es-rUS/strings.xml b/wear/compose/compose-material3/src/main/res/values-es-rUS/strings.xml
index 74e4311..56c5f4f 100644
--- a/wear/compose/compose-material3/src/main/res/values-es-rUS/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-es-rUS/strings.xml
@@ -45,6 +45,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Aumentar"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Disminuir"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Aumentar"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Error"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Listo"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Abrir en el teléfono"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-es/strings.xml b/wear/compose/compose-material3/src/main/res/values-es/strings.xml
index a3f0fb8..1a99712 100644
--- a/wear/compose/compose-material3/src/main/res/values-es/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-es/strings.xml
@@ -45,6 +45,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Aumentar"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Reducir"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Aumentar"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Error"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Todo correcto"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Ábrelo en el teléfono"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-et/strings.xml b/wear/compose/compose-material3/src/main/res/values-et/strings.xml
index abb3ac0..8d80314 100644
--- a/wear/compose/compose-material3/src/main/res/values-et/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-et/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Suurenda"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Vähenda"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Suurenda"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Ebaõnnestus"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Õnnestus"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Ava telefonis"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-eu/strings.xml b/wear/compose/compose-material3/src/main/res/values-eu/strings.xml
index a44067d..76fc614 100644
--- a/wear/compose/compose-material3/src/main/res/values-eu/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-eu/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Igo"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Jaitsi"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Igo"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Huts egin du"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Eginda"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Ireki telefonoan"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-fa/strings.xml b/wear/compose/compose-material3/src/main/res/values-fa/strings.xml
index 4ae1008..ecf3999 100644
--- a/wear/compose/compose-material3/src/main/res/values-fa/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-fa/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"افزایش دادن"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"کاهش دادن"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"افزایش دادن"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"انجام نشد"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"انجام شد"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"باز کردن در تلفن"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-fi/strings.xml b/wear/compose/compose-material3/src/main/res/values-fi/strings.xml
index 824c7b52..c704c03 100644
--- a/wear/compose/compose-material3/src/main/res/values-fi/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-fi/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Lisää"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Vähennä"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Lisää"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Epäonnistui"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Onnistui"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Puhelimella"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-fr-rCA/strings.xml b/wear/compose/compose-material3/src/main/res/values-fr-rCA/strings.xml
index 6aae002..f6fa0fe 100644
--- a/wear/compose/compose-material3/src/main/res/values-fr-rCA/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-fr-rCA/strings.xml
@@ -45,6 +45,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Augmenter"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Diminuer"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Augmenter"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Échec"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Réussite"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Ouv. ds tél."</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-fr/strings.xml b/wear/compose/compose-material3/src/main/res/values-fr/strings.xml
index f8cfafe..6cd5c75 100644
--- a/wear/compose/compose-material3/src/main/res/values-fr/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-fr/strings.xml
@@ -45,6 +45,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Augmenter"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Diminuer"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Augmenter"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Échec"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Opération réussie"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Ouvrir sur le téléphone"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-gl/strings.xml b/wear/compose/compose-material3/src/main/res/values-gl/strings.xml
index c22ed45..985b2f3 100644
--- a/wear/compose/compose-material3/src/main/res/values-gl/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-gl/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Aumentar"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Reducir"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Aumentar"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Erro"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Todo correcto"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Abrir no tel."</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-gu/strings.xml b/wear/compose/compose-material3/src/main/res/values-gu/strings.xml
index 92e9105..5d9c5073 100644
--- a/wear/compose/compose-material3/src/main/res/values-gu/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-gu/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"વધારો"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"ઘટાડો"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"વધારો"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"નિષ્ફળ થઈ"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"સફળ થઈ"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"ફોન પર ખોલો"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-hi/strings.xml b/wear/compose/compose-material3/src/main/res/values-hi/strings.xml
index cafe258..b50a062 100644
--- a/wear/compose/compose-material3/src/main/res/values-hi/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-hi/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"बढ़ाएं"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"घटाएं"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"बढ़ाएं"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"काम नहीं हुआ"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"काम हो गया"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"फ़ोन पर खोलें"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-hr/strings.xml b/wear/compose/compose-material3/src/main/res/values-hr/strings.xml
index 754b6b6..1d6cdd0 100644
--- a/wear/compose/compose-material3/src/main/res/values-hr/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-hr/strings.xml
@@ -45,6 +45,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Povećaj"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Smanji"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Povećaj"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Nije uspjelo"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Uspjeh"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Na telefonu"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-hu/strings.xml b/wear/compose/compose-material3/src/main/res/values-hu/strings.xml
index 167ca98..c9cf8e1 100644
--- a/wear/compose/compose-material3/src/main/res/values-hu/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-hu/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Növelés"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Csökkentés"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Növelés"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Sikertelen"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Sikerült"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Nyissa meg mobilon"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-hy/strings.xml b/wear/compose/compose-material3/src/main/res/values-hy/strings.xml
index c2b9640..1edfa943 100644
--- a/wear/compose/compose-material3/src/main/res/values-hy/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-hy/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Ավելացնել"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Իջեցնել"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Բարձրացնել"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Ձախողվել է"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Պատրաստ է"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Բացեք հեռախոսում"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-in/strings.xml b/wear/compose/compose-material3/src/main/res/values-in/strings.xml
index 2edf41c..82f3c6e 100644
--- a/wear/compose/compose-material3/src/main/res/values-in/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-in/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Tingkatkan"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Turunkan"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Tingkatkan"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Gagal"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Berhasil"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Buka di ponsel"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-is/strings.xml b/wear/compose/compose-material3/src/main/res/values-is/strings.xml
index a8654ef..494885e 100644
--- a/wear/compose/compose-material3/src/main/res/values-is/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-is/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Auka"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Lækka"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Hækka"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Mistókst"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Tókst"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Opna í símanum"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-it/strings.xml b/wear/compose/compose-material3/src/main/res/values-it/strings.xml
index 1604a5f..dbb4bdf 100644
--- a/wear/compose/compose-material3/src/main/res/values-it/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-it/strings.xml
@@ -45,6 +45,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Aumenta"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Riduci"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Aumenta"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Non riuscita"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Riuscita"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Su smartph."</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-iw/strings.xml b/wear/compose/compose-material3/src/main/res/values-iw/strings.xml
index 0a0b1cd..27bb9c0 100644
--- a/wear/compose/compose-material3/src/main/res/values-iw/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-iw/strings.xml
@@ -45,6 +45,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"הגברה"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"הפחתה"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"העלאה"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"הפעולה נכשלה"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"הפעולה הצליחה"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"פתיחה בטלפון"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-ja/strings.xml b/wear/compose/compose-material3/src/main/res/values-ja/strings.xml
index d7ac4f2c..e0d13b8 100644
--- a/wear/compose/compose-material3/src/main/res/values-ja/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-ja/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"上げる"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"減らす"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"増やす"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"失敗"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"成功"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"スマホで開く"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-ka/strings.xml b/wear/compose/compose-material3/src/main/res/values-ka/strings.xml
index deda66ae..87a5202 100644
--- a/wear/compose/compose-material3/src/main/res/values-ka/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-ka/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"გაზრდა"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"შემცირება"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"გაზრდა"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"ვერ შესრულდა"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"შესრულდა"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"ტელეფონში გახსნა"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-kk/strings.xml b/wear/compose/compose-material3/src/main/res/values-kk/strings.xml
index e3e7615..8af1496 100644
--- a/wear/compose/compose-material3/src/main/res/values-kk/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-kk/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Көбейту"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Азайту"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Көбейту"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Расталмады."</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Расталды."</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Телефоннан ашыңыз."</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-km/strings.xml b/wear/compose/compose-material3/src/main/res/values-km/strings.xml
index 83ca8d5..4ce6dc5 100644
--- a/wear/compose/compose-material3/src/main/res/values-km/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-km/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"បង្កើន"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"បន្ថយ"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"បង្កើន"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"មិនបានសម្រេច"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"ជោគជ័យ"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"បើកលើទូរសព្ទ"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-kn/strings.xml b/wear/compose/compose-material3/src/main/res/values-kn/strings.xml
index 447dc4d..c0bcb1c 100644
--- a/wear/compose/compose-material3/src/main/res/values-kn/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-kn/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"ಹೆಚ್ಚಿಸಿ"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"ಕಡಿಮೆ ಮಾಡಿ"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"ಹೆಚ್ಚಿಸಿ"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"ವಿಫಲವಾಗಿದೆ"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"ಯಶಸ್ವಿಯಾಗಿದೆ"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"ಫೋನ್‌ನಲ್ಲಿ ತೆರೆಯಿರಿ"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-ko/strings.xml b/wear/compose/compose-material3/src/main/res/values-ko/strings.xml
index f30113a..3870de0 100644
--- a/wear/compose/compose-material3/src/main/res/values-ko/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-ko/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"증가"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"줄이기"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"늘리기"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"실패"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"성공"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"휴대전화에서 열기"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-ky/strings.xml b/wear/compose/compose-material3/src/main/res/values-ky/strings.xml
index 4ffd0d3..9e0d4c0 100644
--- a/wear/compose/compose-material3/src/main/res/values-ky/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-ky/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Жогорулатуу"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Төмөндөтүү"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Жогорулатуу"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Ишке ашпады"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Ийгилик"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Телефондо ачуу"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-lo/strings.xml b/wear/compose/compose-material3/src/main/res/values-lo/strings.xml
index 52e8a9b..774ced7 100644
--- a/wear/compose/compose-material3/src/main/res/values-lo/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-lo/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"ເພີ່ມຂຶ້ນ"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"ຫຼຸດລົງ"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"ເພີ່ມຂຶ້ນ"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"ບໍ່ສຳເລັດ"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"ສຳເລັດ"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"ເປີດໃນໂທລະສັບ"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-lt/strings.xml b/wear/compose/compose-material3/src/main/res/values-lt/strings.xml
index 28e19fe..5bd1303 100644
--- a/wear/compose/compose-material3/src/main/res/values-lt/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-lt/strings.xml
@@ -48,6 +48,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Padidinti"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Sumažinti"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Padidinti"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Nepavyko"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Pavyko"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Atidaryti telefone"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-lv/strings.xml b/wear/compose/compose-material3/src/main/res/values-lv/strings.xml
index 94d0107..f355546 100644
--- a/wear/compose/compose-material3/src/main/res/values-lv/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-lv/strings.xml
@@ -45,6 +45,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Palielināt"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Samazināt"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Palielināt"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Neizdevās"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Izdevās"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Atvērt tālrunī"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-mk/strings.xml b/wear/compose/compose-material3/src/main/res/values-mk/strings.xml
index f2cd97d..3f556e4 100644
--- a/wear/compose/compose-material3/src/main/res/values-mk/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-mk/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Зголеми"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Намалување"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Зголемување"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Неуспешно"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Успешно"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Отвори на телефонот"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-ml/strings.xml b/wear/compose/compose-material3/src/main/res/values-ml/strings.xml
index 4d26863..632c921 100644
--- a/wear/compose/compose-material3/src/main/res/values-ml/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-ml/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"കൂട്ടുക"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"കുറയ്‌ക്കുക"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"കൂട്ടുക"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"പരാജയപ്പെട്ടു"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"വിജയിച്ചു"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"ഫോണിൽ തുറക്കൂ"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-mn/strings.xml b/wear/compose/compose-material3/src/main/res/values-mn/strings.xml
index 3b24ce1..582aa3a 100644
--- a/wear/compose/compose-material3/src/main/res/values-mn/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-mn/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Нэмэгдүүлэх"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Багасгах"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Нэмэгдүүлэх"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Амжилтгүй"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Амжилттай"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Утсанд нээх"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-mr/strings.xml b/wear/compose/compose-material3/src/main/res/values-mr/strings.xml
index e6efee5..acbfd1c 100644
--- a/wear/compose/compose-material3/src/main/res/values-mr/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-mr/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"वाढवा"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"कमी करा"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"वाढवा"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"अयशस्वी"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"यशस्वी झाले"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"फोनवर उघडा"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-ms/strings.xml b/wear/compose/compose-material3/src/main/res/values-ms/strings.xml
index b41938c..9a77a5d 100644
--- a/wear/compose/compose-material3/src/main/res/values-ms/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-ms/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Tambahkan"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Kurangkan"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Tambahkan"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Gagal"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Berjaya"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Buka pada telefon"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-my/strings.xml b/wear/compose/compose-material3/src/main/res/values-my/strings.xml
index 678ad76..da6e684 100644
--- a/wear/compose/compose-material3/src/main/res/values-my/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-my/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"တိုးရန်"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"လျှော့ရန်"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"ချဲ့ရန်"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"မအောင်မြင်ပါ"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"အောင်မြင်သည်"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"ဖုန်း၌ဖွင့်ရန်"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-nb/strings.xml b/wear/compose/compose-material3/src/main/res/values-nb/strings.xml
index 664750c..ef7e2f0 100644
--- a/wear/compose/compose-material3/src/main/res/values-nb/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-nb/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Øk"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Reduser"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Øk"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Mislyktes"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Vellykket"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Åpne på tlf."</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-ne/strings.xml b/wear/compose/compose-material3/src/main/res/values-ne/strings.xml
index fe60e64..fd2cf9b 100644
--- a/wear/compose/compose-material3/src/main/res/values-ne/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-ne/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"बढाउनुहोस्"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"घटाउनुहोस्"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"बढाउनुहोस्"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"पुष्टि गर्न सकिएन"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"पुष्टि गरियो"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"फोनमा खोल्नुहोस्"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-nl/strings.xml b/wear/compose/compose-material3/src/main/res/values-nl/strings.xml
index a267de1..34beeaa 100644
--- a/wear/compose/compose-material3/src/main/res/values-nl/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-nl/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Verhogen"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Verlagen"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Verhogen"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Mislukt"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Geslaagd"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Openen op telefoon"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-or/strings.xml b/wear/compose/compose-material3/src/main/res/values-or/strings.xml
index d356304..1b9346e 100644
--- a/wear/compose/compose-material3/src/main/res/values-or/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-or/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"ବଢ଼ାନ୍ତୁ"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"କମାନ୍ତୁ"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"ବଢ଼ାନ୍ତୁ"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"ବିଫଳ ହୋଇଛି"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"ସଫଳ"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"ଫୋନରେ ଖୋଲନ୍ତୁ"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-pa/strings.xml b/wear/compose/compose-material3/src/main/res/values-pa/strings.xml
index 3c68908..96306b7 100644
--- a/wear/compose/compose-material3/src/main/res/values-pa/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-pa/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"ਵਧਾਓ"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"ਘਟਾਓ"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"ਵਧਾਓ"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"ਅਸਫਲ ਰਿਹਾ"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"ਸਫਲ ਰਿਹਾ"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"ਫ਼ੋਨ \'ਤੇ ਖੋਲ੍ਹੋ"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-pl/strings.xml b/wear/compose/compose-material3/src/main/res/values-pl/strings.xml
index a9249328..fecfbf7 100644
--- a/wear/compose/compose-material3/src/main/res/values-pl/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-pl/strings.xml
@@ -48,6 +48,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Zwiększ"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Zmniejsz"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Zwiększ"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Niepowodzenie"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Udało się"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Otwórz na telefonie"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-pt-rBR/strings.xml b/wear/compose/compose-material3/src/main/res/values-pt-rBR/strings.xml
index 775ebcb..e5ab9320 100644
--- a/wear/compose/compose-material3/src/main/res/values-pt-rBR/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-pt-rBR/strings.xml
@@ -45,6 +45,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Aumentar"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Diminuir"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Aumentar"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Falha"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Pronto"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Abra no smartphone"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-pt-rPT/strings.xml b/wear/compose/compose-material3/src/main/res/values-pt-rPT/strings.xml
index a99c8c1..15c07d1 100644
--- a/wear/compose/compose-material3/src/main/res/values-pt-rPT/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-pt-rPT/strings.xml
@@ -45,6 +45,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Aumentar"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Diminuir"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Aumentar"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Falhou"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Concluído"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Abrir no tel."</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-pt/strings.xml b/wear/compose/compose-material3/src/main/res/values-pt/strings.xml
index 775ebcb..e5ab9320 100644
--- a/wear/compose/compose-material3/src/main/res/values-pt/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-pt/strings.xml
@@ -45,6 +45,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Aumentar"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Diminuir"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Aumentar"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Falha"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Pronto"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Abra no smartphone"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-ro/strings.xml b/wear/compose/compose-material3/src/main/res/values-ro/strings.xml
index b2920e2..8e21c1b 100644
--- a/wear/compose/compose-material3/src/main/res/values-ro/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-ro/strings.xml
@@ -45,6 +45,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Crește"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Scade"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Crește"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Eroare"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Succes"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Pe telefon"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-ru/strings.xml b/wear/compose/compose-material3/src/main/res/values-ru/strings.xml
index 38b6613..bfa21739 100644
--- a/wear/compose/compose-material3/src/main/res/values-ru/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-ru/strings.xml
@@ -48,6 +48,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Увеличить"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Уменьшить"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Увеличить"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Ошибка"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Готово"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Открыть на телефоне"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-si/strings.xml b/wear/compose/compose-material3/src/main/res/values-si/strings.xml
index db2458b..37aa465 100644
--- a/wear/compose/compose-material3/src/main/res/values-si/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-si/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"වැඩි කරන්න"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"අඩු කරන්න"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"වැඩි කරන්න"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"අසමත් විය"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"සාර්ථකයි"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"දුරකථනයෙන් විවෘත කරන්න"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-sk/strings.xml b/wear/compose/compose-material3/src/main/res/values-sk/strings.xml
index 1569d57..30e57bb 100644
--- a/wear/compose/compose-material3/src/main/res/values-sk/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-sk/strings.xml
@@ -48,6 +48,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Zvýšiť"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Znížiť"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Zvýšiť"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Neúspešné"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Podarilo sa"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Otvorte v telefóne"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-sl/strings.xml b/wear/compose/compose-material3/src/main/res/values-sl/strings.xml
index cb50296..54c0542 100644
--- a/wear/compose/compose-material3/src/main/res/values-sl/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-sl/strings.xml
@@ -48,6 +48,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Povečanje"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Zmanjšaj"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Povečaj"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Neuspešno"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Uspešno"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Odpri v telefonu"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-sq/strings.xml b/wear/compose/compose-material3/src/main/res/values-sq/strings.xml
index 0ecac90..ba1133a 100644
--- a/wear/compose/compose-material3/src/main/res/values-sq/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-sq/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Rrit"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Ul"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Rrit"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Dështoi"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Me sukses"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Hape në telefon"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-sr/strings.xml b/wear/compose/compose-material3/src/main/res/values-sr/strings.xml
index 78c8d8c..44ef98d 100644
--- a/wear/compose/compose-material3/src/main/res/values-sr/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-sr/strings.xml
@@ -45,6 +45,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Повећај"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Смањи"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Повећај"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Није успело"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Успело"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"На телефону"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-sv/strings.xml b/wear/compose/compose-material3/src/main/res/values-sv/strings.xml
index c8d50d9..e388d545 100644
--- a/wear/compose/compose-material3/src/main/res/values-sv/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-sv/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Öka"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Minska"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Öka"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Misslyckades"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Klart"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"På telefonen"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-sw/strings.xml b/wear/compose/compose-material3/src/main/res/values-sw/strings.xml
index 78cb7e0..bbdd5f8 100644
--- a/wear/compose/compose-material3/src/main/res/values-sw/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-sw/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Ongeza"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Punguza"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Ongeza"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Imeshindwa"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Imemaliza"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Fungua kwenye simu"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-ta/strings.xml b/wear/compose/compose-material3/src/main/res/values-ta/strings.xml
index b8952f2..18b4454 100644
--- a/wear/compose/compose-material3/src/main/res/values-ta/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-ta/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"அதிகரிக்கும்"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"குறைக்கும்"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"அதிகரிக்கும்"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"தோல்வி"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"முடிந்தது"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"மொபைலில் திற"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-te/strings.xml b/wear/compose/compose-material3/src/main/res/values-te/strings.xml
index 3664364..b0ad3e6 100644
--- a/wear/compose/compose-material3/src/main/res/values-te/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-te/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"పెంచండి"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"తగ్గించండి"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"పెంచండి"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"విఫలమైంది"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"విజయవంతమైంది"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"ఫోన్‌లో తెరు"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-th/strings.xml b/wear/compose/compose-material3/src/main/res/values-th/strings.xml
index f82c0a5..fc10a30 100644
--- a/wear/compose/compose-material3/src/main/res/values-th/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-th/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"เพิ่ม"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"ลด"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"เพิ่ม"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"ไม่สำเร็จ"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"สำเร็จ"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"เปิดในโทรศัพท์"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-tl/strings.xml b/wear/compose/compose-material3/src/main/res/values-tl/strings.xml
index c9781cd..c51056a 100644
--- a/wear/compose/compose-material3/src/main/res/values-tl/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-tl/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Dagdagan"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Bawasan"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Dagdagan"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Nabigo"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Matagumpay"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Buksan"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-tr/strings.xml b/wear/compose/compose-material3/src/main/res/values-tr/strings.xml
index e950de0..425a8af 100644
--- a/wear/compose/compose-material3/src/main/res/values-tr/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-tr/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Artır"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Azalt"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Artır"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Başarısız"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Başarılı"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Telefonda aç"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-uk/strings.xml b/wear/compose/compose-material3/src/main/res/values-uk/strings.xml
index 9c8f77f..b09239b 100644
--- a/wear/compose/compose-material3/src/main/res/values-uk/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-uk/strings.xml
@@ -48,6 +48,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Збільшити"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Зменшити"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Збільшити"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Помилка"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Готово"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"На телефоні"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-ur/strings.xml b/wear/compose/compose-material3/src/main/res/values-ur/strings.xml
index 4c82b62..a6c5a45 100644
--- a/wear/compose/compose-material3/src/main/res/values-ur/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-ur/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"بڑھائیں"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"کم کریں"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"بڑھائیں"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"ناکام ہوا"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"کامیاب"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"فون پر کھولیں"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-uz/strings.xml b/wear/compose/compose-material3/src/main/res/values-uz/strings.xml
index 3a0749d..038a7ef 100644
--- a/wear/compose/compose-material3/src/main/res/values-uz/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-uz/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Oshirish"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Pasaytirish"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Oshirish"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Bajarilmadi"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Bajarildi"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Telefonda"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-vi/strings.xml b/wear/compose/compose-material3/src/main/res/values-vi/strings.xml
index e1a9df8..5110168 100644
--- a/wear/compose/compose-material3/src/main/res/values-vi/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-vi/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Tăng"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Giảm"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Tăng"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Lỗi"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Thành công"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Mở trên điện thoại"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-zh-rCN/strings.xml b/wear/compose/compose-material3/src/main/res/values-zh-rCN/strings.xml
index 7f82188..bcbe3a2 100644
--- a/wear/compose/compose-material3/src/main/res/values-zh-rCN/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-zh-rCN/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"增加"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"降低"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"提高"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"失败"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"成功"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"在手机上打开"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-zh-rHK/strings.xml b/wear/compose/compose-material3/src/main/res/values-zh-rHK/strings.xml
index e87a261..7cedc50 100644
--- a/wear/compose/compose-material3/src/main/res/values-zh-rHK/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-zh-rHK/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"調高"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"調低"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"調高"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"失敗"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"成功"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"在手機開啟"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-zh-rTW/strings.xml b/wear/compose/compose-material3/src/main/res/values-zh-rTW/strings.xml
index 311e77d9..c330c20 100644
--- a/wear/compose/compose-material3/src/main/res/values-zh-rTW/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-zh-rTW/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"調高"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"調低"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"調高"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"失敗"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"成功"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"在手機上開啟"</string>
diff --git a/wear/compose/compose-material3/src/main/res/values-zu/strings.xml b/wear/compose/compose-material3/src/main/res/values-zu/strings.xml
index b71059a..d9b5dbc 100644
--- a/wear/compose/compose-material3/src/main/res/values-zu/strings.xml
+++ b/wear/compose/compose-material3/src/main/res/values-zu/strings.xml
@@ -42,6 +42,10 @@
     <string name="wear_m3c_slider_increase_content_description" msgid="3329631766954416834">"Khulisa"</string>
     <string name="wear_m3c_stepper_decrease_content_description" msgid="6939134411425530620">"Yehlisa"</string>
     <string name="wear_m3c_stepper_increase_content_description" msgid="6513575827514139918">"Khulisa"</string>
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_confirm_button (7776845597891182382) -->
+    <skip />
+    <!-- no translation found for wear_m3c_alert_dialog_content_description_dismiss_button (3572467833850785688) -->
+    <skip />
     <string name="wear_m3c_confirmation_failure_message" msgid="6690105830380889949">"Yehlulekile"</string>
     <string name="wear_m3c_confirmation_success_message" msgid="7045594078216655038">"Impumelelo"</string>
     <string name="wear_m3c_open_on_phone" msgid="5829463187924353601">"Vula efonini"</string>
diff --git a/wear/compose/integration-tests/macrobenchmark/src/main/java/androidx/wear/compose/integration/macrobenchmark/ButtonBenchmarkBase.kt b/wear/compose/integration-tests/macrobenchmark/src/main/java/androidx/wear/compose/integration/macrobenchmark/ButtonBenchmarkBase.kt
index 9ba55cc..3fdfc12 100644
--- a/wear/compose/integration-tests/macrobenchmark/src/main/java/androidx/wear/compose/integration/macrobenchmark/ButtonBenchmarkBase.kt
+++ b/wear/compose/integration-tests/macrobenchmark/src/main/java/androidx/wear/compose/integration/macrobenchmark/ButtonBenchmarkBase.kt
@@ -18,7 +18,9 @@
 
 import android.content.Intent
 import androidx.benchmark.macro.CompilationMode
-import androidx.benchmark.macro.FrameTimingMetric
+import androidx.benchmark.macro.ExperimentalMetricApi
+import androidx.benchmark.macro.FrameTimingGfxInfoMetric
+import androidx.benchmark.macro.MemoryUsageMetric
 import androidx.benchmark.macro.junit4.MacrobenchmarkRule
 import androidx.test.uiautomator.By
 import org.junit.After
@@ -26,6 +28,7 @@
 import org.junit.Rule
 import org.junit.Test
 
+@OptIn(ExperimentalMetricApi::class)
 abstract class ButtonBenchmarkBase(
     private val compilationMode: CompilationMode,
     private val activityAction: String
@@ -46,7 +49,8 @@
     fun start() {
         benchmarkRule.measureRepeated(
             packageName = PACKAGE_NAME,
-            metrics = listOf(FrameTimingMetric()),
+            metrics =
+                listOf(FrameTimingGfxInfoMetric(), MemoryUsageMetric(MemoryUsageMetric.Mode.Last)),
             compilationMode = compilationMode,
             iterations = 10,
             setupBlock = {
diff --git a/wear/compose/integration-tests/macrobenchmark/src/main/java/androidx/wear/compose/integration/macrobenchmark/PositionIndicatorBenchmark.kt b/wear/compose/integration-tests/macrobenchmark/src/main/java/androidx/wear/compose/integration/macrobenchmark/PositionIndicatorBenchmark.kt
index 22b55a3..9662bfc 100644
--- a/wear/compose/integration-tests/macrobenchmark/src/main/java/androidx/wear/compose/integration/macrobenchmark/PositionIndicatorBenchmark.kt
+++ b/wear/compose/integration-tests/macrobenchmark/src/main/java/androidx/wear/compose/integration/macrobenchmark/PositionIndicatorBenchmark.kt
@@ -18,7 +18,9 @@
 
 import android.content.Intent
 import androidx.benchmark.macro.CompilationMode
-import androidx.benchmark.macro.FrameTimingMetric
+import androidx.benchmark.macro.ExperimentalMetricApi
+import androidx.benchmark.macro.FrameTimingGfxInfoMetric
+import androidx.benchmark.macro.MemoryUsageMetric
 import androidx.benchmark.macro.junit4.MacrobenchmarkRule
 import androidx.test.filters.LargeTest
 import androidx.test.uiautomator.By
@@ -32,6 +34,7 @@
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
 
+@OptIn(ExperimentalMetricApi::class)
 @LargeTest
 @RunWith(Parameterized::class)
 class PositionIndicatorBenchmark(private val compilationMode: CompilationMode) {
@@ -51,7 +54,8 @@
     fun start() {
         benchmarkRule.measureRepeated(
             packageName = PACKAGE_NAME,
-            metrics = listOf(FrameTimingMetric()),
+            metrics =
+                listOf(FrameTimingGfxInfoMetric(), MemoryUsageMetric(MemoryUsageMetric.Mode.Last)),
             compilationMode = compilationMode,
             iterations = 5,
             setupBlock = {
diff --git a/wear/compose/integration-tests/macrobenchmark/src/main/java/androidx/wear/compose/integration/macrobenchmark/ScrollBenchmark.kt b/wear/compose/integration-tests/macrobenchmark/src/main/java/androidx/wear/compose/integration/macrobenchmark/ScrollBenchmark.kt
index b3704cc..f357f35 100644
--- a/wear/compose/integration-tests/macrobenchmark/src/main/java/androidx/wear/compose/integration/macrobenchmark/ScrollBenchmark.kt
+++ b/wear/compose/integration-tests/macrobenchmark/src/main/java/androidx/wear/compose/integration/macrobenchmark/ScrollBenchmark.kt
@@ -19,7 +19,9 @@
 import android.content.Intent
 import android.graphics.Point
 import androidx.benchmark.macro.CompilationMode
-import androidx.benchmark.macro.FrameTimingMetric
+import androidx.benchmark.macro.ExperimentalMetricApi
+import androidx.benchmark.macro.FrameTimingGfxInfoMetric
+import androidx.benchmark.macro.MemoryUsageMetric
 import androidx.benchmark.macro.junit4.MacrobenchmarkRule
 import androidx.test.filters.LargeTest
 import androidx.test.uiautomator.By
@@ -31,6 +33,7 @@
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
 
+@OptIn(ExperimentalMetricApi::class)
 @LargeTest
 @RunWith(Parameterized::class)
 class ScrollBenchmark(private val compilationMode: CompilationMode) {
@@ -50,7 +53,11 @@
     fun start() {
         benchmarkRule.measureRepeated(
             packageName = PACKAGE_NAME,
-            metrics = listOf(FrameTimingMetric()),
+            metrics =
+                listOf(
+                    FrameTimingGfxInfoMetric(),
+                    MemoryUsageMetric(MemoryUsageMetric.Mode.Last),
+                ),
             compilationMode = compilationMode,
             iterations = 10,
             setupBlock = {
diff --git a/wear/compose/integration-tests/macrobenchmark/src/main/java/androidx/wear/compose/integration/macrobenchmark/SwipeToDismissBenchmark.kt b/wear/compose/integration-tests/macrobenchmark/src/main/java/androidx/wear/compose/integration/macrobenchmark/SwipeToDismissBenchmark.kt
index fc09578..4e4a9072 100644
--- a/wear/compose/integration-tests/macrobenchmark/src/main/java/androidx/wear/compose/integration/macrobenchmark/SwipeToDismissBenchmark.kt
+++ b/wear/compose/integration-tests/macrobenchmark/src/main/java/androidx/wear/compose/integration/macrobenchmark/SwipeToDismissBenchmark.kt
@@ -18,7 +18,9 @@
 
 import android.content.Intent
 import androidx.benchmark.macro.CompilationMode
-import androidx.benchmark.macro.FrameTimingMetric
+import androidx.benchmark.macro.ExperimentalMetricApi
+import androidx.benchmark.macro.FrameTimingGfxInfoMetric
+import androidx.benchmark.macro.MemoryUsageMetric
 import androidx.benchmark.macro.junit4.MacrobenchmarkRule
 import androidx.test.filters.LargeTest
 import androidx.test.uiautomator.By
@@ -31,6 +33,7 @@
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
 
+@OptIn(ExperimentalMetricApi::class)
 @LargeTest
 @RunWith(Parameterized::class)
 class SwipeToDismissBenchmark(private val compilationMode: CompilationMode) {
@@ -50,7 +53,11 @@
     fun start() {
         benchmarkRule.measureRepeated(
             packageName = PACKAGE_NAME,
-            metrics = listOf(FrameTimingMetric()),
+            metrics =
+                listOf(
+                    FrameTimingGfxInfoMetric(),
+                    MemoryUsageMetric(MemoryUsageMetric.Mode.Last),
+                ),
             compilationMode = compilationMode,
             iterations = 10,
             setupBlock = {
diff --git a/wear/compose/integration-tests/macrobenchmark/src/main/java/androidx/wear/compose/integration/macrobenchmark/SwipeToRevealBenchmark.kt b/wear/compose/integration-tests/macrobenchmark/src/main/java/androidx/wear/compose/integration/macrobenchmark/SwipeToRevealBenchmark.kt
index 9845b66..9786346 100644
--- a/wear/compose/integration-tests/macrobenchmark/src/main/java/androidx/wear/compose/integration/macrobenchmark/SwipeToRevealBenchmark.kt
+++ b/wear/compose/integration-tests/macrobenchmark/src/main/java/androidx/wear/compose/integration/macrobenchmark/SwipeToRevealBenchmark.kt
@@ -18,7 +18,9 @@
 
 import android.content.Intent
 import androidx.benchmark.macro.CompilationMode
-import androidx.benchmark.macro.FrameTimingMetric
+import androidx.benchmark.macro.ExperimentalMetricApi
+import androidx.benchmark.macro.FrameTimingGfxInfoMetric
+import androidx.benchmark.macro.MemoryUsageMetric
 import androidx.benchmark.macro.junit4.MacrobenchmarkRule
 import androidx.test.filters.LargeTest
 import androidx.test.uiautomator.By
@@ -31,6 +33,7 @@
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
 
+@OptIn(ExperimentalMetricApi::class)
 @LargeTest
 @RunWith(Parameterized::class)
 class SwipeToRevealBenchmark(private val compilationMode: CompilationMode) {
@@ -50,7 +53,11 @@
     fun start() {
         benchmarkRule.measureRepeated(
             packageName = PACKAGE_NAME,
-            metrics = listOf(FrameTimingMetric()),
+            metrics =
+                listOf(
+                    FrameTimingGfxInfoMetric(),
+                    MemoryUsageMetric(MemoryUsageMetric.Mode.Last),
+                ),
             compilationMode = compilationMode,
             iterations = 10,
             setupBlock = {
diff --git a/wear/compose/integration-tests/macrobenchmark/src/main/java/androidx/wear/compose/integration/macrobenchmark/material3/DialogBenchmark.kt b/wear/compose/integration-tests/macrobenchmark/src/main/java/androidx/wear/compose/integration/macrobenchmark/material3/DialogBenchmark.kt
index 337bb62..fa6aa78 100644
--- a/wear/compose/integration-tests/macrobenchmark/src/main/java/androidx/wear/compose/integration/macrobenchmark/material3/DialogBenchmark.kt
+++ b/wear/compose/integration-tests/macrobenchmark/src/main/java/androidx/wear/compose/integration/macrobenchmark/material3/DialogBenchmark.kt
@@ -18,7 +18,9 @@
 
 import android.content.Intent
 import androidx.benchmark.macro.CompilationMode
-import androidx.benchmark.macro.FrameTimingMetric
+import androidx.benchmark.macro.ExperimentalMetricApi
+import androidx.benchmark.macro.FrameTimingGfxInfoMetric
+import androidx.benchmark.macro.MemoryUsageMetric
 import androidx.benchmark.macro.junit4.MacrobenchmarkRule
 import androidx.test.filters.LargeTest
 import androidx.test.uiautomator.By
@@ -33,6 +35,7 @@
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
 
+@OptIn(ExperimentalMetricApi::class)
 @LargeTest
 @RunWith(Parameterized::class)
 class DialogBenchmark(private val compilationMode: CompilationMode) {
@@ -52,7 +55,8 @@
     fun start() {
         benchmarkRule.measureRepeated(
             packageName = PACKAGE_NAME,
-            metrics = listOf(FrameTimingMetric()),
+            metrics =
+                listOf(FrameTimingGfxInfoMetric(), MemoryUsageMetric(MemoryUsageMetric.Mode.Last)),
             compilationMode = compilationMode,
             iterations = 5,
             setupBlock = {
diff --git a/wear/protolayout/protolayout-proto/src/main/proto/resources.proto b/wear/protolayout/protolayout-proto/src/main/proto/resources.proto
index 0409795..7e04e8a 100644
--- a/wear/protolayout/protolayout-proto/src/main/proto/resources.proto
+++ b/wear/protolayout/protolayout-proto/src/main/proto/resources.proto
@@ -3,6 +3,7 @@
 
 package androidx.wear.protolayout.proto;
 
+import "animation_parameters.proto";
 import "dynamic.proto";
 import "trigger.proto";
 
@@ -137,6 +138,25 @@
   androidx.wear.protolayout.expression.proto.DynamicFloat progress = 3;
 }
 
+// A Lottie resource that is read from a raw Android resource ID.
+message AndroidLottieResourceByResId {
+  // The Android resource ID, e.g. R.raw.foo
+  int32 raw_resource_id = 1;
+
+  // A DynamicFloat, normally transformed from certain states with the data
+  // binding pipeline to control the progress of the animation.
+  //
+  // <setter>Its value is required to fall in the range of [0.0, 1.0]. Any
+  // values outside this range would be clamped.
+  //
+  // When the first value of the DynamicFloat arrives, the animation starts from
+  // progress 0 to that value. After that it plays from current progress to the
+  // new value on subsequent updates.
+  //
+  // If not set, the animation will play on load.</setter>
+  androidx.wear.protolayout.expression.proto.DynamicFloat progress = 2;
+}
+
 // An image resource, which can be used by layouts. This holds multiple
 // underlying resource types, which the underlying runtime will pick according
 // to what it thinks is appropriate.
@@ -164,6 +184,9 @@
   // resource ID. The animation progress is bound to the provided dynamic float.
   AndroidSeekableAnimatedImageResourceByResId
       android_seekable_animated_resource_by_res_id = 7;
+
+  // A Lottie resource that is read from a raw Android resource ID.
+  AndroidLottieResourceByResId android_lottie_resource_by_res_id = 8;
 }
 
 // The resources for a layout.
diff --git a/wear/protolayout/protolayout-testing/api/current.txt b/wear/protolayout/protolayout-testing/api/current.txt
index e6f50d0..dd57766 100644
--- a/wear/protolayout/protolayout-testing/api/current.txt
+++ b/wear/protolayout/protolayout-testing/api/current.txt
@@ -1 +1,25 @@
 // Signature format: 4.0
+package androidx.wear.protolayout.testing {
+
+  public final class LayoutElementAssertion {
+    method public androidx.wear.protolayout.testing.LayoutElementAssertion assert(androidx.wear.protolayout.testing.LayoutElementMatcher matcher);
+    method public void assertDoesNotExist();
+    method public void assertExists();
+  }
+
+  public final class LayoutElementAssertionsProvider {
+    ctor public LayoutElementAssertionsProvider(androidx.wear.protolayout.LayoutElementBuilders.Layout layout);
+    ctor public LayoutElementAssertionsProvider(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement layoutRoot);
+    method public androidx.wear.protolayout.testing.LayoutElementAssertion onElement(androidx.wear.protolayout.testing.LayoutElementMatcher matcher);
+    method public androidx.wear.protolayout.testing.LayoutElementAssertion onRoot();
+  }
+
+  public final class LayoutElementMatcher {
+    ctor public LayoutElementMatcher(String description, kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.LayoutElementBuilders.LayoutElement,java.lang.Boolean> matcher);
+    method public infix androidx.wear.protolayout.testing.LayoutElementMatcher and(androidx.wear.protolayout.testing.LayoutElementMatcher other);
+    method public operator androidx.wear.protolayout.testing.LayoutElementMatcher not();
+    method public infix androidx.wear.protolayout.testing.LayoutElementMatcher or(androidx.wear.protolayout.testing.LayoutElementMatcher other);
+  }
+
+}
+
diff --git a/wear/protolayout/protolayout-testing/api/restricted_current.txt b/wear/protolayout/protolayout-testing/api/restricted_current.txt
index e6f50d0..dd57766 100644
--- a/wear/protolayout/protolayout-testing/api/restricted_current.txt
+++ b/wear/protolayout/protolayout-testing/api/restricted_current.txt
@@ -1 +1,25 @@
 // Signature format: 4.0
+package androidx.wear.protolayout.testing {
+
+  public final class LayoutElementAssertion {
+    method public androidx.wear.protolayout.testing.LayoutElementAssertion assert(androidx.wear.protolayout.testing.LayoutElementMatcher matcher);
+    method public void assertDoesNotExist();
+    method public void assertExists();
+  }
+
+  public final class LayoutElementAssertionsProvider {
+    ctor public LayoutElementAssertionsProvider(androidx.wear.protolayout.LayoutElementBuilders.Layout layout);
+    ctor public LayoutElementAssertionsProvider(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement layoutRoot);
+    method public androidx.wear.protolayout.testing.LayoutElementAssertion onElement(androidx.wear.protolayout.testing.LayoutElementMatcher matcher);
+    method public androidx.wear.protolayout.testing.LayoutElementAssertion onRoot();
+  }
+
+  public final class LayoutElementMatcher {
+    ctor public LayoutElementMatcher(String description, kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.LayoutElementBuilders.LayoutElement,java.lang.Boolean> matcher);
+    method public infix androidx.wear.protolayout.testing.LayoutElementMatcher and(androidx.wear.protolayout.testing.LayoutElementMatcher other);
+    method public operator androidx.wear.protolayout.testing.LayoutElementMatcher not();
+    method public infix androidx.wear.protolayout.testing.LayoutElementMatcher or(androidx.wear.protolayout.testing.LayoutElementMatcher other);
+  }
+
+}
+
diff --git a/wear/protolayout/protolayout-testing/build.gradle b/wear/protolayout/protolayout-testing/build.gradle
index 565226d..443c60b 100644
--- a/wear/protolayout/protolayout-testing/build.gradle
+++ b/wear/protolayout/protolayout-testing/build.gradle
@@ -31,16 +31,32 @@
 
 dependencies {
     api(libs.kotlinStdlib)
+    api(project(":wear:protolayout:protolayout"))
+    api(project(":wear:protolayout:protolayout-expression"))
     implementation("androidx.annotation:annotation:1.8.1")
+    implementation(project(":wear:protolayout:protolayout-proto"))
+    implementation(project(":wear:protolayout:protolayout-expression-pipeline"))
+
+    testImplementation(libs.junit)
+    testImplementation(libs.robolectric)
+    testImplementation(libs.testExtJunit)
+    testImplementation(libs.truth)
 }
 
 android {
+    defaultConfig {
+        minSdkVersion 26
+    }
     namespace "androidx.wear.protolayout.testing"
+
+    kotlinOptions {
+        jvmTarget = '1.8'
+    }
 }
 
 androidx {
     name = "androidx.wear.protolayout:protolayout-testing"
-    type = LibraryType.PUBLISHED_LIBRARY
+    type = LibraryType.PUBLISHED_TEST_LIBRARY
     inceptionYear = "2024"
     description = "Testing framework for protolayout element tree."
 }
diff --git a/wear/protolayout/protolayout-testing/src/main/java/androidx/wear/protolayout/testing/LayoutElementAssertion.kt b/wear/protolayout/protolayout-testing/src/main/java/androidx/wear/protolayout/testing/LayoutElementAssertion.kt
new file mode 100644
index 0000000..f34070d
--- /dev/null
+++ b/wear/protolayout/protolayout-testing/src/main/java/androidx/wear/protolayout/testing/LayoutElementAssertion.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2024 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.protolayout.testing
+
+import androidx.wear.protolayout.LayoutElementBuilders
+import java.lang.AssertionError
+
+/**
+ * Represents a layout element that can be asserted on.
+ *
+ * <p>An instance of [LayoutElementAssertion] can be obtained from 'onElement' method on a
+ * [LayoutElementAssertionsProvider].
+ */
+public class LayoutElementAssertion
+internal constructor(
+    private val elementDescription: String,
+    internal val element: LayoutElementBuilders.LayoutElement?,
+) {
+    /** Asserts that the element was found in the element tree. */
+    public fun assertExists() {
+        if (element == null) {
+            throw AssertionError("Expected $elementDescription to exist, but it does not.")
+        }
+    }
+
+    /** Asserts that no element was found in the element tree. */
+    public fun assertDoesNotExist() {
+        if (element != null) {
+            throw AssertionError("Expected $elementDescription to not exist, but it does.")
+        }
+    }
+
+    /** Asserts that the provided [LayoutElementMatcher] is satisfied for this element. */
+    public fun assert(matcher: LayoutElementMatcher): LayoutElementAssertion {
+        assertExists()
+        if (!matcher.matches(element!!)) {
+            throw AssertionError(
+                "Expected $elementDescription to match '${matcher.description}'," +
+                    " but it does not."
+            )
+        }
+        return this
+    }
+}
diff --git a/wear/protolayout/protolayout-testing/src/main/java/androidx/wear/protolayout/testing/LayoutElementAssertionsProvider.kt b/wear/protolayout/protolayout-testing/src/main/java/androidx/wear/protolayout/testing/LayoutElementAssertionsProvider.kt
new file mode 100644
index 0000000..4971419
--- /dev/null
+++ b/wear/protolayout/protolayout-testing/src/main/java/androidx/wear/protolayout/testing/LayoutElementAssertionsProvider.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2024 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.protolayout.testing
+
+import androidx.wear.protolayout.LayoutElementBuilders.Layout
+import androidx.wear.protolayout.LayoutElementBuilders.LayoutElement
+import androidx.wear.protolayout.LayoutElementBuilders.layoutElementFromProto
+
+/** Provides the main entry point into testing by exposing methods to find a layout element. */
+public class LayoutElementAssertionsProvider(layoutRoot: LayoutElement) {
+    private val root: LayoutElement =
+        layoutElementFromProto(layoutRoot.toLayoutElementProto(), null)
+
+    public constructor(layout: Layout) : this(layout.root!!)
+
+    /** Finds an element that matches the given condition. */
+    public fun onElement(matcher: LayoutElementMatcher): LayoutElementAssertion {
+        val elementDescription = "element matching '${matcher.description}'"
+        return LayoutElementAssertion(elementDescription, searchElement(root, matcher))
+    }
+
+    /**
+     * Finds the top level element of the element tree added to this
+     * [LayoutElementAssertionsProvider].
+     */
+    public fun onRoot(): LayoutElementAssertion = LayoutElementAssertion("root", root)
+
+    // TODO - b/374944199: add onAllElement which returns a LayoutElementAssertionCollection
+}
diff --git a/wear/protolayout/protolayout-testing/src/main/java/androidx/wear/protolayout/testing/LayoutElementMatcher.kt b/wear/protolayout/protolayout-testing/src/main/java/androidx/wear/protolayout/testing/LayoutElementMatcher.kt
new file mode 100644
index 0000000..77aa0c9
--- /dev/null
+++ b/wear/protolayout/protolayout-testing/src/main/java/androidx/wear/protolayout/testing/LayoutElementMatcher.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2024 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.protolayout.testing
+
+import androidx.wear.protolayout.LayoutElementBuilders.LayoutElement
+
+/**
+ * Wrapper for element matcher lambdas that allows to build string explaining to the developer what
+ * conditions are being tested.
+ *
+ * @param description a string explaining to the developer what conditions were being tested.
+ * @param matcher a lambda performing the actual logic of matching on the layout element.
+ */
+public class LayoutElementMatcher(
+    internal val description: String,
+    private val matcher: (LayoutElement) -> Boolean
+) {
+    /** Returns whether the given element is matched by this matcher. */
+    internal fun matches(element: LayoutElement): Boolean = matcher(element)
+
+    /**
+     * Returns whether the given element is matched by both this and the other mather.
+     *
+     * @param other mather that should also match in addition to current matcher.
+     */
+    public infix fun and(other: LayoutElementMatcher): LayoutElementMatcher =
+        LayoutElementMatcher("($description) && (${other.description})") {
+            matcher(it) && other.matches(it)
+        }
+
+    /**
+     * Returns whether the given element is matched by this or the other mather.
+     *
+     * @param other mather that can be tested to match if the current matcher does not.
+     */
+    public infix fun or(other: LayoutElementMatcher): LayoutElementMatcher =
+        LayoutElementMatcher("($description) || (${other.description})") {
+            matcher(it) || other.matches(it)
+        }
+
+    /** Returns whether the given element does not match the matcher. */
+    public operator fun not(): LayoutElementMatcher =
+        LayoutElementMatcher("NOT ($description)") { !matcher(it) }
+}
diff --git a/wear/protolayout/protolayout-testing/src/main/java/androidx/wear/protolayout/testing/helpers.kt b/wear/protolayout/protolayout-testing/src/main/java/androidx/wear/protolayout/testing/helpers.kt
new file mode 100644
index 0000000..de300bc
--- /dev/null
+++ b/wear/protolayout/protolayout-testing/src/main/java/androidx/wear/protolayout/testing/helpers.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2024 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.protolayout.testing
+
+import androidx.wear.protolayout.LayoutElementBuilders.Box
+import androidx.wear.protolayout.LayoutElementBuilders.Column
+import androidx.wear.protolayout.LayoutElementBuilders.LayoutElement
+import androidx.wear.protolayout.LayoutElementBuilders.Row
+
+internal val LayoutElement.children: List<LayoutElement>
+    get() =
+        when (this) {
+            is Box -> this.contents
+            is Row -> this.contents
+            is Column -> this.contents
+            // TODO b/372916396 - Dealing with Arc container and ArcLayoutElements
+            else -> emptyList<LayoutElement>()
+        }
+
+internal fun searchElement(root: LayoutElement?, matcher: LayoutElementMatcher): LayoutElement? {
+    if (root == null) return null
+    if (matcher.matches(root)) return root
+    return root.children.firstNotNullOfOrNull { searchElement(it, matcher) }
+}
diff --git a/wear/protolayout/protolayout-testing/src/main/java/androidx/wear/protolayout/testing/package-info.java b/wear/protolayout/protolayout-testing/src/main/java/androidx/wear/protolayout/testing/package-info.java
index cef88a5..46afd06 100644
--- a/wear/protolayout/protolayout-testing/src/main/java/androidx/wear/protolayout/testing/package-info.java
+++ b/wear/protolayout/protolayout-testing/src/main/java/androidx/wear/protolayout/testing/package-info.java
@@ -14,8 +14,4 @@
  * limitations under the License.
  */
 
-// TODO(b/371013214): Make protolayout-testing library public.
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
 package androidx.wear.protolayout.testing;
-
-import androidx.annotation.RestrictTo;
diff --git a/wear/protolayout/protolayout-testing/src/test/java/androidx/wear/protolayout/testing/LayoutElementAssertionTest.kt b/wear/protolayout/protolayout-testing/src/test/java/androidx/wear/protolayout/testing/LayoutElementAssertionTest.kt
new file mode 100644
index 0000000..924796a
--- /dev/null
+++ b/wear/protolayout/protolayout-testing/src/test/java/androidx/wear/protolayout/testing/LayoutElementAssertionTest.kt
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2024 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.protolayout.testing
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.wear.protolayout.LayoutElementBuilders.Box
+import androidx.wear.protolayout.LayoutElementBuilders.Text
+import com.google.common.truth.ExpectFailure.assertThat
+import org.junit.Assert.assertThrows
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.annotation.internal.DoNotInstrument
+
+@RunWith(AndroidJUnit4::class)
+@DoNotInstrument
+class LayoutElementAssertionTest {
+
+    @Test
+    fun assertExists_success() {
+        val assertion = LayoutElementAssertion(ELEMENT_DESCRIPTION, Box.Builder().build())
+
+        assertion.assertExists() // no error
+    }
+
+    @Test
+    fun assertExists_error() {
+        val assertion = LayoutElementAssertion(ELEMENT_DESCRIPTION, null)
+
+        val assertionError = assertThrows(AssertionError::class.java) { assertion.assertExists() }
+
+        assertThat(assertionError)
+            .hasMessageThat()
+            .isEqualTo("Expected $ELEMENT_DESCRIPTION to exist, but it does not.")
+    }
+
+    @Test
+    fun assertDoesNotExist_success() {
+        val assertion = LayoutElementAssertion(ELEMENT_DESCRIPTION, null)
+
+        assertion.assertDoesNotExist() // no error
+    }
+
+    @Test
+    fun assertDoesNotExist_error() {
+        val assertion = LayoutElementAssertion(ELEMENT_DESCRIPTION, Box.Builder().build())
+
+        val assertionError =
+            assertThrows(AssertionError::class.java) { assertion.assertDoesNotExist() }
+
+        assertThat(assertionError)
+            .hasMessageThat()
+            .isEqualTo("Expected $ELEMENT_DESCRIPTION to not exist, but it does.")
+    }
+
+    @Test
+    fun assert_withMatcher_success() {
+        val assertion = LayoutElementAssertion(ELEMENT_DESCRIPTION, Box.Builder().build())
+        assertion.assert(LayoutElementMatcher("Element type is Box") { it is Box })
+    }
+
+    @Test
+    fun assert_withMatcher_error() {
+        val assertion = LayoutElementAssertion(ELEMENT_DESCRIPTION, Box.Builder().build())
+        val matcher = LayoutElementMatcher("Element type is Text") { it is Text }
+
+        val assertionError = assertThrows(AssertionError::class.java) { assertion.assert(matcher) }
+
+        assertThat(assertionError)
+            .hasMessageThat()
+            .isEqualTo(
+                "Expected $ELEMENT_DESCRIPTION to match '${matcher.description}'," +
+                    " but it does not."
+            )
+    }
+
+    @Test
+    fun chainAssertions() {
+        val textContent = "testing text"
+        val assertion =
+            LayoutElementAssertion(ELEMENT_DESCRIPTION, Text.Builder().setText(textContent).build())
+        val typeMatcher = LayoutElementMatcher("Element type is Text") { it is Text }
+        val contentMatcher =
+            LayoutElementMatcher("Element text = '$textContent'") {
+                it is Text && it.text?.value == textContent
+            }
+
+        assertion.assert(typeMatcher).assert(contentMatcher)
+    }
+
+    @Test
+    fun chainAssertions_failureInFirst() {
+        val textContent = "testing text"
+        val assertion =
+            LayoutElementAssertion(ELEMENT_DESCRIPTION, Text.Builder().setText(textContent).build())
+        val firstMatcher = LayoutElementMatcher("Element type is Box") { it is Box }
+        val secondMatcher = LayoutElementMatcher("Element type is Text") { it is Text }
+
+        val assertionError =
+            assertThrows(AssertionError::class.java) {
+                assertion.assert(firstMatcher).assert(secondMatcher)
+            }
+
+        assertThat(assertionError)
+            .hasMessageThat()
+            .isEqualTo(
+                "Expected $ELEMENT_DESCRIPTION to match " +
+                    "'${firstMatcher.description}', " +
+                    "but it does not."
+            )
+    }
+
+    @Test
+    fun chainAssertions_failureInSecond() {
+        val textContent = "testing text"
+        val assertion =
+            LayoutElementAssertion(ELEMENT_DESCRIPTION, Text.Builder().setText(textContent).build())
+        val firstMatcher = LayoutElementMatcher("Element type is Text") { it is Text }
+        val secondMatcher = LayoutElementMatcher("Element type is Box") { it is Box }
+
+        val assertionError =
+            assertThrows(AssertionError::class.java) {
+                assertion.assert(firstMatcher).assert(secondMatcher)
+            }
+
+        assertThat(assertionError)
+            .hasMessageThat()
+            .isEqualTo(
+                "Expected $ELEMENT_DESCRIPTION to match " +
+                    "'${secondMatcher.description}', " +
+                    "but it does not."
+            )
+    }
+
+    companion object {
+        const val ELEMENT_DESCRIPTION = "testing element"
+    }
+}
diff --git a/wear/protolayout/protolayout-testing/src/test/java/androidx/wear/protolayout/testing/LayoutElementAssertionsProviderTest.kt b/wear/protolayout/protolayout-testing/src/test/java/androidx/wear/protolayout/testing/LayoutElementAssertionsProviderTest.kt
new file mode 100644
index 0000000..036ef7d
--- /dev/null
+++ b/wear/protolayout/protolayout-testing/src/test/java/androidx/wear/protolayout/testing/LayoutElementAssertionsProviderTest.kt
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2024 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.protolayout.testing
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.wear.protolayout.LayoutElementBuilders.Box
+import androidx.wear.protolayout.LayoutElementBuilders.Column
+import androidx.wear.protolayout.LayoutElementBuilders.Image
+import androidx.wear.protolayout.LayoutElementBuilders.Layout
+import androidx.wear.protolayout.LayoutElementBuilders.Row
+import androidx.wear.protolayout.LayoutElementBuilders.Text
+import com.google.common.truth.ExpectFailure
+import com.google.common.truth.Truth.assertThat
+import junit.framework.TestCase.assertTrue
+import org.junit.Assert.assertThrows
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.annotation.internal.DoNotInstrument
+
+@RunWith(AndroidJUnit4::class)
+@DoNotInstrument
+class LayoutElementAssertionsProviderTest {
+
+    @Test
+    fun primaryConstructor_onRoot() {
+        assertTrue(LayoutElementAssertionsProvider(TEST_LAYOUT.root!!).onRoot().element is Box)
+    }
+
+    @Test
+    fun secondaryConstructor_onRoot() {
+        assertTrue(LayoutElementAssertionsProvider(TEST_LAYOUT).onRoot().element is Box)
+    }
+
+    @Test
+    fun onRoot_description() {
+        val assertionError =
+            assertThrows(AssertionError::class.java) {
+                LayoutElementAssertionsProvider(TEST_LAYOUT).onRoot().assertDoesNotExist()
+            }
+
+        val rootDescription = "root"
+
+        ExpectFailure.assertThat(assertionError)
+            .hasMessageThat()
+            .isEqualTo("Expected $rootDescription to not exist, but it does.")
+    }
+
+    @Test
+    fun onElement_isImage() {
+        val firstImageElement =
+            LayoutElementAssertionsProvider(TEST_LAYOUT).onElement(isImage).element as Image
+        assertThat(firstImageElement.resourceId!!.value).isEqualTo("image1")
+    }
+
+    @Test
+    fun onElement_isText() {
+        val firstTextElement =
+            LayoutElementAssertionsProvider(TEST_LAYOUT).onElement(isText).element as Text
+        assertThat(firstTextElement.text!!.value).isEqualTo("text1")
+    }
+
+    @Test
+    fun onElement_description() {
+        val assertionError =
+            assertThrows(AssertionError::class.java) {
+                LayoutElementAssertionsProvider(TEST_LAYOUT).onElement(isText).assertDoesNotExist()
+            }
+
+        val elementDescription = "element matching '${isText.description}'"
+
+        ExpectFailure.assertThat(assertionError)
+            .hasMessageThat()
+            .isEqualTo("Expected $elementDescription to not exist, but it does.")
+    }
+
+    companion object {
+        val isBox = LayoutElementMatcher("Element type is Box") { it is Box }
+        val isImage = LayoutElementMatcher("Element type is Image") { it is Image }
+        val isText = LayoutElementMatcher("Element type is Text") { it is Text }
+        val TEST_LAYOUT =
+            Layout.Builder()
+                .setRoot(
+                    Box.Builder()
+                        .addContent(
+                            Row.Builder()
+                                .addContent(Image.Builder().setResourceId("image1").build())
+                                .addContent(Image.Builder().setResourceId("image2").build())
+                                .build()
+                        )
+                        .addContent(
+                            Column.Builder()
+                                .addContent(Text.Builder().setText("text1").build())
+                                .addContent(Text.Builder().setText("text2").build())
+                                .build()
+                        )
+                        .build()
+                )
+                .build()
+    }
+}
diff --git a/wear/protolayout/protolayout/api/current.txt b/wear/protolayout/protolayout/api/current.txt
index 721be43..7ef6729 100644
--- a/wear/protolayout/protolayout/api/current.txt
+++ b/wear/protolayout/protolayout/api/current.txt
@@ -1242,6 +1242,17 @@
     method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=0) public androidx.wear.protolayout.ResourceBuilders.AndroidImageResourceByResId.Builder setResourceId(@DrawableRes int);
   }
 
+  @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=500) public static final class ResourceBuilders.AndroidLottieResourceByResId {
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat? getProgress();
+    method @RawRes public int getRawResourceId();
+  }
+
+  public static final class ResourceBuilders.AndroidLottieResourceByResId.Builder {
+    ctor @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=500) public ResourceBuilders.AndroidLottieResourceByResId.Builder(@RawRes int);
+    method public androidx.wear.protolayout.ResourceBuilders.AndroidLottieResourceByResId build();
+    method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=500) public androidx.wear.protolayout.ResourceBuilders.AndroidLottieResourceByResId.Builder setProgress(androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat);
+  }
+
   @SuppressCompatibility @androidx.wear.protolayout.expression.ProtoLayoutExperimental @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=200) public static final class ResourceBuilders.AndroidSeekableAnimatedImageResourceByResId {
     method public int getAnimatedImageFormat();
     method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat? getProgress();
@@ -1258,6 +1269,7 @@
 
   @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=0) public static final class ResourceBuilders.ImageResource {
     method @SuppressCompatibility @androidx.wear.protolayout.expression.ProtoLayoutExperimental public androidx.wear.protolayout.ResourceBuilders.AndroidAnimatedImageResourceByResId? getAndroidAnimatedResourceByResId();
+    method public androidx.wear.protolayout.ResourceBuilders.AndroidLottieResourceByResId? getAndroidLottieResourceByResId();
     method public androidx.wear.protolayout.ResourceBuilders.AndroidImageResourceByResId? getAndroidResourceByResId();
     method @SuppressCompatibility @androidx.wear.protolayout.expression.ProtoLayoutExperimental public androidx.wear.protolayout.ResourceBuilders.AndroidSeekableAnimatedImageResourceByResId? getAndroidSeekableAnimatedResourceByResId();
     method public androidx.wear.protolayout.ResourceBuilders.InlineImageResource? getInlineResource();
@@ -1267,6 +1279,7 @@
     ctor public ResourceBuilders.ImageResource.Builder();
     method public androidx.wear.protolayout.ResourceBuilders.ImageResource build();
     method @SuppressCompatibility @androidx.wear.protolayout.expression.ProtoLayoutExperimental @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=200) public androidx.wear.protolayout.ResourceBuilders.ImageResource.Builder setAndroidAnimatedResourceByResId(androidx.wear.protolayout.ResourceBuilders.AndroidAnimatedImageResourceByResId);
+    method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=500) public androidx.wear.protolayout.ResourceBuilders.ImageResource.Builder setAndroidLottieResourceByResId(androidx.wear.protolayout.ResourceBuilders.AndroidLottieResourceByResId);
     method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=0) public androidx.wear.protolayout.ResourceBuilders.ImageResource.Builder setAndroidResourceByResId(androidx.wear.protolayout.ResourceBuilders.AndroidImageResourceByResId);
     method @SuppressCompatibility @androidx.wear.protolayout.expression.ProtoLayoutExperimental @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=200) public androidx.wear.protolayout.ResourceBuilders.ImageResource.Builder setAndroidSeekableAnimatedResourceByResId(androidx.wear.protolayout.ResourceBuilders.AndroidSeekableAnimatedImageResourceByResId);
     method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=0) public androidx.wear.protolayout.ResourceBuilders.ImageResource.Builder setInlineResource(androidx.wear.protolayout.ResourceBuilders.InlineImageResource);
diff --git a/wear/protolayout/protolayout/api/restricted_current.txt b/wear/protolayout/protolayout/api/restricted_current.txt
index 721be43..7ef6729 100644
--- a/wear/protolayout/protolayout/api/restricted_current.txt
+++ b/wear/protolayout/protolayout/api/restricted_current.txt
@@ -1242,6 +1242,17 @@
     method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=0) public androidx.wear.protolayout.ResourceBuilders.AndroidImageResourceByResId.Builder setResourceId(@DrawableRes int);
   }
 
+  @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=500) public static final class ResourceBuilders.AndroidLottieResourceByResId {
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat? getProgress();
+    method @RawRes public int getRawResourceId();
+  }
+
+  public static final class ResourceBuilders.AndroidLottieResourceByResId.Builder {
+    ctor @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=500) public ResourceBuilders.AndroidLottieResourceByResId.Builder(@RawRes int);
+    method public androidx.wear.protolayout.ResourceBuilders.AndroidLottieResourceByResId build();
+    method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=500) public androidx.wear.protolayout.ResourceBuilders.AndroidLottieResourceByResId.Builder setProgress(androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat);
+  }
+
   @SuppressCompatibility @androidx.wear.protolayout.expression.ProtoLayoutExperimental @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=200) public static final class ResourceBuilders.AndroidSeekableAnimatedImageResourceByResId {
     method public int getAnimatedImageFormat();
     method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat? getProgress();
@@ -1258,6 +1269,7 @@
 
   @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=0) public static final class ResourceBuilders.ImageResource {
     method @SuppressCompatibility @androidx.wear.protolayout.expression.ProtoLayoutExperimental public androidx.wear.protolayout.ResourceBuilders.AndroidAnimatedImageResourceByResId? getAndroidAnimatedResourceByResId();
+    method public androidx.wear.protolayout.ResourceBuilders.AndroidLottieResourceByResId? getAndroidLottieResourceByResId();
     method public androidx.wear.protolayout.ResourceBuilders.AndroidImageResourceByResId? getAndroidResourceByResId();
     method @SuppressCompatibility @androidx.wear.protolayout.expression.ProtoLayoutExperimental public androidx.wear.protolayout.ResourceBuilders.AndroidSeekableAnimatedImageResourceByResId? getAndroidSeekableAnimatedResourceByResId();
     method public androidx.wear.protolayout.ResourceBuilders.InlineImageResource? getInlineResource();
@@ -1267,6 +1279,7 @@
     ctor public ResourceBuilders.ImageResource.Builder();
     method public androidx.wear.protolayout.ResourceBuilders.ImageResource build();
     method @SuppressCompatibility @androidx.wear.protolayout.expression.ProtoLayoutExperimental @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=200) public androidx.wear.protolayout.ResourceBuilders.ImageResource.Builder setAndroidAnimatedResourceByResId(androidx.wear.protolayout.ResourceBuilders.AndroidAnimatedImageResourceByResId);
+    method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=500) public androidx.wear.protolayout.ResourceBuilders.ImageResource.Builder setAndroidLottieResourceByResId(androidx.wear.protolayout.ResourceBuilders.AndroidLottieResourceByResId);
     method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=0) public androidx.wear.protolayout.ResourceBuilders.ImageResource.Builder setAndroidResourceByResId(androidx.wear.protolayout.ResourceBuilders.AndroidImageResourceByResId);
     method @SuppressCompatibility @androidx.wear.protolayout.expression.ProtoLayoutExperimental @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=200) public androidx.wear.protolayout.ResourceBuilders.ImageResource.Builder setAndroidSeekableAnimatedResourceByResId(androidx.wear.protolayout.ResourceBuilders.AndroidSeekableAnimatedImageResourceByResId);
     method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=0) public androidx.wear.protolayout.ResourceBuilders.ImageResource.Builder setInlineResource(androidx.wear.protolayout.ResourceBuilders.InlineImageResource);
diff --git a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ResourceBuilders.java b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ResourceBuilders.java
index 8fdc539..72d7ef0 100644
--- a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ResourceBuilders.java
+++ b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ResourceBuilders.java
@@ -26,6 +26,7 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.OptIn;
+import androidx.annotation.RawRes;
 import androidx.annotation.RestrictTo;
 import androidx.annotation.RestrictTo.Scope;
 import androidx.wear.protolayout.TriggerBuilders.Trigger;
@@ -518,6 +519,118 @@
         }
     }
 
+    /** A Lottie resource that is read from a raw Android resource ID. */
+    @RequiresSchemaVersion(major = 1, minor = 500)
+    public static final class AndroidLottieResourceByResId {
+        private final ResourceProto.AndroidLottieResourceByResId mImpl;
+
+        AndroidLottieResourceByResId(ResourceProto.AndroidLottieResourceByResId impl) {
+            this.mImpl = impl;
+        }
+
+        /** Gets the Android resource ID, e.g. R.raw.foo. */
+        @RawRes
+        public int getRawResourceId() {
+            return mImpl.getRawResourceId();
+        }
+
+        /**
+         * Gets a {@link androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat},
+         * normally transformed from certain states with the data binding pipeline to control the
+         * progress of the animation.
+         */
+        @Nullable
+        public DynamicFloat getProgress() {
+            if (mImpl.hasProgress()) {
+                return DynamicBuilders.dynamicFloatFromProto(mImpl.getProgress());
+            } else {
+                return null;
+            }
+        }
+
+        /** Creates a new wrapper instance from the proto. */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        public static AndroidLottieResourceByResId fromProto(
+                @NonNull ResourceProto.AndroidLottieResourceByResId proto) {
+            return new AndroidLottieResourceByResId(proto);
+        }
+
+        /** Returns the internal proto instance. */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        public ResourceProto.AndroidLottieResourceByResId toProto() {
+            return mImpl;
+        }
+
+        @Override
+        @NonNull
+        public String toString() {
+            return "AndroidLottieResourceByResId{"
+                    + "rawResourceId="
+                    + getRawResourceId()
+                    + ", progress="
+                    + getProgress()
+                    + "}";
+        }
+
+        /** Builder for {@link AndroidLottieResourceByResId} */
+        public static final class Builder {
+            private final ResourceProto.AndroidLottieResourceByResId.Builder mImpl =
+                    ResourceProto.AndroidLottieResourceByResId.newBuilder();
+
+            /**
+             * Creates an instance of {@link Builder}.
+             *
+             * @param resourceId the Android resource ID, e.g. R.raw.foo.
+             */
+            @RequiresSchemaVersion(major = 1, minor = 500)
+            @SuppressLint("CheckResult") // (b/247804720)
+            public Builder(@RawRes int resourceId) {
+                setRawResourceId(resourceId);
+            }
+
+            @RequiresSchemaVersion(major = 1, minor = 500)
+            Builder() {}
+
+            /** Sets the Android resource ID, e.g. R.raw.foo. */
+            @RequiresSchemaVersion(major = 1, minor = 500)
+            @NonNull
+            Builder setRawResourceId(@RawRes int rawResourceId) {
+                mImpl.setRawResourceId(rawResourceId);
+                return this;
+            }
+
+            /**
+             * Sets a {@link androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat},
+             * normally transformed from certain states with the data binding pipeline to control
+             * the progress of the animation.
+             *
+             * <p>Its value is required to fall in the range of [0.0, 1.0]. Any values outside this
+             * range would be clamped.
+             *
+             * <p>When the first value of the {@link
+             * androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat} arrives, the
+             * animation starts from progress 0 to that value. After that it plays from current
+             * progress to the new value on subsequent updates.
+             *
+             * <p>If not set, the animation will play on load.
+             */
+            @RequiresSchemaVersion(major = 1, minor = 500)
+            @NonNull
+            public Builder setProgress(@NonNull DynamicFloat progress) {
+                mImpl.setProgress(progress.toDynamicFloatProto());
+                return this;
+            }
+
+            /** Builds an instance from accumulated values. */
+            @NonNull
+            public AndroidLottieResourceByResId build() {
+                return AndroidLottieResourceByResId.fromProto(mImpl.build());
+            }
+        }
+    }
+
     /**
      * An image resource, which can be used by layouts. This holds multiple underlying resource
      * types, which the underlying runtime will pick according to what it thinks is appropriate.
@@ -581,6 +694,17 @@
             }
         }
 
+        /** Gets a Lottie resource that is read from a raw Android resource ID. */
+        @Nullable
+        public AndroidLottieResourceByResId getAndroidLottieResourceByResId() {
+            if (mImpl.hasAndroidLottieResourceByResId()) {
+                return AndroidLottieResourceByResId.fromProto(
+                        mImpl.getAndroidLottieResourceByResId());
+            } else {
+                return null;
+            }
+        }
+
         /** Creates a new wrapper instance from the proto. */
         @RestrictTo(Scope.LIBRARY_GROUP)
         @NonNull
@@ -608,6 +732,8 @@
                     + getAndroidAnimatedResourceByResId()
                     + ", androidSeekableAnimatedResourceByResId="
                     + getAndroidSeekableAnimatedResourceByResId()
+                    + ", androidLottieResourceByResId="
+                    + getAndroidLottieResourceByResId()
                     + "}";
         }
 
@@ -665,6 +791,15 @@
                 return this;
             }
 
+            /** sets a Lottie resource that is read from a raw Android resource ID. */
+            @RequiresSchemaVersion(major = 1, minor = 500)
+            @NonNull
+            public Builder setAndroidLottieResourceByResId(
+                    @NonNull AndroidLottieResourceByResId androidLottieResourceByResId) {
+                mImpl.setAndroidLottieResourceByResId(androidLottieResourceByResId.toProto());
+                return this;
+            }
+
             /** Builds an instance from accumulated values. */
             @NonNull
             public ImageResource build() {
diff --git a/wear/protolayout/protolayout/src/test/java/androidx/wear/protolayout/ResourceBuildersTest.java b/wear/protolayout/protolayout/src/test/java/androidx/wear/protolayout/ResourceBuildersTest.java
index 7f63205..3591875 100644
--- a/wear/protolayout/protolayout/src/test/java/androidx/wear/protolayout/ResourceBuildersTest.java
+++ b/wear/protolayout/protolayout/src/test/java/androidx/wear/protolayout/ResourceBuildersTest.java
@@ -65,4 +65,18 @@
         assertThat(avdProto.getAnimatedImageFormat().getNumber()).isEqualTo(FORMAT);
         assertThat(avdProto.getProgress().getStateSource().getSourceKey()).isEqualTo(stateKey);
     }
+
+    @Test
+    public void lottieAnimation() {
+        String stateKey = "state-key";
+        ResourceBuilders.AndroidLottieResourceByResId lottieResource =
+                new ResourceBuilders.AndroidLottieResourceByResId.Builder(RESOURCE_ID)
+                        .setProgress(DynamicBuilders.DynamicFloat.from(new AppDataKey<>(stateKey)))
+                        .build();
+
+        ResourceProto.AndroidLottieResourceByResId avdProto = lottieResource.toProto();
+
+        assertThat(avdProto.getRawResourceId()).isEqualTo(RESOURCE_ID);
+        assertThat(avdProto.getProgress().getStateSource().getSourceKey()).isEqualTo(stateKey);
+    }
 }