Merge "feat: supress Experimental Carousel features until we launch RC candidate" into androidx-main
diff --git a/activity/activity/src/androidTest/java/androidx/activity/ComponentDialogTest.kt b/activity/activity/src/androidTest/java/androidx/activity/ComponentDialogTest.kt
index b914f18..9517064e 100644
--- a/activity/activity/src/androidTest/java/androidx/activity/ComponentDialogTest.kt
+++ b/activity/activity/src/androidTest/java/androidx/activity/ComponentDialogTest.kt
@@ -31,7 +31,6 @@
 import com.google.common.truth.Truth.assertThat
 import com.google.common.truth.Truth.assertWithMessage
 import leakcanary.DetectLeaksAfterTestSuccess
-import org.junit.Ignore
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -44,7 +43,6 @@
     @get:Rule
     val rule = DetectLeaksAfterTestSuccess()
 
-    @Ignore("b/286303870")
     @Test
     fun testLifecycle() {
        withUse(ActivityScenario.launch(EmptyContentActivity::class.java)) {
diff --git a/activity/integration-tests/testapp/build.gradle b/activity/integration-tests/testapp/build.gradle
index 24d7a2e..ce12c4a 100644
--- a/activity/integration-tests/testapp/build.gradle
+++ b/activity/integration-tests/testapp/build.gradle
@@ -35,6 +35,7 @@
     implementation("androidx.core:core-splashscreen:1.0.0")
 
     // Manually align dependencies across debugRuntime and debugAndroidTestRuntime.
+    androidTestImplementation(project(":annotation:annotation"))
     androidTestImplementation("androidx.annotation:annotation-experimental:1.4.0")
 
     androidTestImplementation(libs.kotlinStdlib)
diff --git a/appcompat/integration-tests/receive-content-testapp/build.gradle b/appcompat/integration-tests/receive-content-testapp/build.gradle
index 0a9360b..118297f 100644
--- a/appcompat/integration-tests/receive-content-testapp/build.gradle
+++ b/appcompat/integration-tests/receive-content-testapp/build.gradle
@@ -35,6 +35,7 @@
     implementation(libs.material)
 
     // Align dependencies in debugRuntimeClasspath and debugAndroidTestRuntimeClasspath.
+    androidTestImplementation(project(":annotation:annotation"))
     androidTestImplementation("androidx.annotation:annotation-experimental:1.4.0")
 
     androidTestImplementation("androidx.lifecycle:lifecycle-common:2.6.1")
diff --git a/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/utils/AgpPlugin.kt b/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/utils/AgpPlugin.kt
index ae1c025..583f424 100644
--- a/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/utils/AgpPlugin.kt
+++ b/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/utils/AgpPlugin.kt
@@ -226,6 +226,9 @@
 
     private fun checkAgpVersion() {
         val agpVersion = project.agpVersion()
+        if (agpVersion.previewType == "dev") {
+            return // Skip version check for androidx-studio-integration branch
+        }
         if (agpVersion < minAgpVersionInclusive) {
             throw GradleException(
                 """
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoConfig.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoConfig.kt
index 561d71c..7eda4fc 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoConfig.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoConfig.kt
@@ -34,6 +34,7 @@
 import perfetto.protos.TraceConfig
 import perfetto.protos.TraceConfig.BufferConfig
 import perfetto.protos.TraceConfig.BufferConfig.FillPolicy
+import perfetto.protos.TrackEventConfig
 
 /**
  * Configuration for Perfetto trace recording.
@@ -333,7 +334,12 @@
         TraceConfig.DataSource(DataSourceConfig("android.gpu.memory")),
         TraceConfig.DataSource(DataSourceConfig("android.surfaceflinger.frame")),
         TraceConfig.DataSource(DataSourceConfig("android.surfaceflinger.frametimeline")),
-        TraceConfig.DataSource(DataSourceConfig("track_event")) // required by tracing-perfetto
+        TraceConfig.DataSource(DataSourceConfig(
+            "track_event",
+            track_event_config = TrackEventConfig(
+                enabled_categories = listOf("*") // required by tracing-perfetto
+            )
+        ))
     )
     if (stackSamplingConfig != null) {
         dataSources += stackSamplingSource(
diff --git a/benchmark/benchmark-macro-junit4/src/main/java/androidx/benchmark/macro/junit4/InstrumentationResultsRunListener.kt b/benchmark/benchmark-macro-junit4/src/main/java/androidx/benchmark/macro/junit4/InstrumentationResultsRunListener.kt
new file mode 100644
index 0000000..d93e294
--- /dev/null
+++ b/benchmark/benchmark-macro-junit4/src/main/java/androidx/benchmark/macro/junit4/InstrumentationResultsRunListener.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.benchmark.macro.junit4
+
+import android.os.Bundle
+import android.util.Log
+import androidx.annotation.RestrictTo
+import androidx.benchmark.InstrumentationResults
+import androidx.test.internal.runner.listener.InstrumentationRunListener
+import java.io.PrintStream
+import org.junit.runner.Result
+
+/**
+ * Used to register files to copy at the end of the entire test run in CI.
+ *
+ * See [InstrumentationResults.runEndResultBundle]
+ */
+@Suppress("unused", "RestrictedApiAndroidX") // referenced by inst arg at runtime
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+class InstrumentationResultsRunListener : InstrumentationRunListener() {
+    override fun instrumentationRunFinished(
+        streamResult: PrintStream?,
+        resultBundle: Bundle,
+        junitResults: Result?
+    ) {
+        Log.d("Benchmark", "InstrumentationResultsRunListener#instrumentationRunFinished")
+        resultBundle.putAll(InstrumentationResults.runEndResultBundle)
+    }
+}
diff --git a/benchmark/benchmark-macro-junit4/src/main/java/androidx/benchmark/macro/junit4/SideEffectRunListener.kt b/benchmark/benchmark-macro-junit4/src/main/java/androidx/benchmark/macro/junit4/SideEffectRunListener.kt
index 3aaa557..17ddf62 100644
--- a/benchmark/benchmark-macro-junit4/src/main/java/androidx/benchmark/macro/junit4/SideEffectRunListener.kt
+++ b/benchmark/benchmark-macro-junit4/src/main/java/androidx/benchmark/macro/junit4/SideEffectRunListener.kt
@@ -16,6 +16,7 @@
 
 package androidx.benchmark.macro.junit4
 
+import android.util.Log
 import androidx.annotation.RestrictTo
 import androidx.benchmark.DisableDexOpt
 import androidx.benchmark.DisablePackages
@@ -27,6 +28,7 @@
 /**
  * Enables the use of side-effects that reduce the noise during a macro benchmark run.
  */
+@Suppress("unused") // referenced by inst arg at runtime
 @RestrictTo(RestrictTo.Scope.LIBRARY)
 class SideEffectRunListener : RunListener() {
     private val delegate: RunListenerDelegate = RunListenerDelegate(
@@ -38,11 +40,13 @@
 
     override fun testRunStarted(description: Description) {
         super.testRunStarted(description)
+        Log.d("Benchmark", "SideEffectRunListener#onTestRunStarted")
         delegate.onTestRunStarted()
     }
 
     override fun testRunFinished(result: Result) {
         super.testRunFinished(result)
+        Log.d("Benchmark", "SideEffectRunListener#onTestRunFinished")
         delegate.onTestRunFinished()
     }
 }
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/StartupTimingQuery.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/StartupTimingQuery.kt
index 13876b5..38076ff 100644
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/StartupTimingQuery.kt
+++ b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/StartupTimingQuery.kt
@@ -94,15 +94,23 @@
     private fun findEndRenderTimeForUiFrame(
         uiSlices: List<Slice>,
         rtSlices: List<Slice>,
+        predicateErrorLabel: String,
         predicate: (Slice) -> Boolean
     ): Long {
         // find first UI slice that corresponds with the predicate
-        val uiSlice = uiSlices.first(predicate)
+        val uiSlice = uiSlices.firstOrNull(predicate)
+
+        check(uiSlice != null) { "No Choreographer#doFrame $predicateErrorLabel" }
 
         // find corresponding rt slice
-        val rtSlice = rtSlices.first { rtSlice ->
+        val rtSlice = rtSlices.firstOrNull { rtSlice ->
             rtSlice.ts > uiSlice.ts
         }
+
+        check(rtSlice != null) {
+            "No RT frame slice associated with UI thread frame slice $predicateErrorLabel"
+        }
+
         return rtSlice.endTs
     }
 
@@ -140,7 +148,7 @@
         val rtSlices = groupedData.getOrElse(StartupSliceType.FrameRenderThread) { listOf() }
 
         if (uiSlices.isEmpty() || rtSlices.isEmpty()) {
-            Log.d("Benchmark", "No UI / RT slices seen, not reporting startup.")
+            Log.w("Benchmark", "No UI / RT slices seen, not reporting startup.")
             return null
         }
 
@@ -151,13 +159,23 @@
             val launchingSlice = groupedData[StartupSliceType.Launching]?.firstOrNull {
                 // verify full name only on API 23+, since before package name not specified
                 (captureApiLevel < 23 || it.name == "launching: $targetPackageName")
-            } ?: return null
+            } ?: run {
+                Log.w("Benchmark", "No launching slice seen, not reporting startup.")
+                return null
+            }
 
             startTs = if (captureApiLevel >= 29) {
                 // Starting on API 29, expect to see 'notify started' system_server slice
                 val notifyStartedSlice = groupedData[StartupSliceType.NotifyStarted]?.lastOrNull {
                     it.ts < launchingSlice.ts
-                } ?: return null
+                } ?: run {
+                    Log.w(
+                        "Benchmark",
+                        "No launchObserverNotifyIntentStarted slice seen before launching: " +
+                            "slice, not reporting startup."
+                    )
+                    return null
+                }
                 notifyStartedSlice.ts
             } else {
                 launchingSlice.ts
@@ -167,15 +185,26 @@
             // both because on some platforms the launching slice may not wait for renderthread, but
             // also because this allows us to make the guarantee that timeToInitialDisplay ==
             // timeToFirstDisplay when they are the same frame.
-            initialDisplayTs = findEndRenderTimeForUiFrame(uiSlices, rtSlices) { uiSlice ->
+            initialDisplayTs = findEndRenderTimeForUiFrame(
+                uiSlices = uiSlices,
+                rtSlices = rtSlices,
+                predicateErrorLabel = "after launching slice"
+            ) { uiSlice ->
                 uiSlice.ts > launchingSlice.ts
             }
         } else {
             // Prior to API 29, hot starts weren't traced with the launching slice, so we do a best
             // guess - the time taken to Activity#onResume, and then produce the next frame.
             startTs = groupedData[StartupSliceType.ActivityResume]?.first()?.ts
-                ?: return null
-            initialDisplayTs = findEndRenderTimeForUiFrame(uiSlices, rtSlices) { uiSlice ->
+                ?: run {
+                    Log.w("Benchmark", "No activityResume slice, not reporting startup.")
+                    return null
+                }
+            initialDisplayTs = findEndRenderTimeForUiFrame(
+                uiSlices = uiSlices,
+                rtSlices = rtSlices,
+                predicateErrorLabel = "after activityResume"
+            ) { uiSlice ->
                 uiSlice.ts > startTs
             }
         }
@@ -185,7 +214,11 @@
         val reportFullyDrawnEndTs: Long? = reportFullyDrawnSlice?.let {
             // find first uiSlice with end after reportFullyDrawn (reportFullyDrawn may happen
             // during or before a given frame)
-            findEndRenderTimeForUiFrame(uiSlices, rtSlices) { uiSlice ->
+            findEndRenderTimeForUiFrame(
+                uiSlices = uiSlices,
+                rtSlices = rtSlices,
+                predicateErrorLabel = "ends after reportFullyDrawn"
+            ) { uiSlice ->
                 uiSlice.endTs > reportFullyDrawnSlice.ts
             }
         }
diff --git a/benchmark/integration-tests/macrobenchmark/build.gradle b/benchmark/integration-tests/macrobenchmark/build.gradle
index 07b8c7f..ec90c5b 100644
--- a/benchmark/integration-tests/macrobenchmark/build.gradle
+++ b/benchmark/integration-tests/macrobenchmark/build.gradle
@@ -57,7 +57,7 @@
 androidComponents { beforeVariants(selector().all()) { enabled = buildType == 'release' } }
 
 dependencies {
-    implementation(project(":benchmark:benchmark-junit4"))
+    implementation(project(":benchmark:benchmark-common"))
     implementation(project(":benchmark:benchmark-macro-junit4"))
     implementation(project(":internal-testutils-macrobenchmark"))
     implementation(project(":tracing:tracing-ktx"))
diff --git a/biometric/biometric/src/main/res/values-b+sr+Latn/strings.xml b/biometric/biometric/src/main/res/values-b+sr+Latn/strings.xml
index de4ee97..68e7ac4 100644
--- a/biometric/biometric/src/main/res/values-b+sr+Latn/strings.xml
+++ b/biometric/biometric/src/main/res/values-b+sr+Latn/strings.xml
@@ -33,15 +33,15 @@
     <string name="use_fingerprint_label" msgid="6961788485681412417">"Koristite otisak prsta"</string>
     <string name="use_face_label" msgid="6533512708069459542">"Koristite lice"</string>
     <string name="use_biometric_label" msgid="6524145989441579428">"Koristite biometriju"</string>
-    <string name="use_screen_lock_label" msgid="5459869335976243512">"Koristi zaključavanje ekrana"</string>
-    <string name="use_fingerprint_or_screen_lock_label" msgid="7577690399303139443">"Koristite otisak prsta ili zaključavanje ekrana"</string>
-    <string name="use_face_or_screen_lock_label" msgid="2116180187159450292">"Koristite zaključavanje licem ili zaključavanje ekrana"</string>
-    <string name="use_biometric_or_screen_lock_label" msgid="5385448280139639016">"Koristite biometriju ili zaključavanje ekrana"</string>
+    <string name="use_screen_lock_label" msgid="5459869335976243512">"Koristi otključavanje ekrana"</string>
+    <string name="use_fingerprint_or_screen_lock_label" msgid="7577690399303139443">"Koristite otisak prsta ili otključavanje ekrana"</string>
+    <string name="use_face_or_screen_lock_label" msgid="2116180187159450292">"Koristite zaključavanje licem ili otključavanje ekrana"</string>
+    <string name="use_biometric_or_screen_lock_label" msgid="5385448280139639016">"Koristite biometriju ili otključavanje ekrana"</string>
     <string name="fingerprint_prompt_message" msgid="7449360011861769080">"Nastavite pomoću otiska prsta"</string>
     <string name="face_prompt_message" msgid="2282389249605674226">"Potvrdite identitet licem da biste nastavili"</string>
     <string name="biometric_prompt_message" msgid="1160635338192065472">"Koristite biometrijski podatak da biste nastavili"</string>
-    <string name="screen_lock_prompt_message" msgid="5659570757430909869">"Upotrebite zaključavanje ekrana da biste nastavili"</string>
-    <string name="fingerprint_or_screen_lock_prompt_message" msgid="8382576858490514495">"Koristite otisak prsta ili zaključavanje ekrana da biste nastavili"</string>
-    <string name="face_or_screen_lock_prompt_message" msgid="4562557128765735254">"Koristite lice ili zaključavanje ekrana da biste nastavili"</string>
-    <string name="biometric_or_screen_lock_prompt_message" msgid="2102429900219199821">"Koristite biometrijski podatak ili zaključavanje ekrana da biste nastavili"</string>
+    <string name="screen_lock_prompt_message" msgid="5659570757430909869">"Upotrebite otključavanje ekrana da biste nastavili"</string>
+    <string name="fingerprint_or_screen_lock_prompt_message" msgid="8382576858490514495">"Koristite otisak prsta ili otključavanje ekrana da biste nastavili"</string>
+    <string name="face_or_screen_lock_prompt_message" msgid="4562557128765735254">"Koristite lice ili otključavanje ekrana da biste nastavili"</string>
+    <string name="biometric_or_screen_lock_prompt_message" msgid="2102429900219199821">"Koristite biometrijski podatak ili otključavanje ekrana da biste nastavili"</string>
 </resources>
diff --git a/biometric/biometric/src/main/res/values-sr/strings.xml b/biometric/biometric/src/main/res/values-sr/strings.xml
index 3b8204b..bf059e9 100644
--- a/biometric/biometric/src/main/res/values-sr/strings.xml
+++ b/biometric/biometric/src/main/res/values-sr/strings.xml
@@ -33,15 +33,15 @@
     <string name="use_fingerprint_label" msgid="6961788485681412417">"Користите отисак прста"</string>
     <string name="use_face_label" msgid="6533512708069459542">"Користите лице"</string>
     <string name="use_biometric_label" msgid="6524145989441579428">"Користите биометрију"</string>
-    <string name="use_screen_lock_label" msgid="5459869335976243512">"Користи закључавање екрана"</string>
-    <string name="use_fingerprint_or_screen_lock_label" msgid="7577690399303139443">"Користите отисак прста или закључавање екрана"</string>
-    <string name="use_face_or_screen_lock_label" msgid="2116180187159450292">"Користите закључавање лицем или закључавање екрана"</string>
-    <string name="use_biometric_or_screen_lock_label" msgid="5385448280139639016">"Користите биометрију или закључавање екрана"</string>
+    <string name="use_screen_lock_label" msgid="5459869335976243512">"Користи откључавање екрана"</string>
+    <string name="use_fingerprint_or_screen_lock_label" msgid="7577690399303139443">"Користите отисак прста или откључавање екрана"</string>
+    <string name="use_face_or_screen_lock_label" msgid="2116180187159450292">"Користите закључавање лицем или откључавање екрана"</string>
+    <string name="use_biometric_or_screen_lock_label" msgid="5385448280139639016">"Користите биометрију или откључавање екрана"</string>
     <string name="fingerprint_prompt_message" msgid="7449360011861769080">"Наставите помоћу отиска прста"</string>
     <string name="face_prompt_message" msgid="2282389249605674226">"Потврдите идентитет лицем да бисте наставили"</string>
     <string name="biometric_prompt_message" msgid="1160635338192065472">"Користите биометријски податак да бисте наставили"</string>
-    <string name="screen_lock_prompt_message" msgid="5659570757430909869">"Употребите закључавање екрана да бисте наставили"</string>
-    <string name="fingerprint_or_screen_lock_prompt_message" msgid="8382576858490514495">"Користите отисак прста или закључавање екрана да бисте наставили"</string>
-    <string name="face_or_screen_lock_prompt_message" msgid="4562557128765735254">"Користите лице или закључавање екрана да бисте наставили"</string>
-    <string name="biometric_or_screen_lock_prompt_message" msgid="2102429900219199821">"Користите биометријски податак или закључавање екрана да бисте наставили"</string>
+    <string name="screen_lock_prompt_message" msgid="5659570757430909869">"Употребите откључавање екрана да бисте наставили"</string>
+    <string name="fingerprint_or_screen_lock_prompt_message" msgid="8382576858490514495">"Користите отисак прста или откључавање екрана да бисте наставили"</string>
+    <string name="face_or_screen_lock_prompt_message" msgid="4562557128765735254">"Користите лице или откључавање екрана да бисте наставили"</string>
+    <string name="biometric_or_screen_lock_prompt_message" msgid="2102429900219199821">"Користите биометријски податак или откључавање екрана да бисте наставили"</string>
 </resources>
diff --git a/buildSrc-tests/src/test/java/androidx/build/testConfiguration/AndroidTestConfigBuilderTest.kt b/buildSrc-tests/src/test/java/androidx/build/testConfiguration/AndroidTestConfigBuilderTest.kt
index 4919c7e..a691c88 100644
--- a/buildSrc-tests/src/test/java/androidx/build/testConfiguration/AndroidTestConfigBuilderTest.kt
+++ b/buildSrc-tests/src/test/java/androidx/build/testConfiguration/AndroidTestConfigBuilderTest.kt
@@ -457,7 +457,6 @@
     <option name="config-descriptor:metadata" key="applicationId" value="com.androidx.placeholder.Placeholder" />
     <option name="wifi:disable" value="true" />
     <option name="instrumentation-arg" key="notAnnotation" value="androidx.test.filters.FlakyTest" />
-    <option name="instrumentation-arg" key="listener" value="androidx.benchmark.junit4.InstrumentationResultsRunListener,androidx.benchmark.junit4.SideEffectRunListener" />
     <include name="google/unbundled/common/setup" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
     <option name="cleanup-apks" value="true" />
@@ -471,6 +470,8 @@
     <test class="com.android.tradefed.testtype.AndroidJUnitTest">
     <option name="runner" value="com.example.Runner"/>
     <option name="package" value="com.androidx.placeholder.Placeholder" />
+    <option name="device-listeners" value="androidx.benchmark.junit4.InstrumentationResultsRunListener" />
+    <option name="device-listeners" value="androidx.benchmark.junit4.SideEffectRunListener" />
     </test>
     </configuration>
 """.trimIndent()
@@ -497,7 +498,6 @@
     <option name="instrumentation-arg" key="notAnnotation" value="androidx.test.filters.FlakyTest" />
     <option name="instrumentation-arg" key="androidx.test.argument1" value="something1" />
     <option name="instrumentation-arg" key="androidx.test.argument2" value="something2" />
-    <option name="instrumentation-arg" key="listener" value="androidx.benchmark.junit4.InstrumentationResultsRunListener,androidx.benchmark.macro.junit4.SideEffectRunListener" />
     <include name="google/unbundled/common/setup" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
     <option name="cleanup-apks" value="true" />
@@ -507,6 +507,8 @@
     <test class="com.android.tradefed.testtype.AndroidJUnitTest">
     <option name="runner" value="com.example.Runner"/>
     <option name="package" value="com.androidx.placeholder.Placeholder" />
+    <option name="device-listeners" value="androidx.benchmark.macro.junit4.InstrumentationResultsRunListener" />
+    <option name="device-listeners" value="androidx.benchmark.macro.junit4.SideEffectRunListener" />
     </test>
     </configuration>
 """.trimIndent()
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/docs/AndroidXDocsImplPlugin.kt b/buildSrc/private/src/main/kotlin/androidx/build/docs/AndroidXDocsImplPlugin.kt
index 2f04406..4cd160c 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/docs/AndroidXDocsImplPlugin.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/docs/AndroidXDocsImplPlugin.kt
@@ -276,9 +276,8 @@
             "mergeMultiplatformMetadata",
             MergeMultiplatformMetadataTask::class.java
         ) {
-            it.dependsOn(unzipMultiplatformSources)
             it.mergedProjectMetadata.set(mergedProjectMetadata)
-            it.inputDirectory.set(tempMultiplatformMetadataDirectory)
+            it.inputDirectory.set(unzipMultiplatformSources.flatMap { it.metadataOutput })
         }
     }
 
@@ -503,9 +502,11 @@
                     )
                 )
                 task.apply {
+                    // Remove once there is property version of Copy#destinationDir
+                    // Use samplesDir.set(unzipSamplesTask.flatMap { it.destinationDirectory })
+                    // https://github.com/gradle/gradle/issues/25824
                     dependsOn(unzipJvmSourcesTask)
                     dependsOn(unzipSamplesTask)
-                    dependsOn(generateMetadataTask)
                     dependsOn(configureMultiplatformSourcesTask)
 
                     description =
@@ -532,7 +533,7 @@
                     excludedPackages.set(hiddenPackages.toSet())
                     excludedPackagesForJava.set(hiddenPackagesJava)
                     excludedPackagesForKotlin.set(emptySet())
-                    libraryMetadataFile.set(getMetadataRegularFile(project))
+                    libraryMetadataFile.set(generateMetadataTask.flatMap { it.destinationFile })
                     projectStructureMetadataFile.set(mergedProjectMetadata)
                     // See go/dackka-source-link for details on these links.
                     baseSourceLink.set("https://cs.android.com/search?q=file:%s+class:%s")
@@ -563,8 +564,7 @@
         val zipTask =
             project.tasks.register("zipDocs", Zip::class.java) { task ->
                 task.apply {
-                    dependsOn(dackkaTask)
-                    from(generatedDocsDir)
+                    from(dackkaTask.flatMap { it.destinationDir })
 
                     val baseName = "docs-$docsType"
                     val buildId = getBuildId()
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/testConfiguration/AndroidTestConfigBuilder.kt b/buildSrc/private/src/main/kotlin/androidx/build/testConfiguration/AndroidTestConfigBuilder.kt
index 3d4eb41..01da246 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/testConfiguration/AndroidTestConfigBuilder.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/testConfiguration/AndroidTestConfigBuilder.kt
@@ -110,12 +110,8 @@
         sb.append(MODULE_METADATA_TAG_OPTION.replace("APPLICATION_ID", applicationId))
             .append(WIFI_DISABLE_OPTION)
             .append(FLAKY_TEST_OPTION)
-        if (isMicrobenchmark) {
-            if (isPostsubmit) {
-                sb.append(MICROBENCHMARK_POSTSUBMIT_OPTIONS)
-            } else {
-                sb.append(MICROBENCHMARK_PRESUBMIT_OPTION)
-            }
+        if (!isPostsubmit && (isMicrobenchmark || isMacrobenchmark)) {
+            sb.append(BENCHMARK_PRESUBMIT_INST_ARGS)
         }
         instrumentationArgsMap.forEach { (key, value) ->
             sb.append("""
@@ -123,9 +119,6 @@
 
                 """.trimIndent())
         }
-        if (isMacrobenchmark) {
-            sb.append(MACROBENCHMARK_POSTSUBMIT_OPTIONS)
-        }
         sb.append(SETUP_INCLUDE)
             .append(TARGET_PREPARER_OPEN.replace("CLEANUP_APKS", "true"))
         initialSetupApks.forEach { apk ->
@@ -148,6 +141,16 @@
         sb.append(TEST_BLOCK_OPEN)
             .append(RUNNER_OPTION.replace("TEST_RUNNER", testRunner))
             .append(PACKAGE_OPTION.replace("APPLICATION_ID", applicationId))
+            .apply {
+                if (isPostsubmit) {
+                    // These listeners should be unified eventually (b/331974955)
+                    if (isMicrobenchmark) {
+                        sb.append(MICROBENCHMARK_POSTSUBMIT_LISTENERS)
+                    } else if (isMacrobenchmark) {
+                        sb.append(MACROBENCHMARK_POSTSUBMIT_LISTENERS)
+                    }
+                }
+            }
             .append(TEST_BLOCK_CLOSE)
         sb.append(CONFIGURATION_CLOSE)
         return sb.toString()
@@ -358,25 +361,27 @@
 """
         .trimIndent()
 
-private val MICROBENCHMARK_PRESUBMIT_OPTION =
+private val BENCHMARK_PRESUBMIT_INST_ARGS =
     """
     <option name="instrumentation-arg" key="androidx.benchmark.dryRunMode.enable" value="true" />
 
 """
         .trimIndent()
 
-// NOTE: can only specify one "listener" key, must manually concat within that
-private val MICROBENCHMARK_POSTSUBMIT_OPTIONS =
+private val MICROBENCHMARK_POSTSUBMIT_LISTENERS =
     """
-    <option name="instrumentation-arg" key="listener" value="androidx.benchmark.junit4.InstrumentationResultsRunListener,androidx.benchmark.junit4.SideEffectRunListener" />
+    <option name="device-listeners" value="androidx.benchmark.junit4.InstrumentationResultsRunListener" />
+    <option name="device-listeners" value="androidx.benchmark.junit4.SideEffectRunListener" />
 
 """
         .trimIndent()
 
-// NOTE: can only specify one "listener" key, must manually concat within that
-private val MACROBENCHMARK_POSTSUBMIT_OPTIONS =
+// NOTE: listeners are duplicated in macro package due to no common module w/ junit dependency
+// See b/331974955
+private val MACROBENCHMARK_POSTSUBMIT_LISTENERS =
     """
-    <option name="instrumentation-arg" key="listener" value="androidx.benchmark.junit4.InstrumentationResultsRunListener,androidx.benchmark.macro.junit4.SideEffectRunListener" />
+    <option name="device-listeners" value="androidx.benchmark.macro.junit4.InstrumentationResultsRunListener" />
+    <option name="device-listeners" value="androidx.benchmark.macro.junit4.SideEffectRunListener" />
 
 """
         .trimIndent()
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/testConfiguration/GenerateTestConfigurationTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/testConfiguration/GenerateTestConfigurationTask.kt
index c890c2a..d673710 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/testConfiguration/GenerateTestConfigurationTask.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/testConfiguration/GenerateTestConfigurationTask.kt
@@ -196,6 +196,11 @@
             // macro benchmarks do not have a dryRunMode, so we don't run them in presubmit
             configBuilder.isMacrobenchmark(true)
             configBuilder.tag("macrobenchmarks")
+            if (additionalTags.get().contains("wear")) {
+                // Wear macrobenchmarks are tagged separately to enable running on wear in CI
+                // standard macrobenchmarks don't currently run well on wear (b/189952249)
+                configBuilder.tag("wear-macrobenchmarks")
+            }
         } else {
             configBuilder.tag("androidx_unit_tests")
         }
diff --git a/busytown/androidx-studio-integration-lint.sh b/busytown/androidx-studio-integration-lint.sh
index 80d7657..54081de 100755
--- a/busytown/androidx-studio-integration-lint.sh
+++ b/busytown/androidx-studio-integration-lint.sh
@@ -4,5 +4,5 @@
 $SCRIPT_PATH/impl/build-studio-and-androidx.sh \
   --ci \
   -x verifyDependencyVersions \
-  lintAnalyze \
-  lintAnalyzeDebug
+  lintReportJvm \
+  lintReportDebug
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraFactoryAdapter.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraFactoryAdapter.kt
index a22309f..66a0832 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraFactoryAdapter.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraFactoryAdapter.kt
@@ -65,32 +65,32 @@
             )
             .build()
         debug { "Created CameraFactoryAdapter in ${start.measureNow(timeSource).formatMs()}" }
-        debug { "availableCamerasSelector: $availableCamerasSelector " }
         Debug.traceStop()
         result
     }
-    private var mAvailableCamerasSelector: CameraSelector? = availableCamerasSelector
-    private var mAvailableCameraIds: List<String>
+    private val availableCameraIds: LinkedHashSet<String>
     private val cameraCoordinator: CameraCoordinatorAdapter = CameraCoordinatorAdapter(
         appComponent.getCameraPipe(),
         appComponent.getCameraDevices(),
     )
 
     init {
-        debug { "Created CameraFactoryAdapter" }
-
         val optimizedCameraIds = CameraSelectionOptimizer.getSelectedAvailableCameraIds(
             this,
-            mAvailableCamerasSelector
+            availableCamerasSelector
         )
-        mAvailableCameraIds = CameraCompatibilityFilter.getBackwardCompatibleCameraIds(
-            appComponent.getCameraDevices(),
-            optimizedCameraIds
+
+        // Use a LinkedHashSet to preserve order
+        availableCameraIds = LinkedHashSet(
+            CameraCompatibilityFilter.getBackwardCompatibleCameraIds(
+                appComponent.getCameraDevices(),
+                optimizedCameraIds
+            )
         )
     }
 
     /**
-     * The [getCamera] method is responsible for providing CameraInternal object based on cameraID.
+     * The [getCamera] method is responsible for providing CameraInternal object based on cameraId.
      * Use cameraId from set of cameraIds provided by [getAvailableCameraIds] method.
      */
     override fun getCamera(cameraId: String): CameraInternal {
@@ -102,13 +102,12 @@
         return cameraInternal
     }
 
-    override fun getAvailableCameraIds(): Set<String> =
-        // Use a LinkedHashSet to preserve order
-        LinkedHashSet(mAvailableCameraIds)
+    override fun getAvailableCameraIds(): Set<String> = availableCameraIds
 
     override fun getCameraCoordinator(): CameraCoordinator {
         return cameraCoordinator
     }
 
+    /** This is an implementation specific object that is specific to the integration package */
     override fun getCameraManager(): Any = appComponent
 }
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraFactoryProvider.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraFactoryProvider.kt
index 08af33b..74b8b25 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraFactoryProvider.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraFactoryProvider.kt
@@ -34,7 +34,8 @@
 
 /**
  * The [CameraFactoryProvider] is responsible for creating the root dagger component that is used
- * to share resources across Camera instances.
+ * to share resources across Camera instances. There should generally be one
+ * [CameraFactoryProvider] instance per CameraX instance.
  */
 @RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
 class CameraFactoryProvider(
@@ -42,14 +43,12 @@
     private val sharedAppContext: Context? = null,
     private val sharedThreadConfig: CameraThreadConfig? = null
 ) : CameraFactory.Provider {
-    private val cameraInteropStateCallbackRepository = CameraInteropStateCallbackRepository()
+    private val sharedInteropCallbacks = CameraInteropStateCallbackRepository()
     private val lock = Any()
 
     @GuardedBy("lock")
     private var cachedCameraPipe: Pair<Context, Lazy<CameraPipe>>? = null
 
-    private var cameraOpenRetryMaxTimeoutNs: DurationNs? = null
-
     override fun newInstance(
         context: Context,
         threadConfig: CameraThreadConfig,
@@ -57,21 +56,24 @@
         cameraOpenRetryMaxTimeoutInMs: Long
     ): CameraFactory {
 
-        this.cameraOpenRetryMaxTimeoutNs = if (cameraOpenRetryMaxTimeoutInMs != -1L) null
+        val openRetryMaxTimeout = if (cameraOpenRetryMaxTimeoutInMs != -1L) null
         else DurationNs(cameraOpenRetryMaxTimeoutInMs)
 
-        val lazyCameraPipe = getOrCreateCameraPipe(context)
+        val lazyCameraPipe = getOrCreateCameraPipe(context, openRetryMaxTimeout)
 
         return CameraFactoryAdapter(
             lazyCameraPipe,
             sharedAppContext ?: context,
             sharedThreadConfig ?: threadConfig,
-            cameraInteropStateCallbackRepository,
+            sharedInteropCallbacks,
             availableCamerasLimiter
         )
     }
 
-    private fun getOrCreateCameraPipe(context: Context): Lazy<CameraPipe> {
+    private fun getOrCreateCameraPipe(
+        context: Context,
+        openRetryMaxTimeout: DurationNs?,
+    ): Lazy<CameraPipe> {
         if (sharedCameraPipe != null) {
             return lazyOf(sharedCameraPipe)
         }
@@ -79,19 +81,22 @@
         synchronized(lock) {
             val existing = cachedCameraPipe
             if (existing == null) {
-                val sharedCameraPipe = lazy { createCameraPipe(context) }
-                cachedCameraPipe = context to sharedCameraPipe
-                return sharedCameraPipe
+                val lazyCameraPipe = lazy {
+                    createCameraPipe(context, openRetryMaxTimeout)
+                }
+                cachedCameraPipe = context to lazyCameraPipe
+                return lazyCameraPipe
             } else {
                 check(context == existing.first) {
-                    "Mismatched context! Expected ${existing.first} but was $context"
+                    "Failed to create CameraPipe, existing instance was created using " +
+                        "${existing.first}, but received $context."
                 }
                 return existing.second
             }
         }
     }
 
-    private fun createCameraPipe(context: Context): CameraPipe {
+    private fun createCameraPipe(context: Context, openRetryMaxTimeout: DurationNs?): CameraPipe {
         Debug.traceStart { "Create CameraPipe" }
         val timeSource = SystemTimeSource()
         val start = Timestamps.now(timeSource)
@@ -100,9 +105,9 @@
             CameraPipe.Config(
                 appContext = context.applicationContext,
                 cameraInteropConfig = CameraPipe.CameraInteropConfig(
-                    cameraInteropStateCallbackRepository.deviceStateCallback,
-                    cameraInteropStateCallbackRepository.sessionStateCallback,
-                    cameraOpenRetryMaxTimeoutNs
+                    sharedInteropCallbacks.deviceStateCallback,
+                    sharedInteropCallbacks.sessionStateCallback,
+                    openRetryMaxTimeout
                 )
             )
         )
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraInfoAdapter.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraInfoAdapter.kt
index b2a2064..0b8364c 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraInfoAdapter.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraInfoAdapter.kt
@@ -29,6 +29,7 @@
 import android.view.Surface
 import androidx.annotation.RequiresApi
 import androidx.camera.camera2.pipe.CameraId
+import androidx.camera.camera2.pipe.CameraMetadata.Companion.supportsLogicalMultiCamera
 import androidx.camera.camera2.pipe.CameraPipe
 import androidx.camera.camera2.pipe.core.Log
 import androidx.camera.camera2.pipe.integration.compat.DynamicRangeProfilesCompat
@@ -38,6 +39,7 @@
 import androidx.camera.camera2.pipe.integration.config.CameraConfig
 import androidx.camera.camera2.pipe.integration.config.CameraScope
 import androidx.camera.camera2.pipe.integration.impl.CameraCallbackMap
+import androidx.camera.camera2.pipe.integration.impl.CameraPipeCameraProperties
 import androidx.camera.camera2.pipe.integration.impl.CameraProperties
 import androidx.camera.camera2.pipe.integration.impl.DeviceInfoLogger
 import androidx.camera.camera2.pipe.integration.impl.FocusMeteringControl
@@ -91,6 +93,17 @@
         DeviceInfoLogger.logDeviceInfo(cameraProperties)
     }
 
+    private val _physicalCameraInfos by lazy {
+        cameraProperties.metadata.physicalCameraIds.mapTo(mutableSetOf<CameraInfo>()) {
+                physicalCameraId ->
+            val cameraProperties = CameraPipeCameraProperties(
+                CameraConfig(physicalCameraId),
+                cameraProperties.metadata.awaitPhysicalMetadata(physicalCameraId)
+            )
+            PhysicalCameraInfoAdapter(cameraProperties)
+        }
+    }
+
     private val isLegacyDevice by lazy {
         cameraProperties.metadata[
             CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL
@@ -102,6 +115,12 @@
         Camera2CameraInfo.create(cameraProperties)
     }
 
+    override fun isLogicalMultiCameraSupported(): Boolean {
+        return cameraProperties.metadata.supportsLogicalMultiCamera
+    }
+
+    override fun getPhysicalCameraInfos(): Set<CameraInfo> = _physicalCameraInfos
+
     override fun getCameraId(): String = cameraConfig.cameraId.value
     override fun getLensFacing(): Int =
         getCameraSelectorLensFacing(cameraProperties.metadata[CameraCharacteristics.LENS_FACING]!!)
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/PhysicalCameraInfoAdapter.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/PhysicalCameraInfoAdapter.kt
new file mode 100644
index 0000000..da5bda2
--- /dev/null
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/PhysicalCameraInfoAdapter.kt
@@ -0,0 +1,135 @@
+/*
+ * 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.integration.adapter
+
+import android.annotation.SuppressLint
+import android.util.Range
+import androidx.annotation.RequiresApi
+import androidx.camera.camera2.pipe.UnsafeWrapper
+import androidx.camera.camera2.pipe.integration.impl.CameraProperties
+import androidx.camera.camera2.pipe.integration.interop.Camera2CameraInfo
+import androidx.camera.camera2.pipe.integration.interop.ExperimentalCamera2Interop
+import androidx.camera.core.CameraInfo
+import androidx.camera.core.CameraSelector
+import androidx.camera.core.CameraState
+import androidx.camera.core.DynamicRange
+import androidx.camera.core.ExperimentalZeroShutterLag
+import androidx.camera.core.ExposureState
+import androidx.camera.core.FocusMeteringAction
+import androidx.camera.core.ZoomState
+import androidx.lifecycle.LiveData
+import kotlin.reflect.KClass
+
+/**
+ * Implementation of [CameraInfo] for physical camera. In comparison,
+ * [CameraInfoAdapter] is the version of logical camera.
+ */
+@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
+class PhysicalCameraInfoAdapter(
+    private val cameraProperties: CameraProperties
+) : CameraInfo, UnsafeWrapper {
+
+    @OptIn(ExperimentalCamera2Interop::class)
+    internal val camera2CameraInfo: Camera2CameraInfo by lazy {
+        Camera2CameraInfo.create(cameraProperties)
+    }
+
+    override fun getSensorRotationDegrees(): Int {
+        throw UnsupportedOperationException("Physical camera doesn't support this function")
+    }
+
+    override fun getSensorRotationDegrees(relativeRotation: Int): Int {
+        throw UnsupportedOperationException("Physical camera doesn't support this function")
+    }
+
+    override fun hasFlashUnit(): Boolean {
+        throw UnsupportedOperationException("Physical camera doesn't support this function")
+    }
+
+    override fun getTorchState(): LiveData<Int> {
+        throw UnsupportedOperationException("Physical camera doesn't support this function")
+    }
+
+    override fun getZoomState(): LiveData<ZoomState> {
+        throw UnsupportedOperationException("Physical camera doesn't support this function")
+    }
+
+    override fun getExposureState(): ExposureState {
+        throw UnsupportedOperationException("Physical camera doesn't support this function")
+    }
+
+    override fun getCameraState(): LiveData<CameraState> {
+        throw UnsupportedOperationException("Physical camera doesn't support this function")
+    }
+
+    override fun getImplementationType(): String {
+        throw UnsupportedOperationException("Physical camera doesn't support this function")
+    }
+
+    override fun getCameraSelector(): CameraSelector {
+        throw UnsupportedOperationException("Physical camera doesn't support this function")
+    }
+
+    override fun getLensFacing(): Int {
+        throw UnsupportedOperationException("Physical camera doesn't support this function")
+    }
+
+    override fun getIntrinsicZoomRatio(): Float {
+        throw UnsupportedOperationException("Physical camera doesn't support this function")
+    }
+
+    override fun isFocusMeteringSupported(action: FocusMeteringAction): Boolean {
+        throw UnsupportedOperationException("Physical camera doesn't support this function")
+    }
+
+    @SuppressLint("NullAnnotationGroup")
+    @ExperimentalZeroShutterLag
+    override fun isZslSupported(): Boolean {
+        throw UnsupportedOperationException("Physical camera doesn't support this function")
+    }
+
+    override fun getSupportedFrameRateRanges(): Set<Range<Int>> {
+        throw UnsupportedOperationException("Physical camera doesn't support this function")
+    }
+
+    override fun isLogicalMultiCameraSupported(): Boolean {
+        throw UnsupportedOperationException("Physical camera doesn't support this function")
+    }
+
+    override fun isPrivateReprocessingSupported(): Boolean {
+        throw UnsupportedOperationException("Physical camera doesn't support this function")
+    }
+
+    override fun querySupportedDynamicRanges(
+        candidateDynamicRanges: Set<DynamicRange>
+    ): Set<DynamicRange> {
+        throw UnsupportedOperationException("Physical camera doesn't support this function")
+    }
+
+    override fun getPhysicalCameraInfos(): Set<CameraInfo> {
+        throw UnsupportedOperationException("Physical camera doesn't support this function")
+    }
+
+    @OptIn(ExperimentalCamera2Interop::class)
+    @Suppress("UNCHECKED_CAST")
+    override fun <T : Any> unwrapAs(type: KClass<T>): T? {
+        return when (type) {
+            Camera2CameraInfo::class -> camera2CameraInfo as T
+            else -> cameraProperties.metadata.unwrapAs(type)
+        }
+    }
+}
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/FocusMeteringControl.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/FocusMeteringControl.kt
index 15bbea2..efbb0d7 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/FocusMeteringControl.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/FocusMeteringControl.kt
@@ -30,6 +30,7 @@
 import androidx.camera.camera2.pipe.CameraMetadata.Companion.supportsAutoFocusTrigger
 import androidx.camera.camera2.pipe.Lock3ABehavior
 import androidx.camera.camera2.pipe.Result3A
+import androidx.camera.camera2.pipe.core.Log.debug
 import androidx.camera.camera2.pipe.integration.adapter.asListenableFuture
 import androidx.camera.camera2.pipe.integration.adapter.propagateTo
 import androidx.camera.camera2.pipe.integration.compat.ZoomCompat
@@ -50,8 +51,9 @@
 import kotlinx.coroutines.CompletableDeferred
 import kotlinx.coroutines.Deferred
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.delay
 import kotlinx.coroutines.launch
-import kotlinx.coroutines.runBlocking
 
 /**
  * Implementation of focus and metering controls exposed by [CameraControlInternal].
@@ -105,9 +107,12 @@
         cameraProperties.metadata.getOrDefault(CameraCharacteristics.CONTROL_MAX_REGIONS_AE, 0)
     private val maxAwbRegionCount =
         cameraProperties.metadata.getOrDefault(CameraCharacteristics.CONTROL_MAX_REGIONS_AWB, 0)
+
     private var updateSignal: CompletableDeferred<FocusMeteringResult>? = null
     private var cancelSignal: CompletableDeferred<Result3A?>? = null
 
+    private var autoCancelJob: Job? = null
+
     fun startFocusAndMetering(
         action: FocusMeteringAction,
         autoFocusTimeoutMs: Long = AUTO_FOCUS_TIMEOUT_DURATION,
@@ -116,8 +121,10 @@
 
         useCaseCamera?.let { useCaseCamera ->
             threads.sequentialScope.launch {
+                autoCancelJob?.cancel()
                 cancelSignal?.setCancelException("Cancelled by another startFocusAndMetering()")
                 updateSignal?.setCancelException("Cancelled by another startFocusAndMetering()")
+
                 updateSignal = signal
 
                 val aeRectangles = meteringRegionsFromMeteringPoints(
@@ -167,14 +174,6 @@
                     awbRectangles.ifEmpty { METERING_REGIONS_DEFAULT.toList() }
                 else null
 
-                val (isCancelEnabled, timeout) = if (action.isAutoCancelEnabled &&
-                    action.autoCancelDurationInMillis < autoFocusTimeoutMs
-                ) {
-                    (true to action.autoCancelDurationInMillis)
-                } else {
-                    (false to autoFocusTimeoutMs)
-                }
-
                 val deferredResult3A = if (
                     afRectangles.isEmpty() || !cameraProperties.metadata.supportsAutoFocusTrigger
                 ) {
@@ -185,13 +184,24 @@
                      * instead of all cases because Controller3A.update3A() will invalidate
                      * the CameraGraph and thus may cause extra requests to the camera.
                      */
+                    debug { "startFocusAndMetering: updating 3A regions only" }
                     useCaseCamera.requestControl.update3aRegions(
                         aeRegions = aeRegions,
                         afRegions = afRegions,
                         awbRegions = awbRegions,
                     )
                 } else {
-                    /**
+                    // No need to keep trying to focus if auto-cancel is already triggered
+                    val finalFocusTimeout = if (action.isAutoCancelEnabled &&
+                        action.autoCancelDurationInMillis < autoFocusTimeoutMs
+                    ) {
+                        action.autoCancelDurationInMillis
+                    } else {
+                        autoFocusTimeoutMs
+                    }
+
+                    debug { "startFocusAndMetering: updating 3A regions & triggering AF" }
+                    /*
                      * If device does not support a 3A region, we should not update it at all.
                      * If device does support but a region list is empty, it means any previously
                      * set region should be removed, so the no-op METERING_REGIONS_DEFAULT is used.
@@ -205,7 +215,7 @@
                         else null,
                         afTriggerStartAeMode = cameraProperties.getSupportedAeMode(AeMode.ON),
                         timeLimitNs = TimeUnit.NANOSECONDS.convert(
-                            timeout,
+                            finalFocusTimeout,
                             TimeUnit.MILLISECONDS
                         )
                     )
@@ -213,10 +223,12 @@
 
                 deferredResult3A.propagateToFocusMeteringResultDeferred(
                     resultDeferred = signal,
-                    isCancelEnabled = isCancelEnabled,
                     shouldTriggerAf = afRectangles.isNotEmpty(),
-                    useCaseCamera = useCaseCamera
                 )
+
+                if (action.isAutoCancelEnabled) {
+                    triggerAutoCancel(action.autoCancelDurationInMillis, signal, useCaseCamera)
+                }
            }
         } ?: run {
             signal.completeExceptionally(
@@ -227,31 +239,36 @@
         return signal.asListenableFuture()
     }
 
+    private fun triggerAutoCancel(
+        delayMillis: Long,
+        resultToCancel: CompletableDeferred<FocusMeteringResult>,
+        useCaseCamera: UseCaseCamera,
+    ) {
+        autoCancelJob?.cancel()
+
+        autoCancelJob = threads.scope.launch {
+            delay(delayMillis)
+            debug { "triggerAutoCancel: auto-canceling after $delayMillis ms" }
+            cancelFocusAndMeteringNowAsync(useCaseCamera, resultToCancel)
+        }
+    }
+
     private fun Deferred<Result3A>.propagateToFocusMeteringResultDeferred(
         resultDeferred: CompletableDeferred<FocusMeteringResult>,
-        isCancelEnabled: Boolean,
         shouldTriggerAf: Boolean,
-        useCaseCamera: UseCaseCamera,
     ) {
         invokeOnCompletion { throwable ->
             if (throwable != null) {
                 resultDeferred.completeExceptionally(throwable)
             } else {
                 val result3A = getCompleted()
+                debug { "propagateToFocusMeteringResultDeferred: result3A = $result3A" }
                 if (result3A.status == Result3A.Status.SUBMIT_FAILED) {
                     resultDeferred.completeExceptionally(
                         OperationCanceledException("Camera is not active.")
                     )
                 } else if (result3A.status == Result3A.Status.TIME_LIMIT_REACHED) {
-                    if (isCancelEnabled) {
-                        if (resultDeferred.isActive) {
-                            runBlocking {
-                                cancelFocusAndMeteringNowAsync(useCaseCamera, resultDeferred)
-                            }
-                        }
-                    } else {
-                        resultDeferred.complete(FocusMeteringResult.create(false))
-                    }
+                    resultDeferred.complete(FocusMeteringResult.create(false))
                 } else {
                     resultDeferred.complete(
                         result3A.toFocusMeteringResult(
@@ -314,6 +331,7 @@
         val signal = CompletableDeferred<Result3A?>()
         useCaseCamera?.let { useCaseCamera ->
             threads.sequentialScope.launch {
+                autoCancelJob?.cancel()
                 cancelSignal?.setCancelException("Cancelled by another cancelFocusAndMetering()")
                 cancelSignal = signal
                 cancelFocusAndMeteringNowAsync(useCaseCamera, updateSignal).propagateTo(signal)
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/interop/Camera2CameraInfo.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/interop/Camera2CameraInfo.kt
index cf910d3..80539f3 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/interop/Camera2CameraInfo.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/interop/Camera2CameraInfo.kt
@@ -20,6 +20,7 @@
 import androidx.annotation.RequiresApi
 import androidx.annotation.RestrictTo
 import androidx.camera.camera2.pipe.integration.adapter.CameraInfoAdapter
+import androidx.camera.camera2.pipe.integration.adapter.PhysicalCameraInfoAdapter
 import androidx.camera.camera2.pipe.integration.compat.workaround.getSafely
 import androidx.camera.camera2.pipe.integration.impl.CameraProperties
 import androidx.camera.core.CameraInfo
@@ -86,6 +87,12 @@
          */
         @JvmStatic
         fun from(@Suppress("UNUSED_PARAMETER") cameraInfo: CameraInfo): Camera2CameraInfo {
+            // Physical camera
+            if (cameraInfo is PhysicalCameraInfoAdapter) {
+                return cameraInfo.unwrapAs(Camera2CameraInfo::class)!!
+            }
+
+            // Logical camera
             var cameraInfoImpl = (cameraInfo as CameraInfoInternal).implementation
             Preconditions.checkArgument(
                 cameraInfoImpl is CameraInfoAdapter,
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/CameraInfoAdapterTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/CameraInfoAdapterTest.kt
index ac3a615..226c5fc 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/CameraInfoAdapterTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/CameraInfoAdapterTest.kt
@@ -31,6 +31,8 @@
 import androidx.camera.camera2.pipe.integration.impl.ZoomControl
 import androidx.camera.camera2.pipe.integration.internal.DOLBY_VISION_10B_UNCONSTRAINED
 import androidx.camera.camera2.pipe.integration.internal.HLG10_UNCONSTRAINED
+import androidx.camera.camera2.pipe.integration.interop.Camera2CameraInfo
+import androidx.camera.camera2.pipe.integration.interop.ExperimentalCamera2Interop
 import androidx.camera.camera2.pipe.integration.testing.FakeCameraInfoAdapterCreator.createCameraInfoAdapter
 import androidx.camera.camera2.pipe.integration.testing.FakeCameraInfoAdapterCreator.useCaseThreads
 import androidx.camera.camera2.pipe.integration.testing.FakeCameraProperties
@@ -437,6 +439,29 @@
     }
 
     @Test
+    fun cameraInfo_queryLogicalMultiCameraSupported() {
+        val cameraInfo: CameraInfo = createCameraInfoAdapter()
+
+        assertThat(cameraInfo.isLogicalMultiCameraSupported).isTrue()
+    }
+
+    @OptIn(ExperimentalCamera2Interop::class)
+    @Test
+    fun cameraInfo_getPhysicalCameraInfos() {
+        val physicalCameraIds = setOf(
+            CameraId.fromCamera2Id("5"),
+            CameraId.fromCamera2Id("6"))
+        val cameraInfo: CameraInfo = createCameraInfoAdapter()
+
+        assertThat(cameraInfo.physicalCameraInfos).isNotNull()
+        assertThat(cameraInfo.physicalCameraInfos.size).isEqualTo(2)
+        for (info in cameraInfo.physicalCameraInfos) {
+            assertThat(physicalCameraIds).contains(
+                CameraId(Camera2CameraInfo.from(info).getCameraId()))
+        }
+    }
+
+    @Test
     fun intrinsicZoomRatioIsLessThan1_whenSensorHorizontalLengthWiderThanDefault() {
         val cameraInfo: CameraInfoInternal = createCameraInfoAdapter(
             cameraId = CameraId(ultraWideCameraId),
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/FocusMeteringControlTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/FocusMeteringControlTest.kt
index d5f89a3..230aa9f 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/FocusMeteringControlTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/FocusMeteringControlTest.kt
@@ -86,6 +86,7 @@
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.test.StandardTestDispatcher
 import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.advanceTimeBy
 import kotlinx.coroutines.test.advanceUntilIdle
 import kotlinx.coroutines.test.runTest
 import kotlinx.coroutines.withContext
@@ -1087,6 +1088,7 @@
             // Arrange.
             // Set an incomplete CompletableDeferred
             fakeRequestControl.focusMeteringResult = CompletableDeferred()
+            fakeRequestControl.awaitFocusMetering = false // simulates async
             val autoCancelDuration: Long = 500
             val action = FocusMeteringAction.Builder(point1)
                 .setAutoCancelDuration(autoCancelDuration, TimeUnit.MILLISECONDS)
@@ -1100,6 +1102,8 @@
             )
 
             // simulate UseCaseCamera timing out during auto focus
+            advanceUntilIdle() // ensures all operations are triggered already
+            delay(autoFocusTimeoutDuration)
             fakeRequestControl.focusMeteringResult.complete(
                 Result3A(status = Result3A.Status.TIME_LIMIT_REACHED)
             )
@@ -1164,7 +1168,10 @@
     @Test
     fun startFocusMetering_afAutoModeIsSet() = runTest {
         // Arrange.
-        val action = FocusMeteringAction.Builder(point1, FocusMeteringAction.FLAG_AF).build()
+        val action = FocusMeteringAction
+            .Builder(point1, FocusMeteringAction.FLAG_AF)
+            .setAutoCancelDuration(8, TimeUnit.SECONDS)
+            .build()
         val state3AControl = createState3AControl(CAMERA_ID_0)
         focusMeteringControl = initFocusMeteringControl(
             cameraId = CAMERA_ID_0,
@@ -1176,7 +1183,8 @@
         // Act.
         focusMeteringControl.startFocusAndMeteringAndAdvanceTestScope(
             this,
-            action
+            action,
+            testScopeAdvanceTimeMillis = 6000, // not cancelled yet
         )[5, TimeUnit.SECONDS]
 
         // Assert.
@@ -1186,6 +1194,32 @@
     }
 
     @Test
+    fun startFocusMetering_afModeResetAfterAutoCancel() = runTest {
+        // Arrange.
+        val action = FocusMeteringAction
+            .Builder(point1, FocusMeteringAction.FLAG_AF)
+            .build()
+        val state3AControl = createState3AControl(CAMERA_ID_0)
+        focusMeteringControl = initFocusMeteringControl(
+            cameraId = CAMERA_ID_0,
+            useCases = setOf(createPreview(Size(1920, 1080))),
+            useCaseThreads = fakeUseCaseThreads,
+            state3AControl = state3AControl,
+        )
+
+        // Act.
+        focusMeteringControl.startFocusAndMeteringAndAdvanceTestScope(
+            this,
+            action,
+        )[5, TimeUnit.SECONDS]
+
+        // Assert.
+        assertThat(
+            state3AControl.preferredFocusMode
+        ).isNull()
+    }
+
+    @Test
     fun startFocusMetering_AfNotInvolved_afAutoModeNotSet() = runTest {
         // Arrange.
         val action = FocusMeteringAction.Builder(
@@ -1669,14 +1703,19 @@
     private fun FocusMeteringControl.startFocusAndMeteringAndAdvanceTestScope(
         testScope: TestScope,
         action: FocusMeteringAction,
-        autoFocusTimeoutMs: Long? = null
+        autoFocusTimeoutMs: Long? = null,
+        testScopeAdvanceTimeMillis: Long? = null,
     ): ListenableFuture<FocusMeteringResult> {
         val future = autoFocusTimeoutMs?.let {
             startFocusAndMetering(action, it)
         } ?: run {
             startFocusAndMetering(action)
         }
-        testScope.advanceUntilIdle()
+        if (testScopeAdvanceTimeMillis == null) {
+            testScope.advanceUntilIdle()
+        } else {
+            testScope.advanceTimeBy(testScopeAdvanceTimeMillis)
+        }
         return future
     }
 }
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeCameraInfoAdapterCreator.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeCameraInfoAdapterCreator.kt
index 427d14d..7ce86eb 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeCameraInfoAdapterCreator.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeCameraInfoAdapterCreator.kt
@@ -18,6 +18,7 @@
 
 import android.graphics.Rect
 import android.hardware.camera2.CameraCharacteristics
+import android.hardware.camera2.CameraMetadata
 import android.hardware.camera2.params.StreamConfigurationMap
 import android.util.Range
 import android.util.Size
@@ -58,6 +59,8 @@
 @RequiresApi(21)
 object FakeCameraInfoAdapterCreator {
     private val CAMERA_ID_0 = CameraId("0")
+    private val PHYSICAL_CAMERA_ID_5 = CameraId("5")
+    private val PHYSICAL_CAMERA_ID_6 = CameraId("6")
 
     val useCaseThreads by lazy {
         val executor = MoreExecutors.directExecutor()
@@ -85,6 +88,9 @@
             Range(24, 24),
             Range(30, 30),
             Range(60, 60)
+        ),
+        CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES to intArrayOf(
+            CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA
         )
     )
 
@@ -95,7 +101,10 @@
         cameraProperties: CameraProperties = FakeCameraProperties(
             FakeCameraMetadata(
                 cameraId = cameraId,
-                characteristics = cameraCharacteristics
+                characteristics = cameraCharacteristics,
+                physicalMetadata = mapOf(
+                    PHYSICAL_CAMERA_ID_5 to FakeCameraMetadata(),
+                    PHYSICAL_CAMERA_ID_6 to FakeCameraMetadata())
             ),
             cameraId
         ),
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeUseCaseCamera.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeUseCaseCamera.kt
index 2113912..53d949f 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeUseCaseCamera.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeUseCaseCamera.kt
@@ -132,6 +132,8 @@
     var cancelFocusMeteringCallCount = 0
     var cancelFocusMeteringResult = CompletableDeferred(Result3A(status = Result3A.Status.OK))
 
+    var awaitFocusMetering = true
+
     override suspend fun startFocusAndMeteringAsync(
         aeRegions: List<MeteringRectangle>?,
         afRegions: List<MeteringRectangle>?,
@@ -154,13 +156,19 @@
                 timeLimitNs
             )
         )
-        withTimeoutOrNull(TimeUnit.MILLISECONDS.convert(timeLimitNs, TimeUnit.NANOSECONDS)) {
-            focusMeteringResult.await()
-        }.let { result3A ->
-            if (result3A == null) {
-                focusMeteringResult.complete(Result3A(status = Result3A.Status.TIME_LIMIT_REACHED))
+
+        if (awaitFocusMetering) {
+            withTimeoutOrNull(TimeUnit.MILLISECONDS.convert(timeLimitNs, TimeUnit.NANOSECONDS)) {
+                focusMeteringResult.await()
+            }.let { result3A ->
+                if (result3A == null) {
+                    focusMeteringResult.complete(
+                        Result3A(status = Result3A.Status.TIME_LIMIT_REACHED)
+                    )
+                }
             }
         }
+
         return focusMeteringResult
     }
 
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2CaptureSequenceProcessor.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2CaptureSequenceProcessor.kt
index dfb9b4f..42c2066 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2CaptureSequenceProcessor.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2CaptureSequenceProcessor.kt
@@ -331,9 +331,10 @@
                     ) { it.awaitStarted() }
                 }
             }
+            imageWriter?.close()
+            session.inputSurface?.release()
             closed = true
         }
-        imageWriter?.close()
     }
 
     override fun toString(): String {
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraInfoImpl.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraInfoImpl.java
index dc63a51..91eaa9d 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraInfoImpl.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraInfoImpl.java
@@ -26,6 +26,7 @@
 
 import static androidx.camera.camera2.internal.ZslUtil.isCapabilitySupported;
 
+import android.annotation.SuppressLint;
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CameraMetadata;
 import android.os.Build;
@@ -397,6 +398,7 @@
         }
     }
 
+    @SuppressLint("NullAnnotationGroup")
     @OptIn(markerClass = androidx.camera.core.ExperimentalZeroShutterLag.class)
     @Override
     public boolean isZslSupported() {
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/CameraEffect.java b/camera/camera-core/src/main/java/androidx/camera/core/CameraEffect.java
index ad649f9..65c1bcb 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/CameraEffect.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/CameraEffect.java
@@ -104,6 +104,15 @@
     }
 
     /**
+     * Options for how many outputs the effect handles.
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    @IntDef(value = {OUTPUT_OPTION_ONE_FOR_ALL_TARGETS, OUTPUT_OPTION_ONE_FOR_EACH_TARGET})
+    public @interface OutputOptions {
+    }
+
+    /**
      * Bitmask options for the effect buffer formats.
      */
     @Retention(RetentionPolicy.SOURCE)
@@ -173,8 +182,34 @@
     @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
     public static final int TRANSFORMATION_PASSTHROUGH = 2;
 
+    /**
+     * Use this option to receive one output Surface for all the output targets.
+     *
+     * <p>When the effect targets multiple UseCases, e.g. Preview, VideoCapture, the effect will
+     * only receive one output Surface for all the outputs. CameraX is responsible for copying the
+     * processed frames to different output Surfaces.
+     *
+     * <p>Use this option if all UseCases receive the same content.
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    public static final int OUTPUT_OPTION_ONE_FOR_ALL_TARGETS = 0;
+
+    /**
+     * Use this option to receive one output Surface for each corresponding output target.
+     *
+     * <p>When the effect targets multiple UseCases, e.g. Preview, VideoCapture, the effect will
+     * receive two output Surfaces, one for Preview and one for VideoCapture. The effect is
+     * responsible for drawing the processed frames to the corresponding output Surfaces.
+     *
+     * <p>Use this option if each UseCase receives different content.
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    public static final int OUTPUT_OPTION_ONE_FOR_EACH_TARGET = 1;
+
     @Targets
     private final int mTargets;
+    @OutputOptions
+    private final int mOutputOption;
     @Transformations
     private final int mTransformation;
     @NonNull
@@ -208,12 +243,24 @@
                 "Currently ImageProcessor can only target IMAGE_CAPTURE.");
         mTargets = targets;
         mTransformation = TRANSFORMATION_ARBITRARY;
+        mOutputOption = OUTPUT_OPTION_ONE_FOR_ALL_TARGETS;
         mExecutor = executor;
         mSurfaceProcessor = null;
         mImageProcessor = imageProcessor;
         mErrorListener = errorListener;
     }
 
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    protected CameraEffect(
+            @Targets int targets,
+            @Transformations int transformation,
+            @NonNull Executor executor,
+            @NonNull SurfaceProcessor surfaceProcessor,
+            @NonNull Consumer<Throwable> errorListener) {
+        this(targets, OUTPUT_OPTION_ONE_FOR_ALL_TARGETS, transformation, executor, surfaceProcessor,
+                errorListener);
+    }
+
     /**
      * @param targets          the target {@link UseCase} to which this effect should be applied.
      *                         Currently {@link SurfaceProcessor} can target the following
@@ -226,6 +273,7 @@
      *                         </ul>
      *                         Targeting other {@link UseCase} combinations will throw
      *                         {@link IllegalArgumentException}.
+     * @param outputOption     the option to specify how many output Surface the effect will handle.
      * @param transformation   the transformation that the {@link SurfaceProcessor} will handle.
      * @param executor         the {@link Executor} on which the {@param imageProcessor} and
      *                         {@param errorListener} will be invoked.
@@ -241,12 +289,14 @@
     @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
     protected CameraEffect(
             @Targets int targets,
+            @OutputOptions int outputOption,
             @Transformations int transformation,
             @NonNull Executor executor,
             @NonNull SurfaceProcessor surfaceProcessor,
             @NonNull Consumer<Throwable> errorListener) {
         checkSupportedTargets(SURFACE_PROCESSOR_TARGETS, targets);
         mTargets = targets;
+        mOutputOption = outputOption;
         mTransformation = transformation;
         mExecutor = executor;
         mSurfaceProcessor = surfaceProcessor;
@@ -282,13 +332,8 @@
             @NonNull Executor executor,
             @NonNull SurfaceProcessor surfaceProcessor,
             @NonNull Consumer<Throwable> errorListener) {
-        checkSupportedTargets(SURFACE_PROCESSOR_TARGETS, targets);
-        mTargets = targets;
-        mTransformation = TRANSFORMATION_ARBITRARY;
-        mExecutor = executor;
-        mSurfaceProcessor = surfaceProcessor;
-        mImageProcessor = null;
-        mErrorListener = errorListener;
+        this(targets, OUTPUT_OPTION_ONE_FOR_ALL_TARGETS, TRANSFORMATION_ARBITRARY, executor,
+                surfaceProcessor, errorListener);
     }
 
     /**
@@ -309,6 +354,15 @@
     }
 
     /**
+     * Gets the target option.
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    @OutputOptions
+    public int getOutputOption() {
+        return mOutputOption;
+    }
+
+    /**
      * Gets the {@link Executor} associated with this effect.
      *
      * <p>This method returns the value set in the constructor.
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/ResolutionsMerger.java b/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/ResolutionsMerger.java
index 9e55048..ae2491b 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/ResolutionsMerger.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/ResolutionsMerger.java
@@ -53,6 +53,7 @@
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -619,6 +620,15 @@
         Collections.sort(resolutions, new CompareSizesByArea(true));
     }
 
+    /** Removes duplicate sizes and preserves the order. */
+    @NonNull
+    private static List<Size> removeDuplicates(@NonNull List<Size> resolutions) {
+        if (resolutions.isEmpty()) {
+            return resolutions;
+        }
+        return new ArrayList<>(new LinkedHashSet<>(resolutions));
+    }
+
     /**
      * Returns a list of resolution that all resolutions are with the input aspect-ratio.
      *
@@ -690,6 +700,10 @@
         if (childSizes.isEmpty() || parentSizes.isEmpty()) {
             return new ArrayList<>();
         }
+        // This method requires no duplicate parentSizes to correctly remove the last item.
+        // For example, if parentSizes = [1280x720, 1280x720] and 1280x720 can cover childSizes,
+        // removing the last item would cause 1280x720 to be mistakenly considered too large.
+        parentSizes = removeDuplicates(parentSizes);
 
         List<Size> result = new ArrayList<>();
         for (Size parentSize : parentSizes) {
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/StreamSharing.java b/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/StreamSharing.java
index 9844499..d690404 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/StreamSharing.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/StreamSharing.java
@@ -253,8 +253,7 @@
                 isMirroringRequired(camera)); // Mirroring can be overridden by children.
         mSharingInputEdge = getSharingInputEdge(mCameraEdge, camera);
 
-        mSharingNode = new SurfaceProcessorNode(camera,
-                DefaultSurfaceProcessor.Factory.newInstance(streamSpec.getDynamicRange()));
+        mSharingNode = getSharingNode(camera, streamSpec);
 
         // Transform the input based on virtual camera configuration.
         boolean isViewportSet = getViewPortCropRect() != null;
@@ -314,11 +313,19 @@
     @NonNull
     private SurfaceEdge getSharingInputEdge(@NonNull SurfaceEdge cameraEdge,
             @NonNull CameraInternal camera) {
-        if (getEffect() == null
-                || getEffect().getTransformation() == CameraEffect.TRANSFORMATION_PASSTHROUGH) {
+        if (getEffect() == null) {
             // No effect. The input edge is the camera edge.
             return cameraEdge;
         }
+        if (getEffect().getTransformation() == CameraEffect.TRANSFORMATION_PASSTHROUGH) {
+            // This is a passthrough effect for testing.
+            return cameraEdge;
+        }
+        if (getEffect().getOutputOption() == CameraEffect.OUTPUT_OPTION_ONE_FOR_EACH_TARGET) {
+            // When OUTPUT_OPTION_ONE_FOR_EACH_TARGET is used, we will apply the effect at the
+            // sharing stage.
+            return cameraEdge;
+        }
         // Transform the camera edge to get the input edge.
         mEffectNode = new SurfaceProcessorNode(camera,
                 getEffect().createSurfaceProcessorInternal());
@@ -338,6 +345,23 @@
         return requireNonNull(out.get(outConfig));
     }
 
+    @NonNull
+    private SurfaceProcessorNode getSharingNode(@NonNull CameraInternal camera,
+            @NonNull StreamSpec streamSpec) {
+        if (getEffect() != null
+                && getEffect().getOutputOption()
+                == CameraEffect.OUTPUT_OPTION_ONE_FOR_EACH_TARGET) {
+            // The effect wants to handle the sharing itself. Use the effect's node for sharing.
+            mEffectNode = new SurfaceProcessorNode(camera,
+                    getEffect().createSurfaceProcessorInternal());
+            return mEffectNode;
+        } else {
+            // Create an internal node for sharing.
+            return new SurfaceProcessorNode(camera,
+                    DefaultSurfaceProcessor.Factory.newInstance(streamSpec.getDynamicRange()));
+        }
+    }
+
     private int getRotationAppliedByEffect() {
         CameraEffect effect = checkNotNull(getEffect());
         if (effect.getTransformation() == CameraEffect.TRANSFORMATION_CAMERA_AND_SURFACE_ROTATION) {
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/streamsharing/ResolutionsMergerTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/streamsharing/ResolutionsMergerTest.kt
index dde7b9e..f54e764 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/streamsharing/ResolutionsMergerTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/streamsharing/ResolutionsMergerTest.kt
@@ -629,6 +629,17 @@
     }
 
     @Test
+    fun getParentSizesThatAreTooLarge_containsDuplicateParentSize() {
+        val parentSizes = listOf(
+            SIZE_1920_1440,
+            SIZE_1920_1440, // duplicate
+            SIZE_1280_960,
+        )
+        val childSizes = setOf(SIZE_1920_1080)
+        assertThat(getParentSizesThatAreTooLarge(childSizes, parentSizes)).isEmpty()
+    }
+
+    @Test
     fun hasUpscaling_return_false_whenTwoSizesAreEqualed() {
         assertThat(hasUpscaling(SIZE_1280_960, SIZE_1280_960)).isFalse()
         assertThat(hasUpscaling(SIZE_1920_1080, SIZE_1920_1080)).isFalse()
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/streamsharing/StreamSharingTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/streamsharing/StreamSharingTest.kt
index e427b91..71dc045 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/streamsharing/StreamSharingTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/streamsharing/StreamSharingTest.kt
@@ -60,6 +60,7 @@
 import androidx.camera.core.internal.TargetConfig.OPTION_TARGET_CLASS
 import androidx.camera.core.internal.TargetConfig.OPTION_TARGET_NAME
 import androidx.camera.core.processing.DefaultSurfaceProcessor
+import androidx.camera.core.processing.SurfaceProcessorWithExecutor
 import androidx.camera.testing.fakes.FakeCamera
 import androidx.camera.testing.fakes.FakeCameraInfoInternal
 import androidx.camera.testing.impl.fakes.FakeCameraCaptureResult
@@ -147,6 +148,37 @@
     }
 
     @Test
+    fun effectHandleSharing_effectUsedAsSharingNode() {
+        // Arrange: create an effect that handles sharing.
+        effect = FakeSurfaceEffect(
+            PREVIEW or VIDEO_CAPTURE,
+            CameraEffect.TRANSFORMATION_CAMERA_AND_SURFACE_ROTATION,
+            CameraEffect.OUTPUT_OPTION_ONE_FOR_EACH_TARGET,
+            effectProcessor
+        )
+        val preview = Preview.Builder().build()
+        val videoCapture = VideoCapture.Builder(Recorder.Builder().build()).build()
+        streamSharing =
+            StreamSharing(frontCamera, setOf(preview, videoCapture), useCaseConfigFactory)
+        streamSharing.setViewPortCropRect(cropRect)
+        streamSharing.effect = effect
+
+        // Act: Bind effect and get sharing input edge.
+        streamSharing.bindToCamera(frontCamera, null, defaultConfig)
+        streamSharing.onSuggestedStreamSpecUpdated(StreamSpec.builder(size).build())
+
+        // Assert: the sharing node is built with the effect's processor
+        val sharingProcessor =
+            (streamSharing.sharingNode!!.surfaceProcessor as SurfaceProcessorWithExecutor).processor
+        assertThat(sharingProcessor).isEqualTo(effectProcessor)
+        assertThat(streamSharing.sharingInputEdge).isEqualTo(streamSharing.cameraEdge)
+        assertThat(streamSharing.virtualCameraAdapter.mChildrenEdges[preview]!!.targets)
+            .isEqualTo(PREVIEW)
+        assertThat(streamSharing.virtualCameraAdapter.mChildrenEdges[videoCapture]!!.targets)
+            .isEqualTo(VIDEO_CAPTURE)
+    }
+
+    @Test
     fun effectHandleRotationAndMirroring_remainingTransformationIsEmpty() {
         // Arrange: create an effect that handles rotation.
         effect = FakeSurfaceEffect(
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/impl/fakes/FakeSurfaceEffect.java b/camera/camera-testing/src/main/java/androidx/camera/testing/impl/fakes/FakeSurfaceEffect.java
index 26925b4..9a5a3df 100644
--- a/camera/camera-testing/src/main/java/androidx/camera/testing/impl/fakes/FakeSurfaceEffect.java
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/impl/fakes/FakeSurfaceEffect.java
@@ -66,6 +66,14 @@
         mSurfaceProcessorInternal = surfaceProcessorInternal;
     }
 
+    public FakeSurfaceEffect(@Targets int targets, @Transformations int transformation,
+            @OutputOptions int targetOption,
+            @NonNull SurfaceProcessorInternal surfaceProcessorInternal) {
+        super(targets, transformation, targetOption, mainThreadExecutor(), surfaceProcessorInternal,
+                throwable -> {
+                });
+    }
+
     /**
      * Create a fake {@link CameraEffect} the {@link #createSurfaceProcessorInternal} value
      * overridden.
diff --git a/camera/camera-video/src/androidTest/java/androidx/camera/video/internal/audio/AudioRecordCompatibilityTest.kt b/camera/camera-video/src/androidTest/java/androidx/camera/video/internal/audio/AudioRecordCompatibilityTest.kt
index 55cc4e3..5121639 100644
--- a/camera/camera-video/src/androidTest/java/androidx/camera/video/internal/audio/AudioRecordCompatibilityTest.kt
+++ b/camera/camera-video/src/androidTest/java/androidx/camera/video/internal/audio/AudioRecordCompatibilityTest.kt
@@ -25,7 +25,7 @@
 import android.os.Build
 import androidx.annotation.RequiresApi
 import androidx.camera.core.Logger
-import androidx.camera.testing.impl.LabTestRule
+import androidx.camera.testing.impl.RequiresDevice
 import androidx.camera.video.internal.audio.AudioUtils.computeInterpolatedTimeNs
 import androidx.camera.video.internal.audio.AudioUtils.getBytesPerFrame
 import androidx.camera.video.internal.audio.AudioUtils.sizeToFrameCount
@@ -75,9 +75,6 @@
     }
 
     @get:Rule
-    val labTest: LabTestRule = LabTestRule()
-
-    @get:Rule
     var audioPermissionRule: GrantPermissionRule = GrantPermissionRule.grant(
         Manifest.permission.RECORD_AUDIO
     )
@@ -103,7 +100,7 @@
     }
 
     // See b/301067226 for more information.
-    @LabTestRule.LabTestOnly
+    @RequiresDevice
     @SdkSuppress(minSdkVersion = 24)
     @Test
     fun read_withNoNegativeFramePositionIssue_whenRecordingMultipleTimes() {
@@ -130,7 +127,7 @@
     }
 
     // See b/301067226 for more information.
-    @LabTestRule.LabTestOnly
+    @RequiresDevice
     @SdkSuppress(minSdkVersion = 24)
     @Test
     fun read_withNoNegativeFramePositionIssue_whenRecordingAfterRecreatingMultipleTimes() {
@@ -158,7 +155,7 @@
     }
 
     // See b/301067226 for more information.
-    @LabTestRule.LabTestOnly
+    @RequiresDevice
     @SdkSuppress(minSdkVersion = 24)
     @Test
     fun read_withTimestampDiffToSystemInLimit_whenRecordingMultipleTimes() {
diff --git a/camera/camera-view/src/androidTest/java/androidx/camera/view/VideoCaptureDeviceTest.kt b/camera/camera-view/src/androidTest/java/androidx/camera/view/VideoCaptureDeviceTest.kt
index 2890858..06a97b4 100644
--- a/camera/camera-view/src/androidTest/java/androidx/camera/view/VideoCaptureDeviceTest.kt
+++ b/camera/camera-view/src/androidTest/java/androidx/camera/view/VideoCaptureDeviceTest.kt
@@ -220,6 +220,7 @@
 
     @Test
     fun canRecordToMediaStore() {
+        if (Build.VERSION.SDK_INT == 28) return // b/264902324
         assumeTrue(
             "Ignore the test since the MediaStore.Video has compatibility issues.",
             DeviceQuirks.get(MediaStoreVideoCannotWrite::class.java) == null
@@ -281,6 +282,7 @@
 
     @Test
     fun canRecordToFile_withoutAudio_whenAudioDisabled() {
+        if (Build.VERSION.SDK_INT == 28) return // b/264902324
         // Arrange.
         val file = createTempFile()
         val outputOptions = FileOutputOptions.Builder(file).build()
@@ -299,6 +301,7 @@
 
     @Test
     fun canRecordToFile_whenLifecycleStops() {
+        if (Build.VERSION.SDK_INT == 28) return // b/264902324
         assumeStopCodecAfterSurfaceRemovalCrashMediaServerQuirk()
 
         // Arrange.
@@ -374,6 +377,7 @@
 
     @Test
     fun canRecordToFile_rightAfterPreviousRecordingStopped() {
+        if (Build.VERSION.SDK_INT == 30) return // b/264902324
         // Arrange.
         val file1 = createTempFile()
         val file2 = createTempFile()
diff --git a/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/viewpager/ViewPager2ActivityTest.kt b/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/viewpager/ViewPager2ActivityTest.kt
index 75ed2eb..39ad0ec 100644
--- a/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/viewpager/ViewPager2ActivityTest.kt
+++ b/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/viewpager/ViewPager2ActivityTest.kt
@@ -41,6 +41,7 @@
 import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
 import androidx.test.espresso.matcher.ViewMatchers.withId
 import androidx.test.filters.LargeTest
+import androidx.test.filters.SdkSuppress
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.google.common.truth.Truth.assertThat
@@ -156,6 +157,7 @@
     }
 
     // The test makes sure the TextureView surface texture keeps the same after switch.
+    @SdkSuppress(maxSdkVersion = 33) // b/331933633
     @Test
     fun testPreviewViewUpdateAfterSwitch() {
 
diff --git a/car/app/app-automotive/src/main/res/values-nl/strings.xml b/car/app/app-automotive/src/main/res/values-nl/strings.xml
index d1c0cbd..c9bcda9 100644
--- a/car/app/app-automotive/src/main/res/values-nl/strings.xml
+++ b/car/app/app-automotive/src/main/res/values-nl/strings.xml
@@ -18,7 +18,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="error_action_finish" msgid="7621130025103996211">"App sluiten"</string>
-    <string name="error_action_update_host" msgid="4802951804749609593">"Controleren op updates"</string>
+    <string name="error_action_update_host" msgid="4802951804749609593">"Zoeken naar updates"</string>
     <string name="error_action_retry" msgid="985347670495166517">"Opnieuw proberen"</string>
     <string name="error_message_client_side_error" msgid="3323186720368387787">"App-fout. Meld deze fout aan de app-ontwikkelaar."</string>
     <string name="error_message_host_error" msgid="5484419926049675696">"Systeemfout"</string>
diff --git a/car/app/app-automotive/src/main/res/values-te/strings.xml b/car/app/app-automotive/src/main/res/values-te/strings.xml
index f331f46..546f0bf 100644
--- a/car/app/app-automotive/src/main/res/values-te/strings.xml
+++ b/car/app/app-automotive/src/main/res/values-te/strings.xml
@@ -17,7 +17,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="error_action_finish" msgid="7621130025103996211">"యాప్‌ను మూసివేయి"</string>
+    <string name="error_action_finish" msgid="7621130025103996211">"యాప్‌ను మూసివేయండి"</string>
     <string name="error_action_update_host" msgid="4802951804749609593">"అప్‌డేట్‌ల కోసం చెక్ చేయండి"</string>
     <string name="error_action_retry" msgid="985347670495166517">"మళ్లీ ట్రై చేయండి"</string>
     <string name="error_message_client_side_error" msgid="3323186720368387787">"యాప్ ఎర్రర్. దయచేసి ఈ ఎర్రర్‌ను యాప్ డెవలపర్‌కు రిపోర్ట్ చేయండి"</string>
diff --git a/car/app/app-samples/showcase/common/src/main/res/values-ar/strings.xml b/car/app/app-samples/showcase/common/src/main/res/values-ar/strings.xml
index 50819b5..31c6ba3 100644
--- a/car/app/app-samples/showcase/common/src/main/res/values-ar/strings.xml
+++ b/car/app/app-samples/showcase/common/src/main/res/values-ar/strings.xml
@@ -40,7 +40,7 @@
     <string name="reject_action_title" msgid="6730366705938402668">"رفض"</string>
     <string name="ok_action_title" msgid="7128494973966098611">"حسنًا"</string>
     <string name="throw_action_title" msgid="7163710562670220163">"طرح"</string>
-    <string name="commute_action_title" msgid="2585755255290185096">"تنقُّل"</string>
+    <string name="commute_action_title" msgid="2585755255290185096">"التنقُّل"</string>
     <string name="sign_out_action_title" msgid="1653943000866713010">"تسجيل الخروج"</string>
     <string name="try_anyway_action_title" msgid="7384500054249311718">"المحاولة على أيّ حال"</string>
     <string name="yes_action_title" msgid="5507096013762092189">"نعم"</string>
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 62e4725..2668924 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
@@ -247,7 +247,7 @@
     <string name="sign_in_instructions" msgid="9044850228284294762">"Introdueix les teves credencials"</string>
     <string name="invalid_email_error_msg" msgid="5261362663718987167">"El nom d\'usuari ha de ser una adreça electrònica vàlida"</string>
     <string name="invalid_length_error_msg" msgid="8238905276326976425">"El nom d\'usuari ha de tenir com a mínim %s caràcters"</string>
-    <string name="invalid_password_error_msg" msgid="1090359893902674610">"La contrasenya no és vàlida"</string>
+    <string name="invalid_password_error_msg" msgid="1090359893902674610">"Contrasenya no vàlida"</string>
     <string name="password_hint" msgid="2869107073860012864">"contrasenya"</string>
     <string name="password_sign_in_instruction_prefix" msgid="9105788349198243508">"Nom d\'usuari"</string>
     <string name="pin_sign_in_instruction" msgid="2288691296234360441">"Escriu aquest PIN al telèfon"</string>
diff --git a/car/app/app-samples/showcase/common/src/main/res/values-in/strings.xml b/car/app/app-samples/showcase/common/src/main/res/values-in/strings.xml
index 38c0edf..abe09b9 100644
--- a/car/app/app-samples/showcase/common/src/main/res/values-in/strings.xml
+++ b/car/app/app-samples/showcase/common/src/main/res/values-in/strings.xml
@@ -40,7 +40,7 @@
     <string name="reject_action_title" msgid="6730366705938402668">"Tolak"</string>
     <string name="ok_action_title" msgid="7128494973966098611">"Oke"</string>
     <string name="throw_action_title" msgid="7163710562670220163">"Lempar"</string>
-    <string name="commute_action_title" msgid="2585755255290185096">"Perjalanan"</string>
+    <string name="commute_action_title" msgid="2585755255290185096">"Perjalanan sehari-hari"</string>
     <string name="sign_out_action_title" msgid="1653943000866713010">"Logout"</string>
     <string name="try_anyway_action_title" msgid="7384500054249311718">"Tetap Coba"</string>
     <string name="yes_action_title" msgid="5507096013762092189">"Ya"</string>
diff --git a/car/app/app-samples/showcase/common/src/main/res/values-zh-rTW/strings.xml b/car/app/app-samples/showcase/common/src/main/res/values-zh-rTW/strings.xml
index f4b2b1d..78779d1 100644
--- a/car/app/app-samples/showcase/common/src/main/res/values-zh-rTW/strings.xml
+++ b/car/app/app-samples/showcase/common/src/main/res/values-zh-rTW/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="8456567953748293512">"這是紅色的文字"</string>
     <string name="example_2_text" msgid="718820705318661440">"這是綠色的文字"</string>
diff --git a/compose/animation/animation-core/api/current.txt b/compose/animation/animation-core/api/current.txt
index b69132f..b4bf45a 100644
--- a/compose/animation/animation-core/api/current.txt
+++ b/compose/animation/animation-core/api/current.txt
@@ -125,7 +125,8 @@
     method @Deprecated @androidx.compose.runtime.Stable public static <T> androidx.compose.animation.core.InfiniteRepeatableSpec<T> infiniteRepeatable(androidx.compose.animation.core.DurationBasedAnimationSpec<T> animation, optional androidx.compose.animation.core.RepeatMode repeatMode);
     method @androidx.compose.runtime.Stable public static <T> androidx.compose.animation.core.InfiniteRepeatableSpec<T> infiniteRepeatable(androidx.compose.animation.core.DurationBasedAnimationSpec<T> animation, optional androidx.compose.animation.core.RepeatMode repeatMode, optional long initialStartOffset);
     method @androidx.compose.runtime.Stable public static <T> androidx.compose.animation.core.KeyframesSpec<T> keyframes(kotlin.jvm.functions.Function1<? super androidx.compose.animation.core.KeyframesSpec.KeyframesSpecConfig<T>,kotlin.Unit> init);
-    method @SuppressCompatibility @androidx.compose.animation.core.ExperimentalAnimationSpecApi @androidx.compose.runtime.Stable public static <T> androidx.compose.animation.core.KeyframesWithSplineSpec<T> keyframesWithSpline(kotlin.jvm.functions.Function1<? super androidx.compose.animation.core.KeyframesWithSplineSpec.KeyframesWithSplineSpecConfig<T>,kotlin.Unit> init);
+    method @SuppressCompatibility @androidx.compose.animation.core.ExperimentalAnimationSpecApi public static <T> androidx.compose.animation.core.KeyframesWithSplineSpec<T> keyframesWithSpline(@FloatRange(from=0.0, to=1.0) float periodicBias, kotlin.jvm.functions.Function1<? super androidx.compose.animation.core.KeyframesWithSplineSpec.KeyframesWithSplineSpecConfig<T>,kotlin.Unit> init);
+    method @SuppressCompatibility @androidx.compose.animation.core.ExperimentalAnimationSpecApi public static <T> androidx.compose.animation.core.KeyframesWithSplineSpec<T> keyframesWithSpline(kotlin.jvm.functions.Function1<? super androidx.compose.animation.core.KeyframesWithSplineSpec.KeyframesWithSplineSpecConfig<T>,kotlin.Unit> init);
     method @Deprecated @androidx.compose.runtime.Stable public static <T> androidx.compose.animation.core.RepeatableSpec<T> repeatable(int iterations, androidx.compose.animation.core.DurationBasedAnimationSpec<T> animation, optional androidx.compose.animation.core.RepeatMode repeatMode);
     method @androidx.compose.runtime.Stable public static <T> androidx.compose.animation.core.RepeatableSpec<T> repeatable(int iterations, androidx.compose.animation.core.DurationBasedAnimationSpec<T> animation, optional androidx.compose.animation.core.RepeatMode repeatMode, optional long initialStartOffset);
     method @androidx.compose.runtime.Stable public static <T> androidx.compose.animation.core.SnapSpec<T> snap(optional int delayMillis);
@@ -207,35 +208,29 @@
   }
 
   @SuppressCompatibility @androidx.compose.animation.core.ExperimentalAnimationSpecApi @androidx.compose.runtime.Immutable public final class ArcAnimationSpec<T> implements androidx.compose.animation.core.DurationBasedAnimationSpec<T> {
-    ctor public ArcAnimationSpec(optional androidx.compose.animation.core.ArcMode mode, optional int durationMillis, optional int delayMillis, optional androidx.compose.animation.core.Easing easing);
+    ctor public ArcAnimationSpec(optional int mode, optional int durationMillis, optional int delayMillis, optional androidx.compose.animation.core.Easing easing);
     method public int getDelayMillis();
     method public int getDurationMillis();
     method public androidx.compose.animation.core.Easing getEasing();
-    method public androidx.compose.animation.core.ArcMode getMode();
+    method public int getMode();
     method public <V extends androidx.compose.animation.core.AnimationVector> androidx.compose.animation.core.VectorizedDurationBasedAnimationSpec<V> vectorize(androidx.compose.animation.core.TwoWayConverter<T,V> converter);
     property public final int delayMillis;
     property public final int durationMillis;
     property public final androidx.compose.animation.core.Easing easing;
-    property public final androidx.compose.animation.core.ArcMode mode;
+    property public final int mode;
   }
 
-  @SuppressCompatibility @androidx.compose.animation.core.ExperimentalAnimationSpecApi public abstract sealed class ArcMode {
+  @SuppressCompatibility @androidx.compose.animation.core.ExperimentalAnimationSpecApi @kotlin.jvm.JvmInline public final value class ArcMode {
     field public static final androidx.compose.animation.core.ArcMode.Companion Companion;
   }
 
   public static final class ArcMode.Companion {
-  }
-
-  @SuppressCompatibility @androidx.compose.animation.core.ExperimentalAnimationSpecApi public static final class ArcMode.Companion.ArcAbove extends androidx.compose.animation.core.ArcMode {
-    field public static final androidx.compose.animation.core.ArcMode.Companion.ArcAbove INSTANCE;
-  }
-
-  @SuppressCompatibility @androidx.compose.animation.core.ExperimentalAnimationSpecApi public static final class ArcMode.Companion.ArcBelow extends androidx.compose.animation.core.ArcMode {
-    field public static final androidx.compose.animation.core.ArcMode.Companion.ArcBelow INSTANCE;
-  }
-
-  @SuppressCompatibility @androidx.compose.animation.core.ExperimentalAnimationSpecApi public static final class ArcMode.Companion.ArcLinear extends androidx.compose.animation.core.ArcMode {
-    field public static final androidx.compose.animation.core.ArcMode.Companion.ArcLinear INSTANCE;
+    method public int getArcAbove();
+    method public int getArcBelow();
+    method public int getArcLinear();
+    property public final int ArcAbove;
+    property public final int ArcBelow;
+    property public final int ArcLinear;
   }
 
   @androidx.compose.runtime.Immutable public final class CubicBezierEasing implements androidx.compose.animation.core.Easing {
@@ -501,7 +496,7 @@
     ctor public KeyframesSpec.KeyframesSpecConfig();
     method public infix androidx.compose.animation.core.KeyframesSpec.KeyframeEntity<T> at(T, @IntRange(from=0L) int timeStamp);
     method public infix androidx.compose.animation.core.KeyframesSpec.KeyframeEntity<T> atFraction(T, @FloatRange(from=0.0, to=1.0) float fraction);
-    method @SuppressCompatibility @androidx.compose.animation.core.ExperimentalAnimationSpecApi public infix androidx.compose.animation.core.KeyframesSpec.KeyframeEntity<T> using(androidx.compose.animation.core.KeyframesSpec.KeyframeEntity<T>, androidx.compose.animation.core.ArcMode arcMode);
+    method @SuppressCompatibility @androidx.compose.animation.core.ExperimentalAnimationSpecApi public infix androidx.compose.animation.core.KeyframesSpec.KeyframeEntity<T> using(androidx.compose.animation.core.KeyframesSpec.KeyframeEntity<T>, int arcMode);
     method @Deprecated public infix void with(androidx.compose.animation.core.KeyframesSpec.KeyframeEntity<T>, androidx.compose.animation.core.Easing easing);
   }
 
@@ -519,6 +514,7 @@
 
   @SuppressCompatibility @androidx.compose.animation.core.ExperimentalAnimationSpecApi @androidx.compose.runtime.Immutable public final class KeyframesWithSplineSpec<T> implements androidx.compose.animation.core.DurationBasedAnimationSpec<T> {
     ctor public KeyframesWithSplineSpec(androidx.compose.animation.core.KeyframesWithSplineSpec.KeyframesWithSplineSpecConfig<T> config);
+    ctor public KeyframesWithSplineSpec(androidx.compose.animation.core.KeyframesWithSplineSpec.KeyframesWithSplineSpecConfig<T> config, @FloatRange(from=0.0, to=1.0) float periodicBias);
     method public androidx.compose.animation.core.KeyframesWithSplineSpec.KeyframesWithSplineSpecConfig<T> getConfig();
     method public <V extends androidx.compose.animation.core.AnimationVector> androidx.compose.animation.core.VectorizedDurationBasedAnimationSpec<V> vectorize(androidx.compose.animation.core.TwoWayConverter<T,V> converter);
     property public final androidx.compose.animation.core.KeyframesWithSplineSpec.KeyframesWithSplineSpecConfig<T> config;
diff --git a/compose/animation/animation-core/api/restricted_current.txt b/compose/animation/animation-core/api/restricted_current.txt
index a861c60..bea0bde 100644
--- a/compose/animation/animation-core/api/restricted_current.txt
+++ b/compose/animation/animation-core/api/restricted_current.txt
@@ -125,7 +125,8 @@
     method @Deprecated @androidx.compose.runtime.Stable public static <T> androidx.compose.animation.core.InfiniteRepeatableSpec<T> infiniteRepeatable(androidx.compose.animation.core.DurationBasedAnimationSpec<T> animation, optional androidx.compose.animation.core.RepeatMode repeatMode);
     method @androidx.compose.runtime.Stable public static <T> androidx.compose.animation.core.InfiniteRepeatableSpec<T> infiniteRepeatable(androidx.compose.animation.core.DurationBasedAnimationSpec<T> animation, optional androidx.compose.animation.core.RepeatMode repeatMode, optional long initialStartOffset);
     method @androidx.compose.runtime.Stable public static <T> androidx.compose.animation.core.KeyframesSpec<T> keyframes(kotlin.jvm.functions.Function1<? super androidx.compose.animation.core.KeyframesSpec.KeyframesSpecConfig<T>,kotlin.Unit> init);
-    method @SuppressCompatibility @androidx.compose.animation.core.ExperimentalAnimationSpecApi @androidx.compose.runtime.Stable public static <T> androidx.compose.animation.core.KeyframesWithSplineSpec<T> keyframesWithSpline(kotlin.jvm.functions.Function1<? super androidx.compose.animation.core.KeyframesWithSplineSpec.KeyframesWithSplineSpecConfig<T>,kotlin.Unit> init);
+    method @SuppressCompatibility @androidx.compose.animation.core.ExperimentalAnimationSpecApi public static <T> androidx.compose.animation.core.KeyframesWithSplineSpec<T> keyframesWithSpline(@FloatRange(from=0.0, to=1.0) float periodicBias, kotlin.jvm.functions.Function1<? super androidx.compose.animation.core.KeyframesWithSplineSpec.KeyframesWithSplineSpecConfig<T>,kotlin.Unit> init);
+    method @SuppressCompatibility @androidx.compose.animation.core.ExperimentalAnimationSpecApi public static <T> androidx.compose.animation.core.KeyframesWithSplineSpec<T> keyframesWithSpline(kotlin.jvm.functions.Function1<? super androidx.compose.animation.core.KeyframesWithSplineSpec.KeyframesWithSplineSpecConfig<T>,kotlin.Unit> init);
     method @Deprecated @androidx.compose.runtime.Stable public static <T> androidx.compose.animation.core.RepeatableSpec<T> repeatable(int iterations, androidx.compose.animation.core.DurationBasedAnimationSpec<T> animation, optional androidx.compose.animation.core.RepeatMode repeatMode);
     method @androidx.compose.runtime.Stable public static <T> androidx.compose.animation.core.RepeatableSpec<T> repeatable(int iterations, androidx.compose.animation.core.DurationBasedAnimationSpec<T> animation, optional androidx.compose.animation.core.RepeatMode repeatMode, optional long initialStartOffset);
     method @androidx.compose.runtime.Stable public static <T> androidx.compose.animation.core.SnapSpec<T> snap(optional int delayMillis);
@@ -207,35 +208,29 @@
   }
 
   @SuppressCompatibility @androidx.compose.animation.core.ExperimentalAnimationSpecApi @androidx.compose.runtime.Immutable public final class ArcAnimationSpec<T> implements androidx.compose.animation.core.DurationBasedAnimationSpec<T> {
-    ctor public ArcAnimationSpec(optional androidx.compose.animation.core.ArcMode mode, optional int durationMillis, optional int delayMillis, optional androidx.compose.animation.core.Easing easing);
+    ctor public ArcAnimationSpec(optional int mode, optional int durationMillis, optional int delayMillis, optional androidx.compose.animation.core.Easing easing);
     method public int getDelayMillis();
     method public int getDurationMillis();
     method public androidx.compose.animation.core.Easing getEasing();
-    method public androidx.compose.animation.core.ArcMode getMode();
+    method public int getMode();
     method public <V extends androidx.compose.animation.core.AnimationVector> androidx.compose.animation.core.VectorizedDurationBasedAnimationSpec<V> vectorize(androidx.compose.animation.core.TwoWayConverter<T,V> converter);
     property public final int delayMillis;
     property public final int durationMillis;
     property public final androidx.compose.animation.core.Easing easing;
-    property public final androidx.compose.animation.core.ArcMode mode;
+    property public final int mode;
   }
 
-  @SuppressCompatibility @androidx.compose.animation.core.ExperimentalAnimationSpecApi public abstract sealed class ArcMode {
+  @SuppressCompatibility @androidx.compose.animation.core.ExperimentalAnimationSpecApi @kotlin.jvm.JvmInline public final value class ArcMode {
     field public static final androidx.compose.animation.core.ArcMode.Companion Companion;
   }
 
   public static final class ArcMode.Companion {
-  }
-
-  @SuppressCompatibility @androidx.compose.animation.core.ExperimentalAnimationSpecApi public static final class ArcMode.Companion.ArcAbove extends androidx.compose.animation.core.ArcMode {
-    field public static final androidx.compose.animation.core.ArcMode.Companion.ArcAbove INSTANCE;
-  }
-
-  @SuppressCompatibility @androidx.compose.animation.core.ExperimentalAnimationSpecApi public static final class ArcMode.Companion.ArcBelow extends androidx.compose.animation.core.ArcMode {
-    field public static final androidx.compose.animation.core.ArcMode.Companion.ArcBelow INSTANCE;
-  }
-
-  @SuppressCompatibility @androidx.compose.animation.core.ExperimentalAnimationSpecApi public static final class ArcMode.Companion.ArcLinear extends androidx.compose.animation.core.ArcMode {
-    field public static final androidx.compose.animation.core.ArcMode.Companion.ArcLinear INSTANCE;
+    method public int getArcAbove();
+    method public int getArcBelow();
+    method public int getArcLinear();
+    property public final int ArcAbove;
+    property public final int ArcBelow;
+    property public final int ArcLinear;
   }
 
   @androidx.compose.runtime.Immutable public final class CubicBezierEasing implements androidx.compose.animation.core.Easing {
@@ -501,7 +496,7 @@
     ctor public KeyframesSpec.KeyframesSpecConfig();
     method public infix androidx.compose.animation.core.KeyframesSpec.KeyframeEntity<T> at(T, @IntRange(from=0L) int timeStamp);
     method public infix androidx.compose.animation.core.KeyframesSpec.KeyframeEntity<T> atFraction(T, @FloatRange(from=0.0, to=1.0) float fraction);
-    method @SuppressCompatibility @androidx.compose.animation.core.ExperimentalAnimationSpecApi public infix androidx.compose.animation.core.KeyframesSpec.KeyframeEntity<T> using(androidx.compose.animation.core.KeyframesSpec.KeyframeEntity<T>, androidx.compose.animation.core.ArcMode arcMode);
+    method @SuppressCompatibility @androidx.compose.animation.core.ExperimentalAnimationSpecApi public infix androidx.compose.animation.core.KeyframesSpec.KeyframeEntity<T> using(androidx.compose.animation.core.KeyframesSpec.KeyframeEntity<T>, int arcMode);
     method @Deprecated public infix void with(androidx.compose.animation.core.KeyframesSpec.KeyframeEntity<T>, androidx.compose.animation.core.Easing easing);
   }
 
@@ -519,6 +514,7 @@
 
   @SuppressCompatibility @androidx.compose.animation.core.ExperimentalAnimationSpecApi @androidx.compose.runtime.Immutable public final class KeyframesWithSplineSpec<T> implements androidx.compose.animation.core.DurationBasedAnimationSpec<T> {
     ctor public KeyframesWithSplineSpec(androidx.compose.animation.core.KeyframesWithSplineSpec.KeyframesWithSplineSpecConfig<T> config);
+    ctor public KeyframesWithSplineSpec(androidx.compose.animation.core.KeyframesWithSplineSpec.KeyframesWithSplineSpecConfig<T> config, @FloatRange(from=0.0, to=1.0) float periodicBias);
     method public androidx.compose.animation.core.KeyframesWithSplineSpec.KeyframesWithSplineSpecConfig<T> getConfig();
     method public <V extends androidx.compose.animation.core.AnimationVector> androidx.compose.animation.core.VectorizedDurationBasedAnimationSpec<V> vectorize(androidx.compose.animation.core.TwoWayConverter<T,V> converter);
     property public final androidx.compose.animation.core.KeyframesWithSplineSpec.KeyframesWithSplineSpecConfig<T> config;
diff --git a/compose/animation/animation-core/samples/src/main/java/androidx/compose/animation/core/samples/AnimatableSamples.kt b/compose/animation/animation-core/samples/src/main/java/androidx/compose/animation/core/samples/AnimatableSamples.kt
index 0ddab6d..13e6acb 100644
--- a/compose/animation/animation-core/samples/src/main/java/androidx/compose/animation/core/samples/AnimatableSamples.kt
+++ b/compose/animation/animation-core/samples/src/main/java/androidx/compose/animation/core/samples/AnimatableSamples.kt
@@ -252,12 +252,12 @@
         sizeAnimation: DeferredTargetAnimation<IntSize, AnimationVector2D>,
         coroutineScope: CoroutineScope
     ) = this.approachLayout(
-        isMeasurementApproachComplete = { lookaheadSize ->
+        isMeasurementApproachInProgress = { lookaheadSize ->
             // Update the target of the size animation.
             sizeAnimation.updateTarget(lookaheadSize, coroutineScope)
-            // Return true if the size animation has no pending target change and has finished
+            // Return true if the size animation has pending target change or is currently
             // running.
-            sizeAnimation.isIdle
+            !sizeAnimation.isIdle
         }
     ) { measurable, _ ->
         // In the measurement approach, the goal is to gradually reach the destination size
diff --git a/compose/animation/animation-core/samples/src/main/java/androidx/compose/animation/core/samples/KeyframesWithSplineBuilderSample.kt b/compose/animation/animation-core/samples/src/main/java/androidx/compose/animation/core/samples/KeyframesWithSplineBuilderSample.kt
index 701201d..c69397e 100644
--- a/compose/animation/animation-core/samples/src/main/java/androidx/compose/animation/core/samples/KeyframesWithSplineBuilderSample.kt
+++ b/compose/animation/animation-core/samples/src/main/java/androidx/compose/animation/core/samples/KeyframesWithSplineBuilderSample.kt
@@ -18,8 +18,26 @@
 
 import androidx.annotation.Sampled
 import androidx.compose.animation.core.ExperimentalAnimationSpecApi
+import androidx.compose.animation.core.LinearEasing
+import androidx.compose.animation.core.RepeatMode
+import androidx.compose.animation.core.animate
+import androidx.compose.animation.core.infiniteRepeatable
 import androidx.compose.animation.core.keyframesWithSpline
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.layout.size
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Favorite
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableFloatStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
 import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.ColorFilter
+import androidx.compose.ui.graphics.graphicsLayer
 import androidx.compose.ui.unit.DpOffset
 import androidx.compose.ui.unit.IntOffset
 import androidx.compose.ui.unit.dp
@@ -56,3 +74,36 @@
         DpOffset(400.dp, 50.dp) at 150
     }
 }
+
+@OptIn(ExperimentalAnimationSpecApi::class)
+@Composable
+@Sampled
+fun PeriodicKeyframesWithSplines() {
+    var alpha by remember { mutableFloatStateOf(0f) }
+    LaunchedEffect(Unit) {
+        animate(
+            initialValue = 0f,
+            targetValue = 0f,
+            animationSpec = infiniteRepeatable(
+                // With a periodicBias of 0.5f it creates a similar animation to a sinusoidal curve
+                // so the transition as the animation repeats is completely seamless
+                animation = keyframesWithSpline(periodicBias = 0.5f) {
+                    durationMillis = 2000
+
+                    1f at 1000 using LinearEasing
+                },
+                repeatMode = RepeatMode.Restart
+            )
+        ) { value, _ ->
+            alpha = value
+        }
+    }
+    Image(
+        imageVector = Icons.Filled.Favorite,
+        contentDescription = null,
+        modifier = Modifier
+            .size(150.dp)
+            .graphicsLayer { this.alpha = alpha },
+        colorFilter = ColorFilter.tint(Color.Red)
+    )
+}
diff --git a/compose/animation/animation-core/src/androidUnitTest/kotlin/androidx/compose/animation/core/KeyframeSplineAnimationTest.kt b/compose/animation/animation-core/src/androidUnitTest/kotlin/androidx/compose/animation/core/KeyframeSplineAnimationTest.kt
index d6f6aea..64c1360 100644
--- a/compose/animation/animation-core/src/androidUnitTest/kotlin/androidx/compose/animation/core/KeyframeSplineAnimationTest.kt
+++ b/compose/animation/animation-core/src/androidUnitTest/kotlin/androidx/compose/animation/core/KeyframeSplineAnimationTest.kt
@@ -61,6 +61,82 @@
         )
     }
 
+    // Tests the expected effect that different periodic bias have compared against a regular spline
+    @Test
+    fun interpolatedValues_periodic() {
+        // Testing a curve with points at [0, 1, 0], where the intermediate point is at half of the
+        // duration
+        // This means that on a linear interpolation, the initial velocity (past 0ms) would be
+        // positive and the final velocity would be negative with the same magnitude
+        val sharedConfig = KeyframesWithSplineSpec.KeyframesWithSplineSpecConfig<Float>().apply {
+            durationMillis = 1000
+
+            1f at 500 using LinearEasing
+        }
+
+        // We'll compare different periodic bias against the regular spline
+        val splineAnimation = KeyframesWithSplineSpec(sharedConfig, Float.NaN)
+            .vectorize(Float.VectorConverter)
+        val splineAnimationBalancedBias = KeyframesWithSplineSpec(sharedConfig, 0.5f)
+            .vectorize(Float.VectorConverter)
+        val splineAnimationStartBias = KeyframesWithSplineSpec(sharedConfig, 0f)
+            .vectorize(Float.VectorConverter)
+        val splineAnimationEndBias = KeyframesWithSplineSpec(sharedConfig, 1f)
+            .vectorize(Float.VectorConverter)
+
+        // Periodic bias affect the velocity at the start and end of the animation.
+        // Note that we don't test at exactly 0 since that would always return the initial velocity
+        fun VectorizedDurationBasedAnimationSpec<AnimationVector1D>.startVelocity():
+            AnimationVector1D {
+            return getVelocityFromNanos(
+                playTimeNanos = 1L,
+                initialValue = AnimationVector1D(0f),
+                targetValue = AnimationVector1D(0f),
+                initialVelocity = AnimationVector1D(0f)
+            ).let { AnimationVector1D(it.value) } // Copy since vector is reused internally
+        }
+        fun VectorizedDurationBasedAnimationSpec<AnimationVector1D>.endVelocity():
+            AnimationVector1D {
+            return getVelocityFromNanos(
+                playTimeNanos = 1000 * MillisToNanos,
+                initialValue = AnimationVector1D(0f),
+                targetValue = AnimationVector1D(0f),
+                initialVelocity = AnimationVector1D(0f)
+            ).let { AnimationVector1D(it.value) } // Copy since vector is reused internally
+        }
+
+        val regularV0 = splineAnimation.startVelocity()
+        val regularV1 = splineAnimation.endVelocity()
+
+        val balancedV0 = splineAnimationBalancedBias.startVelocity()
+        val balancedV1 = splineAnimationBalancedBias.endVelocity()
+
+        val startBiasV0 =
+            splineAnimationStartBias.startVelocity()
+        val startBiasV1 =
+            splineAnimationStartBias.endVelocity()
+
+        val endBiasV0 = splineAnimationEndBias.startVelocity()
+        val endBiasV1 = splineAnimationEndBias.endVelocity()
+
+        // On splines with periodic bias, the start and end velocity should be the same
+        assertEquals(balancedV0.value, balancedV1.value, 0.0001f)
+        assertEquals(startBiasV0.value, startBiasV1.value, 0.0001f)
+        assertEquals(endBiasV0.value, endBiasV1.value, 0.001f)
+
+        // Velocities on balanced bias should be the average of the start/end velocities of the
+        // regular monotonic spline
+        val avg = (regularV0.value + regularV1.value) / 2f
+        assertEquals(avg, balancedV0.value)
+        assertEquals(avg, balancedV1.value)
+
+        // On fully biased at the start, the end velocity remains unchanged
+        assertEquals(startBiasV1.value, regularV1.value, 0.00001f)
+
+        // On fully biased at the end, the start velocity remains unchanged
+        assertEquals(endBiasV0.value, regularV0.value, 0.00001f)
+    }
+
     @Test
     fun testMultipleEasing() {
         val animation = keyframesWithSpline {
@@ -215,8 +291,8 @@
             }
         )
 
-        animationA = KeyframesWithSplineSpec(config)
-        animationB = KeyframesWithSplineSpec(config)
+        animationA = KeyframesWithSplineSpec(config, Float.NaN)
+        animationB = KeyframesWithSplineSpec(config, Float.NaN)
 
         // Test re-using config
         assertNotEquals(animationA, animationB)
diff --git a/compose/animation/animation-core/src/androidUnitTest/kotlin/androidx/compose/animation/core/MonoSplineTest.kt b/compose/animation/animation-core/src/androidUnitTest/kotlin/androidx/compose/animation/core/MonoSplineTest.kt
index 3b1fd60..96a3ea0 100644
--- a/compose/animation/animation-core/src/androidUnitTest/kotlin/androidx/compose/animation/core/MonoSplineTest.kt
+++ b/compose/animation/animation-core/src/androidUnitTest/kotlin/androidx/compose/animation/core/MonoSplineTest.kt
@@ -31,7 +31,7 @@
         val time = floatArrayOf(
             0f, 5f, 10f
         )
-        val spline = MonoSpline(time, points)
+        val spline = MonoSpline(time, points, Float.NaN)
         var value = spline.getPos(5f, 0).toDouble()
         assertEquals(1.0, value, 0.001)
         value = spline.getPos(7f, 0).toDouble()
@@ -53,7 +53,7 @@
         val time = floatArrayOf(
             0f, 1f, 2f, 3f, 4f, 5f
         )
-        val mspline = MonoSpline(time, points)
+        val mspline = MonoSpline(time, points, Float.NaN)
         assertEquals(1.0f, mspline.getPos(1f, 0), 0.001f)
         assertEquals(1.0f, mspline.getPos(1.1f, 0), 0.001f)
         assertEquals(1.0f, mspline.getPos(1.3f, 0), 0.001f)
diff --git a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/AnimationSpec.kt b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/AnimationSpec.kt
index e0a9a50..8833cf2 100644
--- a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/AnimationSpec.kt
+++ b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/AnimationSpec.kt
@@ -725,14 +725,44 @@
  * [KeyframesWithSplineSpec] is best used with 2D values such as [Offset]. For example:
  * @sample androidx.compose.animation.core.samples.KeyframesBuilderForOffsetWithSplines
  *
+ * You may however, provide a [periodicBias] value (between 0f and 1f) to make a periodic spline.
+ * Periodic splines adjust the initial and final velocity to be the same. This is useful to
+ * create smooth repeatable animations. Such as an infinite pulsating animation:
+ *
+ * @sample androidx.compose.animation.core.samples.PeriodicKeyframesWithSplines
+ *
+ * The [periodicBias] value (from 0.0 to 1.0) indicates how much of the original starting and final
+ * velocity are modified to achieve periodicity:
+ * - 0f: Modifies only the starting velocity to match the final velocity
+ * - 1f: Modifies only the final velocity to match the starting velocity
+ * - 0.5f: Modifies both velocities equally, picking the average between the two
+ *
  * @see keyframesWithSpline
  * @sample androidx.compose.animation.core.samples.KeyframesBuilderForIntOffsetWithSplines
  * @sample androidx.compose.animation.core.samples.KeyframesBuilderForDpOffsetWithSplines
  */
 @ExperimentalAnimationSpecApi
 @Immutable
-class KeyframesWithSplineSpec<T>(val config: KeyframesWithSplineSpecConfig<T>) :
-    DurationBasedAnimationSpec<T> {
+class KeyframesWithSplineSpec<T>(
+    val config: KeyframesWithSplineSpecConfig<T>,
+) : DurationBasedAnimationSpec<T> {
+    // Periodic bias property, NaN by default. Only meant to be set by secondary constructor
+    private var periodicBias: Float = Float.NaN
+
+    /**
+     * Constructor that returns a periodic spline implementation.
+     *
+     * @param config Keyframe configuration of the spline, should contain the set of values,
+     * timestamps and easing curves to animate through.
+     * @param periodicBias A value from 0f to 1f, indicating how much the starting or ending
+     * velocities are modified respectively to achieve periodicity.
+     */
+    constructor(
+        config: KeyframesWithSplineSpecConfig<T>,
+        @FloatRange(0.0, 1.0) periodicBias: Float
+    ) : this(config) {
+        this.periodicBias = periodicBias
+    }
 
     @ExperimentalAnimationSpecApi
     class KeyframesWithSplineSpecConfig<T> :
@@ -763,7 +793,8 @@
             timestamps = timestamps,
             keyframes = timeToVectorMap,
             durationMillis = config.durationMillis,
-            delayMillis = config.delayMillis
+            delayMillis = config.delayMillis,
+            periodicBias = periodicBias
         )
     }
 }
@@ -834,7 +865,6 @@
  * @sample androidx.compose.animation.core.samples.KeyframesBuilderForDpOffsetWithSplines
  */
 @ExperimentalAnimationSpecApi
-@Stable
 fun <T> keyframesWithSpline(
     init: KeyframesWithSplineSpec.KeyframesWithSplineSpecConfig<T>.() -> Unit
 ): KeyframesWithSplineSpec<T> =
@@ -843,6 +873,37 @@
     )
 
 /**
+ * Creates a *periodic* [KeyframesWithSplineSpec] animation, initialized with [init].
+ *
+ * Use overload without [periodicBias] parameter for the non-periodic implementation.
+ *
+ * A periodic spline is one such that the starting and ending velocities are equal. This makes them
+ * useful to crete smooth repeatable animations. Such as an infinite pulsating animation:
+ *
+ * @sample androidx.compose.animation.core.samples.PeriodicKeyframesWithSplines
+ *
+ * The [periodicBias] value (from 0.0 to 1.0) indicates how much of the original starting and final
+ * velocity are modified to achieve periodicity:
+ * - 0f: Modifies only the starting velocity to match the final velocity
+ * - 1f: Modifies only the final velocity to match the starting velocity
+ * - 0.5f: Modifies both velocities equally, picking the average between the two
+ *
+ * @param periodicBias A value from 0f to 1f, indicating how much the starting or ending velocities
+ * are modified respectively to achieve periodicity.
+ * @param init Initialization function for the [KeyframesWithSplineSpec] animation
+ * @see KeyframesWithSplineSpec.KeyframesWithSplineSpecConfig
+ */
+@ExperimentalAnimationSpecApi
+fun <T> keyframesWithSpline(
+    @FloatRange(0.0, 1.0) periodicBias: Float,
+    init: KeyframesWithSplineSpec.KeyframesWithSplineSpecConfig<T>.() -> Unit
+): KeyframesWithSplineSpec<T> =
+    KeyframesWithSplineSpec(
+        config = KeyframesWithSplineSpec.KeyframesWithSplineSpecConfig<T>().apply(init),
+        periodicBias = periodicBias,
+    )
+
+/**
  * Creates a [RepeatableSpec] that plays a [DurationBasedAnimationSpec] (e.g.
  * [TweenSpec], [KeyframesSpec]) the amount of iterations specified by [iterations].
  *
diff --git a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/MonoSpline.kt b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/MonoSpline.kt
index 850ad269..3dd88e4 100644
--- a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/MonoSpline.kt
+++ b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/MonoSpline.kt
@@ -23,7 +23,7 @@
  * time is an array of all positions and y is a list of arrays each with the values at each point
  */
 @ExperimentalAnimationSpecApi
-internal class MonoSpline(time: FloatArray, y: Array<FloatArray>) {
+internal class MonoSpline(time: FloatArray, y: Array<FloatArray>, periodicBias: Float) {
     private val timePoints: FloatArray
     private val values: Array<FloatArray>
     private val tangents: Array<FloatArray>
@@ -48,6 +48,17 @@
             }
             tangent[n - 1][j] = slope[n - 2][j]
         }
+        if (!periodicBias.isNaN()) {
+            for (j in 0 until dim) {
+                // Slope indicated by bias, where 0.0f is the last slope and 1f is the initial slope
+                val adjustedSlope =
+                    (slope[n - 2][j] * (1 - periodicBias)) + (slope[0][j] * periodicBias)
+                slope[0][j] = adjustedSlope
+                slope[n - 2][j] = adjustedSlope
+                tangent[n - 1][j] = adjustedSlope
+                tangent[0][j] = adjustedSlope
+            }
+        }
         for (i in 0 until n - 1) {
             for (j in 0 until dim) {
                 if (slope[i][j] == 0.0f) {
@@ -208,14 +219,24 @@
      * You may provide [index] to simplify searching for the correct keyframe for the given [time].
      */
     fun getSlope(time: Float, v: AnimationVector, index: Int = 0) {
-        var t = time
+        val t = time
         val n = timePoints.size
         val dim = values[0].size
+
+        // If time is 0, max or out of range we directly return the corresponding slope value
         if (t <= timePoints[0]) {
-            t = timePoints[0]
+            for (j in 0 until dim) {
+                v[j] = tangents[0][j]
+            }
+            return
         } else if (t >= timePoints[n - 1]) {
-            t = timePoints[n - 1]
+            for (j in 0 until dim) {
+                v[j] = tangents[n - 1][j]
+            }
+            return
         }
+
+        // Otherwise, calculate interpolated velocity
         for (i in index until n - 1) {
             if (t <= timePoints[i + 1]) {
                 val h = timePoints[i + 1] - timePoints[i]
diff --git a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/VectorizedAnimationSpec.kt b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/VectorizedAnimationSpec.kt
index 9d09a90..07d9fb2 100644
--- a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/VectorizedAnimationSpec.kt
+++ b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/VectorizedAnimationSpec.kt
@@ -529,15 +529,6 @@
         val index = timestamps.binarySearch(timeMillis)
         return if (index < -1) -(index + 2) else index
     }
-
-    @Suppress("unused")
-    private val ArcMode.value: Int
-        get() = when (this) {
-            ArcMode.Companion.ArcAbove -> ArcSpline.ArcAbove
-            ArcMode.Companion.ArcBelow -> ArcSpline.ArcBelow
-            ArcMode.Companion.ArcLinear -> ArcSpline.ArcStartLinear
-            else -> ArcSpline.ArcStartLinear // Unknown mode, fallback to linear
-        }
 }
 
 @OptIn(ExperimentalAnimationSpecApi::class)
@@ -557,35 +548,28 @@
  * @see ArcAnimationSpec
  */
 @ExperimentalAnimationSpecApi
-sealed class ArcMode {
+@JvmInline
+value class ArcMode internal constructor(internal val value: Int) {
+
     companion object {
         /**
          * Interpolates using a quarter of an Ellipse where the curve is "above" the center of the
          * Ellipse.
          */
-        @ExperimentalAnimationSpecApi
-        object ArcAbove : ArcMode()
+        val ArcAbove = ArcMode(ArcSpline.ArcAbove)
 
         /**
          * Interpolates using a quarter of an Ellipse where the curve is "below" the center of the
          * Ellipse.
          */
-        @ExperimentalAnimationSpecApi
-        object ArcBelow : ArcMode()
+        val ArcBelow = ArcMode(ArcSpline.ArcBelow)
 
         /**
          * An [ArcMode] that forces linear interpolation.
          *
          * You'll likely only use this mode within a keyframe.
          */
-        @ExperimentalAnimationSpecApi
-        object ArcLinear : ArcMode()
-
-        /**
-         * Unused [ArcMode] to prevent exhaustive `when` usage.
-         */
-        @Suppress("unused")
-        private object UnexpectedArc : ArcMode()
+        val ArcLinear = ArcMode(ArcSpline.ArcStartLinear)
     }
 }
 
diff --git a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/VectorizedMonoSplineKeyframesSpec.kt b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/VectorizedMonoSplineKeyframesSpec.kt
index 0bd8e17..2673945 100644
--- a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/VectorizedMonoSplineKeyframesSpec.kt
+++ b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/VectorizedMonoSplineKeyframesSpec.kt
@@ -27,7 +27,8 @@
     private val timestamps: IntList,
     private val keyframes: IntObjectMap<Pair<V, Easing>>,
     override val durationMillis: Int,
-    override val delayMillis: Int
+    override val delayMillis: Int,
+    private val periodicBias: Float,
 ) : VectorizedDurationBasedAnimationSpec<V> {
     // Objects initialized lazily once
     private lateinit var valueVector: V
@@ -99,7 +100,7 @@
                         FloatArray(dimension, targetValue::get)
                 }
             }
-            monoSpline = MonoSpline(times, values)
+            monoSpline = MonoSpline(times, values, periodicBias)
         }
     }
 
diff --git a/compose/animation/animation/api/current.txt b/compose/animation/animation/api/current.txt
index 343fa22..c84af4c 100644
--- a/compose/animation/animation/api/current.txt
+++ b/compose/animation/animation/api/current.txt
@@ -56,9 +56,9 @@
   }
 
   @kotlin.jvm.JvmDefaultWithCompatibility public interface AnimatedVisibilityScope {
-    method @SuppressCompatibility @androidx.compose.animation.ExperimentalAnimationApi public default androidx.compose.ui.Modifier animateEnterExit(androidx.compose.ui.Modifier, optional androidx.compose.animation.EnterTransition enter, optional androidx.compose.animation.ExitTransition exit, optional String label);
-    method @SuppressCompatibility @androidx.compose.animation.ExperimentalAnimationApi public androidx.compose.animation.core.Transition<androidx.compose.animation.EnterExitState> getTransition();
-    property @SuppressCompatibility @androidx.compose.animation.ExperimentalAnimationApi public abstract androidx.compose.animation.core.Transition<androidx.compose.animation.EnterExitState> transition;
+    method public default androidx.compose.ui.Modifier animateEnterExit(androidx.compose.ui.Modifier, optional androidx.compose.animation.EnterTransition enter, optional androidx.compose.animation.ExitTransition exit, optional String label);
+    method public androidx.compose.animation.core.Transition<androidx.compose.animation.EnterExitState> getTransition();
+    property public abstract androidx.compose.animation.core.Transition<androidx.compose.animation.EnterExitState> transition;
   }
 
   public final class AnimationModifierKt {
diff --git a/compose/animation/animation/api/restricted_current.txt b/compose/animation/animation/api/restricted_current.txt
index 343fa22..c84af4c 100644
--- a/compose/animation/animation/api/restricted_current.txt
+++ b/compose/animation/animation/api/restricted_current.txt
@@ -56,9 +56,9 @@
   }
 
   @kotlin.jvm.JvmDefaultWithCompatibility public interface AnimatedVisibilityScope {
-    method @SuppressCompatibility @androidx.compose.animation.ExperimentalAnimationApi public default androidx.compose.ui.Modifier animateEnterExit(androidx.compose.ui.Modifier, optional androidx.compose.animation.EnterTransition enter, optional androidx.compose.animation.ExitTransition exit, optional String label);
-    method @SuppressCompatibility @androidx.compose.animation.ExperimentalAnimationApi public androidx.compose.animation.core.Transition<androidx.compose.animation.EnterExitState> getTransition();
-    property @SuppressCompatibility @androidx.compose.animation.ExperimentalAnimationApi public abstract androidx.compose.animation.core.Transition<androidx.compose.animation.EnterExitState> transition;
+    method public default androidx.compose.ui.Modifier animateEnterExit(androidx.compose.ui.Modifier, optional androidx.compose.animation.EnterTransition enter, optional androidx.compose.animation.ExitTransition exit, optional String label);
+    method public androidx.compose.animation.core.Transition<androidx.compose.animation.EnterExitState> getTransition();
+    property public abstract androidx.compose.animation.core.Transition<androidx.compose.animation.EnterExitState> transition;
   }
 
   public final class AnimationModifierKt {
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimationDemos.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimationDemos.kt
index 40b35d5..6885430 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimationDemos.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimationDemos.kt
@@ -64,6 +64,7 @@
 import androidx.compose.animation.demos.suspendfun.InfiniteAnimationDemo
 import androidx.compose.animation.demos.suspendfun.OffsetKeyframeSplinePlaygroundDemo
 import androidx.compose.animation.demos.suspendfun.OffsetKeyframeWithSplineDemo
+import androidx.compose.animation.demos.suspendfun.PeriodicMonoSplineDemo
 import androidx.compose.animation.demos.suspendfun.SuspendAnimationDemo
 import androidx.compose.animation.demos.suspendfun.SuspendDoubleTapToLikeDemo
 import androidx.compose.animation.demos.vectorgraphics.AnimatedVectorGraphicsDemo
@@ -168,6 +169,7 @@
                     OffsetKeyframeSplinePlaygroundDemo()
                 },
                 ComposableDemo("Arc Offset Demo") { ArcOffsetDemo() },
+                ComposableDemo("Periodic Spline Demo") { PeriodicMonoSplineDemo() },
             )
         ),
         DemoCategory(
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/AnimateBoundsModifier.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/AnimateBoundsModifier.kt
index 62f03d5..ef1708d 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/AnimateBoundsModifier.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/AnimateBoundsModifier.kt
@@ -81,18 +81,18 @@
             }
         }
         .approachLayout(
-            isMeasurementApproachComplete = {
+            isMeasurementApproachInProgress = {
                 outerSizeAnimation.updateTarget(it, coroutineScope, sizeAnimationSpec)
-                outerSizeAnimation.isIdle
+                !outerSizeAnimation.isIdle
             },
-            isPlacementApproachComplete = {
+            isPlacementApproachInProgress = {
                 val target = lookaheadScopeCoordinates.localLookaheadPositionOf(it)
                 outerOffsetAnimation.updateTarget(
                     target.round(),
                     coroutineScope,
                     positionAnimationSpec
                 )
-                outerOffsetAnimation.isIdle
+                !outerOffsetAnimation.isIdle
             }
         ) { measurable, constraints ->
             val (w, h) = outerSizeAnimation.updateTarget(
@@ -126,18 +126,18 @@
             }
         }
         .approachLayout(
-            isMeasurementApproachComplete = {
+            isMeasurementApproachInProgress = {
                 sizeAnimation.updateTarget(it, coroutineScope, sizeAnimationSpec)
-                sizeAnimation.isIdle
+                !sizeAnimation.isIdle
             },
-            isPlacementApproachComplete = {
+            isPlacementApproachInProgress = {
                 val target = lookaheadScopeCoordinates.localLookaheadPositionOf(it)
                 offsetAnimation.updateTarget(
                     target.round(),
                     coroutineScope,
                     positionAnimationSpec
                 )
-                offsetAnimation.isIdle
+                !offsetAnimation.isIdle
             }
         ) { measurable, _ ->
             // When layout changes, the lookahead pass will calculate a new final size for the
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/CraneDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/CraneDemo.kt
index 4f80c38..ea680e2 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/CraneDemo.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/CraneDemo.kt
@@ -217,7 +217,7 @@
             } ?: IntOffset(0, 0)
         }
     }
-    this.approachLayout({ provider.progress == 1f }) { measurable, _ ->
+    this.approachLayout({ provider.progress != 1f }) { measurable, _ ->
         val (width, height) = calculateSize(lookaheadSize)
         val animatedConstraints = Constraints.fixed(width, height)
         val placeable = measurable.measure(animatedConstraints)
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/LookaheadWithDisappearingMoveableContentDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/LookaheadWithDisappearingMoveableContentDemo.kt
index 56fed32..db9f9b9 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/LookaheadWithDisappearingMoveableContentDemo.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/LookaheadWithDisappearingMoveableContentDemo.kt
@@ -157,8 +157,8 @@
         DeferredTargetAnimation(IntOffset.VectorConverter)
     }
     val coroutineScope = rememberCoroutineScope()
-    this.approachLayout(isMeasurementApproachComplete = { true },
-        isPlacementApproachComplete = {
+    this.approachLayout(isMeasurementApproachInProgress = { false },
+        isPlacementApproachInProgress = {
             offsetAnimation.updateTarget(
                 lookaheadScopeCoordinates.localLookaheadPositionOf(
                     it
@@ -166,7 +166,7 @@
                 coroutineScope,
                 spring(stiffness = Spring.StiffnessMediumLow)
             )
-            offsetAnimation.isIdle
+            !offsetAnimation.isIdle
         }
     ) { measurable, constraints ->
         measurable.measure(constraints).run {
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/LookaheadWithMovableContentDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/LookaheadWithMovableContentDemo.kt
index d4e84bc..3a06425 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/LookaheadWithMovableContentDemo.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/LookaheadWithMovableContentDemo.kt
@@ -163,14 +163,14 @@
     val offsetAnim = remember { DeferredTargetAnimation(IntOffset.VectorConverter) }
     val scope = rememberCoroutineScope()
     this.approachLayout(
-        isMeasurementApproachComplete = {
+        isMeasurementApproachInProgress = {
             sizeAnim.updateTarget(it, scope)
-            sizeAnim.isIdle
+            !sizeAnim.isIdle
         },
-        isPlacementApproachComplete = {
+        isPlacementApproachInProgress = {
             val target = lookaheadScopeCoordinates.localLookaheadPositionOf(it)
             offsetAnim.updateTarget(target.round(), scope, spring())
-            offsetAnim.isIdle
+            !offsetAnim.isIdle
         }
     ) { measurable, _ ->
         val (animWidth, animHeight) = sizeAnim.updateTarget(
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/SceneHostExperiment.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/SceneHostExperiment.kt
index eeef14b..4ba36700 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/SceneHostExperiment.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/SceneHostExperiment.kt
@@ -86,14 +86,14 @@
                 }
             }
             .approachLayout(
-                isMeasurementApproachComplete = {
+                isMeasurementApproachInProgress = {
                     sizeAnimation.updateTarget(it, coroutineScope)
-                    sizeAnimation.isIdle
+                    !sizeAnimation.isIdle
                 },
-                isPlacementApproachComplete = {
+                isPlacementApproachInProgress = {
                     val target = lookaheadScopeCoordinates.localLookaheadPositionOf(it)
                     offsetAnimation.updateTarget(target.round(), coroutineScope, spring())
-                    offsetAnimation.isIdle
+                    !offsetAnimation.isIdle
                 }
             ) { measurable, _ ->
                 with(coroutineScope) {
@@ -139,9 +139,9 @@
             }
         }
         .approachLayout(
-            isMeasurementApproachComplete = {
+            isMeasurementApproachInProgress = {
                 sizeAnimation.updateTarget(it, scope)
-                sizeAnimation.isIdle
+                !sizeAnimation.isIdle
             }
         ) { measurable, constraints ->
             targetSize = lookaheadSize
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/suspendfun/OffsetKeyframeSplinePlaygroundDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/suspendfun/OffsetKeyframeSplinePlaygroundDemo.kt
index 4ec936a..6356b68 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/suspendfun/OffsetKeyframeSplinePlaygroundDemo.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/suspendfun/OffsetKeyframeSplinePlaygroundDemo.kt
@@ -18,7 +18,10 @@
 
 import android.util.Log
 import androidx.compose.animation.core.Animatable
+import androidx.compose.animation.core.AnimationVector2D
 import androidx.compose.animation.core.ExperimentalAnimationSpecApi
+import androidx.compose.animation.core.InfiniteRepeatableSpec
+import androidx.compose.animation.core.RepeatMode
 import androidx.compose.animation.core.VectorConverter
 import androidx.compose.animation.core.keyframesWithSpline
 import androidx.compose.foundation.gestures.detectDragGestures
@@ -35,15 +38,18 @@
 import androidx.compose.material.Slider
 import androidx.compose.material.Text
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.MutableState
 import androidx.compose.runtime.derivedStateOf
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableFloatStateOf
 import androidx.compose.runtime.mutableIntStateOf
+import androidx.compose.runtime.mutableLongStateOf
 import androidx.compose.runtime.mutableStateListOf
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.runtime.setValue
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.draw.drawBehind
@@ -52,6 +58,7 @@
 import androidx.compose.ui.graphics.Path
 import androidx.compose.ui.graphics.PathEffect
 import androidx.compose.ui.graphics.PointMode
+import androidx.compose.ui.graphics.StrokeCap
 import androidx.compose.ui.graphics.drawscope.Fill
 import androidx.compose.ui.graphics.drawscope.translate
 import androidx.compose.ui.graphics.graphicsLayer
@@ -77,6 +84,7 @@
 import kotlin.math.roundToLong
 import kotlin.math.sin
 import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.isActive
 import kotlinx.coroutines.launch
 
 @Preview
@@ -148,6 +156,11 @@
 private class SplineKeyframesPlaygroundModel(
     private val scope: CoroutineScope
 ) {
+    private val zero2DVector = AnimationVector2D(0f, 0f)
+
+    // TODO: This is extremely hacky, find a way to improve
+    private var modificationIndicator by mutableLongStateOf(0L)
+
     private val pointCount = 6
     private val animatedOffset = Animatable(Offset.Zero, Offset.VectorConverter)
     private val anchors = mutableStateListOf<Offset>()
@@ -158,6 +171,8 @@
     private val durationPerAnchor = mutableFloatStateOf(600f)
 
     private val pathPoints = mutableStateListOf<Offset>()
+    private val samplePoints = mutableListOf<Offset>()
+    private val sampleCount = 100
 
     val totalDuration by derivedStateOf { anchors.size * durationPerAnchor.floatValue }
 
@@ -171,13 +186,14 @@
         }
     }
 
+    private val diamondPath = Path()
     private val diamondColor = Color(0xFFFF9800)
     private val diamondSize = 5.dp
     private val textOffset = 6.dp
     private val pathColor = diamondColor.copy(alpha = 0.7f)
     private val pathWidth = 2.dp
-    private val pathOn = 6.dp
-    private val pathOff = 4.dp
+    private val pathOn = 3.dp
+    private val pathOff = 6.dp
 
     @Composable
     fun DrawContent(modifier: Modifier = Modifier) {
@@ -186,6 +202,18 @@
         val fontFamilyResolver = LocalFontFamilyResolver.current
         val textMeasurer = remember { TextMeasurer(fontFamilyResolver, density, layoutDirection) }
         val textColor = MaterialTheme.colors.onSurface
+
+        remember(density.density) {
+            val diamondSizePx = with(density) { diamondSize.toPx() }
+            diamondPath.reset()
+            diamondPath.moveTo(0f, -diamondSizePx)
+            diamondPath.lineTo(diamondSizePx, 0f)
+            diamondPath.lineTo(0f, diamondSizePx)
+            diamondPath.lineTo(-diamondSizePx, 0f)
+            diamondPath.close()
+            false
+        }
+
         init(density)
 
         Box(
@@ -201,8 +229,9 @@
                     translate(center.x, center.y) {
                         drawPoints(
                             points = pathPoints,
-                            pointMode = PointMode.Lines,
+                            pointMode = PointMode.Polygon,
                             color = pathColor,
+                            cap = StrokeCap.Round,
                             strokeWidth = pathWidthPx,
                             pathEffect = pathEffect
                         )
@@ -212,24 +241,16 @@
                     if (anchors.isEmpty()) {
                         return@drawBehind
                     }
-                    val diamondSizePx = with(this) { diamondSize.toPx() }
                     val textOffsetPx = with(this) {
                         Offset(textOffset.toPx(), textOffset.toPx())
                     }
 
                     // Draw anchors
-                    val path = Path()
                     translate(center.x, center.y) {
                         anchors.forEachIndexed { index, anchorPosition ->
                             translate(anchorPosition.x, anchorPosition.y) {
-                                path.reset()
-                                path.moveTo(0f, -diamondSizePx)
-                                path.lineTo(diamondSizePx, 0f)
-                                path.lineTo(0f, diamondSizePx)
-                                path.lineTo(-diamondSizePx, 0f)
-                                path.close()
                                 drawPath(
-                                    path = path,
+                                    path = diamondPath,
                                     color = diamondColor,
                                     style = Fill
                                 )
@@ -269,6 +290,37 @@
                     .graphicsLayer { rotationZ = angle.floatValue - 90f }
             )
         }
+
+        // TODO: This is extremely hacky, find a way to improve
+        LaunchedEffect(modificationIndicator) {
+            samplePoints.clear()
+            var i = 0
+            val vectorized = keyframesWithSpline(0.5f) {
+                durationMillis = totalDuration.roundToInt()
+
+                anchors.forEachIndexed { index, offset ->
+                    val fraction = (index + 1f) / (anchorCount + 1)
+                    offset atFraction fraction
+                }
+            }.vectorize(Offset.VectorConverter)
+
+            var timeMillis = 0f
+            val step = vectorized.durationMillis.toFloat() / sampleCount
+            while (isActive && i < sampleCount) {
+                val vectorValue = vectorized.getValueFromNanos(
+                    playTimeNanos = timeMillis.roundToLong() * 1_000_000,
+                    initialValue = zero2DVector,
+                    targetValue = zero2DVector,
+                    initialVelocity = zero2DVector
+                )
+                samplePoints.add(Offset(vectorValue.v1, vectorValue.v2))
+                timeMillis += step
+                i++
+            }
+            samplePoints.add(Offset.Zero)
+            pathPoints.clear()
+            pathPoints.addAll(samplePoints)
+        }
     }
 
     fun onNewDuration(newTotalDuration: Float) {
@@ -277,21 +329,22 @@
 
     fun addAnchor(density: Density) {
         scope.launch { animatedOffset.snapTo(Offset.Zero) }
-        pathPoints.clear()
         anchors.add(getNextPosition(density))
+        modificationIndicator++
     }
 
     fun removeAnchor() {
         if (anchors.size > 1) {
             scope.launch { animatedOffset.snapTo(Offset.Zero) }
-            pathPoints.clear()
             anchors.removeLast()
+            modificationIndicator++
         }
     }
 
     private val minDuration = 600f
     private val baseMaxDuration = 10000f
     private val durationIncrement = minDuration
+
     val range: ClosedFloatingPointRange<Float>
         get() =
             if (totalDuration < baseMaxDuration) {
@@ -307,21 +360,22 @@
     private val angle = mutableFloatStateOf(0f)
 
     fun onRun() {
-        pathPoints.clear()
         scope.launch {
             animatedOffset.snapTo(Offset.Zero)
             animatedOffset.animateTo(
                 targetValue = Offset.Zero,
-                animationSpec = keyframesWithSpline {
-                    durationMillis = totalDuration.roundToInt()
+                animationSpec = InfiniteRepeatableSpec(
+                    keyframesWithSpline(0.5f) {
+                        durationMillis = totalDuration.roundToInt()
 
-                    anchors.forEachIndexed { index, offset ->
-                        val fraction = (index + 1f) / (anchorCount + 2)
-                        offset atFraction fraction
-                    }
-                }
+                        anchors.forEachIndexed { index, offset ->
+                            val fraction = (index + 1f) / (anchorCount + 1)
+                            offset atFraction fraction
+                        }
+                    },
+                    RepeatMode.Restart
+                )
             ) {
-                pathPoints.add(this.value)
                 angle.floatValue =
                     Math.toDegrees(atan2(y = velocity.y, x = velocity.x).toDouble()).toFloat() + 90f
             }
@@ -383,7 +437,6 @@
     // TODO: Consider using a threshold like this to find the anchor quicker
     //   private val diffThreshold = 10 * 10 * 2
     private fun onDragStart(position: Offset, size: IntSize) {
-        pathPoints.clear()
         scope.launch { animatedOffset.snapTo(Offset.Zero) }
         val relPosition = Offset(
             position.x - (size.width * 0.5f),
@@ -413,6 +466,7 @@
         val index = draggingIndex.intValue
         if (index >= 0) {
             anchors[index] = anchors[index] + dragAmount
+            modificationIndicator++
         }
     }
 
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/suspendfun/PeriodicMonoSplineDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/suspendfun/PeriodicMonoSplineDemo.kt
new file mode 100644
index 0000000..e7f44d3
--- /dev/null
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/suspendfun/PeriodicMonoSplineDemo.kt
@@ -0,0 +1,244 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:OptIn(ExperimentalAnimationSpecApi::class)
+@file:Suppress("InfiniteTransitionLabel", "InfinitePropertiesLabel")
+
+package androidx.compose.animation.demos.suspendfun
+
+import androidx.compose.animation.core.AnimationVector2D
+import androidx.compose.animation.core.ExperimentalAnimationSpecApi
+import androidx.compose.animation.core.InfiniteRepeatableSpec
+import androidx.compose.animation.core.KeyframesWithSplineSpec
+import androidx.compose.animation.core.RepeatMode
+import androidx.compose.animation.core.VectorConverter
+import androidx.compose.animation.core.animateValue
+import androidx.compose.animation.core.keyframesWithSpline
+import androidx.compose.animation.core.rememberInfiniteTransition
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.verticalScroll
+import androidx.compose.material.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.drawBehind
+import androidx.compose.ui.draw.drawWithCache
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.Path
+import androidx.compose.ui.graphics.drawscope.Fill
+import androidx.compose.ui.graphics.drawscope.Stroke
+import androidx.compose.ui.graphics.drawscope.scale
+import androidx.compose.ui.graphics.drawscope.translate
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import kotlin.math.roundToLong
+
+@Preview
+@Composable
+fun PeriodicMonoSplineDemo() {
+    Column(
+        verticalArrangement = Arrangement.spacedBy(8.dp),
+        modifier = Modifier
+            .fillMaxWidth()
+            .verticalScroll(rememberScrollState())
+    ) {
+        MonoSplineCurve(
+            periodicBias = Float.NaN,
+            modifier = Modifier
+                .height(300.dp)
+                .background(Color.LightGray)
+        )
+        MonoSplineCurve(
+            periodicBias = 0f,
+            modifier = Modifier
+                .height(300.dp)
+                .background(Color.LightGray)
+        )
+        MonoSplineCurve(
+            periodicBias = 0.5f,
+            modifier = Modifier
+                .height(300.dp)
+                .background(Color.LightGray)
+        )
+        MonoSplineCurve(
+            periodicBias = 1f,
+            modifier = Modifier
+                .height(300.dp)
+                .background(Color.LightGray)
+        )
+    }
+}
+
+private fun periodicKeyframes(periodicBias: Float): KeyframesWithSplineSpec<Offset> =
+    keyframesWithSpline(periodicBias) {
+        durationMillis = 2000
+
+        Offset(0.5f, 1f) atFraction 0.5f
+    }
+
+private val pathWidth = 2.dp
+private val pathColor = Color(0xFFFFC107)
+private val padding = 40.dp
+private val indicatorSize = 4.dp
+
+@Composable
+private fun MonoSplineCurve(
+    periodicBias: Float,
+    modifier: Modifier = Modifier
+) {
+    val sampleSize = 1_000
+    val density = LocalDensity.current
+    val keyframesSpec = remember(periodicBias) { periodicKeyframes(periodicBias) }
+    val points = remember { FloatArray(sampleSize) }
+    val pointsPath = remember { Path() }
+    var isDraw by remember { mutableStateOf(false) }
+
+    val infiniteAnimation = rememberInfiniteTransition()
+    val animatedValue = infiniteAnimation.animateValue(
+        initialValue = Offset.Zero,
+        targetValue = Offset(1f, 0f),
+        typeConverter = Offset.VectorConverter,
+        animationSpec = InfiniteRepeatableSpec(
+            animation = keyframesSpec,
+            repeatMode = RepeatMode.Restart
+        )
+    )
+
+    val text = remember(periodicBias) {
+        if (periodicBias.isNaN()) {
+            "Normal Monotonic Spline"
+        } else {
+            "Periodic with bias: $periodicBias"
+        }
+    }
+
+    val indicatorSizePx = with(density) { indicatorSize.toPx() }
+    val indicatorPath = remember(indicatorSizePx) {
+        Path().apply {
+            moveTo(0f, -indicatorSizePx)
+            lineTo(indicatorSizePx, 0f)
+            lineTo(0f, indicatorSizePx)
+            lineTo(-indicatorSizePx, 0f)
+            close()
+        }
+    }
+
+    Row(modifier) {
+        Box(
+            Modifier
+                .fillMaxHeight()
+                .weight(1f, true)
+        ) {
+            Text(text = text)
+            Box(
+                Modifier
+                    .fillMaxSize()
+                    .padding(padding)
+                    .drawWithCache {
+                        if (isDraw) {
+                            val pathWidthPx = pathWidth.toPx()
+                            pointsPath.reset()
+                            val arraySize = points.size
+                            val width = size.width
+                            val height = size.height
+                            points.forEachIndexed { index, yFactor ->
+                                val xi = (index.toFloat() / arraySize) * width
+                                pointsPath.lineTo(xi, yFactor * height)
+                            }
+                            onDrawBehind {
+                                scale(1f, -1f) {
+                                    drawPath(
+                                        path = pointsPath,
+                                        color = pathColor,
+                                        style = Stroke(width = pathWidthPx)
+                                    )
+                                }
+                            }
+                        } else {
+                            onDrawBehind {}
+                        }
+                    }
+                    .drawBehind {
+                        scale(1f, -1f) {
+                            val currValue = animatedValue.value
+                            translate(size.width * currValue.x, size.height * currValue.y) {
+                                drawPath(
+                                    path = indicatorPath,
+                                    color = Color.Red,
+                                    style = Fill
+                                )
+                            }
+                        }
+                    }
+            )
+        }
+        Box(
+            Modifier
+                .fillMaxHeight()
+                .width(40.dp)
+                .padding(vertical = padding)
+                .drawBehind {
+                    scale(1f, -1f) {
+                        drawCircle(
+                            color = Color.Red,
+                            radius = size.width * 0.5f,
+                            center = Offset(
+                                x = size.width * 0.5f,
+                                y = size.height * animatedValue.value.y
+                            )
+                        )
+                    }
+                }
+        )
+    }
+
+    LaunchedEffect(Unit) {
+        val zeroVector = AnimationVector2D(0f, 0f)
+        val vectorized = keyframesSpec.vectorize(Offset.VectorConverter)
+        var timeMillis = 0f
+        val step = vectorized.durationMillis.toFloat() / sampleSize
+        var count = 0
+        while (count < sampleSize) {
+            val vectorValue = vectorized.getValueFromNanos(
+                playTimeNanos = timeMillis.roundToLong() * 1_000_000,
+                initialValue = zeroVector,
+                targetValue = zeroVector,
+                initialVelocity = zeroVector
+            )
+            points[count] = vectorValue.v2
+            timeMillis += step
+            count++
+        }
+        isDraw = true
+    }
+}
diff --git a/compose/animation/animation/src/androidInstrumentedTest/kotlin/androidx/compose/animation/AnimatedContentTest.kt b/compose/animation/animation/src/androidInstrumentedTest/kotlin/androidx/compose/animation/AnimatedContentTest.kt
index 10ce8e0..4cae1c4 100644
--- a/compose/animation/animation/src/androidInstrumentedTest/kotlin/androidx/compose/animation/AnimatedContentTest.kt
+++ b/compose/animation/animation/src/androidInstrumentedTest/kotlin/androidx/compose/animation/AnimatedContentTest.kt
@@ -50,12 +50,14 @@
 import androidx.compose.runtime.setValue
 import androidx.compose.runtime.withFrameMillis
 import androidx.compose.ui.Alignment
+import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.layout.LayoutCoordinates
 import androidx.compose.ui.layout.LookaheadScope
 import androidx.compose.ui.layout.SubcomposeLayout
+import androidx.compose.ui.layout.layout
 import androidx.compose.ui.layout.onGloballyPositioned
 import androidx.compose.ui.layout.positionInRoot
 import androidx.compose.ui.platform.LocalDensity
@@ -74,6 +76,7 @@
 import kotlinx.coroutines.delay
 import org.junit.Assert.assertEquals
 import org.junit.Assert.assertFalse
+import org.junit.Assert.assertNotEquals
 import org.junit.Assert.assertNotNull
 import org.junit.Assert.assertNull
 import org.junit.Assert.assertTrue
@@ -927,6 +930,198 @@
         assertTrue(box2EnterFinished)
     }
 
+    @OptIn(ExperimentalComposeUiApi::class)
+    @Test
+    fun AnimatedContentLookaheadTest() {
+        // Test that AnimatedContent's lookahead size is its target content's lookahead size.
+        // Also test that the lookahead placement for content is correct.
+        val size1 = 400
+        val size2 = 20
+        val transitionState = MutableTransitionState(true)
+        var playTimeMillis by mutableStateOf(0)
+        val testModifier = TestModifier()
+        var lookaheadPosition: Offset? = null
+        var approachPosition: Offset? = null
+        rule.mainClock.autoAdvance = false
+        rule.setContent {
+            CompositionLocalProvider(LocalDensity provides Density(1f)) {
+                LookaheadScope {
+                    Box(testModifier) {
+                        val transition = rememberTransition(transitionState)
+                        playTimeMillis = (transition.playTimeNanos / 1_000_000L).toInt()
+                        transition.AnimatedContent(
+                            transitionSpec = {
+                                if (true isTransitioningTo false) {
+                                    fadeIn() togetherWith fadeOut() using SizeTransform { _, _ ->
+                                        tween(durationMillis = 80, easing = LinearEasing)
+                                    }
+                                } else {
+                                    fadeIn() togetherWith fadeOut() using SizeTransform { _, _ ->
+                                        tween(durationMillis = 80, easing = LinearEasing)
+                                    }
+                                }
+                            },
+                            contentAlignment = Alignment.Center
+                        ) {
+                            if (it) {
+                                Box(modifier = Modifier.size(size = size1.dp))
+                            } else {
+                                Box(modifier = Modifier
+                                    .layout { m, c ->
+                                        m
+                                            .measure(c)
+                                            .run {
+                                                layout(width, height) {
+                                                    if (isLookingAhead) {
+                                                        with(this@LookaheadScope) {
+                                                            lookaheadPosition =
+                                                                lookaheadScopeCoordinates
+                                                                    .localLookaheadPositionOf(
+                                                                        coordinates!!
+                                                                    )
+                                                        }
+                                                    } else {
+                                                        approachPosition = lookaheadScopeCoordinates
+                                                            .localPositionOf(
+                                                                coordinates!!,
+                                                                Offset.Zero
+                                                            )
+                                                    }
+                                                    place(0, 0)
+                                                }
+                                            }
+                                    }
+                                    .size(size = size2.dp))
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        rule.runOnIdle {
+            assertTrue(transitionState.targetState)
+            assertEquals(IntSize(size1, size1), testModifier.lookaheadSize)
+            transitionState.targetState = false
+        }
+        rule.waitForIdle()
+        rule.mainClock.advanceTimeByFrame()
+
+        // Transition from item1 to item2 in 320ms, animating to full width in the first 160ms
+        // then full height in the next 160ms
+        while (transitionState.currentState != transitionState.targetState) {
+            rule.runOnIdle {
+                assertEquals(IntSize(size2, size2), testModifier.lookaheadSize)
+                assertNotNull(approachPosition)
+                assertNotNull(lookaheadPosition)
+                assertOffsetEquals(Offset(0f, 0f), lookaheadPosition!!)
+            }
+            rule.mainClock.advanceTimeByFrame()
+        }
+        rule.waitForIdle()
+    }
+
+    @OptIn(ExperimentalComposeUiApi::class)
+    @Test
+    fun testTargetChangeLookaheadPlacement() {
+        var lookaheadPosition1: Offset? = null
+        var lookaheadPosition2: Offset? = null
+        val transitionState = MutableTransitionState(true)
+        var playTimeMillis by mutableStateOf(0)
+        rule.setContent {
+            LookaheadScope {
+                val transition = rememberTransition(transitionState)
+                playTimeMillis = (transition.playTimeNanos / 1_000_000L).toInt()
+                transition.AnimatedContent(
+                    contentAlignment = Alignment.Center,
+                    transitionSpec = { fadeIn() togetherWith fadeOut() using null }
+                ) {
+                    if (it) {
+                        Box(
+                            Modifier
+                                .layout { measurable, constraints ->
+                                    measurable
+                                        .measure(constraints)
+                                        .run {
+                                            layout(width, height) {
+                                                if (isLookingAhead) {
+                                                    lookaheadPosition1 = lookaheadScopeCoordinates
+                                                        .localLookaheadPositionOf(coordinates!!)
+                                                }
+                                            }
+                                        }
+                                }
+                                .fillMaxSize()
+                                .background(Color.Blue)
+                        )
+                    } else {
+                        Box(
+                            Modifier
+                                .layout { measurable, constraints ->
+                                    measurable
+                                        .measure(constraints)
+                                        .run {
+                                            layout(width, height) {
+                                                if (isLookingAhead) {
+                                                    lookaheadPosition2 = lookaheadScopeCoordinates
+                                                        .localLookaheadPositionOf(coordinates!!)
+                                                }
+                                            }
+                                        }
+                                }
+                                .size(100.dp)
+                                .background(Color.Red)
+                        )
+                    }
+                }
+            }
+        }
+        rule.runOnIdle {
+            assertTrue(transitionState.targetState)
+            assertTrue(transitionState.currentState)
+            transitionState.targetState = false
+        }
+        rule.mainClock.autoAdvance = false
+        rule.runOnIdle {
+            assertNotNull(lookaheadPosition1)
+            assertOffsetEquals(Offset(0f, 0f), lookaheadPosition1!!)
+            transitionState.targetState = false
+        }
+        rule.waitForIdle()
+        rule.mainClock.advanceTimeByFrame()
+
+        // Transition from item1 to item2 in 320ms, animating to full width in the first 160ms
+        // then full height in the next 160ms
+        repeat(3) {
+            assertNotEquals(transitionState.currentState, transitionState.targetState)
+            rule.runOnIdle {
+                assertNotNull(lookaheadPosition2)
+                assertOffsetEquals(Offset(0f, 0f), lookaheadPosition2!!)
+            }
+            rule.mainClock.advanceTimeByFrame()
+            rule.waitForIdle()
+        }
+
+        // Check that the lookahead position for the outgoing content changed
+        assertNotEquals(0f, lookaheadPosition1!!.x)
+        assertNotEquals(0f, lookaheadPosition1!!.y)
+        // Interruption during animation
+        transitionState.targetState = true
+        rule.mainClock.advanceTimeByFrame()
+        rule.waitForIdle()
+
+        rule.runOnIdle {
+            assertNotNull(lookaheadPosition1)
+            // Check that after the target state change, the new incoming content has
+            // a 0, 0 lookahead offset.
+            assertOffsetEquals(Offset(0f, 0f), lookaheadPosition1!!)
+        }
+    }
+
+    private fun assertOffsetEquals(expected: Offset, actual: Offset) {
+        assertEquals(expected.x, actual.x, 0.00001f)
+        assertEquals(expected.y, actual.y, 0.00001f)
+    }
+
     @OptIn(InternalAnimationApi::class)
     private val Transition<*>.playTimeMillis get() = (playTimeNanos / 1_000_000L).toInt()
 }
diff --git a/compose/animation/animation/src/androidInstrumentedTest/kotlin/androidx/compose/animation/AnimationModifierTest.kt b/compose/animation/animation/src/androidInstrumentedTest/kotlin/androidx/compose/animation/AnimationModifierTest.kt
index 52034ab..32c7532 100644
--- a/compose/animation/animation/src/androidInstrumentedTest/kotlin/androidx/compose/animation/AnimationModifierTest.kt
+++ b/compose/animation/animation/src/androidInstrumentedTest/kotlin/androidx/compose/animation/AnimationModifierTest.kt
@@ -384,11 +384,14 @@
 internal class TestModifier : LayoutModifier {
     var width: Int = 0
     var height: Int = 0
+    var lookaheadSize: IntSize? = null
+        private set
     override fun MeasureScope.measure(
         measurable: Measurable,
         constraints: Constraints
     ): MeasureResult {
         val placeable = measurable.measure(constraints)
+        if (isLookingAhead) lookaheadSize = IntSize(placeable.width, placeable.height)
         width = placeable.width
         height = placeable.height
         return layout(width, height) {
diff --git a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedContent.kt b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedContent.kt
index 644b02d..e4cfdf2 100644
--- a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedContent.kt
+++ b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedContent.kt
@@ -1,4 +1,3 @@
-
 /*
  * Copyright 2021 The Android Open Source Project
  *
@@ -15,7 +14,9 @@
  * limitations under the License.
  */
 @file:OptIn(InternalAnimationApi::class)
+
 package androidx.compose.animation
+
 import androidx.collection.mutableScatterMapOf
 import androidx.compose.animation.AnimatedContentTransitionScope.SlideDirection.Companion.Down
 import androidx.compose.animation.AnimatedContentTransitionScope.SlideDirection.Companion.End
@@ -68,6 +69,7 @@
 import androidx.compose.ui.util.fastForEach
 import androidx.compose.ui.util.fastForEachIndexed
 import androidx.compose.ui.util.fastMaxOfOrNull
+
 /**
  * [AnimatedContent] is a container that automatically animates its content when [targetState]
  * changes. Its [content] for different target states is defined in a mapping between a target
@@ -146,6 +148,7 @@
         content = content
     )
 }
+
 /**
  * [ContentTransform] defines how the target content (i.e. content associated with target state)
  * enters [AnimatedContent] and how the initial content disappears.
@@ -196,6 +199,7 @@
      * content with the same index, the target content will be placed on top.
      */
     var targetContentZIndex by mutableFloatStateOf(targetContentZIndex)
+
     /**
      * [sizeTransform] manages the expanding and shrinking of the container if there is any size
      * change as new content enters the [AnimatedContent] and old content leaves.
@@ -206,6 +210,7 @@
     var sizeTransform: SizeTransform? = sizeTransform
         internal set
 }
+
 /**
  * This creates a [SizeTransform] with the provided [clip] and [sizeAnimationSpec]. By default,
  * [clip] will be true. This means during the size animation, the content will be clipped to the
@@ -223,6 +228,7 @@
             )
         }
 ): SizeTransform = SizeTransformImpl(clip, sizeAnimationSpec)
+
 /**
  * [SizeTransform] defines how to transform from one size to another when the size of the content
  * changes. When [clip] is true, the content will be clipped to the animation size.
@@ -236,12 +242,14 @@
      * Whether the content should be clipped using the animated size.
      */
     val clip: Boolean
+
     /**
      * This allows [FiniteAnimationSpec] to be defined based on the [initialSize] before the size
      * animation and the [targetSize] of the animation.
      */
     fun createAnimationSpec(initialSize: IntSize, targetSize: IntSize): FiniteAnimationSpec<IntSize>
 }
+
 /**
  * Private implementation of SizeTransform interface.
  */
@@ -255,6 +263,7 @@
         targetSize: IntSize
     ): FiniteAnimationSpec<IntSize> = sizeAnimationSpec(initialSize, targetSize)
 }
+
 /**
  * This creates a [ContentTransform] using the provided [EnterTransition] and [exit], where the
  * enter and exit transition will be running simultaneously.
@@ -263,12 +272,14 @@
  * @sample androidx.compose.animation.samples.AnimatedContentTransitionSpecSample
  */
 infix fun EnterTransition.togetherWith(exit: ExitTransition) = ContentTransform(this, exit)
+
 @ExperimentalAnimationApi
 @Deprecated(
     "Infix fun EnterTransition.with(ExitTransition) has been renamed to" +
         " togetherWith", ReplaceWith("togetherWith(exit)")
 )
 infix fun EnterTransition.with(exit: ExitTransition) = ContentTransform(this, exit)
+
 /**
  * [AnimatedContentTransitionScope] provides functions that are convenient and only applicable in the
  * context of [AnimatedContent], such as [slideIntoContainer] and [slideOutOfContainer].
@@ -280,6 +291,7 @@
      * @sample androidx.compose.animation.samples.AnimatedContentTransitionSpecSample
      */
     infix fun ContentTransform.using(sizeTransform: SizeTransform?): ContentTransform
+
     /**
      * [SlideDirection] defines the direction of the slide in/out for [slideIntoContainer] and
      * [slideOutOfContainer]. The supported directions are: [Left], [Right], [Up] and [Down].
@@ -295,6 +307,7 @@
             val Start = SlideDirection(4)
             val End = SlideDirection(5)
         }
+
         override fun toString(): String {
             return when (this) {
                 Left -> "Left"
@@ -307,6 +320,7 @@
             }
         }
     }
+
     /**
      * This defines a horizontal/vertical slide-in that is specific to [AnimatedContent] from the
      * edge of the container. The offset amount is dynamically calculated based on the current
@@ -336,6 +350,7 @@
         ),
         initialOffset: (offsetForFullSlide: Int) -> Int = { it }
     ): EnterTransition
+
     /**
      * This defines a horizontal/vertical exit transition to completely slide out of the
      * [AnimatedContent] container. The offset amount is dynamically calculated based on the current
@@ -364,6 +379,7 @@
         ),
         targetOffset: (offsetForFullSlide: Int) -> Int = { it }
     ): ExitTransition
+
     /**
      * [KeepUntilTransitionsFinished] defers the disposal of the exiting content till both enter and
      * exit transitions have finished. It can be combined with other [ExitTransition]s using
@@ -379,11 +395,13 @@
      */
     val ExitTransition.Companion.KeepUntilTransitionsFinished: ExitTransition
         get() = KeepUntilTransitionsFinished
+
     /**
      * This returns the [Alignment] specified on [AnimatedContent].
      */
     val contentAlignment: Alignment
 }
+
 internal class AnimatedContentTransitionScopeImpl<S> internal constructor(
     internal val transition: Transition<S>,
     override var contentAlignment: Alignment,
@@ -395,12 +413,14 @@
     override val initialState: S
         @Suppress("UnknownNullness")
         get() = transition.segment.initialState
+
     /**
      * Target state of a Transition Segment. This is the state that transition will end on.
      */
     override val targetState: S
         @Suppress("UnknownNullness")
         get() = transition.segment.targetState
+
     /**
      * Customizes the [SizeTransform] of a given [ContentTransform]. For example:
      *
@@ -409,6 +429,7 @@
     override infix fun ContentTransform.using(sizeTransform: SizeTransform?) = this.apply {
         this.sizeTransform = sizeTransform
     }
+
     /**
      * This defines a horizontal/vertical slide-in that is specific to [AnimatedContent] from the
      * edge of the container. The offset amount is dynamically calculated based on the current
@@ -445,19 +466,24 @@
                     currentSize.width - calculateOffset(IntSize(it, it), currentSize).x
                 )
             }
+
             towards.isRight -> slideInHorizontally(animationSpec) {
                 initialOffset.invoke(-calculateOffset(IntSize(it, it), currentSize).x - it)
             }
+
             towards == Up -> slideInVertically(animationSpec) {
                 initialOffset.invoke(
                     currentSize.height - calculateOffset(IntSize(it, it), currentSize).y
                 )
             }
+
             towards == Down -> slideInVertically(animationSpec) {
                 initialOffset.invoke(-calculateOffset(IntSize(it, it), currentSize).y - it)
             }
+
             else -> EnterTransition.None
         }
+
     private val AnimatedContentTransitionScope.SlideDirection.isLeft: Boolean
         get() {
             return this == Left || this == Start && layoutDirection == LayoutDirection.Ltr ||
@@ -468,9 +494,11 @@
             return this == Right || this == Start && layoutDirection == LayoutDirection.Rtl ||
                 this == End && layoutDirection == LayoutDirection.Ltr
         }
+
     private fun calculateOffset(fullSize: IntSize, currentSize: IntSize): IntOffset {
         return contentAlignment.align(fullSize, currentSize, LayoutDirection.Ltr)
     }
+
     /**
      * This defines a horizontal/vertical exit transition to completely slide out of the
      * [AnimatedContent] container. The offset amount is dynamically calculated based on the current
@@ -506,32 +534,39 @@
                 val targetSize = targetSizeMap[transition.targetState]?.value ?: IntSize.Zero
                 targetOffset.invoke(-calculateOffset(IntSize(it, it), targetSize).x - it)
             }
+
             towards.isRight -> slideOutHorizontally(animationSpec) {
                 val targetSize = targetSizeMap[transition.targetState]?.value ?: IntSize.Zero
                 targetOffset.invoke(
                     -calculateOffset(IntSize(it, it), targetSize).x + targetSize.width
                 )
             }
+
             towards == Up -> slideOutVertically(animationSpec) {
                 val targetSize = targetSizeMap[transition.targetState]?.value ?: IntSize.Zero
                 targetOffset.invoke(-calculateOffset(IntSize(it, it), targetSize).y - it)
             }
+
             towards == Down -> slideOutVertically(animationSpec) {
                 val targetSize = targetSizeMap[transition.targetState]?.value ?: IntSize.Zero
                 targetOffset.invoke(
                     -calculateOffset(IntSize(it, it), targetSize).y + targetSize.height
                 )
             }
+
             else -> ExitTransition.None
         }
     }
+
     internal var measuredSize: IntSize by mutableStateOf(IntSize.Zero)
     internal val targetSizeMap = mutableScatterMapOf<S, State<IntSize>>()
     internal var animatedSize: State<IntSize>? = null
+
     // Current size of the container. If there's any size animation, the current size will be
     // read from the animation value, otherwise we'll use the current
     private val currentSize: IntSize
         get() = animatedSize?.value ?: measuredSize
+
     @Suppress("ComposableModifierFactory", "ModifierFactoryExtensionFunction")
     @Composable
     internal fun createSizeAnimationModifier(
@@ -558,13 +593,18 @@
             Modifier
         }
     }
+
     // This helps track the target measurable without affecting the placement order. Target
     // measurable needs to be measured first but placed last.
-    internal data class ChildData(var isTarget: Boolean) : ParentDataModifier {
+    internal class ChildData(isTarget: Boolean) : ParentDataModifier {
+        // isTarget is read during measure. It is necessary to make this a MutableState
+        // such that when the target changes, measure is triggered
+        var isTarget by mutableStateOf(isTarget)
         override fun Density.modifyParentData(parentData: Any?): Any {
             return this@ChildData
         }
     }
+
     private inner class SizeModifier(
         val sizeAnimation: Transition<S>.DeferredAnimation<IntSize, AnimationVector2D>,
         val sizeTransform: State<SizeTransform?>,
@@ -584,15 +624,22 @@
                 targetSizeMap[it]?.value ?: IntSize.Zero
             }
             animatedSize = size
-            val offset = contentAlignment.align(
-                IntSize(placeable.width, placeable.height), size.value, LayoutDirection.Ltr
-            )
-            return layout(size.value.width, size.value.height) {
+            val measuredSize: IntSize
+            if (isLookingAhead) {
+                measuredSize = IntSize(placeable.width, placeable.height)
+            } else {
+                measuredSize = size.value
+            }
+            return layout(measuredSize.width, measuredSize.height) {
+                val offset = contentAlignment.align(
+                    IntSize(placeable.width, placeable.height), measuredSize, LayoutDirection.Ltr
+                )
                 placeable.place(offset)
             }
         }
     }
 }
+
 /**
  * Receiver scope for content lambda for AnimatedContent. In this scope,
  * [transition][AnimatedVisibilityScope.transition] can be used to observe the state of the
@@ -602,6 +649,7 @@
 private class AnimatedContentScopeImpl internal constructor(
     animatedVisibilityScope: AnimatedVisibilityScope
 ) : AnimatedContentScope, AnimatedVisibilityScope by animatedVisibilityScope
+
 /**
  * [AnimatedContent] is a container that automatically animates its content when
  * [Transition.targetState] changes. Its [content] for different target states is defined in a
@@ -772,6 +820,7 @@
         measurePolicy = remember { AnimatedContentMeasurePolicy(rootScope) }
     )
 }
+
 private class AnimatedContentMeasurePolicy(val rootScope: AnimatedContentTransitionScopeImpl<*>) :
     MeasurePolicy {
     override fun MeasureScope.measure(
@@ -779,12 +828,15 @@
         constraints: Constraints
     ): MeasureResult {
         val placeables = arrayOfNulls<Placeable>(measurables.size)
+        var targetSize = IntSize.Zero
         // Measure the target composable first (but place it on top unless zIndex is specified)
         measurables.fastForEachIndexed { index, measurable ->
             if ((measurable.parentData as? AnimatedContentTransitionScopeImpl.ChildData)
                     ?.isTarget == true
             ) {
-                placeables[index] = measurable.measure(constraints)
+                placeables[index] = measurable.measure(constraints).also {
+                    targetSize = IntSize(it.width, it.height)
+                }
             }
         }
         // Measure the non-target composables after target, since these have no impact on
@@ -794,9 +846,21 @@
                 placeables[index] = measurable.measure(constraints)
             }
         }
-        val maxWidth: Int = placeables.maxByOrNull { it?.width ?: 0 }?.width ?: 0
-        val maxHeight = placeables.maxByOrNull { it?.height ?: 0 }?.height ?: 0
-        rootScope.measuredSize = IntSize(maxWidth, maxHeight)
+        val maxWidth: Int = if (isLookingAhead) {
+            targetSize.width
+        } else {
+            placeables.maxByOrNull { it?.width ?: 0 }?.width ?: 0
+        }
+        val maxHeight = if (isLookingAhead) {
+            targetSize.height
+        } else {
+            placeables.maxByOrNull { it?.height ?: 0 }?.height ?: 0
+        }
+        if (!isLookingAhead) {
+            // update currently measured size only during approach
+            rootScope.measuredSize = IntSize(maxWidth, maxHeight)
+        }
+
         // Position the children.
         return layout(maxWidth, maxHeight) {
             placeables.forEach { placeable ->
@@ -811,18 +875,22 @@
             }
         }
     }
+
     override fun IntrinsicMeasureScope.minIntrinsicWidth(
         measurables: List<IntrinsicMeasurable>,
         height: Int
     ) = measurables.fastMaxOfOrNull { it.minIntrinsicWidth(height) } ?: 0
+
     override fun IntrinsicMeasureScope.minIntrinsicHeight(
         measurables: List<IntrinsicMeasurable>,
         width: Int
     ) = measurables.fastMaxOfOrNull { it.minIntrinsicHeight(width) } ?: 0
+
     override fun IntrinsicMeasureScope.maxIntrinsicWidth(
         measurables: List<IntrinsicMeasurable>,
         height: Int
     ) = measurables.fastMaxOfOrNull { it.maxIntrinsicWidth(height) } ?: 0
+
     override fun IntrinsicMeasureScope.maxIntrinsicHeight(
         measurables: List<IntrinsicMeasurable>,
         width: Int
diff --git a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedVisibility.kt b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedVisibility.kt
index 7c9e02f..970d9ca 100644
--- a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedVisibility.kt
+++ b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedVisibility.kt
@@ -633,9 +633,6 @@
      * [transition] allows custom enter/exit animations to be specified. It will run simultaneously
      * with the built-in enter/exit transitions specified in [AnimatedVisibility].
      */
-    @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
-    @get:ExperimentalAnimationApi
-    @ExperimentalAnimationApi
     val transition: Transition<EnterExitState>
 
     /**
@@ -651,11 +648,8 @@
      * does not matter, as the transition animations will start simultaneously. See [EnterTransition]
      * and [ExitTransition] for details on the three types of transition.
      *
-     * By default, the enter transition will be a combination of [fadeIn] and [expandIn] of the
-     * content from the bottom end. And the exit transition will be shrinking the content towards
-     * the bottom end while fading out (i.e. [fadeOut] + [shrinkOut]). The expanding and shrinking
-     * will likely also animate the parent and siblings if they rely on the size of
-     * appearing/disappearing content.
+     * By default, the enter transition will be a [fadeIn] of the content. And the exit transition
+     * will be fading out the content using [fadeOut].
      *
      * In some cases it may be desirable to have [AnimatedVisibility] apply no animation at all for
      * enter and/or exit, such that children of [AnimatedVisibility] can each have their distinct
@@ -664,10 +658,9 @@
      *
      * @sample androidx.compose.animation.samples.AnimateEnterExitPartialContent
      */
-    @ExperimentalAnimationApi
     fun Modifier.animateEnterExit(
-        enter: EnterTransition = fadeIn() + expandIn(),
-        exit: ExitTransition = fadeOut() + shrinkOut(),
+        enter: EnterTransition = fadeIn(),
+        exit: ExitTransition = fadeOut(),
         label: String = "animateEnterExit"
     ): Modifier = composed(
         inspectorInfo = debugInspectorInfo {
@@ -818,17 +811,25 @@
             Layout(
                 content = { scope.content() },
                 modifier = modifier
-                    .then(childTransition.createModifier(enter, exit, "Built-in")
+                    .then(childTransition
+                        .createModifier(enter, exit, "Built-in")
                         .then(if (onLookaheadMeasured != null) {
                             Modifier.layout { measurable, constraints ->
-                                measurable.measure(constraints).run {
-                                    if (isLookingAhead) {
-                                        onLookaheadMeasured.invoke(IntSize(width, height))
+                                measurable
+                                    .measure(constraints)
+                                    .run {
+                                        if (isLookingAhead) {
+                                            onLookaheadMeasured.invoke(
+                                                IntSize(
+                                                    width,
+                                                    height
+                                                )
+                                            )
+                                        }
+                                        layout(width, height) {
+                                            place(0, 0)
+                                        }
                                     }
-                                    layout(width, height) {
-                                        place(0, 0)
-                                    }
-                                }
                             }
                         } else Modifier)
                     ),
@@ -845,6 +846,7 @@
 private class AnimatedEnterExitMeasurePolicy(
     val scope: AnimatedVisibilityScopeImpl
 ) : MeasurePolicy {
+    var hasLookaheadOccurred = false
     override fun MeasureScope.measure(
         measurables: List<Measurable>,
         constraints: Constraints
@@ -853,7 +855,13 @@
         val maxWidth: Int = placeables.fastMaxBy { it.width }?.width ?: 0
         val maxHeight = placeables.fastMaxBy { it.height }?.height ?: 0
         // Position the children.
-        scope.targetSize.value = IntSize(maxWidth, maxHeight)
+        if (isLookingAhead) {
+            hasLookaheadOccurred = true
+            scope.targetSize.value = IntSize(maxWidth, maxHeight)
+        } else if (!hasLookaheadOccurred) {
+            // Not in lookahead scope.
+            scope.targetSize.value = IntSize(maxWidth, maxHeight)
+        }
         return layout(maxWidth, maxHeight) {
             placeables.fastForEach {
                 it.place(0, 0)
diff --git a/compose/foundation/foundation-layout/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/layout/WindowInsetsDeviceTest.kt b/compose/foundation/foundation-layout/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/layout/WindowInsetsDeviceTest.kt
index e99233e..6800c39 100644
--- a/compose/foundation/foundation-layout/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/layout/WindowInsetsDeviceTest.kt
+++ b/compose/foundation/foundation-layout/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/layout/WindowInsetsDeviceTest.kt
@@ -46,6 +46,8 @@
 import androidx.core.view.WindowInsetsCompat
 import androidx.core.view.WindowInsetsControllerCompat
 import androidx.core.view.children
+import androidx.lifecycle.DefaultLifecycleObserver
+import androidx.lifecycle.LifecycleOwner
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
 import androidx.test.filters.SdkSuppress
@@ -64,10 +66,22 @@
 class WindowInsetsDeviceTest {
     @get:Rule
     val rule = createAndroidComposeRule<WindowInsetsActivity>()
+    private lateinit var finishLatch: CountDownLatch
+    private val finishLatchGetter
+        get() = finishLatch
+    private val observer = object : DefaultLifecycleObserver {
+        override fun onDestroy(owner: LifecycleOwner) {
+            finishLatchGetter.countDown()
+        }
+    }
 
     @Before
     fun setup() {
         rule.activity.createdLatch.await(1, TimeUnit.SECONDS)
+        finishLatch = CountDownLatch(1)
+        rule.runOnUiThread {
+            rule.activity.lifecycle.addObserver(observer)
+        }
     }
 
     @After
@@ -75,6 +89,7 @@
         rule.runOnUiThread {
             rule.activity.finish()
         }
+        assertThat(finishLatch.await(1, TimeUnit.SECONDS)).isTrue()
     }
 
     @OptIn(ExperimentalLayoutApi::class)
@@ -91,8 +106,12 @@
         val innerComposable: @Composable () -> Unit = {
             imeInset2 = WindowInsets.ime.getBottom(LocalDensity.current)
             Box(
-                Modifier.fillMaxSize().imePadding().imeNestedScroll()
-                    .nestedScroll(connection, dispatcher).background(
+                Modifier
+                    .fillMaxSize()
+                    .imePadding()
+                    .imeNestedScroll()
+                    .nestedScroll(connection, dispatcher)
+                    .background(
                         Color.Cyan
                     )
             )
diff --git a/compose/foundation/foundation-layout/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/layout/WindowInsetsPaddingTest.kt b/compose/foundation/foundation-layout/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/layout/WindowInsetsPaddingTest.kt
index 7e408e5..c72c7d7 100644
--- a/compose/foundation/foundation-layout/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/layout/WindowInsetsPaddingTest.kt
+++ b/compose/foundation/foundation-layout/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/layout/WindowInsetsPaddingTest.kt
@@ -53,11 +53,15 @@
 import androidx.core.view.DisplayCutoutCompat
 import androidx.core.view.WindowInsetsCompat
 import androidx.core.view.forEach
+import androidx.lifecycle.DefaultLifecycleObserver
+import androidx.lifecycle.LifecycleOwner
 import androidx.test.ext.junit.rules.ActivityScenarioRule
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
 import androidx.test.filters.SdkSuppress
 import com.google.common.truth.Truth.assertThat
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.TimeUnit
 import kotlin.math.roundToInt
 import org.junit.After
 import org.junit.Before
@@ -73,9 +77,22 @@
 
     private lateinit var insetsView: InsetsView
 
+    private lateinit var finishLatch: CountDownLatch
+    private val finishLatchGetter
+        get() = finishLatch
+    private val observer = object : DefaultLifecycleObserver {
+        override fun onDestroy(owner: LifecycleOwner) {
+            finishLatchGetter.countDown()
+        }
+    }
+
     @Before
     fun setup() {
         WindowInsetsHolder.setUseTestInsets(true)
+        finishLatch = CountDownLatch(1)
+        rule.runOnUiThread {
+            rule.activity.lifecycle.addObserver(observer)
+        }
     }
 
     @After
@@ -84,6 +101,7 @@
         rule.runOnUiThread {
             rule.activity.finish()
         }
+        assertThat(finishLatch.await(1, TimeUnit.SECONDS)).isTrue()
     }
 
     @Test
diff --git a/compose/foundation/foundation-layout/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/layout/WindowInsetsSizeTest.kt b/compose/foundation/foundation-layout/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/layout/WindowInsetsSizeTest.kt
index 7c113ab..7fdd264 100644
--- a/compose/foundation/foundation-layout/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/layout/WindowInsetsSizeTest.kt
+++ b/compose/foundation/foundation-layout/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/layout/WindowInsetsSizeTest.kt
@@ -36,10 +36,14 @@
 import androidx.core.graphics.Insets as AndroidXInsets
 import androidx.core.view.DisplayCutoutCompat
 import androidx.core.view.WindowInsetsCompat
+import androidx.lifecycle.DefaultLifecycleObserver
+import androidx.lifecycle.LifecycleOwner
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
 import androidx.test.filters.SdkSuppress
 import com.google.common.truth.Truth.assertThat
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.TimeUnit
 import org.junit.After
 import org.junit.Before
 import org.junit.Rule
@@ -54,9 +58,22 @@
 
     private lateinit var insetsView: InsetsView
 
+    private lateinit var finishLatch: CountDownLatch
+    private val finishLatchGetter
+        get() = finishLatch
+    private val observer = object : DefaultLifecycleObserver {
+        override fun onDestroy(owner: LifecycleOwner) {
+            finishLatchGetter.countDown()
+        }
+    }
+
     @Before
     fun setup() {
         WindowInsetsHolder.setUseTestInsets(true)
+        finishLatch = CountDownLatch(1)
+        rule.runOnUiThread {
+            rule.activity.lifecycle.addObserver(observer)
+        }
     }
 
     @After
@@ -65,6 +82,7 @@
         rule.runOnUiThread {
             rule.activity.finish()
         }
+        assertThat(finishLatch.await(1, TimeUnit.SECONDS)).isTrue()
     }
 
     @OptIn(ExperimentalLayoutApi::class)
diff --git a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/RowColumnMeasurePolicy.kt b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/RowColumnMeasurePolicy.kt
index 2e3bcb8..af3d877 100644
--- a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/RowColumnMeasurePolicy.kt
+++ b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/RowColumnMeasurePolicy.kt
@@ -168,8 +168,11 @@
                 remainder -= weightedSize.fastRoundToInt()
             } catch (e: IllegalArgumentException) {
                 throw IllegalArgumentException(
-                    e.message + " Tracked at " +
-                        "https://issuetracker.google.com/issues/297974033" +
+                    "This log indicates a hard-to-reproduce Compose issue, " +
+                        "modified with additional debugging details. " +
+                        "Please help us by adding your experiences to the bug link provided. " +
+                        "Thank you for helping us improve Compose. " +
+                        "https://issuetracker.google.com/issues/297974033 " +
                         "mainAxisMax " + mainAxisMax +
                         "mainAxisMin " + mainAxisMin +
                         "targetSpace " + targetSpace +
@@ -224,8 +227,11 @@
                     )
                 } catch (e: IllegalArgumentException) {
                     throw IllegalArgumentException(
-                        e.message + " Tracked at " +
-                            "https://issuetracker.google.com/issues/300280216" +
+                        "This log indicates a hard-to-reproduce Compose issue, " +
+                            "modified with additional debugging details. " +
+                            "Please help us by adding your experiences to the bug link provided. " +
+                            "Thank you for helping us improve Compose. " +
+                            "https://issuetracker.google.com/issues/300280216 " +
                             "mainAxisMax " + mainAxisMax +
                             "mainAxisMin " + mainAxisMin +
                             "targetSpace " + targetSpace +
diff --git a/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/ClickableTest.kt b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/ClickableTest.kt
index 4ed0d6d..90f9d1e 100644
--- a/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/ClickableTest.kt
+++ b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/ClickableTest.kt
@@ -52,6 +52,7 @@
 import androidx.compose.ui.focus.focusRequester
 import androidx.compose.ui.focus.onFocusEvent
 import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.drawscope.ContentDrawScope
 import androidx.compose.ui.input.InputMode
 import androidx.compose.ui.input.InputMode.Companion.Keyboard
@@ -143,7 +144,9 @@
             Box {
                 BasicText(
                     "ClickableText",
-                    modifier = Modifier.testTag("myClickable").clickable {}
+                    modifier = Modifier
+                        .testTag("myClickable")
+                        .clickable {}
                 )
             }
         }
@@ -160,7 +163,9 @@
             Box {
                 BasicText(
                     "ClickableText",
-                    modifier = Modifier.testTag("myClickable").clickable(enabled = false) {}
+                    modifier = Modifier
+                        .testTag("myClickable")
+                        .clickable(enabled = false) {}
                 )
             }
         }
@@ -179,7 +184,8 @@
             Box {
                 BasicText(
                     "ClickableText",
-                    modifier = Modifier.testTag("myClickable")
+                    modifier = Modifier
+                        .testTag("myClickable")
                         .clickable(enabled = enabled, role = role) {}
                 )
             }
@@ -1324,7 +1330,9 @@
     private fun Modifier.dynamicPointerInputModifier(
         enabled: Boolean,
         key: Any? = Unit,
-        onPress: () -> Unit
+        onPress: () -> Unit = { },
+        onMove: () -> Unit = { },
+        onRelease: () -> Unit = { },
     ) = if (enabled) {
         pointerInput(key) {
             awaitPointerEventScope {
@@ -1332,6 +1340,10 @@
                     val event = awaitPointerEvent()
                     if (event.type == PointerEventType.Press) {
                         onPress()
+                    } else if (event.type == PointerEventType.Move) {
+                        onMove()
+                    } else if (event.type == PointerEventType.Release) {
+                        onRelease()
                     }
                 }
             }
@@ -1557,9 +1569,13 @@
             Box(Modifier
                 .size(200.dp)
                 .testTag("myClickable")
-                .dynamicPointerInputModifier(activateDynamicPointerInput, "unique_key_123") {
-                    dynamicPressCounter++
-                }
+                .dynamicPointerInputModifier(
+                    enabled = activateDynamicPointerInput,
+                    key = "unique_key_123",
+                    onPress = {
+                        dynamicPressCounter++
+                    }
+                )
                 .clickable {
                     clickableClickCounter++
                     activateDynamicPointerInput = true
@@ -1593,7 +1609,12 @@
             Box(Modifier
                 .size(200.dp)
                 .testTag("myClickable")
-                .dynamicPointerInputModifier(activateDynamicPointerInput) { dynamicPressCounter++ }
+                .dynamicPointerInputModifier(
+                    enabled = activateDynamicPointerInput,
+                    onPress = {
+                        dynamicPressCounter++
+                    }
+                )
                 .clickable {
                     clickableClickCounter++
                     activateDynamicPointerInput = true
@@ -1616,6 +1637,132 @@
         }
     }
 
+    // Tests a dynamic pointer input AND a dynamic clickable{} above an existing pointer input.
+    @Test
+    fun dynamicInputModifiersInTouchStream_addsAboveClickableWithUnitKey_triggersAllModifiers() {
+        var activeDynamicClickable by mutableStateOf(false)
+        var dynamicClickableCounter by mutableStateOf(0)
+
+        var activeDynamicPointerInput by mutableStateOf(false)
+        var dynamicPointerInputPressCounter by mutableStateOf(0)
+        var dynamicPointerInputMoveCounter by mutableStateOf(0)
+        var dynamicPointerInputReleaseCounter by mutableStateOf(0)
+
+        var originalPointerInputLambdaExecutionCount by mutableStateOf(0)
+        var originalPointerInputEventCounter by mutableStateOf(0)
+
+        rule.setContent {
+            Box(Modifier
+                .size(200.dp)
+                .testTag("myClickable")
+                .dynamicPointerInputModifier(
+                    enabled = activeDynamicPointerInput,
+                    onPress = {
+                        dynamicPointerInputPressCounter++
+                    },
+                    onMove = {
+                        dynamicPointerInputMoveCounter++
+                    },
+                    onRelease = {
+                        dynamicPointerInputReleaseCounter++
+                        activeDynamicClickable = true
+                    }
+                )
+                .dynamicClickableModifier(activeDynamicClickable) {
+                    dynamicClickableCounter++
+                }
+                .background(Color.Green)
+                .pointerInput(Unit) {
+                    originalPointerInputLambdaExecutionCount++
+                    awaitPointerEventScope {
+                        while (true) {
+                            awaitPointerEvent()
+                            originalPointerInputEventCounter++
+                            activeDynamicPointerInput = true
+                        }
+                    }
+                }
+            )
+        }
+
+        // Even though we are enabling the dynamic pointer input, it will NOT receive events until
+        // the next event stream (after the click is over) which is why you see zeros below.
+        // Only two events are triggered for click (down/up)
+        rule.onNodeWithTag("myClickable").performClick()
+
+        rule.runOnIdle {
+            assertEquals(1, originalPointerInputLambdaExecutionCount)
+            // With these events, we enable the dynamic pointer input
+            assertEquals(2, originalPointerInputEventCounter)
+
+            assertEquals(0, dynamicPointerInputPressCounter)
+            assertEquals(0, dynamicPointerInputMoveCounter)
+            assertEquals(0, dynamicPointerInputReleaseCounter)
+
+            assertEquals(0, dynamicClickableCounter)
+        }
+
+        rule.onNodeWithTag("myClickable").performTouchInput {
+            down(Offset(0f, 0f))
+        }
+
+        rule.runOnIdle {
+            assertEquals(1, originalPointerInputLambdaExecutionCount)
+            assertEquals(3, originalPointerInputEventCounter)
+
+            assertEquals(1, dynamicPointerInputPressCounter)
+            assertEquals(0, dynamicPointerInputMoveCounter)
+            assertEquals(0, dynamicPointerInputReleaseCounter)
+
+            assertEquals(0, dynamicClickableCounter)
+        }
+
+        rule.onNodeWithTag("myClickable").performTouchInput {
+            moveTo(Offset(1f, 1f))
+        }
+
+        rule.runOnIdle {
+            assertEquals(1, originalPointerInputLambdaExecutionCount)
+            assertEquals(4, originalPointerInputEventCounter)
+
+            assertEquals(1, dynamicPointerInputPressCounter)
+            assertEquals(1, dynamicPointerInputMoveCounter)
+            assertEquals(0, dynamicPointerInputReleaseCounter)
+
+            assertEquals(0, dynamicClickableCounter)
+        }
+
+        rule.onNodeWithTag("myClickable").performTouchInput {
+            up()
+        }
+
+        rule.runOnIdle {
+            assertEquals(1, originalPointerInputLambdaExecutionCount)
+            assertEquals(5, originalPointerInputEventCounter)
+
+            assertEquals(1, dynamicPointerInputPressCounter)
+            assertEquals(1, dynamicPointerInputMoveCounter)
+            // With this release counter, we enable the dynamic clickable{}
+            assertEquals(1, dynamicPointerInputReleaseCounter)
+
+            assertEquals(0, dynamicClickableCounter)
+        }
+
+        // Only two events are triggered for click (down/up)
+        rule.onNodeWithTag("myClickable").performClick()
+
+        rule.runOnIdle {
+            assertEquals(1, originalPointerInputLambdaExecutionCount)
+            assertEquals(7, originalPointerInputEventCounter)
+
+            assertEquals(2, dynamicPointerInputPressCounter)
+            assertEquals(1, dynamicPointerInputMoveCounter)
+            assertEquals(2, dynamicPointerInputReleaseCounter)
+
+            assertEquals(1, dynamicClickableCounter)
+        }
+    }
+
     /*
      * Tests adding dynamic modifier with COMPLETE mouse events, that is, the expected events from
      * using a hardware device with an Android device.
@@ -1632,9 +1779,13 @@
             Box(Modifier
                 .size(200.dp)
                 .testTag("myClickable")
-                .dynamicPointerInputModifier(activateDynamicPointerInput, "unique_key_123") {
-                    dynamicPressCounter++
-                }
+                .dynamicPointerInputModifier(
+                    enabled = activateDynamicPointerInput,
+                    key = "unique_key_123",
+                    onPress = {
+                        dynamicPressCounter++
+                    }
+                )
                 .clickable {
                     clickableClickCounter++
                     activateDynamicPointerInput = true
@@ -1680,7 +1831,12 @@
             Box(Modifier
                 .size(200.dp)
                 .testTag("myClickable")
-                .dynamicPointerInputModifier(activateDynamicPointerInput) { dynamicPressCounter++ }
+                .dynamicPointerInputModifier(
+                    enabled = activateDynamicPointerInput,
+                    onPress = {
+                        dynamicPressCounter++
+                    }
+                )
                 .clickable {
                     clickableClickCounter++
                     activateDynamicPointerInput = true
@@ -1710,6 +1866,153 @@
         }
     }
 
+    /* Tests dynamically adding a pointer input DURING an event stream (specifically, Hover).
+     * Hover is the only scenario where you can add a new pointer input modifier during the event
+     * stream AND receive events in the same active stream from that new pointer input modifier.
+     * It isn't possible in the down/up scenario because you add the new modifier during the down
+     * but you don't get another down until the next event stream.
+     */
+    @OptIn(ExperimentalTestApi::class)
+    @Test
+    fun dynamicInputModifierHoverMouse_addsAbovePointerInputWithUnitKey_triggersBothModifiers() {
+        var originalPointerInputLambdaExecutionCount by mutableStateOf(0)
+        var originalPointerInputEventCounter by mutableStateOf(0)
+
+        var dynamicPressCounter by mutableStateOf(0)
+        var dynamicReleaseCounter by mutableStateOf(0)
+        var activateDynamicPointerInput by mutableStateOf(false)
+
+        rule.setContent {
+            Box(Modifier
+                .size(200.dp)
+                .testTag("myClickable")
+                .dynamicPointerInputModifier(
+                    enabled = activateDynamicPointerInput,
+                    onPress = {
+                        dynamicPressCounter++
+                    },
+                    onRelease = {
+                        dynamicReleaseCounter++
+                    }
+                )
+                .background(Color.Green)
+                .pointerInput(Unit) {
+                    originalPointerInputLambdaExecutionCount++
+                    awaitPointerEventScope {
+                        while (true) {
+                            awaitPointerEvent()
+                            originalPointerInputEventCounter++
+                            activateDynamicPointerInput = true
+                        }
+                    }
+                }
+            )
+        }
+
+        rule.onNodeWithTag("myClickable").performMouseInput {
+            enter()
+        }
+
+        rule.runOnIdle {
+            assertEquals(1, originalPointerInputLambdaExecutionCount)
+            assertEquals(1, originalPointerInputEventCounter)
+            assertEquals(0, dynamicPressCounter)
+            assertEquals(0, dynamicReleaseCounter)
+        }
+
+        rule.onNodeWithTag("myClickable").performMouseInput {
+            press()
+        }
+
+        rule.runOnIdle {
+            assertEquals(1, originalPointerInputLambdaExecutionCount)
+            assertEquals(2, originalPointerInputEventCounter)
+            assertEquals(1, dynamicPressCounter)
+            assertEquals(0, dynamicReleaseCounter)
+        }
+
+        rule.onNodeWithTag("myClickable").performMouseInput {
+            release()
+        }
+
+        rule.runOnIdle {
+            assertEquals(1, originalPointerInputLambdaExecutionCount)
+            assertEquals(3, originalPointerInputEventCounter)
+            assertEquals(1, dynamicPressCounter)
+            assertEquals(1, dynamicReleaseCounter)
+        }
+
+        rule.onNodeWithTag("myClickable").performMouseInput {
+            exit()
+        }
+
+        rule.runOnIdle {
+            assertEquals(1, originalPointerInputLambdaExecutionCount)
+            assertEquals(4, originalPointerInputEventCounter)
+            assertEquals(1, dynamicPressCounter)
+            assertEquals(1, dynamicReleaseCounter)
+        }
+    }
+
+    /* This is the same as the test above, but
+     *   1. Using clickable{}
+     *   2. It enables the dynamic pointer input and starts the hover event stream in a more
+     * hacky way (using mouse click without hover which triggers hover enter on release).
+     */
+    @OptIn(ExperimentalTestApi::class)
+    @Test
+    fun dynamicInputModifierIncompleteMouse_addsAboveClickableHackyEvents_triggersBothModifiers() {
+        var clickableClickCounter by mutableStateOf(0)
+        // Note: I'm tracking press instead of release because clickable{} consumes release
+        var dynamicPressCounter by mutableStateOf(0)
+        var activateDynamicPointerInput by mutableStateOf(false)
+
+        rule.setContent {
+            Box(Modifier
+                .size(200.dp)
+                .testTag("myClickable")
+                .dynamicPointerInputModifier(
+                    enabled = activateDynamicPointerInput,
+                    onPress = {
+                        dynamicPressCounter++
+                    }
+                )
+                .clickable {
+                    clickableClickCounter++
+                    activateDynamicPointerInput = true
+                }
+            )
+        }
+
+        // Usually, a proper event stream from hardware for mouse input would be:
+        // - enter() (hover enter)
+        // - click()
+        // - exit()
+        // However, in this case, I'm just calling click() which triggers actions:
+        // - press
+        // - release
+        // - hover enter
+        // This starts a hover event stream (in a more hacky way) and also enables the dynamic
+        // pointer input to start recording events.
+        rule.onNodeWithTag("myClickable").performMouseInput {
+            click()
+        }
+
+        rule.runOnIdle {
+            assertEquals(1, clickableClickCounter)
+            assertEquals(0, dynamicPressCounter)
+        }
+
+        rule.onNodeWithTag("myClickable").performMouseInput {
+            click()
+        }
+
+        rule.runOnIdle {
+            assertEquals(2, clickableClickCounter)
+            assertEquals(1, dynamicPressCounter)
+        }
+    }
+
     @OptIn(ExperimentalTestApi::class)
     @Test
     @LargeTest
@@ -2614,7 +2917,10 @@
             inputModeManager = LocalInputModeManager.current
             // Add focusable to the top so that when initial focus is dispatched, the clickable
             // doesn't become focused
-            Box(Modifier.padding(10.dp).focusable()) {
+            Box(
+                Modifier
+                    .padding(10.dp)
+                    .focusable()) {
                 Box(
                     modifier = Modifier
                         .testTag("clickable")
@@ -2623,7 +2929,10 @@
                             indication = indication
                         ) {}
                 ) {
-                    Box(Modifier.focusRequester(focusRequester).focusable())
+                    Box(
+                        Modifier
+                            .focusRequester(focusRequester)
+                            .focusable())
                 }
             }
         }
diff --git a/compose/foundation/foundation/src/androidUnitTest/kotlin/androidx/compose/foundation/text/input/InputTransformationTest.kt b/compose/foundation/foundation/src/androidUnitTest/kotlin/androidx/compose/foundation/text/input/InputTransformationTest.kt
index 551712a..d517272 100644
--- a/compose/foundation/foundation/src/androidUnitTest/kotlin/androidx/compose/foundation/text/input/InputTransformationTest.kt
+++ b/compose/foundation/foundation/src/androidUnitTest/kotlin/androidx/compose/foundation/text/input/InputTransformationTest.kt
@@ -22,6 +22,9 @@
 import androidx.compose.ui.semantics.SemanticsProperties
 import androidx.compose.ui.semantics.SemanticsPropertyReceiver
 import androidx.compose.ui.semantics.maxTextLength
+import androidx.compose.ui.text.input.ImeAction
+import androidx.compose.ui.text.input.KeyboardCapitalization
+import androidx.compose.ui.text.input.KeyboardType
 import com.google.common.truth.Truth.assertThat
 import org.junit.Test
 
@@ -146,6 +149,40 @@
     }
 
     @Test
+    fun chainedFilters_mergeKeyboardOptions_withPrecedenceToNext() {
+        val options1 = KeyboardOptions(
+            keyboardType = KeyboardType.Password,
+            capitalization = KeyboardCapitalization.Sentences
+        )
+        val options2 = KeyboardOptions(
+            keyboardType = KeyboardType.Email,
+            imeAction = ImeAction.Search
+        )
+        val filter1 = object : InputTransformation {
+            override val keyboardOptions = options1
+
+            override fun TextFieldBuffer.transformInput() {
+            }
+        }
+        val filter2 = object : InputTransformation {
+            override val keyboardOptions = options2
+
+            override fun TextFieldBuffer.transformInput() {
+            }
+        }
+
+        val chain = filter1.then(filter2)
+
+        assertThat(chain.keyboardOptions).isEqualTo(
+            KeyboardOptions(
+                keyboardType = KeyboardType.Email,
+                capitalization = KeyboardCapitalization.Sentences,
+                imeAction = ImeAction.Search
+            )
+        )
+    }
+
+    @Test
     fun chainedFilters_applySecondSemantics_afterFirstSemantics() {
         val filter1 = object : InputTransformation {
             override fun SemanticsPropertyReceiver.applySemantics() {
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/KeyboardOptions.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/KeyboardOptions.kt
index 585821a..69f9b2b 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/KeyboardOptions.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/KeyboardOptions.kt
@@ -404,7 +404,7 @@
      * [other]s null or `Unspecified` properties are replaced with the non-null properties of
      * this object.
      *
-     * If the [other] is null, returns this.
+     * If the either this or [other] is null, returns the non-null one.
      */
     // TODO(b/331222000) Rename to be more clear about precedence.
     fun merge(other: KeyboardOptions?): KeyboardOptions =
@@ -418,7 +418,7 @@
      * [other]. This differs from the behavior of [copy], which always takes the
      * passed value over the current one, even if an unspecified value is passed.
      *
-     * If the [other] is null, returns this.
+     * If the either this or [other] is null, returns the non-null one.
      */
     @Stable
     internal fun fillUnspecifiedValuesWith(other: KeyboardOptions?): KeyboardOptions {
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/input/InputTransformation.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/input/InputTransformation.kt
index 91f0fc8..b6e4c7b 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/input/InputTransformation.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/input/InputTransformation.kt
@@ -109,8 +109,9 @@
  * Creates a filter chain that will run [next] after this. Filters are applied sequentially, so any
  * changes made by this filter will be visible to [next].
  *
- * The returned filter will use the [KeyboardOptions] from [next] if non-null, otherwise it will
- * use the options from this transformation.
+ * The returned filter will [merge][KeyboardOptions.merge] this transformation's [KeyboardOptions]
+ * with those from [next], preferring options from [next] where both transformations specify the
+ * same option.
  *
  * @sample androidx.compose.foundation.samples.BasicTextFieldInputTransformationChainingSample
  *
@@ -173,8 +174,8 @@
 ) : InputTransformation {
 
     override val keyboardOptions: KeyboardOptions?
-        // TODO(b/295951492) Do proper merging.
-        get() = second.keyboardOptions ?: first.keyboardOptions
+        get() = second.keyboardOptions?.fillUnspecifiedValuesWith(first.keyboardOptions)
+            ?: first.keyboardOptions
 
     override fun SemanticsPropertyReceiver.applySemantics() {
         with(first) { applySemantics() }
diff --git a/compose/material3/adaptive/adaptive-layout/src/commonMain/kotlin/androidx/compose/material3/adaptive/layout/AnimateBoundsModifier.kt b/compose/material3/adaptive/adaptive-layout/src/commonMain/kotlin/androidx/compose/material3/adaptive/layout/AnimateBoundsModifier.kt
index 6ce252b..be35102 100644
--- a/compose/material3/adaptive/adaptive-layout/src/commonMain/kotlin/androidx/compose/material3/adaptive/layout/AnimateBoundsModifier.kt
+++ b/compose/material3/adaptive/adaptive-layout/src/commonMain/kotlin/androidx/compose/material3/adaptive/layout/AnimateBoundsModifier.kt
@@ -50,11 +50,11 @@
         return@composed this
     }
     this.approachLayout(
-        isMeasurementApproachComplete = {
-            animateFraction == 1f
+        isMeasurementApproachInProgress = {
+            animateFraction != 1f
         },
-        isPlacementApproachComplete = {
-            animateFraction == 1f
+        isPlacementApproachInProgress = {
+            animateFraction != 1f
         },
     ) { measurable, _ ->
         // When layout changes, the lookahead pass will calculate a new final size for the
diff --git a/compose/material3/material3/api/current.txt b/compose/material3/material3/api/current.txt
index 31efc68..c6e24d83 100644
--- a/compose/material3/material3/api/current.txt
+++ b/compose/material3/material3/api/current.txt
@@ -394,7 +394,7 @@
   }
 
   @androidx.compose.runtime.Immutable public final class ColorScheme {
-    ctor public ColorScheme(long primary, long onPrimary, long primaryContainer, long onPrimaryContainer, long inversePrimary, long secondary, long onSecondary, long secondaryContainer, long onSecondaryContainer, long tertiary, long onTertiary, long tertiaryContainer, long onTertiaryContainer, long background, long onBackground, long surface, long onSurface, long surfaceVariant, long onSurfaceVariant, long surfaceTint, long inverseSurface, long inverseOnSurface, long error, long onError, long errorContainer, long onErrorContainer, long outline, long outlineVariant, long scrim);
+    ctor @Deprecated public ColorScheme(long primary, long onPrimary, long primaryContainer, long onPrimaryContainer, long inversePrimary, long secondary, long onSecondary, long secondaryContainer, long onSecondaryContainer, long tertiary, long onTertiary, long tertiaryContainer, long onTertiaryContainer, long background, long onBackground, long surface, long onSurface, long surfaceVariant, long onSurfaceVariant, long surfaceTint, long inverseSurface, long inverseOnSurface, long error, long onError, long errorContainer, long onErrorContainer, long outline, long outlineVariant, long scrim);
     ctor public ColorScheme(long primary, long onPrimary, long primaryContainer, long onPrimaryContainer, long inversePrimary, long secondary, long onSecondary, long secondaryContainer, long onSecondaryContainer, long tertiary, long onTertiary, long tertiaryContainer, long onTertiaryContainer, long background, long onBackground, long surface, long onSurface, long surfaceVariant, long onSurfaceVariant, long surfaceTint, long inverseSurface, long inverseOnSurface, long error, long onError, long errorContainer, long onErrorContainer, long outline, long outlineVariant, long scrim, long surfaceBright, long surfaceDim, long surfaceContainer, long surfaceContainerHigh, long surfaceContainerHighest, long surfaceContainerLow, long surfaceContainerLowest);
     method @Deprecated public androidx.compose.material3.ColorScheme copy(optional long primary, optional long onPrimary, optional long primaryContainer, optional long onPrimaryContainer, optional long inversePrimary, optional long secondary, optional long onSecondary, optional long secondaryContainer, optional long onSecondaryContainer, optional long tertiary, optional long onTertiary, optional long tertiaryContainer, optional long onTertiaryContainer, optional long background, optional long onBackground, optional long surface, optional long onSurface, optional long surfaceVariant, optional long onSurfaceVariant, optional long surfaceTint, optional long inverseSurface, optional long inverseOnSurface, optional long error, optional long onError, optional long errorContainer, optional long onErrorContainer, optional long outline, optional long outlineVariant, optional long scrim);
     method public androidx.compose.material3.ColorScheme copy(optional long primary, optional long onPrimary, optional long primaryContainer, optional long onPrimaryContainer, optional long inversePrimary, optional long secondary, optional long onSecondary, optional long secondaryContainer, optional long onSecondaryContainer, optional long tertiary, optional long onTertiary, optional long tertiaryContainer, optional long onTertiaryContainer, optional long background, optional long onBackground, optional long surface, optional long onSurface, optional long surfaceVariant, optional long onSurfaceVariant, optional long surfaceTint, optional long inverseSurface, optional long inverseOnSurface, optional long error, optional long onError, optional long errorContainer, optional long onErrorContainer, optional long outline, optional long outlineVariant, optional long scrim, optional long surfaceBright, optional long surfaceDim, optional long surfaceContainer, optional long surfaceContainerHigh, optional long surfaceContainerHighest, optional long surfaceContainerLow, optional long surfaceContainerLowest);
@@ -2138,12 +2138,23 @@
     field public static final androidx.compose.material3.carousel.CarouselDefaults INSTANCE;
   }
 
-  public final class CarouselKt {
-    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void HorizontalMultiBrowseCarousel(androidx.compose.material3.carousel.CarouselState state, float preferredItemWidth, optional androidx.compose.ui.Modifier modifier, optional float itemSpacing, optional androidx.compose.foundation.gestures.TargetedFlingBehavior flingBehavior, optional float minSmallItemWidth, optional float maxSmallItemWidth, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function2<? super androidx.compose.material3.carousel.CarouselScope,? super java.lang.Integer,kotlin.Unit> content);
-    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void HorizontalUncontainedCarousel(androidx.compose.material3.carousel.CarouselState state, float itemWidth, optional androidx.compose.ui.Modifier modifier, optional float itemSpacing, optional androidx.compose.foundation.gestures.TargetedFlingBehavior flingBehavior, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function2<? super androidx.compose.material3.carousel.CarouselScope,? super java.lang.Integer,kotlin.Unit> content);
+  @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public sealed interface CarouselItemInfo {
+    method public float getMaxSize();
+    method public float getMinSize();
+    method public float getSize();
+    property public abstract float maxSize;
+    property public abstract float minSize;
+    property public abstract float size;
   }
 
-  @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public sealed interface CarouselScope {
+  @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public sealed interface CarouselItemScope {
+    method public androidx.compose.material3.carousel.CarouselItemInfo getCarouselItemInfo();
+    property public abstract androidx.compose.material3.carousel.CarouselItemInfo carouselItemInfo;
+  }
+
+  public final class CarouselKt {
+    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void HorizontalMultiBrowseCarousel(androidx.compose.material3.carousel.CarouselState state, float preferredItemWidth, optional androidx.compose.ui.Modifier modifier, optional float itemSpacing, optional androidx.compose.foundation.gestures.TargetedFlingBehavior flingBehavior, optional float minSmallItemWidth, optional float maxSmallItemWidth, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function2<? super androidx.compose.material3.carousel.CarouselItemScope,? super java.lang.Integer,kotlin.Unit> content);
+    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void HorizontalUncontainedCarousel(androidx.compose.material3.carousel.CarouselState state, float itemWidth, optional androidx.compose.ui.Modifier modifier, optional float itemSpacing, optional androidx.compose.foundation.gestures.TargetedFlingBehavior flingBehavior, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function2<? super androidx.compose.material3.carousel.CarouselItemScope,? super java.lang.Integer,kotlin.Unit> content);
   }
 
   @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public final class CarouselState implements androidx.compose.foundation.gestures.ScrollableState {
@@ -2164,7 +2175,9 @@
   }
 
   public final class CarouselStateKt {
+    method public static float endOffset(androidx.compose.material3.carousel.CarouselItemInfo);
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.carousel.CarouselState rememberCarouselState(optional int initialItem, kotlin.jvm.functions.Function0<java.lang.Integer> itemCount);
+    method public static float startOffset(androidx.compose.material3.carousel.CarouselItemInfo);
   }
 
 }
diff --git a/compose/material3/material3/api/restricted_current.txt b/compose/material3/material3/api/restricted_current.txt
index 31efc68..c6e24d83 100644
--- a/compose/material3/material3/api/restricted_current.txt
+++ b/compose/material3/material3/api/restricted_current.txt
@@ -394,7 +394,7 @@
   }
 
   @androidx.compose.runtime.Immutable public final class ColorScheme {
-    ctor public ColorScheme(long primary, long onPrimary, long primaryContainer, long onPrimaryContainer, long inversePrimary, long secondary, long onSecondary, long secondaryContainer, long onSecondaryContainer, long tertiary, long onTertiary, long tertiaryContainer, long onTertiaryContainer, long background, long onBackground, long surface, long onSurface, long surfaceVariant, long onSurfaceVariant, long surfaceTint, long inverseSurface, long inverseOnSurface, long error, long onError, long errorContainer, long onErrorContainer, long outline, long outlineVariant, long scrim);
+    ctor @Deprecated public ColorScheme(long primary, long onPrimary, long primaryContainer, long onPrimaryContainer, long inversePrimary, long secondary, long onSecondary, long secondaryContainer, long onSecondaryContainer, long tertiary, long onTertiary, long tertiaryContainer, long onTertiaryContainer, long background, long onBackground, long surface, long onSurface, long surfaceVariant, long onSurfaceVariant, long surfaceTint, long inverseSurface, long inverseOnSurface, long error, long onError, long errorContainer, long onErrorContainer, long outline, long outlineVariant, long scrim);
     ctor public ColorScheme(long primary, long onPrimary, long primaryContainer, long onPrimaryContainer, long inversePrimary, long secondary, long onSecondary, long secondaryContainer, long onSecondaryContainer, long tertiary, long onTertiary, long tertiaryContainer, long onTertiaryContainer, long background, long onBackground, long surface, long onSurface, long surfaceVariant, long onSurfaceVariant, long surfaceTint, long inverseSurface, long inverseOnSurface, long error, long onError, long errorContainer, long onErrorContainer, long outline, long outlineVariant, long scrim, long surfaceBright, long surfaceDim, long surfaceContainer, long surfaceContainerHigh, long surfaceContainerHighest, long surfaceContainerLow, long surfaceContainerLowest);
     method @Deprecated public androidx.compose.material3.ColorScheme copy(optional long primary, optional long onPrimary, optional long primaryContainer, optional long onPrimaryContainer, optional long inversePrimary, optional long secondary, optional long onSecondary, optional long secondaryContainer, optional long onSecondaryContainer, optional long tertiary, optional long onTertiary, optional long tertiaryContainer, optional long onTertiaryContainer, optional long background, optional long onBackground, optional long surface, optional long onSurface, optional long surfaceVariant, optional long onSurfaceVariant, optional long surfaceTint, optional long inverseSurface, optional long inverseOnSurface, optional long error, optional long onError, optional long errorContainer, optional long onErrorContainer, optional long outline, optional long outlineVariant, optional long scrim);
     method public androidx.compose.material3.ColorScheme copy(optional long primary, optional long onPrimary, optional long primaryContainer, optional long onPrimaryContainer, optional long inversePrimary, optional long secondary, optional long onSecondary, optional long secondaryContainer, optional long onSecondaryContainer, optional long tertiary, optional long onTertiary, optional long tertiaryContainer, optional long onTertiaryContainer, optional long background, optional long onBackground, optional long surface, optional long onSurface, optional long surfaceVariant, optional long onSurfaceVariant, optional long surfaceTint, optional long inverseSurface, optional long inverseOnSurface, optional long error, optional long onError, optional long errorContainer, optional long onErrorContainer, optional long outline, optional long outlineVariant, optional long scrim, optional long surfaceBright, optional long surfaceDim, optional long surfaceContainer, optional long surfaceContainerHigh, optional long surfaceContainerHighest, optional long surfaceContainerLow, optional long surfaceContainerLowest);
@@ -2138,12 +2138,23 @@
     field public static final androidx.compose.material3.carousel.CarouselDefaults INSTANCE;
   }
 
-  public final class CarouselKt {
-    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void HorizontalMultiBrowseCarousel(androidx.compose.material3.carousel.CarouselState state, float preferredItemWidth, optional androidx.compose.ui.Modifier modifier, optional float itemSpacing, optional androidx.compose.foundation.gestures.TargetedFlingBehavior flingBehavior, optional float minSmallItemWidth, optional float maxSmallItemWidth, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function2<? super androidx.compose.material3.carousel.CarouselScope,? super java.lang.Integer,kotlin.Unit> content);
-    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void HorizontalUncontainedCarousel(androidx.compose.material3.carousel.CarouselState state, float itemWidth, optional androidx.compose.ui.Modifier modifier, optional float itemSpacing, optional androidx.compose.foundation.gestures.TargetedFlingBehavior flingBehavior, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function2<? super androidx.compose.material3.carousel.CarouselScope,? super java.lang.Integer,kotlin.Unit> content);
+  @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public sealed interface CarouselItemInfo {
+    method public float getMaxSize();
+    method public float getMinSize();
+    method public float getSize();
+    property public abstract float maxSize;
+    property public abstract float minSize;
+    property public abstract float size;
   }
 
-  @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public sealed interface CarouselScope {
+  @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public sealed interface CarouselItemScope {
+    method public androidx.compose.material3.carousel.CarouselItemInfo getCarouselItemInfo();
+    property public abstract androidx.compose.material3.carousel.CarouselItemInfo carouselItemInfo;
+  }
+
+  public final class CarouselKt {
+    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void HorizontalMultiBrowseCarousel(androidx.compose.material3.carousel.CarouselState state, float preferredItemWidth, optional androidx.compose.ui.Modifier modifier, optional float itemSpacing, optional androidx.compose.foundation.gestures.TargetedFlingBehavior flingBehavior, optional float minSmallItemWidth, optional float maxSmallItemWidth, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function2<? super androidx.compose.material3.carousel.CarouselItemScope,? super java.lang.Integer,kotlin.Unit> content);
+    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void HorizontalUncontainedCarousel(androidx.compose.material3.carousel.CarouselState state, float itemWidth, optional androidx.compose.ui.Modifier modifier, optional float itemSpacing, optional androidx.compose.foundation.gestures.TargetedFlingBehavior flingBehavior, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function2<? super androidx.compose.material3.carousel.CarouselItemScope,? super java.lang.Integer,kotlin.Unit> content);
   }
 
   @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public final class CarouselState implements androidx.compose.foundation.gestures.ScrollableState {
@@ -2164,7 +2175,9 @@
   }
 
   public final class CarouselStateKt {
+    method public static float endOffset(androidx.compose.material3.carousel.CarouselItemInfo);
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.carousel.CarouselState rememberCarouselState(optional int initialItem, kotlin.jvm.functions.Function0<java.lang.Integer> itemCount);
+    method public static float startOffset(androidx.compose.material3.carousel.CarouselItemInfo);
   }
 
 }
diff --git a/compose/material3/material3/integration-tests/material3-catalog/src/main/java/androidx/compose/material3/catalog/library/model/Examples.kt b/compose/material3/material3/integration-tests/material3-catalog/src/main/java/androidx/compose/material3/catalog/library/model/Examples.kt
index 71aa822..242201a 100644
--- a/compose/material3/material3/integration-tests/material3-catalog/src/main/java/androidx/compose/material3/catalog/library/model/Examples.kt
+++ b/compose/material3/material3/integration-tests/material3-catalog/src/main/java/androidx/compose/material3/catalog/library/model/Examples.kt
@@ -67,6 +67,7 @@
 import androidx.compose.material3.samples.ExposedDropdownMenuSample
 import androidx.compose.material3.samples.ExtendedFloatingActionButtonSample
 import androidx.compose.material3.samples.ExtendedFloatingActionButtonTextSample
+import androidx.compose.material3.samples.FadingHorizontalMultiBrowseCarouselSample
 import androidx.compose.material3.samples.FancyIndicatorContainerTabs
 import androidx.compose.material3.samples.FancyIndicatorTabs
 import androidx.compose.material3.samples.FancyTabs
@@ -340,6 +341,13 @@
         sourceUrl = CarouselExampleSourceUrl
     ) {
         HorizontalUncontainedCarouselSample()
+    },
+    Example(
+        name = ::FadingHorizontalMultiBrowseCarouselSample.name,
+        description = CarouselExampleDescription,
+        sourceUrl = CarouselExampleSourceUrl
+    ) {
+        FadingHorizontalMultiBrowseCarouselSample()
     }
 )
 
diff --git a/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/CarouselSamples.kt b/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/CarouselSamples.kt
index 5410945..90522ff 100644
--- a/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/CarouselSamples.kt
+++ b/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/CarouselSamples.kt
@@ -20,17 +20,21 @@
 import androidx.annotation.Sampled
 import androidx.annotation.StringRes
 import androidx.compose.foundation.Image
+import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.PaddingValues
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.layout.width
 import androidx.compose.material3.Card
 import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.Text
 import androidx.compose.material3.carousel.HorizontalMultiBrowseCarousel
 import androidx.compose.material3.carousel.HorizontalUncontainedCarousel
 import androidx.compose.material3.carousel.rememberCarouselState
+import androidx.compose.material3.carousel.startOffset
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.graphicsLayer
 import androidx.compose.ui.layout.ContentScale
 import androidx.compose.ui.res.painterResource
 import androidx.compose.ui.res.stringResource
@@ -123,3 +127,60 @@
         }
     }
 }
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Preview
+@Sampled
+@Composable
+fun FadingHorizontalMultiBrowseCarouselSample() {
+
+    data class CarouselItem(
+        val id: Int,
+        @DrawableRes val imageResId: Int,
+        @StringRes val contentDescriptionResId: Int
+    )
+
+    val items = listOf(
+        CarouselItem(0, R.drawable.carousel_image_1, R.string.carousel_image_1_description),
+        CarouselItem(1, R.drawable.carousel_image_2, R.string.carousel_image_2_description),
+        CarouselItem(2, R.drawable.carousel_image_3, R.string.carousel_image_3_description),
+        CarouselItem(3, R.drawable.carousel_image_4, R.string.carousel_image_4_description),
+        CarouselItem(4, R.drawable.carousel_image_5, R.string.carousel_image_5_description),
+    )
+    val state = rememberCarouselState { items.count() }
+    HorizontalMultiBrowseCarousel(
+        state = state,
+        modifier = Modifier
+            .width(412.dp)
+            .height(221.dp),
+        preferredItemWidth = 130.dp,
+        itemSpacing = 8.dp,
+        contentPadding = PaddingValues(horizontal = 16.dp)
+    ) { i ->
+        val item = items[i]
+        Card(
+            modifier = Modifier
+                .height(205.dp)
+        ) {
+            Box(
+                modifier = Modifier
+                    .graphicsLayer {
+                        alpha = carouselItemInfo.size / carouselItemInfo.maxSize
+                    }
+            ) {
+                Image(
+                    painter = painterResource(id = item.imageResId),
+                    contentDescription = stringResource(item.contentDescriptionResId),
+                    modifier = Modifier.fillMaxSize(),
+                    contentScale = ContentScale.Crop
+                )
+                Text(
+                    text = "sample text",
+                    modifier = Modifier.graphicsLayer {
+                        translationX = carouselItemInfo.startOffset()
+                    }
+                )
+            }
+        }
+    }
+}
diff --git a/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/PullToRefreshSamples.kt b/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/PullToRefreshSamples.kt
index 6555891..a374481 100644
--- a/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/PullToRefreshSamples.kt
+++ b/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/PullToRefreshSamples.kt
@@ -21,11 +21,18 @@
 import androidx.compose.animation.core.animate
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Refresh
 import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
 import androidx.compose.material3.LinearProgressIndicator
 import androidx.compose.material3.ListItem
+import androidx.compose.material3.Scaffold
 import androidx.compose.material3.Text
+import androidx.compose.material3.TopAppBar
 import androidx.compose.material3.pulltorefresh.PullToRefreshContainer
 import androidx.compose.material3.pulltorefresh.PullToRefreshState
 import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState
@@ -62,18 +69,33 @@
             state.endRefresh()
         }
     }
-    Box(Modifier.nestedScroll(state.nestedScrollConnection)) {
-        LazyColumn(Modifier.fillMaxSize()) {
-            if (!state.isRefreshing) {
-                items(itemCount) {
-                    ListItem({ Text(text = "Item ${itemCount - it}") })
+    Scaffold(
+        modifier = Modifier.nestedScroll(state.nestedScrollConnection),
+        topBar = {
+            TopAppBar(
+                title = { Text("TopAppBar") },
+                // Provide an accessible alternative to trigger refresh.
+                actions = {
+                    IconButton(onClick = { state.startRefresh() }) {
+                        Icon(Icons.Filled.Refresh, "Trigger Refresh")
+                    }
+                }
+            )
+        }
+    ) {
+        Box(Modifier.padding(it)) {
+            LazyColumn(Modifier.fillMaxSize()) {
+                if (!state.isRefreshing) {
+                    items(itemCount) {
+                        ListItem({ Text(text = "Item ${itemCount - it}") })
+                    }
                 }
             }
+            PullToRefreshContainer(
+                modifier = Modifier.align(Alignment.TopCenter),
+                state = state,
+            )
         }
-        PullToRefreshContainer(
-            modifier = Modifier.align(Alignment.TopCenter),
-            state = state,
-        )
     }
 }
 
@@ -95,20 +117,35 @@
     val scaleFraction = if (state.isRefreshing) 1f else
         LinearOutSlowInEasing.transform(state.progress).coerceIn(0f, 1f)
 
-    Box(Modifier.nestedScroll(state.nestedScrollConnection)) {
-        LazyColumn(Modifier.fillMaxSize()) {
-            if (!state.isRefreshing) {
-                items(itemCount) {
-                    ListItem({ Text(text = "Item ${itemCount - it}") })
+    Scaffold(
+        modifier = Modifier.nestedScroll(state.nestedScrollConnection),
+        topBar = {
+            TopAppBar(
+                title = { Text("TopAppBar") },
+                // Provide an accessible alternative to trigger refresh.
+                actions = {
+                    IconButton(onClick = { state.startRefresh() }) {
+                        Icon(Icons.Filled.Refresh, "Trigger Refresh")
+                    }
+                }
+            )
+        }
+    ) {
+        Box(Modifier.padding(it)) {
+            LazyColumn(Modifier.fillMaxSize()) {
+                if (!state.isRefreshing) {
+                    items(itemCount) {
+                        ListItem({ Text(text = "Item ${itemCount - it}") })
+                    }
                 }
             }
+            PullToRefreshContainer(
+                modifier = Modifier
+                    .align(Alignment.TopCenter)
+                    .graphicsLayer(scaleX = scaleFraction, scaleY = scaleFraction),
+                state = state,
+            )
         }
-        PullToRefreshContainer(
-            modifier = Modifier
-                .align(Alignment.TopCenter)
-                .graphicsLayer(scaleX = scaleFraction, scaleY = scaleFraction),
-            state = state,
-        )
     }
 }
 
@@ -127,18 +164,33 @@
             state.endRefresh()
         }
     }
-    Box(Modifier.nestedScroll(state.nestedScrollConnection)) {
-        LazyColumn(Modifier.fillMaxSize()) {
-            if (!state.isRefreshing) {
-                items(itemCount) {
-                    ListItem({ Text(text = "Item ${itemCount - it}") })
+    Scaffold(
+        modifier = Modifier.nestedScroll(state.nestedScrollConnection),
+        topBar = {
+            TopAppBar(
+                title = { Text("TopAppBar") },
+                // Provide an accessible alternative to trigger refresh.
+                actions = {
+                    IconButton(onClick = { state.startRefresh() }) {
+                        Icon(Icons.Filled.Refresh, "Trigger Refresh")
+                    }
+                }
+            )
+        }
+    ) {
+        Box(Modifier.padding(it)) {
+            LazyColumn(Modifier.fillMaxSize()) {
+                if (!state.isRefreshing) {
+                    items(itemCount) {
+                        ListItem({ Text(text = "Item ${itemCount - it}") })
+                    }
                 }
             }
-        }
-        if (state.isRefreshing) {
-            LinearProgressIndicator()
-        } else {
-            LinearProgressIndicator(progress = { state.progress })
+            if (state.isRefreshing) {
+                LinearProgressIndicator()
+            } else {
+                LinearProgressIndicator(progress = { state.progress })
+            }
         }
     }
 }
@@ -226,18 +278,32 @@
                 }
         }
     }
-
-    Box(Modifier.nestedScroll(state.nestedScrollConnection)) {
-        LazyColumn(Modifier.fillMaxSize()) {
-            if (!state.isRefreshing) {
-                items(itemCount) {
-                    ListItem({ Text(text = "Item ${itemCount - it}") })
+    Scaffold(
+        modifier = Modifier.nestedScroll(state.nestedScrollConnection),
+        topBar = {
+            TopAppBar(
+                title = { Text("TopAppBar") },
+                // Provide an accessible alternative to trigger refresh.
+                actions = {
+                    IconButton(onClick = { state.startRefresh() }) {
+                        Icon(Icons.Filled.Refresh, "Trigger Refresh")
+                    }
+                }
+            )
+        }
+    ) {
+        Box(Modifier.padding(it)) {
+            LazyColumn(Modifier.fillMaxSize()) {
+                if (!state.isRefreshing) {
+                    items(itemCount) {
+                        ListItem({ Text(text = "Item ${itemCount - it}") })
+                    }
                 }
             }
+            PullToRefreshContainer(
+                modifier = Modifier.align(Alignment.TopCenter),
+                state = state,
+            )
         }
-        PullToRefreshContainer(
-            modifier = Modifier.align(Alignment.TopCenter),
-            state = state,
-        )
     }
 }
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 df864c1..006e50e 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
@@ -817,6 +817,73 @@
     }
 
     @Test
+    fun bottomSheetScaffold_gesturesDisabled_doesNotParticipateInNestedScroll() {
+        lateinit var sheetState: SheetState
+        lateinit var sheetContentScrollState: ScrollState
+        lateinit var scope: CoroutineScope
+
+        rule.setContent {
+            sheetState = rememberStandardBottomSheetState()
+            scope = rememberCoroutineScope()
+            BottomSheetScaffold(
+                scaffoldState = rememberBottomSheetScaffoldState(bottomSheetState = sheetState),
+                sheetSwipeEnabled = false,
+                sheetContent = {
+                    sheetContentScrollState = rememberScrollState()
+                    Column(
+                        Modifier
+                            .verticalScroll(sheetContentScrollState)
+                            .testTag(sheetTag)
+                    ) {
+                        repeat(100) {
+                            Text(it.toString(), Modifier.requiredHeight(50.dp))
+                        }
+                    }
+                },
+                sheetPeekHeight = peekHeight,
+            ) {
+                Box(Modifier.fillMaxSize()) {
+                    Text("Content")
+                }
+            }
+        }
+
+        // Initial scrollState is at 0 and sheetState is partially expanded
+        assertThat(sheetContentScrollState.value).isEqualTo(0)
+        assertThat(sheetState.currentValue).isEqualTo(SheetValue.PartiallyExpanded)
+
+        // Scrolling up within the sheet causes content to scroll without changing sheet state
+        // because swipe gestures are disabled.
+        rule.onNodeWithTag(sheetTag)
+            .performTouchInput {
+                swipeUp()
+            }
+        rule.waitForIdle()
+        assertThat(sheetContentScrollState.value).isGreaterThan(0)
+        assertThat(sheetState.currentValue).isEqualTo(SheetValue.PartiallyExpanded)
+
+        scope.launch {
+            sheetState.snapTo(SheetValue.Expanded)
+            sheetContentScrollState.scrollTo(10)
+        }
+        rule.waitForIdle()
+
+        // Initial scrollState is > 0 and sheetState is fully expanded
+        assertThat(sheetContentScrollState.value).isEqualTo(10)
+        assertThat(sheetState.currentValue).isEqualTo(SheetValue.Expanded)
+
+        // Scrolling down within the sheet causes content to scroll without changing sheet state
+        // because swipe gestures are disabled.
+        rule.onNodeWithTag(sheetTag)
+            .performTouchInput {
+                swipeDown()
+            }
+        rule.waitForIdle()
+        assertThat(sheetContentScrollState.value).isEqualTo(0)
+        assertThat(sheetState.currentValue).isEqualTo(SheetValue.Expanded)
+    }
+
+    @Test
     fun bottomSheetScaffold_sheetMaxWidth_sizeChanges_snapsToNewTarget() {
         lateinit var sheetMaxWidth: MutableState<Dp>
         var screenWidth by mutableStateOf(0.dp)
diff --git a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/OutlinedTextFieldTest.kt b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/OutlinedTextFieldTest.kt
index 2dde725..2176687 100644
--- a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/OutlinedTextFieldTest.kt
+++ b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/OutlinedTextFieldTest.kt
@@ -41,6 +41,7 @@
 import androidx.compose.material3.internal.MinTextLineHeight
 import androidx.compose.material3.internal.Strings
 import androidx.compose.material3.internal.SupportingTopPadding
+import androidx.compose.material3.internal.TextFieldAnimationDuration
 import androidx.compose.material3.internal.TextFieldPadding
 import androidx.compose.material3.internal.getString
 import androidx.compose.runtime.CompositionLocalProvider
@@ -1661,8 +1662,8 @@
             focusRequester.requestFocus()
         }
 
-        // animation duration is 150, advancing by 75 to get into middle of animation
-        rule.mainClock.advanceTimeBy(75)
+        // advance to middle of animation
+        rule.mainClock.advanceTimeBy(TextFieldAnimationDuration.toLong() / 2)
 
         rule.runOnIdle {
             assertThat(textStyle.color).isEqualTo(expectedLabelColor)
diff --git a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/TextFieldTest.kt b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/TextFieldTest.kt
index a93e323..aa7bf96 100644
--- a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/TextFieldTest.kt
+++ b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/TextFieldTest.kt
@@ -46,6 +46,7 @@
 import androidx.compose.material3.internal.MinTextLineHeight
 import androidx.compose.material3.internal.Strings.Companion.DefaultErrorMessage
 import androidx.compose.material3.internal.SupportingTopPadding
+import androidx.compose.material3.internal.TextFieldAnimationDuration
 import androidx.compose.material3.internal.TextFieldPadding
 import androidx.compose.material3.internal.getString
 import androidx.compose.runtime.CompositionLocalProvider
@@ -1728,8 +1729,8 @@
             focusRequester.requestFocus()
         }
 
-        // animation duration is 150, advancing by 75 to get into middle of animation
-        rule.mainClock.advanceTimeBy(75)
+        // advance to middle of animation
+        rule.mainClock.advanceTimeBy(TextFieldAnimationDuration.toLong() / 2)
 
         rule.runOnIdle {
             assertThat(textStyle.color).isEqualTo(expectedLabelColor)
diff --git a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/carousel/CarouselTest.kt b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/carousel/CarouselTest.kt
index a6050e0..95b8a25 100644
--- a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/carousel/CarouselTest.kt
+++ b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/carousel/CarouselTest.kt
@@ -265,7 +265,7 @@
                 state = it,
             )
         },
-        content: @Composable CarouselScope.(item: Int) -> Unit = { Item(index = it) }
+        content: @Composable CarouselItemScope.(item: Int) -> Unit = { Item(index = it) }
     ) {
         rule.setMaterialContent(lightColorScheme()) {
             val state = rememberCarouselState(initialItem, itemCount).also {
@@ -299,7 +299,7 @@
         modifier: Modifier = Modifier
             .width(412.dp)
             .height(221.dp),
-        content: @Composable CarouselScope.(item: Int) -> Unit = { Item(index = it) }
+        content: @Composable CarouselItemScope.(item: Int) -> Unit = { Item(index = it) }
     ) {
         rule.setMaterialContent(lightColorScheme()) {
             val state = rememberCarouselState(initialItem, itemCount).also {
diff --git a/compose/material3/material3/src/androidUnitTest/kotlin/androidx/compose/material3/carousel/StrategyTest.kt b/compose/material3/material3/src/androidUnitTest/kotlin/androidx/compose/material3/carousel/StrategyTest.kt
index 595e34c..e19e370 100644
--- a/compose/material3/material3/src/androidUnitTest/kotlin/androidx/compose/material3/carousel/StrategyTest.kt
+++ b/compose/material3/material3/src/androidUnitTest/kotlin/androidx/compose/material3/carousel/StrategyTest.kt
@@ -589,6 +589,40 @@
         assertThat(firstNonAnchorLeft).isWithin(.01f).of(0f)
     }
 
+    @Test
+    fun testStartStrategy_twoLargeOneSmall_shouldAccountForPadding() {
+        val strategy = Strategy { availableSpace, itemSpacing ->
+            keylineListOf(availableSpace, itemSpacing, CarouselAlignment.Start) {
+                add(10f, isAnchor = true)
+                add(186f)
+                add(186f)
+                add(56f)
+                add(10f, isAnchor = true)
+            }
+        }.apply(
+            availableSpace = 444f,
+            itemSpacing = 8f,
+            beforeContentPadding = 16f,
+            afterContentPadding = 16f
+        )
+
+        assertThat(strategy.itemMainAxisSize).isEqualTo(186f)
+
+        val lastStartStepSmallItem = strategy.startKeylineSteps.last()[3]
+        assertThat(lastStartStepSmallItem.offset + (lastStartStepSmallItem.size / 2f))
+            .isWithin(.001f)
+            .of(444f)
+
+        val lastEndSteps = strategy.endKeylineSteps.last()
+        assertThat(lastEndSteps[1].size + 8f + lastEndSteps[2].size + 8f + lastEndSteps[3].size)
+            .isEqualTo(444f - 16f)
+
+        val lastEndStepSmallItem = strategy.endKeylineSteps.last()[1]
+        assertThat(lastEndStepSmallItem.offset - (lastEndStepSmallItem.size / 2f))
+            .isWithin(.001f)
+            .of(0f)
+    }
+
     private fun assertEqualWithFloatTolerance(
         tolerance: Float,
         actual: Keyline,
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/BottomSheetScaffold.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/BottomSheetScaffold.kt
index 62820f5..39f902f 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/BottomSheetScaffold.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/BottomSheetScaffold.kt
@@ -226,20 +226,25 @@
     val scope = rememberCoroutineScope()
     val orientation = Orientation.Vertical
     val peekHeightPx = with(LocalDensity.current) { peekHeight.toPx() }
+    val nestedScroll = if (sheetSwipeEnabled) {
+        Modifier.nestedScroll(
+            remember(state.anchoredDraggableState) {
+                ConsumeSwipeWithinBottomSheetBoundsNestedScrollConnection(
+                    sheetState = state,
+                    orientation = orientation,
+                    onFling = { scope.launch { state.settle(it) } }
+                )
+            }
+        )
+    } else {
+        Modifier
+    }
     Surface(
         modifier = Modifier
             .widthIn(max = sheetMaxWidth)
             .fillMaxWidth()
             .requiredHeightIn(min = peekHeight)
-            .nestedScroll(
-                remember(state.anchoredDraggableState) {
-                    ConsumeSwipeWithinBottomSheetBoundsNestedScrollConnection(
-                        sheetState = state,
-                        orientation = orientation,
-                        onFling = { scope.launch { state.settle(it) } }
-                    )
-                }
-            )
+            .then(nestedScroll)
             .draggableAnchors(state.anchoredDraggableState, orientation) { sheetSize, constraints ->
                 val layoutHeight = constraints.maxHeight.toFloat()
                 val sheetHeight = sheetSize.height.toFloat()
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/ColorScheme.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/ColorScheme.kt
index 79d2960..c93dafa 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/ColorScheme.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/ColorScheme.kt
@@ -151,6 +151,46 @@
     val surfaceContainerLow: Color,
     val surfaceContainerLowest: Color,
 ) {
+    @Deprecated(
+        level = DeprecationLevel.WARNING,
+        message = "Use constructor with additional 'surfaceContainer' roles.",
+        replaceWith = ReplaceWith("ColorScheme(primary,\n" +
+            "onPrimary,\n" +
+            "primaryContainer,\n" +
+            "onPrimaryContainer,\n" +
+            "inversePrimary,\n" +
+            "secondary,\n" +
+            "onSecondary,\n" +
+            "secondaryContainer,\n" +
+            "onSecondaryContainer,\n" +
+            "tertiary,\n" +
+            "onTertiary,\n" +
+            "tertiaryContainer,\n" +
+            "onTertiaryContainer,\n" +
+            "background,\n" +
+            "onBackground,\n" +
+            "surface,\n" +
+            "onSurface,\n" +
+            "surfaceVariant,\n" +
+            "onSurfaceVariant,\n" +
+            "surfaceTint,\n" +
+            "inverseSurface,\n" +
+            "inverseOnSurface,\n" +
+            "error,\n" +
+            "onError,\n" +
+            "errorContainer,\n" +
+            "onErrorContainer,\n" +
+            "outline,\n" +
+            "outlineVariant,\n" +
+            "scrim,\n" +
+            "surfaceBright,\n" +
+            "surfaceDim,\n" +
+            "surfaceContainer,\n" +
+            "surfaceContainerHigh,\n" +
+            "surfaceContainerHighest,\n" +
+            "surfaceContainerLow,\n" +
+            "surfaceContainerLowest,)")
+    )
     constructor(
         primary: Color,
         onPrimary: Color,
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/OutlinedTextField.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/OutlinedTextField.kt
index c8f3ecc..ed4970e 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/OutlinedTextField.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/OutlinedTextField.kt
@@ -980,12 +980,6 @@
         Alignment.CenterVertically.align(leadingPlaceable.height, height)
     )
 
-    // placed center vertically and to the end edge horizontally
-    trailingPlaceable?.placeRelative(
-        width - trailingPlaceable.width,
-        Alignment.CenterVertically.align(trailingPlaceable.height, height)
-    )
-
     // label position is animated
     // in single line text field, label is centered vertically before animation starts
     labelPlaceable?.let {
@@ -1022,11 +1016,6 @@
         calculateVerticalPosition(prefixPlaceable)
     )
 
-    suffixPlaceable?.placeRelative(
-        width - widthOrZero(trailingPlaceable) - suffixPlaceable.width,
-        calculateVerticalPosition(suffixPlaceable)
-    )
-
     val textHorizontalPosition = widthOrZero(leadingPlaceable) + widthOrZero(prefixPlaceable)
 
     textFieldPlaceable.placeRelative(
@@ -1040,13 +1029,25 @@
         calculateVerticalPosition(placeholderPlaceable)
     )
 
+    suffixPlaceable?.placeRelative(
+        width - widthOrZero(trailingPlaceable) - suffixPlaceable.width,
+        calculateVerticalPosition(suffixPlaceable)
+    )
+
+    // placed center vertically and to the end edge horizontally
+    trailingPlaceable?.placeRelative(
+        width - trailingPlaceable.width,
+        Alignment.CenterVertically.align(trailingPlaceable.height, height)
+    )
+
     // place supporting text
     supportingPlaceable?.placeRelative(0, height)
 }
 
-internal fun Modifier.outlineCutout(labelSize: Size, paddingValues: PaddingValues) =
+internal fun Modifier.outlineCutout(labelSize: () -> Size, paddingValues: PaddingValues) =
     this.drawWithContent {
-        val labelWidth = labelSize.width
+        val labelSizeValue = labelSize()
+        val labelWidth = labelSizeValue.width
         if (labelWidth > 0f) {
             val innerPadding = OutlinedTextFieldInnerPadding.toPx()
             val leftLtr = paddingValues.calculateLeftPadding(layoutDirection).toPx() - innerPadding
@@ -1059,7 +1060,7 @@
                 LayoutDirection.Rtl -> size.width - leftLtr.coerceAtLeast(0f)
                 else -> rightLtr
             }
-            val labelHeight = labelSize.height
+            val labelHeight = labelSizeValue.height
             // using label height as a cutout area to make sure that no hairline artifacts are
             // left when we clip the border
             clipRect(left, -labelHeight / 2, right, labelHeight / 2, ClipOp.Difference) {
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextField.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextField.kt
index 6eb7ad4..79ee41b 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextField.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextField.kt
@@ -57,6 +57,7 @@
 import androidx.compose.material3.internal.widthOrZero
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.State
 import androidx.compose.runtime.remember
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
@@ -81,7 +82,6 @@
 import androidx.compose.ui.text.input.TextFieldValue
 import androidx.compose.ui.text.input.VisualTransformation
 import androidx.compose.ui.unit.Constraints
-import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.IntOffset
 import androidx.compose.ui.unit.coerceAtLeast
 import androidx.compose.ui.unit.dp
@@ -964,10 +964,6 @@
         0,
         Alignment.CenterVertically.align(leadingPlaceable.height, height)
     )
-    trailingPlaceable?.placeRelative(
-        width - trailingPlaceable.width,
-        Alignment.CenterVertically.align(trailingPlaceable.height, height)
-    )
     labelPlaceable?.let {
         // if it's a single line, the label's start position is in the center of the
         // container. When it's a multiline text field, the label's start position is at the
@@ -985,14 +981,20 @@
     }
 
     prefixPlaceable?.placeRelative(widthOrZero(leadingPlaceable), textPosition)
+
+    val textHorizontalPosition = widthOrZero(leadingPlaceable) + widthOrZero(prefixPlaceable)
+    textfieldPlaceable.placeRelative(textHorizontalPosition, textPosition)
+    placeholderPlaceable?.placeRelative(textHorizontalPosition, textPosition)
+
     suffixPlaceable?.placeRelative(
         width - widthOrZero(trailingPlaceable) - suffixPlaceable.width,
         textPosition,
     )
 
-    val textHorizontalPosition = widthOrZero(leadingPlaceable) + widthOrZero(prefixPlaceable)
-    textfieldPlaceable.placeRelative(textHorizontalPosition, textPosition)
-    placeholderPlaceable?.placeRelative(textHorizontalPosition, textPosition)
+    trailingPlaceable?.placeRelative(
+        width - trailingPlaceable.width,
+        Alignment.CenterVertically.align(trailingPlaceable.height, height)
+    )
 
     supportingPlaceable?.placeRelative(0, height)
 }
@@ -1028,10 +1030,6 @@
         0,
         Alignment.CenterVertically.align(leadingPlaceable.height, height)
     )
-    trailingPlaceable?.placeRelative(
-        width - trailingPlaceable.width,
-        Alignment.CenterVertically.align(trailingPlaceable.height, height)
-    )
 
     // Single line text field without label places its text components centered vertically.
     // Multiline text field without label places its text components at the top with padding.
@@ -1048,11 +1046,6 @@
         calculateVerticalPosition(prefixPlaceable)
     )
 
-    suffixPlaceable?.placeRelative(
-        width - widthOrZero(trailingPlaceable) - suffixPlaceable.width,
-        calculateVerticalPosition(suffixPlaceable),
-    )
-
     val textHorizontalPosition = widthOrZero(leadingPlaceable) + widthOrZero(prefixPlaceable)
 
     textPlaceable.placeRelative(textHorizontalPosition, calculateVerticalPosition(textPlaceable))
@@ -1062,21 +1055,29 @@
         calculateVerticalPosition(placeholderPlaceable)
     )
 
+    suffixPlaceable?.placeRelative(
+        width - widthOrZero(trailingPlaceable) - suffixPlaceable.width,
+        calculateVerticalPosition(suffixPlaceable),
+    )
+
+    trailingPlaceable?.placeRelative(
+        width - trailingPlaceable.width,
+        Alignment.CenterVertically.align(trailingPlaceable.height, height)
+    )
+
     supportingPlaceable?.placeRelative(0, height)
 }
 
 /**
  * A draw modifier that draws a bottom indicator line in [TextField]
  */
-internal fun Modifier.drawIndicatorLine(indicatorBorder: BorderStroke): Modifier {
-    val strokeWidthDp = indicatorBorder.width
+internal fun Modifier.drawIndicatorLine(indicatorBorder: State<BorderStroke>): Modifier {
     return drawWithContent {
         drawContent()
-        if (strokeWidthDp == Dp.Hairline) return@drawWithContent
-        val strokeWidth = strokeWidthDp.value * density
+        val strokeWidth = indicatorBorder.value.width.toPx()
         val y = size.height - strokeWidth / 2
         drawLine(
-            indicatorBorder.brush,
+            indicatorBorder.value.brush,
             Offset(0f, y),
             Offset(size.width, y),
             strokeWidth
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextFieldDefaults.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextFieldDefaults.kt
index a1a1458..96612a6 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextFieldDefaults.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextFieldDefaults.kt
@@ -17,10 +17,7 @@
 package androidx.compose.material3
 
 import androidx.compose.animation.animateColorAsState
-import androidx.compose.animation.core.animateDpAsState
 import androidx.compose.animation.core.tween
-import androidx.compose.foundation.BorderStroke
-import androidx.compose.foundation.background
 import androidx.compose.foundation.border
 import androidx.compose.foundation.interaction.Interaction
 import androidx.compose.foundation.interaction.InteractionSource
@@ -31,24 +28,22 @@
 import androidx.compose.foundation.text.BasicTextField
 import androidx.compose.foundation.text.selection.LocalTextSelectionColors
 import androidx.compose.foundation.text.selection.TextSelectionColors
-import androidx.compose.material3.internal.AnimationDuration
 import androidx.compose.material3.internal.CommonDecorationBox
 import androidx.compose.material3.internal.SupportingTopPadding
+import androidx.compose.material3.internal.TextFieldAnimationDuration
 import androidx.compose.material3.internal.TextFieldPadding
 import androidx.compose.material3.internal.TextFieldType
+import androidx.compose.material3.internal.animateBorderStrokeAsState
+import androidx.compose.material3.internal.textFieldBackground
 import androidx.compose.material3.tokens.FilledTextFieldTokens
 import androidx.compose.material3.tokens.OutlinedTextFieldTokens
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.Immutable
 import androidx.compose.runtime.Stable
-import androidx.compose.runtime.State
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.rememberUpdatedState
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.composed
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.Shape
-import androidx.compose.ui.graphics.SolidColor
 import androidx.compose.ui.graphics.takeOrElse
 import androidx.compose.ui.platform.debugInspectorInfo
 import androidx.compose.ui.text.input.VisualTransformation
@@ -117,12 +112,13 @@
         unfocusedIndicatorLineThickness: Dp = UnfocusedIndicatorThickness,
     ) {
         val focused = interactionSource.collectIsFocusedAsState().value
-        val containerColor = colors.containerColor(enabled, isError, focused)
-        val containerColorState =
-            animateColorAsState(containerColor, tween(durationMillis = AnimationDuration))
+        val containerColor = animateColorAsState(
+            targetValue = colors.containerColor(enabled, isError, focused),
+            animationSpec = tween(durationMillis = TextFieldAnimationDuration),
+        )
         Box(
             modifier
-                .background(containerColorState.value, shape)
+                .textFieldBackground(containerColor::value, shape)
                 .indicatorLine(
                     enabled = enabled,
                     isError = isError,
@@ -169,51 +165,48 @@
         properties["focusedIndicatorLineThickness"] = focusedIndicatorLineThickness
         properties["unfocusedIndicatorLineThickness"] = unfocusedIndicatorLineThickness
     }) {
+        val focused = interactionSource.collectIsFocusedAsState().value
         val stroke = animateBorderStrokeAsState(
             enabled,
             isError,
-            interactionSource,
+            focused,
             colors,
             focusedIndicatorLineThickness,
             unfocusedIndicatorLineThickness
         )
-        Modifier.drawIndicatorLine(stroke.value)
+        Modifier.drawIndicatorLine(stroke)
     }
 
     /**
-     * A decoration box which helps creating custom text fields based on
-     * <a href="https://material.io/components/text-fields#filled-text-field" class="external" target="_blank">Material Design filled text field</a>.
+     * A decoration box used to create custom text fields based on
+     * <a href="https://m3.material.io/components/text-fields/overview" class="external" target="_blank">Material Design filled text field</a>.
      *
      * If your text field requires customising elements that aren't exposed by [TextField],
      * consider using this decoration box to achieve the desired design.
      *
-     * For example, if you need to create a dense text field, use [contentPadding] parameter to
-     * decrease the paddings around the input field. If you need to customise the bottom indicator,
-     * apply [indicatorLine] modifier to achieve that.
+     * For example, if you wish to customise the bottom indicator line, you can pass a custom
+     * [Container] to this decoration box's [container].
      *
-     * See example of using [DecorationBox] to build your own custom text field
+     * An example of building a custom text field using [DecorationBox]:
      * @sample androidx.compose.material3.samples.CustomTextFieldBasedOnDecorationBox
      *
      * @param value the input [String] shown by the text field
      * @param innerTextField input text field that this decoration box wraps. You will pass here a
      * framework-controlled composable parameter "innerTextField" from the decorationBox lambda of
      * the [BasicTextField]
-     * @param enabled controls the enabled state of the text field. When `false`, this component
-     * will not respond to user input, and it will appear visually disabled and disabled to
-     * accessibility services. You must also pass the same value to the [BasicTextField] for it to
-     * adjust the behavior accordingly.
-     * @param singleLine indicates if this is a single line or multi line text field. You must pass
-     * the same value as to [BasicTextField].
-     * @param visualTransformation transforms the visual representation of the input [value]. You
-     * must pass the same value as to [BasicTextField].
+     * @param enabled the enabled state of the text field. When `false`, this decoration box will
+     * appear visually disabled. This must be the same value that is passed to [BasicTextField].
+     * @param singleLine indicates if this is a single line or multi line text field. This must be
+     * the same value that is passed to [BasicTextField].
+     * @param visualTransformation transforms the visual representation of the input [value]. This
+     * must be the same value that is passed to [BasicTextField].
      * @param interactionSource the read-only [InteractionSource] representing the stream of
      * [Interaction]s for this text field. You must first create and pass in your own `remember`ed
      * [MutableInteractionSource] instance to the [BasicTextField] for it to dispatch events. And
      * then pass the same instance to this decoration box to observe [Interaction]s and customize
      * the appearance / behavior of this text field in different states.
-     * @param isError indicates if the text field's current value is in error state. If set to
-     * true, the label, bottom indicator and trailing icon by default will be displayed in error
-     * color.
+     * @param isError indicates if the text field's current value is in an error state. When `true`,
+     * this decoration box will display its contents in an error color.
      * @param label the optional label to be displayed inside the text field container. The default
      * text style for internal [Text] is [Typography.bodySmall] when the text field is in focus and
      * [Typography.bodyLarge] when the text field is not in focus.
@@ -227,20 +220,17 @@
      * @param prefix the optional prefix to be displayed before the input text in the text field
      * @param suffix the optional suffix to be displayed after the input text in the text field
      * @param supportingText the optional supporting text to be displayed below the text field
-     * @param shape defines the shape of this text field's container
+     * @param shape defines the shape of this decoration box's container
      * @param colors [TextFieldColors] that will be used to resolve the colors used for this text
-     * field in different states. See [TextFieldDefaults.colors].
-     * @param contentPadding the spacing values to apply internally between the internals of text
-     * field and the decoration box container. You can use it to implement dense text fields or
-     * simply to control horizontal padding. See [TextFieldDefaults.contentPaddingWithLabel] and
-     * [TextFieldDefaults.contentPaddingWithoutLabel].
-     * Note that if there's a label in the text field, the [top][PaddingValues.calculateTopPadding]
-     * padding represents the distance from the top edge of the container to the top of the label.
-     * Otherwise if label is null, it represents the distance from the top edge of the container to
-     * the top of the input field. All other paddings represent the distance from the corresponding
-     * edge of the container to the corresponding edge of the closest element.
-     * @param container the container to be drawn behind the text field. By default, this includes
-     * the bottom indicator line. Default colors for the container come from the [colors].
+     * field decoration box in different states. See [TextFieldDefaults.colors].
+     * @param contentPadding the padding applied between the internal elements of this decoration
+     * box and the edge of its container. If a [label] is present, the top padding represents
+     * the distance from the top edge of the container to the top of the label when the text field
+     * is focused. When [label] is null, the top padding represents the distance from the top edge
+     * of the container to the top of the input field. All other paddings represent the distance
+     * from the edge of the container to the corresponding edge of the closest element.
+     * @param container the container to be drawn behind the text field. By default, this uses
+     * [Container]. Default colors for the container come from the [colors].
      */
     @Composable
     @ExperimentalMaterial3Api
@@ -305,11 +295,8 @@
     /**
      * Default content padding applied to [TextField] when there is a label.
      *
-     * Note that when the label is present, the "top" padding is a distance between the top edge of
-     * the [TextField] and the top of the label, not to the top of the input field. The input field
-     * is placed directly beneath the label.
-     *
-     * See [PaddingValues] for more details.
+     * The top padding represents ths distance between the top edge of the [TextField] and the top
+     * of the label in the focused state. The input field is placed directly beneath the label.
      */
     fun contentPaddingWithLabel(
         start: Dp = TextFieldPadding,
@@ -320,7 +307,6 @@
 
     /**
      * Default content padding applied to [TextField] when the label is null.
-     * See [PaddingValues] for more details.
      */
     fun contentPaddingWithoutLabel(
         start: Dp = TextFieldPadding,
@@ -745,59 +731,56 @@
         focusedBorderThickness: Dp = FocusedBorderThickness,
         unfocusedBorderThickness: Dp = UnfocusedBorderThickness,
     ) {
+        val focused = interactionSource.collectIsFocusedAsState().value
         val borderStroke = animateBorderStrokeAsState(
             enabled,
             isError,
-            interactionSource,
+            focused,
             colors,
             focusedBorderThickness,
             unfocusedBorderThickness,
         )
-        val focused = interactionSource.collectIsFocusedAsState().value
-        val containerColor = colors.containerColor(enabled, isError, focused)
-        val containerColorState =
-            animateColorAsState(containerColor, tween(durationMillis = AnimationDuration))
+        val containerColor = animateColorAsState(
+            targetValue = colors.containerColor(enabled, isError, focused),
+            animationSpec = tween(durationMillis = TextFieldAnimationDuration),
+        )
         Box(
             modifier
                 .border(borderStroke.value, shape)
-                .background(containerColorState.value, shape)
+                .textFieldBackground(containerColor::value, shape)
         )
     }
 
     /**
-     * A decoration box which helps creating custom text fields based on
-     * <a href="https://material.io/components/text-fields#outlined-text-field" class="external" target="_blank">Material Design outlined text field</a>.
+     * A decoration box used to create custom text fields based on
+     * <a href="https://m3.material.io/components/text-fields/overview" class="external" target="_blank">Material Design outlined text field</a>.
      *
      * If your text field requires customising elements that aren't exposed by [OutlinedTextField],
      * consider using this decoration box to achieve the desired design.
      *
-     * For example, if you need to create a dense outlined text field, use [contentPadding]
-     * parameter to decrease the paddings around the input field. If you need to change the
-     * thickness of the border, use [container] parameter to achieve that.
+     * For example, if you wish to customize the thickness of the border, you can pass a custom
+     * [Container] to this decoration box's [container].
      *
-     * Example of custom text field based on [OutlinedTextFieldDefaults.DecorationBox]:
+     * An example of building a custom text field using [DecorationBox]:
      * @sample androidx.compose.material3.samples.CustomOutlinedTextFieldBasedOnDecorationBox
      *
      * @param value the input [String] shown by the text field
      * @param innerTextField input text field that this decoration box wraps. You will pass here a
      * framework-controlled composable parameter "innerTextField" from the decorationBox lambda of
      * the [BasicTextField]
-     * @param enabled controls the enabled state of the text field. When `false`, this component
-     * will not respond to user input, and it will appear visually disabled and disabled to
-     * accessibility services. You must also pass the same value to the [BasicTextField] for it to
-     * adjust the behavior accordingly.
-     * @param singleLine indicates if this is a single line or multi line text field. You must pass
-     * the same value as to [BasicTextField].
-     * @param visualTransformation transforms the visual representation of the input [value]. You
-     * must pass the same value as to [BasicTextField].
+     * @param enabled the enabled state of the text field. When `false`, this decoration box will
+     * appear visually disabled. This must be the same value that is passed to [BasicTextField].
+     * @param singleLine indicates if this is a single line or multi line text field. This must be
+     * the same value that is passed to [BasicTextField].
+     * @param visualTransformation transforms the visual representation of the input [value]. This
+     * must be the same value that is passed to [BasicTextField].
      * @param interactionSource the read-only [InteractionSource] representing the stream of
      * [Interaction]s for this text field. You must first create and pass in your own `remember`ed
      * [MutableInteractionSource] instance to the [BasicTextField] for it to dispatch events. And
      * then pass the same instance to this decoration box to observe [Interaction]s and customize
      * the appearance / behavior of this text field in different states.
-     * @param isError indicates if the text field's current value is in error state. If set to
-     * true, the label, bottom indicator and trailing icon by default will be displayed in error
-     * color.
+     * @param isError indicates if the text field's current value is in an error state. When `true`,
+     * this decoration box will display its contents in an error color.
      * @param label the optional label to be displayed inside the text field container. The default
      * text style for internal [Text] is [Typography.bodySmall] when the text field is in focus and
      * [Typography.bodyLarge] when the text field is not in focus.
@@ -813,13 +796,12 @@
      * @param supportingText the optional supporting text to be displayed below the text field
      * @param colors [TextFieldColors] that will be used to resolve the colors used for this text
      * field in different states. See [OutlinedTextFieldDefaults.colors].
-     * @param contentPadding the spacing values to apply internally between the internals of text
-     * field and the decoration box container. You can use it to implement dense text fields or
-     * simply to control horizontal padding. See [OutlinedTextFieldDefaults.contentPadding].
+     * @param contentPadding the padding applied between the internal elements of this decoration
+     * box and the edge of its container
      * @param container the container to be drawn behind the text field. By default, this is
      * transparent and only includes a border. The cutout in the border to fit the [label] will be
-     * automatically added by the framework. Note that by default the color of the border comes from
-     * the [colors].
+     * automatically added by the framework. Default colors for the container come from the
+     * [colors].
      */
     @Composable
     @ExperimentalMaterial3Api
@@ -1639,30 +1621,3 @@
         return result
     }
 }
-
-@Composable
-private fun animateBorderStrokeAsState(
-    enabled: Boolean,
-    isError: Boolean,
-    interactionSource: InteractionSource,
-    colors: TextFieldColors,
-    focusedBorderThickness: Dp,
-    unfocusedBorderThickness: Dp
-): State<BorderStroke> {
-    val focused by interactionSource.collectIsFocusedAsState()
-    val indicatorColor = colors.indicatorColor(enabled, isError, focused)
-    val indicatorColorState = if (enabled) {
-        animateColorAsState(indicatorColor, tween(durationMillis = AnimationDuration))
-    } else {
-        rememberUpdatedState(indicatorColor)
-    }
-    val targetThickness = if (focused) focusedBorderThickness else unfocusedBorderThickness
-    val animatedThickness = if (enabled) {
-        animateDpAsState(targetThickness, tween(durationMillis = AnimationDuration))
-    } else {
-        rememberUpdatedState(unfocusedBorderThickness)
-    }
-    return rememberUpdatedState(
-        BorderStroke(animatedThickness.value, SolidColor(indicatorColorState.value))
-    )
-}
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/carousel/Carousel.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/carousel/Carousel.kt
index df65fa5..65effa4 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/carousel/Carousel.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/carousel/Carousel.kt
@@ -112,7 +112,7 @@
     minSmallItemWidth: Dp = CarouselDefaults.MinSmallItemSize,
     maxSmallItemWidth: Dp = CarouselDefaults.MaxSmallItemSize,
     contentPadding: PaddingValues = PaddingValues(0.dp),
-    content: @Composable CarouselScope.(itemIndex: Int) -> Unit
+    content: @Composable CarouselItemScope.(itemIndex: Int) -> Unit
 ) {
     val density = LocalDensity.current
     Carousel(
@@ -174,7 +174,7 @@
     itemSpacing: Dp = 0.dp,
     flingBehavior: TargetedFlingBehavior = CarouselDefaults.noSnapFlingBehavior(),
     contentPadding: PaddingValues = PaddingValues(0.dp),
-    content: @Composable CarouselScope.(itemIndex: Int) -> Unit
+    content: @Composable CarouselItemScope.(itemIndex: Int) -> Unit
 ) {
     val density = LocalDensity.current
     Carousel(
@@ -228,7 +228,7 @@
     itemSpacing: Dp = 0.dp,
     flingBehavior: TargetedFlingBehavior =
         CarouselDefaults.singleAdvanceFlingBehavior(state = state),
-    content: @Composable CarouselScope.(itemIndex: Int) -> Unit
+    content: @Composable CarouselItemScope.(itemIndex: Int) -> Unit
 ) {
     val isRtl = LocalLayoutDirection.current == LayoutDirection.Rtl
     val beforeContentPadding = contentPadding.calculateBeforeContentPadding(orientation)
@@ -240,7 +240,6 @@
     val beyondViewportPageCount = remember(pageSize.strategy.itemMainAxisSize) {
         calculateBeyondViewportPageCount(pageSize.strategy)
     }
-    val carouselScope = CarouselScopeImpl
 
     val snapPositionMap = remember(pageSize.strategy.itemMainAxisSize) {
         calculateSnapPositions(
@@ -265,16 +264,20 @@
             flingBehavior = flingBehavior,
             modifier = modifier
         ) { page ->
+            val carouselItemInfo = remember { CarouselItemInfoImpl() }
+            val scope = remember { CarouselItemScopeImpl(itemInfo = carouselItemInfo) }
+
             Box(
                 modifier = Modifier.carouselItem(
                     index = page,
                     state = state,
                     strategy = pageSize.strategy,
                     itemPositionMap = snapPositionMap,
+                    carouselItemInfo = carouselItemInfo,
                     isRtl = isRtl
                 )
             ) {
-                carouselScope.content(page)
+                scope.content(page)
             }
         }
     } else if (orientation == Orientation.Vertical) {
@@ -292,16 +295,20 @@
             flingBehavior = flingBehavior,
             modifier = modifier
         ) { page ->
+            val carouselItemInfo = remember { CarouselItemInfoImpl() }
+            val scope = remember { CarouselItemScopeImpl(itemInfo = carouselItemInfo) }
+
             Box(
                 modifier = Modifier.carouselItem(
                     index = page,
                     state = state,
                     strategy = pageSize.strategy,
                     itemPositionMap = snapPositionMap,
+                    carouselItemInfo = carouselItemInfo,
                     isRtl = isRtl
                 )
             ) {
-                carouselScope.content(page)
+                scope.content(page)
             }
         }
     }
@@ -401,6 +408,7 @@
  * @param state the carousel state
  * @param strategy the strategy used to mask and translate items in the carousel
  * @param itemPositionMap the position of each index when it is the current item
+ * @param carouselItemInfo the item info that should be updated with the changes in this modifier
  * @param isRtl true if the layout direction is right-to-left
  */
 @OptIn(ExperimentalMaterial3Api::class)
@@ -409,6 +417,7 @@
     state: CarouselState,
     strategy: Strategy,
     itemPositionMap: IntIntMap,
+    carouselItemInfo: CarouselItemInfoImpl,
     isRtl: Boolean
 ): Modifier {
     if (!strategy.isValid()) return this
@@ -442,6 +451,11 @@
         val maxScrollOffset = calculateMaxScrollOffset(state, strategy)
         // TODO: Reduce the number of times a keyline for the same scroll offset is calculated
         val keylines = strategy.getKeylineListForScrollOffset(scrollOffset, maxScrollOffset)
+        val roundedKeylines = strategy.getKeylineListForScrollOffset(
+            scrollOffset = scrollOffset,
+            maxScrollOffset = maxScrollOffset,
+            roundToNearestStep = true
+        )
 
         // Find center of the item at this index
         val itemSizeWithSpacing = strategy.itemMainAxisSize + strategy.itemSpacing
@@ -458,6 +472,26 @@
         val interpolatedKeyline = lerp(keylineBefore, keylineAfter, progress)
         val isOutOfKeylineBounds = keylineBefore == keylineAfter
 
+        val centerX =
+            if (isVertical) size.height / 2f else strategy.itemMainAxisSize / 2f
+        val centerY =
+            if (isVertical) strategy.itemMainAxisSize / 2f else size.height / 2f
+        val halfMaskWidth =
+            if (isVertical) size.width / 2f else interpolatedKeyline.size / 2f
+        val halfMaskHeight =
+            if (isVertical) interpolatedKeyline.size / 2f else size.height / 2f
+        val maskRect = Rect(
+            left = centerX - halfMaskWidth,
+            top = centerY - halfMaskHeight,
+            right = centerX + halfMaskWidth,
+            bottom = centerY + halfMaskHeight
+        )
+
+        // Update carousel item info
+        carouselItemInfo.sizeState.floatValue = interpolatedKeyline.size
+        carouselItemInfo.minSizeState.floatValue = roundedKeylines.minBy { it.size }.size
+        carouselItemInfo.maxSizeState.floatValue = roundedKeylines.firstFocal.size
+
         // Clip the item
         clip = true
         shape = object : Shape {
@@ -469,29 +503,15 @@
                 layoutDirection: LayoutDirection,
                 density: Density
             ): Outline {
-                val centerX =
-                    if (isVertical) size.height / 2f else strategy.itemMainAxisSize / 2f
-                val centerY =
-                    if (isVertical) strategy.itemMainAxisSize / 2f else size.height / 2f
-                val halfMaskWidth =
-                    if (isVertical) size.width / 2f else interpolatedKeyline.size / 2f
-                val halfMaskHeight =
-                    if (isVertical) interpolatedKeyline.size / 2f else size.height / 2f
-                val rect = Rect(
-                    left = centerX - halfMaskWidth,
-                    top = centerY - halfMaskHeight,
-                    right = centerX + halfMaskWidth,
-                    bottom = centerY + halfMaskHeight
-                )
                 val cornerSize =
                     roundedCornerShape.topStart.toPx(
-                        Size(rect.width, rect.height),
+                        Size(maskRect.width, maskRect.height),
                         density
                     )
                 val cornerRadius = CornerRadius(cornerSize)
                 return Outline.Rounded(
                     RoundRect(
-                        rect = rect,
+                        rect = maskRect,
                         topLeft = cornerRadius,
                         topRight = cornerRadius,
                         bottomRight = cornerRadius,
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/carousel/CarouselItemScope.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/carousel/CarouselItemScope.kt
new file mode 100644
index 0000000..fea9940
--- /dev/null
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/carousel/CarouselItemScope.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.compose.material3.carousel
+
+import androidx.compose.material3.ExperimentalMaterial3Api
+
+/**
+ * Receiver scope for [Carousel] item content.
+ */
+@ExperimentalMaterial3Api
+sealed interface CarouselItemScope {
+    /**
+     * Information regarding the carousel item, such as its minimum and maximum size.
+     *
+     * The item information is updated after every scroll. If you use it in a composable function,
+     * it will be recomposed on every change causing potential performance issues. Avoid using it
+     * in the composition.
+     */
+    val carouselItemInfo: CarouselItemInfo
+}
+
+@ExperimentalMaterial3Api
+internal class CarouselItemScopeImpl(
+    private val itemInfo: CarouselItemInfo
+) : CarouselItemScope {
+    override val carouselItemInfo: CarouselItemInfo
+        get() = itemInfo
+}
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/carousel/CarouselScope.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/carousel/CarouselScope.kt
deleted file mode 100644
index 467d8a5..0000000
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/carousel/CarouselScope.kt
+++ /dev/null
@@ -1,28 +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.compose.material3.carousel
-
-import androidx.compose.material3.ExperimentalMaterial3Api
-
-/**
- * Receiver scope for [Carousel].
- */
-@ExperimentalMaterial3Api
-sealed interface CarouselScope
-
-@ExperimentalMaterial3Api
-internal object CarouselScopeImpl : CarouselScope
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/carousel/CarouselState.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/carousel/CarouselState.kt
index 4c26f8a..1f5f990 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/carousel/CarouselState.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/carousel/CarouselState.kt
@@ -23,6 +23,7 @@
 import androidx.compose.foundation.pager.PagerState
 import androidx.compose.material3.ExperimentalMaterial3Api
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.mutableFloatStateOf
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.saveable.Saver
 import androidx.compose.runtime.saveable.listSaver
@@ -108,3 +109,80 @@
         itemCountState.value = itemCount
     }
 }
+
+/**
+ * Interface to hold information about a Carousel item and its size.
+ *
+ * Example of CarouselItemInfo usage:
+ * @sample androidx.compose.material3.samples.FadingHorizontalMultiBrowseCarouselSample
+ */
+@ExperimentalMaterial3Api
+sealed interface CarouselItemInfo {
+
+    /** The size of the carousel item in the main axis */
+    val size: Float
+
+    /**
+     * The minimum size in the main axis of the carousel item, eg. the size of the item when it
+     * scrolls off the sides of the carousel
+     */
+    val minSize: Float
+
+    /**
+     * The maximum size in the main axis of the carousel item, eg. the size of the item when it is
+     * at a focal position
+     */
+    val maxSize: Float
+}
+
+/**
+ * Gets the start offset of the carousel item from its full size. This offset can be used to pin any
+ * carousel item content to the left side of the item (or right if RTL).
+ */
+@OptIn(ExperimentalMaterial3Api::class)
+fun CarouselItemInfo.startOffset(): Float {
+    return (maxSize - size) / 2f
+}
+
+/**
+ * Gets the end offset of the carousel item from its full size. This offset can be used to pin any
+ * carousel item content to the right side of the item (or left if RTL).
+ */
+@OptIn(ExperimentalMaterial3Api::class)
+fun CarouselItemInfo.endOffset(): Float {
+    return maxSize - (maxSize - size) / 2f
+}
+
+@OptIn(ExperimentalMaterial3Api::class)
+internal class CarouselItemInfoImpl : CarouselItemInfo {
+
+    val sizeState = mutableFloatStateOf(0f)
+    override val size: Float
+        get() = sizeState.floatValue
+
+    val minSizeState = mutableFloatStateOf(0f)
+    override val minSize: Float
+        get() = minSizeState.floatValue
+
+    val maxSizeState = mutableFloatStateOf(0f)
+    override val maxSize: Float
+        get() = maxSizeState.floatValue
+
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other !is CarouselItemInfoImpl) return false
+
+        if (sizeState != other.sizeState) return false
+        if (minSizeState != other.minSizeState) return false
+        if (maxSizeState != other.maxSizeState) return false
+
+        return true
+    }
+
+    override fun hashCode(): Int {
+        var result = sizeState.hashCode()
+        result = 31 * result + minSizeState.hashCode()
+        result = 31 * result + maxSizeState.hashCode()
+        return result
+    }
+}
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/carousel/Strategy.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/carousel/Strategy.kt
index 916efe0..92a5bba 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/carousel/Strategy.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/carousel/Strategy.kt
@@ -309,7 +309,9 @@
                             defaultKeylines,
                             carouselMainAxisSize,
                             itemSpacing,
-                            beforeContentPadding
+                            beforeContentPadding,
+                            defaultKeylines.firstFocal,
+                            defaultKeylines.firstFocalIndex
                         )
                     )
                 }
@@ -364,7 +366,9 @@
                     steps.last(),
                     carouselMainAxisSize,
                     itemSpacing,
-                    beforeContentPadding
+                    beforeContentPadding,
+                    steps.last().firstFocal,
+                    steps.last().firstFocalIndex
                 )
             }
 
@@ -402,7 +406,9 @@
                         defaultKeylines,
                         carouselMainAxisSize,
                         itemSpacing,
-                        -afterContentPadding
+                        -afterContentPadding,
+                        defaultKeylines.lastFocal,
+                        defaultKeylines.lastFocalIndex
                     ))
                 }
                 return steps
@@ -456,7 +462,9 @@
                     steps.last(),
                     carouselMainAxisSize,
                     itemSpacing,
-                    -afterContentPadding
+                    -afterContentPadding,
+                    steps.last().lastFocal,
+                    steps.last().lastFocalIndex
                 )
             }
 
@@ -471,7 +479,9 @@
             from: KeylineList,
             carouselMainAxisSize: Float,
             itemSpacing: Float,
-            contentPadding: Float
+            contentPadding: Float,
+            pivot: Keyline,
+            pivotIndex: Int
         ): KeylineList {
             val numberOfNonAnchorKeylines = from.fastFilter { !it.isAnchor }.count()
             val sizeReduction = contentPadding / numberOfNonAnchorKeylines
@@ -480,8 +490,8 @@
             val newKeylines = keylineListOf(
                 carouselMainAxisSize = carouselMainAxisSize,
                 itemSpacing = itemSpacing,
-                pivotIndex = from.pivotIndex,
-                pivotOffset = from.pivot.offset + contentPadding - (sizeReduction / 2f)
+                pivotIndex = pivotIndex,
+                pivotOffset = pivot.offset - (sizeReduction / 2f) + contentPadding
             ) {
                 from.fastForEach { k -> add(k.size - abs(sizeReduction), k.isAnchor) }
             }
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/internal/TextFieldImpl.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/internal/TextFieldImpl.kt
index 886c2e2..d3f51de 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/internal/TextFieldImpl.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/internal/TextFieldImpl.kt
@@ -17,11 +17,14 @@
 package androidx.compose.material3.internal
 
 import androidx.compose.animation.animateColor
+import androidx.compose.animation.animateColorAsState
 import androidx.compose.animation.core.LinearEasing
+import androidx.compose.animation.core.animateDpAsState
 import androidx.compose.animation.core.animateFloat
 import androidx.compose.animation.core.spring
 import androidx.compose.animation.core.tween
 import androidx.compose.animation.core.updateTransition
+import androidx.compose.foundation.BorderStroke
 import androidx.compose.foundation.interaction.InteractionSource
 import androidx.compose.foundation.interaction.collectIsFocusedAsState
 import androidx.compose.foundation.layout.Box
@@ -35,13 +38,21 @@
 import androidx.compose.material3.outlineCutout
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.State
+import androidx.compose.runtime.derivedStateOf
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberUpdatedState
+import androidx.compose.runtime.structuralEqualityPolicy
 import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.alpha
+import androidx.compose.ui.draw.drawWithCache
 import androidx.compose.ui.geometry.Size
 import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.ColorProducer
+import androidx.compose.ui.graphics.Shape
+import androidx.compose.ui.graphics.drawOutline
+import androidx.compose.ui.graphics.graphicsLayer
 import androidx.compose.ui.graphics.takeOrElse
 import androidx.compose.ui.layout.IntrinsicMeasurable
 import androidx.compose.ui.layout.LayoutIdParentData
@@ -54,6 +65,7 @@
 import androidx.compose.ui.text.input.VisualTransformation
 import androidx.compose.ui.text.lerp
 import androidx.compose.ui.unit.Constraints
+import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
 
 internal enum class TextFieldType {
@@ -100,33 +112,34 @@
     val typography = MaterialTheme.typography
     val bodyLarge = typography.bodyLarge
     val bodySmall = typography.bodySmall
-    val shouldOverrideTextStyleColor =
+    val overrideLabelTextStyleColor =
         (bodyLarge.color == Color.Unspecified && bodySmall.color != Color.Unspecified) ||
             (bodyLarge.color != Color.Unspecified && bodySmall.color == Color.Unspecified)
 
-    TextFieldTransitionScope.Transition(
+    TextFieldTransitionScope(
         inputState = inputState,
-        focusedTextStyleColor = with(MaterialTheme.typography.bodySmall.color) {
-            if (shouldOverrideTextStyleColor) this.takeOrElse { labelColor } else this
+        focusedLabelTextStyleColor = with(bodySmall.color) {
+            if (overrideLabelTextStyleColor) this.takeOrElse { labelColor } else this
         },
-        unfocusedTextStyleColor = with(MaterialTheme.typography.bodyLarge.color) {
-            if (shouldOverrideTextStyleColor) this.takeOrElse { labelColor } else this
+        unfocusedLabelTextStyleColor = with(bodyLarge.color) {
+            if (overrideLabelTextStyleColor) this.takeOrElse { labelColor } else this
         },
-        contentColor = labelColor,
-        showLabel = label != null
-    ) { labelProgress, labelTextStyleColor, labelContentColor, placeholderAlphaProgress,
-        prefixSuffixAlphaProgress ->
-
+        labelColor = labelColor,
+        showLabel = label != null,
+    ) { labelProgress, labelTextStyleColor, labelContentColor, placeholderAlpha,
+        prefixSuffixAlpha ->
+        val labelProgressValue = labelProgress.value
         val decoratedLabel: @Composable (() -> Unit)? = label?.let {
             @Composable {
-                val labelTextStyle = lerp(
-                    MaterialTheme.typography.bodyLarge,
-                    MaterialTheme.typography.bodySmall,
-                    labelProgress
-                ).let {
-                    if (shouldOverrideTextStyleColor) it.copy(color = labelTextStyleColor) else it
-                }
-                Decoration(labelContentColor, labelTextStyle, it)
+                val labelTextStyle =
+                    lerp(bodyLarge, bodySmall, labelProgressValue).let { textStyle ->
+                        if (overrideLabelTextStyleColor) {
+                            textStyle.copy(color = labelTextStyleColor.value)
+                        } else {
+                            textStyle
+                        }
+                    }
+                Decoration(labelContentColor.value, labelTextStyle, it)
             }
         }
 
@@ -134,13 +147,18 @@
         // have alpha == 0, we set the component to null instead.
 
         val placeholderColor = colors.placeholderColor(enabled, isError, isFocused)
+        val showPlaceholder by remember {
+            derivedStateOf(structuralEqualityPolicy()) {
+                placeholderAlpha.value > 0f
+            }
+        }
         val decoratedPlaceholder: @Composable ((Modifier) -> Unit)? =
-            if (placeholder != null && transformedText.isEmpty() && placeholderAlphaProgress > 0f) {
+            if (placeholder != null && transformedText.isEmpty() && showPlaceholder) {
                 @Composable { modifier ->
-                    Box(modifier.alpha(placeholderAlphaProgress)) {
+                    Box(modifier.graphicsLayer { alpha = placeholderAlpha.value }) {
                         Decoration(
                             contentColor = placeholderColor,
-                            typography = MaterialTheme.typography.bodyLarge,
+                            textStyle = bodyLarge,
                             content = placeholder
                         )
                     }
@@ -148,13 +166,18 @@
             } else null
 
         val prefixColor = colors.prefixColor(enabled, isError, isFocused)
+        val showPrefixSuffix by remember {
+            derivedStateOf(structuralEqualityPolicy()) {
+                prefixSuffixAlpha.value > 0f
+            }
+        }
         val decoratedPrefix: @Composable (() -> Unit)? =
-            if (prefix != null && prefixSuffixAlphaProgress > 0f) {
+            if (prefix != null && showPrefixSuffix) {
                 @Composable {
-                    Box(Modifier.alpha(prefixSuffixAlphaProgress)) {
+                    Box(Modifier.graphicsLayer { alpha = prefixSuffixAlpha.value }) {
                         Decoration(
                             contentColor = prefixColor,
-                            typography = bodyLarge,
+                            textStyle = bodyLarge,
                             content = prefix
                         )
                     }
@@ -163,12 +186,12 @@
 
         val suffixColor = colors.suffixColor(enabled, isError, isFocused)
         val decoratedSuffix: @Composable (() -> Unit)? =
-            if (suffix != null && prefixSuffixAlphaProgress > 0f) {
+            if (suffix != null && showPrefixSuffix) {
                 @Composable {
-                    Box(Modifier.alpha(prefixSuffixAlphaProgress)) {
+                    Box(Modifier.graphicsLayer { alpha = prefixSuffixAlpha.value }) {
                         Decoration(
                             contentColor = suffixColor,
-                            typography = bodyLarge,
+                            textStyle = bodyLarge,
                             content = suffix
                         )
                     }
@@ -193,7 +216,7 @@
             colors.supportingTextColor(enabled, isError, isFocused)
         val decoratedSupporting: @Composable (() -> Unit)? = supportingText?.let {
             @Composable {
-                Decoration(contentColor = supportingTextColor, typography = bodySmall, content = it)
+                Decoration(contentColor = supportingTextColor, textStyle = bodySmall, content = it)
             }
         }
 
@@ -218,7 +241,8 @@
                     container = containerWithId,
                     supporting = decoratedSupporting,
                     singleLine = singleLine,
-                    animationProgress = labelProgress,
+                    // TODO(b/271000818): progress state read should be deferred to layout phase
+                    animationProgress = labelProgressValue,
                     paddingValues = contentPadding
                 )
             }
@@ -229,7 +253,7 @@
                     Box(
                         Modifier
                             .layoutId(ContainerId)
-                            .outlineCutout(labelSize.value, contentPadding),
+                            .outlineCutout(labelSize::value, contentPadding),
                         propagateMinConstraints = true
                     ) {
                         container()
@@ -248,15 +272,16 @@
                     supporting = decoratedSupporting,
                     singleLine = singleLine,
                     onLabelMeasured = {
-                        val labelWidth = it.width * labelProgress
-                        val labelHeight = it.height * labelProgress
+                        val labelWidth = it.width * labelProgressValue
+                        val labelHeight = it.height * labelProgressValue
                         if (labelSize.value.width != labelWidth ||
                             labelSize.value.height != labelHeight
                         ) {
                             labelSize.value = Size(labelWidth, labelHeight)
                         }
                     },
-                    animationProgress = labelProgress,
+                    // TODO(b/271000818): progress state read should be deferred to layout phase
+                    animationProgress = labelProgressValue,
                     container = borderContainerWithId,
                     paddingValues = contentPadding
                 )
@@ -266,25 +291,23 @@
 }
 
 /**
- * Set content color, typography and emphasis for [content] composable
+ * Decorates [content] with [contentColor] and [textStyle].
  */
 @Composable
-internal fun Decoration(
+private fun Decoration(
     contentColor: Color,
-    typography: TextStyle? = null,
+    textStyle: TextStyle,
     content: @Composable () -> Unit
-) {
-    val contentWithColor: @Composable () -> Unit = @Composable {
-        CompositionLocalProvider(
-            LocalContentColor provides contentColor,
-            content = content
-        )
-    }
-    if (typography != null)
-        ProvideContentColorTextStyle(contentColor, typography, content)
-    else
-        contentWithColor()
-}
+) = ProvideContentColorTextStyle(contentColor, textStyle, content)
+
+/**
+ * Decorates [content] with [contentColor].
+ */
+@Composable
+private fun Decoration(
+    contentColor: Color,
+    content: @Composable () -> Unit
+) = CompositionLocalProvider(LocalContentColor provides contentColor, content = content)
 
 // Developers need to handle invalid input manually. But since we don't provide an error message
 // slot API, we can set the default error message in case developers forget about it.
@@ -293,105 +316,143 @@
     defaultErrorMessage: String,
 ): Modifier = if (isError) semantics { error(defaultErrorMessage) } else this
 
+/**
+ *  Replacement for Modifier.background which takes color as a State to avoid
+ *  recomposition while animating.
+ */
+internal fun Modifier.textFieldBackground(
+    color: ColorProducer,
+    shape: Shape,
+): Modifier = this.drawWithCache {
+    val outline = shape.createOutline(size, layoutDirection, this)
+    onDrawBehind {
+        drawOutline(outline, color = color())
+    }
+}
+
 internal fun widthOrZero(placeable: Placeable?) = placeable?.width ?: 0
 internal fun heightOrZero(placeable: Placeable?) = placeable?.height ?: 0
 
-private object TextFieldTransitionScope {
-    @Composable
-    fun Transition(
-        inputState: InputPhase,
-        focusedTextStyleColor: Color,
-        unfocusedTextStyleColor: Color,
-        contentColor: Color,
-        showLabel: Boolean,
-        content: @Composable (
-            labelProgress: Float,
-            labelTextStyleColor: Color,
-            labelContentColor: Color,
-            placeholderOpacity: Float,
-            prefixSuffixOpacity: Float,
-        ) -> Unit
+@Composable
+private inline fun TextFieldTransitionScope(
+    inputState: InputPhase,
+    focusedLabelTextStyleColor: Color,
+    unfocusedLabelTextStyleColor: Color,
+    labelColor: Color,
+    showLabel: Boolean,
+    content: @Composable (
+        labelProgress: State<Float>,
+        labelTextStyleColor: State<Color>,
+        labelContentColor: State<Color>,
+        placeholderOpacity: State<Float>,
+        prefixSuffixOpacity: State<Float>,
+    ) -> Unit
+) {
+    // Transitions from/to InputPhase.Focused are the most critical in the transition below.
+    // UnfocusedEmpty <-> UnfocusedNotEmpty are needed when a single state is used to control
+    // multiple text fields.
+    val transition = updateTransition(inputState, label = "TextFieldInputState")
+
+    val labelProgress = transition.animateFloat(
+        label = "LabelProgress",
+        transitionSpec = { tween(durationMillis = TextFieldAnimationDuration) }
     ) {
-        // Transitions from/to InputPhase.Focused are the most critical in the transition below.
-        // UnfocusedEmpty <-> UnfocusedNotEmpty are needed when a single state is used to control
-        // multiple text fields.
-        val transition = updateTransition(inputState, label = "TextFieldInputState")
-
-        val labelProgress by transition.animateFloat(
-            label = "LabelProgress",
-            transitionSpec = { tween(durationMillis = AnimationDuration) }
-        ) {
-            when (it) {
-                InputPhase.Focused -> 1f
-                InputPhase.UnfocusedEmpty -> 0f
-                InputPhase.UnfocusedNotEmpty -> 1f
-            }
+        when (it) {
+            InputPhase.Focused -> 1f
+            InputPhase.UnfocusedEmpty -> 0f
+            InputPhase.UnfocusedNotEmpty -> 1f
         }
-
-        val placeholderOpacity by transition.animateFloat(
-            label = "PlaceholderOpacity",
-            transitionSpec = {
-                if (InputPhase.Focused isTransitioningTo InputPhase.UnfocusedEmpty) {
-                    tween(
-                        durationMillis = PlaceholderAnimationDelayOrDuration,
-                        easing = LinearEasing
-                    )
-                } else if (InputPhase.UnfocusedEmpty isTransitioningTo InputPhase.Focused ||
-                    InputPhase.UnfocusedNotEmpty isTransitioningTo InputPhase.UnfocusedEmpty
-                ) {
-                    tween(
-                        durationMillis = PlaceholderAnimationDuration,
-                        delayMillis = PlaceholderAnimationDelayOrDuration,
-                        easing = LinearEasing
-                    )
-                } else {
-                    spring()
-                }
-            }
-        ) {
-            when (it) {
-                InputPhase.Focused -> 1f
-                InputPhase.UnfocusedEmpty -> if (showLabel) 0f else 1f
-                InputPhase.UnfocusedNotEmpty -> 0f
-            }
-        }
-
-        val prefixSuffixOpacity by transition.animateFloat(
-            label = "PrefixSuffixOpacity",
-            transitionSpec = { tween(durationMillis = AnimationDuration) }
-        ) {
-            when (it) {
-                InputPhase.Focused -> 1f
-                InputPhase.UnfocusedEmpty -> if (showLabel) 0f else 1f
-                InputPhase.UnfocusedNotEmpty -> 1f
-            }
-        }
-
-        val labelTextStyleColor by transition.animateColor(
-            transitionSpec = { tween(durationMillis = AnimationDuration) },
-            label = "LabelTextStyleColor"
-        ) {
-            when (it) {
-                InputPhase.Focused -> focusedTextStyleColor
-                else -> unfocusedTextStyleColor
-            }
-        }
-
-        @Suppress("UnusedTransitionTargetStateParameter")
-        val labelContentColor by transition.animateColor(
-            transitionSpec = { tween(durationMillis = AnimationDuration) },
-            label = "LabelContentColor",
-            targetValueByState = { contentColor }
-        )
-
-        content(
-            labelProgress,
-            labelTextStyleColor,
-            labelContentColor,
-            placeholderOpacity,
-            prefixSuffixOpacity,
-        )
     }
+
+    val placeholderOpacity = transition.animateFloat(
+        label = "PlaceholderOpacity",
+        transitionSpec = {
+            if (InputPhase.Focused isTransitioningTo InputPhase.UnfocusedEmpty) {
+                tween(
+                    durationMillis = PlaceholderAnimationDelayOrDuration,
+                    easing = LinearEasing
+                )
+            } else if (InputPhase.UnfocusedEmpty isTransitioningTo InputPhase.Focused ||
+                InputPhase.UnfocusedNotEmpty isTransitioningTo InputPhase.UnfocusedEmpty
+            ) {
+                tween(
+                    durationMillis = PlaceholderAnimationDuration,
+                    delayMillis = PlaceholderAnimationDelayOrDuration,
+                    easing = LinearEasing
+                )
+            } else {
+                spring()
+            }
+        }
+    ) {
+        when (it) {
+            InputPhase.Focused -> 1f
+            InputPhase.UnfocusedEmpty -> if (showLabel) 0f else 1f
+            InputPhase.UnfocusedNotEmpty -> 0f
+        }
+    }
+
+    val prefixSuffixOpacity = transition.animateFloat(
+        label = "PrefixSuffixOpacity",
+        transitionSpec = { tween(durationMillis = TextFieldAnimationDuration) }
+    ) {
+        when (it) {
+            InputPhase.Focused -> 1f
+            InputPhase.UnfocusedEmpty -> if (showLabel) 0f else 1f
+            InputPhase.UnfocusedNotEmpty -> 1f
+        }
+    }
+
+    val labelTextStyleColor = transition.animateColor(
+        transitionSpec = { tween(durationMillis = TextFieldAnimationDuration) },
+        label = "LabelTextStyleColor"
+    ) {
+        when (it) {
+            InputPhase.Focused -> focusedLabelTextStyleColor
+            else -> unfocusedLabelTextStyleColor
+        }
+    }
+
+    @Suppress("UnusedTransitionTargetStateParameter")
+    val labelContentColor = transition.animateColor(
+        transitionSpec = { tween(durationMillis = TextFieldAnimationDuration) },
+        label = "LabelContentColor",
+        targetValueByState = { labelColor }
+    )
+
+    content(
+        labelProgress,
+        labelTextStyleColor,
+        labelContentColor,
+        placeholderOpacity,
+        prefixSuffixOpacity,
+    )
+}
+
+@Composable
+internal fun animateBorderStrokeAsState(
+    enabled: Boolean,
+    isError: Boolean,
+    focused: Boolean,
+    colors: TextFieldColors,
+    focusedBorderThickness: Dp,
+    unfocusedBorderThickness: Dp
+): State<BorderStroke> {
+    val targetColor = colors.indicatorColor(enabled, isError, focused)
+    val indicatorColor = if (enabled) {
+        animateColorAsState(targetColor, tween(durationMillis = TextFieldAnimationDuration))
+    } else {
+        rememberUpdatedState(targetColor)
+    }
+
+    val thickness = if (enabled) {
+        val targetThickness = if (focused) focusedBorderThickness else unfocusedBorderThickness
+        animateDpAsState(targetThickness, tween(durationMillis = TextFieldAnimationDuration))
+    } else {
+        rememberUpdatedState(unfocusedBorderThickness)
+    }
+
+    return rememberUpdatedState(BorderStroke(thickness.value, indicatorColor.value))
 }
 
 /**
@@ -422,7 +483,7 @@
 internal const val ContainerId = "Container"
 internal val ZeroConstraints = Constraints(0, 0, 0, 0)
 
-internal const val AnimationDuration = 150
+internal const val TextFieldAnimationDuration = 150
 private const val PlaceholderAnimationDuration = 83
 private const val PlaceholderAnimationDelayOrDuration = 67
 
diff --git a/compose/runtime/runtime-saveable/src/androidUnitTest/kotlin/androidx/compose/runtime/saveable/SaveableStateRegistryTest.kt b/compose/runtime/runtime-saveable/src/androidUnitTest/kotlin/androidx/compose/runtime/saveable/SaveableStateRegistryTest.kt
index 1dbda70..c74d862 100644
--- a/compose/runtime/runtime-saveable/src/androidUnitTest/kotlin/androidx/compose/runtime/saveable/SaveableStateRegistryTest.kt
+++ b/compose/runtime/runtime-saveable/src/androidUnitTest/kotlin/androidx/compose/runtime/saveable/SaveableStateRegistryTest.kt
@@ -92,6 +92,17 @@
         }
     }
 
+    @Test
+    fun singleCharacterKeysAreAllowed() {
+        val registry = createRegistry()
+
+        registry.registerProvider("a") { 1 }
+
+        registry.performSave().apply {
+            assertThat(get("a")).isEqualTo(listOf(1))
+        }
+    }
+
     @Test(expected = IllegalArgumentException::class)
     fun emptyKeysAreNotAllowed() {
         val registry = createRegistry()
diff --git a/compose/runtime/runtime-saveable/src/commonMain/kotlin/androidx/compose/runtime/saveable/SaveableStateRegistry.kt b/compose/runtime/runtime-saveable/src/commonMain/kotlin/androidx/compose/runtime/saveable/SaveableStateRegistry.kt
index 8af7791..0428ffe 100644
--- a/compose/runtime/runtime-saveable/src/commonMain/kotlin/androidx/compose/runtime/saveable/SaveableStateRegistry.kt
+++ b/compose/runtime/runtime-saveable/src/commonMain/kotlin/androidx/compose/runtime/saveable/SaveableStateRegistry.kt
@@ -93,7 +93,7 @@
 // CharSequence.isBlank() allocates an iterator because it calls indices.all{}
 private fun CharSequence.fastIsBlank(): Boolean {
     var blank = true
-    for (i in 0 until length - 1) {
+    for (i in 0 until length) {
         if (!this[i].isWhitespace()) {
             blank = false
             break
diff --git a/compose/runtime/runtime/api/api_lint.ignore b/compose/runtime/runtime/api/api_lint.ignore
index ced886f..e36cd55 100644
--- a/compose/runtime/runtime/api/api_lint.ignore
+++ b/compose/runtime/runtime/api/api_lint.ignore
@@ -21,6 +21,8 @@
     Getter for boolean property `hasInvalidations` is named `getHasInvalidations` but should match the property name. Use `@get:JvmName` to rename.
 GetterSetterNames: androidx.compose.runtime.ControlledComposition#getHasPendingChanges():
     Getter for boolean property `hasPendingChanges` is named `getHasPendingChanges` but should match the property name. Use `@get:JvmName` to rename.
+GetterSetterNames: androidx.compose.runtime.ProvidedValue#getCanOverride():
+    Getter for boolean property `canOverride` is named `getCanOverride` but should match the property name. Use `@get:JvmName` to rename.
 GetterSetterNames: androidx.compose.runtime.Recomposer#getHasPendingWork():
     Getter for boolean property `hasPendingWork` is named `getHasPendingWork` but should match the property name. Use `@get:JvmName` to rename.
 GetterSetterNames: androidx.compose.runtime.RecomposerInfo#getHasPendingWork():
diff --git a/compose/runtime/runtime/api/current.txt b/compose/runtime/runtime/api/current.txt
index 0163760..36648cc 100644
--- a/compose/runtime/runtime/api/current.txt
+++ b/compose/runtime/runtime/api/current.txt
@@ -227,6 +227,10 @@
     property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final inline T current;
   }
 
+  public interface CompositionLocalAccessorScope {
+    method public <T> T getCurrentValue(androidx.compose.runtime.CompositionLocal<T>);
+  }
+
   @androidx.compose.runtime.Stable public final class CompositionLocalContext {
   }
 
@@ -235,6 +239,7 @@
     method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonSkippableComposable public static void CompositionLocalProvider(androidx.compose.runtime.ProvidedValue<?> value, kotlin.jvm.functions.Function0<kotlin.Unit> content);
     method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonSkippableComposable public static void CompositionLocalProvider(androidx.compose.runtime.ProvidedValue<?>[] values, kotlin.jvm.functions.Function0<kotlin.Unit> content);
     method public static <T> androidx.compose.runtime.ProvidableCompositionLocal<T> compositionLocalOf(optional androidx.compose.runtime.SnapshotMutationPolicy<T> policy, kotlin.jvm.functions.Function0<? extends T> defaultFactory);
+    method public static <T> androidx.compose.runtime.ProvidableCompositionLocal<T> compositionLocalWithComputedDefaultOf(kotlin.jvm.functions.Function1<? super androidx.compose.runtime.CompositionLocalAccessorScope,? extends T> defaultComputation);
     method public static <T> androidx.compose.runtime.ProvidableCompositionLocal<T> staticCompositionLocalOf(kotlin.jvm.functions.Function0<? extends T> defaultFactory);
   }
 
@@ -473,6 +478,7 @@
 
   @androidx.compose.runtime.Stable public abstract class ProvidableCompositionLocal<T> extends androidx.compose.runtime.CompositionLocal<T> {
     method public final infix androidx.compose.runtime.ProvidedValue<T> provides(T value);
+    method public final infix androidx.compose.runtime.ProvidedValue<T> providesComputed(kotlin.jvm.functions.Function1<? super androidx.compose.runtime.CompositionLocalAccessorScope,? extends T> compute);
     method public final infix androidx.compose.runtime.ProvidedValue<T> providesDefault(T value);
   }
 
diff --git a/compose/runtime/runtime/api/restricted_current.txt b/compose/runtime/runtime/api/restricted_current.txt
index 5240627..ee4de2d 100644
--- a/compose/runtime/runtime/api/restricted_current.txt
+++ b/compose/runtime/runtime/api/restricted_current.txt
@@ -245,6 +245,10 @@
     property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final inline T current;
   }
 
+  public interface CompositionLocalAccessorScope {
+    method public <T> T getCurrentValue(androidx.compose.runtime.CompositionLocal<T>);
+  }
+
   @androidx.compose.runtime.Stable public final class CompositionLocalContext {
   }
 
@@ -253,6 +257,7 @@
     method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonSkippableComposable public static void CompositionLocalProvider(androidx.compose.runtime.ProvidedValue<?> value, kotlin.jvm.functions.Function0<kotlin.Unit> content);
     method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonSkippableComposable public static void CompositionLocalProvider(androidx.compose.runtime.ProvidedValue<?>[] values, kotlin.jvm.functions.Function0<kotlin.Unit> content);
     method public static <T> androidx.compose.runtime.ProvidableCompositionLocal<T> compositionLocalOf(optional androidx.compose.runtime.SnapshotMutationPolicy<T> policy, kotlin.jvm.functions.Function0<? extends T> defaultFactory);
+    method public static <T> androidx.compose.runtime.ProvidableCompositionLocal<T> compositionLocalWithComputedDefaultOf(kotlin.jvm.functions.Function1<? super androidx.compose.runtime.CompositionLocalAccessorScope,? extends T> defaultComputation);
     method public static <T> androidx.compose.runtime.ProvidableCompositionLocal<T> staticCompositionLocalOf(kotlin.jvm.functions.Function0<? extends T> defaultFactory);
   }
 
@@ -501,6 +506,7 @@
 
   @androidx.compose.runtime.Stable public abstract class ProvidableCompositionLocal<T> extends androidx.compose.runtime.CompositionLocal<T> {
     method public final infix androidx.compose.runtime.ProvidedValue<T> provides(T value);
+    method public final infix androidx.compose.runtime.ProvidedValue<T> providesComputed(kotlin.jvm.functions.Function1<? super androidx.compose.runtime.CompositionLocalAccessorScope,? extends T> compute);
     method public final infix androidx.compose.runtime.ProvidedValue<T> providesDefault(T value);
   }
 
diff --git a/compose/runtime/runtime/samples/src/main/java/androidx/compose/runtime/samples/CompositionLocalSamples.kt b/compose/runtime/runtime/samples/src/main/java/androidx/compose/runtime/samples/CompositionLocalSamples.kt
index 5369df3..06e3907 100644
--- a/compose/runtime/runtime/samples/src/main/java/androidx/compose/runtime/samples/CompositionLocalSamples.kt
+++ b/compose/runtime/runtime/samples/src/main/java/androidx/compose/runtime/samples/CompositionLocalSamples.kt
@@ -22,6 +22,7 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.CompositionLocalProvider
 import androidx.compose.runtime.compositionLocalOf
+import androidx.compose.runtime.compositionLocalWithComputedDefaultOf
 
 @Sampled
 fun createCompositionLocal() {
@@ -39,6 +40,31 @@
 }
 
 @Sampled
+fun compositionLocalComputedByDefault() {
+    val LocalBaseValue = compositionLocalOf { 10 }
+    val LocalLargerValue = compositionLocalWithComputedDefaultOf {
+        LocalBaseValue.currentValue + 10
+    }
+}
+
+@Sampled
+fun compositionLocalProvidedComputed() {
+    val LocalValue = compositionLocalOf { 10 }
+    val LocalLargerValue = compositionLocalOf { 12 }
+
+    @Composable
+    fun App() {
+        CompositionLocalProvider(
+            LocalLargerValue providesComputed {
+                LocalValue.currentValue + 10
+            }
+        ) {
+            SomeScreen()
+        }
+    }
+}
+
+@Sampled
 fun someScreenSample() {
     @Composable
     fun SomeScreen() {
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composer.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composer.kt
index d21e787..d11df0e 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composer.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composer.kt
@@ -305,14 +305,61 @@
 
 /**
  * An instance to hold a value provided by [CompositionLocalProvider] and is created by the
- * [ProvidableCompositionLocal.provides] infixed operator. If [canOverride] is `false`, the
+ * [ProvidableCompositionLocal.provides] infix operator. If [canOverride] is `false`, the
  * provided value will not overwrite a potentially already existing value in the scope.
+ *
+ * This value cannot be created directly. It can only be created by using one of the `provides`
+ * operators of [ProvidableCompositionLocal].
+ *
+ * @see ProvidableCompositionLocal.provides
+ * @see ProvidableCompositionLocal.providesDefault
+ * @see ProvidableCompositionLocal.providesComputed
  */
 class ProvidedValue<T> internal constructor(
+    /**
+     * The composition local that is provided by this value. This is the left-hand side of the
+     * [ProvidableCompositionLocal.provides] infix operator.
+     */
     val compositionLocal: CompositionLocal<T>,
-    val value: T,
-    val canOverride: Boolean
-)
+    value: T?,
+    private val explicitNull: Boolean,
+    internal val mutationPolicy: SnapshotMutationPolicy<T>?,
+    internal val state: MutableState<T>?,
+    internal val compute: (CompositionLocalAccessorScope.() -> T)?,
+    internal val isDynamic: Boolean
+) {
+    private val providedValue: T? = value
+
+    /**
+     * The value provided by the [ProvidableCompositionLocal.provides] infix operator. This is the
+     * right-hand side of the operator.
+     */
+    @Suppress("UNCHECKED_CAST")
+    val value: T get() = providedValue as T
+
+    /**
+     * This value is `true` if the provided value will override any value provided above it. This
+     * value is `true` when using [ProvidableCompositionLocal.provides] but `false` when using
+     * [ProvidableCompositionLocal.providesDefault].
+     *
+     * @see ProvidableCompositionLocal.provides
+     * @see ProvidableCompositionLocal.providesDefault
+     */
+    @get:JvmName("getCanOverride")
+    var canOverride: Boolean = true
+        private set
+    @Suppress("UNCHECKED_CAST")
+    internal val effectiveValue: T
+        get() = when {
+            explicitNull -> null as T
+            state != null -> state.value
+            providedValue != null -> providedValue
+            else -> composeRuntimeError("Unexpected form of a provided value")
+        }
+    internal val isStatic get() = (explicitNull || value != null) && !isDynamic
+
+    internal fun ifNotAlreadyProvided() = this.also { canOverride = false }
+}
 
 /**
  * A Compose compiler plugin API. DO NOT call directly.
@@ -2127,9 +2174,15 @@
                 writer.anchor(group)
             } else null
         } else {
-            if (reader.isAfterFirstChild)
-                reader.anchor(reader.currentGroup - 1)
-            else null
+            if (reader.isAfterFirstChild) {
+                var group = reader.currentGroup - 1
+                var parent = reader.parent(group)
+                while (parent != reader.parent && parent >= 0) {
+                    group = parent
+                    parent = reader.parent(group)
+                }
+                reader.anchor(group)
+            } else null
         }
 
     override val compositionData: CompositionData get() = slotTable
@@ -2208,10 +2261,10 @@
         startGroup(providerKey, provider)
         val oldState = rememberedValue().let {
             if (it == Composer.Empty) null
-            else it as State<Any?>
+            else it as ValueHolder<Any?>
         }
         val local = value.compositionLocal as CompositionLocal<Any?>
-        val state = local.updatedStateOf(value.value, oldState)
+        val state = local.updatedStateOf(value as ProvidedValue<Any?>, oldState)
         val change = state != oldState
         if (change) {
             updateRememberedValue(state)
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/CompositionLocal.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/CompositionLocal.kt
index 4f9cf8c..4af9eb7 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/CompositionLocal.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/CompositionLocal.kt
@@ -56,10 +56,13 @@
  * @sample androidx.compose.runtime.samples.consumeCompositionLocal
  */
 @Stable
-sealed class CompositionLocal<T> constructor(defaultFactory: () -> T) {
-    internal val defaultValueHolder = LazyValueHolder(defaultFactory)
+sealed class CompositionLocal<T>(defaultFactory: () -> T) {
+    internal open val defaultValueHolder: ValueHolder<T> = LazyValueHolder(defaultFactory)
 
-    internal abstract fun updatedStateOf(value: T, previous: State<T>?): State<T>
+    internal abstract fun updatedStateOf(
+        value: ProvidedValue<T>,
+        previous: ValueHolder<T>?
+    ): ValueHolder<T>
 
     /**
      * Return the value provided by the nearest [CompositionLocalProvider] component that invokes, directly or
@@ -85,6 +88,7 @@
 @Stable
 abstract class ProvidableCompositionLocal<T> internal constructor(defaultFactory: () -> T) :
     CompositionLocal<T> (defaultFactory) {
+    internal abstract fun defaultProvidedValue(value: T): ProvidedValue<T>
 
     /**
      * Associates a [CompositionLocal] key to a value in a call to [CompositionLocalProvider].
@@ -92,16 +96,76 @@
      * @see CompositionLocal
      * @see ProvidableCompositionLocal
      */
-    infix fun provides(value: T) = ProvidedValue(this, value, true)
+    infix fun provides(value: T) = defaultProvidedValue(value)
 
     /**
-     * Associates a [CompositionLocal] key to a value in a call to [CompositionLocalProvider] if the key does not
-     * already have an associated value.
+     * Associates a [CompositionLocal] key to a value in a call to [CompositionLocalProvider] if the
+     * key does not already have an associated value.
      *
      * @see CompositionLocal
      * @see ProvidableCompositionLocal
      */
-    infix fun providesDefault(value: T) = ProvidedValue(this, value, false)
+    infix fun providesDefault(value: T) = defaultProvidedValue(value).ifNotAlreadyProvided()
+
+    /**
+     * Associates a [CompositionLocal] key to a lambda, [compute], in a call to [CompositionLocal].
+     * The [compute] lambda is invoked whenever the key is retrieved. The lambda is executed in
+     * the context of a [CompositionLocalContext] which allow retrieving the current values of
+     * other composition locals by calling [CompositionLocalAccessorScope.currentValue], which is an
+     * extension function provided by the context for a [CompositionLocal] key.
+     *
+     * @sample androidx.compose.runtime.samples.compositionLocalProvidedComputed
+     *
+     * @see CompositionLocal
+     * @see CompositionLocalContext
+     * @see ProvidableCompositionLocal
+     */
+    infix fun providesComputed(compute: CompositionLocalAccessorScope.() -> T) =
+        ProvidedValue(
+            compositionLocal = this,
+            value = null,
+            explicitNull = false,
+            mutationPolicy = null,
+            state = null,
+            compute = compute,
+            isDynamic = false
+        )
+
+    override fun updatedStateOf(
+        value: ProvidedValue<T>,
+        previous: ValueHolder<T>?
+    ): ValueHolder<T> {
+        return when (previous) {
+            is DynamicValueHolder ->
+                if (value.isDynamic) {
+                    previous.state.value = value.effectiveValue
+                    previous
+                } else null
+            is StaticValueHolder ->
+                if (value.isStatic && value.effectiveValue == previous.value)
+                    previous
+                else null
+            is ComputedValueHolder ->
+                if (value.compute == previous.compute)
+                    previous
+                else null
+            else -> null
+        } ?: valueHolderOf(value)
+    }
+
+    private fun valueHolderOf(value: ProvidedValue<T>): ValueHolder<T> =
+        when {
+            value.isDynamic ->
+                DynamicValueHolder(
+                    value.state
+                        ?: mutableStateOf(value.value, value.mutationPolicy
+                            ?: structuralEqualityPolicy()
+                        )
+                )
+            value.compute != null -> ComputedValueHolder(value.compute)
+            value.state != null -> DynamicValueHolder(value.state)
+            else -> StaticValueHolder(value.effectiveValue)
+        }
 }
 
 /**
@@ -113,18 +177,21 @@
  *
  * @see compositionLocalOf
  */
-internal class DynamicProvidableCompositionLocal<T> constructor(
+internal class DynamicProvidableCompositionLocal<T>(
     private val policy: SnapshotMutationPolicy<T>,
     defaultFactory: () -> T
 ) : ProvidableCompositionLocal<T>(defaultFactory) {
 
-    override fun updatedStateOf(value: T, previous: State<T>?): State<T> =
-        if (previous != null && previous is MutableState<T>) {
-            previous.value = value
-            previous
-        } else {
-            mutableStateOf(value, policy)
-        }
+    override fun defaultProvidedValue(value: T) =
+        ProvidedValue(
+            compositionLocal = this,
+            value = value,
+            explicitNull = value === null,
+            mutationPolicy = policy,
+            state = null,
+            compute = null,
+            isDynamic = true
+        )
 }
 
 /**
@@ -135,9 +202,16 @@
 internal class StaticProvidableCompositionLocal<T>(defaultFactory: () -> T) :
     ProvidableCompositionLocal<T>(defaultFactory) {
 
-    override fun updatedStateOf(value: T, previous: State<T>?): State<T> =
-        if (previous != null && previous.value == value) previous
-        else StaticValueHolder(value)
+    override fun defaultProvidedValue(value: T) =
+        ProvidedValue(
+            compositionLocal = this,
+            value = value,
+            explicitNull = value === null,
+            mutationPolicy = null,
+            state = null,
+            compute = null,
+            isDynamic = false
+        )
 }
 
 /**
@@ -197,6 +271,65 @@
     StaticProvidableCompositionLocal(defaultFactory)
 
 /**
+ * Create a [CompositionLocal] that behaves like it was provided using
+ * [ProvidableCompositionLocal.providesComputed] by default. If a value is provided using
+ * [ProvidableCompositionLocal.provides] it behaves as if the [CompositionLocal] was produced
+ * by calling [compositionLocalOf].
+ *
+ * In other words, a [CompositionLocal] produced by can be provided identically to
+ * [CompositionLocal] created with  [compositionLocalOf] with the only difference is how it behaves
+ * when the value is not provided. For a [compositionLocalOf] the default value is returned. If no
+ * default value has be computed for [CompositionLocal] the default computation is called.
+ *
+ * @sample androidx.compose.runtime.samples.compositionLocalComputedByDefault
+ *
+ * @param defaultComputation the default computation to use when this [CompositionLocal] is not
+ * provided.
+ *
+ * @see CompositionLocal
+ * @see ProvidableCompositionLocal
+ */
+fun <T> compositionLocalWithComputedDefaultOf(
+    defaultComputation: CompositionLocalAccessorScope.() -> T
+): ProvidableCompositionLocal<T> =
+    ComputedProvidableCompositionLocal(defaultComputation)
+
+internal class ComputedProvidableCompositionLocal<T>(
+    defaultComputation: CompositionLocalAccessorScope.() -> T
+) : ProvidableCompositionLocal<T>({ composeRuntimeError("Unexpected call to default provider") }) {
+    override val defaultValueHolder = ComputedValueHolder(defaultComputation)
+
+    override fun defaultProvidedValue(value: T): ProvidedValue<T> =
+        ProvidedValue(
+            compositionLocal = this,
+            value = value,
+            explicitNull = value === null,
+            mutationPolicy = null,
+            state = null,
+            compute = null,
+            isDynamic = true
+        )
+}
+
+interface CompositionLocalAccessorScope {
+    /**
+     * An extension property that allows accessing the current value of a composition local in
+     * the context of this scope. This scope is the type of the `this` parameter when in a
+     * computed composition. Computed composition locals can be provided by either using
+     * [compositionLocalWithComputedDefaultOf] or by using the
+     * [ProvidableCompositionLocal.providesComputed] infix operator.
+     *
+     * @sample androidx.compose.runtime.samples.compositionLocalProvidedComputed
+     *
+     * @see ProvidableCompositionLocal
+     * @see ProvidableCompositionLocal.providesComputed
+     * @see ProvidableCompositionLocal.provides
+     * @see CompositionLocalProvider
+     */
+    val <T> CompositionLocal<T>.currentValue: T
+}
+
+/**
  * Stores [CompositionLocal]'s and their values.
  *
  * Can be obtained via [currentCompositionLocalContext] and passed to another composition
@@ -266,9 +399,7 @@
 @Composable
 fun CompositionLocalProvider(context: CompositionLocalContext, content: @Composable () -> Unit) {
     CompositionLocalProvider(
-        *context.compositionLocals
-            .map { it.key as ProvidableCompositionLocal<Any?> provides it.value.value }
-            .toTypedArray(),
+        *context.compositionLocals.map { it.value.toProvided(it.key) }.toTypedArray(),
         content = content
     )
 }
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/CompositionLocalMap.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/CompositionLocalMap.kt
index a34bc3a..45e4540 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/CompositionLocalMap.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/CompositionLocalMap.kt
@@ -54,10 +54,17 @@
  * [CompositionLocal]s.
  */
 internal interface PersistentCompositionLocalMap :
-    PersistentMap<CompositionLocal<Any?>, State<Any?>>,
-    CompositionLocalMap {
+    PersistentMap<CompositionLocal<Any?>, ValueHolder<Any?>>,
+    CompositionLocalMap,
+    CompositionLocalAccessorScope {
 
-    fun putValue(key: CompositionLocal<Any?>, value: State<Any?>): PersistentCompositionLocalMap
+    fun putValue(
+        key: CompositionLocal<Any?>,
+        value: ValueHolder<Any?>
+    ): PersistentCompositionLocalMap
+
+    override val <T> CompositionLocal<T>.currentValue: T
+        get() = read(this)
 
     // Override the builder APIs so that we can create new PersistentMaps that retain the type
     // information of PersistentCompositionLocalMap. If we use the built-in implementation, we'll
@@ -65,13 +72,13 @@
     // PersistentCompositionLocalMap
     override fun builder(): Builder
 
-    interface Builder : PersistentMap.Builder<CompositionLocal<Any?>, State<Any?>> {
+    interface Builder : PersistentMap.Builder<CompositionLocal<Any?>, ValueHolder<Any?>> {
         override fun build(): PersistentCompositionLocalMap
     }
 }
 
 internal inline fun PersistentCompositionLocalMap.mutate(
-    mutator: (MutableMap<CompositionLocal<Any?>, State<Any?>>) -> Unit
+    mutator: (MutableMap<CompositionLocal<Any?>, ValueHolder<Any?>>) -> Unit
 ): PersistentCompositionLocalMap = builder().apply(mutator).build()
 
 @Suppress("UNCHECKED_CAST")
@@ -81,7 +88,7 @@
 @Suppress("UNCHECKED_CAST")
 internal fun <T> PersistentCompositionLocalMap.read(
     key: CompositionLocal<T>
-): T = getOrElse(key as CompositionLocal<Any?>) { key.defaultValueHolder }.value as T
+): T = getOrElse(key as CompositionLocal<Any?>) { key.defaultValueHolder }.readValue(this) as T
 
 internal fun updateCompositionMap(
     values: Array<out ProvidedValue<*>>,
@@ -90,14 +97,14 @@
 ): PersistentCompositionLocalMap {
     val builder: PersistentCompositionLocalMap.Builder =
         persistentCompositionLocalHashMapOf().builder()
-    val map: PersistentMap<CompositionLocal<Any?>, State<Any?>> = previous
+    val map: PersistentMap<CompositionLocal<Any?>, ValueHolder<Any?>> = previous
     @Suppress("UNCHECKED_CAST")
     for (index in values.indices) {
         val provided = values[index]
         val local = provided.compositionLocal as ProvidableCompositionLocal<Any?>
         if (provided.canOverride || !parentScope.contains(local)) {
             val previousState = map[local]
-            val newState = local.updatedStateOf(provided.value, previousState)
+            val newState = local.updatedStateOf(provided as ProvidedValue<Any?>, previousState)
             builder[local] = newState
         }
     }
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/ValueHolders.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/ValueHolders.kt
index 0c7d125..fa3eca0 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/ValueHolders.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/ValueHolders.kt
@@ -16,17 +16,67 @@
 
 package androidx.compose.runtime
 
+internal interface ValueHolder<T> {
+    fun readValue(map: PersistentCompositionLocalMap): T
+    fun toProvided(local: CompositionLocal<T>): ProvidedValue<T>
+}
+
 /**
  * A StaticValueHolder holds a value that will never change.
  */
-internal data class StaticValueHolder<T>(override val value: T) : State<T>
+internal data class StaticValueHolder<T>(val value: T) : ValueHolder<T> {
+    override fun readValue(map: PersistentCompositionLocalMap): T = value
+    override fun toProvided(local: CompositionLocal<T>): ProvidedValue<T> =
+        ProvidedValue(
+            compositionLocal = local,
+            value = value,
+            explicitNull = value === null,
+            mutationPolicy = null,
+            state = null,
+            compute = null,
+            isDynamic = false
+        )
+}
 
 /**
  * A lazy value holder is static value holder for which the value is produced by the valueProducer
  * parameter which is called once and the result is remembered for the life of LazyValueHolder.
  */
-internal class LazyValueHolder<T>(valueProducer: () -> T) : State<T> {
+internal class LazyValueHolder<T>(valueProducer: () -> T) : ValueHolder<T> {
     private val current by lazy(valueProducer)
 
-    override val value: T get() = current
+    override fun readValue(map: PersistentCompositionLocalMap): T = current
+    override fun toProvided(local: CompositionLocal<T>): ProvidedValue<T> =
+        composeRuntimeError("Cannot produce a provider from a lazy value holder")
+}
+
+internal data class ComputedValueHolder<T>(
+    val compute: CompositionLocalAccessorScope.() -> T
+) : ValueHolder<T> {
+    override fun readValue(map: PersistentCompositionLocalMap): T =
+        map.compute()
+    override fun toProvided(local: CompositionLocal<T>): ProvidedValue<T> =
+        ProvidedValue(
+            compositionLocal = local,
+            value = null,
+            explicitNull = false,
+            mutationPolicy = null,
+            state = null,
+            compute = compute,
+            isDynamic = false
+        )
+}
+
+internal data class DynamicValueHolder<T>(val state: MutableState<T>) : ValueHolder<T> {
+    override fun readValue(map: PersistentCompositionLocalMap): T = state.value
+    override fun toProvided(local: CompositionLocal<T>): ProvidedValue<T> =
+        ProvidedValue(
+            compositionLocal = local,
+            value = null,
+            explicitNull = false,
+            mutationPolicy = null,
+            state = state,
+            compute = null,
+            isDynamic = true
+        )
 }
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/internal/PersistentCompositionLocalMap.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/internal/PersistentCompositionLocalMap.kt
index cac2470..c0c60e6 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/internal/PersistentCompositionLocalMap.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/internal/PersistentCompositionLocalMap.kt
@@ -18,7 +18,7 @@
 
 import androidx.compose.runtime.CompositionLocal
 import androidx.compose.runtime.PersistentCompositionLocalMap
-import androidx.compose.runtime.State
+import androidx.compose.runtime.ValueHolder
 import androidx.compose.runtime.external.kotlinx.collections.immutable.ImmutableSet
 import androidx.compose.runtime.external.kotlinx.collections.immutable.implementations.immutableMap.PersistentHashMap
 import androidx.compose.runtime.external.kotlinx.collections.immutable.implementations.immutableMap.PersistentHashMapBuilder
@@ -28,19 +28,19 @@
 import androidx.compose.runtime.read
 
 internal class PersistentCompositionLocalHashMap(
-    node: TrieNode<CompositionLocal<Any?>, State<Any?>>,
+    node: TrieNode<CompositionLocal<Any?>, ValueHolder<Any?>>,
     size: Int
-) : PersistentHashMap<CompositionLocal<Any?>, State<Any?>>(node, size),
+) : PersistentHashMap<CompositionLocal<Any?>, ValueHolder<Any?>>(node, size),
     PersistentCompositionLocalMap {
 
-    override val entries: ImmutableSet<Map.Entry<CompositionLocal<Any?>, State<Any?>>>
+    override val entries: ImmutableSet<Map.Entry<CompositionLocal<Any?>, ValueHolder<Any?>>>
         get() = super.entries
 
     override fun <T> get(key: CompositionLocal<T>): T = read(key)
 
     override fun putValue(
         key: CompositionLocal<Any?>,
-        value: State<Any?>
+        value: ValueHolder<Any?>
     ): PersistentCompositionLocalMap {
         val newNodeResult = node.put(key.hashCode(), key, value, 0) ?: return this
         return PersistentCompositionLocalHashMap(
@@ -55,7 +55,7 @@
 
     class Builder(
         internal var map: PersistentCompositionLocalHashMap
-    ) : PersistentHashMapBuilder<CompositionLocal<Any?>, State<Any?>>(map),
+    ) : PersistentHashMapBuilder<CompositionLocal<Any?>, ValueHolder<Any?>>(map),
         PersistentCompositionLocalMap.Builder {
         override fun build(): PersistentCompositionLocalHashMap {
             map = if (node === map.node) {
@@ -71,7 +71,7 @@
     companion object {
         @Suppress("UNCHECKED_CAST")
         val Empty = PersistentCompositionLocalHashMap(
-            node = TrieNode.EMPTY as TrieNode<CompositionLocal<Any?>, State<Any?>>,
+            node = TrieNode.EMPTY as TrieNode<CompositionLocal<Any?>, ValueHolder<Any?>>,
             size = 0
         )
     }
@@ -80,5 +80,5 @@
 internal fun persistentCompositionLocalHashMapOf() = PersistentCompositionLocalHashMap.Empty
 
 internal fun persistentCompositionLocalHashMapOf(
-    vararg pairs: Pair<CompositionLocal<Any?>, State<Any?>>
+    vararg pairs: Pair<CompositionLocal<Any?>, ValueHolder<Any?>>
 ): PersistentCompositionLocalMap = PersistentCompositionLocalHashMap.Empty.mutate { it += pairs }
diff --git a/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/CompositionLocalTests.kt b/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/CompositionLocalTests.kt
index ddfcc02..3e4c0db 100644
--- a/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/CompositionLocalTests.kt
+++ b/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/CompositionLocalTests.kt
@@ -714,6 +714,66 @@
             }
         }
     }
+
+    @Test
+    fun testDefaultComputedLocal() = compositionTest {
+        val local1 = compositionLocalOf { 0 }
+        val local2 = compositionLocalWithComputedDefaultOf { local1.currentValue + 10 }
+        compose {
+            val valueOfLocal1 = local1.current
+            val valueOfLocal2 = local2.current
+            assertEquals(valueOfLocal1 + 10, valueOfLocal2)
+            CompositionLocalProvider(local1 provides 20) {
+                val nestedValueOfLocal1 = local1.current
+                val nestedValueOfLocal2 = local2.current
+                assertEquals(nestedValueOfLocal1 + 10, nestedValueOfLocal2)
+            }
+        }
+    }
+
+    @Test
+    fun testProvidingDynamicLocalAsComputed() = compositionTest {
+        val local1 = compositionLocalOf { 0 }
+        val local2 = compositionLocalOf { 0 }
+        compose {
+            val valueOfLocal1A = local1.current
+            val valueOfLocal2A = local2.current
+            assertEquals(0, valueOfLocal1A)
+            assertEquals(0, valueOfLocal2A)
+            CompositionLocalProvider(local2 providesComputed { local1.currentValue + 10 }) {
+                val valueOfLocal1B = local1.current
+                val valueOfLocal2B = local2.current
+                assertEquals(valueOfLocal1B + 10, valueOfLocal2B)
+                CompositionLocalProvider(local1 provides 10) {
+                    val valueOfLocal1C = local1.current
+                    val valueOfLocal2C = local2.current
+                    assertEquals(valueOfLocal1C + 10, valueOfLocal2C)
+                }
+            }
+        }
+    }
+
+    @Test
+    fun testProvidingAStaticLocalAsComputed() = compositionTest {
+        val local1 = staticCompositionLocalOf { 0 }
+        val local2 = staticCompositionLocalOf { 0 }
+        compose {
+            val valueOfLocal1A = local1.current
+            val valueOfLocal2A = local2.current
+            assertEquals(0, valueOfLocal1A)
+            assertEquals(0, valueOfLocal2A)
+            CompositionLocalProvider(local2 providesComputed { local1.currentValue + 10 }) {
+                val valueOfLocal1B = local1.current
+                val valueOfLocal2B = local2.current
+                assertEquals(valueOfLocal1B + 10, valueOfLocal2B)
+                CompositionLocalProvider(local1 provides 10) {
+                    val valueOfLocal1C = local1.current
+                    val valueOfLocal2C = local2.current
+                    assertEquals(valueOfLocal1C + 10, valueOfLocal2C)
+                }
+            }
+        }
+    }
 }
 
 val cacheLocal = staticCompositionLocalOf { "Unset" }
diff --git a/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/MovableContentTests.kt b/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/MovableContentTests.kt
index 7f0a6d3..00ca17b 100644
--- a/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/MovableContentTests.kt
+++ b/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/MovableContentTests.kt
@@ -1592,6 +1592,34 @@
 
         revalidate()
     }
+
+    @Test
+    fun movableContent_rememberOrdering() = compositionTest {
+        val movableContent1 = movableContentOf {
+            repeat(100) {
+                Text("Some content")
+            }
+        }
+        var includeContent by mutableStateOf(true)
+        var rememberKey by mutableStateOf(0)
+
+        compose {
+            if (includeContent) {
+                movableContent1()
+            }
+            val a = remember(rememberKey) {
+                SimpleRememberedObject("Key $rememberKey")
+            }
+            Text(a.name)
+        }
+
+        rememberKey++
+        expectChanges()
+
+        includeContent = false
+        rememberKey++
+        expectChanges()
+    }
 }
 
 @Composable
@@ -1756,3 +1784,14 @@
         if (count == 0) died = true
     }
 }
+
+class SimpleRememberedObject(val name: String) : RememberObserver {
+    override fun onRemembered() {
+    }
+
+    override fun onForgotten() {
+    }
+
+    override fun onAbandoned() {
+    }
+}
diff --git a/compose/ui/ui-graphics/api/current.txt b/compose/ui/ui-graphics/api/current.txt
index db1a98b..2e7e6e7e 100644
--- a/compose/ui/ui-graphics/api/current.txt
+++ b/compose/ui/ui-graphics/api/current.txt
@@ -1293,7 +1293,6 @@
   }
 
   @androidx.compose.ui.graphics.drawscope.DrawScopeMarker @kotlin.jvm.JvmDefaultWithCompatibility public interface DrawScope extends androidx.compose.ui.unit.Density {
-    method public default androidx.compose.ui.graphics.layer.GraphicsLayer buildLayer(androidx.compose.ui.graphics.layer.GraphicsLayer, optional long size, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
     method public void drawArc(androidx.compose.ui.graphics.Brush brush, float startAngle, float sweepAngle, boolean useCenter, optional long topLeft, optional long size, optional @FloatRange(from=0.0, to=1.0) float alpha, optional androidx.compose.ui.graphics.drawscope.DrawStyle style, optional androidx.compose.ui.graphics.ColorFilter? colorFilter, optional int blendMode);
     method public void drawArc(long color, float startAngle, float sweepAngle, boolean useCenter, optional long topLeft, optional long size, optional @FloatRange(from=0.0, to=1.0) float alpha, optional androidx.compose.ui.graphics.drawscope.DrawStyle style, optional androidx.compose.ui.graphics.ColorFilter? colorFilter, optional int blendMode);
     method public void drawCircle(androidx.compose.ui.graphics.Brush brush, optional float radius, optional long center, optional @FloatRange(from=0.0, to=1.0) float alpha, optional androidx.compose.ui.graphics.drawscope.DrawStyle style, optional androidx.compose.ui.graphics.ColorFilter? colorFilter, optional int blendMode);
@@ -1317,6 +1316,7 @@
     method public androidx.compose.ui.graphics.drawscope.DrawContext getDrawContext();
     method public androidx.compose.ui.unit.LayoutDirection getLayoutDirection();
     method public default long getSize();
+    method public default void record(androidx.compose.ui.graphics.layer.GraphicsLayer, optional long size, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
     property public default long center;
     property public abstract androidx.compose.ui.graphics.drawscope.DrawContext drawContext;
     property public abstract androidx.compose.ui.unit.LayoutDirection layoutDirection;
@@ -1421,7 +1421,6 @@
   }
 
   public final class GraphicsLayer {
-    method public androidx.compose.ui.graphics.layer.GraphicsLayer buildLayer(androidx.compose.ui.unit.Density density, androidx.compose.ui.unit.LayoutDirection layoutDirection, long size, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
     method public float getAlpha();
     method public long getAmbientShadowColor();
     method public int getBlendMode();
@@ -1446,6 +1445,7 @@
     method public float getTranslationX();
     method public float getTranslationY();
     method public boolean isReleased();
+    method public void record(androidx.compose.ui.unit.Density density, androidx.compose.ui.unit.LayoutDirection layoutDirection, long size, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
     method public void setAlpha(float);
     method public void setAmbientShadowColor(long);
     method public void setBlendMode(int);
diff --git a/compose/ui/ui-graphics/api/restricted_current.txt b/compose/ui/ui-graphics/api/restricted_current.txt
index c66b65d..5224391 100644
--- a/compose/ui/ui-graphics/api/restricted_current.txt
+++ b/compose/ui/ui-graphics/api/restricted_current.txt
@@ -1388,7 +1388,6 @@
   }
 
   @androidx.compose.ui.graphics.drawscope.DrawScopeMarker @kotlin.jvm.JvmDefaultWithCompatibility public interface DrawScope extends androidx.compose.ui.unit.Density {
-    method public default androidx.compose.ui.graphics.layer.GraphicsLayer buildLayer(androidx.compose.ui.graphics.layer.GraphicsLayer, optional long size, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
     method public void drawArc(androidx.compose.ui.graphics.Brush brush, float startAngle, float sweepAngle, boolean useCenter, optional long topLeft, optional long size, optional @FloatRange(from=0.0, to=1.0) float alpha, optional androidx.compose.ui.graphics.drawscope.DrawStyle style, optional androidx.compose.ui.graphics.ColorFilter? colorFilter, optional int blendMode);
     method public void drawArc(long color, float startAngle, float sweepAngle, boolean useCenter, optional long topLeft, optional long size, optional @FloatRange(from=0.0, to=1.0) float alpha, optional androidx.compose.ui.graphics.drawscope.DrawStyle style, optional androidx.compose.ui.graphics.ColorFilter? colorFilter, optional int blendMode);
     method public void drawCircle(androidx.compose.ui.graphics.Brush brush, optional float radius, optional long center, optional @FloatRange(from=0.0, to=1.0) float alpha, optional androidx.compose.ui.graphics.drawscope.DrawStyle style, optional androidx.compose.ui.graphics.ColorFilter? colorFilter, optional int blendMode);
@@ -1412,6 +1411,7 @@
     method public androidx.compose.ui.graphics.drawscope.DrawContext getDrawContext();
     method public androidx.compose.ui.unit.LayoutDirection getLayoutDirection();
     method public default long getSize();
+    method public default void record(androidx.compose.ui.graphics.layer.GraphicsLayer, optional long size, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
     property public default long center;
     property public abstract androidx.compose.ui.graphics.drawscope.DrawContext drawContext;
     property public abstract androidx.compose.ui.unit.LayoutDirection layoutDirection;
@@ -1516,7 +1516,6 @@
   }
 
   public final class GraphicsLayer {
-    method public androidx.compose.ui.graphics.layer.GraphicsLayer buildLayer(androidx.compose.ui.unit.Density density, androidx.compose.ui.unit.LayoutDirection layoutDirection, long size, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
     method public float getAlpha();
     method public long getAmbientShadowColor();
     method public int getBlendMode();
@@ -1541,6 +1540,7 @@
     method public float getTranslationX();
     method public float getTranslationY();
     method public boolean isReleased();
+    method public void record(androidx.compose.ui.unit.Density density, androidx.compose.ui.unit.LayoutDirection layoutDirection, long size, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
     method public void setAlpha(float);
     method public void setAmbientShadowColor(long);
     method public void setBlendMode(int);
diff --git a/compose/ui/ui-graphics/samples/src/main/java/androidx/compose/ui/graphics/samples/GraphicsLayerSamples.kt b/compose/ui/ui-graphics/samples/src/main/java/androidx/compose/ui/graphics/samples/GraphicsLayerSamples.kt
index 045723b..6f5be44 100644
--- a/compose/ui/ui-graphics/samples/src/main/java/androidx/compose/ui/graphics/samples/GraphicsLayerSamples.kt
+++ b/compose/ui/ui-graphics/samples/src/main/java/androidx/compose/ui/graphics/samples/GraphicsLayerSamples.kt
@@ -48,9 +48,10 @@
     // Build the layer with the density, layout direction and size from the DrawScope
     // and position the top left to be 20 pixels from the left and 30 pixels from the top.
     // This will the bounds of the layer with a red rectangle
-    layer.buildLayer {
-        drawRect(Color.Red)
-    }.apply {
+    layer.apply {
+        record {
+            drawRect(Color.Red)
+        }
         this.topLeft = IntOffset(20, 30)
     }
 
@@ -62,7 +63,7 @@
 fun DrawScope.GraphicsLayerSizeSample(layer: GraphicsLayer) {
     // Build the layer with the density, layout direction from the DrawScope that is
     // sized to 200 x 100 pixels and draw a red rectangle that occupies these bounds
-    layer.buildLayer(size = IntSize(200, 100)) {
+    layer.record(size = IntSize(200, 100)) {
         drawRect(Color.Red)
     }
 
@@ -74,12 +75,13 @@
 fun DrawScope.GraphicsLayerScaleAndPivotSample(layer: GraphicsLayer) {
     // Create a 200 x 200 pixel layer that has a red rectangle drawn in the lower right
     // corner.
-    layer.buildLayer(size = IntSize(200, 200)) {
-        drawRect(
-            Color.Red,
-            topLeft = Offset(size.width / 2f, size.height / 2f)
-        )
-    }.apply {
+    layer.apply {
+        record(size = IntSize(200, 200)) {
+            drawRect(
+                Color.Red,
+                topLeft = Offset(size.width / 2f, size.height / 2f)
+            )
+        }
         // Scale the layer by 1.5x in both the x and y axis relative to the bottom
         // right corner
         scaleX = 1.5f
@@ -97,9 +99,10 @@
 @Sampled
 fun DrawScope.GraphicsLayerTranslateSample(layer: GraphicsLayer) {
     // Create a 200 x 200 pixel layer that draws a red square
-    layer.buildLayer(size = IntSize(200, 200)) {
-        drawRect(Color.Red)
-    }.apply {
+    layer.apply {
+        record(size = IntSize(200, 200)) {
+            drawRect(Color.Red)
+        }
         // Configuring the translationX + Y will translate the red square
         // by 100 pixels to the right and 50 pixels from the top when drawn
         // into the destination DrawScope
@@ -114,9 +117,10 @@
 @Sampled
 fun DrawScope.GraphicsLayerShadowSample(layer: GraphicsLayer) {
     // Create a 200 x 200 pixel layer that draws a red square
-    layer.buildLayer(size = IntSize(200, 200)) {
-        drawRect(Color.Red)
-    }.apply {
+    layer.apply {
+        record(size = IntSize(200, 200)) {
+            drawRect(Color.Red)
+        }
         // Apply a shadow with specified colors that has an elevation of 20f when this layer is
         // drawn into the destination DrawScope.
         shadowElevation = 20f
@@ -142,9 +146,10 @@
 
     // Build the GraphicsLayer with the specified offset and size that is filled
     // with a red rectangle.
-    layer.buildLayer(size = layerSize) {
-        drawRect(Color.Red)
-    }.apply {
+    layer.apply {
+        record(size = layerSize) {
+            drawRect(Color.Red)
+        }
         this.topLeft = topLeft
         // Specify the Xor blend mode here so that layer contents will be shown in the
         // destination only if it is transparent, otherwise the destination would be cleared
@@ -170,9 +175,10 @@
 fun DrawScope.GraphicsLayerColorFilterSample(layer: GraphicsLayer) {
     // Create a layer with the same configuration as the destination DrawScope
     // and draw a red rectangle in the layer
-    layer.buildLayer {
-        drawRect(Color.Red)
-    }.apply {
+    layer.apply {
+        record {
+            drawRect(Color.Red)
+        }
         // Apply a ColorFilter that will tint the contents of the layer to blue
         // when it is drawn into the destination DrawScope
         colorFilter = ColorFilter.tint(Color.Blue)
@@ -186,11 +192,12 @@
 fun DrawScope.GraphicsLayerRenderEffectSample(layer: GraphicsLayer) {
     // Create a layer sized to the destination draw scope that is comprised
     // of an inset red rectangle
-    layer.buildLayer {
-        inset(20f, 20f) {
-            drawRect(Color.Red)
+    layer.apply {
+        record {
+            inset(20f, 20f) {
+                drawRect(Color.Red)
+            }
         }
-    }.apply {
         // Configure a blur to the contents of the layer that is applied
         // when drawn to the destination DrawScope
         renderEffect = BlurEffect(20f, 20f, TileMode.Decal)
@@ -203,11 +210,12 @@
 fun DrawScope.GraphicsLayerAlphaSample(layer: GraphicsLayer) {
     // Create a layer sized to the destination draw scope that is comprised
     // of an inset red rectangle
-    layer.buildLayer {
-        inset(20f, 20f) {
-            drawRect(Color.Red)
+    layer.apply {
+        record {
+            inset(20f, 20f) {
+                drawRect(Color.Red)
+            }
         }
-    }.apply {
         // Renders the content of the layer with 50% alpha when it is drawn
         // into the destination
         alpha = 0.5f
@@ -220,9 +228,10 @@
 fun DrawScope.GraphicsLayerOutlineSample(layer: GraphicsLayer) {
     // Create a layer sized to the destination draw scope that is comprised
     // of an inset red rectangle
-    layer.buildLayer {
-        drawRect(Color.Red)
-    }.apply {
+    layer.apply {
+        record {
+            drawRect(Color.Red)
+        }
         // Apply a shadow that is clipped to the specified round rect
         shadowElevation = 20f
         setRoundRectOutline(IntOffset.Zero, IntSize(300, 180), 30f)
@@ -235,9 +244,10 @@
 fun DrawScope.GraphicsLayerRoundRectOutline(layer: GraphicsLayer) {
     // Create a layer sized to the destination draw scope that is comprised
     // of an inset red rectangle
-    layer.buildLayer {
-        drawRect(Color.Red)
-    }.apply {
+    layer.apply {
+        record {
+            drawRect(Color.Red)
+        }
         // Apply a shadow and have the contents of the layer be clipped
         // to the size of the layer with a 20 pixel corner radius
         shadowElevation = 20f
@@ -251,9 +261,10 @@
 fun DrawScope.GraphicsLayerRectOutline(layer: GraphicsLayer) {
     // Create a layer sized to the destination draw scope that is comprised
     // of an inset red rectangle
-    layer.buildLayer {
-        drawRect(Color.Red)
-    }.apply {
+    layer.apply {
+        record {
+            drawRect(Color.Red)
+        }
         // Apply a shadow and have the contents of the layer be clipped
         // to the size of the layer with a 20 pixel corner radius
         shadowElevation = 20f
@@ -265,9 +276,10 @@
 
 @Sampled
 fun DrawScope.GraphicsLayerRotationX(layer: GraphicsLayer) {
-    layer.buildLayer {
-        drawRect(Color.Yellow)
-    }.apply {
+    layer.apply {
+        record {
+            drawRect(Color.Yellow)
+        }
         // Rotates the yellow rect 45f clockwise relative to the x axis
         rotationX = 45f
     }
@@ -277,9 +289,10 @@
 
 @Sampled
 fun DrawScope.GraphicsLayerRotationYWithCameraDistance(layer: GraphicsLayer) {
-    layer.buildLayer {
-        drawRect(Color.Yellow)
-    }.apply {
+    layer.apply {
+        record {
+            drawRect(Color.Yellow)
+        }
         // Rotates the yellow rect 45f clockwise relative to the y axis
         rotationY = 45f
         cameraDistance = 5.0f
@@ -291,7 +304,7 @@
 @OptIn(DelicateCoroutinesApi::class)
 @Sampled
 fun GraphicsLayerToImageBitmap(context: Context, layer: GraphicsLayer) {
-    layer.buildLayer(Density(1f), LayoutDirection.Ltr, IntSize(300, 200)) {
+    layer.record(Density(1f), LayoutDirection.Ltr, IntSize(300, 200)) {
         val half = Size(size.width / 2, size.height)
         drawRect(Color.Red, size = half)
         drawRect(Color.Blue, topLeft = Offset(size.width / 2f, 0f), size = half)
diff --git a/compose/ui/ui-graphics/src/androidInstrumentedTest/kotlin/androidx/compose/ui/graphics/layer/AndroidGraphicsLayerTest.kt b/compose/ui/ui-graphics/src/androidInstrumentedTest/kotlin/androidx/compose/ui/graphics/layer/AndroidGraphicsLayerTest.kt
index a5b0b00..0b9f951 100644
--- a/compose/ui/ui-graphics/src/androidInstrumentedTest/kotlin/androidx/compose/ui/graphics/layer/AndroidGraphicsLayerTest.kt
+++ b/compose/ui/ui-graphics/src/androidInstrumentedTest/kotlin/androidx/compose/ui/graphics/layer/AndroidGraphicsLayerTest.kt
@@ -144,7 +144,7 @@
             block = { graphicsContext ->
                 graphicsContext.createGraphicsLayer().apply {
                     assertEquals(IntSize.Zero, this.size)
-                    buildLayer {
+                    record {
                         drawRect(
                             Color.Red,
                             size = size / 2f
@@ -193,7 +193,7 @@
                 graphicsContext.createGraphicsLayer().apply {
                     graphicsLayer = this
                     assertEquals(IntSize.Zero, this.size)
-                    buildLayer {
+                    record {
                         drawRect(provider!!.color)
                     }
                 }
@@ -219,7 +219,7 @@
             block = { graphicsContext ->
                 layer = graphicsContext.createGraphicsLayer().apply {
                     assertEquals(IntSize.Zero, this.size)
-                    buildLayer {
+                    record {
                         drawRect(Color.Red)
                     }
                 }
@@ -234,11 +234,11 @@
     }
 
     @Test
-    fun testBuildLayerWithSize() {
+    fun testRecordLayerWithSize() {
         graphicsLayerTest(
             block = { graphicsContext ->
                 val layer = graphicsContext.createGraphicsLayer().apply {
-                    buildLayer(IntSize(TEST_WIDTH / 2, TEST_HEIGHT / 2)) {
+                    record(IntSize(TEST_WIDTH / 2, TEST_HEIGHT / 2)) {
                         drawRect(Color.Red)
                     }
                 }
@@ -251,17 +251,16 @@
     }
 
     @Test
-    fun testBuildLayerWithOffset() {
+    fun testRecordLayerWithOffset() {
         var layer: GraphicsLayer? = null
         val topLeft = IntOffset(TEST_WIDTH / 2, TEST_HEIGHT / 2)
         val size = IntSize(TEST_WIDTH, TEST_HEIGHT)
         graphicsLayerTest(
             block = { graphicsContext ->
                 layer = graphicsContext.createGraphicsLayer().apply {
-                    buildLayer {
+                    record {
                         drawRect(Color.Red)
                     }
-                }.apply {
                     this.topLeft = topLeft
                 }
                 drawLayer(layer!!)
@@ -282,7 +281,7 @@
         graphicsLayerTest(
             block = { graphicsContext ->
                 layer = graphicsContext.createGraphicsLayer().apply {
-                    buildLayer {
+                    record {
                         inset(0f, 0f, -4f, -4f) {
                             drawRect(Color.Red)
                         }
@@ -310,7 +309,7 @@
         graphicsLayerTest(
             block = { graphicsContext ->
                 layer = graphicsContext.createGraphicsLayer().apply {
-                    buildLayer {
+                    record {
                         drawRect(Color.Red)
                     }
                     alpha = 0.5f
@@ -339,7 +338,7 @@
         graphicsLayerTest(
             block = { graphicsContext ->
                 layer = graphicsContext.createGraphicsLayer().apply {
-                    buildLayer {
+                    record {
                         drawRect(
                             Color.Red,
                             size = Size(this.size.width / 2, this.size.height / 2)
@@ -366,7 +365,7 @@
         graphicsLayerTest(
             block = { graphicsContext ->
                 layer = graphicsContext.createGraphicsLayer().apply {
-                    buildLayer {
+                    record {
                         drawRect(
                             Color.Red,
                             size = Size(this.size.width / 2, this.size.height / 2)
@@ -393,7 +392,7 @@
         graphicsLayerTest(
             block = { graphicsContext ->
                 layer = graphicsContext.createGraphicsLayer().apply {
-                    buildLayer {
+                    record {
                         inset(this.size.width / 4, this.size.height / 4) {
                             drawRect(Color.Red)
                         }
@@ -419,7 +418,7 @@
         graphicsLayerTest(
             block = { graphicsContext ->
                 layer = graphicsContext.createGraphicsLayer().apply {
-                    buildLayer {
+                    record {
                         drawRect(Color.Red)
                     }
                     scaleY = 0.5f
@@ -444,7 +443,7 @@
         graphicsLayerTest(
             block = { graphicsContext ->
                 layer = graphicsContext.createGraphicsLayer().apply {
-                    buildLayer {
+                    record {
                         drawRect(Color.Red, size = this.size / 2f)
                     }
                     translationX = this.size.width / 2f
@@ -467,7 +466,7 @@
         graphicsLayerTest(
             block = { graphicsContext ->
                 layer = graphicsContext.createGraphicsLayer().apply {
-                    buildLayer {
+                    record {
                         drawRect(Color.Red, size = this.size / 2f)
                     }
                     translationY = this.size.height / 2f
@@ -490,7 +489,7 @@
         graphicsLayerTest(
             block = { graphicsContext ->
                 layer = graphicsContext.createGraphicsLayer().apply {
-                    buildLayer {
+                    record {
                         drawRect(
                             Color.Red,
                             size = Size(this.size.width, this.size.height / 2)
@@ -520,7 +519,7 @@
         graphicsLayerTest(
             block = { graphicsContext ->
                 layer = graphicsContext.createGraphicsLayer().apply {
-                    buildLayer {
+                    record {
                         drawRect(Color.Red)
                     }
                     pivotOffset = Offset(0f, this.size.height / 2f)
@@ -549,7 +548,7 @@
         graphicsLayerTest(
             block = { graphicsContext ->
                 layer = graphicsContext.createGraphicsLayer().apply {
-                    buildLayer {
+                    record {
                         drawRect(
                             Color.Red,
                             topLeft = Offset(
@@ -598,7 +597,7 @@
         graphicsLayerTest(
             block = { graphicsContext ->
                 layer = graphicsContext.createGraphicsLayer().apply {
-                    buildLayer {
+                    record {
                         drawRect(
                             Color.Red,
                             size = Size(100000f, 100000f)
@@ -625,7 +624,7 @@
         graphicsLayerTest(
             block = { graphicsContext ->
                 layer = graphicsContext.createGraphicsLayer().apply {
-                    buildLayer {
+                    record {
                         drawRect(
                             Color.Red,
                             size = Size(100000f, 100000f)
@@ -670,7 +669,7 @@
                 )
 
                 layer = graphicsContext.createGraphicsLayer().apply {
-                    buildLayer(halfSize) {
+                    record(halfSize) {
                         drawRect(targetColor)
                     }
                     shadowElevation = 10f
@@ -721,7 +720,7 @@
                 )
 
                 layer = graphicsContext.createGraphicsLayer().apply {
-                    buildLayer(halfSize) {
+                    record(halfSize) {
                         drawRect(targetColor)
                     }
                     setPathOutline(
@@ -790,7 +789,7 @@
                 bottom = top + halfSize.height
 
                 layer = graphicsContext.createGraphicsLayer().apply {
-                    buildLayer(halfSize) {
+                    record(halfSize) {
                         drawRect(targetColor)
                     }
                     setRoundRectOutline(IntOffset.Zero, halfSize, radius)
@@ -871,7 +870,7 @@
         graphicsLayerTest(
             block = { graphicsContext ->
                 layer = graphicsContext.createGraphicsLayer().apply {
-                    buildLayer {
+                    record {
                         drawRect(Color.Red)
                     }
                     renderEffect = BlurEffect(blurRadius, blurRadius, TileMode.Decal)
@@ -907,7 +906,7 @@
         graphicsLayerTest(
             block = { graphicsContext ->
                 layer = graphicsContext.createGraphicsLayer().apply {
-                    buildLayer {
+                    record {
                         inset(0f, 0f, size.width / 3, size.height / 3) {
                             drawRect(color = Color.Red)
                         }
@@ -945,7 +944,7 @@
         graphicsLayerTest(
             block = { graphicsContext ->
                 layer = graphicsContext.createGraphicsLayer().apply {
-                    buildLayer {
+                    record {
                         inset(0f, 0f, size.width / 3, size.height / 3) {
                             drawRect(color = Color.Red)
                         }
@@ -978,7 +977,7 @@
         graphicsLayerTest(
             block = { graphicsContext ->
                 layer = graphicsContext.createGraphicsLayer().apply {
-                    buildLayer {
+                    record {
                         inset(0f, 0f, size.width / 3, size.height / 3) {
                             drawRect(color = Color.Red)
                         }
@@ -1017,7 +1016,7 @@
         graphicsLayerTest(
             block = { graphicsContext ->
                 layer = graphicsContext.createGraphicsLayer().apply {
-                    buildLayer {
+                    record {
                         drawRect(Color.Red)
                     }
                     cameraDistance = 5.0f
@@ -1045,11 +1044,10 @@
         graphicsLayerTest(
             block = { graphicsContext ->
                 layer = graphicsContext.createGraphicsLayer().apply {
-                    buildLayer {
+                    record {
                         drawRect(Color.Red)
-                    }.apply {
-                        colorFilter = tint(Color.Blue)
                     }
+                    colorFilter = tint(Color.Blue)
                 }
                 drawLayer(layer!!)
             },
@@ -1080,12 +1078,11 @@
                         (drawScopeSize.width / 2).toInt(),
                         (drawScopeSize.height / 2).toInt()
                     )
-                    buildLayer(layerSize) {
+                    record(layerSize) {
                         drawRect(Color.Red)
-                    }.apply {
-                        this.topLeft = topLeft
-                        this.blendMode = BlendMode.Xor
                     }
+                    this.topLeft = topLeft
+                    this.blendMode = BlendMode.Xor
                 }
                 drawRect(Color.Green)
                 drawLayer(layer!!)
@@ -1128,7 +1125,7 @@
         graphicsLayerTest(
             block = { graphicsContext ->
                 layer = graphicsContext.createGraphicsLayer().apply {
-                    buildLayer {
+                    record {
                         drawRect(targetColor)
                     }
                     setRectOutline(this.size.center, this.size / 2)
@@ -1173,7 +1170,7 @@
         graphicsLayerTest(
             block = { graphicsContext ->
                 layer = graphicsContext.createGraphicsLayer().apply {
-                    buildLayer {
+                    record {
                         drawRect(targetColor)
                     }
                     setPathOutline(Path().apply {
@@ -1228,7 +1225,7 @@
         graphicsLayerTest(
             block = { graphicsContext ->
                 layer = graphicsContext.createGraphicsLayer().apply {
-                    buildLayer {
+                    record {
                         drawRect(targetColor)
                     }
                     setRoundRectOutline(
@@ -1367,9 +1364,9 @@
                 if (usePixelCopy && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                     verify(target.captureToImage().toPixelMap())
                 } else {
-                    val buildLayerLatch = CountDownLatch(1)
+                    val recordLatch = CountDownLatch(1)
                     testActivity!!.runOnUiThread {
-                        rootGraphicsLayer!!.buildLayer(
+                        rootGraphicsLayer!!.record(
                             density,
                             Ltr,
                             IntSize(target.width, target.height)
@@ -1378,9 +1375,9 @@
                                 target.draw(canvas.nativeCanvas)
                             }
                         }
-                        buildLayerLatch.countDown()
+                        recordLatch.countDown()
                     }
-                    assertTrue(buildLayerLatch.await(3000, TimeUnit.MILLISECONDS))
+                    assertTrue(recordLatch.await(3000, TimeUnit.MILLISECONDS))
                     val bitmap = runBlocking {
                         rootGraphicsLayer!!.toImageBitmap()
                     }
@@ -1406,7 +1403,7 @@
             var root = rootGraphicsLayer
             if (root == null) {
                 root = graphicsContext.createGraphicsLayer()
-                root.buildLayer(Density(1f, 1f), Ltr, IntSize(width.toInt(), height.toInt())) {
+                root.record(Density(1f, 1f), Ltr, IntSize(width.toInt(), height.toInt())) {
                     block(graphicsContext)
                 }
                 rootGraphicsLayer = root
diff --git a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/AndroidGraphicsContext.android.kt b/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/AndroidGraphicsContext.android.kt
index db290e9..5713996 100644
--- a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/AndroidGraphicsContext.android.kt
+++ b/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/AndroidGraphicsContext.android.kt
@@ -83,7 +83,7 @@
                     // actually doing a placeholder render before the activity is setup
                     // (ex in unit tests) causes the emulator to crash with an NPE in native code
                     // on the HWUI canvas implementation
-                    layer.buildLayer(
+                    layer.record(
                         DefaultDensity,
                         LayoutDirection.Ltr,
                         IntSize(1, 1),
diff --git a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/AndroidGraphicsLayer.android.kt b/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/AndroidGraphicsLayer.android.kt
index 2013787..033690d 100644
--- a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/AndroidGraphicsLayer.android.kt
+++ b/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/AndroidGraphicsLayer.android.kt
@@ -106,7 +106,7 @@
 
     /**
      * Offset in pixels where this [GraphicsLayer] will render within a provided canvas when
-     * [drawLayer] is called. This is configured by calling [buildLayer]
+     * [drawLayer] is called. This is configured by calling [record]
      *
      * @sample androidx.compose.ui.graphics.samples.GraphicsLayerTopLeftSample
      */
@@ -122,7 +122,7 @@
      * Size in pixels of the [GraphicsLayer]. By default [GraphicsLayer] contents can draw outside
      * of the bounds specified by [topLeft] and [size], however, rasterization of this layer into
      * an offscreen buffer will be sized according to the specified size. This is configured
-     * by calling [buildLayer]
+     * by calling [record]
      *
      * @sample androidx.compose.ui.graphics.samples.GraphicsLayerSizeSample
      */
@@ -397,12 +397,12 @@
      * @sample androidx.compose.ui.graphics.samples.GraphicsLayerBlendModeSample
      * @sample androidx.compose.ui.graphics.samples.GraphicsLayerTranslateSample
      */
-    actual fun buildLayer(
+    actual fun record(
         density: Density,
         layoutDirection: LayoutDirection,
         size: IntSize,
         block: DrawScope.() -> Unit
-    ): GraphicsLayer {
+    ) {
         if (this.size != size) {
             setPosition(topLeft, size)
             this.size = size
@@ -415,10 +415,8 @@
         childDependenciesTracker.withTracking(
             onDependencyRemoved = { it.onRemovedFromParentLayer() }
         ) {
-            impl.buildLayer(density, layoutDirection, this, drawBlock)
+            impl.record(density, layoutDirection, this, drawBlock)
         }
-
-        return this
     }
 
     private fun addSubLayer(graphicsLayer: GraphicsLayer) {
@@ -781,7 +779,7 @@
 
     /**
      * Create an [ImageBitmap] with the contents of this [GraphicsLayer] instance. Note that
-     * [GraphicsLayer.buildLayer] must be invoked first to record drawing operations before invoking
+     * [GraphicsLayer.record] must be invoked first to record drawing operations before invoking
      * this method.
      *
      * @sample androidx.compose.ui.graphics.samples.GraphicsLayerToImageBitmap
@@ -930,9 +928,9 @@
     fun draw(canvas: Canvas)
 
     /**
-     * @see GraphicsLayer.buildLayer
+     * @see GraphicsLayer.record
      */
-    fun buildLayer(
+    fun record(
         density: Density,
         layoutDirection: LayoutDirection,
         layer: GraphicsLayer,
diff --git a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/GraphicsLayerV23.android.kt b/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/GraphicsLayerV23.android.kt
index 9a9c22d..db4635e 100644
--- a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/GraphicsLayerV23.android.kt
+++ b/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/GraphicsLayerV23.android.kt
@@ -268,7 +268,7 @@
 
     override var isInvalidated: Boolean = true
 
-    override fun buildLayer(
+    override fun record(
         density: Density,
         layoutDirection: LayoutDirection,
         layer: GraphicsLayer,
diff --git a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/GraphicsLayerV29.android.kt b/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/GraphicsLayerV29.android.kt
index 7a97b5c..1c62892 100644
--- a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/GraphicsLayerV29.android.kt
+++ b/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/GraphicsLayerV29.android.kt
@@ -208,7 +208,7 @@
 
     override var isInvalidated: Boolean = true
 
-    override fun buildLayer(
+    override fun record(
         density: Density,
         layoutDirection: LayoutDirection,
         layer: GraphicsLayer,
diff --git a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/GraphicsViewLayer.android.kt b/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/GraphicsViewLayer.android.kt
index ec3b901..f98f7bf 100644
--- a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/GraphicsViewLayer.android.kt
+++ b/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/GraphicsViewLayer.android.kt
@@ -370,7 +370,7 @@
         }
     }
 
-    override fun buildLayer(
+    override fun record(
         density: Density,
         layoutDirection: LayoutDirection,
         layer: GraphicsLayer,
diff --git a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/LayerSnapshot.android.kt b/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/LayerSnapshot.android.kt
index 4382634..349eccf 100644
--- a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/LayerSnapshot.android.kt
+++ b/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/LayerSnapshot.android.kt
@@ -60,7 +60,7 @@
 
         override fun endRecording() {
             // NO-OP. The GraphicsLayer used here already has its drawing commands recorded via
-            // GraphicsLayer.buildLayer, so there is no additional work to be done here.
+            // GraphicsLayer.record, so there is no additional work to be done here.
         }
 
         override fun getWidth(): Int = graphicsLayer.size.width
diff --git a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/drawscope/DrawScope.kt b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/drawscope/DrawScope.kt
index 93b5576..5be8224 100644
--- a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/drawscope/DrawScope.kt
+++ b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/drawscope/DrawScope.kt
@@ -935,17 +935,17 @@
      * This will retarget the underlying canvas of the provided DrawScope to draw within the layer
      * itself and reset it to the original canvas on the conclusion of this method call.
      */
-    fun GraphicsLayer.buildLayer(
+    fun GraphicsLayer.record(
         size: IntSize = this@DrawScope.size.toIntSize(),
         block: DrawScope.() -> Unit
-    ): GraphicsLayer = buildLayer(
+    ) = record(
         this@DrawScope,
         this@DrawScope.layoutDirection,
         size
     ) {
         this@DrawScope.draw(
-            // we can use this@buildLayer.drawContext directly as the values in this@DrawScope
-            // and this@buildLayer are the same
+            // we can use this@record.drawContext directly as the values in this@DrawScope
+            // and this@record are the same
             drawContext.density,
             drawContext.layoutDirection,
             drawContext.canvas,
diff --git a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/layer/GraphicsLayer.kt b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/layer/GraphicsLayer.kt
index ca57529..62019b8 100644
--- a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/layer/GraphicsLayer.kt
+++ b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/layer/GraphicsLayer.kt
@@ -39,7 +39,7 @@
 
 /**
  * Draw the provided [GraphicsLayer] into the current [DrawScope].
- * The [GraphicsLayer] provided must have [GraphicsLayer.buildLayer] invoked on it otherwise
+ * The [GraphicsLayer] provided must have [GraphicsLayer.record] invoked on it otherwise
  * no visual output will be seen in the rendered result.
  *
  * @sample androidx.compose.ui.graphics.samples.GraphicsLayerTopLeftSample
@@ -71,7 +71,7 @@
  * Usage of a [GraphicsLayer] requires a minimum of 2 steps.
  *
  * 1) The [GraphicsLayer] must be built, which involves specifying the position alongside a list
- * of drawing commands using [GraphicsLayer.buildLayer]
+ * of drawing commands using [GraphicsLayer.record]
  *
  * 2) The [GraphicsLayer] is then drawn into another destination [Canvas] using
  * [GraphicsLayer.draw].
@@ -108,7 +108,7 @@
      * Size in pixels of the [GraphicsLayer]. By default [GraphicsLayer] contents can draw outside
      * of the bounds specified by [topLeft] and [size], however, rasterization of this layer into
      * an offscreen buffer will be sized according to the specified size. This is configured
-     * by calling [buildLayer]
+     * by calling [record]
      *
      * @sample androidx.compose.ui.graphics.samples.GraphicsLayerSizeSample
      */
@@ -230,7 +230,7 @@
     /**
      * Returns the outline specified by either [setPathOutline] or [setRoundRectOutline].
      * By default this will return [Outline.Rectangle] with the size of the [GraphicsLayer]
-     * specified by [buildLayer] or [IntSize.Zero] if [buildLayer] was not previously invoked.
+     * specified by [record] or [IntSize.Zero] if [record] was not previously invoked.
      */
     val outline: Outline
 
@@ -373,16 +373,16 @@
      * @sample androidx.compose.ui.graphics.samples.GraphicsLayerBlendModeSample
      * @sample androidx.compose.ui.graphics.samples.GraphicsLayerTranslateSample
      */
-    fun buildLayer(
+    fun record(
         density: Density,
         layoutDirection: LayoutDirection,
         size: IntSize,
         block: DrawScope.() -> Unit
-    ): GraphicsLayer
+    )
 
     /**
      * Create an [ImageBitmap] with the contents of this [GraphicsLayer] instance. Note that
-     * [GraphicsLayer.buildLayer] must be invoked first to record drawing operations before invoking
+     * [GraphicsLayer.record] must be invoked first to record drawing operations before invoking
      * this method.
      *
      * @sample androidx.compose.ui.graphics.samples.GraphicsLayerToImageBitmap
diff --git a/compose/ui/ui-graphics/src/desktopMain/kotlin/androidx/compose/ui/graphics/layer/GraphicsLayer.desktop.kt b/compose/ui/ui-graphics/src/desktopMain/kotlin/androidx/compose/ui/graphics/layer/GraphicsLayer.desktop.kt
index d7d9c3f..eaf601f 100644
--- a/compose/ui/ui-graphics/src/desktopMain/kotlin/androidx/compose/ui/graphics/layer/GraphicsLayer.desktop.kt
+++ b/compose/ui/ui-graphics/src/desktopMain/kotlin/androidx/compose/ui/graphics/layer/GraphicsLayer.desktop.kt
@@ -163,12 +163,12 @@
         invalidateMatrix()
     }
 
-    actual fun buildLayer(
+    actual fun record(
         density: Density,
         layoutDirection: LayoutDirection,
         size: IntSize,
         block: DrawScope.() -> Unit
-    ): GraphicsLayer {
+    ) {
         this.density = density
         this.size = size
         updateLayerConfiguration()
@@ -200,7 +200,6 @@
             )
         }
         picture = pictureRecorder.finishRecordingAsPicture()
-        return this
     }
 
     private fun addSubLayer(graphicsLayer: GraphicsLayer) {
@@ -406,7 +405,7 @@
     /**
      * Returns the outline specified by either [setPathOutline] or [setRoundRectOutline].
      * By default this will return [Outline.Rectangle] with the size of the [GraphicsLayer]
-     * specified by [buildLayer] or [IntSize.Zero] if [buildLayer] was not previously invoked.
+     * specified by [record] or [IntSize.Zero] if [record] was not previously invoked.
      */
     actual val outline: Outline
         get() = configureOutline()
@@ -547,7 +546,7 @@
 
     /**
      * Create an [ImageBitmap] with the contents of this [GraphicsLayer] instance. Note that
-     * [GraphicsLayer.buildLayer] must be invoked first to record drawing operations before invoking
+     * [GraphicsLayer.record] must be invoked first to record drawing operations before invoking
      * this method.
      */
     actual suspend fun toImageBitmap(): ImageBitmap =
diff --git a/compose/ui/ui-graphics/src/desktopTest/kotlin/androidx/compose/ui/graphics/layer/DesktopGraphicsLayerTest.kt b/compose/ui/ui-graphics/src/desktopTest/kotlin/androidx/compose/ui/graphics/layer/DesktopGraphicsLayerTest.kt
index 463b121..f8941c3 100644
--- a/compose/ui/ui-graphics/src/desktopTest/kotlin/androidx/compose/ui/graphics/layer/DesktopGraphicsLayerTest.kt
+++ b/compose/ui/ui-graphics/src/desktopTest/kotlin/androidx/compose/ui/graphics/layer/DesktopGraphicsLayerTest.kt
@@ -52,7 +52,7 @@
         graphicsLayerTest(
             block = { graphicsContext ->
                 layer = graphicsContext.createGraphicsLayer().apply {
-                    buildLayer {
+                    record {
                         drawRect(Color.Red)
                     }
                 }
@@ -67,11 +67,11 @@
     }
 
     @Test
-    fun testBuildLayerWithSize() {
+    fun testRecordWithSize() {
         graphicsLayerTest(
             block = { graphicsContext ->
                 val layer = graphicsContext.createGraphicsLayer().apply {
-                    buildLayer(
+                    record(
                         size = IntSize(TEST_WIDTH / 2, TEST_HEIGHT / 2)
                     ) {
                         drawRect(Color.Red)
@@ -86,16 +86,17 @@
     }
 
     @Test
-    fun testBuildLayerWithOffset() {
+    fun testRecordWithOffset() {
         var layer: GraphicsLayer? = null
         val topLeft = IntOffset(TEST_WIDTH / 2, TEST_HEIGHT / 2)
         val size = IntSize(TEST_WIDTH, TEST_HEIGHT)
         graphicsLayerTest(
             block = { graphicsContext ->
                 layer = graphicsContext.createGraphicsLayer().apply {
-                    buildLayer {
+                    record {
                         drawRect(Color.Red)
-                    }.topLeft = topLeft
+                    }
+                    this.topLeft = topLeft
                 }
                 drawLayer(layer!!)
             },
@@ -115,11 +116,12 @@
         graphicsLayerTest(
             block = { graphicsContext ->
                 layer = graphicsContext.createGraphicsLayer().apply {
-                    buildLayer {
+                    record {
                         inset(0f, 0f, -4f, -4f) {
                             drawRect(Color.Red)
                         }
-                    }.topLeft = topLeft
+                    }
+                    this.topLeft = topLeft
                 }
                 drawLayer(layer!!)
             },
@@ -142,7 +144,7 @@
         graphicsLayerTest(
             block = { graphicsContext ->
                 layer = graphicsContext.createGraphicsLayer().apply {
-                    buildLayer {
+                    record {
                         drawRect(
                             Color.Red,
                             size = Size(this.size.width / 2, this.size.height / 2)
@@ -169,7 +171,7 @@
         graphicsLayerTest(
             block = { graphicsContext ->
                 layer = graphicsContext.createGraphicsLayer().apply {
-                    buildLayer {
+                    record {
                         drawRect(
                             Color.Red,
                             size = Size(this.size.width / 2, this.size.height / 2)
@@ -196,7 +198,7 @@
         graphicsLayerTest(
             block = { graphicsContext ->
                 layer = graphicsContext.createGraphicsLayer().apply {
-                    buildLayer {
+                    record {
                         inset(this.size.width / 4, this.size.height / 4) {
                             drawRect(Color.Red)
                         }
@@ -222,7 +224,7 @@
         graphicsLayerTest(
             block = { graphicsContext ->
                 layer = graphicsContext.createGraphicsLayer().apply {
-                    buildLayer {
+                    record {
                         drawRect(Color.Red)
                     }
                     scaleY = 0.5f
@@ -247,7 +249,7 @@
         graphicsLayerTest(
             block = { graphicsContext ->
                 layer = graphicsContext.createGraphicsLayer().apply {
-                    buildLayer {
+                    record {
                         drawRect(Color.Red, size = this.size / 2f)
                     }
                     translationX = this.size.width / 2f
@@ -270,7 +272,7 @@
         graphicsLayerTest(
             block = { graphicsContext ->
                 layer = graphicsContext.createGraphicsLayer().apply {
-                    buildLayer {
+                    record {
                         drawRect(Color.Red, size = this.size / 2f)
                     }
                     translationY = this.size.height / 2f
@@ -291,7 +293,7 @@
         graphicsLayerTest(
             block = { graphicsContext ->
                 layer = graphicsContext.createGraphicsLayer().apply {
-                    buildLayer {
+                    record {
                         drawRect(
                             Color.Red,
                             size = Size(100000f, 100000f)
@@ -318,7 +320,7 @@
         graphicsLayerTest(
             block = { graphicsContext ->
                 layer = graphicsContext.createGraphicsLayer().apply {
-                    buildLayer {
+                    record {
                         drawRect(
                             Color.Red,
                             size = Size(100000f, 100000f)
@@ -362,7 +364,7 @@
                 )
 
                 layer = graphicsContext.createGraphicsLayer().apply {
-                    buildLayer(halfSize) {
+                    record(halfSize) {
                         drawRect(targetColor)
                     }
                     shadowElevation = 10f
@@ -409,7 +411,7 @@
                 )
 
                 layer = graphicsContext.createGraphicsLayer().apply {
-                    buildLayer(halfSize) {
+                    record(halfSize) {
                         drawRect(targetColor)
                     }
                     setPathOutline(
@@ -474,7 +476,7 @@
                 bottom = top + halfSize.height
 
                 layer = graphicsContext.createGraphicsLayer().apply {
-                    buildLayer(halfSize) {
+                    record(halfSize) {
                         drawRect(targetColor)
                     }
                     setRoundRectOutline(IntOffset.Zero, halfSize, radius)
@@ -555,7 +557,7 @@
                 layer = graphicsContext.createGraphicsLayer().apply {
                     compositingStrategy = CompositingStrategy.Auto
                     alpha = 0.5f
-                    buildLayer {
+                    record {
                         inset(0f, 0f, size.width / 3, size.height / 3) {
                             drawRect(color = Color.Red)
                         }
@@ -592,7 +594,7 @@
             block = { graphicsContext ->
                 layer = graphicsContext.createGraphicsLayer().apply {
                     compositingStrategy = CompositingStrategy.Offscreen
-                    buildLayer {
+                    record {
                         inset(0f, 0f, size.width / 3, size.height / 3) {
                             drawRect(color = Color.Red)
                         }
@@ -625,7 +627,7 @@
                 layer = graphicsContext.createGraphicsLayer().apply {
                     compositingStrategy = CompositingStrategy.ModulateAlpha
                     alpha = 0.5f
-                    buildLayer {
+                    record {
                         inset(0f, 0f, size.width / 3, size.height / 3) {
                             drawRect(color = Color.Red)
                         }
@@ -662,7 +664,7 @@
         graphicsLayerTest(
             block = { graphicsContext ->
                 layer = graphicsContext.createGraphicsLayer().apply {
-                    buildLayer {
+                    record {
                         drawRect(Color.Red)
                     }.apply {
                         colorFilter = ColorFilter.tint(Color.Blue)
@@ -697,12 +699,11 @@
                         (drawScopeSize.width / 2).toInt(),
                         (drawScopeSize.height / 2).toInt()
                     )
-                    buildLayer(layerSize) {
+                    record(layerSize) {
                         drawRect(Color.Red)
-                    }.apply {
-                        this.topLeft = topLeft
-                        this.blendMode = BlendMode.Xor
                     }
+                    this.topLeft = topLeft
+                    this.blendMode = BlendMode.Xor
                 }
                 drawRect(Color.Green)
                 drawLayer(layer!!)
@@ -745,7 +746,7 @@
         graphicsLayerTest(
             block = { graphicsContext ->
                 layer = graphicsContext.createGraphicsLayer().apply {
-                    buildLayer {
+                    record {
                         drawRect(targetColor)
                     }
                     setRectOutline(this.size.center, this.size / 2)
@@ -790,7 +791,7 @@
         graphicsLayerTest(
             block = { graphicsContext ->
                 layer = graphicsContext.createGraphicsLayer().apply {
-                    buildLayer {
+                    record {
                         drawRect(targetColor)
                     }
                     setPathOutline(Path().apply {
@@ -845,7 +846,7 @@
         graphicsLayerTest(
             block = { graphicsContext ->
                 layer = graphicsContext.createGraphicsLayer().apply {
-                    buildLayer {
+                    record {
                         drawRect(targetColor)
                     }
                     setRoundRectOutline(
diff --git a/compose/ui/ui-inspection/build.gradle b/compose/ui/ui-inspection/build.gradle
index 5f0952ee..20b1101 100644
--- a/compose/ui/ui-inspection/build.gradle
+++ b/compose/ui/ui-inspection/build.gradle
@@ -40,6 +40,7 @@
     // because compose:ui-inspector can be run only in app with compose:ui:ui
     // thus all its transitive dependencies will be present too.
     compileOnly(libs.kotlinStdlib)
+    compileOnly("androidx.collection:collection:1.4.0")
     compileOnly("androidx.inspection:inspection:1.0.0")
     compileOnly("androidx.compose.runtime:runtime:1.2.1")
     compileOnly(project(":compose:ui:ui-graphics"))
@@ -52,7 +53,6 @@
     implementation(libs.kotlinReflect, {
         exclude group: "org.jetbrains.kotlin", module: "kotlin-stdlib"
     })
-    implementation("androidx.collection:collection:1.4.0")
     androidTestImplementation(libs.kotlinStdlib)
     androidTestImplementation(libs.kotlinCoroutinesAndroid)
     androidTestImplementation(libs.testCore)
diff --git a/compose/ui/ui/api/current.txt b/compose/ui/ui/api/current.txt
index ec08ba2..af35be4 100644
--- a/compose/ui/ui/api/current.txt
+++ b/compose/ui/ui/api/current.txt
@@ -360,7 +360,6 @@
   }
 
   public final class CacheDrawScope implements androidx.compose.ui.unit.Density {
-    method public androidx.compose.ui.graphics.layer.GraphicsLayer buildLayer(androidx.compose.ui.graphics.layer.GraphicsLayer, optional androidx.compose.ui.unit.Density density, optional androidx.compose.ui.unit.LayoutDirection layoutDirection, optional long size, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.ContentDrawScope,kotlin.Unit> block);
     method public float getDensity();
     method public float getFontScale();
     method public androidx.compose.ui.unit.LayoutDirection getLayoutDirection();
@@ -368,6 +367,7 @@
     method public androidx.compose.ui.graphics.layer.GraphicsLayer obtainGraphicsLayer();
     method public androidx.compose.ui.draw.DrawResult onDrawBehind(kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
     method public androidx.compose.ui.draw.DrawResult onDrawWithContent(kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.ContentDrawScope,kotlin.Unit> block);
+    method public void record(androidx.compose.ui.graphics.layer.GraphicsLayer, optional androidx.compose.ui.unit.Density density, optional androidx.compose.ui.unit.LayoutDirection layoutDirection, optional long size, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.ContentDrawScope,kotlin.Unit> block);
     property public float density;
     property public float fontScale;
     property public final androidx.compose.ui.unit.LayoutDirection layoutDirection;
@@ -2065,17 +2065,17 @@
   }
 
   public interface ApproachLayoutModifierNode extends androidx.compose.ui.node.LayoutModifierNode {
-    method @SuppressCompatibility @androidx.compose.ui.ExperimentalComposeUiApi public androidx.compose.ui.layout.MeasureResult approachMeasure(androidx.compose.ui.layout.ApproachMeasureScope, androidx.compose.ui.layout.Measurable measurable, long constraints);
-    method public boolean isMeasurementApproachComplete(long lookaheadSize);
-    method public default boolean isPlacementApproachComplete(androidx.compose.ui.layout.Placeable.PlacementScope, androidx.compose.ui.layout.LayoutCoordinates lookaheadCoordinates);
-    method @SuppressCompatibility @androidx.compose.ui.ExperimentalComposeUiApi public default int maxApproachIntrinsicHeight(androidx.compose.ui.layout.ApproachIntrinsicMeasureScope, androidx.compose.ui.layout.IntrinsicMeasurable measurable, int width);
-    method @SuppressCompatibility @androidx.compose.ui.ExperimentalComposeUiApi public default int maxApproachIntrinsicWidth(androidx.compose.ui.layout.ApproachIntrinsicMeasureScope, androidx.compose.ui.layout.IntrinsicMeasurable measurable, int height);
+    method public androidx.compose.ui.layout.MeasureResult approachMeasure(androidx.compose.ui.layout.ApproachMeasureScope, androidx.compose.ui.layout.Measurable measurable, long constraints);
+    method public boolean isMeasurementApproachInProgress(long lookaheadSize);
+    method public default boolean isPlacementApproachInProgress(androidx.compose.ui.layout.Placeable.PlacementScope, androidx.compose.ui.layout.LayoutCoordinates lookaheadCoordinates);
+    method public default int maxApproachIntrinsicHeight(androidx.compose.ui.layout.ApproachIntrinsicMeasureScope, androidx.compose.ui.layout.IntrinsicMeasurable measurable, int width);
+    method public default int maxApproachIntrinsicWidth(androidx.compose.ui.layout.ApproachIntrinsicMeasureScope, androidx.compose.ui.layout.IntrinsicMeasurable measurable, int height);
     method public default androidx.compose.ui.layout.MeasureResult measure(androidx.compose.ui.layout.MeasureScope, androidx.compose.ui.layout.Measurable measurable, long constraints);
-    method @SuppressCompatibility @androidx.compose.ui.ExperimentalComposeUiApi public default int minApproachIntrinsicHeight(androidx.compose.ui.layout.ApproachIntrinsicMeasureScope, androidx.compose.ui.layout.IntrinsicMeasurable measurable, int width);
-    method @SuppressCompatibility @androidx.compose.ui.ExperimentalComposeUiApi public default int minApproachIntrinsicWidth(androidx.compose.ui.layout.ApproachIntrinsicMeasureScope, androidx.compose.ui.layout.IntrinsicMeasurable measurable, int height);
+    method public default int minApproachIntrinsicHeight(androidx.compose.ui.layout.ApproachIntrinsicMeasureScope, androidx.compose.ui.layout.IntrinsicMeasurable measurable, int width);
+    method public default int minApproachIntrinsicWidth(androidx.compose.ui.layout.ApproachIntrinsicMeasureScope, androidx.compose.ui.layout.IntrinsicMeasurable measurable, int height);
   }
 
-  @SuppressCompatibility @androidx.compose.ui.ExperimentalComposeUiApi public sealed interface ApproachMeasureScope extends androidx.compose.ui.layout.ApproachIntrinsicMeasureScope androidx.compose.ui.layout.MeasureScope {
+  public sealed interface ApproachMeasureScope extends androidx.compose.ui.layout.ApproachIntrinsicMeasureScope androidx.compose.ui.layout.MeasureScope {
   }
 
   public interface BeyondBoundsLayout {
@@ -2157,9 +2157,6 @@
     ctor public HorizontalRuler();
   }
 
-  @Deprecated @SuppressCompatibility @androidx.compose.ui.ExperimentalComposeUiApi public interface IntermediateMeasureScope extends androidx.compose.ui.layout.ApproachMeasureScope kotlinx.coroutines.CoroutineScope androidx.compose.ui.layout.LookaheadScope {
-  }
-
   public interface IntrinsicMeasurable {
     method public Object? getParentData();
     method public int maxIntrinsicHeight(int width);
@@ -2273,8 +2270,7 @@
 
   public final class LookaheadScopeKt {
     method @androidx.compose.runtime.Composable @androidx.compose.ui.UiComposable public static void LookaheadScope(kotlin.jvm.functions.Function1<? super androidx.compose.ui.layout.LookaheadScope,kotlin.Unit> content);
-    method @SuppressCompatibility @androidx.compose.ui.ExperimentalComposeUiApi public static androidx.compose.ui.Modifier approachLayout(androidx.compose.ui.Modifier, kotlin.jvm.functions.Function1<? super androidx.compose.ui.unit.IntSize,java.lang.Boolean> isMeasurementApproachComplete, optional kotlin.jvm.functions.Function2<? super androidx.compose.ui.layout.Placeable.PlacementScope,? super androidx.compose.ui.layout.LayoutCoordinates,java.lang.Boolean> isPlacementApproachComplete, kotlin.jvm.functions.Function3<? super androidx.compose.ui.layout.ApproachMeasureScope,? super androidx.compose.ui.layout.Measurable,? super androidx.compose.ui.unit.Constraints,? extends androidx.compose.ui.layout.MeasureResult> approachMeasure);
-    method @Deprecated @SuppressCompatibility @androidx.compose.ui.ExperimentalComposeUiApi public static androidx.compose.ui.Modifier intermediateLayout(androidx.compose.ui.Modifier, kotlin.jvm.functions.Function3<? super androidx.compose.ui.layout.IntermediateMeasureScope,? super androidx.compose.ui.layout.Measurable,? super androidx.compose.ui.unit.Constraints,? extends androidx.compose.ui.layout.MeasureResult> measure);
+    method public static androidx.compose.ui.Modifier approachLayout(androidx.compose.ui.Modifier, kotlin.jvm.functions.Function1<? super androidx.compose.ui.unit.IntSize,java.lang.Boolean> isMeasurementApproachInProgress, optional kotlin.jvm.functions.Function2<? super androidx.compose.ui.layout.Placeable.PlacementScope,? super androidx.compose.ui.layout.LayoutCoordinates,java.lang.Boolean> isPlacementApproachInProgress, kotlin.jvm.functions.Function3<? super androidx.compose.ui.layout.ApproachMeasureScope,? super androidx.compose.ui.layout.Measurable,? super androidx.compose.ui.unit.Constraints,? extends androidx.compose.ui.layout.MeasureResult> approachMeasure);
   }
 
   public interface Measurable extends androidx.compose.ui.layout.IntrinsicMeasurable {
diff --git a/compose/ui/ui/api/restricted_current.txt b/compose/ui/ui/api/restricted_current.txt
index 4ba9b32..0c0e4ac 100644
--- a/compose/ui/ui/api/restricted_current.txt
+++ b/compose/ui/ui/api/restricted_current.txt
@@ -360,7 +360,6 @@
   }
 
   public final class CacheDrawScope implements androidx.compose.ui.unit.Density {
-    method public androidx.compose.ui.graphics.layer.GraphicsLayer buildLayer(androidx.compose.ui.graphics.layer.GraphicsLayer, optional androidx.compose.ui.unit.Density density, optional androidx.compose.ui.unit.LayoutDirection layoutDirection, optional long size, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.ContentDrawScope,kotlin.Unit> block);
     method public float getDensity();
     method public float getFontScale();
     method public androidx.compose.ui.unit.LayoutDirection getLayoutDirection();
@@ -368,6 +367,7 @@
     method public androidx.compose.ui.graphics.layer.GraphicsLayer obtainGraphicsLayer();
     method public androidx.compose.ui.draw.DrawResult onDrawBehind(kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
     method public androidx.compose.ui.draw.DrawResult onDrawWithContent(kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.ContentDrawScope,kotlin.Unit> block);
+    method public void record(androidx.compose.ui.graphics.layer.GraphicsLayer, optional androidx.compose.ui.unit.Density density, optional androidx.compose.ui.unit.LayoutDirection layoutDirection, optional long size, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.ContentDrawScope,kotlin.Unit> block);
     property public float density;
     property public float fontScale;
     property public final androidx.compose.ui.unit.LayoutDirection layoutDirection;
@@ -2065,17 +2065,17 @@
   }
 
   public interface ApproachLayoutModifierNode extends androidx.compose.ui.node.LayoutModifierNode {
-    method @SuppressCompatibility @androidx.compose.ui.ExperimentalComposeUiApi public androidx.compose.ui.layout.MeasureResult approachMeasure(androidx.compose.ui.layout.ApproachMeasureScope, androidx.compose.ui.layout.Measurable measurable, long constraints);
-    method public boolean isMeasurementApproachComplete(long lookaheadSize);
-    method public default boolean isPlacementApproachComplete(androidx.compose.ui.layout.Placeable.PlacementScope, androidx.compose.ui.layout.LayoutCoordinates lookaheadCoordinates);
-    method @SuppressCompatibility @androidx.compose.ui.ExperimentalComposeUiApi public default int maxApproachIntrinsicHeight(androidx.compose.ui.layout.ApproachIntrinsicMeasureScope, androidx.compose.ui.layout.IntrinsicMeasurable measurable, int width);
-    method @SuppressCompatibility @androidx.compose.ui.ExperimentalComposeUiApi public default int maxApproachIntrinsicWidth(androidx.compose.ui.layout.ApproachIntrinsicMeasureScope, androidx.compose.ui.layout.IntrinsicMeasurable measurable, int height);
+    method public androidx.compose.ui.layout.MeasureResult approachMeasure(androidx.compose.ui.layout.ApproachMeasureScope, androidx.compose.ui.layout.Measurable measurable, long constraints);
+    method public boolean isMeasurementApproachInProgress(long lookaheadSize);
+    method public default boolean isPlacementApproachInProgress(androidx.compose.ui.layout.Placeable.PlacementScope, androidx.compose.ui.layout.LayoutCoordinates lookaheadCoordinates);
+    method public default int maxApproachIntrinsicHeight(androidx.compose.ui.layout.ApproachIntrinsicMeasureScope, androidx.compose.ui.layout.IntrinsicMeasurable measurable, int width);
+    method public default int maxApproachIntrinsicWidth(androidx.compose.ui.layout.ApproachIntrinsicMeasureScope, androidx.compose.ui.layout.IntrinsicMeasurable measurable, int height);
     method public default androidx.compose.ui.layout.MeasureResult measure(androidx.compose.ui.layout.MeasureScope, androidx.compose.ui.layout.Measurable measurable, long constraints);
-    method @SuppressCompatibility @androidx.compose.ui.ExperimentalComposeUiApi public default int minApproachIntrinsicHeight(androidx.compose.ui.layout.ApproachIntrinsicMeasureScope, androidx.compose.ui.layout.IntrinsicMeasurable measurable, int width);
-    method @SuppressCompatibility @androidx.compose.ui.ExperimentalComposeUiApi public default int minApproachIntrinsicWidth(androidx.compose.ui.layout.ApproachIntrinsicMeasureScope, androidx.compose.ui.layout.IntrinsicMeasurable measurable, int height);
+    method public default int minApproachIntrinsicHeight(androidx.compose.ui.layout.ApproachIntrinsicMeasureScope, androidx.compose.ui.layout.IntrinsicMeasurable measurable, int width);
+    method public default int minApproachIntrinsicWidth(androidx.compose.ui.layout.ApproachIntrinsicMeasureScope, androidx.compose.ui.layout.IntrinsicMeasurable measurable, int height);
   }
 
-  @SuppressCompatibility @androidx.compose.ui.ExperimentalComposeUiApi public sealed interface ApproachMeasureScope extends androidx.compose.ui.layout.ApproachIntrinsicMeasureScope androidx.compose.ui.layout.MeasureScope {
+  public sealed interface ApproachMeasureScope extends androidx.compose.ui.layout.ApproachIntrinsicMeasureScope androidx.compose.ui.layout.MeasureScope {
   }
 
   public interface BeyondBoundsLayout {
@@ -2157,9 +2157,6 @@
     ctor public HorizontalRuler();
   }
 
-  @Deprecated @SuppressCompatibility @androidx.compose.ui.ExperimentalComposeUiApi public interface IntermediateMeasureScope extends androidx.compose.ui.layout.ApproachMeasureScope kotlinx.coroutines.CoroutineScope androidx.compose.ui.layout.LookaheadScope {
-  }
-
   public interface IntrinsicMeasurable {
     method public Object? getParentData();
     method public int maxIntrinsicHeight(int width);
@@ -2276,8 +2273,7 @@
 
   public final class LookaheadScopeKt {
     method @androidx.compose.runtime.Composable @androidx.compose.ui.UiComposable public static void LookaheadScope(kotlin.jvm.functions.Function1<? super androidx.compose.ui.layout.LookaheadScope,kotlin.Unit> content);
-    method @SuppressCompatibility @androidx.compose.ui.ExperimentalComposeUiApi public static androidx.compose.ui.Modifier approachLayout(androidx.compose.ui.Modifier, kotlin.jvm.functions.Function1<? super androidx.compose.ui.unit.IntSize,java.lang.Boolean> isMeasurementApproachComplete, optional kotlin.jvm.functions.Function2<? super androidx.compose.ui.layout.Placeable.PlacementScope,? super androidx.compose.ui.layout.LayoutCoordinates,java.lang.Boolean> isPlacementApproachComplete, kotlin.jvm.functions.Function3<? super androidx.compose.ui.layout.ApproachMeasureScope,? super androidx.compose.ui.layout.Measurable,? super androidx.compose.ui.unit.Constraints,? extends androidx.compose.ui.layout.MeasureResult> approachMeasure);
-    method @Deprecated @SuppressCompatibility @androidx.compose.ui.ExperimentalComposeUiApi public static androidx.compose.ui.Modifier intermediateLayout(androidx.compose.ui.Modifier, kotlin.jvm.functions.Function3<? super androidx.compose.ui.layout.IntermediateMeasureScope,? super androidx.compose.ui.layout.Measurable,? super androidx.compose.ui.unit.Constraints,? extends androidx.compose.ui.layout.MeasureResult> measure);
+    method public static androidx.compose.ui.Modifier approachLayout(androidx.compose.ui.Modifier, kotlin.jvm.functions.Function1<? super androidx.compose.ui.unit.IntSize,java.lang.Boolean> isMeasurementApproachInProgress, optional kotlin.jvm.functions.Function2<? super androidx.compose.ui.layout.Placeable.PlacementScope,? super androidx.compose.ui.layout.LayoutCoordinates,java.lang.Boolean> isPlacementApproachInProgress, kotlin.jvm.functions.Function3<? super androidx.compose.ui.layout.ApproachMeasureScope,? super androidx.compose.ui.layout.Measurable,? super androidx.compose.ui.unit.Constraints,? extends androidx.compose.ui.layout.MeasureResult> approachMeasure);
   }
 
   public interface Measurable extends androidx.compose.ui.layout.IntrinsicMeasurable {
diff --git a/compose/ui/ui/build.gradle b/compose/ui/ui/build.gradle
index 8f79926..000723b 100644
--- a/compose/ui/ui/build.gradle
+++ b/compose/ui/ui/build.gradle
@@ -99,6 +99,18 @@
                 implementation("androidx.emoji2:emoji2:1.2.0")
 
                 implementation("androidx.profileinstaller:profileinstaller:1.3.1")
+
+                // `compose-ui` has a transitive dependency on `lifecycle-livedata-core`, and
+                // converting `lifecycle-runtime-compose` to KMP triggered a Gradle bug. Adding
+                // the `livedata` dependency directly works around the issue.
+                // See https://github.com/gradle/gradle/issues/14220 for details.
+                compileOnly(projectOrArtifact(":lifecycle:lifecycle-livedata-core"))
+
+                // `compose-ui` has a transitive dependency on `lifecycle-viewmodel-savedstate`, and
+                // converting `lifecycle-runtime-compose` to KMP triggered a Gradle bug. Adding
+                // the `lifecycle-viewmodel-savedstate` dependency directly works around the issue.
+                // See https://github.com/gradle/gradle/issues/14220 for details.
+                compileOnly(projectOrArtifact(":lifecycle:lifecycle-viewmodel-savedstate"))
             }
         }
 
diff --git a/compose/ui/ui/samples/src/main/java/androidx/compose/ui/samples/LookaheadScopeSample.kt b/compose/ui/ui/samples/src/main/java/androidx/compose/ui/samples/LookaheadScopeSample.kt
index 036583e..c34126c 100644
--- a/compose/ui/ui/samples/src/main/java/androidx/compose/ui/samples/LookaheadScopeSample.kt
+++ b/compose/ui/ui/samples/src/main/java/androidx/compose/ui/samples/LookaheadScopeSample.kt
@@ -82,12 +82,12 @@
         sizeAnimation: DeferredTargetAnimation<IntSize, AnimationVector2D>,
         coroutineScope: CoroutineScope
     ) = this.approachLayout(
-        isMeasurementApproachComplete = { lookaheadSize ->
+        isMeasurementApproachInProgress = { lookaheadSize ->
             // Update the target of the size animation.
             sizeAnimation.updateTarget(lookaheadSize, coroutineScope)
-            // Return true if the size animation has no pending target change and has finished
+            // Return true if the size animation has pending target change or hasn't finished
             // running.
-            sizeAnimation.isIdle
+            !sizeAnimation.isIdle
         }
     ) { measurable, _ ->
         // In the measurement approach, the goal is to gradually reach the destination size
@@ -150,21 +150,21 @@
                 IntOffset.VectorConverter
             )
 
-        override fun isMeasurementApproachComplete(lookaheadSize: IntSize): Boolean {
+        override fun isMeasurementApproachInProgress(lookaheadSize: IntSize): Boolean {
             // Since we only animate the placement here, we can consider measurement approach
             // complete.
-            return true
+            return false
         }
 
-        // Returns true when the offset animation is complete, false otherwise.
-        override fun Placeable.PlacementScope.isPlacementApproachComplete(
+        // Returns true when the offset animation is in progress, false otherwise.
+        override fun Placeable.PlacementScope.isPlacementApproachInProgress(
             lookaheadCoordinates: LayoutCoordinates
         ): Boolean {
             val target = with(lookaheadScope) {
                 lookaheadScopeCoordinates.localLookaheadPositionOf(lookaheadCoordinates).round()
             }
             offsetAnimation.updateTarget(target, coroutineScope)
-            return offsetAnimation.isIdle
+            return !offsetAnimation.isIdle
         }
 
         @ExperimentalComposeUiApi
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/draw/DrawModifierTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/draw/DrawModifierTest.kt
index b591a0e..911aac3 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/draw/DrawModifierTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/draw/DrawModifierTest.kt
@@ -164,7 +164,7 @@
 
     @Test
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
-    fun testBuildLayerWithCache() {
+    fun testRecordWithCache() {
         var graphicsLayer: GraphicsLayer? = null
         val testTag = "TestTag"
         val size = 120.dp
@@ -179,13 +179,12 @@
                 .then(
                     Modifier.drawWithCache {
                         val layer = obtainGraphicsLayer().also { graphicsLayer = it }
-                        layer
-                            .buildLayer {
+                        layer.apply {
+                            record {
                                 drawContent()
                             }
-                            .apply {
-                                this.colorFilter = ColorFilter.tint(tintColor)
-                            }
+                            this.colorFilter = ColorFilter.tint(tintColor)
+                        }
                         onDrawWithContent {
                             drawLayer(layer)
                         }
@@ -217,7 +216,7 @@
         val drawGraphicsLayer = mutableStateOf(0)
         val rectColor = Color.Red
         val bgColor = Color.Blue
-        var isLayerBuilt = false
+        var isLayerRecorded = false
         rule.setContent {
             val graphicsLayer = rememberGraphicsLayer()
             assertEquals(IntSize.Zero, graphicsLayer.size)
@@ -226,11 +225,11 @@
                 .testTag(testTag)
                 .then(
                     Modifier.drawWithCache {
-                        if (!isLayerBuilt) {
-                            graphicsLayer.buildLayer {
+                        if (!isLayerRecorded) {
+                            graphicsLayer.record {
                                 drawRect(rectColor)
                             }
-                            isLayerBuilt = true
+                            isLayerRecorded = true
                         }
                         onDrawWithContent {
                             drawRect(bgColor)
@@ -271,7 +270,7 @@
 
     @Test
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
-    fun testBuildLayerDrawContent() {
+    fun testRecordDrawContent() {
         val testTag = "TestTag"
         val targetColor = Color.Blue
         rule.setContent {
@@ -282,7 +281,7 @@
                         .size(40.dp)
                         .background(Color.Green)
                         .drawWithContent {
-                            layer.buildLayer {
+                            layer.record {
                                 this@drawWithContent.drawContent()
                             }
                             drawLayer(layer)
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/draw/DrawingPrebuiltGraphicsLayerTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/draw/DrawingPrebuiltGraphicsLayerTest.kt
index c9f8888..a2ae451 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/draw/DrawingPrebuiltGraphicsLayerTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/draw/DrawingPrebuiltGraphicsLayerTest.kt
@@ -365,7 +365,7 @@
         layer: GraphicsLayer = obtainLayer()
     ): Modifier {
         return drawWithContent {
-            layer.buildLayer {
+            layer.record {
                 this@drawWithContent.drawContent()
             }
             drawLayer(layer)
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/pointer/HitPathTrackerTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/pointer/HitPathTrackerTest.kt
index 67479b38..626fed9 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/pointer/HitPathTrackerTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/pointer/HitPathTrackerTest.kt
@@ -251,6 +251,351 @@
         assertThat(areEqual(hitPathTracker.root, expectedRoot)).isTrue()
     }
 
+    // Inserts a new Node at the top of an existing branch (tests removal of duplicate Nodes too).
+    @Test
+    fun addHitPath_dynamicNodeAddedTopPartiallyMatchingTreeWithOnePointerId_correctResult() {
+        val pif1 = PointerInputNodeMock()
+        val pif2 = PointerInputNodeMock()
+        val pif3 = PointerInputNodeMock()
+        val pif4 = PointerInputNodeMock()
+        val pifNew1 = PointerInputNodeMock()
+
+        val pointerId1 = PointerId(1)
+        hitPathTracker.addHitPath(pointerId1, listOf(pif1, pif2, pif3, pif4))
+        hitPathTracker.addHitPath(pointerId1, listOf(pifNew1, pif1, pif2, pif3, pif4))
+
+        val expectedRoot = NodeParent().apply {
+            children.add(
+                Node(pifNew1).apply {
+                    pointerIds.add(pointerId1)
+                    children.add(
+                        Node(pif1).apply {
+                            pointerIds.add(pointerId1)
+                            children.add(
+                                Node(pif2).apply {
+                                    pointerIds.add(pointerId1)
+                                    children.add(
+                                        Node(pif3).apply {
+                                            pointerIds.add(pointerId1)
+                                            children.add(
+                                                Node(pif4).apply {
+                                                    pointerIds.add(pointerId1)
+                                                }
+                                            )
+                                        }
+                                    )
+                                }
+                            )
+                        }
+                    )
+                }
+            )
+        }
+        assertThat(areEqual(hitPathTracker.root, expectedRoot)).isTrue()
+    }
+
+    @Test
+    fun addHitPath_dynamicNodeAddedTopPartiallyMatchingTreeWithTwoPointerIds_correctResult() {
+        val pif1 = PointerInputNodeMock()
+        val pif2 = PointerInputNodeMock()
+        val pif3 = PointerInputNodeMock()
+        val pif4 = PointerInputNodeMock()
+        val pif5 = PointerInputNodeMock()
+        val pif6 = PointerInputNodeMock()
+        val pif7 = PointerInputNodeMock()
+        val pif8 = PointerInputNodeMock()
+
+        val pifNew1 = PointerInputNodeMock()
+
+        val pointerId1 = PointerId(1)
+        val pointerId2 = PointerId(2)
+
+        hitPathTracker.addHitPath(pointerId1, listOf(pif1, pif2, pif3, pif4))
+        hitPathTracker.addHitPath(pointerId2, listOf(pif5, pif6, pif7, pif8))
+
+        hitPathTracker.addHitPath(pointerId2, listOf(pifNew1, pif5, pif6, pif7, pif8))
+
+        val expectedRoot = NodeParent().apply {
+            children.add(
+                Node(pif1).apply {
+                    pointerIds.add(pointerId1)
+                    children.add(
+                        Node(pif2).apply {
+                            pointerIds.add(pointerId1)
+                            children.add(
+                                Node(pif3).apply {
+                                    pointerIds.add(pointerId1)
+                                    children.add(
+                                        Node(pif4).apply {
+                                            pointerIds.add(pointerId1)
+                                        }
+                                    )
+                                }
+                            )
+                        }
+                    )
+                }
+            )
+
+            children.add(
+                Node(pifNew1).apply {
+                    pointerIds.add(pointerId2)
+                    children.add(
+                        Node(pif5).apply {
+                            pointerIds.add(pointerId2)
+                            children.add(
+                                Node(pif6).apply {
+                                    pointerIds.add(pointerId2)
+                                    children.add(
+                                        Node(pif7).apply {
+                                            pointerIds.add(pointerId2)
+                                            children.add(
+                                                Node(pif8).apply {
+                                                    pointerIds.add(pointerId2)
+                                                }
+                                            )
+                                        }
+                                    )
+                                }
+                            )
+                        }
+                    )
+                }
+            )
+        }
+        assertThat(areEqual(hitPathTracker.root, expectedRoot)).isTrue()
+    }
+
+    // Inserts a new Node inside an existing branch (tests removal of duplicate Nodes too).
+    @Test
+    fun addHitPath_dynamicNodeAddedInsidePartiallyMatchingTreeWithOnePointerId_correctResult() {
+        val pif1 = PointerInputNodeMock()
+        val pif2 = PointerInputNodeMock()
+        val pif3 = PointerInputNodeMock()
+        val pif4 = PointerInputNodeMock()
+        val pifNew1 = PointerInputNodeMock()
+
+        val pointerId1 = PointerId(1)
+        hitPathTracker.addHitPath(pointerId1, listOf(pif1, pif2, pif3, pif4))
+        hitPathTracker.addHitPath(pointerId1, listOf(pif1, pifNew1, pif2, pif3, pif4))
+
+        val expectedRoot = NodeParent().apply {
+            children.add(
+                Node(pif1).apply {
+                    pointerIds.add(pointerId1)
+                    children.add(
+                        Node(pifNew1).apply {
+                            pointerIds.add(pointerId1)
+                            children.add(
+                                Node(pif2).apply {
+                                    pointerIds.add(pointerId1)
+                                    children.add(
+                                        Node(pif3).apply {
+                                            pointerIds.add(pointerId1)
+                                            children.add(
+                                                Node(pif4).apply {
+                                                    pointerIds.add(pointerId1)
+                                                }
+                                            )
+                                        }
+                                    )
+                                }
+                            )
+                        }
+                    )
+                }
+            )
+        }
+        assertThat(areEqual(hitPathTracker.root, expectedRoot)).isTrue()
+    }
+
+    @Test
+    fun addHitPath_dynamicNodeAddedInsidePartiallyMatchingTreeWithTwoPointerIds_correctResult() {
+        val pif1 = PointerInputNodeMock()
+        val pif2 = PointerInputNodeMock()
+        val pif3 = PointerInputNodeMock()
+        val pif4 = PointerInputNodeMock()
+        val pif5 = PointerInputNodeMock()
+        val pif6 = PointerInputNodeMock()
+        val pif7 = PointerInputNodeMock()
+        val pif8 = PointerInputNodeMock()
+
+        val pifNew1 = PointerInputNodeMock()
+
+        val pointerId1 = PointerId(1)
+        val pointerId2 = PointerId(2)
+
+        hitPathTracker.addHitPath(pointerId1, listOf(pif1, pif2, pif3, pif4))
+        hitPathTracker.addHitPath(pointerId2, listOf(pif5, pif6, pif7, pif8))
+
+        hitPathTracker.addHitPath(pointerId2, listOf(pif5, pif6, pifNew1, pif7, pif8))
+
+        val expectedRoot = NodeParent().apply {
+            children.add(
+                Node(pif1).apply {
+                    pointerIds.add(pointerId1)
+                    children.add(
+                        Node(pif2).apply {
+                            pointerIds.add(pointerId1)
+                            children.add(
+                                Node(pif3).apply {
+                                    pointerIds.add(pointerId1)
+                                    children.add(
+                                        Node(pif4).apply {
+                                            pointerIds.add(pointerId1)
+                                        }
+                                    )
+                                }
+                            )
+                        }
+                    )
+                }
+            )
+
+            children.add(
+                Node(pif5).apply {
+                    pointerIds.add(pointerId2)
+                    children.add(
+                        Node(pif6).apply {
+                            pointerIds.add(pointerId2)
+                            children.add(
+                                Node(pifNew1).apply {
+                                    pointerIds.add(pointerId2)
+                                    children.add(
+                                        Node(pif7).apply {
+                                            pointerIds.add(pointerId2)
+                                            children.add(
+                                                Node(pif8).apply {
+                                                    pointerIds.add(pointerId2)
+                                                }
+                                            )
+                                        }
+                                    )
+                                }
+                            )
+                        }
+                    )
+                }
+            )
+        }
+        assertThat(areEqual(hitPathTracker.root, expectedRoot)).isTrue()
+    }
+
+    // Inserts a Node in the bottom of an existing branch (tests removal of duplicate Nodes too).
+    @Test
+    fun addHitPath_dynamicNodeAddedBelowPartiallyMatchingTreeWithOnePointerId_correctResult() {
+        val pif1 = PointerInputNodeMock()
+        val pif2 = PointerInputNodeMock()
+        val pif3 = PointerInputNodeMock()
+        val pif4 = PointerInputNodeMock()
+        val pifNew1 = PointerInputNodeMock()
+
+        val pointerId1 = PointerId(1)
+        hitPathTracker.addHitPath(pointerId1, listOf(pif1, pif2, pif3, pif4))
+        hitPathTracker.addHitPath(pointerId1, listOf(pif1, pif2, pif3, pif4, pifNew1))
+
+        val expectedRoot = NodeParent().apply {
+            children.add(
+                Node(pif1).apply {
+                    pointerIds.add(pointerId1)
+                    children.add(
+                        Node(pif2).apply {
+                            pointerIds.add(pointerId1)
+                            children.add(
+                                Node(pif3).apply {
+                                    pointerIds.add(pointerId1)
+                                    children.add(
+                                        Node(pif4).apply {
+                                            pointerIds.add(pointerId1)
+                                            children.add(
+                                                Node(pifNew1).apply {
+                                                    pointerIds.add(pointerId1)
+                                                }
+                                            )
+                                        }
+                                    )
+                                }
+                            )
+                        }
+                    )
+                }
+            )
+        }
+        assertThat(areEqual(hitPathTracker.root, expectedRoot)).isTrue()
+    }
+
+    @Test
+    fun addHitPath_dynamicNodeAddedBelowPartiallyMatchingTreeWithTwoPointerIds_correctResult() {
+        val pif1 = PointerInputNodeMock()
+        val pif2 = PointerInputNodeMock()
+        val pif3 = PointerInputNodeMock()
+        val pif4 = PointerInputNodeMock()
+        val pif5 = PointerInputNodeMock()
+        val pif6 = PointerInputNodeMock()
+        val pif7 = PointerInputNodeMock()
+        val pif8 = PointerInputNodeMock()
+
+        val pifNew1 = PointerInputNodeMock()
+
+        val pointerId1 = PointerId(1)
+        val pointerId2 = PointerId(2)
+
+        hitPathTracker.addHitPath(pointerId1, listOf(pif1, pif2, pif3, pif4))
+        hitPathTracker.addHitPath(pointerId2, listOf(pif5, pif6, pif7, pif8))
+
+        hitPathTracker.addHitPath(pointerId2, listOf(pif5, pif6, pif7, pif8, pifNew1))
+
+        val expectedRoot = NodeParent().apply {
+            children.add(
+                Node(pif1).apply {
+                    pointerIds.add(pointerId1)
+                    children.add(
+                        Node(pif2).apply {
+                            pointerIds.add(pointerId1)
+                            children.add(
+                                Node(pif3).apply {
+                                    pointerIds.add(pointerId1)
+                                    children.add(
+                                        Node(pif4).apply {
+                                            pointerIds.add(pointerId1)
+                                        }
+                                    )
+                                }
+                            )
+                        }
+                    )
+                }
+            )
+
+            children.add(
+                Node(pif5).apply {
+                    pointerIds.add(pointerId2)
+                    children.add(
+                        Node(pif6).apply {
+                            pointerIds.add(pointerId2)
+                            children.add(
+                                Node(pif7).apply {
+                                    pointerIds.add(pointerId2)
+                                    children.add(
+                                        Node(pif8).apply {
+                                            pointerIds.add(pointerId2)
+                                            children.add(
+                                                Node(pifNew1).apply {
+                                                    pointerIds.add(pointerId2)
+                                                }
+                                            )
+                                        }
+                                    )
+                                }
+                            )
+                        }
+                    )
+                }
+            )
+        }
+        assertThat(areEqual(hitPathTracker.root, expectedRoot)).isTrue()
+    }
+
     @Test
     fun dispatchChanges_noNodes_doesNotCrash() {
         hitPathTracker.dispatchChanges(internalPointerEventOf(down(0)))
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/ApproachLayoutTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/ApproachLayoutTest.kt
index 5b7f21c..0f191a2 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/ApproachLayoutTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/ApproachLayoutTest.kt
@@ -53,7 +53,9 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
 import kotlin.test.assertEquals
+import org.junit.Assert.assertFalse
 import org.junit.Assert.assertNotEquals
+import org.junit.Assert.assertTrue
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -68,16 +70,16 @@
     val excessiveAssertions = AndroidOwnerExtraAssertionsRule()
 
     // Test that measurement approach has no effect on parent or child when
-    // isMeasurementApproachComplete returns true
+    // isMeasurementApproachProgress returns false
     @OptIn(ExperimentalComposeUiApi::class)
     @Test
-    fun toggleIsMeasurementApproachComplete() {
+    fun toggleIsMeasurementApproachInProgress() {
         var isComplete by mutableStateOf(true)
         var parentLookaheadSize = IntSize(-1, -1)
         var childLookaheadConstraints: Constraints? = null
         var childLookaheadSize = IntSize(-1, -1)
         // This fraction change triggers a lookahead pass, which will be required to
-        // do a `isMeasurementApproachComplete` after its prior completion.
+        // do a `isMeasurementApproachInProgress` after its prior completion.
         var fraction by mutableStateOf(0.5f)
         var lookaheadPositionInParent = androidx.compose.ui.geometry.Offset(Float.NaN, Float.NaN)
         rule.setContent {
@@ -104,7 +106,7 @@
                             }
                     }
                     .approachLayout(
-                        isMeasurementApproachComplete = { isComplete }
+                        isMeasurementApproachInProgress = { !isComplete }
                     ) { measurable, _ ->
                         // Intentionally use different constraints, placement and report different
                         // measure result than lookahead, to verify that they have no effect on
@@ -214,8 +216,8 @@
                             }
                     }
                     .approachLayout(
-                        isMeasurementApproachComplete = { isMeasurementApproachComplete },
-                        isPlacementApproachComplete = { isPlacementApproachComplete }
+                        isMeasurementApproachInProgress = { !isMeasurementApproachComplete },
+                        isPlacementApproachInProgress = { !isPlacementApproachComplete }
                     ) { measurable, _ ->
                         // Intentionally use different constraints, placement and report different
                         // measure result than lookahead, to verify that they have no effect on
@@ -334,8 +336,8 @@
         var childLookaheadSize: IntSize? = null
         var childApproachSize: IntSize? = null
         val parentApproachNode = object : TestApproachLayoutModifierNode() {
-            override fun isMeasurementApproachComplete(lookaheadSize: IntSize): Boolean {
-                return parentMeasureApproachComplete
+            override fun isMeasurementApproachInProgress(lookaheadSize: IntSize): Boolean {
+                return !parentMeasureApproachComplete
             }
 
             @ExperimentalComposeUiApi
@@ -392,7 +394,7 @@
                                         }
                                     }
                             }
-                            .approachLayout({ childMeasureApproachComplete }) { m, _ ->
+                            .approachLayout({ !childMeasureApproachComplete }) { m, _ ->
                                 m
                                     .measure(Constraints.fixed(500, 500))
                                     .run {
@@ -470,8 +472,8 @@
         var childLookaheadSize: IntSize? = null
         var childApproachSize: IntSize? = null
         val parentApproachNode = object : TestApproachLayoutModifierNode() {
-            override fun isMeasurementApproachComplete(lookaheadSize: IntSize): Boolean {
-                return parentMeasureApproachComplete
+            override fun isMeasurementApproachInProgress(lookaheadSize: IntSize): Boolean {
+                return !parentMeasureApproachComplete
             }
 
             @ExperimentalComposeUiApi
@@ -528,7 +530,7 @@
                                         }
                                     }
                             }
-                            .approachLayout({ childMeasureApproachComplete }) { m, _ ->
+                            .approachLayout({ !childMeasureApproachComplete }) { m, _ ->
                                 m
                                     .measure(Constraints.fixed(500, 500))
                                     .run {
@@ -596,8 +598,8 @@
     fun testDefaultPlacementApproachComplete() {
         var measurementComplete = true
         val node = object : ApproachLayoutModifierNode {
-            override fun isMeasurementApproachComplete(lookaheadSize: IntSize): Boolean {
-                return measurementComplete
+            override fun isMeasurementApproachInProgress(lookaheadSize: IntSize): Boolean {
+                return !measurementComplete
             }
 
             @ExperimentalComposeUiApi
@@ -615,23 +617,23 @@
             override val node: Node = object : Node() {}
         }
 
-        assertEquals(true, node.isMeasurementApproachComplete(IntSize.Zero))
+        assertFalse(node.isMeasurementApproachInProgress(IntSize.Zero))
         with(TestPlacementScope()) {
             with(node) {
-                isPlacementApproachComplete(LayoutCoordinatesStub())
+                isPlacementApproachInProgress(LayoutCoordinatesStub())
             }
         }.also {
-            assertEquals(true, it)
+            assertFalse(it)
         }
 
         measurementComplete = false
-        assertEquals(false, node.isMeasurementApproachComplete(IntSize.Zero))
+        assertTrue(node.isMeasurementApproachInProgress(IntSize.Zero))
         with(TestPlacementScope()) {
             with(node) {
-                isPlacementApproachComplete(LayoutCoordinatesStub())
+                isPlacementApproachInProgress(LayoutCoordinatesStub())
             }
         }.also {
-            assertEquals(true, it)
+            assertFalse(it)
         }
     }
 
@@ -644,14 +646,14 @@
         var measureWithFixedConstraints by mutableStateOf(false)
         var removeChild by mutableStateOf(false)
         val parentNode = object : TestApproachLayoutModifierNode() {
-            override fun isMeasurementApproachComplete(lookaheadSize: IntSize): Boolean {
-                return false
+            override fun isMeasurementApproachInProgress(lookaheadSize: IntSize): Boolean {
+                return true
             }
 
-            override fun Placeable.PlacementScope.isPlacementApproachComplete(
+            override fun Placeable.PlacementScope.isPlacementApproachInProgress(
                 lookaheadCoordinates: LayoutCoordinates
             ): Boolean {
-                return true
+                return false
             }
 
             @ExperimentalComposeUiApi
@@ -673,14 +675,14 @@
         }
 
         val childNode = object : TestApproachLayoutModifierNode() {
-            override fun isMeasurementApproachComplete(lookaheadSize: IntSize): Boolean {
-                return true
+            override fun isMeasurementApproachInProgress(lookaheadSize: IntSize): Boolean {
+                return false
             }
 
-            override fun Placeable.PlacementScope.isPlacementApproachComplete(
+            override fun Placeable.PlacementScope.isPlacementApproachInProgress(
                 lookaheadCoordinates: LayoutCoordinates
             ): Boolean {
-                return true
+                return false
             }
 
             @ExperimentalComposeUiApi
@@ -788,15 +790,15 @@
                             Box(
                                 Modifier
                                     .approachLayout(
-                                        isMeasurementApproachComplete = {
-                                            return@approachLayout true
+                                        isMeasurementApproachInProgress = {
+                                            return@approachLayout false
                                         },
-                                        isPlacementApproachComplete = { coordinates ->
+                                        isPlacementApproachInProgress = { coordinates ->
                                             lastTargetPosition =
                                                 lookaheadScopeCoordinates.localLookaheadPositionOf(
                                                     coordinates
                                                 )
-                                            return@approachLayout true
+                                            return@approachLayout false
                                         },
                                         approachMeasure = { measurable, constraints ->
                                             val placeable = measurable.measure(constraints)
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/LookaheadScopeTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/LookaheadScopeTest.kt
index 9157baad..1255231 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/LookaheadScopeTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/LookaheadScopeTest.kt
@@ -211,10 +211,10 @@
                     Modifier
                         .requiredSize(targetSize.width.dp, targetSize.height.dp)
                         .createIntermediateElement(object : TestApproachLayoutModifierNode() {
-                            override fun isMeasurementApproachComplete(
+                            override fun isMeasurementApproachInProgress(
                                 lookaheadSize: IntSize
                             ): Boolean {
-                                return iteration > 6
+                                return iteration <= 6
                             }
 
                             @ExperimentalComposeUiApi
@@ -428,10 +428,10 @@
                             .createIntermediateElement(object :
                                 TestApproachLayoutModifierNode() {
 
-                                override fun isMeasurementApproachComplete(
+                                override fun isMeasurementApproachInProgress(
                                     lookaheadSize: IntSize
                                 ): Boolean {
-                                    return rootPostPlace >= 12
+                                    return rootPostPlace < 12
                                 }
 
                                 @ExperimentalComposeUiApi
@@ -471,10 +471,10 @@
                                         .createIntermediateElement(object :
                                             TestApproachLayoutModifierNode() {
 
-                                            override fun isMeasurementApproachComplete(
+                                            override fun isMeasurementApproachInProgress(
                                                 lookaheadSize: IntSize
                                             ): Boolean {
-                                                return rootPostPlace >= 12
+                                                return rootPostPlace < 12
                                             }
 
                                             @ExperimentalComposeUiApi
@@ -556,7 +556,7 @@
                             MyLookaheadLayout {
                                 Box(modifier = Modifier
                                     .approachLayout(
-                                        isMeasurementApproachComplete = { scaleFactor > 3f }
+                                        isMeasurementApproachInProgress = { scaleFactor <= 3f }
                                     ) { measurable, constraints ->
                                         assertEquals(width, lookaheadSize.width)
                                         assertEquals(height, lookaheadSize.height)
@@ -2777,8 +2777,8 @@
         with(scope) {
             this@composed
                 .createIntermediateElement(object : TestApproachLayoutModifierNode() {
-                    override fun isMeasurementApproachComplete(lookaheadSize: IntSize): Boolean {
-                        return true
+                    override fun isMeasurementApproachInProgress(lookaheadSize: IntSize): Boolean {
+                        return false
                     }
 
                     @ExperimentalComposeUiApi
@@ -2892,7 +2892,7 @@
             measurable: Measurable,
             constraints: Constraints,
         ) -> MeasureResult,
-    ): Modifier = approachLayout({ testFinished }, approachMeasure = measure)
+    ): Modifier = approachLayout({ !testFinished }, approachMeasure = measure)
 }
 
 private fun Modifier.createIntermediateElement(node: TestApproachLayoutModifierNode): Modifier =
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/PlacementLayoutCoordinatesTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/PlacementLayoutCoordinatesTest.kt
index 2e93bb2..f1e4df3 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/PlacementLayoutCoordinatesTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/PlacementLayoutCoordinatesTest.kt
@@ -833,7 +833,7 @@
                     Box(
                         Modifier
                             .approachLayout({
-                                intermediateLayoutBlockCalls > 20
+                                intermediateLayoutBlockCalls <= 20
                             }) { measurable, constraints ->
                                 val p = measurable.measure(constraints)
                                 layout(p.width, p.height) {
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/FocusSearchBackwardInteropTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/FocusSearchBackwardInteropTest.kt
index a5de4b7..c2220bf 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/FocusSearchBackwardInteropTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/FocusSearchBackwardInteropTest.kt
@@ -18,7 +18,6 @@
 
 import android.os.Build.VERSION.SDK_INT
 import android.os.Build.VERSION_CODES.O
-import android.os.Build.VERSION_CODES.P
 import android.view.KeyEvent
 import android.view.KeyEvent.ACTION_DOWN
 import android.view.KeyEvent.META_SHIFT_ON as Shift
@@ -195,17 +194,22 @@
         rule.runOnIdle { assertThat(view.isFocused).isTrue() }
     }
 
-    @SdkSuppress(minSdkVersion = P) // b/328143586
     @Test
     fun focusedComposableWithFocusableView_view_inLinearLayout() {
         // Arrange.
+        var isComposableFocused = false
         setContent {
-            AndroidView({
-                LinearLayout(it).apply {
-                    addView(FocusableView(it).apply { view2 = this })
-                    addView(ComposeView(it).apply {
+            AndroidView({ context ->
+                LinearLayout(context).apply {
+                    addView(FocusableView(context).apply { view2 = this })
+                    addView(ComposeView(context).apply {
                         setContent {
-                            Row(Modifier.testTag(composable).focusable()) {
+                            Row(
+                                Modifier
+                                    .testTag(composable)
+                                    .onFocusChanged { isComposableFocused = it.isFocused }
+                                    .focusable()
+                            ) {
                                 AndroidView({ FocusableView(it).apply { view1 = this } })
                             }
                         }
@@ -214,13 +218,16 @@
             })
         }
         rule.onNodeWithTag(composable).requestFocus()
+        rule.waitUntil { isComposableFocused }
 
         // Act.
-        rule.focusSearchBackward()
+        rule.focusSearchBackward(waitForIdle = false)
 
         // Assert.
-        rule.onNodeWithTag(composable).assertIsNotFocused()
-        rule.runOnIdle { assertThat(view2.isFocused).isTrue() }
+        rule.waitUntil { !isComposableFocused }
+
+        // TODO(b/332345953) Figure out why this fails on sdk 25 and below.
+        if (SDK_INT >= O) rule.waitUntil { view2.isFocused }
     }
 
     @Test
@@ -655,11 +662,11 @@
         rule.onNodeWithTag(composable).assertIsNotFocused()
     }
 
-    private fun ComposeContentTestRule.focusSearchBackward() {
+    private fun ComposeContentTestRule.focusSearchBackward(waitForIdle: Boolean = true) {
+        if (waitForIdle) waitForIdle()
         if (moveFocusProgrammatically) {
-            runOnIdle { focusManager.moveFocus(FocusDirection.Previous) }
+            runOnUiThread { focusManager.moveFocus(FocusDirection.Previous) }
         } else {
-            waitForIdle()
             InstrumentationRegistry
                 .getInstrumentation()
                 .sendKeySync(KeyEvent(0L, 0L, ACTION_DOWN, Key.Tab.nativeKeyCode, 0, Shift))
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/FocusSearchDownInteropTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/FocusSearchDownInteropTest.kt
index a471c4a..b96dda8 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/FocusSearchDownInteropTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/FocusSearchDownInteropTest.kt
@@ -16,7 +16,6 @@
 
 package androidx.compose.ui.viewinterop
 
-import android.os.Build.VERSION_CODES.P
 import android.view.KeyEvent
 import android.view.View
 import android.widget.LinearLayout
@@ -46,7 +45,6 @@
 import androidx.compose.ui.test.requestFocus
 import androidx.compose.ui.unit.dp
 import androidx.test.filters.MediumTest
-import androidx.test.filters.SdkSuppress
 import androidx.test.platform.app.InstrumentationRegistry
 import com.google.common.truth.Truth.assertThat
 import org.junit.Rule
@@ -188,33 +186,38 @@
         rule.runOnIdle { assertThat(view.isFocused).isTrue() }
     }
 
-    @SdkSuppress(minSdkVersion = P) // b/328143586
     @Test
     fun focusedComposableWithFocusableView_view_inLinearLayout() {
         // Arrange.
+        var isComposableFocused = false
         setContent {
-            AndroidView({
-                LinearLayout(it).apply {
+            AndroidView({ context ->
+                LinearLayout(context).apply {
                     orientation = VERTICAL
-                    addView(ComposeView(it).apply {
+                    addView(ComposeView(context).apply {
                         setContent {
-                            Column(Modifier.testTag(composable).focusable()) {
+                            Column(
+                                Modifier
+                                    .testTag(composable)
+                                    .onFocusChanged { isComposableFocused = it.isFocused }
+                                    .focusable()
+                            ) {
                                 AndroidView({ FocusableView(it).apply { view1 = this } })
                             }
                         }
                     })
-                    addView(FocusableView(it).apply { view2 = this })
+                    addView(FocusableView(context).apply { view2 = this })
                 }
             })
         }
         rule.onNodeWithTag(composable).requestFocus()
+        rule.waitUntil { isComposableFocused }
 
         // Act.
-        rule.focusSearchDown()
+        rule.focusSearchDown(waitForIdle = false)
 
         // Assert.
-        rule.onNodeWithTag(composable).assertIsNotFocused()
-        rule.runOnIdle { assertThat(view2.isFocused).isTrue() }
+        rule.waitUntil { !isComposableFocused && view2.isFocused }
     }
 
     @Test
@@ -652,11 +655,11 @@
         rule.onNodeWithTag(composable).assertIsNotFocused()
     }
 
-    private fun ComposeContentTestRule.focusSearchDown() {
+    private fun ComposeContentTestRule.focusSearchDown(waitForIdle: Boolean = true) {
+        if (waitForIdle) waitForIdle()
         if (moveFocusProgrammatically) {
-            runOnIdle { focusManager.moveFocus(FocusDirection.Down) }
+            runOnUiThread { focusManager.moveFocus(FocusDirection.Down) }
         } else {
-            waitForIdle()
             InstrumentationRegistry
                 .getInstrumentation()
                 .sendKeySync(KeyEvent(KeyEvent.ACTION_DOWN, Key.DirectionDown.nativeKeyCode))
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/FocusSearchForwardInteropTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/FocusSearchForwardInteropTest.kt
index 189bea1..1d22244 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/FocusSearchForwardInteropTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/FocusSearchForwardInteropTest.kt
@@ -17,7 +17,6 @@
 package androidx.compose.ui.viewinterop
 
 import android.os.Build.VERSION_CODES.O
-import android.os.Build.VERSION_CODES.P
 import android.view.KeyEvent as AndroidKeyEvent
 import android.view.KeyEvent.ACTION_DOWN
 import android.view.View
@@ -187,32 +186,37 @@
         rule.runOnIdle { assertThat(view.isFocused).isTrue() }
     }
 
-    @SdkSuppress(minSdkVersion = P) // b/328143586
     @Test
     fun focusedComposableWithFocusableView_view_inLinearLayout() {
         // Arrange.
+        var isComposableFocused = false
         setContent {
-            AndroidView({
-                LinearLayout(it).apply {
-                    addView(ComposeView(it).apply {
+            AndroidView({ context ->
+                LinearLayout(context).apply {
+                    addView(ComposeView(context).apply {
                         setContent {
-                            Row(Modifier.testTag(composable).focusable()) {
+                            Row(
+                                Modifier
+                                    .testTag(composable)
+                                    .onFocusChanged { isComposableFocused = it.isFocused }
+                                    .focusable()
+                            ) {
                                 AndroidView({ FocusableView(it).apply { view1 = this } })
                             }
                         }
                     })
-                    addView(FocusableView(it).apply { view2 = this })
+                    addView(FocusableView(context).apply { view2 = this })
                 }
             })
         }
         rule.onNodeWithTag(composable).requestFocus()
+        rule.waitUntil { isComposableFocused }
 
         // Act.
-        rule.focusSearchForward()
+        rule.focusSearchForward(waitForIdle = false)
 
         // Assert.
-        rule.onNodeWithTag(composable).assertIsNotFocused()
-        rule.runOnIdle { assertThat(view1.isFocused).isTrue() }
+        rule.waitUntil { !isComposableFocused && view1.isFocused }
     }
 
     @Test
@@ -639,11 +643,11 @@
         rule.onNodeWithTag(composable).assertIsNotFocused()
     }
 
-    private fun ComposeContentTestRule.focusSearchForward() {
+    private fun ComposeContentTestRule.focusSearchForward(waitForIdle: Boolean = true) {
+        if (waitForIdle) waitForIdle()
         if (moveFocusProgrammatically) {
-            runOnIdle { focusManager.moveFocus(FocusDirection.Next) }
+            runOnUiThread { focusManager.moveFocus(FocusDirection.Next) }
         } else {
-            waitForIdle()
             InstrumentationRegistry
                 .getInstrumentation()
                 .sendKeySync(AndroidKeyEvent(ACTION_DOWN, Key.Tab.nativeKeyCode))
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/FocusSearchLeftInteropTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/FocusSearchLeftInteropTest.kt
index 35e2277..fdfa90e 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/FocusSearchLeftInteropTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/FocusSearchLeftInteropTest.kt
@@ -18,7 +18,6 @@
 
 import android.os.Build.VERSION.SDK_INT
 import android.os.Build.VERSION_CODES.O
-import android.os.Build.VERSION_CODES.P
 import android.view.KeyEvent
 import android.view.View
 import android.widget.LinearLayout
@@ -48,7 +47,6 @@
 import androidx.compose.ui.test.requestFocus
 import androidx.compose.ui.unit.dp
 import androidx.test.filters.MediumTest
-import androidx.test.filters.SdkSuppress
 import androidx.test.platform.app.InstrumentationRegistry
 import com.google.common.truth.Truth.assertThat
 import org.junit.Rule
@@ -195,18 +193,23 @@
         rule.runOnIdle { assertThat(view.isFocused).isTrue() }
     }
 
-    @SdkSuppress(minSdkVersion = P) // b/328143586
     @Test
     fun focusedComposableWithFocusableView_view_inLinearLayout() {
         // Arrange.
+        var isComposableFocused = false
         setContent {
-            AndroidView({
-                LinearLayout(it).apply {
+            AndroidView({ context ->
+                LinearLayout(context).apply {
                     orientation = HORIZONTAL
-                    addView(FocusableView(it).apply { view2 = this })
-                    addView(ComposeView(it).apply {
+                    addView(FocusableView(context).apply { view2 = this })
+                    addView(ComposeView(context).apply {
                         setContent {
-                            Row(Modifier.testTag(composable).focusable()) {
+                            Row(
+                                Modifier
+                                    .testTag(composable)
+                                    .onFocusChanged { isComposableFocused = it.isFocused }
+                                    .focusable()
+                            ) {
                                 AndroidView({ FocusableView(it).apply { view1 = this } })
                             }
                         }
@@ -215,13 +218,13 @@
             })
         }
         rule.onNodeWithTag(composable).requestFocus()
+        rule.waitUntil { isComposableFocused }
 
         // Act.
-        rule.focusSearchLeft()
+        rule.focusSearchLeft(waitForIdle = false)
 
         // Assert.
-        rule.onNodeWithTag(composable).assertIsNotFocused()
-        rule.runOnIdle { assertThat(view2.isFocused).isTrue() }
+        rule.waitUntil { !isComposableFocused && view2.isFocused }
     }
 
     @Test
@@ -669,11 +672,11 @@
         rule.onNodeWithTag(composable).assertIsNotFocused()
     }
 
-    private fun ComposeContentTestRule.focusSearchLeft() {
+    private fun ComposeContentTestRule.focusSearchLeft(waitForIdle: Boolean = true) {
+        if (waitForIdle) waitForIdle()
         if (moveFocusProgrammatically) {
-            runOnIdle { focusManager.moveFocus(FocusDirection.Left) }
+            runOnUiThread { focusManager.moveFocus(FocusDirection.Left) }
         } else {
-            waitForIdle()
             InstrumentationRegistry
                 .getInstrumentation()
                 .sendKeySync(KeyEvent(KeyEvent.ACTION_DOWN, Key.DirectionLeft.nativeKeyCode))
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/FocusSearchRightInteropTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/FocusSearchRightInteropTest.kt
index 4eac80b..2d3eee6 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/FocusSearchRightInteropTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/FocusSearchRightInteropTest.kt
@@ -16,7 +16,6 @@
 
 package androidx.compose.ui.viewinterop
 
-import android.os.Build.VERSION_CODES.P
 import android.view.KeyEvent
 import android.view.View
 import android.widget.LinearLayout
@@ -46,7 +45,6 @@
 import androidx.compose.ui.test.requestFocus
 import androidx.compose.ui.unit.dp
 import androidx.test.filters.MediumTest
-import androidx.test.filters.SdkSuppress
 import androidx.test.platform.app.InstrumentationRegistry
 import com.google.common.truth.Truth.assertThat
 import org.junit.Rule
@@ -188,33 +186,38 @@
         rule.runOnIdle { assertThat(view.isFocused).isTrue() }
     }
 
-    @SdkSuppress(minSdkVersion = P) // b/328143586
     @Test
     fun focusedComposableWithFocusableView_view_inLinearLayout() {
         // Arrange.
+        var isComposableFocused = false
         setContent {
-            AndroidView({
-                LinearLayout(it).apply {
+            AndroidView({ context ->
+                LinearLayout(context).apply {
                     orientation = HORIZONTAL
-                    addView(ComposeView(it).apply {
+                    addView(ComposeView(context).apply {
                         setContent {
-                            Row(Modifier.testTag(composable).focusable()) {
+                            Row(
+                                Modifier
+                                    .testTag(composable)
+                                    .onFocusChanged { isComposableFocused = it.isFocused }
+                                    .focusable()
+                            ) {
                                 AndroidView({ FocusableView(it).apply { view1 = this } })
                             }
                         }
                     })
-                    addView(FocusableView(it).apply { view2 = this })
+                    addView(FocusableView(context).apply { view2 = this })
                 }
             })
         }
         rule.onNodeWithTag(composable).requestFocus()
+        rule.waitUntil { isComposableFocused }
 
         // Act.
-        rule.focusSearchRight()
+        rule.focusSearchRight(waitForIdle = false)
 
         // Assert.
-        rule.onNodeWithTag(composable).assertIsNotFocused()
-        rule.runOnIdle { assertThat(view2.isFocused).isTrue() }
+        rule.waitUntil { !isComposableFocused && view2.isFocused }
     }
 
     @Test
@@ -652,11 +655,11 @@
         rule.onNodeWithTag(composable).assertIsNotFocused()
     }
 
-    private fun ComposeContentTestRule.focusSearchRight() {
+    private fun ComposeContentTestRule.focusSearchRight(waitForIdle: Boolean = true) {
+        if (waitForIdle) waitForIdle()
         if (moveFocusProgrammatically) {
-            runOnIdle { focusManager.moveFocus(FocusDirection.Right) }
+            runOnUiThread { focusManager.moveFocus(FocusDirection.Right) }
         } else {
-            waitForIdle()
             InstrumentationRegistry
                 .getInstrumentation()
                 .sendKeySync(KeyEvent(KeyEvent.ACTION_DOWN, Key.DirectionRight.nativeKeyCode))
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/FocusSearchUpInteropTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/FocusSearchUpInteropTest.kt
index 4780c97..4d2998a 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/FocusSearchUpInteropTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/FocusSearchUpInteropTest.kt
@@ -18,7 +18,6 @@
 
 import android.os.Build.VERSION.SDK_INT
 import android.os.Build.VERSION_CODES.O
-import android.os.Build.VERSION_CODES.P
 import android.view.KeyEvent
 import android.view.View
 import android.widget.LinearLayout
@@ -48,7 +47,6 @@
 import androidx.compose.ui.test.requestFocus
 import androidx.compose.ui.unit.dp
 import androidx.test.filters.MediumTest
-import androidx.test.filters.SdkSuppress
 import androidx.test.platform.app.InstrumentationRegistry
 import com.google.common.truth.Truth.assertThat
 import org.junit.Rule
@@ -195,18 +193,23 @@
         rule.runOnIdle { assertThat(view.isFocused).isTrue() }
     }
 
-    @SdkSuppress(minSdkVersion = P) // b/328143586
     @Test
     fun focusedComposableWithFocusableView_view_inLinearLayout() {
         // Arrange.
+        var isComposableFocused = false
         setContent {
-            AndroidView({
-                LinearLayout(it).apply {
+            AndroidView({ context ->
+                LinearLayout(context).apply {
                     orientation = VERTICAL
-                    addView(FocusableView(it).apply { view2 = this })
-                    addView(ComposeView(it).apply {
+                    addView(FocusableView(context).apply { view2 = this })
+                    addView(ComposeView(context).apply {
                         setContent {
-                            Column(Modifier.testTag(composable).focusable()) {
+                            Column(
+                                Modifier
+                                    .testTag(composable)
+                                    .onFocusChanged { isComposableFocused = it.isFocused }
+                                    .focusable()
+                            ) {
                                 AndroidView({ FocusableView(it).apply { view1 = this } })
                             }
                         }
@@ -215,13 +218,13 @@
             })
         }
         rule.onNodeWithTag(composable).requestFocus()
+        rule.waitUntil { isComposableFocused }
 
         // Act.
-        rule.focusSearchUp()
+        rule.focusSearchUp(waitForIdle = false)
 
         // Assert.
-        rule.onNodeWithTag(composable).assertIsNotFocused()
-        rule.runOnIdle { assertThat(view2.isFocused).isTrue() }
+        rule.waitUntil { !isComposableFocused && view2.isFocused }
     }
 
     @Test
@@ -669,11 +672,11 @@
         rule.onNodeWithTag(composable).assertIsNotFocused()
     }
 
-    private fun ComposeContentTestRule.focusSearchUp() {
+    private fun ComposeContentTestRule.focusSearchUp(waitForIdle: Boolean = true) {
+        if (waitForIdle) waitForIdle()
         if (moveFocusProgrammatically) {
-            runOnIdle { focusManager.moveFocus(FocusDirection.Up) }
+            runOnUiThread { focusManager.moveFocus(FocusDirection.Up) }
         } else {
-            waitForIdle()
             InstrumentationRegistry
                 .getInstrumentation()
                 .sendKeySync(KeyEvent(KeyEvent.ACTION_DOWN, Key.DirectionUp.nativeKeyCode))
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/GraphicsLayerOwnerLayer.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/GraphicsLayerOwnerLayer.android.kt
index d99860d..cecabef 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/GraphicsLayerOwnerLayer.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/GraphicsLayerOwnerLayer.android.kt
@@ -110,7 +110,7 @@
 
     override fun updateDisplayList() {
         if (isDirty) {
-            graphicsLayer.buildLayer(density, layoutDirection, size) {
+            graphicsLayer.record(density, layoutDirection, size) {
                 drawIntoCanvas { canvas ->
                     drawBlock?.let { it(canvas) }
                 }
diff --git a/compose/ui/ui/src/androidMain/res/values-te/strings.xml b/compose/ui/ui/src/androidMain/res/values-te/strings.xml
index fdfdad5a..cecac59e 100644
--- a/compose/ui/ui/src/androidMain/res/values-te/strings.xml
+++ b/compose/ui/ui/src/androidMain/res/values-te/strings.xml
@@ -28,8 +28,8 @@
     <string name="tab" msgid="1672349317127674378">"ట్యాబ్"</string>
     <string name="navigation_menu" msgid="542007171693138492">"నావిగేషన్ మెనూ"</string>
     <string name="dropdown_menu" msgid="1890207353314751437">"డ్రాప్‌డౌన్ మెనూ"</string>
-    <string name="close_drawer" msgid="406453423630273620">"నావిగేషన్ మెనూను మూసివేయి"</string>
-    <string name="close_sheet" msgid="7573152094250666567">"షీట్‌ను మూసివేయి"</string>
+    <string name="close_drawer" msgid="406453423630273620">"నావిగేషన్ మెనూను మూసివేయండి"</string>
+    <string name="close_sheet" msgid="7573152094250666567">"షీట్‌ను మూసివేయండి"</string>
     <string name="default_error_message" msgid="8038256446254964252">"ఇన్‌పుట్ చెల్లదు"</string>
     <string name="default_popup_window_title" msgid="6312721426453364202">"పాప్-అప్ విండో"</string>
     <string name="range_start" msgid="7097486360902471446">"పరిధి ప్రారంభమయింది"</string>
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/draw/DrawModifier.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/draw/DrawModifier.kt
index afb75c1..9c4aca2 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/draw/DrawModifier.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/draw/DrawModifier.kt
@@ -335,15 +335,15 @@
         graphicsContextProvider!!.invoke().createGraphicsLayer()
 
     /**
-     * Create a [GraphicsLayer] with the [Density], [LayoutDirection] and [Size] are given from the
-     * provided [CacheDrawScope]
+     * Record the drawing commands into the [GraphicsLayer] with the [Density], [LayoutDirection]
+     * and [Size] are given from the provided [CacheDrawScope]
      */
-    fun GraphicsLayer.buildLayer(
+    fun GraphicsLayer.record(
         density: Density = this@CacheDrawScope,
         layoutDirection: LayoutDirection = this@CacheDrawScope.layoutDirection,
         size: IntSize = this@CacheDrawScope.size.toIntSize(),
         block: ContentDrawScope.() -> Unit
-    ): GraphicsLayer = buildLayer(density, layoutDirection, size) {
+    ) = record(density, layoutDirection, size) {
         val contentDrawScope = this@CacheDrawScope.contentDrawScope!!
         drawIntoCanvas { canvas ->
             contentDrawScope.draw(
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/graphics/GraphicsLayerScope.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/graphics/GraphicsLayerScope.kt
index b2ff604..9cf5728 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/graphics/GraphicsLayerScope.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/graphics/GraphicsLayerScope.kt
@@ -18,7 +18,7 @@
 
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.ComposableOpenTarget
-import androidx.compose.runtime.DisposableEffect
+import androidx.compose.runtime.RememberObserver
 import androidx.compose.runtime.remember
 import androidx.compose.ui.geometry.Size
 import androidx.compose.ui.graphics.layer.GraphicsLayer
@@ -225,6 +225,25 @@
         get() = Size.Unspecified
 }
 
+private class GraphicsContextObserver(
+    private val graphicsContext: GraphicsContext
+) : RememberObserver {
+
+    val graphicsLayer = graphicsContext.createGraphicsLayer()
+
+    override fun onRemembered() {
+        // NO-OP
+    }
+
+    override fun onForgotten() {
+        graphicsContext.releaseGraphicsLayer(graphicsLayer)
+    }
+
+    override fun onAbandoned() {
+        graphicsContext.releaseGraphicsLayer(graphicsLayer)
+    }
+}
+
 /**
  * Create a new [GraphicsLayer] instance that will automatically be released when the Composable
  * is disposed.
@@ -235,15 +254,7 @@
 @ComposableOpenTarget(-1)
 fun rememberGraphicsLayer(): GraphicsLayer {
     val graphicsContext = LocalGraphicsContext.current
-    val layer = remember {
-        graphicsContext.createGraphicsLayer()
-    }
-    DisposableEffect(layer) {
-        onDispose {
-            graphicsContext.releaseGraphicsLayer(layer)
-        }
-    }
-    return layer
+    return remember { GraphicsContextObserver(graphicsContext) }.graphicsLayer
 }
 
 /**
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/pointer/HitPathTracker.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/pointer/HitPathTracker.kt
index 8613ddd..dfa305b 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/pointer/HitPathTracker.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/pointer/HitPathTracker.kt
@@ -42,6 +42,9 @@
     /*@VisibleForTesting*/
     internal val root: NodeParent = NodeParent()
 
+    // Only used when removing duplicate Nodes from the Node tree ([removeDuplicateNode]).
+    private val vectorForHandlingDuplicateNodes: MutableVector<NodeParent> = mutableVectorOf()
+
     /**
      * Associates a [pointerId] to a list of hit [pointerInputNodes] and keeps track of them.
      *
@@ -57,6 +60,8 @@
     fun addHitPath(pointerId: PointerId, pointerInputNodes: List<Modifier.Node>) {
         var parent: NodeParent = root
         var merging = true
+        var nodeBranchPathToSkipDuringDuplicateNodeRemoval: Node? = null
+
         eachPin@ for (i in pointerInputNodes.indices) {
             val pointerInputNode = pointerInputNodes[i]
             if (merging) {
@@ -76,11 +81,53 @@
             val node = Node(pointerInputNode).apply {
                 pointerIds.add(pointerId)
             }
+
+            if (nodeBranchPathToSkipDuringDuplicateNodeRemoval == null) {
+                // Null means this is the first new Node created that will need a new branch path
+                // (possibly from a pre-existing cached version of the node chain).
+                // If that is the case, we need to skip this path when looking for duplicate
+                // nodes to remove (that may have previously existed somewhere else in the tree).
+                nodeBranchPathToSkipDuringDuplicateNodeRemoval = node
+            } else {
+                // Every node after the top new node (that is, the top Node in the new path)
+                // could have potentially existed somewhere else in the cached node tree, and
+                // we need to remove it if we are adding it to this new branch.
+                removeDuplicateNode(node, nodeBranchPathToSkipDuringDuplicateNodeRemoval)
+            }
+
             parent.children.add(node)
             parent = node
         }
     }
 
+    /*
+     * Removes duplicate nodes when using a cached version of the node tree. Uses breadth-first
+     * search for simplicity (and because the tree will be very small).
+     */
+    private fun removeDuplicateNode(
+        duplicateNodeToRemove: Node,
+        headOfPathToSkip: Node
+    ) {
+        vectorForHandlingDuplicateNodes.clear()
+        vectorForHandlingDuplicateNodes.add(root)
+
+        while (vectorForHandlingDuplicateNodes.isNotEmpty()) {
+            val parent = vectorForHandlingDuplicateNodes.removeAt(0)
+
+            for (index in parent.children.indices) {
+                val child = parent.children[index]
+                if (child == headOfPathToSkip) continue
+                if (child.modifierNode == duplicateNodeToRemove.modifierNode) {
+                    // Assumes there is only one unique Node in the tree (not copies).
+                    // This also removes all children attached below the node.
+                    parent.children.remove(child)
+                    return
+                }
+                vectorForHandlingDuplicateNodes.add(child)
+            }
+        }
+    }
+
     /**
      * Dispatches [internalPointerEvent] through the hierarchy.
      *
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode.kt
index c026b1f..0f58b93 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode.kt
@@ -16,7 +16,6 @@
 
 package androidx.compose.ui.layout
 
-import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.node.LayoutModifierNode
 import androidx.compose.ui.node.NodeMeasuringIntrinsics
 import androidx.compose.ui.unit.Constraints
@@ -42,65 +41,65 @@
  * measure results without modification. This can be overridden as needed. [approachMeasure]
  * will be invoked during the approach pass after lookahead.
  *
- * [isMeasurementApproachComplete] signals whether the measurement has already reached the
+ * [isMeasurementApproachInProgress] signals whether the measurement is in progress of approaching
  * destination size. It will be queried after the destination has been determined by the lookahead
  * pass, before [approachMeasure] is invoked. The lookahead size is provided to
- * [isMeasurementApproachComplete] for convenience in deciding whether the destination size has
+ * [isMeasurementApproachInProgress] for convenience in deciding whether the destination size has
  * been reached.
  *
- * [isPlacementApproachComplete] indicates whether the position has approached
+ * [isPlacementApproachInProgress] indicates whether the position is actively approaching
  * destination defined by the lookahead, hence it's a signal to the system for whether additional
- * approach placements are necessary. [isPlacementApproachComplete] will be invoked after the
+ * approach placements are necessary. [isPlacementApproachInProgress] will be invoked after the
  * destination position has been determined by lookahead pass, and before the placement phase in
  * [approachMeasure].
  *
  * **IMPORTANT**:
- * When both [isMeasurementApproachComplete] and [isPlacementApproachComplete] become true, the
+ * When both [isMeasurementApproachInProgress] and [isPlacementApproachInProgress] become false, the
  * approach is considered complete. Approach pass will subsequently snap the measurement and
  * placement to lookahead measurement and placement. Once approach is complete, [approachMeasure]
- * may never be invoked until either [isMeasurementApproachComplete] or
- * [isPlacementApproachComplete] becomes false again. Therefore it is important to ensure
+ * may never be invoked until either [isMeasurementApproachInProgress] or
+ * [isPlacementApproachInProgress] becomes true again. Therefore it is important to ensure
  * [approachMeasure] and [measure] result in the same measurement and placement when the approach is
  * complete. Otherwise, there may be visual discontinuity when we snap the measurement and placement
  * to lookahead.
  *
- * It is important to be accurate in [isPlacementApproachComplete] and
- * [isMeasurementApproachComplete]. A prolonged indication of incomplete approach will prevent the
+ * It is important to be accurate in [isPlacementApproachInProgress] and
+ * [isMeasurementApproachInProgress]. A prolonged indication of incomplete approach will prevent the
  * system from potentially skipping approach pass when possible.
  *
  * @sample androidx.compose.ui.samples.LookaheadLayoutCoordinatesSample
  */
 interface ApproachLayoutModifierNode : LayoutModifierNode {
     /**
-     * [isMeasurementApproachComplete] signals whether the measurement has already reached the
+     * [isMeasurementApproachInProgress] signals whether the measurement is currently approaching
      * destination size. It will be queried after the destination has been determined by the
      * lookahead pass, before [approachMeasure] is invoked. The lookahead size is provided to
-     * [isMeasurementApproachComplete] for convenience in deciding whether the destination size has
-     * been reached.
+     * [isMeasurementApproachInProgress] for convenience in deciding whether the destination size
+     * has been reached.
      *
-     * Note: It is important to be accurate in [isPlacementApproachComplete] and
-     * [isMeasurementApproachComplete]. A prolonged indication of incomplete approach will prevent
+     * Note: It is important to be accurate in [isPlacementApproachInProgress] and
+     * [isMeasurementApproachInProgress]. A prolonged indication of incomplete approach will prevent
      * the system from potentially skipping approach pass when possible.
      */
-    fun isMeasurementApproachComplete(lookaheadSize: IntSize): Boolean
+    fun isMeasurementApproachInProgress(lookaheadSize: IntSize): Boolean
 
     /**
-     * [isPlacementApproachComplete] indicates whether the position has approached destination
+     * [isPlacementApproachInProgress] indicates whether the position is approaching destination
      * defined by the lookahead, hence it's a signal to the system for whether additional
-     * approach placements are necessary. [isPlacementApproachComplete] will be invoked after the
+     * approach placements are necessary. [isPlacementApproachInProgress] will be invoked after the
      * destination position has been determined by lookahead pass, and before the placement phase in
      * [approachMeasure].
      *
-     * Note: It is important to be accurate in [isPlacementApproachComplete] and
-     * [isMeasurementApproachComplete]. A prolonged indication of incomplete approach will prevent
+     * Note: It is important to be accurate in [isPlacementApproachInProgress] and
+     * [isMeasurementApproachInProgress]. A prolonged indication of incomplete approach will prevent
      * the system from potentially skipping approach pass when possible.
      *
-     * By default, [isPlacementApproachComplete] returns true.
+     * By default, [isPlacementApproachInProgress] returns false.
      */
-    fun Placeable.PlacementScope.isPlacementApproachComplete(
+    fun Placeable.PlacementScope.isPlacementApproachInProgress(
         lookaheadCoordinates: LayoutCoordinates
     ): Boolean {
-        return true
+        return false
     }
 
     override fun MeasureScope.measure(
@@ -125,13 +124,12 @@
      * achieved.
      *
      * Note: [approachMeasure] is only guaranteed to be invoked when either
-     * [isPlacementApproachComplete] or [isMeasurementApproachComplete] is false. Otherwise, the
+     * [isMeasurementApproachInProgress] or [isMeasurementApproachInProgress] is true. Otherwise, the
      * system will consider the approach complete (i.e. destination reached) and may skip the
      * approach pass when possible.
      *
      * @sample androidx.compose.ui.samples.LookaheadLayoutCoordinatesSample
      */
-    @ExperimentalComposeUiApi
     fun ApproachMeasureScope.approachMeasure(
         measurable: Measurable,
         constraints: Constraints
@@ -140,7 +138,6 @@
     /**
      * The function used to calculate minIntrinsicWidth for the approach pass changes.
      */
-    @ExperimentalComposeUiApi
     fun ApproachIntrinsicMeasureScope.minApproachIntrinsicWidth(
         measurable: IntrinsicMeasurable,
         height: Int
@@ -156,7 +153,6 @@
     /**
      * The function used to calculate minIntrinsicHeight for the approach pass changes.
      */
-    @ExperimentalComposeUiApi
     fun ApproachIntrinsicMeasureScope.minApproachIntrinsicHeight(
         measurable: IntrinsicMeasurable,
         width: Int
@@ -172,7 +168,6 @@
     /**
      * The function used to calculate maxIntrinsicWidth for the approach pass changes.
      */
-    @ExperimentalComposeUiApi
     fun ApproachIntrinsicMeasureScope.maxApproachIntrinsicWidth(
         measurable: IntrinsicMeasurable,
         height: Int
@@ -188,7 +183,6 @@
     /**
      * The function used to calculate maxIntrinsicHeight for the approach pass changes.
      */
-    @ExperimentalComposeUiApi
     fun ApproachIntrinsicMeasureScope.maxApproachIntrinsicHeight(
         measurable: IntrinsicMeasurable,
         width: Int
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/ApproachMeasureScope.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/ApproachMeasureScope.kt
index 94a755c..94e83fc 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/ApproachMeasureScope.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/ApproachMeasureScope.kt
@@ -53,7 +53,6 @@
  * in [ApproachLayoutModifierNode] to morph the layout gradually in both size and position
  * to arrive at its precalculated bounds.
  */
-@ExperimentalComposeUiApi
 sealed interface ApproachMeasureScope : ApproachIntrinsicMeasureScope, MeasureScope
 
 internal class ApproachMeasureScopeImpl(
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/LookaheadScope.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/LookaheadScope.kt
index b5c58fa..bbdeb4f 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/LookaheadScope.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/LookaheadScope.kt
@@ -32,8 +32,6 @@
 import androidx.compose.ui.platform.InspectorInfo
 import androidx.compose.ui.unit.Constraints
 import androidx.compose.ui.unit.IntSize
-import kotlin.coroutines.CoroutineContext
-import kotlinx.coroutines.CoroutineScope
 
 /**
  * [LookaheadScope] creates a scope in which all layouts will first determine their destination
@@ -72,30 +70,6 @@
     )
 }
 
-@ExperimentalComposeUiApi
-@Deprecated(
-    "IntermediateMeasureScope has been renamed to ApproachMeasureScope",
-    replaceWith = ReplaceWith("ApproachMeasureScope")
-)
-interface IntermediateMeasureScope : ApproachMeasureScope, CoroutineScope, LookaheadScope
-
-@ExperimentalComposeUiApi
-@Deprecated(
-    "intermediateLayout has been replaced with approachLayout, and requires an" +
-        "additional parameter to signal if the approach is complete.",
-    replaceWith = ReplaceWith(
-        "approachLayout(isMeasurementApproachComplete = ," +
-            "approachMeasure = measure)"
-    )
-)
-fun Modifier.intermediateLayout(
-    @Suppress("DEPRECATION")
-    measure: IntermediateMeasureScope.(
-        measurable: Measurable,
-        constraints: Constraints,
-    ) -> MeasureResult,
-) = this then IntermediateLayoutElement(measure)
-
 /**
  * Creates an approach layout intended to help gradually approach the destination layout calculated
  * in the lookahead pass. This can be particularly helpful when the destination layout is
@@ -110,145 +84,77 @@
  * [Placeable.PlacementScope.coordinates]. The sample code below illustrates how that can be
  * achieved.
  *
- * [isMeasurementApproachComplete] signals whether the measurement has already reached the
+ * [isMeasurementApproachInProgress] signals whether the measurement is in progress of approaching
  * destination size. It will be queried after the destination has been determined by the lookahead
  * pass, before [approachMeasure] is invoked. The lookahead size is provided to
- * [isMeasurementApproachComplete] for convenience in deciding whether the destination size has
+ * [isMeasurementApproachInProgress] for convenience in deciding whether the destination size has
  * been reached.
  *
- * [isPlacementApproachComplete] indicates whether the position has approached
+ * [isMeasurementApproachInProgress] indicates whether the position is currently approaching
  * destination defined by the lookahead, hence it's a signal to the system for whether additional
- * approach placements are necessary. [isPlacementApproachComplete] will be invoked after the
+ * approach placements are necessary. [isPlacementApproachInProgress] will be invoked after the
  * destination position has been determined by lookahead pass, and before the placement phase in
  * [approachMeasure].
  *
- * Once both [isMeasurementApproachComplete] and [isPlacementApproachComplete] return true, the
+ * Once both [isMeasurementApproachInProgress] and [isPlacementApproachInProgress] return false, the
  * system may skip approach pass until additional approach passes are necessary as indicated by
- * [isMeasurementApproachComplete] and [isPlacementApproachComplete].
+ * [isMeasurementApproachInProgress] and [isPlacementApproachInProgress].
  *
  * **IMPORTANT**:
- * It is important to be accurate in [isPlacementApproachComplete] and
- * [isMeasurementApproachComplete]. A prolonged indication of incomplete approach will prevent the
+ * It is important to be accurate in [isPlacementApproachInProgress] and
+ * [isMeasurementApproachInProgress]. A prolonged indication of incomplete approach will prevent the
  * system from potentially skipping approach pass when possible.
  *
  * @see ApproachLayoutModifierNode
  * @sample androidx.compose.ui.samples.approachLayoutSample
  */
-@ExperimentalComposeUiApi
 fun Modifier.approachLayout(
-    isMeasurementApproachComplete: (lookaheadSize: IntSize) -> Boolean,
-    isPlacementApproachComplete: Placeable.PlacementScope.(
+    isMeasurementApproachInProgress: (lookaheadSize: IntSize) -> Boolean,
+    isPlacementApproachInProgress: Placeable.PlacementScope.(
         lookaheadCoordinates: LayoutCoordinates
-    ) -> Boolean = defaultPlacementApproachComplete,
+    ) -> Boolean = defaultPlacementApproachInProgress,
     approachMeasure: ApproachMeasureScope.(
         measurable: Measurable,
         constraints: Constraints,
     ) -> MeasureResult,
 ): Modifier = this then ApproachLayoutElement(
-    isMeasurementApproachComplete = isMeasurementApproachComplete,
-    isPlacementApproachComplete = isPlacementApproachComplete,
+    isMeasurementApproachInProgress = isMeasurementApproachInProgress,
+    isPlacementApproachInProgress = isPlacementApproachInProgress,
     approachMeasure = approachMeasure
 )
 
-private val defaultPlacementApproachComplete: Placeable.PlacementScope.(
+private val defaultPlacementApproachInProgress: Placeable.PlacementScope.(
     lookaheadCoordinates: LayoutCoordinates
-) -> Boolean = { true }
+) -> Boolean = { false }
 
-@Suppress("DEPRECATION")
-@OptIn(ExperimentalComposeUiApi::class)
-private data class IntermediateLayoutElement(
-    val measure: IntermediateMeasureScope.(
-        measurable: Measurable,
-        constraints: Constraints,
-    ) -> MeasureResult,
-) : ModifierNodeElement<IntermediateLayoutModifierNodeImpl>() {
-    override fun create() =
-        IntermediateLayoutModifierNodeImpl(
-            measure,
-        )
-
-    override fun update(node: IntermediateLayoutModifierNodeImpl) {
-        node.measureBlock = measure
-    }
-
-    override fun InspectorInfo.inspectableProperties() {
-        name = "intermediateLayout"
-        properties["measure"] = measure
-    }
-}
-
-@Suppress("DEPRECATION")
-@OptIn(ExperimentalComposeUiApi::class)
-private class IntermediateLayoutModifierNodeImpl(
-    var measureBlock: IntermediateMeasureScope.(
-        measurable: Measurable,
-        constraints: Constraints,
-    ) -> MeasureResult,
-) : ApproachLayoutModifierNode, Modifier.Node() {
-    private var intermediateMeasureScope: IntermediateMeasureScopeImpl? = null
-
-    private inner class IntermediateMeasureScopeImpl(
-        val approachScope: ApproachMeasureScopeImpl
-    ) : IntermediateMeasureScope, LookaheadScope by approachScope,
-        ApproachMeasureScope by approachScope, CoroutineScope {
-        override val coroutineContext: CoroutineContext
-            get() = this@IntermediateLayoutModifierNodeImpl.coroutineScope.coroutineContext
-    }
-
-    override fun isMeasurementApproachComplete(lookaheadSize: IntSize): Boolean {
-        // Important: Returning false here is strongly discouraged as it'll prevent layout
-        // performance optimization. This ModifierNodeImpl is only intended to help devs transition
-        // over to the new ApproachLayoutNodeModifier, and it'll be removed after a couple of
-        // releases.
-        return false
-    }
-
-    override fun ApproachMeasureScope.approachMeasure(
-        measurable: Measurable,
-        constraints: Constraints
-    ): MeasureResult {
-        val scope = intermediateMeasureScope
-        val newScope = if (scope?.approachScope != this) {
-            IntermediateMeasureScopeImpl(this as ApproachMeasureScopeImpl)
-        } else {
-            scope
-        }
-        intermediateMeasureScope = newScope
-        return with(newScope) {
-            measureBlock(measurable, constraints)
-        }
-    }
-}
-
-@OptIn(ExperimentalComposeUiApi::class)
 private data class ApproachLayoutElement(
     val approachMeasure: ApproachMeasureScope.(
         measurable: Measurable,
         constraints: Constraints,
     ) -> MeasureResult,
-    val isMeasurementApproachComplete: (IntSize) -> Boolean,
-    val isPlacementApproachComplete: Placeable.PlacementScope.(
+    val isMeasurementApproachInProgress: (IntSize) -> Boolean,
+    val isPlacementApproachInProgress: Placeable.PlacementScope.(
         lookaheadCoordinates: LayoutCoordinates
-    ) -> Boolean = defaultPlacementApproachComplete,
+    ) -> Boolean = defaultPlacementApproachInProgress,
 ) : ModifierNodeElement<ApproachLayoutModifierNodeImpl>() {
     override fun create() =
         ApproachLayoutModifierNodeImpl(
             approachMeasure,
-            isMeasurementApproachComplete,
-            isPlacementApproachComplete
+            isMeasurementApproachInProgress,
+            isPlacementApproachInProgress
         )
 
     override fun update(node: ApproachLayoutModifierNodeImpl) {
         node.measureBlock = approachMeasure
-        node.isMeasurementApproachComplete = isMeasurementApproachComplete
-        node.isPlacementApproachComplete = isPlacementApproachComplete
+        node.isMeasurementApproachInProgress = isMeasurementApproachInProgress
+        node.isPlacementApproachInProgress = isPlacementApproachInProgress
     }
 
     override fun InspectorInfo.inspectableProperties() {
         name = "approachLayout"
         properties["approachMeasure"] = approachMeasure
-        properties["isMeasurementApproachComplete"] = isMeasurementApproachComplete
-        properties["isPlacementApproachComplete"] = isPlacementApproachComplete
+        properties["isMeasurementApproachInProgress"] = isMeasurementApproachInProgress
+        properties["isPlacementApproachInProgress"] = isPlacementApproachInProgress
     }
 }
 
@@ -258,18 +164,18 @@
         measurable: Measurable,
         constraints: Constraints,
     ) -> MeasureResult,
-    var isMeasurementApproachComplete: (IntSize) -> Boolean,
-    var isPlacementApproachComplete:
+    var isMeasurementApproachInProgress: (IntSize) -> Boolean,
+    var isPlacementApproachInProgress:
     Placeable.PlacementScope.(LayoutCoordinates) -> Boolean,
 ) : ApproachLayoutModifierNode, Modifier.Node() {
-    override fun isMeasurementApproachComplete(lookaheadSize: IntSize): Boolean {
-        return isMeasurementApproachComplete.invoke(lookaheadSize)
+    override fun isMeasurementApproachInProgress(lookaheadSize: IntSize): Boolean {
+        return isMeasurementApproachInProgress.invoke(lookaheadSize)
     }
 
-    override fun Placeable.PlacementScope.isPlacementApproachComplete(
+    override fun Placeable.PlacementScope.isPlacementApproachInProgress(
         lookaheadCoordinates: LayoutCoordinates
     ): Boolean {
-        return isPlacementApproachComplete.invoke(this, lookaheadCoordinates)
+        return isPlacementApproachInProgress.invoke(this, lookaheadCoordinates)
     }
 
     override fun ApproachMeasureScope.approachMeasure(
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutModifierNodeCoordinator.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutModifierNodeCoordinator.kt
index e491fd1e..fb22252 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutModifierNodeCoordinator.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutModifierNodeCoordinator.kt
@@ -158,7 +158,7 @@
                 // approachMeasureScope is created/updated when layoutModifierNode is set. An
                 // ApproachLayoutModifierNode will lead to a non-null approachMeasureScope.
                 with(scope.approachNode) {
-                    scope.approachMeasureRequired = !isMeasurementApproachComplete(
+                    scope.approachMeasureRequired = isMeasurementApproachInProgress(
                         scope.lookaheadSize
                     ) || constraints != lookaheadConstraints
                     if (!scope.approachMeasureRequired) {
@@ -257,7 +257,7 @@
         approachMeasureScope?.let {
             with(it.approachNode) {
                 val approachComplete = with(placementScope) {
-                    isPlacementApproachComplete(
+                    !isPlacementApproachInProgress(
                         lookaheadDelegate!!.lookaheadLayoutCoordinates
                     ) && !it.approachMeasureRequired &&
                         size == lookaheadDelegate?.size &&
diff --git a/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/draw/DesktopDrawingPrebuiltGraphicsLayerTest.kt b/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/draw/DesktopDrawingPrebuiltGraphicsLayerTest.kt
index 00083ea..daeb08a 100644
--- a/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/draw/DesktopDrawingPrebuiltGraphicsLayerTest.kt
+++ b/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/draw/DesktopDrawingPrebuiltGraphicsLayerTest.kt
@@ -332,7 +332,7 @@
         layer: GraphicsLayer = obtainLayer()
     ): Modifier {
         return drawWithContent {
-            layer.buildLayer {
+            layer.record {
                 this@drawWithContent.drawContent()
             }
             drawLayer(layer)
diff --git a/core/core-i18n/lint-baseline.xml b/core/core-i18n/lint-baseline.xml
deleted file mode 100644
index 25cd21f..0000000
--- a/core/core-i18n/lint-baseline.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.4.0-alpha12" type="baseline" client="gradle" dependencies="false" name="AGP (8.4.0-alpha12)" variant="all" version="8.4.0-alpha12">
-
-    <issue
-        id="PrereleaseSdkCoreDependency"
-        message="Prelease SDK check isAtLeastV cannot be called as this project has a versioned dependency on androidx.core:core"
-        errorLine1="            &quot;V: &quot; + BuildCompat.isAtLeastV()"
-        errorLine2="                    ~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/core/i18n/DateTimeFormatterTest.kt"/>
-    </issue>
-
-</issues>
diff --git a/core/core/api/current.txt b/core/core/api/current.txt
index 11c7e35..cc704bd 100644
--- a/core/core/api/current.txt
+++ b/core/core/api/current.txt
@@ -5,8 +5,8 @@
     method public static String capabilityToString(int);
     method public static String feedbackTypeToString(int);
     method public static String? flagToString(int);
-    method public static int getCapabilities(android.accessibilityservice.AccessibilityServiceInfo);
-    method public static String? loadDescription(android.accessibilityservice.AccessibilityServiceInfo, android.content.pm.PackageManager);
+    method @Deprecated @ReplaceWith(expression="info.getCapabilities()") public static int getCapabilities(android.accessibilityservice.AccessibilityServiceInfo);
+    method @Deprecated @ReplaceWith(expression="info.loadDescription(packageManager)") public static String? loadDescription(android.accessibilityservice.AccessibilityServiceInfo, android.content.pm.PackageManager);
     field public static final int CAPABILITY_CAN_FILTER_KEY_EVENTS = 8; // 0x8
     field public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 4; // 0x4
     field public static final int CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION = 2; // 0x2
@@ -56,7 +56,7 @@
   }
 
   public final class ActivityManagerCompat {
-    method public static boolean isLowRamDevice(android.app.ActivityManager);
+    method @Deprecated @ReplaceWith(expression="activityManager.isLowRamDevice()") public static boolean isLowRamDevice(android.app.ActivityManager);
   }
 
   public class ActivityOptionsCompat {
@@ -83,7 +83,7 @@
     method public static boolean canScheduleExactAlarms(android.app.AlarmManager);
     method public static void setAlarmClock(android.app.AlarmManager, long, android.app.PendingIntent, android.app.PendingIntent);
     method public static void setAndAllowWhileIdle(android.app.AlarmManager, int, long, android.app.PendingIntent);
-    method public static void setExact(android.app.AlarmManager, int, long, android.app.PendingIntent);
+    method @Deprecated @ReplaceWith(expression="alarmManager.setExact(type, triggerAtMillis, operation)") public static void setExact(android.app.AlarmManager, int, long, android.app.PendingIntent);
     method public static void setExactAndAllowWhileIdle(android.app.AlarmManager, int, long, android.app.PendingIntent);
   }
 
@@ -121,8 +121,8 @@
   }
 
   @Deprecated public final class BundleCompat {
-    method @Deprecated public static android.os.IBinder? getBinder(android.os.Bundle, String?);
-    method @Deprecated public static void putBinder(android.os.Bundle, String?, android.os.IBinder?);
+    method @Deprecated @ReplaceWith(expression="bundle.getBinder(key)") public static android.os.IBinder? getBinder(android.os.Bundle, String?);
+    method @Deprecated @ReplaceWith(expression="bundle.putBinder(key, binder)") public static void putBinder(android.os.Bundle, String?, android.os.IBinder?);
   }
 
   public class DialogCompat {
@@ -199,8 +199,8 @@
     method public static String? getParentActivityName(android.app.Activity);
     method public static String? getParentActivityName(android.content.Context, android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
     method public static void navigateUpFromSameTask(android.app.Activity);
-    method public static void navigateUpTo(android.app.Activity, android.content.Intent);
-    method public static boolean shouldUpRecreateTask(android.app.Activity, android.content.Intent);
+    method @Deprecated @ReplaceWith(expression="sourceActivity.navigateUpTo(upIntent)") public static void navigateUpTo(android.app.Activity, android.content.Intent);
+    method @Deprecated @ReplaceWith(expression="sourceActivity.shouldUpRecreateTask(targetIntent)") public static boolean shouldUpRecreateTask(android.app.Activity, android.content.Intent);
     field public static final String PARENT_ACTIVITY = "android.support.PARENT_ACTIVITY";
   }
 
@@ -273,7 +273,7 @@
     method public static CharSequence? getContentInfo(android.app.Notification);
     method public static CharSequence? getContentText(android.app.Notification);
     method public static CharSequence? getContentTitle(android.app.Notification);
-    method public static android.os.Bundle? getExtras(android.app.Notification);
+    method @Deprecated @ReplaceWith(expression="notification.extras") public static android.os.Bundle? getExtras(android.app.Notification);
     method public static String? getGroup(android.app.Notification);
     method public static int getGroupAlertBehavior(android.app.Notification);
     method @RequiresApi(21) public static java.util.List<androidx.core.app.NotificationCompat.Action!> getInvisibleActions(android.app.Notification);
@@ -1109,11 +1109,11 @@
     method public static java.io.File? getDataDir(android.content.Context);
     method public static android.view.Display getDisplayOrDefault(@DisplayContext android.content.Context);
     method public static android.graphics.drawable.Drawable? getDrawable(android.content.Context, @DrawableRes int);
-    method public static java.io.File![] getExternalCacheDirs(android.content.Context);
-    method public static java.io.File![] getExternalFilesDirs(android.content.Context, String?);
+    method @Deprecated @ReplaceWith(expression="context.getExternalCacheDirs()") public static java.io.File![] getExternalCacheDirs(android.content.Context);
+    method @Deprecated @ReplaceWith(expression="context.getExternalFilesDirs(type)") public static java.io.File![] getExternalFilesDirs(android.content.Context, String?);
     method public static java.util.concurrent.Executor getMainExecutor(android.content.Context);
     method public static java.io.File? getNoBackupFilesDir(android.content.Context);
-    method public static java.io.File![] getObbDirs(android.content.Context);
+    method @Deprecated @ReplaceWith(expression="context.getObbDirs()") public static java.io.File![] getObbDirs(android.content.Context);
     method public static String getString(android.content.Context, int);
     method public static <T> T? getSystemService(android.content.Context, Class<T!>);
     method public static String? getSystemServiceName(android.content.Context, Class<?>);
@@ -1122,7 +1122,7 @@
     method public static android.content.Intent? registerReceiver(android.content.Context, android.content.BroadcastReceiver?, android.content.IntentFilter, String?, android.os.Handler?, int);
     method public static boolean startActivities(android.content.Context, android.content.Intent![]);
     method public static boolean startActivities(android.content.Context, android.content.Intent![], android.os.Bundle?);
-    method public static void startActivity(android.content.Context, android.content.Intent, android.os.Bundle?);
+    method @Deprecated @ReplaceWith(expression="context.startActivity(intent, options)") public static void startActivity(android.content.Context, android.content.Intent, android.os.Bundle?);
     method public static void startForegroundService(android.content.Context, android.content.Intent);
     field public static final int RECEIVER_EXPORTED = 2; // 0x2
     field public static final int RECEIVER_NOT_EXPORTED = 4; // 0x4
@@ -1428,9 +1428,9 @@
 
   public final class BitmapCompat {
     method public static android.graphics.Bitmap createScaledBitmap(android.graphics.Bitmap, int, int, android.graphics.Rect?, boolean);
-    method public static int getAllocationByteCount(android.graphics.Bitmap);
-    method public static boolean hasMipMap(android.graphics.Bitmap);
-    method public static void setHasMipMap(android.graphics.Bitmap, boolean);
+    method @Deprecated @ReplaceWith(expression="bitmap.getAllocationByteCount()") public static int getAllocationByteCount(android.graphics.Bitmap);
+    method @Deprecated @ReplaceWith(expression="bitmap.hasMipMap()") public static boolean hasMipMap(android.graphics.Bitmap);
+    method @Deprecated @ReplaceWith(expression="bitmap.setHasMipMap(hasMipMap)") public static void setHasMipMap(android.graphics.Bitmap, boolean);
   }
 
   public class BlendModeColorFilterCompat {
@@ -1558,13 +1558,13 @@
     method public static void applyTheme(android.graphics.drawable.Drawable, android.content.res.Resources.Theme);
     method public static boolean canApplyTheme(android.graphics.drawable.Drawable);
     method public static void clearColorFilter(android.graphics.drawable.Drawable);
-    method public static int getAlpha(android.graphics.drawable.Drawable);
+    method @Deprecated @ReplaceWith(expression="drawable.getAlpha()") public static int getAlpha(android.graphics.drawable.Drawable);
     method public static android.graphics.ColorFilter? getColorFilter(android.graphics.drawable.Drawable);
     method public static int getLayoutDirection(android.graphics.drawable.Drawable);
     method public static void inflate(android.graphics.drawable.Drawable, android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet, android.content.res.Resources.Theme?) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public static boolean isAutoMirrored(android.graphics.drawable.Drawable);
-    method @Deprecated public static void jumpToCurrentState(android.graphics.drawable.Drawable);
-    method public static void setAutoMirrored(android.graphics.drawable.Drawable, boolean);
+    method @Deprecated @ReplaceWith(expression="drawable.isAutoMirrored()") public static boolean isAutoMirrored(android.graphics.drawable.Drawable);
+    method @Deprecated @ReplaceWith(expression="drawable.jumpToCurrentState()") public static void jumpToCurrentState(android.graphics.drawable.Drawable);
+    method @Deprecated @ReplaceWith(expression="drawable.setAutoMirrored(mirrored)") public static void setAutoMirrored(android.graphics.drawable.Drawable, boolean);
     method public static void setHotspot(android.graphics.drawable.Drawable, float, float);
     method public static void setHotspotBounds(android.graphics.drawable.Drawable, int, int, int, int);
     method public static boolean setLayoutDirection(android.graphics.drawable.Drawable, int);
@@ -1690,7 +1690,7 @@
   public final class LocationCompat {
     method public static float getBearingAccuracyDegrees(android.location.Location);
     method public static long getElapsedRealtimeMillis(android.location.Location);
-    method public static long getElapsedRealtimeNanos(android.location.Location);
+    method @Deprecated @ReplaceWith(expression="location.getElapsedRealtimeNanos()") public static long getElapsedRealtimeNanos(android.location.Location);
     method @FloatRange(from=0.0) public static float getMslAltitudeAccuracyMeters(android.location.Location);
     method public static double getMslAltitudeMeters(android.location.Location);
     method public static float getSpeedAccuracyMetersPerSecond(android.location.Location);
@@ -1700,7 +1700,7 @@
     method public static boolean hasMslAltitudeAccuracy(android.location.Location);
     method public static boolean hasSpeedAccuracy(android.location.Location);
     method public static boolean hasVerticalAccuracy(android.location.Location);
-    method public static boolean isMock(android.location.Location);
+    method @Deprecated @ReplaceWith(expression="location.isFromMockProvider()") public static boolean isMock(android.location.Location);
     method public static void removeBearingAccuracy(android.location.Location);
     method public static void removeMslAltitude(android.location.Location);
     method public static void removeMslAltitudeAccuracy(android.location.Location);
@@ -1803,7 +1803,7 @@
   public final class ConnectivityManagerCompat {
     method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public static android.net.NetworkInfo? getNetworkInfoFromBroadcast(android.net.ConnectivityManager, android.content.Intent);
     method public static int getRestrictBackgroundStatus(android.net.ConnectivityManager);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public static boolean isActiveNetworkMetered(android.net.ConnectivityManager);
+    method @Deprecated @ReplaceWith(expression="cm.isActiveNetworkMetered()") @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public static boolean isActiveNetworkMetered(android.net.ConnectivityManager);
     field public static final int RESTRICT_BACKGROUND_STATUS_DISABLED = 1; // 0x1
     field public static final int RESTRICT_BACKGROUND_STATUS_ENABLED = 3; // 0x3
     field public static final int RESTRICT_BACKGROUND_STATUS_WHITELISTED = 2; // 0x2
@@ -1871,13 +1871,13 @@
   }
 
   public final class BundleCompat {
-    method @Deprecated public static android.os.IBinder? getBinder(android.os.Bundle, String?);
+    method @Deprecated @ReplaceWith(expression="bundle.getBinder(key)") public static android.os.IBinder? getBinder(android.os.Bundle, String?);
     method public static <T> T? getParcelable(android.os.Bundle, String?, Class<T!>);
     method public static android.os.Parcelable![]? getParcelableArray(android.os.Bundle, String?, Class<? extends android.os.Parcelable!>);
     method public static <T> java.util.ArrayList<T!>? getParcelableArrayList(android.os.Bundle, String?, Class<? extends T!>);
     method public static <T extends java.io.Serializable> T? getSerializable(android.os.Bundle, String?, Class<T!>);
     method public static <T> android.util.SparseArray<T!>? getSparseParcelableArray(android.os.Bundle, String?, Class<? extends T!>);
-    method @Deprecated public static void putBinder(android.os.Bundle, String?, android.os.IBinder?);
+    method @Deprecated @ReplaceWith(expression="bundle.putBinder(key, binder)") public static void putBinder(android.os.Bundle, String?, android.os.IBinder?);
   }
 
   @Deprecated public final class CancellationSignal {
@@ -1956,7 +1956,7 @@
     method @RequiresApi(api=android.os.Build.VERSION_CODES.Q) public static <T> java.util.List<T!> readParcelableList(android.os.Parcel, java.util.List<T!>, ClassLoader?, Class<T!>);
     method public static <T extends java.io.Serializable> T? readSerializable(android.os.Parcel, ClassLoader?, Class<T!>);
     method public static <T> android.util.SparseArray<T!>? readSparseArray(android.os.Parcel, ClassLoader?, Class<? extends T!>);
-    method public static void writeBoolean(android.os.Parcel, boolean);
+    method @Deprecated @ReplaceWith(expression="out.writeInt(value ? 1 : 0)") public static void writeBoolean(android.os.Parcel, boolean);
   }
 
   @Deprecated public final class ParcelableCompat {
@@ -2592,18 +2592,18 @@
 
   @Deprecated public final class MarginLayoutParamsCompat {
     method @Deprecated public static int getLayoutDirection(android.view.ViewGroup.MarginLayoutParams);
-    method @Deprecated public static int getMarginEnd(android.view.ViewGroup.MarginLayoutParams);
-    method @Deprecated public static int getMarginStart(android.view.ViewGroup.MarginLayoutParams);
-    method @Deprecated public static boolean isMarginRelative(android.view.ViewGroup.MarginLayoutParams);
-    method @Deprecated public static void resolveLayoutDirection(android.view.ViewGroup.MarginLayoutParams, int);
-    method @Deprecated public static void setLayoutDirection(android.view.ViewGroup.MarginLayoutParams, int);
-    method @Deprecated public static void setMarginEnd(android.view.ViewGroup.MarginLayoutParams, int);
-    method @Deprecated public static void setMarginStart(android.view.ViewGroup.MarginLayoutParams, int);
+    method @Deprecated @ReplaceWith(expression="lp.getMarginEnd()") public static int getMarginEnd(android.view.ViewGroup.MarginLayoutParams);
+    method @Deprecated @ReplaceWith(expression="lp.getMarginStart()") public static int getMarginStart(android.view.ViewGroup.MarginLayoutParams);
+    method @Deprecated @ReplaceWith(expression="lp.isMarginRelative()") public static boolean isMarginRelative(android.view.ViewGroup.MarginLayoutParams);
+    method @Deprecated @ReplaceWith(expression="lp.resolveLayoutDirection(layoutDirection)") public static void resolveLayoutDirection(android.view.ViewGroup.MarginLayoutParams, int);
+    method @Deprecated @ReplaceWith(expression="lp.setLayoutDirection(layoutDirection)") public static void setLayoutDirection(android.view.ViewGroup.MarginLayoutParams, int);
+    method @Deprecated @ReplaceWith(expression="lp.setMarginEnd(marginEnd)") public static void setMarginEnd(android.view.ViewGroup.MarginLayoutParams, int);
+    method @Deprecated @ReplaceWith(expression="lp.setMarginStart(marginStart)") public static void setMarginStart(android.view.ViewGroup.MarginLayoutParams, int);
   }
 
   public final class MenuCompat {
     method public static void setGroupDividerEnabled(android.view.Menu, boolean);
-    method @Deprecated public static void setShowAsAction(android.view.MenuItem!, int);
+    method @Deprecated @ReplaceWith(expression="item.setShowAsAction(actionEnum)") public static void setShowAsAction(android.view.MenuItem!, int);
   }
 
   public interface MenuHost {
@@ -2627,20 +2627,20 @@
   }
 
   public final class MenuItemCompat {
-    method @Deprecated public static boolean collapseActionView(android.view.MenuItem!);
-    method @Deprecated public static boolean expandActionView(android.view.MenuItem!);
+    method @Deprecated @ReplaceWith(expression="item.collapseActionView()") public static boolean collapseActionView(android.view.MenuItem!);
+    method @Deprecated @ReplaceWith(expression="item.expandActionView()") public static boolean expandActionView(android.view.MenuItem!);
     method public static androidx.core.view.ActionProvider? getActionProvider(android.view.MenuItem);
-    method @Deprecated public static android.view.View! getActionView(android.view.MenuItem!);
+    method @Deprecated @ReplaceWith(expression="item.getActionView()") public static android.view.View! getActionView(android.view.MenuItem!);
     method public static int getAlphabeticModifiers(android.view.MenuItem);
     method public static CharSequence? getContentDescription(android.view.MenuItem);
     method public static android.content.res.ColorStateList? getIconTintList(android.view.MenuItem);
     method public static android.graphics.PorterDuff.Mode? getIconTintMode(android.view.MenuItem);
     method public static int getNumericModifiers(android.view.MenuItem);
     method public static CharSequence? getTooltipText(android.view.MenuItem);
-    method @Deprecated public static boolean isActionViewExpanded(android.view.MenuItem!);
+    method @Deprecated @ReplaceWith(expression="item.isActionViewExpanded()") public static boolean isActionViewExpanded(android.view.MenuItem!);
     method public static android.view.MenuItem? setActionProvider(android.view.MenuItem, androidx.core.view.ActionProvider?);
-    method @Deprecated public static android.view.MenuItem! setActionView(android.view.MenuItem!, android.view.View!);
-    method @Deprecated public static android.view.MenuItem! setActionView(android.view.MenuItem!, int);
+    method @Deprecated @ReplaceWith(expression="item.setActionView(view)") public static android.view.MenuItem! setActionView(android.view.MenuItem!, android.view.View!);
+    method @Deprecated @ReplaceWith(expression="item.setActionView(resId)") public static android.view.MenuItem! setActionView(android.view.MenuItem!, int);
     method public static void setAlphabeticShortcut(android.view.MenuItem, char, int);
     method public static void setContentDescription(android.view.MenuItem, CharSequence?);
     method public static void setIconTintList(android.view.MenuItem, android.content.res.ColorStateList?);
@@ -2648,7 +2648,7 @@
     method public static void setNumericShortcut(android.view.MenuItem, char, int);
     method @Deprecated public static android.view.MenuItem! setOnActionExpandListener(android.view.MenuItem!, androidx.core.view.MenuItemCompat.OnActionExpandListener!);
     method public static void setShortcut(android.view.MenuItem, char, char, int, int);
-    method @Deprecated public static void setShowAsAction(android.view.MenuItem!, int);
+    method @Deprecated @ReplaceWith(expression="item.setShowAsAction(actionEnum)") public static void setShowAsAction(android.view.MenuItem!, int);
     method public static void setTooltipText(android.view.MenuItem, CharSequence?);
     field @Deprecated public static final int SHOW_AS_ACTION_ALWAYS = 2; // 0x2
     field @Deprecated public static final int SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW = 8; // 0x8
@@ -2670,17 +2670,17 @@
   }
 
   public final class MotionEventCompat {
-    method @Deprecated public static int findPointerIndex(android.view.MotionEvent!, int);
-    method @Deprecated public static int getActionIndex(android.view.MotionEvent!);
-    method @Deprecated public static int getActionMasked(android.view.MotionEvent!);
-    method @Deprecated public static float getAxisValue(android.view.MotionEvent!, int);
-    method @Deprecated public static float getAxisValue(android.view.MotionEvent!, int, int);
-    method @Deprecated public static int getButtonState(android.view.MotionEvent!);
-    method @Deprecated public static int getPointerCount(android.view.MotionEvent!);
-    method @Deprecated public static int getPointerId(android.view.MotionEvent!, int);
-    method @Deprecated public static int getSource(android.view.MotionEvent!);
-    method @Deprecated public static float getX(android.view.MotionEvent!, int);
-    method @Deprecated public static float getY(android.view.MotionEvent!, int);
+    method @Deprecated @ReplaceWith(expression="event.findPointerIndex(pointerId)") public static int findPointerIndex(android.view.MotionEvent!, int);
+    method @Deprecated @ReplaceWith(expression="event.getActionIndex()") public static int getActionIndex(android.view.MotionEvent!);
+    method @Deprecated @ReplaceWith(expression="event.getActionMasked()") public static int getActionMasked(android.view.MotionEvent!);
+    method @Deprecated @ReplaceWith(expression="event.getAxisValue(axis)") public static float getAxisValue(android.view.MotionEvent!, int);
+    method @Deprecated @ReplaceWith(expression="event.getAxisValue(axis, pointerIndex)") public static float getAxisValue(android.view.MotionEvent!, int, int);
+    method @Deprecated @ReplaceWith(expression="event.getButtonState()") public static int getButtonState(android.view.MotionEvent!);
+    method @Deprecated @ReplaceWith(expression="event.getPointerCount()") public static int getPointerCount(android.view.MotionEvent!);
+    method @Deprecated @ReplaceWith(expression="event.getPointerId(pointerIndex)") public static int getPointerId(android.view.MotionEvent!, int);
+    method @Deprecated @ReplaceWith(expression="event.getSource()") public static int getSource(android.view.MotionEvent!);
+    method @Deprecated @ReplaceWith(expression="event.getX(pointerIndex)") public static float getX(android.view.MotionEvent!, int);
+    method @Deprecated @ReplaceWith(expression="event.getY(pointerIndex)") public static float getY(android.view.MotionEvent!, int);
     method public static boolean isFromSource(android.view.MotionEvent, int);
     field @Deprecated public static final int ACTION_HOVER_ENTER = 9; // 0x9
     field @Deprecated public static final int ACTION_HOVER_EXIT = 10; // 0xa
@@ -2866,9 +2866,9 @@
   }
 
   public final class ScaleGestureDetectorCompat {
-    method public static boolean isQuickScaleEnabled(android.view.ScaleGestureDetector);
+    method @Deprecated @ReplaceWith(expression="scaleGestureDetector.isQuickScaleEnabled()") public static boolean isQuickScaleEnabled(android.view.ScaleGestureDetector);
     method @Deprecated public static boolean isQuickScaleEnabled(Object!);
-    method public static void setQuickScaleEnabled(android.view.ScaleGestureDetector, boolean);
+    method @Deprecated @ReplaceWith(expression="scaleGestureDetector.setQuickScaleEnabled(enabled)") public static void setQuickScaleEnabled(android.view.ScaleGestureDetector, boolean);
     method @Deprecated public static void setQuickScaleEnabled(Object!, boolean);
   }
 
@@ -2901,8 +2901,8 @@
     method public static void computeCurrentVelocity(android.view.VelocityTracker, int, float);
     method public static float getAxisVelocity(android.view.VelocityTracker, int);
     method public static float getAxisVelocity(android.view.VelocityTracker, int, int);
-    method @Deprecated public static float getXVelocity(android.view.VelocityTracker!, int);
-    method @Deprecated public static float getYVelocity(android.view.VelocityTracker!, int);
+    method @Deprecated @ReplaceWith(expression="tracker.getXVelocity(pointerId)") public static float getXVelocity(android.view.VelocityTracker!, int);
+    method @Deprecated @ReplaceWith(expression="tracker.getYVelocity(pointerId)") public static float getYVelocity(android.view.VelocityTracker!, int);
     method public static boolean isAxisSupported(android.view.VelocityTracker, int);
     method public static void recycle(android.view.VelocityTracker);
   }
@@ -2913,8 +2913,8 @@
     method public static void addKeyboardNavigationClusters(android.view.View, java.util.Collection<android.view.View!>, int);
     method public static void addOnUnhandledKeyEventListener(android.view.View, androidx.core.view.ViewCompat.OnUnhandledKeyEventListenerCompat);
     method @Deprecated public static androidx.core.view.ViewPropertyAnimatorCompat animate(android.view.View);
-    method @Deprecated public static boolean canScrollHorizontally(android.view.View!, int);
-    method @Deprecated public static boolean canScrollVertically(android.view.View!, int);
+    method @Deprecated @ReplaceWith(expression="view.canScrollHorizontally(direction)") public static boolean canScrollHorizontally(android.view.View!, int);
+    method @Deprecated @ReplaceWith(expression="view.canScrollVertically(direction)") public static boolean canScrollVertically(android.view.View!, int);
     method public static void cancelDragAndDrop(android.view.View);
     method @Deprecated public static int combineMeasuredStates(int, int);
     method public static androidx.core.view.WindowInsetsCompat computeSystemWindowInsets(android.view.View, androidx.core.view.WindowInsetsCompat, android.graphics.Rect);
@@ -2931,93 +2931,93 @@
     method public static void enableAccessibleClickableSpanSupport(android.view.View);
     method @Deprecated public static int generateViewId();
     method public static androidx.core.view.AccessibilityDelegateCompat? getAccessibilityDelegate(android.view.View);
-    method @Deprecated public static int getAccessibilityLiveRegion(android.view.View);
+    method @Deprecated @ReplaceWith(expression="view.getAccessibilityLiveRegion()") public static int getAccessibilityLiveRegion(android.view.View);
     method public static androidx.core.view.accessibility.AccessibilityNodeProviderCompat? getAccessibilityNodeProvider(android.view.View);
     method @UiThread public static CharSequence? getAccessibilityPaneTitle(android.view.View);
-    method @Deprecated public static float getAlpha(android.view.View!);
+    method @Deprecated @ReplaceWith(expression="view.getAlpha()") public static float getAlpha(android.view.View!);
     method public static androidx.core.view.autofill.AutofillIdCompat? getAutofillId(android.view.View);
     method public static android.content.res.ColorStateList? getBackgroundTintList(android.view.View);
     method public static android.graphics.PorterDuff.Mode? getBackgroundTintMode(android.view.View);
-    method @Deprecated public static android.graphics.Rect? getClipBounds(android.view.View);
+    method @Deprecated @ReplaceWith(expression="view.getClipBounds()") public static android.graphics.Rect? getClipBounds(android.view.View);
     method public static androidx.core.view.contentcapture.ContentCaptureSessionCompat? getContentCaptureSession(android.view.View);
-    method @Deprecated public static android.view.Display? getDisplay(android.view.View);
+    method @Deprecated @ReplaceWith(expression="view.getDisplay()") public static android.view.Display? getDisplay(android.view.View);
     method public static float getElevation(android.view.View);
-    method @Deprecated public static boolean getFitsSystemWindows(android.view.View);
-    method @Deprecated public static int getImportantForAccessibility(android.view.View);
+    method @Deprecated @ReplaceWith(expression="view.getFitsSystemWindows()") public static boolean getFitsSystemWindows(android.view.View);
+    method @Deprecated @ReplaceWith(expression="view.getImportantForAccessibility()") public static int getImportantForAccessibility(android.view.View);
     method public static int getImportantForAutofill(android.view.View);
     method public static int getImportantForContentCapture(android.view.View);
-    method @Deprecated public static int getLabelFor(android.view.View);
-    method @Deprecated public static int getLayerType(android.view.View!);
-    method @Deprecated public static int getLayoutDirection(android.view.View);
-    method @Deprecated public static android.graphics.Matrix? getMatrix(android.view.View!);
-    method @Deprecated public static int getMeasuredHeightAndState(android.view.View!);
-    method @Deprecated public static int getMeasuredState(android.view.View!);
-    method @Deprecated public static int getMeasuredWidthAndState(android.view.View!);
-    method @Deprecated public static int getMinimumHeight(android.view.View);
-    method @Deprecated public static int getMinimumWidth(android.view.View);
+    method @Deprecated @ReplaceWith(expression="view.getLabelFor()") public static int getLabelFor(android.view.View);
+    method @Deprecated @ReplaceWith(expression="view.getLayerType()") public static int getLayerType(android.view.View!);
+    method @Deprecated @ReplaceWith(expression="view.getLayoutDirection()") public static int getLayoutDirection(android.view.View);
+    method @Deprecated @ReplaceWith(expression="view.getMatrix()") public static android.graphics.Matrix? getMatrix(android.view.View!);
+    method @Deprecated @ReplaceWith(expression="view.getMeasuredHeightAndState()") public static int getMeasuredHeightAndState(android.view.View!);
+    method @Deprecated @ReplaceWith(expression="view.getMeasuredState()") public static int getMeasuredState(android.view.View!);
+    method @Deprecated @ReplaceWith(expression="view.getMeasuredWidthAndState()") public static int getMeasuredWidthAndState(android.view.View!);
+    method @Deprecated @ReplaceWith(expression="view.getMinimumHeight()") public static int getMinimumHeight(android.view.View);
+    method @Deprecated @ReplaceWith(expression="view.getMinimumWidth()") public static int getMinimumWidth(android.view.View);
     method public static int getNextClusterForwardId(android.view.View);
     method public static String![]? getOnReceiveContentMimeTypes(android.view.View);
-    method @Deprecated public static int getOverScrollMode(android.view.View!);
-    method @Deprecated @Px public static int getPaddingEnd(android.view.View);
-    method @Deprecated @Px public static int getPaddingStart(android.view.View);
-    method @Deprecated public static android.view.ViewParent? getParentForAccessibility(android.view.View);
-    method @Deprecated public static float getPivotX(android.view.View!);
-    method @Deprecated public static float getPivotY(android.view.View!);
+    method @Deprecated @ReplaceWith(expression="view.getOverScrollMode()") public static int getOverScrollMode(android.view.View!);
+    method @Deprecated @Px @ReplaceWith(expression="view.getPaddingEnd()") public static int getPaddingEnd(android.view.View);
+    method @Deprecated @Px @ReplaceWith(expression="view.getPaddingStart()") public static int getPaddingStart(android.view.View);
+    method @Deprecated @ReplaceWith(expression="view.getParentForAccessibility()") public static android.view.ViewParent? getParentForAccessibility(android.view.View);
+    method @Deprecated @ReplaceWith(expression="view.getPivotX()") public static float getPivotX(android.view.View!);
+    method @Deprecated @ReplaceWith(expression="view.getPivotY()") public static float getPivotY(android.view.View!);
     method public static androidx.core.view.WindowInsetsCompat? getRootWindowInsets(android.view.View);
-    method @Deprecated public static float getRotation(android.view.View!);
-    method @Deprecated public static float getRotationX(android.view.View!);
-    method @Deprecated public static float getRotationY(android.view.View!);
-    method @Deprecated public static float getScaleX(android.view.View!);
-    method @Deprecated public static float getScaleY(android.view.View!);
+    method @Deprecated @ReplaceWith(expression="view.getRotation()") public static float getRotation(android.view.View!);
+    method @Deprecated @ReplaceWith(expression="view.getRotationX()") public static float getRotationX(android.view.View!);
+    method @Deprecated @ReplaceWith(expression="view.getRotationY()") public static float getRotationY(android.view.View!);
+    method @Deprecated @ReplaceWith(expression="view.getScaleX()") public static float getScaleX(android.view.View!);
+    method @Deprecated @ReplaceWith(expression="view.getScaleY()") public static float getScaleY(android.view.View!);
     method public static int getScrollIndicators(android.view.View);
     method @UiThread public static CharSequence? getStateDescription(android.view.View);
     method public static java.util.List<android.graphics.Rect!> getSystemGestureExclusionRects(android.view.View);
     method public static String? getTransitionName(android.view.View);
-    method @Deprecated public static float getTranslationX(android.view.View!);
-    method @Deprecated public static float getTranslationY(android.view.View!);
+    method @Deprecated @ReplaceWith(expression="view.getTranslationX()") public static float getTranslationX(android.view.View!);
+    method @Deprecated @ReplaceWith(expression="view.getTranslationY()") public static float getTranslationY(android.view.View!);
     method public static float getTranslationZ(android.view.View);
     method @Deprecated public static androidx.core.view.WindowInsetsControllerCompat? getWindowInsetsController(android.view.View);
-    method @Deprecated public static int getWindowSystemUiVisibility(android.view.View);
-    method @Deprecated public static float getX(android.view.View!);
-    method @Deprecated public static float getY(android.view.View!);
+    method @Deprecated @ReplaceWith(expression="view.getWindowSystemUiVisibility()") public static int getWindowSystemUiVisibility(android.view.View);
+    method @Deprecated @ReplaceWith(expression="view.getX()") public static float getX(android.view.View!);
+    method @Deprecated @ReplaceWith(expression="view.getY()") public static float getY(android.view.View!);
     method public static float getZ(android.view.View);
     method public static boolean hasAccessibilityDelegate(android.view.View);
     method public static boolean hasExplicitFocusable(android.view.View);
     method public static boolean hasNestedScrollingParent(android.view.View);
     method public static boolean hasNestedScrollingParent(android.view.View, int);
-    method @Deprecated public static boolean hasOnClickListeners(android.view.View);
-    method @Deprecated public static boolean hasOverlappingRendering(android.view.View);
-    method @Deprecated public static boolean hasTransientState(android.view.View);
+    method @Deprecated @ReplaceWith(expression="view.hasOnClickListeners()") public static boolean hasOnClickListeners(android.view.View);
+    method @Deprecated @ReplaceWith(expression="view.hasOverlappingRendering()") public static boolean hasOverlappingRendering(android.view.View);
+    method @Deprecated @ReplaceWith(expression="view.hasTransientState()") public static boolean hasTransientState(android.view.View);
     method @UiThread public static boolean isAccessibilityHeading(android.view.View);
-    method @Deprecated public static boolean isAttachedToWindow(android.view.View);
+    method @Deprecated @ReplaceWith(expression="view.isAttachedToWindow()") public static boolean isAttachedToWindow(android.view.View);
     method public static boolean isFocusedByDefault(android.view.View);
     method public static boolean isImportantForAccessibility(android.view.View);
     method public static boolean isImportantForAutofill(android.view.View);
     method public static boolean isImportantForContentCapture(android.view.View);
-    method @Deprecated public static boolean isInLayout(android.view.View);
+    method @Deprecated @ReplaceWith(expression="view.isInLayout()") public static boolean isInLayout(android.view.View);
     method public static boolean isKeyboardNavigationCluster(android.view.View);
-    method @Deprecated public static boolean isLaidOut(android.view.View);
-    method @Deprecated public static boolean isLayoutDirectionResolved(android.view.View);
+    method @Deprecated @ReplaceWith(expression="view.isLaidOut()") public static boolean isLaidOut(android.view.View);
+    method @Deprecated @ReplaceWith(expression="view.isLayoutDirectionResolved()") public static boolean isLayoutDirectionResolved(android.view.View);
     method public static boolean isNestedScrollingEnabled(android.view.View);
-    method @Deprecated public static boolean isOpaque(android.view.View!);
-    method @Deprecated public static boolean isPaddingRelative(android.view.View);
+    method @Deprecated @ReplaceWith(expression="view.isOpaque()") public static boolean isOpaque(android.view.View!);
+    method @Deprecated @ReplaceWith(expression="view.isPaddingRelative()") public static boolean isPaddingRelative(android.view.View);
     method @UiThread public static boolean isScreenReaderFocusable(android.view.View);
-    method @Deprecated public static void jumpDrawablesToCurrentState(android.view.View!);
+    method @Deprecated @ReplaceWith(expression="view.jumpDrawablesToCurrentState()") public static void jumpDrawablesToCurrentState(android.view.View!);
     method public static android.view.View? keyboardNavigationClusterSearch(android.view.View, android.view.View?, int);
     method public static void offsetLeftAndRight(android.view.View, int);
     method public static void offsetTopAndBottom(android.view.View, int);
     method public static androidx.core.view.WindowInsetsCompat onApplyWindowInsets(android.view.View, androidx.core.view.WindowInsetsCompat);
-    method @Deprecated public static void onInitializeAccessibilityEvent(android.view.View!, android.view.accessibility.AccessibilityEvent!);
-    method @Deprecated public static void onInitializeAccessibilityNodeInfo(android.view.View, androidx.core.view.accessibility.AccessibilityNodeInfoCompat);
-    method @Deprecated public static void onPopulateAccessibilityEvent(android.view.View!, android.view.accessibility.AccessibilityEvent!);
-    method @Deprecated public static boolean performAccessibilityAction(android.view.View, int, android.os.Bundle?);
+    method @Deprecated @ReplaceWith(expression="v.onInitializeAccessibilityEvent(event)") public static void onInitializeAccessibilityEvent(android.view.View!, android.view.accessibility.AccessibilityEvent!);
+    method @Deprecated @ReplaceWith(expression="v.onInitializeAccessibilityNodeInfo(info.unwrap())") public static void onInitializeAccessibilityNodeInfo(android.view.View, androidx.core.view.accessibility.AccessibilityNodeInfoCompat);
+    method @Deprecated @ReplaceWith(expression="v.onPopulateAccessibilityEvent(event)") public static void onPopulateAccessibilityEvent(android.view.View!, android.view.accessibility.AccessibilityEvent!);
+    method @Deprecated @ReplaceWith(expression="view.performAccessibilityAction(action, arguments)") public static boolean performAccessibilityAction(android.view.View, int, android.os.Bundle?);
     method public static boolean performHapticFeedback(android.view.View, int);
     method public static boolean performHapticFeedback(android.view.View, int, int);
     method public static androidx.core.view.ContentInfoCompat? performReceiveContent(android.view.View, androidx.core.view.ContentInfoCompat);
-    method @Deprecated public static void postInvalidateOnAnimation(android.view.View);
-    method @Deprecated public static void postInvalidateOnAnimation(android.view.View, int, int, int, int);
-    method @Deprecated public static void postOnAnimation(android.view.View, Runnable);
-    method @Deprecated public static void postOnAnimationDelayed(android.view.View, Runnable, long);
+    method @Deprecated @ReplaceWith(expression="view.postInvalidateOnAnimation()") public static void postInvalidateOnAnimation(android.view.View);
+    method @Deprecated @ReplaceWith(expression="view.postInvalidateOnAnimation(left, top, right, bottom)") public static void postInvalidateOnAnimation(android.view.View, int, int, int, int);
+    method @Deprecated @ReplaceWith(expression="view.postOnAnimation(action)") public static void postOnAnimation(android.view.View, Runnable);
+    method @Deprecated @ReplaceWith(expression="view.postOnAnimationDelayed(action, delayMillis)") public static void postOnAnimationDelayed(android.view.View, Runnable, long);
     method public static void removeAccessibilityAction(android.view.View, int);
     method public static void removeOnUnhandledKeyEventListener(android.view.View, androidx.core.view.ViewCompat.OnUnhandledKeyEventListenerCompat);
     method public static void replaceAccessibilityAction(android.view.View, androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat, CharSequence?, androidx.core.view.accessibility.AccessibilityViewCommand?);
@@ -3028,45 +3028,45 @@
     method public static void saveAttributeDataForStyleable(android.view.View, android.content.Context, int[], android.util.AttributeSet?, android.content.res.TypedArray, int, int);
     method public static void setAccessibilityDelegate(android.view.View, androidx.core.view.AccessibilityDelegateCompat?);
     method @UiThread public static void setAccessibilityHeading(android.view.View, boolean);
-    method @Deprecated public static void setAccessibilityLiveRegion(android.view.View, int);
+    method @Deprecated @ReplaceWith(expression="view.setAccessibilityLiveRegion(mode)") public static void setAccessibilityLiveRegion(android.view.View, int);
     method @UiThread public static void setAccessibilityPaneTitle(android.view.View, CharSequence?);
-    method @Deprecated public static void setActivated(android.view.View!, boolean);
-    method @Deprecated public static void setAlpha(android.view.View!, @FloatRange(from=0.0, to=1.0) float);
+    method @Deprecated @ReplaceWith(expression="view.setActivated(activated)") public static void setActivated(android.view.View!, boolean);
+    method @Deprecated @ReplaceWith(expression="view.setAlpha(value)") public static void setAlpha(android.view.View!, @FloatRange(from=0.0, to=1.0) float);
     method public static void setAutofillHints(android.view.View, java.lang.String!...?);
     method public static void setAutofillId(android.view.View, androidx.core.view.autofill.AutofillIdCompat?);
-    method @Deprecated public static void setBackground(android.view.View, android.graphics.drawable.Drawable?);
+    method @Deprecated @ReplaceWith(expression="view.setBackground(background)") public static void setBackground(android.view.View, android.graphics.drawable.Drawable?);
     method public static void setBackgroundTintList(android.view.View, android.content.res.ColorStateList?);
     method public static void setBackgroundTintMode(android.view.View, android.graphics.PorterDuff.Mode?);
     method @Deprecated public static void setChildrenDrawingOrderEnabled(android.view.ViewGroup!, boolean);
-    method @Deprecated public static void setClipBounds(android.view.View, android.graphics.Rect?);
+    method @Deprecated @ReplaceWith(expression="view.setClipBounds(clipBounds)") public static void setClipBounds(android.view.View, android.graphics.Rect?);
     method public static void setContentCaptureSession(android.view.View, androidx.core.view.contentcapture.ContentCaptureSessionCompat?);
     method public static void setElevation(android.view.View, float);
-    method @Deprecated public static void setFitsSystemWindows(android.view.View!, boolean);
+    method @Deprecated @ReplaceWith(expression="view.setFitsSystemWindows(fitSystemWindows)") public static void setFitsSystemWindows(android.view.View!, boolean);
     method public static void setFocusedByDefault(android.view.View, boolean);
-    method @Deprecated public static void setHasTransientState(android.view.View, boolean);
-    method @Deprecated @UiThread public static void setImportantForAccessibility(android.view.View, int);
+    method @Deprecated @ReplaceWith(expression="view.setHasTransientState(hasTransientState)") public static void setHasTransientState(android.view.View, boolean);
+    method @Deprecated @ReplaceWith(expression="view.setImportantForAccessibility(mode)") @UiThread public static void setImportantForAccessibility(android.view.View, int);
     method public static void setImportantForAutofill(android.view.View, int);
     method public static void setImportantForContentCapture(android.view.View, int);
     method public static void setKeyboardNavigationCluster(android.view.View, boolean);
-    method @Deprecated public static void setLabelFor(android.view.View, @IdRes int);
-    method @Deprecated public static void setLayerPaint(android.view.View, android.graphics.Paint?);
-    method @Deprecated public static void setLayerType(android.view.View!, int, android.graphics.Paint!);
-    method @Deprecated public static void setLayoutDirection(android.view.View, int);
+    method @Deprecated @ReplaceWith(expression="view.setLabelFor(labeledId)") public static void setLabelFor(android.view.View, @IdRes int);
+    method @Deprecated @ReplaceWith(expression="view.setLayerPaint(paint)") public static void setLayerPaint(android.view.View, android.graphics.Paint?);
+    method @Deprecated @ReplaceWith(expression="view.setLayerType(layerType, paint)") public static void setLayerType(android.view.View!, int, android.graphics.Paint!);
+    method @Deprecated @ReplaceWith(expression="view.setLayoutDirection(layoutDirection)") public static void setLayoutDirection(android.view.View, int);
     method public static void setNestedScrollingEnabled(android.view.View, boolean);
     method public static void setNextClusterForwardId(android.view.View, int);
     method public static void setOnApplyWindowInsetsListener(android.view.View, androidx.core.view.OnApplyWindowInsetsListener?);
     method public static void setOnReceiveContentListener(android.view.View, String![]?, androidx.core.view.OnReceiveContentListener?);
-    method @Deprecated public static void setOverScrollMode(android.view.View!, int);
-    method @Deprecated public static void setPaddingRelative(android.view.View, @Px int, @Px int, @Px int, @Px int);
-    method @Deprecated public static void setPivotX(android.view.View!, float);
-    method @Deprecated public static void setPivotY(android.view.View!, float);
+    method @Deprecated @ReplaceWith(expression="view.setOverScrollMode(overScrollMode)") public static void setOverScrollMode(android.view.View!, int);
+    method @Deprecated @ReplaceWith(expression="view.setPaddingRelative(start, top, end, bottom)") public static void setPaddingRelative(android.view.View, @Px int, @Px int, @Px int, @Px int);
+    method @Deprecated @ReplaceWith(expression="view.setPivotX(value)") public static void setPivotX(android.view.View!, float);
+    method @Deprecated @ReplaceWith(expression="view.setPivotY(value)") public static void setPivotY(android.view.View!, float);
     method public static void setPointerIcon(android.view.View, androidx.core.view.PointerIconCompat?);
-    method @Deprecated public static void setRotation(android.view.View!, float);
-    method @Deprecated public static void setRotationX(android.view.View!, float);
-    method @Deprecated public static void setRotationY(android.view.View!, float);
-    method @Deprecated public static void setSaveFromParentEnabled(android.view.View!, boolean);
-    method @Deprecated public static void setScaleX(android.view.View!, float);
-    method @Deprecated public static void setScaleY(android.view.View!, float);
+    method @Deprecated @ReplaceWith(expression="view.setRotation(value)") public static void setRotation(android.view.View!, float);
+    method @Deprecated @ReplaceWith(expression="view.setRotationX(value)") public static void setRotationX(android.view.View!, float);
+    method @Deprecated @ReplaceWith(expression="view.setRotationY(value)") public static void setRotationY(android.view.View!, float);
+    method @Deprecated @ReplaceWith(expression="view.setSaveFromParentEnabled(enabled)") public static void setSaveFromParentEnabled(android.view.View!, boolean);
+    method @Deprecated @ReplaceWith(expression="view.setScaleX(value)") public static void setScaleX(android.view.View!, float);
+    method @Deprecated @ReplaceWith(expression="view.setScaleY(value)") public static void setScaleY(android.view.View!, float);
     method @UiThread public static void setScreenReaderFocusable(android.view.View, boolean);
     method public static void setScrollIndicators(android.view.View, int);
     method public static void setScrollIndicators(android.view.View, int, int);
@@ -3074,12 +3074,12 @@
     method public static void setSystemGestureExclusionRects(android.view.View, java.util.List<android.graphics.Rect!>);
     method public static void setTooltipText(android.view.View, CharSequence?);
     method public static void setTransitionName(android.view.View, String?);
-    method @Deprecated public static void setTranslationX(android.view.View!, float);
-    method @Deprecated public static void setTranslationY(android.view.View!, float);
+    method @Deprecated @ReplaceWith(expression="view.setTranslationX(value)") public static void setTranslationX(android.view.View!, float);
+    method @Deprecated @ReplaceWith(expression="view.setTranslationY(value)") public static void setTranslationY(android.view.View!, float);
     method public static void setTranslationZ(android.view.View, float);
     method public static void setWindowInsetsAnimationCallback(android.view.View, androidx.core.view.WindowInsetsAnimationCompat.Callback?);
-    method @Deprecated public static void setX(android.view.View!, float);
-    method @Deprecated public static void setY(android.view.View!, float);
+    method @Deprecated @ReplaceWith(expression="view.setX(value)") public static void setX(android.view.View!, float);
+    method @Deprecated @ReplaceWith(expression="view.setY(value)") public static void setY(android.view.View!, float);
     method public static void setZ(android.view.View, float);
     method public static boolean startDragAndDrop(android.view.View, android.content.ClipData?, android.view.View.DragShadowBuilder, Object?, int);
     method public static boolean startNestedScroll(android.view.View, int);
@@ -3135,26 +3135,26 @@
     method public static int getScaledHoverSlop(android.view.ViewConfiguration);
     method public static int getScaledMaximumFlingVelocity(android.content.Context, android.view.ViewConfiguration, int, int, int);
     method public static int getScaledMinimumFlingVelocity(android.content.Context, android.view.ViewConfiguration, int, int, int);
-    method @Deprecated public static int getScaledPagingTouchSlop(android.view.ViewConfiguration!);
+    method @Deprecated @ReplaceWith(expression="config.getScaledPagingTouchSlop()") public static int getScaledPagingTouchSlop(android.view.ViewConfiguration!);
     method public static float getScaledVerticalScrollFactor(android.view.ViewConfiguration, android.content.Context);
-    method @Deprecated public static boolean hasPermanentMenuKey(android.view.ViewConfiguration!);
+    method @Deprecated @ReplaceWith(expression="config.hasPermanentMenuKey()") public static boolean hasPermanentMenuKey(android.view.ViewConfiguration!);
     method public static boolean shouldShowMenuShortcutsWhenKeyboardPresent(android.view.ViewConfiguration, android.content.Context);
   }
 
   public final class ViewGroupCompat {
-    method public static int getLayoutMode(android.view.ViewGroup);
+    method @Deprecated @ReplaceWith(expression="group.getLayoutMode()") public static int getLayoutMode(android.view.ViewGroup);
     method public static int getNestedScrollAxes(android.view.ViewGroup);
     method public static boolean isTransitionGroup(android.view.ViewGroup);
-    method @Deprecated public static boolean onRequestSendAccessibilityEvent(android.view.ViewGroup!, android.view.View!, android.view.accessibility.AccessibilityEvent!);
-    method public static void setLayoutMode(android.view.ViewGroup, int);
-    method @Deprecated public static void setMotionEventSplittingEnabled(android.view.ViewGroup!, boolean);
+    method @Deprecated @ReplaceWith(expression="group.onRequestSendAccessibilityEvent(child, event)") public static boolean onRequestSendAccessibilityEvent(android.view.ViewGroup!, android.view.View!, android.view.accessibility.AccessibilityEvent!);
+    method @Deprecated @ReplaceWith(expression="group.setLayoutMode(mode)") public static void setLayoutMode(android.view.ViewGroup, int);
+    method @Deprecated @ReplaceWith(expression="group.setMotionEventSplittingEnabled(split)") public static void setMotionEventSplittingEnabled(android.view.ViewGroup!, boolean);
     method public static void setTransitionGroup(android.view.ViewGroup, boolean);
     field public static final int LAYOUT_MODE_CLIP_BOUNDS = 0; // 0x0
     field public static final int LAYOUT_MODE_OPTICAL_BOUNDS = 1; // 0x1
   }
 
   public final class ViewParentCompat {
-    method public static void notifySubtreeAccessibilityStateChanged(android.view.ViewParent, android.view.View, android.view.View, int);
+    method @Deprecated @ReplaceWith(expression="parent.notifySubtreeAccessibilityStateChanged(child, source, changeType)") public static void notifySubtreeAccessibilityStateChanged(android.view.ViewParent, android.view.View, android.view.View, int);
     method public static boolean onNestedFling(android.view.ViewParent, android.view.View, float, float, boolean);
     method public static boolean onNestedPreFling(android.view.ViewParent, android.view.View, float, float);
     method public static void onNestedPreScroll(android.view.ViewParent, android.view.View, int, int, int[]);
@@ -3168,7 +3168,7 @@
     method public static boolean onStartNestedScroll(android.view.ViewParent, android.view.View, android.view.View, int, int);
     method public static void onStopNestedScroll(android.view.ViewParent, android.view.View);
     method public static void onStopNestedScroll(android.view.ViewParent, android.view.View, int);
-    method @Deprecated public static boolean requestSendAccessibilityEvent(android.view.ViewParent!, android.view.View!, android.view.accessibility.AccessibilityEvent!);
+    method @Deprecated @ReplaceWith(expression="parent.requestSendAccessibilityEvent(child, event)") public static boolean requestSendAccessibilityEvent(android.view.ViewParent!, android.view.View!, android.view.accessibility.AccessibilityEvent!);
   }
 
   public final class ViewPropertyAnimatorCompat {
@@ -3395,18 +3395,18 @@
   }
 
   public final class AccessibilityEventCompat {
-    method @Deprecated public static void appendRecord(android.view.accessibility.AccessibilityEvent!, androidx.core.view.accessibility.AccessibilityRecordCompat!);
+    method @Deprecated @ReplaceWith(expression="event.appendRecord(record)") public static void appendRecord(android.view.accessibility.AccessibilityEvent!, androidx.core.view.accessibility.AccessibilityRecordCompat!);
     method @Deprecated public static androidx.core.view.accessibility.AccessibilityRecordCompat! asRecord(android.view.accessibility.AccessibilityEvent!);
-    method public static int getAction(android.view.accessibility.AccessibilityEvent);
-    method public static int getContentChangeTypes(android.view.accessibility.AccessibilityEvent);
-    method public static int getMovementGranularity(android.view.accessibility.AccessibilityEvent);
+    method @Deprecated @ReplaceWith(expression="event.getAction()") public static int getAction(android.view.accessibility.AccessibilityEvent);
+    method @Deprecated @ReplaceWith(expression="event.getContentChangeTypes()") public static int getContentChangeTypes(android.view.accessibility.AccessibilityEvent);
+    method @Deprecated @ReplaceWith(expression="event.getMovementGranularity()") public static int getMovementGranularity(android.view.accessibility.AccessibilityEvent);
     method @Deprecated public static androidx.core.view.accessibility.AccessibilityRecordCompat! getRecord(android.view.accessibility.AccessibilityEvent!, int);
-    method @Deprecated public static int getRecordCount(android.view.accessibility.AccessibilityEvent!);
+    method @Deprecated @ReplaceWith(expression="event.getRecordCount()") public static int getRecordCount(android.view.accessibility.AccessibilityEvent!);
     method public static boolean isAccessibilityDataSensitive(android.view.accessibility.AccessibilityEvent);
     method public static void setAccessibilityDataSensitive(android.view.accessibility.AccessibilityEvent, boolean);
-    method public static void setAction(android.view.accessibility.AccessibilityEvent, int);
-    method public static void setContentChangeTypes(android.view.accessibility.AccessibilityEvent, int);
-    method public static void setMovementGranularity(android.view.accessibility.AccessibilityEvent, int);
+    method @Deprecated @ReplaceWith(expression="event.setAction(action)") public static void setAction(android.view.accessibility.AccessibilityEvent, int);
+    method @Deprecated @ReplaceWith(expression="event.setContentChangeTypes(changeTypes)") public static void setContentChangeTypes(android.view.accessibility.AccessibilityEvent, int);
+    method @Deprecated @ReplaceWith(expression="event.setMovementGranularity(granularity)") public static void setMovementGranularity(android.view.accessibility.AccessibilityEvent, int);
     field public static final int CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION = 4; // 0x4
     field public static final int CONTENT_CHANGE_TYPE_CONTENT_INVALID = 1024; // 0x400
     field public static final int CONTENT_CHANGE_TYPE_DRAG_CANCELLED = 512; // 0x200
@@ -3445,13 +3445,13 @@
 
   public final class AccessibilityManagerCompat {
     method @Deprecated public static boolean addAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager!, androidx.core.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener!);
-    method public static boolean addTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager, androidx.core.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener);
-    method @Deprecated public static java.util.List<android.accessibilityservice.AccessibilityServiceInfo!>! getEnabledAccessibilityServiceList(android.view.accessibility.AccessibilityManager!, int);
-    method @Deprecated public static java.util.List<android.accessibilityservice.AccessibilityServiceInfo!>! getInstalledAccessibilityServiceList(android.view.accessibility.AccessibilityManager!);
+    method @Deprecated @ReplaceWith(expression="manager.addTouchExplorationStateChangeListener(listener)") public static boolean addTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager, androidx.core.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener);
+    method @Deprecated @ReplaceWith(expression="manager.getEnabledAccessibilityServiceList(feedbackTypeFlags)") public static java.util.List<android.accessibilityservice.AccessibilityServiceInfo!>! getEnabledAccessibilityServiceList(android.view.accessibility.AccessibilityManager!, int);
+    method @Deprecated @ReplaceWith(expression="manager.getInstalledAccessibilityServiceList()") public static java.util.List<android.accessibilityservice.AccessibilityServiceInfo!>! getInstalledAccessibilityServiceList(android.view.accessibility.AccessibilityManager!);
     method public static boolean isRequestFromAccessibilityTool(android.view.accessibility.AccessibilityManager);
-    method @Deprecated public static boolean isTouchExplorationEnabled(android.view.accessibility.AccessibilityManager!);
+    method @Deprecated @ReplaceWith(expression="manager.isTouchExplorationEnabled()") public static boolean isTouchExplorationEnabled(android.view.accessibility.AccessibilityManager!);
     method @Deprecated public static boolean removeAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager!, androidx.core.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener!);
-    method public static boolean removeTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager, androidx.core.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener);
+    method @Deprecated @ReplaceWith(expression="manager.removeTouchExplorationStateChangeListener(listener)") public static boolean removeTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager, androidx.core.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener);
   }
 
   @Deprecated public static interface AccessibilityManagerCompat.AccessibilityStateChangeListener {
@@ -3816,9 +3816,9 @@
     method @Deprecated public Object! getImpl();
     method @Deprecated public int getItemCount();
     method @Deprecated public int getMaxScrollX();
-    method public static int getMaxScrollX(android.view.accessibility.AccessibilityRecord);
+    method @Deprecated @ReplaceWith(expression="record.getMaxScrollX()") public static int getMaxScrollX(android.view.accessibility.AccessibilityRecord);
     method @Deprecated public int getMaxScrollY();
-    method public static int getMaxScrollY(android.view.accessibility.AccessibilityRecord);
+    method @Deprecated @ReplaceWith(expression="record.getMaxScrollY()") public static int getMaxScrollY(android.view.accessibility.AccessibilityRecord);
     method @Deprecated public android.os.Parcelable! getParcelableData();
     method @Deprecated public int getRemovedCount();
     method @Deprecated public int getScrollX();
@@ -3846,9 +3846,9 @@
     method @Deprecated public void setFromIndex(int);
     method @Deprecated public void setFullScreen(boolean);
     method @Deprecated public void setItemCount(int);
-    method public static void setMaxScrollX(android.view.accessibility.AccessibilityRecord, int);
+    method @Deprecated @ReplaceWith(expression="record.setMaxScrollX(maxScrollX)") public static void setMaxScrollX(android.view.accessibility.AccessibilityRecord, int);
     method @Deprecated public void setMaxScrollX(int);
-    method public static void setMaxScrollY(android.view.accessibility.AccessibilityRecord, int);
+    method @Deprecated @ReplaceWith(expression="record.setMaxScrollY(maxScrollY)") public static void setMaxScrollY(android.view.accessibility.AccessibilityRecord, int);
     method @Deprecated public void setMaxScrollY(int);
     method @Deprecated public void setParcelableData(android.os.Parcelable!);
     method @Deprecated public void setPassword(boolean);
@@ -3856,7 +3856,7 @@
     method @Deprecated public void setScrollX(int);
     method @Deprecated public void setScrollY(int);
     method @Deprecated public void setScrollable(boolean);
-    method public static void setSource(android.view.accessibility.AccessibilityRecord, android.view.View?, int);
+    method @Deprecated @ReplaceWith(expression="record.setSource(root, virtualDescendantId)") public static void setSource(android.view.accessibility.AccessibilityRecord, android.view.View?, int);
     method @Deprecated public void setSource(android.view.View!);
     method @Deprecated public void setSource(android.view.View!, int);
     method @Deprecated public void setToIndex(int);
@@ -4049,7 +4049,7 @@
   }
 
   public final class CheckedTextViewCompat {
-    method public static android.graphics.drawable.Drawable? getCheckMarkDrawable(android.widget.CheckedTextView);
+    method @Deprecated @ReplaceWith(expression="textView.getCheckMarkDrawable()") public static android.graphics.drawable.Drawable? getCheckMarkDrawable(android.widget.CheckedTextView);
     method public static android.content.res.ColorStateList? getCheckMarkTintList(android.widget.CheckedTextView);
     method public static android.graphics.PorterDuff.Mode? getCheckMarkTintMode(android.widget.CheckedTextView);
     method public static void setCheckMarkTintList(android.widget.CheckedTextView, android.content.res.ColorStateList?);
@@ -4097,7 +4097,7 @@
   }
 
   public final class ListPopupWindowCompat {
-    method public static android.view.View.OnTouchListener? createDragToOpenListener(android.widget.ListPopupWindow, android.view.View);
+    method @Deprecated @ReplaceWith(expression="listPopupWindow.createDragToOpenListener(src)") public static android.view.View.OnTouchListener? createDragToOpenListener(android.widget.ListPopupWindow, android.view.View);
     method @Deprecated public static android.view.View.OnTouchListener! createDragToOpenListener(Object!, android.view.View!);
   }
 
@@ -4109,8 +4109,8 @@
   }
 
   @Deprecated public final class ListViewCompat {
-    method @Deprecated public static boolean canScrollList(android.widget.ListView, int);
-    method @Deprecated public static void scrollListBy(android.widget.ListView, int);
+    method @Deprecated @ReplaceWith(expression="listView.canScrollList(direction)") public static boolean canScrollList(android.widget.ListView, int);
+    method @Deprecated @ReplaceWith(expression="listView.scrollListBy(y)") public static void scrollListBy(android.widget.ListView, int);
   }
 
   public class NestedScrollView extends android.widget.FrameLayout implements androidx.core.view.NestedScrollingChild3 androidx.core.view.NestedScrollingParent3 androidx.core.view.ScrollingView {
@@ -4167,7 +4167,7 @@
     method public static int getWindowLayoutType(android.widget.PopupWindow);
     method public static void setOverlapAnchor(android.widget.PopupWindow, boolean);
     method public static void setWindowLayoutType(android.widget.PopupWindow, int);
-    method public static void showAsDropDown(android.widget.PopupWindow, android.view.View, int, int, int);
+    method @Deprecated @ReplaceWith(expression="popup.showAsDropDown(anchor, xoff, yoff, gravity)") public static void showAsDropDown(android.widget.PopupWindow, android.view.View, int, int, int);
   }
 
   @Deprecated public final class ScrollerCompat {
@@ -4199,21 +4199,21 @@
     method public static int getAutoSizeTextType(android.widget.TextView);
     method public static android.content.res.ColorStateList? getCompoundDrawableTintList(android.widget.TextView);
     method public static android.graphics.PorterDuff.Mode? getCompoundDrawableTintMode(android.widget.TextView);
-    method public static android.graphics.drawable.Drawable![] getCompoundDrawablesRelative(android.widget.TextView);
+    method @Deprecated @ReplaceWith(expression="textView.getCompoundDrawablesRelative()") public static android.graphics.drawable.Drawable![] getCompoundDrawablesRelative(android.widget.TextView);
     method public static int getFirstBaselineToTopHeight(android.widget.TextView);
     method public static int getLastBaselineToBottomHeight(android.widget.TextView);
-    method public static int getMaxLines(android.widget.TextView);
-    method public static int getMinLines(android.widget.TextView);
+    method @Deprecated @ReplaceWith(expression="textView.getMaxLines()") public static int getMaxLines(android.widget.TextView);
+    method @Deprecated @ReplaceWith(expression="textView.getMinLines()") public static int getMinLines(android.widget.TextView);
     method public static androidx.core.text.PrecomputedTextCompat.Params getTextMetricsParams(android.widget.TextView);
     method public static void setAutoSizeTextTypeUniformWithConfiguration(android.widget.TextView, int, int, int, int) throws java.lang.IllegalArgumentException;
     method public static void setAutoSizeTextTypeUniformWithPresetSizes(android.widget.TextView, int[], int) throws java.lang.IllegalArgumentException;
     method public static void setAutoSizeTextTypeWithDefaults(android.widget.TextView, int);
     method public static void setCompoundDrawableTintList(android.widget.TextView, android.content.res.ColorStateList?);
     method public static void setCompoundDrawableTintMode(android.widget.TextView, android.graphics.PorterDuff.Mode?);
-    method public static void setCompoundDrawablesRelative(android.widget.TextView, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?);
-    method public static void setCompoundDrawablesRelativeWithIntrinsicBounds(android.widget.TextView, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?);
-    method public static void setCompoundDrawablesRelativeWithIntrinsicBounds(android.widget.TextView, @DrawableRes int, @DrawableRes int, @DrawableRes int, @DrawableRes int);
-    method public static void setCustomSelectionActionModeCallback(android.widget.TextView, android.view.ActionMode.Callback);
+    method @Deprecated @ReplaceWith(expression="textView.setCompoundDrawablesRelative(start, top, end, bottom)") public static void setCompoundDrawablesRelative(android.widget.TextView, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?);
+    method @Deprecated @ReplaceWith(expression="textView.setCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom)") public static void setCompoundDrawablesRelativeWithIntrinsicBounds(android.widget.TextView, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?);
+    method @Deprecated @ReplaceWith(expression="textView.setCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom)") public static void setCompoundDrawablesRelativeWithIntrinsicBounds(android.widget.TextView, @DrawableRes int, @DrawableRes int, @DrawableRes int, @DrawableRes int);
+    method @Deprecated @ReplaceWith(expression="textView.setCustomSelectionActionModeCallback(callback)") public static void setCustomSelectionActionModeCallback(android.widget.TextView, android.view.ActionMode.Callback);
     method public static void setFirstBaselineToTopHeight(android.widget.TextView, @IntRange(from=0) @Px int);
     method public static void setLastBaselineToBottomHeight(android.widget.TextView, @IntRange(from=0) @Px int);
     method public static void setLineHeight(android.widget.TextView, @IntRange(from=0) @Px int);
diff --git a/core/core/api/restricted_current.txt b/core/core/api/restricted_current.txt
index 3414ef2..5414e99 100644
--- a/core/core/api/restricted_current.txt
+++ b/core/core/api/restricted_current.txt
@@ -18,8 +18,8 @@
     method public static String capabilityToString(int);
     method public static String feedbackTypeToString(int);
     method public static String? flagToString(int);
-    method public static int getCapabilities(android.accessibilityservice.AccessibilityServiceInfo);
-    method public static String? loadDescription(android.accessibilityservice.AccessibilityServiceInfo, android.content.pm.PackageManager);
+    method @Deprecated @ReplaceWith(expression="info.getCapabilities()") public static int getCapabilities(android.accessibilityservice.AccessibilityServiceInfo);
+    method @Deprecated @ReplaceWith(expression="info.loadDescription(packageManager)") public static String? loadDescription(android.accessibilityservice.AccessibilityServiceInfo, android.content.pm.PackageManager);
     field public static final int CAPABILITY_CAN_FILTER_KEY_EVENTS = 8; // 0x8
     field public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 4; // 0x4
     field public static final int CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION = 2; // 0x2
@@ -74,7 +74,7 @@
   }
 
   public final class ActivityManagerCompat {
-    method public static boolean isLowRamDevice(android.app.ActivityManager);
+    method @Deprecated @ReplaceWith(expression="activityManager.isLowRamDevice()") public static boolean isLowRamDevice(android.app.ActivityManager);
   }
 
   public class ActivityOptionsCompat {
@@ -101,7 +101,7 @@
     method public static boolean canScheduleExactAlarms(android.app.AlarmManager);
     method public static void setAlarmClock(android.app.AlarmManager, long, android.app.PendingIntent, android.app.PendingIntent);
     method public static void setAndAllowWhileIdle(android.app.AlarmManager, int, long, android.app.PendingIntent);
-    method public static void setExact(android.app.AlarmManager, int, long, android.app.PendingIntent);
+    method @Deprecated @ReplaceWith(expression="alarmManager.setExact(type, triggerAtMillis, operation)") public static void setExact(android.app.AlarmManager, int, long, android.app.PendingIntent);
     method public static void setExactAndAllowWhileIdle(android.app.AlarmManager, int, long, android.app.PendingIntent);
   }
 
@@ -144,8 +144,8 @@
   }
 
   @Deprecated public final class BundleCompat {
-    method @Deprecated public static android.os.IBinder? getBinder(android.os.Bundle, String?);
-    method @Deprecated public static void putBinder(android.os.Bundle, String?, android.os.IBinder?);
+    method @Deprecated @ReplaceWith(expression="bundle.getBinder(key)") public static android.os.IBinder? getBinder(android.os.Bundle, String?);
+    method @Deprecated @ReplaceWith(expression="bundle.putBinder(key, binder)") public static void putBinder(android.os.Bundle, String?, android.os.IBinder?);
   }
 
   @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class ComponentActivity extends android.app.Activity implements androidx.core.view.KeyEventDispatcher.Component androidx.lifecycle.LifecycleOwner {
@@ -247,8 +247,8 @@
     method public static String? getParentActivityName(android.app.Activity);
     method public static String? getParentActivityName(android.content.Context, android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
     method public static void navigateUpFromSameTask(android.app.Activity);
-    method public static void navigateUpTo(android.app.Activity, android.content.Intent);
-    method public static boolean shouldUpRecreateTask(android.app.Activity, android.content.Intent);
+    method @Deprecated @ReplaceWith(expression="sourceActivity.navigateUpTo(upIntent)") public static void navigateUpTo(android.app.Activity, android.content.Intent);
+    method @Deprecated @ReplaceWith(expression="sourceActivity.shouldUpRecreateTask(targetIntent)") public static boolean shouldUpRecreateTask(android.app.Activity, android.content.Intent);
     field public static final String PARENT_ACTIVITY = "android.support.PARENT_ACTIVITY";
   }
 
@@ -325,7 +325,7 @@
     method public static CharSequence? getContentInfo(android.app.Notification);
     method public static CharSequence? getContentText(android.app.Notification);
     method public static CharSequence? getContentTitle(android.app.Notification);
-    method public static android.os.Bundle? getExtras(android.app.Notification);
+    method @Deprecated @ReplaceWith(expression="notification.extras") public static android.os.Bundle? getExtras(android.app.Notification);
     method public static String? getGroup(android.app.Notification);
     method @androidx.core.app.NotificationCompat.GroupAlertBehavior public static int getGroupAlertBehavior(android.app.Notification);
     method @RequiresApi(21) public static java.util.List<androidx.core.app.NotificationCompat.Action!> getInvisibleActions(android.app.Notification);
@@ -1232,11 +1232,11 @@
     method public static java.io.File? getDataDir(android.content.Context);
     method public static android.view.Display getDisplayOrDefault(@DisplayContext android.content.Context);
     method public static android.graphics.drawable.Drawable? getDrawable(android.content.Context, @DrawableRes int);
-    method public static java.io.File![] getExternalCacheDirs(android.content.Context);
-    method public static java.io.File![] getExternalFilesDirs(android.content.Context, String?);
+    method @Deprecated @ReplaceWith(expression="context.getExternalCacheDirs()") public static java.io.File![] getExternalCacheDirs(android.content.Context);
+    method @Deprecated @ReplaceWith(expression="context.getExternalFilesDirs(type)") public static java.io.File![] getExternalFilesDirs(android.content.Context, String?);
     method public static java.util.concurrent.Executor getMainExecutor(android.content.Context);
     method public static java.io.File? getNoBackupFilesDir(android.content.Context);
-    method public static java.io.File![] getObbDirs(android.content.Context);
+    method @Deprecated @ReplaceWith(expression="context.getObbDirs()") public static java.io.File![] getObbDirs(android.content.Context);
     method public static String getString(android.content.Context, int);
     method public static <T> T? getSystemService(android.content.Context, Class<T!>);
     method public static String? getSystemServiceName(android.content.Context, Class<?>);
@@ -1245,7 +1245,7 @@
     method public static android.content.Intent? registerReceiver(android.content.Context, android.content.BroadcastReceiver?, android.content.IntentFilter, String?, android.os.Handler?, int);
     method public static boolean startActivities(android.content.Context, android.content.Intent![]);
     method public static boolean startActivities(android.content.Context, android.content.Intent![], android.os.Bundle?);
-    method public static void startActivity(android.content.Context, android.content.Intent, android.os.Bundle?);
+    method @Deprecated @ReplaceWith(expression="context.startActivity(intent, options)") public static void startActivity(android.content.Context, android.content.Intent, android.os.Bundle?);
     method public static void startForegroundService(android.content.Context, android.content.Intent);
     field public static final int RECEIVER_EXPORTED = 2; // 0x2
     field public static final int RECEIVER_NOT_EXPORTED = 4; // 0x4
@@ -1670,9 +1670,9 @@
 
   public final class BitmapCompat {
     method public static android.graphics.Bitmap createScaledBitmap(android.graphics.Bitmap, int, int, android.graphics.Rect?, boolean);
-    method public static int getAllocationByteCount(android.graphics.Bitmap);
-    method public static boolean hasMipMap(android.graphics.Bitmap);
-    method public static void setHasMipMap(android.graphics.Bitmap, boolean);
+    method @Deprecated @ReplaceWith(expression="bitmap.getAllocationByteCount()") public static int getAllocationByteCount(android.graphics.Bitmap);
+    method @Deprecated @ReplaceWith(expression="bitmap.hasMipMap()") public static boolean hasMipMap(android.graphics.Bitmap);
+    method @Deprecated @ReplaceWith(expression="bitmap.setHasMipMap(hasMipMap)") public static void setHasMipMap(android.graphics.Bitmap, boolean);
   }
 
   public class BlendModeColorFilterCompat {
@@ -1852,13 +1852,13 @@
     method public static void applyTheme(android.graphics.drawable.Drawable, android.content.res.Resources.Theme);
     method public static boolean canApplyTheme(android.graphics.drawable.Drawable);
     method public static void clearColorFilter(android.graphics.drawable.Drawable);
-    method public static int getAlpha(android.graphics.drawable.Drawable);
+    method @Deprecated @ReplaceWith(expression="drawable.getAlpha()") public static int getAlpha(android.graphics.drawable.Drawable);
     method public static android.graphics.ColorFilter? getColorFilter(android.graphics.drawable.Drawable);
     method public static int getLayoutDirection(android.graphics.drawable.Drawable);
     method public static void inflate(android.graphics.drawable.Drawable, android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet, android.content.res.Resources.Theme?) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public static boolean isAutoMirrored(android.graphics.drawable.Drawable);
-    method @Deprecated public static void jumpToCurrentState(android.graphics.drawable.Drawable);
-    method public static void setAutoMirrored(android.graphics.drawable.Drawable, boolean);
+    method @Deprecated @ReplaceWith(expression="drawable.isAutoMirrored()") public static boolean isAutoMirrored(android.graphics.drawable.Drawable);
+    method @Deprecated @ReplaceWith(expression="drawable.jumpToCurrentState()") public static void jumpToCurrentState(android.graphics.drawable.Drawable);
+    method @Deprecated @ReplaceWith(expression="drawable.setAutoMirrored(mirrored)") public static void setAutoMirrored(android.graphics.drawable.Drawable, boolean);
     method public static void setHotspot(android.graphics.drawable.Drawable, float, float);
     method public static void setHotspotBounds(android.graphics.drawable.Drawable, int, int, int, int);
     method public static boolean setLayoutDirection(android.graphics.drawable.Drawable, int);
@@ -2077,7 +2077,7 @@
   public final class LocationCompat {
     method public static float getBearingAccuracyDegrees(android.location.Location);
     method public static long getElapsedRealtimeMillis(android.location.Location);
-    method public static long getElapsedRealtimeNanos(android.location.Location);
+    method @Deprecated @ReplaceWith(expression="location.getElapsedRealtimeNanos()") public static long getElapsedRealtimeNanos(android.location.Location);
     method @FloatRange(from=0.0) public static float getMslAltitudeAccuracyMeters(android.location.Location);
     method public static double getMslAltitudeMeters(android.location.Location);
     method public static float getSpeedAccuracyMetersPerSecond(android.location.Location);
@@ -2087,7 +2087,7 @@
     method public static boolean hasMslAltitudeAccuracy(android.location.Location);
     method public static boolean hasSpeedAccuracy(android.location.Location);
     method public static boolean hasVerticalAccuracy(android.location.Location);
-    method public static boolean isMock(android.location.Location);
+    method @Deprecated @ReplaceWith(expression="location.isFromMockProvider()") public static boolean isMock(android.location.Location);
     method public static void removeBearingAccuracy(android.location.Location);
     method public static void removeMslAltitude(android.location.Location);
     method public static void removeMslAltitudeAccuracy(android.location.Location);
@@ -2190,7 +2190,7 @@
   public final class ConnectivityManagerCompat {
     method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public static android.net.NetworkInfo? getNetworkInfoFromBroadcast(android.net.ConnectivityManager, android.content.Intent);
     method @androidx.core.net.ConnectivityManagerCompat.RestrictBackgroundStatus public static int getRestrictBackgroundStatus(android.net.ConnectivityManager);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public static boolean isActiveNetworkMetered(android.net.ConnectivityManager);
+    method @Deprecated @ReplaceWith(expression="cm.isActiveNetworkMetered()") @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public static boolean isActiveNetworkMetered(android.net.ConnectivityManager);
     field public static final int RESTRICT_BACKGROUND_STATUS_DISABLED = 1; // 0x1
     field public static final int RESTRICT_BACKGROUND_STATUS_ENABLED = 3; // 0x3
     field public static final int RESTRICT_BACKGROUND_STATUS_WHITELISTED = 2; // 0x2
@@ -2261,13 +2261,13 @@
   }
 
   public final class BundleCompat {
-    method @Deprecated public static android.os.IBinder? getBinder(android.os.Bundle, String?);
+    method @Deprecated @ReplaceWith(expression="bundle.getBinder(key)") public static android.os.IBinder? getBinder(android.os.Bundle, String?);
     method public static <T> T? getParcelable(android.os.Bundle, String?, Class<T!>);
     method public static android.os.Parcelable![]? getParcelableArray(android.os.Bundle, String?, Class<? extends android.os.Parcelable!>);
     method public static <T> java.util.ArrayList<T!>? getParcelableArrayList(android.os.Bundle, String?, Class<? extends T!>);
     method public static <T extends java.io.Serializable> T? getSerializable(android.os.Bundle, String?, Class<T!>);
     method public static <T> android.util.SparseArray<T!>? getSparseParcelableArray(android.os.Bundle, String?, Class<? extends T!>);
-    method @Deprecated public static void putBinder(android.os.Bundle, String?, android.os.IBinder?);
+    method @Deprecated @ReplaceWith(expression="bundle.putBinder(key, binder)") public static void putBinder(android.os.Bundle, String?, android.os.IBinder?);
   }
 
   @Deprecated public final class CancellationSignal {
@@ -2346,7 +2346,7 @@
     method @RequiresApi(api=android.os.Build.VERSION_CODES.Q) public static <T> java.util.List<T!> readParcelableList(android.os.Parcel, java.util.List<T!>, ClassLoader?, Class<T!>);
     method public static <T extends java.io.Serializable> T? readSerializable(android.os.Parcel, ClassLoader?, Class<T!>);
     method public static <T> android.util.SparseArray<T!>? readSparseArray(android.os.Parcel, ClassLoader?, Class<? extends T!>);
-    method public static void writeBoolean(android.os.Parcel, boolean);
+    method @Deprecated @ReplaceWith(expression="out.writeInt(value ? 1 : 0)") public static void writeBoolean(android.os.Parcel, boolean);
   }
 
   @Deprecated public final class ParcelableCompat {
@@ -3077,18 +3077,18 @@
 
   @Deprecated public final class MarginLayoutParamsCompat {
     method @Deprecated public static int getLayoutDirection(android.view.ViewGroup.MarginLayoutParams);
-    method @Deprecated public static int getMarginEnd(android.view.ViewGroup.MarginLayoutParams);
-    method @Deprecated public static int getMarginStart(android.view.ViewGroup.MarginLayoutParams);
-    method @Deprecated public static boolean isMarginRelative(android.view.ViewGroup.MarginLayoutParams);
-    method @Deprecated public static void resolveLayoutDirection(android.view.ViewGroup.MarginLayoutParams, int);
-    method @Deprecated public static void setLayoutDirection(android.view.ViewGroup.MarginLayoutParams, int);
-    method @Deprecated public static void setMarginEnd(android.view.ViewGroup.MarginLayoutParams, int);
-    method @Deprecated public static void setMarginStart(android.view.ViewGroup.MarginLayoutParams, int);
+    method @Deprecated @ReplaceWith(expression="lp.getMarginEnd()") public static int getMarginEnd(android.view.ViewGroup.MarginLayoutParams);
+    method @Deprecated @ReplaceWith(expression="lp.getMarginStart()") public static int getMarginStart(android.view.ViewGroup.MarginLayoutParams);
+    method @Deprecated @ReplaceWith(expression="lp.isMarginRelative()") public static boolean isMarginRelative(android.view.ViewGroup.MarginLayoutParams);
+    method @Deprecated @ReplaceWith(expression="lp.resolveLayoutDirection(layoutDirection)") public static void resolveLayoutDirection(android.view.ViewGroup.MarginLayoutParams, int);
+    method @Deprecated @ReplaceWith(expression="lp.setLayoutDirection(layoutDirection)") public static void setLayoutDirection(android.view.ViewGroup.MarginLayoutParams, int);
+    method @Deprecated @ReplaceWith(expression="lp.setMarginEnd(marginEnd)") public static void setMarginEnd(android.view.ViewGroup.MarginLayoutParams, int);
+    method @Deprecated @ReplaceWith(expression="lp.setMarginStart(marginStart)") public static void setMarginStart(android.view.ViewGroup.MarginLayoutParams, int);
   }
 
   public final class MenuCompat {
     method public static void setGroupDividerEnabled(android.view.Menu, boolean);
-    method @Deprecated public static void setShowAsAction(android.view.MenuItem!, int);
+    method @Deprecated @ReplaceWith(expression="item.setShowAsAction(actionEnum)") public static void setShowAsAction(android.view.MenuItem!, int);
   }
 
   public interface MenuHost {
@@ -3112,20 +3112,20 @@
   }
 
   public final class MenuItemCompat {
-    method @Deprecated public static boolean collapseActionView(android.view.MenuItem!);
-    method @Deprecated public static boolean expandActionView(android.view.MenuItem!);
+    method @Deprecated @ReplaceWith(expression="item.collapseActionView()") public static boolean collapseActionView(android.view.MenuItem!);
+    method @Deprecated @ReplaceWith(expression="item.expandActionView()") public static boolean expandActionView(android.view.MenuItem!);
     method public static androidx.core.view.ActionProvider? getActionProvider(android.view.MenuItem);
-    method @Deprecated public static android.view.View! getActionView(android.view.MenuItem!);
+    method @Deprecated @ReplaceWith(expression="item.getActionView()") public static android.view.View! getActionView(android.view.MenuItem!);
     method public static int getAlphabeticModifiers(android.view.MenuItem);
     method public static CharSequence? getContentDescription(android.view.MenuItem);
     method public static android.content.res.ColorStateList? getIconTintList(android.view.MenuItem);
     method public static android.graphics.PorterDuff.Mode? getIconTintMode(android.view.MenuItem);
     method public static int getNumericModifiers(android.view.MenuItem);
     method public static CharSequence? getTooltipText(android.view.MenuItem);
-    method @Deprecated public static boolean isActionViewExpanded(android.view.MenuItem!);
+    method @Deprecated @ReplaceWith(expression="item.isActionViewExpanded()") public static boolean isActionViewExpanded(android.view.MenuItem!);
     method public static android.view.MenuItem? setActionProvider(android.view.MenuItem, androidx.core.view.ActionProvider?);
-    method @Deprecated public static android.view.MenuItem! setActionView(android.view.MenuItem!, android.view.View!);
-    method @Deprecated public static android.view.MenuItem! setActionView(android.view.MenuItem!, int);
+    method @Deprecated @ReplaceWith(expression="item.setActionView(view)") public static android.view.MenuItem! setActionView(android.view.MenuItem!, android.view.View!);
+    method @Deprecated @ReplaceWith(expression="item.setActionView(resId)") public static android.view.MenuItem! setActionView(android.view.MenuItem!, int);
     method public static void setAlphabeticShortcut(android.view.MenuItem, char, int);
     method public static void setContentDescription(android.view.MenuItem, CharSequence?);
     method public static void setIconTintList(android.view.MenuItem, android.content.res.ColorStateList?);
@@ -3133,7 +3133,7 @@
     method public static void setNumericShortcut(android.view.MenuItem, char, int);
     method @Deprecated public static android.view.MenuItem! setOnActionExpandListener(android.view.MenuItem!, androidx.core.view.MenuItemCompat.OnActionExpandListener!);
     method public static void setShortcut(android.view.MenuItem, char, char, int, int);
-    method @Deprecated public static void setShowAsAction(android.view.MenuItem!, int);
+    method @Deprecated @ReplaceWith(expression="item.setShowAsAction(actionEnum)") public static void setShowAsAction(android.view.MenuItem!, int);
     method public static void setTooltipText(android.view.MenuItem, CharSequence?);
     field @Deprecated public static final int SHOW_AS_ACTION_ALWAYS = 2; // 0x2
     field @Deprecated public static final int SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW = 8; // 0x8
@@ -3155,17 +3155,17 @@
   }
 
   public final class MotionEventCompat {
-    method @Deprecated public static int findPointerIndex(android.view.MotionEvent!, int);
-    method @Deprecated public static int getActionIndex(android.view.MotionEvent!);
-    method @Deprecated public static int getActionMasked(android.view.MotionEvent!);
-    method @Deprecated public static float getAxisValue(android.view.MotionEvent!, int);
-    method @Deprecated public static float getAxisValue(android.view.MotionEvent!, int, int);
-    method @Deprecated public static int getButtonState(android.view.MotionEvent!);
-    method @Deprecated public static int getPointerCount(android.view.MotionEvent!);
-    method @Deprecated public static int getPointerId(android.view.MotionEvent!, int);
-    method @Deprecated public static int getSource(android.view.MotionEvent!);
-    method @Deprecated public static float getX(android.view.MotionEvent!, int);
-    method @Deprecated public static float getY(android.view.MotionEvent!, int);
+    method @Deprecated @ReplaceWith(expression="event.findPointerIndex(pointerId)") public static int findPointerIndex(android.view.MotionEvent!, int);
+    method @Deprecated @ReplaceWith(expression="event.getActionIndex()") public static int getActionIndex(android.view.MotionEvent!);
+    method @Deprecated @ReplaceWith(expression="event.getActionMasked()") public static int getActionMasked(android.view.MotionEvent!);
+    method @Deprecated @ReplaceWith(expression="event.getAxisValue(axis)") public static float getAxisValue(android.view.MotionEvent!, int);
+    method @Deprecated @ReplaceWith(expression="event.getAxisValue(axis, pointerIndex)") public static float getAxisValue(android.view.MotionEvent!, int, int);
+    method @Deprecated @ReplaceWith(expression="event.getButtonState()") public static int getButtonState(android.view.MotionEvent!);
+    method @Deprecated @ReplaceWith(expression="event.getPointerCount()") public static int getPointerCount(android.view.MotionEvent!);
+    method @Deprecated @ReplaceWith(expression="event.getPointerId(pointerIndex)") public static int getPointerId(android.view.MotionEvent!, int);
+    method @Deprecated @ReplaceWith(expression="event.getSource()") public static int getSource(android.view.MotionEvent!);
+    method @Deprecated @ReplaceWith(expression="event.getX(pointerIndex)") public static float getX(android.view.MotionEvent!, int);
+    method @Deprecated @ReplaceWith(expression="event.getY(pointerIndex)") public static float getY(android.view.MotionEvent!, int);
     method public static boolean isFromSource(android.view.MotionEvent, int);
     field @Deprecated public static final int ACTION_HOVER_ENTER = 9; // 0x9
     field @Deprecated public static final int ACTION_HOVER_EXIT = 10; // 0xa
@@ -3352,9 +3352,9 @@
   }
 
   public final class ScaleGestureDetectorCompat {
-    method public static boolean isQuickScaleEnabled(android.view.ScaleGestureDetector);
+    method @Deprecated @ReplaceWith(expression="scaleGestureDetector.isQuickScaleEnabled()") public static boolean isQuickScaleEnabled(android.view.ScaleGestureDetector);
     method @Deprecated public static boolean isQuickScaleEnabled(Object!);
-    method public static void setQuickScaleEnabled(android.view.ScaleGestureDetector, boolean);
+    method @Deprecated @ReplaceWith(expression="scaleGestureDetector.setQuickScaleEnabled(enabled)") public static void setQuickScaleEnabled(android.view.ScaleGestureDetector, boolean);
     method @Deprecated public static void setQuickScaleEnabled(Object!, boolean);
   }
 
@@ -3387,8 +3387,8 @@
     method public static void computeCurrentVelocity(android.view.VelocityTracker, int, float);
     method public static float getAxisVelocity(android.view.VelocityTracker, @androidx.core.view.VelocityTrackerCompat.VelocityTrackableMotionEventAxis int);
     method public static float getAxisVelocity(android.view.VelocityTracker, @androidx.core.view.VelocityTrackerCompat.VelocityTrackableMotionEventAxis int, int);
-    method @Deprecated public static float getXVelocity(android.view.VelocityTracker!, int);
-    method @Deprecated public static float getYVelocity(android.view.VelocityTracker!, int);
+    method @Deprecated @ReplaceWith(expression="tracker.getXVelocity(pointerId)") public static float getXVelocity(android.view.VelocityTracker!, int);
+    method @Deprecated @ReplaceWith(expression="tracker.getYVelocity(pointerId)") public static float getYVelocity(android.view.VelocityTracker!, int);
     method public static boolean isAxisSupported(android.view.VelocityTracker, @androidx.core.view.VelocityTrackerCompat.VelocityTrackableMotionEventAxis int);
     method public static void recycle(android.view.VelocityTracker);
   }
@@ -3402,8 +3402,8 @@
     method public static void addKeyboardNavigationClusters(android.view.View, java.util.Collection<android.view.View!>, int);
     method public static void addOnUnhandledKeyEventListener(android.view.View, androidx.core.view.ViewCompat.OnUnhandledKeyEventListenerCompat);
     method @Deprecated public static androidx.core.view.ViewPropertyAnimatorCompat animate(android.view.View);
-    method @Deprecated public static boolean canScrollHorizontally(android.view.View!, int);
-    method @Deprecated public static boolean canScrollVertically(android.view.View!, int);
+    method @Deprecated @ReplaceWith(expression="view.canScrollHorizontally(direction)") public static boolean canScrollHorizontally(android.view.View!, int);
+    method @Deprecated @ReplaceWith(expression="view.canScrollVertically(direction)") public static boolean canScrollVertically(android.view.View!, int);
     method public static void cancelDragAndDrop(android.view.View);
     method @Deprecated public static int combineMeasuredStates(int, int);
     method public static androidx.core.view.WindowInsetsCompat computeSystemWindowInsets(android.view.View, androidx.core.view.WindowInsetsCompat, android.graphics.Rect);
@@ -3420,93 +3420,93 @@
     method public static void enableAccessibleClickableSpanSupport(android.view.View);
     method @Deprecated public static int generateViewId();
     method public static androidx.core.view.AccessibilityDelegateCompat? getAccessibilityDelegate(android.view.View);
-    method @Deprecated public static int getAccessibilityLiveRegion(android.view.View);
+    method @Deprecated @ReplaceWith(expression="view.getAccessibilityLiveRegion()") public static int getAccessibilityLiveRegion(android.view.View);
     method public static androidx.core.view.accessibility.AccessibilityNodeProviderCompat? getAccessibilityNodeProvider(android.view.View);
     method @UiThread public static CharSequence? getAccessibilityPaneTitle(android.view.View);
-    method @Deprecated public static float getAlpha(android.view.View!);
+    method @Deprecated @ReplaceWith(expression="view.getAlpha()") public static float getAlpha(android.view.View!);
     method public static androidx.core.view.autofill.AutofillIdCompat? getAutofillId(android.view.View);
     method public static android.content.res.ColorStateList? getBackgroundTintList(android.view.View);
     method public static android.graphics.PorterDuff.Mode? getBackgroundTintMode(android.view.View);
-    method @Deprecated public static android.graphics.Rect? getClipBounds(android.view.View);
+    method @Deprecated @ReplaceWith(expression="view.getClipBounds()") public static android.graphics.Rect? getClipBounds(android.view.View);
     method public static androidx.core.view.contentcapture.ContentCaptureSessionCompat? getContentCaptureSession(android.view.View);
-    method @Deprecated public static android.view.Display? getDisplay(android.view.View);
+    method @Deprecated @ReplaceWith(expression="view.getDisplay()") public static android.view.Display? getDisplay(android.view.View);
     method public static float getElevation(android.view.View);
-    method @Deprecated public static boolean getFitsSystemWindows(android.view.View);
-    method @Deprecated public static int getImportantForAccessibility(android.view.View);
+    method @Deprecated @ReplaceWith(expression="view.getFitsSystemWindows()") public static boolean getFitsSystemWindows(android.view.View);
+    method @Deprecated @ReplaceWith(expression="view.getImportantForAccessibility()") public static int getImportantForAccessibility(android.view.View);
     method public static int getImportantForAutofill(android.view.View);
     method public static int getImportantForContentCapture(android.view.View);
-    method @Deprecated public static int getLabelFor(android.view.View);
-    method @Deprecated public static int getLayerType(android.view.View!);
-    method @Deprecated public static int getLayoutDirection(android.view.View);
-    method @Deprecated public static android.graphics.Matrix? getMatrix(android.view.View!);
-    method @Deprecated public static int getMeasuredHeightAndState(android.view.View!);
-    method @Deprecated public static int getMeasuredState(android.view.View!);
-    method @Deprecated public static int getMeasuredWidthAndState(android.view.View!);
-    method @Deprecated public static int getMinimumHeight(android.view.View);
-    method @Deprecated public static int getMinimumWidth(android.view.View);
+    method @Deprecated @ReplaceWith(expression="view.getLabelFor()") public static int getLabelFor(android.view.View);
+    method @Deprecated @ReplaceWith(expression="view.getLayerType()") public static int getLayerType(android.view.View!);
+    method @Deprecated @ReplaceWith(expression="view.getLayoutDirection()") public static int getLayoutDirection(android.view.View);
+    method @Deprecated @ReplaceWith(expression="view.getMatrix()") public static android.graphics.Matrix? getMatrix(android.view.View!);
+    method @Deprecated @ReplaceWith(expression="view.getMeasuredHeightAndState()") public static int getMeasuredHeightAndState(android.view.View!);
+    method @Deprecated @ReplaceWith(expression="view.getMeasuredState()") public static int getMeasuredState(android.view.View!);
+    method @Deprecated @ReplaceWith(expression="view.getMeasuredWidthAndState()") public static int getMeasuredWidthAndState(android.view.View!);
+    method @Deprecated @ReplaceWith(expression="view.getMinimumHeight()") public static int getMinimumHeight(android.view.View);
+    method @Deprecated @ReplaceWith(expression="view.getMinimumWidth()") public static int getMinimumWidth(android.view.View);
     method public static int getNextClusterForwardId(android.view.View);
     method public static String![]? getOnReceiveContentMimeTypes(android.view.View);
-    method @Deprecated public static int getOverScrollMode(android.view.View!);
-    method @Deprecated @Px public static int getPaddingEnd(android.view.View);
-    method @Deprecated @Px public static int getPaddingStart(android.view.View);
-    method @Deprecated public static android.view.ViewParent? getParentForAccessibility(android.view.View);
-    method @Deprecated public static float getPivotX(android.view.View!);
-    method @Deprecated public static float getPivotY(android.view.View!);
+    method @Deprecated @ReplaceWith(expression="view.getOverScrollMode()") public static int getOverScrollMode(android.view.View!);
+    method @Deprecated @Px @ReplaceWith(expression="view.getPaddingEnd()") public static int getPaddingEnd(android.view.View);
+    method @Deprecated @Px @ReplaceWith(expression="view.getPaddingStart()") public static int getPaddingStart(android.view.View);
+    method @Deprecated @ReplaceWith(expression="view.getParentForAccessibility()") public static android.view.ViewParent? getParentForAccessibility(android.view.View);
+    method @Deprecated @ReplaceWith(expression="view.getPivotX()") public static float getPivotX(android.view.View!);
+    method @Deprecated @ReplaceWith(expression="view.getPivotY()") public static float getPivotY(android.view.View!);
     method public static androidx.core.view.WindowInsetsCompat? getRootWindowInsets(android.view.View);
-    method @Deprecated public static float getRotation(android.view.View!);
-    method @Deprecated public static float getRotationX(android.view.View!);
-    method @Deprecated public static float getRotationY(android.view.View!);
-    method @Deprecated public static float getScaleX(android.view.View!);
-    method @Deprecated public static float getScaleY(android.view.View!);
+    method @Deprecated @ReplaceWith(expression="view.getRotation()") public static float getRotation(android.view.View!);
+    method @Deprecated @ReplaceWith(expression="view.getRotationX()") public static float getRotationX(android.view.View!);
+    method @Deprecated @ReplaceWith(expression="view.getRotationY()") public static float getRotationY(android.view.View!);
+    method @Deprecated @ReplaceWith(expression="view.getScaleX()") public static float getScaleX(android.view.View!);
+    method @Deprecated @ReplaceWith(expression="view.getScaleY()") public static float getScaleY(android.view.View!);
     method public static int getScrollIndicators(android.view.View);
     method @UiThread public static CharSequence? getStateDescription(android.view.View);
     method public static java.util.List<android.graphics.Rect!> getSystemGestureExclusionRects(android.view.View);
     method public static String? getTransitionName(android.view.View);
-    method @Deprecated public static float getTranslationX(android.view.View!);
-    method @Deprecated public static float getTranslationY(android.view.View!);
+    method @Deprecated @ReplaceWith(expression="view.getTranslationX()") public static float getTranslationX(android.view.View!);
+    method @Deprecated @ReplaceWith(expression="view.getTranslationY()") public static float getTranslationY(android.view.View!);
     method public static float getTranslationZ(android.view.View);
     method @Deprecated public static androidx.core.view.WindowInsetsControllerCompat? getWindowInsetsController(android.view.View);
-    method @Deprecated public static int getWindowSystemUiVisibility(android.view.View);
-    method @Deprecated public static float getX(android.view.View!);
-    method @Deprecated public static float getY(android.view.View!);
+    method @Deprecated @ReplaceWith(expression="view.getWindowSystemUiVisibility()") public static int getWindowSystemUiVisibility(android.view.View);
+    method @Deprecated @ReplaceWith(expression="view.getX()") public static float getX(android.view.View!);
+    method @Deprecated @ReplaceWith(expression="view.getY()") public static float getY(android.view.View!);
     method public static float getZ(android.view.View);
     method public static boolean hasAccessibilityDelegate(android.view.View);
     method public static boolean hasExplicitFocusable(android.view.View);
     method public static boolean hasNestedScrollingParent(android.view.View);
     method public static boolean hasNestedScrollingParent(android.view.View, @androidx.core.view.ViewCompat.NestedScrollType int);
-    method @Deprecated public static boolean hasOnClickListeners(android.view.View);
-    method @Deprecated public static boolean hasOverlappingRendering(android.view.View);
-    method @Deprecated public static boolean hasTransientState(android.view.View);
+    method @Deprecated @ReplaceWith(expression="view.hasOnClickListeners()") public static boolean hasOnClickListeners(android.view.View);
+    method @Deprecated @ReplaceWith(expression="view.hasOverlappingRendering()") public static boolean hasOverlappingRendering(android.view.View);
+    method @Deprecated @ReplaceWith(expression="view.hasTransientState()") public static boolean hasTransientState(android.view.View);
     method @UiThread public static boolean isAccessibilityHeading(android.view.View);
-    method @Deprecated public static boolean isAttachedToWindow(android.view.View);
+    method @Deprecated @ReplaceWith(expression="view.isAttachedToWindow()") public static boolean isAttachedToWindow(android.view.View);
     method public static boolean isFocusedByDefault(android.view.View);
     method public static boolean isImportantForAccessibility(android.view.View);
     method public static boolean isImportantForAutofill(android.view.View);
     method public static boolean isImportantForContentCapture(android.view.View);
-    method @Deprecated public static boolean isInLayout(android.view.View);
+    method @Deprecated @ReplaceWith(expression="view.isInLayout()") public static boolean isInLayout(android.view.View);
     method public static boolean isKeyboardNavigationCluster(android.view.View);
-    method @Deprecated public static boolean isLaidOut(android.view.View);
-    method @Deprecated public static boolean isLayoutDirectionResolved(android.view.View);
+    method @Deprecated @ReplaceWith(expression="view.isLaidOut()") public static boolean isLaidOut(android.view.View);
+    method @Deprecated @ReplaceWith(expression="view.isLayoutDirectionResolved()") public static boolean isLayoutDirectionResolved(android.view.View);
     method public static boolean isNestedScrollingEnabled(android.view.View);
-    method @Deprecated public static boolean isOpaque(android.view.View!);
-    method @Deprecated public static boolean isPaddingRelative(android.view.View);
+    method @Deprecated @ReplaceWith(expression="view.isOpaque()") public static boolean isOpaque(android.view.View!);
+    method @Deprecated @ReplaceWith(expression="view.isPaddingRelative()") public static boolean isPaddingRelative(android.view.View);
     method @UiThread public static boolean isScreenReaderFocusable(android.view.View);
-    method @Deprecated public static void jumpDrawablesToCurrentState(android.view.View!);
+    method @Deprecated @ReplaceWith(expression="view.jumpDrawablesToCurrentState()") public static void jumpDrawablesToCurrentState(android.view.View!);
     method public static android.view.View? keyboardNavigationClusterSearch(android.view.View, android.view.View?, @androidx.core.view.ViewCompat.FocusDirection int);
     method public static void offsetLeftAndRight(android.view.View, int);
     method public static void offsetTopAndBottom(android.view.View, int);
     method public static androidx.core.view.WindowInsetsCompat onApplyWindowInsets(android.view.View, androidx.core.view.WindowInsetsCompat);
-    method @Deprecated public static void onInitializeAccessibilityEvent(android.view.View!, android.view.accessibility.AccessibilityEvent!);
-    method @Deprecated public static void onInitializeAccessibilityNodeInfo(android.view.View, androidx.core.view.accessibility.AccessibilityNodeInfoCompat);
-    method @Deprecated public static void onPopulateAccessibilityEvent(android.view.View!, android.view.accessibility.AccessibilityEvent!);
-    method @Deprecated public static boolean performAccessibilityAction(android.view.View, int, android.os.Bundle?);
+    method @Deprecated @ReplaceWith(expression="v.onInitializeAccessibilityEvent(event)") public static void onInitializeAccessibilityEvent(android.view.View!, android.view.accessibility.AccessibilityEvent!);
+    method @Deprecated @ReplaceWith(expression="v.onInitializeAccessibilityNodeInfo(info.unwrap())") public static void onInitializeAccessibilityNodeInfo(android.view.View, androidx.core.view.accessibility.AccessibilityNodeInfoCompat);
+    method @Deprecated @ReplaceWith(expression="v.onPopulateAccessibilityEvent(event)") public static void onPopulateAccessibilityEvent(android.view.View!, android.view.accessibility.AccessibilityEvent!);
+    method @Deprecated @ReplaceWith(expression="view.performAccessibilityAction(action, arguments)") public static boolean performAccessibilityAction(android.view.View, int, android.os.Bundle?);
     method public static boolean performHapticFeedback(android.view.View, int);
     method public static boolean performHapticFeedback(android.view.View, int, int);
     method public static androidx.core.view.ContentInfoCompat? performReceiveContent(android.view.View, androidx.core.view.ContentInfoCompat);
-    method @Deprecated public static void postInvalidateOnAnimation(android.view.View);
-    method @Deprecated public static void postInvalidateOnAnimation(android.view.View, int, int, int, int);
-    method @Deprecated public static void postOnAnimation(android.view.View, Runnable);
-    method @Deprecated public static void postOnAnimationDelayed(android.view.View, Runnable, long);
+    method @Deprecated @ReplaceWith(expression="view.postInvalidateOnAnimation()") public static void postInvalidateOnAnimation(android.view.View);
+    method @Deprecated @ReplaceWith(expression="view.postInvalidateOnAnimation(left, top, right, bottom)") public static void postInvalidateOnAnimation(android.view.View, int, int, int, int);
+    method @Deprecated @ReplaceWith(expression="view.postOnAnimation(action)") public static void postOnAnimation(android.view.View, Runnable);
+    method @Deprecated @ReplaceWith(expression="view.postOnAnimationDelayed(action, delayMillis)") public static void postOnAnimationDelayed(android.view.View, Runnable, long);
     method public static void removeAccessibilityAction(android.view.View, int);
     method public static void removeOnUnhandledKeyEventListener(android.view.View, androidx.core.view.ViewCompat.OnUnhandledKeyEventListenerCompat);
     method public static void replaceAccessibilityAction(android.view.View, androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat, CharSequence?, androidx.core.view.accessibility.AccessibilityViewCommand?);
@@ -3517,45 +3517,45 @@
     method public static void saveAttributeDataForStyleable(android.view.View, android.content.Context, int[], android.util.AttributeSet?, android.content.res.TypedArray, int, int);
     method public static void setAccessibilityDelegate(android.view.View, androidx.core.view.AccessibilityDelegateCompat?);
     method @UiThread public static void setAccessibilityHeading(android.view.View, boolean);
-    method @Deprecated public static void setAccessibilityLiveRegion(android.view.View, int);
+    method @Deprecated @ReplaceWith(expression="view.setAccessibilityLiveRegion(mode)") public static void setAccessibilityLiveRegion(android.view.View, int);
     method @UiThread public static void setAccessibilityPaneTitle(android.view.View, CharSequence?);
-    method @Deprecated public static void setActivated(android.view.View!, boolean);
-    method @Deprecated public static void setAlpha(android.view.View!, @FloatRange(from=0.0, to=1.0) float);
+    method @Deprecated @ReplaceWith(expression="view.setActivated(activated)") public static void setActivated(android.view.View!, boolean);
+    method @Deprecated @ReplaceWith(expression="view.setAlpha(value)") public static void setAlpha(android.view.View!, @FloatRange(from=0.0, to=1.0) float);
     method public static void setAutofillHints(android.view.View, java.lang.String!...?);
     method public static void setAutofillId(android.view.View, androidx.core.view.autofill.AutofillIdCompat?);
-    method @Deprecated public static void setBackground(android.view.View, android.graphics.drawable.Drawable?);
+    method @Deprecated @ReplaceWith(expression="view.setBackground(background)") public static void setBackground(android.view.View, android.graphics.drawable.Drawable?);
     method public static void setBackgroundTintList(android.view.View, android.content.res.ColorStateList?);
     method public static void setBackgroundTintMode(android.view.View, android.graphics.PorterDuff.Mode?);
     method @Deprecated public static void setChildrenDrawingOrderEnabled(android.view.ViewGroup!, boolean);
-    method @Deprecated public static void setClipBounds(android.view.View, android.graphics.Rect?);
+    method @Deprecated @ReplaceWith(expression="view.setClipBounds(clipBounds)") public static void setClipBounds(android.view.View, android.graphics.Rect?);
     method public static void setContentCaptureSession(android.view.View, androidx.core.view.contentcapture.ContentCaptureSessionCompat?);
     method public static void setElevation(android.view.View, float);
-    method @Deprecated public static void setFitsSystemWindows(android.view.View!, boolean);
+    method @Deprecated @ReplaceWith(expression="view.setFitsSystemWindows(fitSystemWindows)") public static void setFitsSystemWindows(android.view.View!, boolean);
     method public static void setFocusedByDefault(android.view.View, boolean);
-    method @Deprecated public static void setHasTransientState(android.view.View, boolean);
-    method @Deprecated @UiThread public static void setImportantForAccessibility(android.view.View, int);
+    method @Deprecated @ReplaceWith(expression="view.setHasTransientState(hasTransientState)") public static void setHasTransientState(android.view.View, boolean);
+    method @Deprecated @ReplaceWith(expression="view.setImportantForAccessibility(mode)") @UiThread public static void setImportantForAccessibility(android.view.View, int);
     method public static void setImportantForAutofill(android.view.View, int);
     method public static void setImportantForContentCapture(android.view.View, int);
     method public static void setKeyboardNavigationCluster(android.view.View, boolean);
-    method @Deprecated public static void setLabelFor(android.view.View, @IdRes int);
-    method @Deprecated public static void setLayerPaint(android.view.View, android.graphics.Paint?);
-    method @Deprecated public static void setLayerType(android.view.View!, int, android.graphics.Paint!);
-    method @Deprecated public static void setLayoutDirection(android.view.View, int);
+    method @Deprecated @ReplaceWith(expression="view.setLabelFor(labeledId)") public static void setLabelFor(android.view.View, @IdRes int);
+    method @Deprecated @ReplaceWith(expression="view.setLayerPaint(paint)") public static void setLayerPaint(android.view.View, android.graphics.Paint?);
+    method @Deprecated @ReplaceWith(expression="view.setLayerType(layerType, paint)") public static void setLayerType(android.view.View!, int, android.graphics.Paint!);
+    method @Deprecated @ReplaceWith(expression="view.setLayoutDirection(layoutDirection)") public static void setLayoutDirection(android.view.View, int);
     method public static void setNestedScrollingEnabled(android.view.View, boolean);
     method public static void setNextClusterForwardId(android.view.View, int);
     method public static void setOnApplyWindowInsetsListener(android.view.View, androidx.core.view.OnApplyWindowInsetsListener?);
     method public static void setOnReceiveContentListener(android.view.View, String![]?, androidx.core.view.OnReceiveContentListener?);
-    method @Deprecated public static void setOverScrollMode(android.view.View!, int);
-    method @Deprecated public static void setPaddingRelative(android.view.View, @Px int, @Px int, @Px int, @Px int);
-    method @Deprecated public static void setPivotX(android.view.View!, float);
-    method @Deprecated public static void setPivotY(android.view.View!, float);
+    method @Deprecated @ReplaceWith(expression="view.setOverScrollMode(overScrollMode)") public static void setOverScrollMode(android.view.View!, int);
+    method @Deprecated @ReplaceWith(expression="view.setPaddingRelative(start, top, end, bottom)") public static void setPaddingRelative(android.view.View, @Px int, @Px int, @Px int, @Px int);
+    method @Deprecated @ReplaceWith(expression="view.setPivotX(value)") public static void setPivotX(android.view.View!, float);
+    method @Deprecated @ReplaceWith(expression="view.setPivotY(value)") public static void setPivotY(android.view.View!, float);
     method public static void setPointerIcon(android.view.View, androidx.core.view.PointerIconCompat?);
-    method @Deprecated public static void setRotation(android.view.View!, float);
-    method @Deprecated public static void setRotationX(android.view.View!, float);
-    method @Deprecated public static void setRotationY(android.view.View!, float);
-    method @Deprecated public static void setSaveFromParentEnabled(android.view.View!, boolean);
-    method @Deprecated public static void setScaleX(android.view.View!, float);
-    method @Deprecated public static void setScaleY(android.view.View!, float);
+    method @Deprecated @ReplaceWith(expression="view.setRotation(value)") public static void setRotation(android.view.View!, float);
+    method @Deprecated @ReplaceWith(expression="view.setRotationX(value)") public static void setRotationX(android.view.View!, float);
+    method @Deprecated @ReplaceWith(expression="view.setRotationY(value)") public static void setRotationY(android.view.View!, float);
+    method @Deprecated @ReplaceWith(expression="view.setSaveFromParentEnabled(enabled)") public static void setSaveFromParentEnabled(android.view.View!, boolean);
+    method @Deprecated @ReplaceWith(expression="view.setScaleX(value)") public static void setScaleX(android.view.View!, float);
+    method @Deprecated @ReplaceWith(expression="view.setScaleY(value)") public static void setScaleY(android.view.View!, float);
     method @UiThread public static void setScreenReaderFocusable(android.view.View, boolean);
     method public static void setScrollIndicators(android.view.View, @androidx.core.view.ViewCompat.ScrollIndicators int);
     method public static void setScrollIndicators(android.view.View, @androidx.core.view.ViewCompat.ScrollIndicators int, @androidx.core.view.ViewCompat.ScrollIndicators int);
@@ -3563,12 +3563,12 @@
     method public static void setSystemGestureExclusionRects(android.view.View, java.util.List<android.graphics.Rect!>);
     method public static void setTooltipText(android.view.View, CharSequence?);
     method public static void setTransitionName(android.view.View, String?);
-    method @Deprecated public static void setTranslationX(android.view.View!, float);
-    method @Deprecated public static void setTranslationY(android.view.View!, float);
+    method @Deprecated @ReplaceWith(expression="view.setTranslationX(value)") public static void setTranslationX(android.view.View!, float);
+    method @Deprecated @ReplaceWith(expression="view.setTranslationY(value)") public static void setTranslationY(android.view.View!, float);
     method public static void setTranslationZ(android.view.View, float);
     method public static void setWindowInsetsAnimationCallback(android.view.View, androidx.core.view.WindowInsetsAnimationCompat.Callback?);
-    method @Deprecated public static void setX(android.view.View!, float);
-    method @Deprecated public static void setY(android.view.View!, float);
+    method @Deprecated @ReplaceWith(expression="view.setX(value)") public static void setX(android.view.View!, float);
+    method @Deprecated @ReplaceWith(expression="view.setY(value)") public static void setY(android.view.View!, float);
     method public static void setZ(android.view.View, float);
     method public static boolean startDragAndDrop(android.view.View, android.content.ClipData?, android.view.View.DragShadowBuilder, Object?, int);
     method public static boolean startNestedScroll(android.view.View, @androidx.core.view.ViewCompat.ScrollAxis int);
@@ -3642,26 +3642,26 @@
     method public static int getScaledHoverSlop(android.view.ViewConfiguration);
     method public static int getScaledMaximumFlingVelocity(android.content.Context, android.view.ViewConfiguration, int, int, int);
     method public static int getScaledMinimumFlingVelocity(android.content.Context, android.view.ViewConfiguration, int, int, int);
-    method @Deprecated public static int getScaledPagingTouchSlop(android.view.ViewConfiguration!);
+    method @Deprecated @ReplaceWith(expression="config.getScaledPagingTouchSlop()") public static int getScaledPagingTouchSlop(android.view.ViewConfiguration!);
     method public static float getScaledVerticalScrollFactor(android.view.ViewConfiguration, android.content.Context);
-    method @Deprecated public static boolean hasPermanentMenuKey(android.view.ViewConfiguration!);
+    method @Deprecated @ReplaceWith(expression="config.hasPermanentMenuKey()") public static boolean hasPermanentMenuKey(android.view.ViewConfiguration!);
     method public static boolean shouldShowMenuShortcutsWhenKeyboardPresent(android.view.ViewConfiguration, android.content.Context);
   }
 
   public final class ViewGroupCompat {
-    method public static int getLayoutMode(android.view.ViewGroup);
+    method @Deprecated @ReplaceWith(expression="group.getLayoutMode()") public static int getLayoutMode(android.view.ViewGroup);
     method @androidx.core.view.ViewCompat.ScrollAxis public static int getNestedScrollAxes(android.view.ViewGroup);
     method public static boolean isTransitionGroup(android.view.ViewGroup);
-    method @Deprecated public static boolean onRequestSendAccessibilityEvent(android.view.ViewGroup!, android.view.View!, android.view.accessibility.AccessibilityEvent!);
-    method public static void setLayoutMode(android.view.ViewGroup, int);
-    method @Deprecated public static void setMotionEventSplittingEnabled(android.view.ViewGroup!, boolean);
+    method @Deprecated @ReplaceWith(expression="group.onRequestSendAccessibilityEvent(child, event)") public static boolean onRequestSendAccessibilityEvent(android.view.ViewGroup!, android.view.View!, android.view.accessibility.AccessibilityEvent!);
+    method @Deprecated @ReplaceWith(expression="group.setLayoutMode(mode)") public static void setLayoutMode(android.view.ViewGroup, int);
+    method @Deprecated @ReplaceWith(expression="group.setMotionEventSplittingEnabled(split)") public static void setMotionEventSplittingEnabled(android.view.ViewGroup!, boolean);
     method public static void setTransitionGroup(android.view.ViewGroup, boolean);
     field public static final int LAYOUT_MODE_CLIP_BOUNDS = 0; // 0x0
     field public static final int LAYOUT_MODE_OPTICAL_BOUNDS = 1; // 0x1
   }
 
   public final class ViewParentCompat {
-    method public static void notifySubtreeAccessibilityStateChanged(android.view.ViewParent, android.view.View, android.view.View, int);
+    method @Deprecated @ReplaceWith(expression="parent.notifySubtreeAccessibilityStateChanged(child, source, changeType)") public static void notifySubtreeAccessibilityStateChanged(android.view.ViewParent, android.view.View, android.view.View, int);
     method public static boolean onNestedFling(android.view.ViewParent, android.view.View, float, float, boolean);
     method public static boolean onNestedPreFling(android.view.ViewParent, android.view.View, float, float);
     method public static void onNestedPreScroll(android.view.ViewParent, android.view.View, int, int, int[]);
@@ -3675,7 +3675,7 @@
     method public static boolean onStartNestedScroll(android.view.ViewParent, android.view.View, android.view.View, int, int);
     method public static void onStopNestedScroll(android.view.ViewParent, android.view.View);
     method public static void onStopNestedScroll(android.view.ViewParent, android.view.View, int);
-    method @Deprecated public static boolean requestSendAccessibilityEvent(android.view.ViewParent!, android.view.View!, android.view.accessibility.AccessibilityEvent!);
+    method @Deprecated @ReplaceWith(expression="parent.requestSendAccessibilityEvent(child, event)") public static boolean requestSendAccessibilityEvent(android.view.ViewParent!, android.view.View!, android.view.accessibility.AccessibilityEvent!);
   }
 
   public final class ViewPropertyAnimatorCompat {
@@ -3910,18 +3910,18 @@
   }
 
   public final class AccessibilityEventCompat {
-    method @Deprecated public static void appendRecord(android.view.accessibility.AccessibilityEvent!, androidx.core.view.accessibility.AccessibilityRecordCompat!);
+    method @Deprecated @ReplaceWith(expression="event.appendRecord(record)") public static void appendRecord(android.view.accessibility.AccessibilityEvent!, androidx.core.view.accessibility.AccessibilityRecordCompat!);
     method @Deprecated public static androidx.core.view.accessibility.AccessibilityRecordCompat! asRecord(android.view.accessibility.AccessibilityEvent!);
-    method public static int getAction(android.view.accessibility.AccessibilityEvent);
-    method @androidx.core.view.accessibility.AccessibilityEventCompat.ContentChangeType public static int getContentChangeTypes(android.view.accessibility.AccessibilityEvent);
-    method public static int getMovementGranularity(android.view.accessibility.AccessibilityEvent);
+    method @Deprecated @ReplaceWith(expression="event.getAction()") public static int getAction(android.view.accessibility.AccessibilityEvent);
+    method @Deprecated @ReplaceWith(expression="event.getContentChangeTypes()") @androidx.core.view.accessibility.AccessibilityEventCompat.ContentChangeType public static int getContentChangeTypes(android.view.accessibility.AccessibilityEvent);
+    method @Deprecated @ReplaceWith(expression="event.getMovementGranularity()") public static int getMovementGranularity(android.view.accessibility.AccessibilityEvent);
     method @Deprecated public static androidx.core.view.accessibility.AccessibilityRecordCompat! getRecord(android.view.accessibility.AccessibilityEvent!, int);
-    method @Deprecated public static int getRecordCount(android.view.accessibility.AccessibilityEvent!);
+    method @Deprecated @ReplaceWith(expression="event.getRecordCount()") public static int getRecordCount(android.view.accessibility.AccessibilityEvent!);
     method public static boolean isAccessibilityDataSensitive(android.view.accessibility.AccessibilityEvent);
     method public static void setAccessibilityDataSensitive(android.view.accessibility.AccessibilityEvent, boolean);
-    method public static void setAction(android.view.accessibility.AccessibilityEvent, int);
-    method public static void setContentChangeTypes(android.view.accessibility.AccessibilityEvent, @androidx.core.view.accessibility.AccessibilityEventCompat.ContentChangeType int);
-    method public static void setMovementGranularity(android.view.accessibility.AccessibilityEvent, int);
+    method @Deprecated @ReplaceWith(expression="event.setAction(action)") public static void setAction(android.view.accessibility.AccessibilityEvent, int);
+    method @Deprecated @ReplaceWith(expression="event.setContentChangeTypes(changeTypes)") public static void setContentChangeTypes(android.view.accessibility.AccessibilityEvent, @androidx.core.view.accessibility.AccessibilityEventCompat.ContentChangeType int);
+    method @Deprecated @ReplaceWith(expression="event.setMovementGranularity(granularity)") public static void setMovementGranularity(android.view.accessibility.AccessibilityEvent, int);
     field public static final int CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION = 4; // 0x4
     field public static final int CONTENT_CHANGE_TYPE_CONTENT_INVALID = 1024; // 0x400
     field public static final int CONTENT_CHANGE_TYPE_DRAG_CANCELLED = 512; // 0x200
@@ -3963,13 +3963,13 @@
 
   public final class AccessibilityManagerCompat {
     method @Deprecated public static boolean addAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager!, androidx.core.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener!);
-    method public static boolean addTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager, androidx.core.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener);
-    method @Deprecated public static java.util.List<android.accessibilityservice.AccessibilityServiceInfo!>! getEnabledAccessibilityServiceList(android.view.accessibility.AccessibilityManager!, int);
-    method @Deprecated public static java.util.List<android.accessibilityservice.AccessibilityServiceInfo!>! getInstalledAccessibilityServiceList(android.view.accessibility.AccessibilityManager!);
+    method @Deprecated @ReplaceWith(expression="manager.addTouchExplorationStateChangeListener(listener)") public static boolean addTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager, androidx.core.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener);
+    method @Deprecated @ReplaceWith(expression="manager.getEnabledAccessibilityServiceList(feedbackTypeFlags)") public static java.util.List<android.accessibilityservice.AccessibilityServiceInfo!>! getEnabledAccessibilityServiceList(android.view.accessibility.AccessibilityManager!, int);
+    method @Deprecated @ReplaceWith(expression="manager.getInstalledAccessibilityServiceList()") public static java.util.List<android.accessibilityservice.AccessibilityServiceInfo!>! getInstalledAccessibilityServiceList(android.view.accessibility.AccessibilityManager!);
     method public static boolean isRequestFromAccessibilityTool(android.view.accessibility.AccessibilityManager);
-    method @Deprecated public static boolean isTouchExplorationEnabled(android.view.accessibility.AccessibilityManager!);
+    method @Deprecated @ReplaceWith(expression="manager.isTouchExplorationEnabled()") public static boolean isTouchExplorationEnabled(android.view.accessibility.AccessibilityManager!);
     method @Deprecated public static boolean removeAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager!, androidx.core.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener!);
-    method public static boolean removeTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager, androidx.core.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener);
+    method @Deprecated @ReplaceWith(expression="manager.removeTouchExplorationStateChangeListener(listener)") public static boolean removeTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager, androidx.core.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener);
   }
 
   @Deprecated public static interface AccessibilityManagerCompat.AccessibilityStateChangeListener {
@@ -4341,9 +4341,9 @@
     method @Deprecated public Object! getImpl();
     method @Deprecated public int getItemCount();
     method @Deprecated public int getMaxScrollX();
-    method public static int getMaxScrollX(android.view.accessibility.AccessibilityRecord);
+    method @Deprecated @ReplaceWith(expression="record.getMaxScrollX()") public static int getMaxScrollX(android.view.accessibility.AccessibilityRecord);
     method @Deprecated public int getMaxScrollY();
-    method public static int getMaxScrollY(android.view.accessibility.AccessibilityRecord);
+    method @Deprecated @ReplaceWith(expression="record.getMaxScrollY()") public static int getMaxScrollY(android.view.accessibility.AccessibilityRecord);
     method @Deprecated public android.os.Parcelable! getParcelableData();
     method @Deprecated public int getRemovedCount();
     method @Deprecated public int getScrollX();
@@ -4371,9 +4371,9 @@
     method @Deprecated public void setFromIndex(int);
     method @Deprecated public void setFullScreen(boolean);
     method @Deprecated public void setItemCount(int);
-    method public static void setMaxScrollX(android.view.accessibility.AccessibilityRecord, int);
+    method @Deprecated @ReplaceWith(expression="record.setMaxScrollX(maxScrollX)") public static void setMaxScrollX(android.view.accessibility.AccessibilityRecord, int);
     method @Deprecated public void setMaxScrollX(int);
-    method public static void setMaxScrollY(android.view.accessibility.AccessibilityRecord, int);
+    method @Deprecated @ReplaceWith(expression="record.setMaxScrollY(maxScrollY)") public static void setMaxScrollY(android.view.accessibility.AccessibilityRecord, int);
     method @Deprecated public void setMaxScrollY(int);
     method @Deprecated public void setParcelableData(android.os.Parcelable!);
     method @Deprecated public void setPassword(boolean);
@@ -4381,7 +4381,7 @@
     method @Deprecated public void setScrollX(int);
     method @Deprecated public void setScrollY(int);
     method @Deprecated public void setScrollable(boolean);
-    method public static void setSource(android.view.accessibility.AccessibilityRecord, android.view.View?, int);
+    method @Deprecated @ReplaceWith(expression="record.setSource(root, virtualDescendantId)") public static void setSource(android.view.accessibility.AccessibilityRecord, android.view.View?, int);
     method @Deprecated public void setSource(android.view.View!);
     method @Deprecated public void setSource(android.view.View!, int);
     method @Deprecated public void setToIndex(int);
@@ -4587,7 +4587,7 @@
   }
 
   public final class CheckedTextViewCompat {
-    method public static android.graphics.drawable.Drawable? getCheckMarkDrawable(android.widget.CheckedTextView);
+    method @Deprecated @ReplaceWith(expression="textView.getCheckMarkDrawable()") public static android.graphics.drawable.Drawable? getCheckMarkDrawable(android.widget.CheckedTextView);
     method public static android.content.res.ColorStateList? getCheckMarkTintList(android.widget.CheckedTextView);
     method public static android.graphics.PorterDuff.Mode? getCheckMarkTintMode(android.widget.CheckedTextView);
     method public static void setCheckMarkTintList(android.widget.CheckedTextView, android.content.res.ColorStateList?);
@@ -4635,7 +4635,7 @@
   }
 
   public final class ListPopupWindowCompat {
-    method public static android.view.View.OnTouchListener? createDragToOpenListener(android.widget.ListPopupWindow, android.view.View);
+    method @Deprecated @ReplaceWith(expression="listPopupWindow.createDragToOpenListener(src)") public static android.view.View.OnTouchListener? createDragToOpenListener(android.widget.ListPopupWindow, android.view.View);
     method @Deprecated public static android.view.View.OnTouchListener! createDragToOpenListener(Object!, android.view.View!);
   }
 
@@ -4647,8 +4647,8 @@
   }
 
   @Deprecated public final class ListViewCompat {
-    method @Deprecated public static boolean canScrollList(android.widget.ListView, int);
-    method @Deprecated public static void scrollListBy(android.widget.ListView, int);
+    method @Deprecated @ReplaceWith(expression="listView.canScrollList(direction)") public static boolean canScrollList(android.widget.ListView, int);
+    method @Deprecated @ReplaceWith(expression="listView.scrollListBy(y)") public static void scrollListBy(android.widget.ListView, int);
   }
 
   public class NestedScrollView extends android.widget.FrameLayout implements androidx.core.view.NestedScrollingChild3 androidx.core.view.NestedScrollingParent3 androidx.core.view.ScrollingView {
@@ -4705,7 +4705,7 @@
     method public static int getWindowLayoutType(android.widget.PopupWindow);
     method public static void setOverlapAnchor(android.widget.PopupWindow, boolean);
     method public static void setWindowLayoutType(android.widget.PopupWindow, int);
-    method public static void showAsDropDown(android.widget.PopupWindow, android.view.View, int, int, int);
+    method @Deprecated @ReplaceWith(expression="popup.showAsDropDown(anchor, xoff, yoff, gravity)") public static void showAsDropDown(android.widget.PopupWindow, android.view.View, int, int, int);
   }
 
   @Deprecated public final class ScrollerCompat {
@@ -4737,21 +4737,21 @@
     method public static int getAutoSizeTextType(android.widget.TextView);
     method public static android.content.res.ColorStateList? getCompoundDrawableTintList(android.widget.TextView);
     method public static android.graphics.PorterDuff.Mode? getCompoundDrawableTintMode(android.widget.TextView);
-    method public static android.graphics.drawable.Drawable![] getCompoundDrawablesRelative(android.widget.TextView);
+    method @Deprecated @ReplaceWith(expression="textView.getCompoundDrawablesRelative()") public static android.graphics.drawable.Drawable![] getCompoundDrawablesRelative(android.widget.TextView);
     method public static int getFirstBaselineToTopHeight(android.widget.TextView);
     method public static int getLastBaselineToBottomHeight(android.widget.TextView);
-    method public static int getMaxLines(android.widget.TextView);
-    method public static int getMinLines(android.widget.TextView);
+    method @Deprecated @ReplaceWith(expression="textView.getMaxLines()") public static int getMaxLines(android.widget.TextView);
+    method @Deprecated @ReplaceWith(expression="textView.getMinLines()") public static int getMinLines(android.widget.TextView);
     method public static androidx.core.text.PrecomputedTextCompat.Params getTextMetricsParams(android.widget.TextView);
     method public static void setAutoSizeTextTypeUniformWithConfiguration(android.widget.TextView, int, int, int, int) throws java.lang.IllegalArgumentException;
     method public static void setAutoSizeTextTypeUniformWithPresetSizes(android.widget.TextView, int[], int) throws java.lang.IllegalArgumentException;
     method public static void setAutoSizeTextTypeWithDefaults(android.widget.TextView, int);
     method public static void setCompoundDrawableTintList(android.widget.TextView, android.content.res.ColorStateList?);
     method public static void setCompoundDrawableTintMode(android.widget.TextView, android.graphics.PorterDuff.Mode?);
-    method public static void setCompoundDrawablesRelative(android.widget.TextView, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?);
-    method public static void setCompoundDrawablesRelativeWithIntrinsicBounds(android.widget.TextView, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?);
-    method public static void setCompoundDrawablesRelativeWithIntrinsicBounds(android.widget.TextView, @DrawableRes int, @DrawableRes int, @DrawableRes int, @DrawableRes int);
-    method public static void setCustomSelectionActionModeCallback(android.widget.TextView, android.view.ActionMode.Callback);
+    method @Deprecated @ReplaceWith(expression="textView.setCompoundDrawablesRelative(start, top, end, bottom)") public static void setCompoundDrawablesRelative(android.widget.TextView, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?);
+    method @Deprecated @ReplaceWith(expression="textView.setCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom)") public static void setCompoundDrawablesRelativeWithIntrinsicBounds(android.widget.TextView, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?);
+    method @Deprecated @ReplaceWith(expression="textView.setCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom)") public static void setCompoundDrawablesRelativeWithIntrinsicBounds(android.widget.TextView, @DrawableRes int, @DrawableRes int, @DrawableRes int, @DrawableRes int);
+    method @Deprecated @ReplaceWith(expression="textView.setCustomSelectionActionModeCallback(callback)") public static void setCustomSelectionActionModeCallback(android.widget.TextView, android.view.ActionMode.Callback);
     method public static void setFirstBaselineToTopHeight(android.widget.TextView, @IntRange(from=0) @Px int);
     method public static void setLastBaselineToBottomHeight(android.widget.TextView, @IntRange(from=0) @Px int);
     method public static void setLineHeight(android.widget.TextView, @IntRange(from=0) @Px int);
diff --git a/core/core/build.gradle b/core/core/build.gradle
index 2799274..87f8666 100644
--- a/core/core/build.gradle
+++ b/core/core/build.gradle
@@ -21,7 +21,7 @@
         implementation(project(":core:core-testing"))
     }
 
-    api("androidx.annotation:annotation:1.6.0")
+    api(project(":annotation:annotation"))
     api("androidx.annotation:annotation-experimental:1.4.0")
     api("androidx.lifecycle:lifecycle-runtime:2.6.2")
     api("androidx.versionedparcelable:versionedparcelable:1.1.1")
diff --git a/core/core/src/main/java/androidx/core/accessibilityservice/AccessibilityServiceInfoCompat.java b/core/core/src/main/java/androidx/core/accessibilityservice/AccessibilityServiceInfoCompat.java
index d1dc409..eacb1fc 100644
--- a/core/core/src/main/java/androidx/core/accessibilityservice/AccessibilityServiceInfoCompat.java
+++ b/core/core/src/main/java/androidx/core/accessibilityservice/AccessibilityServiceInfoCompat.java
@@ -190,7 +190,10 @@
      * @param info The service info of interest
      * @param packageManager The current package manager
      * @return The localized description.
+     * @deprecated Call {@link AccessibilityServiceInfo#loadDescription()} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "info.loadDescription(packageManager)")
     @SuppressWarnings("deprecation")
     @Nullable
     public static String loadDescription(
@@ -277,7 +280,10 @@
      * @see #CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION
      * @see #CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY
      * @see #CAPABILITY_CAN_FILTER_KEY_EVENTS
+     * @deprecated Call {@link AccessibilityServiceInfo#getCapabilities()} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "info.getCapabilities()")
     @SuppressWarnings("deprecation")
     public static int getCapabilities(@NonNull AccessibilityServiceInfo info) {
         return info.getCapabilities();
diff --git a/core/core/src/main/java/androidx/core/app/ActivityManagerCompat.java b/core/core/src/main/java/androidx/core/app/ActivityManagerCompat.java
index 696e01f..6afb250 100644
--- a/core/core/src/main/java/androidx/core/app/ActivityManagerCompat.java
+++ b/core/core/src/main/java/androidx/core/app/ActivityManagerCompat.java
@@ -34,7 +34,10 @@
      * something in the class of a 512MB device with about a 800x480 or less screen.
      * This is mostly intended to be used by apps to determine whether they should turn
      * off certain features that require more RAM.
+     * @deprecated Call {@link ActivityManager#isLowRamDevice()} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "activityManager.isLowRamDevice()")
     public static boolean isLowRamDevice(@NonNull ActivityManager activityManager) {
         return activityManager.isLowRamDevice();
     }
diff --git a/core/core/src/main/java/androidx/core/app/AlarmManagerCompat.java b/core/core/src/main/java/androidx/core/app/AlarmManagerCompat.java
index 34e3364..2242966 100644
--- a/core/core/src/main/java/androidx/core/app/AlarmManagerCompat.java
+++ b/core/core/src/main/java/androidx/core/app/AlarmManagerCompat.java
@@ -162,7 +162,10 @@
      * @see AlarmManager#ELAPSED_REALTIME_WAKEUP
      * @see AlarmManager#RTC
      * @see AlarmManager#RTC_WAKEUP
+     * @deprecated Call {@link AlarmManager#setExact()} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "alarmManager.setExact(type, triggerAtMillis, operation)")
     public static void setExact(@NonNull AlarmManager alarmManager, int type, long triggerAtMillis,
             @NonNull PendingIntent operation) {
         alarmManager.setExact(type, triggerAtMillis, operation);
diff --git a/core/core/src/main/java/androidx/core/app/BundleCompat.java b/core/core/src/main/java/androidx/core/app/BundleCompat.java
index a759f36..9be2181 100644
--- a/core/core/src/main/java/androidx/core/app/BundleCompat.java
+++ b/core/core/src/main/java/androidx/core/app/BundleCompat.java
@@ -38,7 +38,10 @@
      * @param bundle The bundle to get the {@link IBinder}.
      * @param key    The key to use while getting the {@link IBinder}.
      * @return       The {@link IBinder} that was obtained.
+     * @deprecated Call {@link Bundle#getBinder()} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "bundle.getBinder(key)")
     @Nullable
     public static IBinder getBinder(@NonNull Bundle bundle, @Nullable String key) {
         return bundle.getBinder(key);
@@ -50,7 +53,10 @@
      * @param bundle The bundle to insert the {@link IBinder}.
      * @param key    The key to use while putting the {@link IBinder}.
      * @param binder The {@link IBinder} to put.
+     * @deprecated Call {@link Bundle#putBinder()} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "bundle.putBinder(key, binder)")
     public static void putBinder(@NonNull Bundle bundle, @Nullable String key,
             @Nullable IBinder binder) {
         bundle.putBinder(key, binder);
diff --git a/core/core/src/main/java/androidx/core/app/NavUtils.java b/core/core/src/main/java/androidx/core/app/NavUtils.java
index 3480592..56fffc4 100644
--- a/core/core/src/main/java/androidx/core/app/NavUtils.java
+++ b/core/core/src/main/java/androidx/core/app/NavUtils.java
@@ -54,7 +54,10 @@
      * @param targetIntent An intent representing the target destination for up navigation
      * @return true if navigating up should recreate a new task stack, false if the same task
      *         should be used for the destination
+     * @deprecated Call {@link Activity#shouldUpRecreateTask()} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "sourceActivity.shouldUpRecreateTask(targetIntent)")
     public static boolean shouldUpRecreateTask(@NonNull Activity sourceActivity,
             @NonNull Intent targetIntent) {
         return sourceActivity.shouldUpRecreateTask(targetIntent);
@@ -98,7 +101,10 @@
      *
      * @param sourceActivity The current activity from which the user is attempting to navigate up
      * @param upIntent An intent representing the target destination for up navigation
+     * @deprecated Call {@link Activity#navigateUpTo()} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "sourceActivity.navigateUpTo(upIntent)")
     public static void navigateUpTo(@NonNull Activity sourceActivity, @NonNull Intent upIntent) {
         sourceActivity.navigateUpTo(upIntent);
     }
diff --git a/core/core/src/main/java/androidx/core/app/NotificationCompat.java b/core/core/src/main/java/androidx/core/app/NotificationCompat.java
index bee883a..6fd698c 100644
--- a/core/core/src/main/java/androidx/core/app/NotificationCompat.java
+++ b/core/core/src/main/java/androidx/core/app/NotificationCompat.java
@@ -8953,7 +8953,10 @@
      * Gets the {@link Notification#extras} field from a notification in a backwards
      * compatible manner. Extras field was supported from JellyBean (Api level 16)
      * forwards. This function will return {@code null} on older api levels.
+     * @deprecated Call {@link Notification#extras} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "notification.extras")
     @Nullable
     public static Bundle getExtras(@NonNull Notification notification) {
         return notification.extras;
diff --git a/core/core/src/main/java/androidx/core/content/ContextCompat.java b/core/core/src/main/java/androidx/core/content/ContextCompat.java
index bacc472..d6b1f9c 100644
--- a/core/core/src/main/java/androidx/core/content/ContextCompat.java
+++ b/core/core/src/main/java/androidx/core/content/ContextCompat.java
@@ -289,7 +289,10 @@
      *                {@link ActivityOptionsCompat} for how to build the Bundle
      *                supplied here; there are no supported definitions for
      *                building it manually.
+     * @deprecated Call {@link Context#startActivity()} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "context.startActivity(intent, options)")
     public static void startActivity(@NonNull Context context, @NonNull Intent intent,
             @Nullable Bundle options) {
         context.startActivity(intent, options);
@@ -362,7 +365,10 @@
      *
      * @see Context#getObbDir()
      * @see EnvironmentCompat#getStorageState(File)
+     * @deprecated Call {@link Context#getObbDirs()} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "context.getObbDirs()")
     @NonNull
     public static File[] getObbDirs(@NonNull Context context) {
         return context.getObbDirs();
@@ -411,7 +417,10 @@
      *
      * @see Context#getExternalFilesDir(String)
      * @see EnvironmentCompat#getStorageState(File)
+     * @deprecated Call {@link Context#getExternalFilesDirs()} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "context.getExternalFilesDirs(type)")
     @NonNull
     public static File[] getExternalFilesDirs(@NonNull Context context, @Nullable String type) {
         return context.getExternalFilesDirs(type);
@@ -460,7 +469,10 @@
      *
      * @see Context#getExternalCacheDir()
      * @see EnvironmentCompat#getStorageState(File)
+     * @deprecated Call {@link Context#getExternalCacheDirs()} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "context.getExternalCacheDirs()")
     @NonNull
     public static File[] getExternalCacheDirs(@NonNull Context context) {
         return context.getExternalCacheDirs();
diff --git a/core/core/src/main/java/androidx/core/graphics/BitmapCompat.java b/core/core/src/main/java/androidx/core/graphics/BitmapCompat.java
index 25d0b7b..547918d 100644
--- a/core/core/src/main/java/androidx/core/graphics/BitmapCompat.java
+++ b/core/core/src/main/java/androidx/core/graphics/BitmapCompat.java
@@ -52,7 +52,10 @@
      * @return true if the renderer should attempt to use mipmaps,
      * false otherwise
      * @see Bitmap#hasMipMap()
+     * @deprecated Call {@link Bitmap#hasMipMap()} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "bitmap.hasMipMap()")
     public static boolean hasMipMap(@NonNull Bitmap bitmap) {
         return bitmap.hasMipMap();
     }
@@ -76,7 +79,10 @@
      * @param hasMipMap indicates whether the renderer should attempt
      *                  to use mipmaps
      * @see Bitmap#setHasMipMap(boolean)
+     * @deprecated Call {@link Bitmap#setHasMipMap()} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "bitmap.setHasMipMap(hasMipMap)")
     public static void setHasMipMap(@NonNull Bitmap bitmap, boolean hasMipMap) {
         bitmap.setHasMipMap(hasMipMap);
     }
@@ -87,7 +93,10 @@
      * This value will not change over the lifetime of a Bitmap.
      *
      * @see Bitmap#getAllocationByteCount()
+     * @deprecated Call {@link Bitmap#getAllocationByteCount()} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "bitmap.getAllocationByteCount()")
     public static int getAllocationByteCount(@NonNull Bitmap bitmap) {
         return bitmap.getAllocationByteCount();
     }
diff --git a/core/core/src/main/java/androidx/core/graphics/drawable/DrawableCompat.java b/core/core/src/main/java/androidx/core/graphics/drawable/DrawableCompat.java
index 32130e6..3eb185e 100644
--- a/core/core/src/main/java/androidx/core/graphics/drawable/DrawableCompat.java
+++ b/core/core/src/main/java/androidx/core/graphics/drawable/DrawableCompat.java
@@ -60,6 +60,7 @@
      *
      * @deprecated Use {@link Drawable#jumpToCurrentState()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "drawable.jumpToCurrentState()")
     @Deprecated
     public static void jumpToCurrentState(@NonNull Drawable drawable) {
         drawable.jumpToCurrentState();
@@ -76,7 +77,10 @@
      * @param drawable The Drawable against which to invoke the method.
      * @param mirrored Set to true if the Drawable should be mirrored, false if
      *            not.
+     * @deprecated Call {@link Drawable#setAutoMirrored()} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "drawable.setAutoMirrored(mirrored)")
     public static void setAutoMirrored(@NonNull Drawable drawable, boolean mirrored) {
         drawable.setAutoMirrored(mirrored);
     }
@@ -91,7 +95,10 @@
      * @param drawable The Drawable against which to invoke the method.
      * @return boolean Returns true if this Drawable will be automatically
      *         mirrored.
+     * @deprecated Call {@link Drawable#isAutoMirrored()} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "drawable.isAutoMirrored()")
     public static boolean isAutoMirrored(@NonNull Drawable drawable) {
         return drawable.isAutoMirrored();
     }
@@ -173,7 +180,10 @@
      * 0 means fully transparent, 255 means fully opaque.
      *
      * @param drawable The Drawable against which to invoke the method.
+     * @deprecated Call {@link Drawable#getAlpha()} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "drawable.getAlpha()")
     @SuppressWarnings("unused")
     public static int getAlpha(@NonNull Drawable drawable) {
         return drawable.getAlpha();
diff --git a/core/core/src/main/java/androidx/core/location/LocationCompat.java b/core/core/src/main/java/androidx/core/location/LocationCompat.java
index 7d4c123..502ef2f 100644
--- a/core/core/src/main/java/androidx/core/location/LocationCompat.java
+++ b/core/core/src/main/java/androidx/core/location/LocationCompat.java
@@ -106,7 +106,10 @@
      * based on the difference between system time and the location time. This should be taken as a
      * best "guess" at what the elapsed realtime might have been, but if the clock used for
      * location derivation is different from the system clock, the results may be inaccurate.
+     * @deprecated Call {@link Location#getElapsedRealtimeNanos()} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "location.getElapsedRealtimeNanos()")
     public static long getElapsedRealtimeNanos(@NonNull Location location) {
         return location.getElapsedRealtimeNanos();
     }
@@ -491,7 +494,10 @@
      * this should be considered a mock location.
      *
      * @see android.location.LocationManager#addTestProvider
+     * @deprecated Call {@link Location#isFromMockProvider()} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "location.isFromMockProvider()")
     public static boolean isMock(@NonNull Location location) {
         return location.isFromMockProvider();
     }
diff --git a/core/core/src/main/java/androidx/core/net/ConnectivityManagerCompat.java b/core/core/src/main/java/androidx/core/net/ConnectivityManagerCompat.java
index e2fdc44..f678649 100644
--- a/core/core/src/main/java/androidx/core/net/ConnectivityManagerCompat.java
+++ b/core/core/src/main/java/androidx/core/net/ConnectivityManagerCompat.java
@@ -86,7 +86,10 @@
      *
      * @return {@code true} if large transfers should be avoided, otherwise
      *        {@code false}.
+     * @deprecated Call {@link ConnectivityManager#isActiveNetworkMetered()} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "cm.isActiveNetworkMetered()")
     @SuppressWarnings("deprecation")
     @RequiresPermission(Manifest.permission.ACCESS_NETWORK_STATE)
     public static boolean isActiveNetworkMetered(@NonNull ConnectivityManager cm) {
diff --git a/core/core/src/main/java/androidx/core/os/BundleCompat.java b/core/core/src/main/java/androidx/core/os/BundleCompat.java
index 5b72c26..3038657 100644
--- a/core/core/src/main/java/androidx/core/os/BundleCompat.java
+++ b/core/core/src/main/java/androidx/core/os/BundleCompat.java
@@ -190,6 +190,7 @@
      *
      * @deprecated Use {@link Bundle#getBinder(String)} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "bundle.getBinder(key)")
     @Deprecated
     @Nullable
     public static IBinder getBinder(@NonNull Bundle bundle, @Nullable String key) {
@@ -206,6 +207,7 @@
      *
      * @deprecated Use {@link Bundle#putBinder(String, IBinder)} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "bundle.putBinder(key, binder)")
     @Deprecated
     public static void putBinder(@NonNull Bundle bundle, @Nullable String key,
             @Nullable IBinder binder) {
diff --git a/core/core/src/main/java/androidx/core/os/ParcelCompat.java b/core/core/src/main/java/androidx/core/os/ParcelCompat.java
index cc52e51..fb67665 100644
--- a/core/core/src/main/java/androidx/core/os/ParcelCompat.java
+++ b/core/core/src/main/java/androidx/core/os/ParcelCompat.java
@@ -53,7 +53,10 @@
      *
      * <p>Note: This method currently delegates to {@link Parcel#writeInt} with a value of 1 or 0
      * for true or false, respectively, but may change in the future.
+     * @deprecated Call {@link Parcel#writeInt()} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "out.writeInt(value ? 1 : 0)")
     public static void writeBoolean(@NonNull Parcel out, boolean value) {
         out.writeInt(value ? 1 : 0);
     }
diff --git a/core/core/src/main/java/androidx/core/view/MarginLayoutParamsCompat.java b/core/core/src/main/java/androidx/core/view/MarginLayoutParamsCompat.java
index a2859f5..876ca0b 100644
--- a/core/core/src/main/java/androidx/core/view/MarginLayoutParamsCompat.java
+++ b/core/core/src/main/java/androidx/core/view/MarginLayoutParamsCompat.java
@@ -43,6 +43,7 @@
      * @return the margin along the starting edge in pixels
      * @deprecated Use {@link ViewGroup.MarginLayoutParams#getMarginStart} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "lp.getMarginStart()")
     @Deprecated
     public static int getMarginStart(@NonNull ViewGroup.MarginLayoutParams lp) {
         return lp.getMarginStart();
@@ -60,6 +61,7 @@
      * @return the margin along the ending edge in pixels
      * @deprecated Use {@link ViewGroup.MarginLayoutParams#getMarginStart} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "lp.getMarginEnd()")
     @Deprecated
     public static int getMarginEnd(@NonNull ViewGroup.MarginLayoutParams lp) {
         return lp.getMarginEnd();
@@ -77,6 +79,7 @@
      * @param marginStart the desired start margin in pixels
      * @deprecated Use {@link ViewGroup.MarginLayoutParams#setMarginStart} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "lp.setMarginStart(marginStart)")
     @Deprecated
     public static void setMarginStart(@NonNull ViewGroup.MarginLayoutParams lp, int marginStart) {
         lp.setMarginStart(marginStart);
@@ -94,6 +97,7 @@
      * @param marginEnd the desired end margin in pixels
      * @deprecated Use {@link ViewGroup.MarginLayoutParams#setMarginEnd} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "lp.setMarginEnd(marginEnd)")
     @Deprecated
     public static void setMarginEnd(@NonNull ViewGroup.MarginLayoutParams lp, int marginEnd) {
         lp.setMarginEnd(marginEnd);
@@ -105,6 +109,7 @@
      * @return true if either marginStart or marginEnd has been set.
      * @deprecated Use {@link ViewGroup.MarginLayoutParams#isMarginRelative} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "lp.isMarginRelative()")
     @Deprecated
     public static boolean isMarginRelative(@NonNull ViewGroup.MarginLayoutParams lp) {
         return lp.isMarginRelative();
@@ -140,6 +145,7 @@
      *                     or {@link ViewCompat#LAYOUT_DIRECTION_RTL}.
      * @deprecated Use {@link ViewGroup.MarginLayoutParams#setLayoutDirection} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "lp.setLayoutDirection(layoutDirection)")
     @Deprecated
     public static void setLayoutDirection(@NonNull ViewGroup.MarginLayoutParams lp,
             int layoutDirection) {
@@ -152,6 +158,7 @@
      *
      * @deprecated Use {@link ViewGroup.MarginLayoutParams#resolveLayoutDirection} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "lp.resolveLayoutDirection(layoutDirection)")
     @Deprecated
     public static void resolveLayoutDirection(@NonNull ViewGroup.MarginLayoutParams lp,
             int layoutDirection) {
diff --git a/core/core/src/main/java/androidx/core/view/MenuCompat.java b/core/core/src/main/java/androidx/core/view/MenuCompat.java
index de416fd..36b96d9 100644
--- a/core/core/src/main/java/androidx/core/view/MenuCompat.java
+++ b/core/core/src/main/java/androidx/core/view/MenuCompat.java
@@ -34,6 +34,7 @@
      *
      * @deprecated Use {@link MenuItem#setShowAsAction(int)} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "item.setShowAsAction(actionEnum)")
     @Deprecated
     public static void setShowAsAction(MenuItem item, int actionEnum) {
         item.setShowAsAction(actionEnum);
diff --git a/core/core/src/main/java/androidx/core/view/MenuItemCompat.java b/core/core/src/main/java/androidx/core/view/MenuItemCompat.java
index 715b9ba..5df61da 100644
--- a/core/core/src/main/java/androidx/core/view/MenuItemCompat.java
+++ b/core/core/src/main/java/androidx/core/view/MenuItemCompat.java
@@ -135,6 +135,7 @@
      *
      * @deprecated Use {@link MenuItem#setShowAsAction(int)} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "item.setShowAsAction(actionEnum)")
     @Deprecated
     public static void setShowAsAction(MenuItem item, int actionEnum) {
         item.setShowAsAction(actionEnum);
@@ -153,6 +154,7 @@
      *
      * @deprecated Use {@link MenuItem#setActionView(View)} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "item.setActionView(view)")
     @Deprecated
     public static MenuItem setActionView(MenuItem item, View view) {
         return item.setActionView(view);
@@ -175,6 +177,7 @@
      *
      * @deprecated Use {@link MenuItem#setActionView(int)} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "item.setActionView(resId)")
     @Deprecated
     public static MenuItem setActionView(MenuItem item, int resId) {
         return item.setActionView(resId);
@@ -188,6 +191,7 @@
      *
      * @deprecated Use {@link MenuItem#getActionView()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "item.getActionView()")
     @Deprecated
     public static View getActionView(MenuItem item) {
         return item.getActionView();
@@ -252,6 +256,7 @@
      *
      * @deprecated Use {@link MenuItem#expandActionView()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "item.expandActionView()")
     @Deprecated
     public static boolean expandActionView(MenuItem item) {
         return item.expandActionView();
@@ -271,6 +276,7 @@
      *
      * @deprecated Use {@link MenuItem#collapseActionView()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "item.collapseActionView()")
     @Deprecated
     public static boolean collapseActionView(MenuItem item) {
         return item.collapseActionView();
@@ -287,6 +293,7 @@
      *
      * @deprecated Use {@link MenuItem#isActionViewExpanded()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "item.isActionViewExpanded()")
     @Deprecated
     public static boolean isActionViewExpanded(MenuItem item) {
         return item.isActionViewExpanded();
diff --git a/core/core/src/main/java/androidx/core/view/MotionEventCompat.java b/core/core/src/main/java/androidx/core/view/MotionEventCompat.java
index b39a46c..bad4584 100644
--- a/core/core/src/main/java/androidx/core/view/MotionEventCompat.java
+++ b/core/core/src/main/java/androidx/core/view/MotionEventCompat.java
@@ -462,6 +462,7 @@
      * @deprecated Call {@link MotionEvent#getAction()} directly. This method will be
      * removed in a future release.
      */
+    @androidx.annotation.ReplaceWith(expression = "event.getActionMasked()")
     @Deprecated
     public static int getActionMasked(MotionEvent event) {
         return event.getActionMasked();
@@ -474,6 +475,7 @@
      * @deprecated Call {@link MotionEvent#getActionIndex()} directly. This method will be
      * removed in a future release.
      */
+    @androidx.annotation.ReplaceWith(expression = "event.getActionIndex()")
     @Deprecated
     public static int getActionIndex(MotionEvent event) {
         return event.getActionIndex();
@@ -485,6 +487,7 @@
      * @deprecated Call {@link MotionEvent#findPointerIndex(int)} directly. This method will be
      * removed in a future release.
      */
+    @androidx.annotation.ReplaceWith(expression = "event.findPointerIndex(pointerId)")
     @Deprecated
     public static int findPointerIndex(MotionEvent event, int pointerId) {
         return event.findPointerIndex(pointerId);
@@ -496,6 +499,7 @@
      * @deprecated Call {@link MotionEvent#getPointerId(int)} directly. This method will be
      * removed in a future release.
      */
+    @androidx.annotation.ReplaceWith(expression = "event.getPointerId(pointerIndex)")
     @Deprecated
     public static int getPointerId(MotionEvent event, int pointerIndex) {
         return event.getPointerId(pointerIndex);
@@ -507,6 +511,7 @@
      * @deprecated Call {@link MotionEvent#getX()} directly. This method will be
      * removed in a future release.
      */
+    @androidx.annotation.ReplaceWith(expression = "event.getX(pointerIndex)")
     @Deprecated
     public static float getX(MotionEvent event, int pointerIndex) {
         return event.getX(pointerIndex);
@@ -518,6 +523,7 @@
      * @deprecated Call {@link MotionEvent#getY()} directly. This method will be
      * removed in a future release.
      */
+    @androidx.annotation.ReplaceWith(expression = "event.getY(pointerIndex)")
     @Deprecated
     public static float getY(MotionEvent event, int pointerIndex) {
         return event.getY(pointerIndex);
@@ -529,6 +535,7 @@
      * @deprecated Call {@link MotionEvent#getPointerCount()} directly. This method will be
      * removed in a future release.
      */
+    @androidx.annotation.ReplaceWith(expression = "event.getPointerCount()")
     @Deprecated
     public static int getPointerCount(MotionEvent event) {
         return event.getPointerCount();
@@ -541,6 +548,7 @@
      * @deprecated Call {@link MotionEvent#getSource()} directly. This method will be
      * removed in a future release.
      */
+    @androidx.annotation.ReplaceWith(expression = "event.getSource()")
     @Deprecated
     public static int getSource(MotionEvent event) {
         return event.getSource();
@@ -569,6 +577,7 @@
      * @deprecated Call {@link MotionEvent#getAxisValue(int)} directly. This method will be
      * removed in a future release.
      */
+    @androidx.annotation.ReplaceWith(expression = "event.getAxisValue(axis)")
     @Deprecated
     public static float getAxisValue(MotionEvent event, int axis) {
         return event.getAxisValue(axis);
@@ -590,6 +599,7 @@
      * @deprecated Call {@link MotionEvent#getAxisValue(int, int)} directly. This method will be
      * removed in a future release.
      */
+    @androidx.annotation.ReplaceWith(expression = "event.getAxisValue(axis, pointerIndex)")
     @Deprecated
     public static float getAxisValue(MotionEvent event, int axis, int pointerIndex) {
         return event.getAxisValue(axis, pointerIndex);
@@ -599,6 +609,7 @@
      * @deprecated Call {@link MotionEvent#getButtonState()} directly. This method will be
      * removed in a future release.
      */
+    @androidx.annotation.ReplaceWith(expression = "event.getButtonState()")
     @Deprecated
     public static int getButtonState(MotionEvent event) {
         return event.getButtonState();
diff --git a/core/core/src/main/java/androidx/core/view/ScaleGestureDetectorCompat.java b/core/core/src/main/java/androidx/core/view/ScaleGestureDetectorCompat.java
index f24ea50..02cc957 100644
--- a/core/core/src/main/java/androidx/core/view/ScaleGestureDetectorCompat.java
+++ b/core/core/src/main/java/androidx/core/view/ScaleGestureDetectorCompat.java
@@ -50,7 +50,10 @@
      *
      * @param scaleGestureDetector detector for which to set the scaling mode.
      * @param enabled true to enable quick scaling, false to disable
+     * @deprecated Call {@link ScaleGestureDetector#setQuickScaleEnabled()} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "scaleGestureDetector.setQuickScaleEnabled(enabled)")
     public static void setQuickScaleEnabled(
             @NonNull ScaleGestureDetector scaleGestureDetector, boolean enabled) {
         scaleGestureDetector.setQuickScaleEnabled(enabled);
@@ -74,7 +77,10 @@
      * Returns whether the quick scale gesture, in which the user performs a double tap followed by
      * a swipe, should perform scaling. See
      * {@link #setQuickScaleEnabled(ScaleGestureDetector, boolean)}.
+     * @deprecated Call {@link ScaleGestureDetector#isQuickScaleEnabled()} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "scaleGestureDetector.isQuickScaleEnabled()")
     public static boolean isQuickScaleEnabled(@NonNull ScaleGestureDetector scaleGestureDetector) {
         return scaleGestureDetector.isQuickScaleEnabled();
     }
diff --git a/core/core/src/main/java/androidx/core/view/VelocityTrackerCompat.java b/core/core/src/main/java/androidx/core/view/VelocityTrackerCompat.java
index 3f20831..aedbab2 100644
--- a/core/core/src/main/java/androidx/core/view/VelocityTrackerCompat.java
+++ b/core/core/src/main/java/androidx/core/view/VelocityTrackerCompat.java
@@ -85,6 +85,7 @@
      *
      * @deprecated Use {@link VelocityTracker#getXVelocity(int)} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "tracker.getXVelocity(pointerId)")
     @Deprecated
     public static float getXVelocity(VelocityTracker tracker, int pointerId) {
         return tracker.getXVelocity(pointerId);
@@ -97,6 +98,7 @@
      *
      * @deprecated Use {@link VelocityTracker#getYVelocity(int)} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "tracker.getYVelocity(pointerId)")
     @Deprecated
     public static float getYVelocity(VelocityTracker tracker, int pointerId) {
         return tracker.getYVelocity(pointerId);
diff --git a/core/core/src/main/java/androidx/core/view/ViewCompat.java b/core/core/src/main/java/androidx/core/view/ViewCompat.java
index 0345c75..46875b0 100644
--- a/core/core/src/main/java/androidx/core/view/ViewCompat.java
+++ b/core/core/src/main/java/androidx/core/view/ViewCompat.java
@@ -595,6 +595,7 @@
      *
      * @deprecated Use {@link View#canScrollHorizontally(int)} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.canScrollHorizontally(direction)")
     @Deprecated
     public static boolean canScrollHorizontally(View view, int direction) {
         return view.canScrollHorizontally(direction);
@@ -608,6 +609,7 @@
      * @return true if this view can be scrolled in the specified direction, false otherwise.
      * @deprecated Use {@link View#canScrollVertically(int)} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.canScrollVertically(direction)")
     @Deprecated
     public static boolean canScrollVertically(View view, int direction) {
         return view.canScrollVertically(direction);
@@ -624,6 +626,7 @@
      * @deprecated Call {@link View#getOverScrollMode()} directly. This method will be
      * removed in a future release.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.getOverScrollMode()")
     @Deprecated
     @OverScroll
     public static int getOverScrollMode(View view) {
@@ -645,6 +648,7 @@
      * @deprecated Call {@link View#setOverScrollMode(int)} directly. This method will be
      * removed in a future release.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.setOverScrollMode(overScrollMode)")
     @Deprecated
     public static void setOverScrollMode(View view, @OverScroll int overScrollMode) {
         view.setOverScrollMode(overScrollMode);
@@ -688,6 +692,7 @@
      * @deprecated Call {@link View#onPopulateAccessibilityEvent(AccessibilityEvent)} directly.
      * This method will be removed in a future release.
      */
+    @androidx.annotation.ReplaceWith(expression = "v.onPopulateAccessibilityEvent(event)")
     @Deprecated
     public static void onPopulateAccessibilityEvent(View v, AccessibilityEvent event) {
         v.onPopulateAccessibilityEvent(event);
@@ -720,6 +725,7 @@
      * @deprecated Call {@link View#onInitializeAccessibilityEvent(AccessibilityEvent)} directly.
      * This method will be removed in a future release.
      */
+    @androidx.annotation.ReplaceWith(expression = "v.onInitializeAccessibilityEvent(event)")
     @Deprecated
     public static void onInitializeAccessibilityEvent(View v, AccessibilityEvent event) {
         v.onInitializeAccessibilityEvent(event);
@@ -754,6 +760,7 @@
      * @deprecated Call {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)}
      * directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "v.onInitializeAccessibilityNodeInfo(info.unwrap())")
     @Deprecated
     public static void onInitializeAccessibilityNodeInfo(@NonNull View v,
             @NonNull AccessibilityNodeInfoCompat info) {
@@ -1290,6 +1297,7 @@
      * @return true if the view has transient state
      * @deprecated Call {@link View#hasTransientState()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.hasTransientState()")
     @Deprecated
     public static boolean hasTransientState(@NonNull View view) {
         return view.hasTransientState();
@@ -1303,6 +1311,7 @@
      * @param hasTransientState true if this view has transient state
      * @deprecated Call {@link View#setHasTransientState(boolean)} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.setHasTransientState(hasTransientState)")
     @Deprecated
     public static void setHasTransientState(@NonNull View view, boolean hasTransientState) {
         view.setHasTransientState(hasTransientState);
@@ -1318,6 +1327,7 @@
      * @param view View to invalidate
      * @deprecated Call {@link View#postInvalidateOnAnimation()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.postInvalidateOnAnimation()")
     @Deprecated
     public static void postInvalidateOnAnimation(@NonNull View view) {
         view.postInvalidateOnAnimation();
@@ -1337,6 +1347,7 @@
      * @param bottom The bottom coordinate of the rectangle to invalidate.
      * @deprecated Call {@link View#postInvalidateOnAnimation(int, int, int, int)} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.postInvalidateOnAnimation(left, top, right, bottom)")
     @Deprecated
     public static void postInvalidateOnAnimation(@NonNull View view, int left, int top,
             int right, int bottom) {
@@ -1354,6 +1365,7 @@
      * @param action The Runnable that will be executed.
      * @deprecated Call {@link View#postOnAnimation(Runnable)} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.postOnAnimation(action)")
     @Deprecated
     public static void postOnAnimation(@NonNull View view, @NonNull Runnable action) {
         view.postOnAnimation(action);
@@ -1373,6 +1385,7 @@
      *        will be executed.
      * @deprecated Call {@link View#postOnAnimationDelayed(Runnable, long)} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.postOnAnimationDelayed(action, delayMillis)")
     @Deprecated
     @SuppressLint("LambdaLast")
     public static void postOnAnimationDelayed(@NonNull View view, @NonNull Runnable action,
@@ -1394,6 +1407,7 @@
      * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO
      * @deprecated Call {@link View#getImportantForAccessibility()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.getImportantForAccessibility()")
     @Deprecated
     @ImportantForAccessibility
     public static int getImportantForAccessibility(@NonNull View view) {
@@ -1420,6 +1434,7 @@
      * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO
      * @deprecated Call {@link View#setImportantForAccessibility(int)} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.setImportantForAccessibility(mode)")
     @Deprecated
     @UiThread
     public static void setImportantForAccessibility(@NonNull View view,
@@ -1492,6 +1507,7 @@
      * @return Whether the action was performed.
      * @deprecated Call {@link View#performAccessibilityAction(int, Bundle)} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.performAccessibilityAction(action, arguments)")
     @Deprecated
     public static boolean performAccessibilityAction(@NonNull View view, int action,
             @Nullable Bundle arguments) {
@@ -1828,6 +1844,7 @@
      *
      * @deprecated Use {@link View#getAlpha()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.getAlpha()")
     @Deprecated
     public static float getAlpha(View view) {
         return view.getAlpha();
@@ -1867,6 +1884,7 @@
      *
      * @deprecated Use {@link View#setLayerType(int, Paint)} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.setLayerType(layerType, paint)")
     @Deprecated
     public static void setLayerType(View view, @LayerType int layerType, Paint paint) {
         view.setLayerType(layerType, paint);
@@ -1890,6 +1908,7 @@
      *
      * @deprecated Use {@link View#getLayerType()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.getLayerType()")
     @Deprecated
     @LayerType
     public static int getLayerType(View view) {
@@ -1905,6 +1924,7 @@
      * @return The labeled view id.
      * @deprecated Call {@link View#getLabelFor()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.getLabelFor()")
     @Deprecated
     public static int getLabelFor(@NonNull View view) {
         return view.getLabelFor();
@@ -1918,6 +1938,7 @@
      * @param labeledId The labeled view id.
      * @deprecated Call {@link View#setLabelFor(int)} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.setLabelFor(labeledId)")
     @Deprecated
     public static void setLabelFor(@NonNull View view, @IdRes int labeledId) {
         view.setLabelFor(labeledId);
@@ -1954,6 +1975,7 @@
      * @see #setLayerType(View, int, android.graphics.Paint)
      * @deprecated Call {@link View#setLayerPaint(Paint)} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.setLayerPaint(paint)")
     @Deprecated
     public static void setLayerPaint(@NonNull View view, @Nullable Paint paint) {
         view.setLayerPaint(paint);
@@ -1971,6 +1993,7 @@
      *
      * @deprecated Call {@link View#getLayoutDirection()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.getLayoutDirection()")
     @Deprecated
     @ResolvedLayoutDirectionMode
     public static int getLayoutDirection(@NonNull View view) {
@@ -1995,6 +2018,7 @@
      *
      * @deprecated Call {@link View#setLayoutDirection(int)} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.setLayoutDirection(layoutDirection)")
     @Deprecated
     public static void setLayoutDirection(@NonNull View view,
             @LayoutDirectionMode int layoutDirection) {
@@ -2010,6 +2034,7 @@
      * @return The parent for use in accessibility inspection
      * @deprecated Call {@link View#getParentForAccessibility()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.getParentForAccessibility()")
     @Deprecated
     @Nullable
     public static ViewParent getParentForAccessibility(@NonNull View view) {
@@ -2054,6 +2079,7 @@
      * @deprecated Use {@link View#isOpaque()} directly. This method will be
      * removed in a future release.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.isOpaque()")
     @Deprecated
     public static boolean isOpaque(View view) {
         return view.isOpaque();
@@ -2092,6 +2118,7 @@
      *
      * @deprecated Use {@link View#getMeasuredWidth()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.getMeasuredWidthAndState()")
     @Deprecated
     public static int getMeasuredWidthAndState(View view) {
         return view.getMeasuredWidthAndState();
@@ -2109,6 +2136,7 @@
      *
      * @deprecated Use {@link View#getMeasuredHeightAndState()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.getMeasuredHeightAndState()")
     @Deprecated
     public static int getMeasuredHeightAndState(View view) {
         return view.getMeasuredHeightAndState();
@@ -2123,6 +2151,7 @@
      *
      * @deprecated Use {@link View#getMeasuredState()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.getMeasuredState()")
     @Deprecated
     public static int getMeasuredState(View view) {
         return view.getMeasuredState();
@@ -2152,6 +2181,7 @@
      * @see ViewCompat#setAccessibilityLiveRegion(View, int)
      * @deprecated Call {@link View#getAccessibilityLiveRegion()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.getAccessibilityLiveRegion()")
     @Deprecated
     @AccessibilityLiveRegion
     public static int getAccessibilityLiveRegion(@NonNull View view) {
@@ -2199,6 +2229,7 @@
      *        </ul>
      * @deprecated Call {@link View#setAccessibilityLiveRegion(int)} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.setAccessibilityLiveRegion(mode)")
     @Deprecated
     public static void setAccessibilityLiveRegion(@NonNull View view,
             @AccessibilityLiveRegion int mode) {
@@ -2214,6 +2245,7 @@
      * @return the start padding in pixels
      * @deprecated Call {@link View#getPaddingStart()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.getPaddingStart()")
     @Deprecated
     @Px
     public static int getPaddingStart(@NonNull View view) {
@@ -2229,6 +2261,7 @@
      * @return the end padding in pixels
      * @deprecated Call {@link View#getPaddingEnd()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.getPaddingEnd()")
     @Deprecated
     @Px
     public static int getPaddingEnd(@NonNull View view) {
@@ -2249,6 +2282,7 @@
      * @param bottom the bottom padding in pixels
      * @deprecated Call {@link View#setPaddingRelative(int, int, int, int)} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.setPaddingRelative(start, top, end, bottom)")
     @Deprecated
     public static void setPaddingRelative(@NonNull View view, @Px int start, @Px int top,
             @Px int end, @Px int bottom) {
@@ -2322,6 +2356,7 @@
      *
      * @deprecated Use {@link View#getTranslationX()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.getTranslationX()")
     @Deprecated
     public static float getTranslationX(View view) {
         return view.getTranslationX();
@@ -2336,6 +2371,7 @@
      *
      * @deprecated Use {@link View#getTranslationY()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.getTranslationY()")
     @Deprecated
     public static float getTranslationY(View view) {
         return view.getTranslationY();
@@ -2357,6 +2393,7 @@
      *
      * @deprecated Use {@link View#getMatrix()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.getMatrix()")
     @Deprecated
     @Nullable
     public static Matrix getMatrix(View view) {
@@ -2371,6 +2408,7 @@
      * @return the minimum width the view will try to be.
      * @deprecated Call {@link View#getMinimumWidth()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.getMinimumWidth()")
     @Deprecated
     @SuppressWarnings({"JavaReflectionMemberAccess", "ConstantConditions"})
     // Reflective access to private field, unboxing result of reflective get()
@@ -2386,6 +2424,7 @@
      * @return the minimum height the view will try to be.
      * @deprecated Call {@link View#getMinimumHeight()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.getMinimumHeight()")
     @Deprecated
     @SuppressWarnings({"JavaReflectionMemberAccess", "ConstantConditions"})
     // Reflective access to private field, unboxing result of reflective get()
@@ -2425,6 +2464,7 @@
      *
      * @deprecated Use {@link View#setTranslationX(float)} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.setTranslationX(value)")
     @Deprecated
     public static void setTranslationX(View view, float value) {
         view.setTranslationX(value);
@@ -2443,6 +2483,7 @@
      *
      * @deprecated Use {@link View#setTranslationY(float)} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.setTranslationY(value)")
     @Deprecated
     public static void setTranslationY(View view, float value) {
         view.setTranslationY(value);
@@ -2461,6 +2502,7 @@
      *
      * @deprecated Use {@link View#setAlpha(float)} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.setAlpha(value)")
     @Deprecated
     public static void setAlpha(View view, @FloatRange(from = 0.0, to = 1.0) float value) {
         view.setAlpha(value);
@@ -2477,6 +2519,7 @@
      *
      * @deprecated Use {@link View#setX(float)} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.setX(value)")
     @Deprecated
     public static void setX(View view, float value) {
         view.setX(value);
@@ -2493,6 +2536,7 @@
      *
      * @deprecated Use {@link View#setY(float)} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.setY(value)")
     @Deprecated
     public static void setY(View view, float value) {
         view.setY(value);
@@ -2507,6 +2551,7 @@
      *
      * @deprecated Use {@link View#setRotation(float)} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.setRotation(value)")
     @Deprecated
     public static void setRotation(View view, float value) {
         view.setRotation(value);
@@ -2522,6 +2567,7 @@
      *
      * @deprecated Use {@link View#setRotationX(float)} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.setRotationX(value)")
     @Deprecated
     public static void setRotationX(View view, float value) {
         view.setRotationX(value);
@@ -2537,6 +2583,7 @@
      *
      * @deprecated Use {@link View#setRotationY(float)} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.setRotationY(value)")
     @Deprecated
     public static void setRotationY(View view, float value) {
         view.setRotationY(value);
@@ -2551,6 +2598,7 @@
      *
      * @deprecated Use {@link View#setScaleX(float)} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.setScaleX(value)")
     @Deprecated
     public static void setScaleX(View view, float value) {
         view.setScaleX(value);
@@ -2565,6 +2613,7 @@
      *
      * @deprecated Use {@link View#setScaleY(float)} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.setScaleY(value)")
     @Deprecated
     public static void setScaleY(View view, float value) {
         view.setScaleY(value);
@@ -2577,6 +2626,7 @@
      * @param view view for which to get the pivot.
      * @deprecated Use {@link View#getPivotX()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.getPivotX()")
     @Deprecated
     public static float getPivotX(View view) {
         return view.getPivotX();
@@ -2594,6 +2644,7 @@
      *
      * @deprecated Use {@link View#setPivotX(float)} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.setPivotX(value)")
     @Deprecated
     public static void setPivotX(View view, float value) {
         view.setPivotX(value);
@@ -2608,6 +2659,7 @@
      *
      * @deprecated Use {@link View#getPivotY()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.getPivotY()")
     @Deprecated
     public static float getPivotY(View view) {
         return view.getPivotY();
@@ -2625,6 +2677,7 @@
      *
      * @deprecated Use {@link View#setPivotX(float)} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.setPivotY(value)")
     @Deprecated
     public static void setPivotY(View view, float value) {
         view.setPivotY(value);
@@ -2634,6 +2687,7 @@
      * @param view view for which to get the rotation.
      * @deprecated Use {@link View#getRotation()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.getRotation()")
     @Deprecated
     public static float getRotation(View view) {
         return view.getRotation();
@@ -2643,6 +2697,7 @@
      * @param view view for which to get the rotation.
      * @deprecated Use {@link View#getRotationX()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.getRotationX()")
     @Deprecated
     public static float getRotationX(View view) {
         return view.getRotationX();
@@ -2652,6 +2707,7 @@
      * @param view view for which to get the rotation.
      * @deprecated Use {@link View#getRotationY()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.getRotationY()")
     @Deprecated
     public static float getRotationY(View view) {
         return view.getRotationY();
@@ -2661,6 +2717,7 @@
      * @param view view for which to get the scale.
      * @deprecated Use {@link View#getScaleX()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.getScaleX()")
     @Deprecated
     public static float getScaleX(View view) {
         return view.getScaleX();
@@ -2670,6 +2727,7 @@
      * @param view view for which to get the scale.
      * @deprecated Use {@link View#getScaleY()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.getScaleY()")
     @Deprecated
     public static float getScaleY(View view) {
         return view.getScaleY();
@@ -2679,6 +2737,7 @@
      * @param view view for which to get the X.
      * @deprecated Use {@link View#getX()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.getX()")
     @Deprecated
     public static float getX(View view) {
         return view.getX();
@@ -2688,6 +2747,7 @@
      * @param view view for which to get the Y.
      * @deprecated Use {@link View#getY()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.getY()")
     @Deprecated
     public static float getY(View view) {
         return view.getY();
@@ -2788,6 +2848,7 @@
      * @deprecated SystemUiVisibility flags are deprecated. Use
      * {@link WindowInsetsController} instead.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.getWindowSystemUiVisibility()")
     @Deprecated
     public static int getWindowSystemUiVisibility(@NonNull View view) {
         return view.getWindowSystemUiVisibility();
@@ -2849,6 +2910,7 @@
      * @param view view for which to get the state.
      * @deprecated Call {@link View#getFitsSystemWindows()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.getFitsSystemWindows()")
     @Deprecated
     public static boolean getFitsSystemWindows(@NonNull View view) {
         return view.getFitsSystemWindows();
@@ -2866,6 +2928,7 @@
      *
      * @deprecated Use {@link View#setFitsSystemWindows(boolean)} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.setFitsSystemWindows(fitSystemWindows)")
     @Deprecated
     public static void setFitsSystemWindows(View view, boolean fitSystemWindows) {
         view.setFitsSystemWindows(fitSystemWindows);
@@ -2881,6 +2944,7 @@
      * @param view view for which to jump the drawable state.
      * @deprecated Use {@link View#jumpDrawablesToCurrentState()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.jumpDrawablesToCurrentState()")
     @Deprecated
     public static void jumpDrawablesToCurrentState(View view) {
         view.jumpDrawablesToCurrentState();
@@ -3300,6 +3364,7 @@
      *
      * @deprecated Use {@link View#setSaveFromParentEnabled(boolean)} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.setSaveFromParentEnabled(enabled)")
     @Deprecated
     public static void setSaveFromParentEnabled(View view, boolean enabled) {
         view.setSaveFromParentEnabled(enabled);
@@ -3317,6 +3382,7 @@
      *
      * @deprecated Use {@link View#setActivated(boolean)} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.setActivated(activated)")
     @Deprecated
     public static void setActivated(View view, boolean activated) {
         view.setActivated(activated);
@@ -3338,6 +3404,7 @@
      * @return true if the content in this view might overlap, false otherwise.
      * @deprecated Call {@link View#hasOverlappingRendering()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.hasOverlappingRendering()")
     @Deprecated
     public static boolean hasOverlappingRendering(@NonNull View view) {
         return view.hasOverlappingRendering();
@@ -3351,6 +3418,7 @@
      * @return true if the padding is relative or false if it is not.
      * @deprecated Call {@link View#isPaddingRelative()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.isPaddingRelative()")
     @Deprecated
     public static boolean isPaddingRelative(@NonNull View view) {
         return view.isPaddingRelative();
@@ -3365,6 +3433,7 @@
      * @param background the drawable to use as view background.
      * @deprecated Call {@link View#setBackground(Drawable)} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.setBackground(background)")
     @Deprecated
     public static void setBackground(@NonNull View view, @Nullable Drawable background) {
         view.setBackground(background);
@@ -3926,6 +3995,7 @@
      * @return whether the view hierarchy is currently undergoing a layout pass
      * @deprecated Call {@link View#isInLayout()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.isInLayout()")
     @Deprecated
     public static boolean isInLayout(@NonNull View view) {
         return view.isInLayout();
@@ -3936,6 +4006,7 @@
      * was last attached to or detached from a window.
      * @deprecated Call {@link View#isLaidOut()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.isLaidOut()")
     @Deprecated
     public static boolean isLaidOut(@NonNull View view) {
         return view.isLaidOut();
@@ -3952,6 +4023,7 @@
      * @return true if layout direction has been resolved.
      * @deprecated Call {@link View#isLayoutDirectionResolved()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.isLayoutDirectionResolved()")
     @Deprecated
     public static boolean isLayoutDirectionResolved(@NonNull View view) {
         return view.isLayoutDirectionResolved();
@@ -4108,6 +4180,7 @@
      * this view, to which future drawing operations will be clipped.
      * @deprecated Call {@link View#setClipBounds(Rect)} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.setClipBounds(clipBounds)")
     @Deprecated
     public static void setClipBounds(@NonNull View view, @Nullable Rect clipBounds) {
         view.setClipBounds(clipBounds);
@@ -4122,6 +4195,7 @@
      * otherwise null.
      * @deprecated Call {@link View#getClipBounds()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.getClipBounds()")
     @Deprecated
     @Nullable
     public static Rect getClipBounds(@NonNull View view) {
@@ -4132,6 +4206,7 @@
      * Returns true if the provided view is currently attached to a window.
      * @deprecated Call {@link View#isAttachedToWindow()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.isAttachedToWindow()")
     @Deprecated
     public static boolean isAttachedToWindow(@NonNull View view) {
         return view.isAttachedToWindow();
@@ -4143,6 +4218,7 @@
      * @return true if there is a listener, false if there is none.
      * @deprecated Call {@link View#hasOnClickListeners()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.hasOnClickListeners()")
     @Deprecated
     public static boolean hasOnClickListeners(@NonNull View view) {
         return view.hasOnClickListeners();
@@ -4246,6 +4322,7 @@
      * @return The logical display, or null if the view is not currently attached to a window.
      * @deprecated Call {@link View#getDisplay()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "view.getDisplay()")
     @Deprecated
     @Nullable
     public static Display getDisplay(@NonNull View view) {
diff --git a/core/core/src/main/java/androidx/core/view/ViewConfigurationCompat.java b/core/core/src/main/java/androidx/core/view/ViewConfigurationCompat.java
index 8e15fb0..157aa0c 100644
--- a/core/core/src/main/java/androidx/core/view/ViewConfigurationCompat.java
+++ b/core/core/src/main/java/androidx/core/view/ViewConfigurationCompat.java
@@ -69,6 +69,7 @@
      * @deprecated Call {@link ViewConfiguration#getScaledPagingTouchSlop()} directly.
      * This method will be removed in a future release.
      */
+    @androidx.annotation.ReplaceWith(expression = "config.getScaledPagingTouchSlop()")
     @Deprecated
     public static int getScaledPagingTouchSlop(ViewConfiguration config) {
         return config.getScaledPagingTouchSlop();
@@ -80,6 +81,7 @@
      *
      * @deprecated Use {@link ViewConfiguration#hasPermanentMenuKey()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "config.hasPermanentMenuKey()")
     @Deprecated
     public static boolean hasPermanentMenuKey(ViewConfiguration config) {
         return config.hasPermanentMenuKey();
diff --git a/core/core/src/main/java/androidx/core/view/ViewGroupCompat.java b/core/core/src/main/java/androidx/core/view/ViewGroupCompat.java
index 3034440..e35464f 100644
--- a/core/core/src/main/java/androidx/core/view/ViewGroupCompat.java
+++ b/core/core/src/main/java/androidx/core/view/ViewGroupCompat.java
@@ -71,6 +71,7 @@
      * @deprecated Use {@link ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)}
      * directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "group.onRequestSendAccessibilityEvent(child, event)")
     @Deprecated
     public static boolean onRequestSendAccessibilityEvent(ViewGroup group, View child,
             AccessibilityEvent event) {
@@ -95,6 +96,7 @@
      *
      * @deprecated Use {@link ViewGroup#setMotionEventSplittingEnabled(boolean)} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "group.setMotionEventSplittingEnabled(split)")
     @Deprecated
     public static void setMotionEventSplittingEnabled(ViewGroup group, boolean split) {
         group.setMotionEventSplittingEnabled(split);
@@ -111,7 +113,10 @@
      * @return the layout mode to use during layout operations
      *
      * @see #setLayoutMode(ViewGroup, int)
+     * @deprecated Call {@link ViewGroup#getLayoutMode()} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "group.getLayoutMode()")
     public static int getLayoutMode(@NonNull ViewGroup group) {
         return group.getLayoutMode();
     }
@@ -125,7 +130,10 @@
      * @param mode the layout mode to use during layout operations
      *
      * @see #getLayoutMode(ViewGroup)
+     * @deprecated Call {@link ViewGroup#setLayoutMode()} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "group.setLayoutMode(mode)")
     public static void setLayoutMode(@NonNull ViewGroup group, int mode) {
         group.setLayoutMode(mode);
     }
diff --git a/core/core/src/main/java/androidx/core/view/ViewParentCompat.java b/core/core/src/main/java/androidx/core/view/ViewParentCompat.java
index 1e3cdef..2a28972 100644
--- a/core/core/src/main/java/androidx/core/view/ViewParentCompat.java
+++ b/core/core/src/main/java/androidx/core/view/ViewParentCompat.java
@@ -62,6 +62,7 @@
      * @deprecated Use {@link ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)}
      * directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "parent.requestSendAccessibilityEvent(child, event)")
     @Deprecated
     public static boolean requestSendAccessibilityEvent(
             ViewParent parent, View child, AccessibilityEvent event) {
@@ -504,7 +505,10 @@
      *            <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_TEXT}
      *            <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_UNDEFINED}
      *            </ul>
+     * @deprecated Call {@link ViewParent#notifySubtreeAccessibilityStateChanged()} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "parent.notifySubtreeAccessibilityStateChanged(child, source, changeType)")
     public static void notifySubtreeAccessibilityStateChanged(@NonNull ViewParent parent,
             @NonNull View child, @NonNull View source, int changeType) {
         parent.notifySubtreeAccessibilityStateChanged(child, source, changeType);
diff --git a/core/core/src/main/java/androidx/core/view/accessibility/AccessibilityEventCompat.java b/core/core/src/main/java/androidx/core/view/accessibility/AccessibilityEventCompat.java
index 30470be..b5002e8 100644
--- a/core/core/src/main/java/androidx/core/view/accessibility/AccessibilityEventCompat.java
+++ b/core/core/src/main/java/androidx/core/view/accessibility/AccessibilityEventCompat.java
@@ -363,6 +363,7 @@
      *
      * @deprecated Use {@link AccessibilityEvent#getRecordCount()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "event.getRecordCount()")
     @Deprecated
     public static int getRecordCount(AccessibilityEvent event) {
         return event.getRecordCount();
@@ -379,6 +380,7 @@
      *
      * @deprecated Use {@link AccessibilityEvent#appendRecord(AccessibilityRecord)} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "event.appendRecord(record)")
     @SuppressWarnings("deprecation")
     @Deprecated
     public static void appendRecord(AccessibilityEvent event, AccessibilityRecordCompat record) {
@@ -429,7 +431,10 @@
      * @param changeTypes The bit mask of change types.
      * @throws IllegalStateException If called from an AccessibilityService.
      * @see #getContentChangeTypes(AccessibilityEvent)
+     * @deprecated Call {@link AccessibilityEvent#setContentChangeTypes()} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "event.setContentChangeTypes(changeTypes)")
     public static void setContentChangeTypes(@NonNull AccessibilityEvent event,
             @ContentChangeType int changeTypes) {
         event.setContentChangeTypes(changeTypes);
@@ -448,7 +453,10 @@
      *         <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_TEXT}
      *         <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_UNDEFINED}
      *         </ul>
+     * @deprecated Call {@link AccessibilityEvent#getContentChangeTypes()} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "event.getContentChangeTypes()")
     @SuppressLint("WrongConstant")
     @ContentChangeType
     public static int getContentChangeTypes(@NonNull AccessibilityEvent event) {
@@ -462,7 +470,10 @@
      * @param granularity The granularity.
      *
      * @throws IllegalStateException If called from an AccessibilityService.
+     * @deprecated Call {@link AccessibilityEvent#setMovementGranularity()} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "event.setMovementGranularity(granularity)")
     public static void setMovementGranularity(@NonNull AccessibilityEvent event, int granularity) {
         event.setMovementGranularity(granularity);
     }
@@ -471,7 +482,10 @@
      * Gets the movement granularity that was traversed.
      *
      * @return The granularity.
+     * @deprecated Call {@link AccessibilityEvent#getMovementGranularity()} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "event.getMovementGranularity()")
     public static int getMovementGranularity(@NonNull AccessibilityEvent event) {
         return event.getMovementGranularity();
     }
@@ -493,7 +507,10 @@
      * @param action The action.
      * @throws IllegalStateException If called from an AccessibilityService.
      * @see AccessibilityNodeInfoCompat#performAction(int)
+     * @deprecated Call {@link AccessibilityEvent#setAction()} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "event.setAction(action)")
     public static void setAction(@NonNull AccessibilityEvent event, int action) {
         event.setAction(action);
     }
@@ -502,7 +519,10 @@
      * Gets the performed action that triggered this event.
      *
      * @return The action.
+     * @deprecated Call {@link AccessibilityEvent#getAction()} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "event.getAction()")
     public static int getAction(@NonNull AccessibilityEvent event) {
         return event.getAction();
     }
diff --git a/core/core/src/main/java/androidx/core/view/accessibility/AccessibilityManagerCompat.java b/core/core/src/main/java/androidx/core/view/accessibility/AccessibilityManagerCompat.java
index 4cba014..db071eb 100644
--- a/core/core/src/main/java/androidx/core/view/accessibility/AccessibilityManagerCompat.java
+++ b/core/core/src/main/java/androidx/core/view/accessibility/AccessibilityManagerCompat.java
@@ -115,6 +115,7 @@
      *
      * @deprecated Use {@link AccessibilityManager#getInstalledAccessibilityServiceList()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "manager.getInstalledAccessibilityServiceList()")
     @Deprecated
     public static List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(
             AccessibilityManager manager) {
@@ -138,6 +139,7 @@
      * @deprecated Use {@link AccessibilityManager#getEnabledAccessibilityServiceList(int)}
      * directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "manager.getEnabledAccessibilityServiceList(feedbackTypeFlags)")
     @Deprecated
     public static List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList(
             AccessibilityManager manager, int feedbackTypeFlags) {
@@ -152,6 +154,7 @@
      *
      * @deprecated Use {@link AccessibilityManager#isTouchExplorationEnabled()} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "manager.isTouchExplorationEnabled()")
     @Deprecated
     public static boolean isTouchExplorationEnabled(AccessibilityManager manager) {
         return manager.isTouchExplorationEnabled();
@@ -164,7 +167,10 @@
      * @param manager AccessibilityManager for which to add the listener.
      * @param listener The listener.
      * @return True if successfully registered.
+     * @deprecated Call {@link AccessibilityManager#addTouchExplorationStateChangeListener(AccessibilityManager.TouchExplorationStateChangeListener)} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "manager.addTouchExplorationStateChangeListener(listener)")
     public static boolean addTouchExplorationStateChangeListener(
             @NonNull AccessibilityManager manager,
             @NonNull TouchExplorationStateChangeListener listener) {
@@ -178,7 +184,10 @@
      * @param manager AccessibilityManager for which to remove the listener.
      * @param listener The listener.
      * @return True if successfully unregistered.
+     * @deprecated Call {@link AccessibilityManager#removeTouchExplorationStateChangeListener(AccessibilityManager.TouchExplorationStateChangeListener)} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "manager.removeTouchExplorationStateChangeListener(listener)")
     public static boolean removeTouchExplorationStateChangeListener(
             @NonNull AccessibilityManager manager,
             @NonNull TouchExplorationStateChangeListener listener) {
diff --git a/core/core/src/main/java/androidx/core/view/accessibility/AccessibilityRecordCompat.java b/core/core/src/main/java/androidx/core/view/accessibility/AccessibilityRecordCompat.java
index 4cdb3ea..cf9d33f 100644
--- a/core/core/src/main/java/androidx/core/view/accessibility/AccessibilityRecordCompat.java
+++ b/core/core/src/main/java/androidx/core/view/accessibility/AccessibilityRecordCompat.java
@@ -136,7 +136,10 @@
      * @param record The {@link AccessibilityRecord} instance to use.
      * @param root The root of the virtual subtree.
      * @param virtualDescendantId The id of the virtual descendant.
+     * @deprecated Call {@link AccessibilityRecord#setSource()} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "record.setSource(root, virtualDescendantId)")
     public static void setSource(@NonNull AccessibilityRecord record, @Nullable View root,
             int virtualDescendantId) {
         record.setSource(root, virtualDescendantId);
@@ -479,7 +482,10 @@
      *
      * @param record The {@link AccessibilityRecord} instance to use.
      * @return The max scroll.
+     * @deprecated Call {@link AccessibilityRecord#getMaxScrollX()} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "record.getMaxScrollX()")
     public static int getMaxScrollX(@NonNull AccessibilityRecord record) {
         return record.getMaxScrollX();
     }
@@ -501,7 +507,10 @@
      *
      * @param record The {@link AccessibilityRecord} instance to use.
      * @param maxScrollX The max scroll.
+     * @deprecated Call {@link AccessibilityRecord#setMaxScrollX()} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "record.setMaxScrollX(maxScrollX)")
     public static void setMaxScrollX(@NonNull AccessibilityRecord record, int maxScrollX) {
         record.setMaxScrollX(maxScrollX);
     }
@@ -523,7 +532,10 @@
      *
      * @param record The {@link AccessibilityRecord} instance to use.
      * @return The max scroll.
+     * @deprecated Call {@link AccessibilityRecord#getMaxScrollY()} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "record.getMaxScrollY()")
     public static int getMaxScrollY(@NonNull AccessibilityRecord record) {
         return record.getMaxScrollY();
     }
@@ -545,7 +557,10 @@
      *
      * @param record The {@link AccessibilityRecord} instance to use.
      * @param maxScrollY The max scroll.
+     * @deprecated Call {@link AccessibilityRecord#setMaxScrollY()} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "record.setMaxScrollY(maxScrollY)")
     public static void setMaxScrollY(@NonNull AccessibilityRecord record, int maxScrollY) {
         record.setMaxScrollY(maxScrollY);
     }
diff --git a/core/core/src/main/java/androidx/core/widget/CheckedTextViewCompat.java b/core/core/src/main/java/androidx/core/widget/CheckedTextViewCompat.java
index 35078e0..fbdd524 100644
--- a/core/core/src/main/java/androidx/core/widget/CheckedTextViewCompat.java
+++ b/core/core/src/main/java/androidx/core/widget/CheckedTextViewCompat.java
@@ -113,7 +113,10 @@
      * Returns the drawable used as the check mark image
      *
      * @see CheckedTextView#setCheckMarkDrawable(Drawable)
+     * @deprecated Call {@link CheckedTextView#getCheckMarkDrawable()} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "textView.getCheckMarkDrawable()")
     @Nullable
     public static Drawable getCheckMarkDrawable(@NonNull CheckedTextView textView) {
         return textView.getCheckMarkDrawable();
diff --git a/core/core/src/main/java/androidx/core/widget/ListPopupWindowCompat.java b/core/core/src/main/java/androidx/core/widget/ListPopupWindowCompat.java
index 4b8c16c..5818729 100644
--- a/core/core/src/main/java/androidx/core/widget/ListPopupWindowCompat.java
+++ b/core/core/src/main/java/androidx/core/widget/ListPopupWindowCompat.java
@@ -90,7 +90,10 @@
      * @param src the view on which the resulting listener will be set
      * @return a touch listener that controls drag-to-open behavior, or {@code null} on
      *         unsupported APIs
+     * @deprecated Call {@link ListPopupWindow#createDragToOpenListener()} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "listPopupWindow.createDragToOpenListener(src)")
     @Nullable
     public static OnTouchListener createDragToOpenListener(
             @NonNull ListPopupWindow listPopupWindow, @NonNull View src) {
diff --git a/core/core/src/main/java/androidx/core/widget/ListViewCompat.java b/core/core/src/main/java/androidx/core/widget/ListViewCompat.java
index 894c7cb..328fcb68a 100644
--- a/core/core/src/main/java/androidx/core/widget/ListViewCompat.java
+++ b/core/core/src/main/java/androidx/core/widget/ListViewCompat.java
@@ -35,6 +35,7 @@
      * @param y the amount of pixels to scroll by vertically
      * @deprecated Use {@link ListView#scrollListBy(int)} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "listView.scrollListBy(y)")
     @Deprecated
     public static void scrollListBy(@NonNull ListView listView, int y) {
         // Call the framework version directly
@@ -52,6 +53,7 @@
      * @see #scrollListBy(ListView, int)
      * @deprecated Use {@link ListView#canScrollList(int)} directly.
      */
+    @androidx.annotation.ReplaceWith(expression = "listView.canScrollList(direction)")
     @Deprecated
     public static boolean canScrollList(@NonNull ListView listView, int direction) {
         // Call the framework version directly
diff --git a/core/core/src/main/java/androidx/core/widget/PopupWindowCompat.java b/core/core/src/main/java/androidx/core/widget/PopupWindowCompat.java
index b87351b..93e4bf0 100644
--- a/core/core/src/main/java/androidx/core/widget/PopupWindowCompat.java
+++ b/core/core/src/main/java/androidx/core/widget/PopupWindowCompat.java
@@ -61,7 +61,10 @@
      * @param xoff A horizontal offset from the anchor in pixels
      * @param yoff A vertical offset from the anchor in pixels
      * @param gravity Alignment of the popup relative to the anchor
+     * @deprecated Call {@link PopupWindow#showAsDropDown()} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "popup.showAsDropDown(anchor, xoff, yoff, gravity)")
     public static void showAsDropDown(@NonNull PopupWindow popup, @NonNull View anchor,
             int xoff, int yoff, int gravity) {
         popup.showAsDropDown(anchor, xoff, yoff, gravity);
diff --git a/core/core/src/main/java/androidx/core/widget/TextViewCompat.java b/core/core/src/main/java/androidx/core/widget/TextViewCompat.java
index c205dc4..b02cad1 100644
--- a/core/core/src/main/java/androidx/core/widget/TextViewCompat.java
+++ b/core/core/src/main/java/androidx/core/widget/TextViewCompat.java
@@ -116,7 +116,10 @@
      * @attr name android:drawableTop
      * @attr name android:drawableEnd
      * @attr name android:drawableBottom
+     * @deprecated Call {@link TextView#setCompoundDrawablesRelative()} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "textView.setCompoundDrawablesRelative(start, top, end, bottom)")
     public static void setCompoundDrawablesRelative(@NonNull TextView textView,
             @Nullable Drawable start, @Nullable Drawable top, @Nullable Drawable end,
             @Nullable Drawable bottom) {
@@ -141,7 +144,10 @@
      * @attr name android:drawableTop
      * @attr name android:drawableEnd
      * @attr name android:drawableBottom
+     * @deprecated Call {@link TextView#setCompoundDrawablesRelativeWithIntrinsicBounds()} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "textView.setCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom)")
     public static void setCompoundDrawablesRelativeWithIntrinsicBounds(@NonNull TextView textView,
             @Nullable Drawable start, @Nullable Drawable top, @Nullable Drawable end,
             @Nullable Drawable bottom) {
@@ -165,7 +171,10 @@
      * @attr name android:drawableTop
      * @attr name android:drawableEnd
      * @attr name android:drawableBottom
+     * @deprecated Call {@link TextView#setCompoundDrawablesRelativeWithIntrinsicBounds()} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "textView.setCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom)")
     public static void setCompoundDrawablesRelativeWithIntrinsicBounds(@NonNull TextView textView,
             @DrawableRes int start, @DrawableRes int top, @DrawableRes int end,
             @DrawableRes int bottom) {
@@ -175,7 +184,10 @@
     /**
      * Returns the maximum number of lines displayed in the given TextView, or -1 if the maximum
      * height was set in pixels instead.
+     * @deprecated Call {@link TextView#getMaxLines()} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "textView.getMaxLines()")
     public static int getMaxLines(@NonNull TextView textView) {
         return textView.getMaxLines();
     }
@@ -183,7 +195,10 @@
     /**
      * Returns the minimum number of lines displayed in the given TextView, or -1 if the minimum
      * height was set in pixels instead.
+     * @deprecated Call {@link TextView#getMinLines()} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "textView.getMinLines()")
     public static int getMinLines(@NonNull TextView textView) {
         return textView.getMinLines();
     }
@@ -207,7 +222,10 @@
 
     /**
      * Returns drawables for the start, top, end, and bottom borders from the given text view.
+     * @deprecated Call {@link TextView#getCompoundDrawablesRelative()} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "textView.getCompoundDrawablesRelative()")
     @NonNull
     public static Drawable[] getCompoundDrawablesRelative(@NonNull TextView textView) {
         return textView.getCompoundDrawablesRelative();
@@ -406,7 +424,10 @@
      *
      * @param textView The TextView to set the action selection mode callback on.
      * @param callback The action selection mode callback to set on textView.
+     * @deprecated Call {@link TextView#setCustomSelectionActionModeCallback(ActionMode.Callback)} directly.
      */
+    @Deprecated
+    @androidx.annotation.ReplaceWith(expression = "textView.setCustomSelectionActionModeCallback(callback)")
     public static void setCustomSelectionActionModeCallback(@NonNull final TextView textView,
                 @NonNull final ActionMode.Callback callback) {
         textView.setCustomSelectionActionModeCallback(
diff --git a/docs-tip-of-tree/build.gradle b/docs-tip-of-tree/build.gradle
index 8de75841..2c6fac9 100644
--- a/docs-tip-of-tree/build.gradle
+++ b/docs-tip-of-tree/build.gradle
@@ -255,7 +255,7 @@
     docs(project(":lifecycle:lifecycle-reactivestreams"))
     docs(project(":lifecycle:lifecycle-reactivestreams-ktx"))
     kmpDocs(project(":lifecycle:lifecycle-runtime"))
-    docs(project(":lifecycle:lifecycle-runtime-compose"))
+    kmpDocs(project(":lifecycle:lifecycle-runtime-compose"))
     samples(project(":lifecycle:lifecycle-runtime-compose:lifecycle-runtime-compose-samples"))
     kmpDocs(project(":lifecycle:lifecycle-runtime-ktx"))
     docs(project(":lifecycle:lifecycle-runtime-testing"))
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-af/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-af/strings.xml
index e4840e4..2f2764a 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-af/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-af/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Geen emosiekone beskikbaar nie"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Jy het nog geen emosiekone gebruik nie"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"emosiekoon-tweerigtingoorskakelaar"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"emosiekoonvariantkieser"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s en %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"skadu"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-am/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-am/strings.xml
index 6f838f3..97c5687 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-am/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-am/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"ምንም ስሜት ገላጭ ምስሎች አይገኙም"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"ምንም ስሜት ገላጭ ምስሎችን እስካሁን አልተጠቀሙም"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"የስሜት ገላጭ ምስል ባለሁለት አቅጣጫ መቀያየሪያ"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"የስሜት ገላጭ ምስል ተለዋዋጭ መራጭ"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s እና %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"ጥላ"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-ar/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-ar/strings.xml
index d345acd..feecf8b 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-ar/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-ar/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"لا تتوفر أي رموز تعبيرية."</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"لم تستخدم أي رموز تعبيرية حتى الآن."</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"مفتاح ثنائي الاتجاه للرموز التعبيرية"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"أداة اختيار الرموز التعبيرية"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"‏%1$s و%2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"الظل"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-as/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-as/strings.xml
index dfdb76c..e5a5711 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-as/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-as/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"কোনো ইম’জি উপলব্ধ নহয়"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"আপুনি এতিয়ালৈকে কোনো ইম’জি ব্যৱহাৰ কৰা নাই"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"ইম’জি বাইডাইৰেকশ্বনেল ছুইচ্চাৰ"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"ইম’জিৰ প্ৰকাৰ বাছনি কৰোঁতা"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s আৰু %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"ছাঁ"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-az/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-az/strings.xml
index 3816c2a..02385b3 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-az/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-az/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Əlçatan emoji yoxdur"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Hələ heç bir emojidən istifadə etməməsiniz"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"ikitərəfli emoji dəyişdirici"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"emoji variant seçicisi"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s və %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"kölgə"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-b+sr+Latn/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-b+sr+Latn/strings.xml
index 9325eeb..2f30bef9 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-b+sr+Latn/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-b+sr+Latn/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Emodžiji nisu dostupni"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Još niste koristili emodžije"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"dvosmerni prebacivač emodžija"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"birač varijanti emodžija"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s i %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"senka"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-be/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-be/strings.xml
index 8c1d50a..6b75a0a 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-be/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-be/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Няма даступных эмодзі"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Вы пакуль не выкарыстоўвалі эмодзі"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"пераключальнік кірунку для эмодзі"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"інструмент выбару варыянтаў эмодзі"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s і %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"цень"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-bg/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-bg/strings.xml
index c1c4050..f6dc8b4 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-bg/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-bg/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Няма налични емоджи"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Все още не сте използвали емоджита"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"двупосочен превключвател на емоджи"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"инструмент за избор на варианти за емоджи"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s и %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"сянка"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-bn/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-bn/strings.xml
index ca8f374..fbfa46f 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-bn/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-bn/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"কোনও ইমোজি উপলভ্য নেই"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"আপনি এখনও কোনও ইমোজি ব্যবহার করেননি"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"ইমোজি দ্বিমুখী সুইচার"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"ইমোজি ভেরিয়েন্ট বাছাইকারী"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s এবং %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"ছায়া"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-bs/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-bs/strings.xml
index b619963..9999766 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-bs/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-bs/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Emoji sličice nisu dostupne"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Još niste koristili nijednu emoji sličicu"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"dvosmjerni prebacivač emodžija"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"birač varijanti emodžija"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s i %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"sjenka"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-ca/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-ca/strings.xml
index 31d1289..74620de 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-ca/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-ca/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"No hi ha cap emoji disponible"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Encara no has fet servir cap emoji"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"selector bidireccional d\'emojis"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"selector de variants d\'emojis"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s i %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"ombra"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-cs/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-cs/strings.xml
index 92e63e5..322f1eb 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-cs/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-cs/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Nejsou k dispozici žádné smajlíky"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Zatím jste žádná emodži nepoužili"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"dvousměrný přepínač smajlíků"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"výběr variant emodži"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s a %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"stín"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-da/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-da/strings.xml
index b2146f9..10003a8 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-da/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-da/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Der er ingen tilgængelige emojis"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Du har ikke brugt nogen emojis endnu"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"tovejsskifter til emojis"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"vælger for emojivariant"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s og %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"skygge"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-de/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-de/strings.xml
index 95fd48a..af1afa6 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-de/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-de/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Keine Emojis verfügbar"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Du hast noch keine Emojis verwendet"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"Bidirektionale Emoji-Auswahl"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"Emojivarianten-Auswahl"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s und %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"Hautton"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-el/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-el/strings.xml
index 48d189f..b2f231a 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-el/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-el/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Δεν υπάρχουν διαθέσιμα emoji"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Δεν έχετε χρησιμοποιήσει κανένα emoji ακόμα"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"αμφίδρομο στοιχείο εναλλαγής emoji"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"επιλογέας παραλλαγής emoji"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s και %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"σκιά"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-en-rAU/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-en-rAU/strings.xml
index 64aafcd..8489a35 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-en-rAU/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-en-rAU/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"No emojis available"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"You haven\'t used any emoji yet"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"emoji bidirectional switcher"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"emoji variant selector"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s and %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"shadow"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-en-rCA/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-en-rCA/strings.xml
index 0aacec5..d056590 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-en-rCA/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-en-rCA/strings.xml
@@ -30,6 +30,7 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"No emojis available"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"You haven\'t used any emojis yet"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"emoji bidirectional switcher"</string>
+    <string name="emoji_bidirectional_switcher_clicked_desc" msgid="5055290162204827523">"emoji facing direction switched"</string>
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"emoji variant selector"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s and %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"shadow"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-en-rGB/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-en-rGB/strings.xml
index 64aafcd..8489a35 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-en-rGB/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-en-rGB/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"No emojis available"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"You haven\'t used any emoji yet"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"emoji bidirectional switcher"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"emoji variant selector"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s and %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"shadow"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-en-rIN/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-en-rIN/strings.xml
index 64aafcd..8489a35 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-en-rIN/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-en-rIN/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"No emojis available"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"You haven\'t used any emoji yet"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"emoji bidirectional switcher"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"emoji variant selector"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s and %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"shadow"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-en-rXC/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-en-rXC/strings.xml
index 3cda27a..3e02185 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-en-rXC/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-en-rXC/strings.xml
@@ -30,6 +30,7 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‎‎‎‎‎‎‎‏‎‎‎‎‏‏‎‏‎‏‏‎‏‎‏‏‎‎‎‎‎‎‎‏‎‏‎‏‎‎‏‏‎‎‎‎‎‏‎‏‎‎‏‎‏‎‎‎‏‎No emojis available‎‏‎‎‏‎"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‏‎‎‎‏‎‎‎‎‏‏‎‏‏‎‎‏‏‏‎‎‎‎‏‎‎‎‏‏‏‏‏‎‏‎‎‎‎‏‏‎‎‎‏‎‏‎‏‎‏‏‎‎‎‎You haven\'t used any emojis yet‎‏‎‎‏‎"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎‏‎‎‏‎‎‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‎‎‏‏‏‏‎‏‎‏‏‏‎‏‎‎‏‎‏‎‎‎‎‏‎‏‎‎‎‏‏‏‏‎‏‎emoji bidirectional switcher‎‏‎‎‏‎"</string>
+    <string name="emoji_bidirectional_switcher_clicked_desc" msgid="5055290162204827523">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‎‏‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‎‏‎‏‎‎‏‎‏‎‏‏‏‏‏‎‏‏‎‏‏‏‏‏‏‎‎‎‎‎‏‏‎emoji facing direction switched‎‏‎‎‏‎"</string>
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‎‎‎‏‏‏‎‏‏‎‎‎‏‎‏‎‏‏‏‏‎‏‎‏‎‏‏‎‏‎‎‎‏‎‎‏‎‎‏‎‎‎‏‏‎‏‎‏‎‎‏‏‎‎‎‎‎‎emoji variant selector‎‏‎‎‏‎"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‎‎‏‎‎‎‏‎‎‏‎‏‏‏‎‎‏‎‎‏‎‏‏‏‏‏‏‎‎‎‏‏‎‎‏‎‎‏‎‏‎‎‎‏‎‏‏‏‏‎‏‎‎‎‏‎%1$s and %2$s‎‏‎‎‏‎"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‎‏‏‎‏‏‎‎‎‏‏‏‎‎‎‏‏‏‏‏‏‏‎‎‎‏‏‎‏‎‎‏‎‏‎‎‏‏‏‏‎‎‎‎‏‏‏‎‏‎‏‏‎‎‎‎‎shadow‎‏‎‎‏‎"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-es-rUS/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-es-rUS/strings.xml
index 852b61a..fe5c953 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-es-rUS/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-es-rUS/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"No hay ningún emoji disponible"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Todavía no usaste ningún emoji"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"selector bidireccional de emojis"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"selector de variantes de emojis"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s y %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"sombra"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-es/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-es/strings.xml
index ec695ad..001b0616 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-es/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-es/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"No hay emojis disponibles"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Aún no has usado ningún emoji"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"cambio bidireccional de emojis"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"selector de variantes de emojis"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s y %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"sombra"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-et/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-et/strings.xml
index c7c7d04..2373a5f 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-et/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-et/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Ühtegi emotikoni pole saadaval"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Te pole veel ühtegi emotikoni kasutanud"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"emotikoni kahesuunaline lüliti"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"emotikoni variandi valija"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s ja %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"vari"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-eu/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-eu/strings.xml
index 6edea1d..ce763b5 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-eu/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-eu/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Ez dago emotikonorik erabilgarri"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Ez duzu erabili emojirik oraingoz"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"noranzko biko emoji-aldatzailea"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"emojien aldaeren hautatzailea"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s eta %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"itzala"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-fa/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-fa/strings.xml
index d917197..ddd1f3e 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-fa/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-fa/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"اموجی دردسترس نیست"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"هنوز از هیچ اموجی‌ای استفاده نکرده‌اید"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"تغییردهنده دوسویه اموجی"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"گزینشگر متغیر اموجی"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"‏%1$s و %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"سایه"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-fi/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-fi/strings.xml
index 4d68349..e184b24 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-fi/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-fi/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Ei emojeita saatavilla"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Et ole vielä käyttänyt emojeita"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"emoji kaksisuuntainen vaihtaja"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"emojivalitsin"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s ja %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"varjostus"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-fr-rCA/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-fr-rCA/strings.xml
index c8fc499..4afaf46 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-fr-rCA/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-fr-rCA/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Aucun émoji proposé"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Vous n\'avez encore utilisé aucun émoji"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"sélecteur bidirectionnel d\'émoji"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"sélecteur de variantes d\'émoji"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s et %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"ombre"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-fr/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-fr/strings.xml
index fad386d..006beb5 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-fr/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-fr/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Aucun emoji disponible"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Vous n\'avez pas encore utilisé d\'emoji"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"sélecteur d\'emoji bidirectionnel"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"sélecteur de variante d\'emoji"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s et %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"ombre"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-gl/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-gl/strings.xml
index 91b3073..74211e6 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-gl/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-gl/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Non hai ningún emoji dispoñible"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Aínda non utilizaches ningún emoji"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"selector bidireccional de emojis"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"selector de variantes de emojis"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s e %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"sombra"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-gu/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-gu/strings.xml
index 0960d6e..27f28f7 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-gu/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-gu/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"કોઈ ઇમોજી ઉપલબ્ધ નથી"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"તમે હજી સુધી કોઈ ઇમોજીનો ઉપયોગ કર્યો નથી"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"બે દિશામાં સ્વિચ થઈ શકતું ઇમોજી સ્વિચર"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"ઇમોજીનો પ્રકાર પસંદગીકર્તા"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s અને %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"શૅડો"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-hi/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-hi/strings.xml
index ab9a466..8954985 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-hi/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-hi/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"कोई इमोजी उपलब्ध नहीं है"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"आपने अब तक किसी भी इमोजी का इस्तेमाल नहीं किया है"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"दोनों तरफ़ ले जा सकने वाले स्विचर का इमोजी"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"इमोजी के वैरिएंट चुनने का टूल"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s और %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"शैडो"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-hr/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-hr/strings.xml
index 00be2dc..9deac2a 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-hr/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-hr/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Nije dostupan nijedan emoji"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Još niste upotrijebili emojije"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"dvosmjerni izmjenjivač emojija"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"alat za odabir varijante emojija"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s i %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"sjena"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-hu/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-hu/strings.xml
index 727f33c..ceddf96 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-hu/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-hu/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Nincsenek rendelkezésre álló emojik"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Még nem használt emojikat"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"kétirányú emojiváltó"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"emojiváltozat-választó"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s és %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"árnyék"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-hy/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-hy/strings.xml
index 414e304..135c7cf 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-hy/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-hy/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Հասանելի էմոջիներ չկան"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Դուք դեռ չեք օգտագործել էմոջիներ"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"էմոջիների երկկողմանի փոխանջատիչ"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"էմոջիների տարբերակի ընտրիչ"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s և %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"ստվեր"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-in/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-in/strings.xml
index 84d9bd5..0c6e8e0 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-in/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-in/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Tidak ada emoji yang tersedia"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Anda belum menggunakan emoji apa pun"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"pengalih dua arah emoji"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"pemilih varian emoji"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s dan %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"bayangan"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-is/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-is/strings.xml
index 60e2844..a8eafdb 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-is/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-is/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Engin emoji-tákn í boði"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Þú hefur ekki notað nein emoji enn"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"emoji-val í báðar áttir"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"val emoji-afbrigðis"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s og %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"skuggi"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-it/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-it/strings.xml
index a2fee10..52ce11a 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-it/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-it/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Nessuna emoji disponibile"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Non hai ancora usato alcuna emoji"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"selettore bidirezionale di emoji"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"selettore variante emoji"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s e %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"ombra"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-iw/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-iw/strings.xml
index c8c10cd..7e5fbef 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-iw/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-iw/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"אין סמלי אמוג\'י זמינים"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"עדיין לא השתמשת באף אמוג\'י"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"לחצן דו-כיווני למעבר לאמוג\'י"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"בורר של סוגי אמוג\'י"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"‏%1$s ו-%2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"צל"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-ja/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-ja/strings.xml
index 128f95b..5ccfb32 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-ja/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-ja/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"使用できる絵文字がありません"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"まだ絵文字を使用していません"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"絵文字の双方向切り替え"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"絵文字バリエーション セレクタ"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s、%2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"シャドウ"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-ka/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-ka/strings.xml
index 4434f10..06eb1bf 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-ka/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-ka/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Emoji-ები მიუწვდომელია"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Emoji-ებით ჯერ არ გისარგებლიათ"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"emoji-ს ორმიმართულებიანი გადამრთველი"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"emoji-ს ვარიანტის ამომრჩევი"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s და %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"ჩრდილი"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-kk/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-kk/strings.xml
index 173b655..3904ef7 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-kk/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-kk/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Эмоджи жоқ"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Әлі ешқандай эмоджи пайдаланылған жоқ."</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"екіжақты эмоджи ауыстырғыш"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"эмоджи нұсқаларын таңдау құралы"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s және %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"көлеңке"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-km/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-km/strings.xml
index f202d60..dd0864f 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-km/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-km/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"មិនមាន​រូប​អារម្មណ៍ទេ"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"អ្នក​មិនទាន់​បានប្រើរូប​អារម្មណ៍​ណាមួយ​នៅឡើយទេ"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"មុខងារប្ដូរទ្វេទិសនៃរូប​អារម្មណ៍"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"ផ្ទាំងជ្រើសរើសជម្រើសរូប​អារម្មណ៍"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s និង %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"ស្រមោល"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-kn/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-kn/strings.xml
index 3e6397e..6b1a4ec 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-kn/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-kn/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"ಯಾವುದೇ ಎಮೊಜಿಗಳು ಲಭ್ಯವಿಲ್ಲ"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"ನೀವು ಇನ್ನೂ ಯಾವುದೇ ಎಮೋಜಿಗಳನ್ನು ಬಳಸಿಲ್ಲ"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"ಎಮೋಜಿ ಬೈಡೈರೆಕ್ಷನಲ್ ಸ್ವಿಚರ್"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"ಎಮೋಜಿ ವೇರಿಯಂಟ್ ಸೆಲೆಕ್ಟರ್"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s ಮತ್ತು %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"ನೆರಳು"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-ko/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-ko/strings.xml
index b0fd567..7b70de3 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-ko/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-ko/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"사용 가능한 그림 이모티콘 없음"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"아직 사용한 이모티콘이 없습니다."</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"그림 이모티콘 양방향 전환기"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"그림 이모티콘 옵션 선택기"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s 및 %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"그림자"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-ky/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-ky/strings.xml
index e5e69cc1..7a611da 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-ky/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-ky/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Жеткиликтүү быйтыкчалар жок"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Бир да быйтыкча колдоно элексиз"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"эки тараптуу быйтыкча которгуч"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"быйтыкча тандагыч"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s жана %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"көлөкө"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-lo/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-lo/strings.xml
index 7203809..66d587d 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-lo/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-lo/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"ບໍ່ມີອີໂມຈິໃຫ້ນຳໃຊ້"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"ທ່ານຍັງບໍ່ໄດ້ໃຊ້ອີໂມຈິໃດເທື່ອ"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"ຕົວສະຫຼັບອີໂມຈິແບບ 2 ທິດທາງ"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"ຕົວເລືອກຕົວແປອີໂມຈິ"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s ແລະ %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"ເງົາ"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-lt/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-lt/strings.xml
index 6c7ed80..dc59457 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-lt/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-lt/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Nėra jokių pasiekiamų jaustukų"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Dar nenaudojote jokių jaustukų"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"dvikryptis jaustukų perjungikli"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"jaustuko varianto parinkiklis"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s ir %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"šešėlis"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-lv/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-lv/strings.xml
index 43ed60e..a5e643a 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-lv/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-lv/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Nav pieejamu emocijzīmju"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Jūs vēl neesat izmantojis nevienu emocijzīmi"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"emocijzīmju divvirzienu pārslēdzējs"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"emocijzīmes varianta atlasītājs"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s un %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"ēna"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-mk/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-mk/strings.xml
index 756205f..7695add 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-mk/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-mk/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Нема достапни емоџија"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Сѐ уште не сте користеле емоџија"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"двонасочен менувач на емоџија"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"избирач на варијанти на емоџија"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s и %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"сенка"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-ml/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-ml/strings.xml
index 5eaa499..8a947b0 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-ml/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-ml/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"ഇമോജികളൊന്നും ലഭ്യമല്ല"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"നിങ്ങൾ ഇതുവരെ ഇമോജികളൊന്നും ഉപയോഗിച്ചിട്ടില്ല"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"ഇമോജി ദ്വിദിശ സ്വിച്ചർ"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"ഇമോജി വേരിയന്റ് സെലക്‌ടർ"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s, %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"ഷാഡോ"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-mn/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-mn/strings.xml
index 8a10449..cc43f11 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-mn/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-mn/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Боломжтой эможи алга"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Та ямар нэгэн эможи ашиглаагүй байна"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"эможигийн хоёр чиглэлтэй сэлгүүр"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"эможигийн хувилбар сонгогч"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s болон %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"сүүдэр"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-mr/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-mr/strings.xml
index ecebaed..8a676b6 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-mr/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-mr/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"कोणतेही इमोजी उपलब्ध नाहीत"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"तुम्ही अद्याप कोणतेही इमोजी वापरलेले नाहीत"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"इमोजीचा द्विदिश स्विचर"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"इमोजी व्हेरीयंट सिलेक्टर"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s आणि %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"शॅडो"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-ms/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-ms/strings.xml
index 616b9ce..92f49b2 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-ms/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-ms/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Tiada emoji tersedia"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Anda belum menggunakan mana-mana emoji lagi"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"penukar dwiarah emoji"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"pemilih varian emoji"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s dan %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"bebayang"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-my/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-my/strings.xml
index 3a8a920..47e9d43 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-my/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-my/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"အီမိုဂျီ မရနိုင်ပါ"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"အီမိုဂျီ အသုံးမပြုသေးပါ"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"အီမိုဂျီ လမ်းကြောင်းနှစ်ခုပြောင်းစနစ်"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"အီမိုဂျီမူကွဲ ရွေးချယ်စနစ်"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s နှင့် %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"အရိပ်"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-nb/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-nb/strings.xml
index 7283de8..eca673e 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-nb/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-nb/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Ingen emojier er tilgjengelige"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Du har ikke brukt noen emojier ennå"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"toveisvelger for emoji"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"velger for emojivariant"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s og %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"skygge"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-ne/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-ne/strings.xml
index 63a95e5..94c2101 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-ne/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-ne/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"कुनै पनि इमोजी उपलब्ध छैन"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"तपाईंले हालसम्म कुनै पनि इमोजी प्रयोग गर्नुभएको छैन"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"दुवै दिशामा लैजान सकिने स्विचरको इमोजी"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"इमोजी भेरियन्ट सेलेक्टर"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s र %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"छाया"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-nl/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-nl/strings.xml
index 1e9aaff..6b7ce3e 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-nl/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-nl/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Geen emoji\'s beschikbaar"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Je hebt nog geen emoji\'s gebruikt"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"bidirectionele emoji-schakelaar"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"emoji-variantkiezer"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s en %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"schaduw"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-or/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-or/strings.xml
index fe11974..d692666 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-or/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-or/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"କୌଣସି ଇମୋଜି ଉପଲବ୍ଧ ନାହିଁ"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"ଆପଣ ଏପର୍ଯ୍ୟନ୍ତ କୌଣସି ଇମୋଜି ବ୍ୟବହାର କରିନାହାଁନ୍ତି"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"ଇମୋଜିର ବାଇଡାଇରେକ୍ସନାଲ ସୁଇଚର"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"ଇମୋଜି ଭାରିଏଣ୍ଟ ଚୟନକାରୀ"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s ଏବଂ %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"ସେଡୋ"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-pa/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-pa/strings.xml
index 2f6c890..65ba6eb 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-pa/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-pa/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"ਕੋਈ ਇਮੋਜੀ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"ਤੁਸੀਂ ਹਾਲੇ ਤੱਕ ਕਿਸੇ ਵੀ ਇਮੋਜੀ ਦੀ ਵਰਤੋਂ ਨਹੀਂ ਕੀਤੀ ਹੈ"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"ਇਮੋਜੀ ਬਾਇਡਾਇਰੈਕਸ਼ਨਲ ਸਵਿੱਚਰ"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"ਇਮੋਜੀ ਕਿਸਮ ਚੋਣਕਾਰ"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s ਅਤੇ %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"ਸ਼ੈਡੋ"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-pl/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-pl/strings.xml
index 5505626..30fc600 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-pl/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-pl/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Brak dostępnych emotikonów"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Żadne emotikony nie zostały jeszcze użyte"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"dwukierunkowy przełącznik emotikonów"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"selektor wariantu emotikona"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s i %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"cień"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-pt-rBR/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-pt-rBR/strings.xml
index caa37c5..687fdf3 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-pt-rBR/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-pt-rBR/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Não há emojis disponíveis"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Você ainda não usou emojis"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"seletor bidirecional de emojis"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"seletor de variante do emoji"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s e %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"sombra"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-pt-rPT/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-pt-rPT/strings.xml
index ad29a54..44dd744 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-pt-rPT/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-pt-rPT/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Nenhum emoji disponível"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Ainda não utilizou emojis"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"comutador bidirecional de emojis"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"seletor de variantes de emojis"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s e %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"sombra"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-pt/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-pt/strings.xml
index caa37c5..687fdf3 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-pt/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-pt/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Não há emojis disponíveis"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Você ainda não usou emojis"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"seletor bidirecional de emojis"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"seletor de variante do emoji"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s e %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"sombra"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-ro/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-ro/strings.xml
index c06f239..621d664 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-ro/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-ro/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Nu sunt disponibile emoji-uri"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Încă nu ai folosit emoji"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"comutator bidirecțional de emojiuri"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"selector de variante de emoji"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s și %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"umbră"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-ru/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-ru/strings.xml
index e2fea1f..79e8f91 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-ru/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-ru/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Нет доступных эмодзи"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Вы ещё не использовали эмодзи"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"Двухсторонний переключатель эмодзи"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"выбор вариантов эмодзи"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s и %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"теневой"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-si/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-si/strings.xml
index b906785..85d2c99 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-si/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-si/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"ඉමොජි කිසිවක් නොලැබේ"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"ඔබ තවමත් කිසිදු ඉමෝජියක් භාවිතා කර නැත"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"ද්විත්ව දිශා ඉමොජි මාරුකරණය"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"ඉමොජි ප්‍රභේද තෝරකය"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s සහ %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"සෙවනැල්ල"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-sk/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-sk/strings.xml
index 96fa6ca..83ffa27 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-sk/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-sk/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Nie sú k dispozícii žiadne emodži"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Zatiaľ ste nepoužili žiadne emodži"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"obojsmerný prepínač emodži"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"selektor variantu emodži"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s a %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"tieň"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-sl/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-sl/strings.xml
index 02f0e10..cdf2ba4 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-sl/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-sl/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Ni emodžijev"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Uporabili niste še nobenega emodžija."</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"dvosmerni preklopnik emodžijev"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"Izbirnik različice emodžija"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s in %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"senčenje"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-sq/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-sq/strings.xml
index 68d70e5..3948314 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-sq/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-sq/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Nuk ofrohen emoji"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Nuk ke përdorur ende asnjë emoji"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"ndërruesi me dy drejtime për emoji-t"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"përzgjedhësi i variantit të emoji-t"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s dhe %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"hije"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-sr/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-sr/strings.xml
index 712a714..14c1a14 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-sr/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-sr/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Емоџији нису доступни"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Још нисте користили емоџије"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"двосмерни пребацивач емоџија"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"бирач варијанти емоџија"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s и %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"сенка"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-sv/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-sv/strings.xml
index 2ce0e0f..48c1766 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-sv/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-sv/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Inga emojier tillgängliga"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Du har ännu inte använt emojis"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"dubbelriktad emojiväxlare"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"Väljare av emoji-varianter"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s och %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"skugga"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-sw/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-sw/strings.xml
index 1f95731..78da124 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-sw/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-sw/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Hakuna emoji zinazopatikana"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Bado hujatumia emoji zozote"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"kibadilishaji cha emoji cha pande mbili"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"kiteuzi cha kibadala cha emoji"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s na %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"kivuli"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-ta/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-ta/strings.xml
index dff24f7..5f54f35 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-ta/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-ta/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"ஈமோஜிகள் எதுவுமில்லை"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"இதுவரை ஈமோஜி எதையும் நீங்கள் பயன்படுத்தவில்லை"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"ஈமோஜி இருபக்க மாற்றி"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"ஈமோஜி வகைத் தேர்வி"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s மற்றும் %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"நிழல்"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-te/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-te/strings.xml
index 0d14b90..3ad93db 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-te/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-te/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"ఎమోజీలు ఏవీ అందుబాటులో లేవు"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"మీరు ఇంకా ఎమోజీలు ఏవీ ఉపయోగించలేదు"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"ఎమోజీ ద్విదిశాత్మక స్విచ్చర్"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"ఎమోజి రకాన్ని ఎంపిక చేసే సాధనం"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s, %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"షాడో"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-th/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-th/strings.xml
index 432627d..7b6e8f3 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-th/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-th/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"ไม่มีอีโมจิ"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"คุณยังไม่ได้ใช้อีโมจิเลย"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"ตัวสลับอีโมจิแบบ 2 ทาง"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"ตัวเลือกตัวแปรอีโมจิ"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s และ %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"เงา"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-tl/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-tl/strings.xml
index 611e2ce..e319300 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-tl/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-tl/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Walang available na emoji"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Hindi ka pa gumamit ng anumang emoji"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"bidirectional na switcher ng emoji"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"selector ng variant ng emoji"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s at %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"shadow"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-tr/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-tr/strings.xml
index 57960f3..5444f71 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-tr/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-tr/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Kullanılabilir emoji yok"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Henüz emoji kullanmadınız"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"çift yönlü emoji değiştirici"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"emoji varyant seçici"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s ve %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"gölge"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-uk/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-uk/strings.xml
index 1d599ff..d611feb 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-uk/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-uk/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Немає смайлів"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Ви ще не використовували смайли"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"двосторонній перемикач смайлів"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"засіб вибору варіанта смайла"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s і %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"тінь"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-ur/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-ur/strings.xml
index 7ed0acd..ab6d0d7 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-ur/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-ur/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"کوئی بھی ایموجی دستیاب نہیں ہے"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"آپ نے ابھی تک کوئی بھی ایموجی استعمال نہیں کی ہے"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"دو طرفہ سوئچر ایموجی"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"ایموجی کی قسم کا منتخب کنندہ"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"‏‎%1$s اور ‎%2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"پرچھائیں"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-uz/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-uz/strings.xml
index f4ff0d5..9670dfa 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-uz/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-uz/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Hech qanday emoji mavjud emas"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Hanuz birorta emoji ishlatmagansiz"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"ikki tomonlama emoji almashtirgich"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"emoji variant tanlagich"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s va %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"soya"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-vi/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-vi/strings.xml
index f765385..5f92913 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-vi/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-vi/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Không có biểu tượng cảm xúc nào"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Bạn chưa sử dụng biểu tượng cảm xúc nào"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"trình chuyển đổi hai chiều biểu tượng cảm xúc"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"bộ chọn biến thể biểu tượng cảm xúc"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s và %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"bóng"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-zh-rCN/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-zh-rCN/strings.xml
index 9774a91..e3e7e19 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-zh-rCN/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-zh-rCN/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"没有可用的表情符号"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"您尚未使用过任何表情符号"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"表情符号双向切换器"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"表情符号变体选择器"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s和%2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"阴影"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-zh-rHK/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-zh-rHK/strings.xml
index 4db6d89..dd58b5b 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-zh-rHK/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-zh-rHK/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"沒有可用的 Emoji"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"你尚未使用任何 Emoji"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"Emoji 雙向切換工具"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"Emoji 變化版本選取器"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s和%2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"陰影"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-zh-rTW/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-zh-rTW/strings.xml
index bc57f72..04ecc98 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-zh-rTW/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-zh-rTW/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"沒有可用的表情符號"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"你尚未使用任何表情符號"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"表情符號雙向切換器"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"表情符號變化版本選取器"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"%1$s和%2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"陰影"</string>
diff --git a/emoji2/emoji2-emojipicker/src/main/res/values-zu/strings.xml b/emoji2/emoji2-emojipicker/src/main/res/values-zu/strings.xml
index adf8cba..bd0c20f 100644
--- a/emoji2/emoji2-emojipicker/src/main/res/values-zu/strings.xml
+++ b/emoji2/emoji2-emojipicker/src/main/res/values-zu/strings.xml
@@ -30,6 +30,8 @@
     <string name="emoji_empty_non_recent_category" msgid="288822832574892625">"Awekho ama-emoji atholakalayo"</string>
     <string name="emoji_empty_recent_category" msgid="7863877827879290200">"Awukasebenzisi noma yimaphi ama-emoji okwamanje"</string>
     <string name="emoji_bidirectional_switcher_content_desc" msgid="5084600168354220605">"isishintshi se-emoji ye-bidirectional"</string>
+    <!-- no translation found for emoji_bidirectional_switcher_clicked_desc (5055290162204827523) -->
+    <skip />
     <string name="emoji_variant_selector_content_desc" msgid="2898934883418401376">"isikhethi esihlukile se-emoji"</string>
     <string name="emoji_variant_content_desc_template" msgid="6381933050671041489">"Okuthi %1$s nokuthi %2$s"</string>
     <string name="emoji_skin_tone_shadow_content_desc" msgid="1759906883307507376">"isithunzi"</string>
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/DefaultSpecialEffectsController.kt b/fragment/fragment/src/main/java/androidx/fragment/app/DefaultSpecialEffectsController.kt
index 77c93de..9dd1719 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/DefaultSpecialEffectsController.kt
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/DefaultSpecialEffectsController.kt
@@ -338,6 +338,13 @@
                 if (sharedElementNameMapping.isEmpty()) {
                     // We couldn't find any valid shared element mappings, so clear out
                     // the shared element transition information entirely
+                    Log.i(FragmentManager.TAG,
+                        "Ignoring shared elements transition $sharedElementTransition between " +
+                            "$firstOut and $lastIn as there are no matching elements " +
+                            "in both the entering and exiting fragment. In order to run a " +
+                            "SharedElementTransition, both fragments involved must have the " +
+                            "element."
+                    )
                     sharedElementTransition = null
                     sharedElementFirstOutViews.clear()
                     sharedElementLastInViews.clear()
@@ -716,7 +723,9 @@
                     Build.VERSION.SDK_INT >= 34 &&
                         it.transition != null &&
                         transitionImpl.isSeekingSupported(it.transition)
-                }
+                } &&
+                (sharedElementTransition == null ||
+                transitionImpl.isSeekingSupported(sharedElementTransition))
 
         val transitioning: Boolean
             get() = transitionInfos.all {
@@ -737,6 +746,16 @@
                 }
                 return
             }
+            if (transitioning && sharedElementTransition != null && !isSeekingSupported) {
+                Log.i(FragmentManager.TAG,
+                    "Ignoring shared elements transition $sharedElementTransition between " +
+                        "$firstOut and $lastIn as neither fragment has set a Transition. In " +
+                        "order to run a SharedElementTransition, you must also set either an " +
+                        "enter or exit transition on a fragment involved in the transaction. The " +
+                        "sharedElementTransition will run after the back gesture has been " +
+                        "committed."
+                )
+            }
             if (isSeekingSupported && transitioning) {
                 // We need to set the listener before we create the controller, but we need the
                 // controller to do the desired cancel behavior (animateToStart). So we use this
diff --git a/glance/glance-appwidget-testing/src/test/kotlin/androidx/glance/appwidget/testing/unit/GlanceAppWidgetUnitTestEnvironmentTest.kt b/glance/glance-appwidget-testing/src/test/kotlin/androidx/glance/appwidget/testing/unit/GlanceAppWidgetUnitTestEnvironmentTest.kt
index 457cc70..e71b14a 100644
--- a/glance/glance-appwidget-testing/src/test/kotlin/androidx/glance/appwidget/testing/unit/GlanceAppWidgetUnitTestEnvironmentTest.kt
+++ b/glance/glance-appwidget-testing/src/test/kotlin/androidx/glance/appwidget/testing/unit/GlanceAppWidgetUnitTestEnvironmentTest.kt
@@ -27,6 +27,7 @@
 import androidx.datastore.preferences.core.Preferences
 import androidx.datastore.preferences.core.booleanPreferencesKey
 import androidx.datastore.preferences.core.preferencesOf
+import androidx.glance.Button
 import androidx.glance.GlanceModifier
 import androidx.glance.Image
 import androidx.glance.ImageProvider
@@ -205,7 +206,7 @@
                     Text("text-row")
                 }
                 Spacer()
-                Text("text-in-column")
+                Button("text-in-column", onClick = {})
             }
         }
 
diff --git a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/components/Scaffold.kt b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/components/Scaffold.kt
index 4ea2755..4c136aa 100644
--- a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/components/Scaffold.kt
+++ b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/components/Scaffold.kt
@@ -42,7 +42,7 @@
 fun Scaffold(
     titleBar: @Composable () -> Unit,
     modifier: GlanceModifier = GlanceModifier,
-    backgroundColor: ColorProvider = GlanceTheme.colors.surface,
+    backgroundColor: ColorProvider = GlanceTheme.colors.widgetBackground,
     content: @Composable () -> Unit,
     ) {
     Box(modifier
diff --git a/glance/glance-testing/src/test/kotlin/androidx/glance/testing/unit/UnitTestFiltersTest.kt b/glance/glance-testing/src/test/kotlin/androidx/glance/testing/unit/UnitTestFiltersTest.kt
index 69aa1a9..02f1d26 100644
--- a/glance/glance-testing/src/test/kotlin/androidx/glance/testing/unit/UnitTestFiltersTest.kt
+++ b/glance/glance-testing/src/test/kotlin/androidx/glance/testing/unit/UnitTestFiltersTest.kt
@@ -16,6 +16,7 @@
 
 package androidx.glance.testing.unit
 
+import androidx.glance.EmittableButton
 import androidx.glance.GlanceModifier
 import androidx.glance.layout.EmittableColumn
 import androidx.glance.semantics.semantics
@@ -68,6 +69,19 @@
     }
 
     @Test
+    fun hasTextOnButton_match_returnsTrue() {
+        val testSingleNode = GlanceMappedNode(
+            EmittableButton().apply {
+                text = "existing text"
+            }
+        )
+
+        val result = hasTextEqualTo("existing text").matches(testSingleNode)
+
+        assertThat(result).isTrue()
+    }
+
+    @Test
     fun hasTextEqualTo_noMatch_returnsFalse() {
         val testSingleNode = GlanceMappedNode(
             EmittableText().apply {
diff --git a/glance/glance/src/main/java/androidx/glance/Button.kt b/glance/glance/src/main/java/androidx/glance/Button.kt
index c40d42c..56592f7 100644
--- a/glance/glance/src/main/java/androidx/glance/Button.kt
+++ b/glance/glance/src/main/java/androidx/glance/Button.kt
@@ -129,13 +129,10 @@
 }
 
 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-class EmittableButton : Emittable {
+class EmittableButton : EmittableWithText() {
     override var modifier: GlanceModifier = GlanceModifier
-    var text: String = ""
-    var style: TextStyle? = null
     var colors: ButtonColors? = null
     var enabled: Boolean = true
-    var maxLines: Int = Int.MAX_VALUE
 
     override fun copy(): Emittable = EmittableButton().also {
         it.modifier = modifier
diff --git a/graphics/graphics-core/src/androidTest/java/androidx/graphics/opengl/GLRendererTest.kt b/graphics/graphics-core/src/androidTest/java/androidx/graphics/opengl/GLRendererTest.kt
index 962b2ad..a5b9900 100644
--- a/graphics/graphics-core/src/androidTest/java/androidx/graphics/opengl/GLRendererTest.kt
+++ b/graphics/graphics-core/src/androidTest/java/androidx/graphics/opengl/GLRendererTest.kt
@@ -134,6 +134,25 @@
     }
 
     @Test
+    fun testExecuteHasEGLContext() {
+        val glRenderer = GLRenderer()
+        glRenderer.start()
+        try {
+            var hasContext = false
+            val contextLatch = CountDownLatch(1)
+            glRenderer.execute {
+                val eglContext = EGL14.eglGetCurrentContext()
+                hasContext = eglContext != null && eglContext != EGL14.EGL_NO_CONTEXT
+                contextLatch.countDown()
+            }
+            assertTrue(contextLatch.await(3000, TimeUnit.MILLISECONDS))
+            assertTrue(hasContext)
+        } finally {
+            glRenderer.stop(true)
+        }
+    }
+
+    @Test
     fun testDetachExecutesPendingRequests() {
         val latch = CountDownLatch(1)
         val renderer = object : GLRenderer.RenderCallback {
diff --git a/graphics/graphics-core/src/main/java/androidx/graphics/opengl/GLRenderer.kt b/graphics/graphics-core/src/main/java/androidx/graphics/opengl/GLRenderer.kt
index b4354a1..86ab2af 100644
--- a/graphics/graphics-core/src/main/java/androidx/graphics/opengl/GLRenderer.kt
+++ b/graphics/graphics-core/src/main/java/androidx/graphics/opengl/GLRenderer.kt
@@ -225,7 +225,8 @@
 
     /**
      * Queue a [Runnable] to be executed on the GL rendering thread. Note it is important that this
-     * [Runnable] does not block otherwise it can stall the GL thread.
+     * [Runnable] does not block otherwise it can stall the GL thread. The EGLContext will
+     * be created after [start] is invoked and before the runnable is executed.
      *
      * @param runnable Runnable to be executed
      */
@@ -304,8 +305,8 @@
         /**
          * Callback invoked on the backing thread after EGL dependencies are initialized.
          * This is guaranteed to be invoked before any instance of
-         * [RenderCallback.onSurfaceCreated] is called.
-         * This will be invoked lazily before the first request to [GLRenderer.requestRender]
+         * [RenderCallback.onSurfaceCreated] is called. This will be invoked after
+         * [GLRenderer.start].
          */
         // Suppressing CallbackMethodName due to b/238939160
         @Suppress("AcronymName", "CallbackMethodName")
diff --git a/graphics/graphics-core/src/main/java/androidx/graphics/opengl/GLThread.kt b/graphics/graphics-core/src/main/java/androidx/graphics/opengl/GLThread.kt
index afd433b..26d395e 100644
--- a/graphics/graphics-core/src/main/java/androidx/graphics/opengl/GLThread.kt
+++ b/graphics/graphics-core/src/main/java/androidx/graphics/opengl/GLThread.kt
@@ -51,7 +51,11 @@
 
     override fun start() {
         super.start()
-        mHandler = Handler(looper)
+        mHandler = Handler(looper).apply {
+            // Create an EGLContext right after starting in order to have one ready on a call to
+            // GLRenderer#execute
+            post { obtainEGLManager() }
+        }
     }
 
     /**
diff --git a/libraryversions.toml b/libraryversions.toml
index c3050a51..6be3d78 100644
--- a/libraryversions.toml
+++ b/libraryversions.toml
@@ -14,10 +14,10 @@
 BLUETOOTH = "1.0.0-alpha02"
 BROWSER = "1.9.0-alpha01"
 BUILDSRC_TESTS = "1.0.0-alpha01"
-CAMERA = "1.4.0-alpha04"
+CAMERA = "1.4.0-alpha05"
 CAMERA_PIPE = "1.0.0-alpha01"
 CAMERA_TESTING = "1.0.0-alpha01"
-CAMERA_VIEWFINDER = "1.4.0-alpha04"
+CAMERA_VIEWFINDER = "1.4.0-alpha05"
 CAMERA_VIEWFINDER_COMPOSE = "1.0.0-alpha01"
 CARDVIEW = "1.1.0-alpha01"
 CAR_APP = "1.7.0-alpha01"
diff --git a/lifecycle/lifecycle-runtime-compose/build.gradle b/lifecycle/lifecycle-runtime-compose/build.gradle
index 5acc0e3..a772da7 100644
--- a/lifecycle/lifecycle-runtime-compose/build.gradle
+++ b/lifecycle/lifecycle-runtime-compose/build.gradle
@@ -22,28 +22,52 @@
  * modifying its settings.
  */
 import androidx.build.LibraryType
+import androidx.build.PlatformIdentifier
 
 plugins {
     id("AndroidXPlugin")
     id("com.android.library")
     id("AndroidXComposePlugin")
-    id("org.jetbrains.kotlin.android")
 }
 
-dependencies {
-    api projectOrArtifact(":lifecycle:lifecycle-runtime-ktx")
-    api("androidx.annotation:annotation-experimental:1.4.0")
-    api("androidx.compose.runtime:runtime:1.0.1")
+androidXMultiplatform {
+    android()
+    desktop()
 
-    implementation(libs.kotlinStdlib)
+    defaultPlatform(PlatformIdentifier.ANDROID)
 
-    androidTestImplementation(projectOrArtifact(":lifecycle:lifecycle-runtime-testing"))
-    androidTestImplementation projectOrArtifact(":compose:ui:ui-test-junit4")
-    androidTestImplementation project(":compose:test-utils")
-    androidTestImplementation(libs.testRules)
-    androidTestImplementation(libs.testRunner)
-    androidTestImplementation(libs.junit)
-    androidTestImplementation(libs.truth)
+    sourceSets {
+        commonMain {
+            dependencies {
+                api(projectOrArtifact(":lifecycle:lifecycle-runtime"))
+                api(project(":annotation:annotation"))
+                api(project(":compose:runtime:runtime"))
+            }
+        }
+
+        androidMain {
+            dependsOn(commonMain)
+            dependencies {
+                // Although this artifact is empty, it ensures that upgrading
+                // `lifecycle-runtime-compose` also updates `lifecycle-runtime-ktx`
+                // in cases where our constraints fail (e.g., internally in AndroidX
+                // when using project dependencies).
+                api(projectOrArtifact(":lifecycle:lifecycle-runtime-ktx"))
+            }
+        }
+
+        androidInstrumentedTest {
+            dependencies {
+                implementation(projectOrArtifact(":lifecycle:lifecycle-runtime-testing"))
+                implementation(projectOrArtifact(":compose:ui:ui-test-junit4"))
+                implementation(project(":compose:test-utils"))
+                implementation(libs.testRules)
+                implementation(libs.testRunner)
+                implementation(libs.junit)
+                implementation(libs.truth)
+            }
+        }
+    }
 }
 
 androidx {
@@ -52,7 +76,7 @@
     inceptionYear = "2021"
     description = "Compose integration with Lifecycle"
     metalavaK2UastEnabled = true
-    samples(projectOrArtifact(":lifecycle:lifecycle-runtime-compose:lifecycle-runtime-compose-samples"))
+    samples(project(":lifecycle:lifecycle-runtime-compose:lifecycle-runtime-compose-samples"))
 }
 
 android {
diff --git a/lifecycle/lifecycle-runtime-compose/src/androidTest/java/androidx/lifecycle/compose/CollectAsStateWithLifecycleTests.kt b/lifecycle/lifecycle-runtime-compose/src/androidInstrumentedTest/kotlin/androidx/lifecycle/compose/CollectAsStateWithLifecycleTests.kt
similarity index 100%
rename from lifecycle/lifecycle-runtime-compose/src/androidTest/java/androidx/lifecycle/compose/CollectAsStateWithLifecycleTests.kt
rename to lifecycle/lifecycle-runtime-compose/src/androidInstrumentedTest/kotlin/androidx/lifecycle/compose/CollectAsStateWithLifecycleTests.kt
diff --git a/lifecycle/lifecycle-runtime-compose/src/androidTest/java/androidx/lifecycle/compose/DropUnlessLifecycleTest.kt b/lifecycle/lifecycle-runtime-compose/src/androidInstrumentedTest/kotlin/androidx/lifecycle/compose/DropUnlessLifecycleTest.kt
similarity index 100%
rename from lifecycle/lifecycle-runtime-compose/src/androidTest/java/androidx/lifecycle/compose/DropUnlessLifecycleTest.kt
rename to lifecycle/lifecycle-runtime-compose/src/androidInstrumentedTest/kotlin/androidx/lifecycle/compose/DropUnlessLifecycleTest.kt
diff --git a/lifecycle/lifecycle-runtime-compose/src/androidTest/java/androidx/lifecycle/compose/LifecycleEffectTest.kt b/lifecycle/lifecycle-runtime-compose/src/androidInstrumentedTest/kotlin/androidx/lifecycle/compose/LifecycleEffectTest.kt
similarity index 100%
rename from lifecycle/lifecycle-runtime-compose/src/androidTest/java/androidx/lifecycle/compose/LifecycleEffectTest.kt
rename to lifecycle/lifecycle-runtime-compose/src/androidInstrumentedTest/kotlin/androidx/lifecycle/compose/LifecycleEffectTest.kt
diff --git a/lifecycle/lifecycle-runtime-compose/src/androidTest/java/androidx/lifecycle/compose/LifecycleExtTest.kt b/lifecycle/lifecycle-runtime-compose/src/androidInstrumentedTest/kotlin/androidx/lifecycle/compose/LifecycleExtTest.kt
similarity index 100%
rename from lifecycle/lifecycle-runtime-compose/src/androidTest/java/androidx/lifecycle/compose/LifecycleExtTest.kt
rename to lifecycle/lifecycle-runtime-compose/src/androidInstrumentedTest/kotlin/androidx/lifecycle/compose/LifecycleExtTest.kt
diff --git a/lifecycle/lifecycle-runtime-compose/src/main/java/androidx/lifecycle/compose/DropUnlessLifecycle.kt b/lifecycle/lifecycle-runtime-compose/src/commonMain/kotlin/androidx/lifecycle/compose/DropUnlessLifecycle.kt
similarity index 100%
rename from lifecycle/lifecycle-runtime-compose/src/main/java/androidx/lifecycle/compose/DropUnlessLifecycle.kt
rename to lifecycle/lifecycle-runtime-compose/src/commonMain/kotlin/androidx/lifecycle/compose/DropUnlessLifecycle.kt
diff --git a/lifecycle/lifecycle-runtime-compose/src/main/java/androidx/lifecycle/compose/FlowExt.kt b/lifecycle/lifecycle-runtime-compose/src/commonMain/kotlin/androidx/lifecycle/compose/FlowExt.kt
similarity index 97%
rename from lifecycle/lifecycle-runtime-compose/src/main/java/androidx/lifecycle/compose/FlowExt.kt
rename to lifecycle/lifecycle-runtime-compose/src/commonMain/kotlin/androidx/lifecycle/compose/FlowExt.kt
index d5cc18c..3aaed3b 100644
--- a/lifecycle/lifecycle-runtime-compose/src/main/java/androidx/lifecycle/compose/FlowExt.kt
+++ b/lifecycle/lifecycle-runtime-compose/src/commonMain/kotlin/androidx/lifecycle/compose/FlowExt.kt
@@ -53,6 +53,7 @@
  * @param context [CoroutineContext] to use for collecting.
  */
 @Composable
+@Suppress("StateFlowValueCalledInComposition") // Initial value for an ongoing collect.
 fun <T> StateFlow<T>.collectAsStateWithLifecycle(
     lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current,
     minActiveState: Lifecycle.State = Lifecycle.State.STARTED,
@@ -87,6 +88,7 @@
  * @param context [CoroutineContext] to use for collecting.
  */
 @Composable
+@Suppress("StateFlowValueCalledInComposition") // Initial value for an ongoing collect.
 fun <T> StateFlow<T>.collectAsStateWithLifecycle(
     lifecycle: Lifecycle,
     minActiveState: Lifecycle.State = Lifecycle.State.STARTED,
diff --git a/lifecycle/lifecycle-runtime-compose/src/main/java/androidx/lifecycle/compose/LifecycleEffect.kt b/lifecycle/lifecycle-runtime-compose/src/commonMain/kotlin/androidx/lifecycle/compose/LifecycleEffect.kt
similarity index 100%
rename from lifecycle/lifecycle-runtime-compose/src/main/java/androidx/lifecycle/compose/LifecycleEffect.kt
rename to lifecycle/lifecycle-runtime-compose/src/commonMain/kotlin/androidx/lifecycle/compose/LifecycleEffect.kt
diff --git a/lifecycle/lifecycle-runtime-compose/src/main/java/androidx/lifecycle/compose/LifecycleExt.kt b/lifecycle/lifecycle-runtime-compose/src/commonMain/kotlin/androidx/lifecycle/compose/LifecycleExt.kt
similarity index 100%
rename from lifecycle/lifecycle-runtime-compose/src/main/java/androidx/lifecycle/compose/LifecycleExt.kt
rename to lifecycle/lifecycle-runtime-compose/src/commonMain/kotlin/androidx/lifecycle/compose/LifecycleExt.kt
diff --git a/lifecycle/lifecycle-runtime-compose/src/main/java/androidx/lifecycle/compose/LocalLifecycleOwner.kt b/lifecycle/lifecycle-runtime-compose/src/commonMain/kotlin/androidx/lifecycle/compose/LocalLifecycleOwner.kt
similarity index 100%
rename from lifecycle/lifecycle-runtime-compose/src/main/java/androidx/lifecycle/compose/LocalLifecycleOwner.kt
rename to lifecycle/lifecycle-runtime-compose/src/commonMain/kotlin/androidx/lifecycle/compose/LocalLifecycleOwner.kt
diff --git a/lifecycle/lifecycle-viewmodel/build.gradle b/lifecycle/lifecycle-viewmodel/build.gradle
index 7a72a8e..6fdae8ef 100644
--- a/lifecycle/lifecycle-viewmodel/build.gradle
+++ b/lifecycle/lifecycle-viewmodel/build.gradle
@@ -47,6 +47,10 @@
     defaultPlatform(PlatformIdentifier.ANDROID)
 
     sourceSets {
+        configureEach {
+            languageSettings.optIn("kotlin.contracts.ExperimentalContracts")
+        }
+
         commonMain {
             dependencies {
                 api(project(":annotation:annotation"))
diff --git a/lifecycle/lifecycle-viewmodel/src/commonMain/kotlin/androidx/lifecycle/ViewModel.kt b/lifecycle/lifecycle-viewmodel/src/commonMain/kotlin/androidx/lifecycle/ViewModel.kt
index 9328eab..cb1bb1a 100644
--- a/lifecycle/lifecycle-viewmodel/src/commonMain/kotlin/androidx/lifecycle/ViewModel.kt
+++ b/lifecycle/lifecycle-viewmodel/src/commonMain/kotlin/androidx/lifecycle/ViewModel.kt
@@ -18,9 +18,10 @@
 package androidx.lifecycle
 
 import androidx.annotation.MainThread
-import androidx.lifecycle.viewmodel.internal.Lock
+import androidx.lifecycle.viewmodel.internal.SynchronizedObject
 import androidx.lifecycle.viewmodel.internal.VIEW_MODEL_SCOPE_KEY
 import androidx.lifecycle.viewmodel.internal.createViewModelScope
+import androidx.lifecycle.viewmodel.internal.synchronized
 import kotlin.coroutines.EmptyCoroutineContext
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
@@ -220,9 +221,9 @@
  * @see ViewModel.onCleared
  */
 public val ViewModel.viewModelScope: CoroutineScope
-    get() = viewModelScopeLock.withLock {
+    get() = synchronized(VIEW_MODEL_SCOPE_LOCK) {
         getCloseable(VIEW_MODEL_SCOPE_KEY)
             ?: createViewModelScope().also { scope -> addCloseable(VIEW_MODEL_SCOPE_KEY, scope) }
     }
 
-private val viewModelScopeLock = Lock()
+private val VIEW_MODEL_SCOPE_LOCK = SynchronizedObject()
diff --git a/lifecycle/lifecycle-viewmodel/src/commonMain/kotlin/androidx/lifecycle/viewmodel/InitializerViewModelFactory.kt b/lifecycle/lifecycle-viewmodel/src/commonMain/kotlin/androidx/lifecycle/viewmodel/InitializerViewModelFactory.kt
index a38409b..4e111db 100644
--- a/lifecycle/lifecycle-viewmodel/src/commonMain/kotlin/androidx/lifecycle/viewmodel/InitializerViewModelFactory.kt
+++ b/lifecycle/lifecycle-viewmodel/src/commonMain/kotlin/androidx/lifecycle/viewmodel/InitializerViewModelFactory.kt
@@ -20,6 +20,7 @@
 import androidx.lifecycle.ViewModel
 import androidx.lifecycle.ViewModelProvider
 import androidx.lifecycle.viewmodel.internal.ViewModelProviders
+import androidx.lifecycle.viewmodel.internal.canonicalName
 import kotlin.jvm.JvmName
 import kotlin.reflect.KClass
 
@@ -54,7 +55,7 @@
         initializer: CreationExtras.() -> T,
     ) {
         require(clazz !in initializers) {
-            "A `initializer` with the same `clazz` has already been added: ${clazz.qualifiedName}."
+            "A `initializer` with the same `clazz` has already been added: ${clazz.canonicalName}."
         }
         initializers[clazz] = ViewModelInitializer(clazz, initializer)
     }
diff --git a/lifecycle/lifecycle-viewmodel/src/commonMain/kotlin/androidx/lifecycle/viewmodel/internal/Lock.kt b/lifecycle/lifecycle-viewmodel/src/commonMain/kotlin/androidx/lifecycle/viewmodel/internal/Lock.kt
deleted file mode 100644
index b342a19..0000000
--- a/lifecycle/lifecycle-viewmodel/src/commonMain/kotlin/androidx/lifecycle/viewmodel/internal/Lock.kt
+++ /dev/null
@@ -1,33 +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.lifecycle.viewmodel.internal
-
-/**
- * Provides a custom multiplatform locking mechanism for controlling access to a shared resource by
- * multiple threads.
- *
- * The implementation depends on the platform:
- * - On JVM/ART: uses JDK's synchronization.
- * - On Native: uses posix.
- */
-internal expect class Lock() {
-
-    /**
-     * Executes the given function [block] while holding the monitor of the current [Lock].
-     */
-    inline fun <T> withLock(crossinline block: () -> T): T
-}
diff --git a/lifecycle/lifecycle-viewmodel/src/commonMain/kotlin/androidx/lifecycle/viewmodel/internal/SynchronizedObject.kt b/lifecycle/lifecycle-viewmodel/src/commonMain/kotlin/androidx/lifecycle/viewmodel/internal/SynchronizedObject.kt
new file mode 100644
index 0000000..d7af3ef
--- /dev/null
+++ b/lifecycle/lifecycle-viewmodel/src/commonMain/kotlin/androidx/lifecycle/viewmodel/internal/SynchronizedObject.kt
@@ -0,0 +1,56 @@
+/*
+ * 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.lifecycle.viewmodel.internal
+
+import kotlin.contracts.InvocationKind
+import kotlin.contracts.contract
+
+/**
+ * A [SynchronizedObject] provides a mechanism for thread coordination. Instances of this class
+ * are used within [synchronized] functions to establish mutual exclusion, guaranteeing that only
+ * one thread accesses a protected resource or code block at a time.
+ */
+internal expect class SynchronizedObject()
+
+/**
+ * Executes the given function [action] while holding the monitor of the given object [lock].
+ *
+ * The implementation is platform specific:
+ * - JVM: implemented via `synchronized`, `ReentrantLock` is avoided for performance reasons.
+ * - Native: implemented via POSIX mutex with `PTHREAD_MUTEX_RECURSIVE` flag.
+ */
+internal inline fun <T> synchronized(lock: SynchronizedObject, crossinline action: () -> T): T {
+    contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) }
+    return synchronizedImpl(lock, action)
+}
+
+/**
+ * Executes the given function [action] while holding the monitor of the given object [lock].
+ *
+ * The implementation is platform specific:
+ * - JVM: implemented via `synchronized`, `ReentrantLock` is avoided for performance reasons.
+ * - Native: implemented via POSIX mutex with `PTHREAD_MUTEX_RECURSIVE` flag.
+ *
+ * **This is a private API and should not be used from general code.** This function exists
+ * primarily as a workaround for a Kotlin issue
+ * ([KT-29963](https://youtrack.jetbrains.com/issue/KT-29963)).
+ *
+ * You **MUST** use [synchronized] instead.
+ */
+internal expect inline fun <T> synchronizedImpl(
+    lock: SynchronizedObject,
+    crossinline action: () -> T,
+): T
diff --git a/lifecycle/lifecycle-viewmodel/src/commonMain/kotlin/androidx/lifecycle/viewmodel/internal/ViewModelImpl.kt b/lifecycle/lifecycle-viewmodel/src/commonMain/kotlin/androidx/lifecycle/viewmodel/internal/ViewModelImpl.kt
index 752ec79..dd79e0c 100644
--- a/lifecycle/lifecycle-viewmodel/src/commonMain/kotlin/androidx/lifecycle/viewmodel/internal/ViewModelImpl.kt
+++ b/lifecycle/lifecycle-viewmodel/src/commonMain/kotlin/androidx/lifecycle/viewmodel/internal/ViewModelImpl.kt
@@ -33,7 +33,7 @@
  */
 internal class ViewModelImpl {
 
-    private val lock = Lock()
+    private val lock = SynchronizedObject()
 
     /**
      * Holds a mapping between [String] keys and [AutoCloseable] resources that have been associated
@@ -47,7 +47,7 @@
      * 2. [closeables][AutoCloseable.close]
      * 3. [ViewModel.onCleared]
      *
-     * **Note:** Manually [Lock] is necessary to prevent issues on Android API 21 and 22.
+     * **Note:** Manually [SynchronizedObject] is necessary to prevent issues on Android API 21 and 22.
      * This avoids potential problems found in older versions of `ConcurrentHashMap`.
      *
      * @see <a href="https://issuetracker.google.com/37042460">b/37042460</a>
@@ -83,7 +83,7 @@
         if (isCleared) return
 
         isCleared = true
-        lock.withLock {
+        synchronized(lock) {
             // 1. Closes resources added without a key.
             // 2. Closes resources added with a key.
             for (closeable in closeables + keyToCloseables.values) {
@@ -105,7 +105,7 @@
             return
         }
 
-        val oldCloseable = lock.withLock { keyToCloseables.put(key, closeable) }
+        val oldCloseable = synchronized(lock) { keyToCloseables.put(key, closeable) }
         closeWithRuntimeException(oldCloseable)
     }
 
@@ -119,13 +119,13 @@
             return
         }
 
-        lock.withLock { closeables += closeable }
+        synchronized(lock) { closeables += closeable }
     }
 
     /** @see [ViewModel.getCloseable] */
     fun <T : AutoCloseable> getCloseable(key: String): T? =
         @Suppress("UNCHECKED_CAST")
-        lock.withLock { keyToCloseables[key] as T? }
+        synchronized(lock) { keyToCloseables[key] as T? }
 
     private fun closeWithRuntimeException(closeable: AutoCloseable?) {
         try {
diff --git a/lifecycle/lifecycle-viewmodel/src/jvmMain/kotlin/androidx/lifecycle/viewmodel/internal/Lock.jvm.kt b/lifecycle/lifecycle-viewmodel/src/jvmMain/kotlin/androidx/lifecycle/viewmodel/internal/SynchronizedObject.jvm.kt
similarity index 75%
rename from lifecycle/lifecycle-viewmodel/src/jvmMain/kotlin/androidx/lifecycle/viewmodel/internal/Lock.jvm.kt
rename to lifecycle/lifecycle-viewmodel/src/jvmMain/kotlin/androidx/lifecycle/viewmodel/internal/SynchronizedObject.jvm.kt
index 9d20353..6d79f87 100644
--- a/lifecycle/lifecycle-viewmodel/src/jvmMain/kotlin/androidx/lifecycle/viewmodel/internal/Lock.jvm.kt
+++ b/lifecycle/lifecycle-viewmodel/src/jvmMain/kotlin/androidx/lifecycle/viewmodel/internal/SynchronizedObject.jvm.kt
@@ -13,10 +13,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package androidx.lifecycle.viewmodel.internal
 
-internal actual class Lock actual constructor() {
-    actual inline fun <T> withLock(crossinline block: () -> T): T =
-        synchronized(lock = this, block)
-}
+internal actual class SynchronizedObject actual constructor()
+
+internal actual inline fun <T> synchronizedImpl(
+    lock: SynchronizedObject,
+    crossinline action: () -> T
+): T = kotlin.synchronized(lock, action)
diff --git a/lifecycle/lifecycle-viewmodel/src/nativeMain/kotlin/androidx/lifecycle/viewmodel/internal/Lock.native.kt b/lifecycle/lifecycle-viewmodel/src/nativeMain/kotlin/androidx/lifecycle/viewmodel/internal/SynchronizedObject.native.kt
similarity index 79%
rename from lifecycle/lifecycle-viewmodel/src/nativeMain/kotlin/androidx/lifecycle/viewmodel/internal/Lock.native.kt
rename to lifecycle/lifecycle-viewmodel/src/nativeMain/kotlin/androidx/lifecycle/viewmodel/internal/SynchronizedObject.native.kt
index b694342..e20fb64 100644
--- a/lifecycle/lifecycle-viewmodel/src/nativeMain/kotlin/androidx/lifecycle/viewmodel/internal/Lock.native.kt
+++ b/lifecycle/lifecycle-viewmodel/src/nativeMain/kotlin/androidx/lifecycle/viewmodel/internal/SynchronizedObject.native.kt
@@ -13,7 +13,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package androidx.lifecycle.viewmodel.internal
 
 import kotlin.native.internal.createCleaner
@@ -30,7 +29,6 @@
 import platform.posix.pthread_mutexattr_init
 import platform.posix.pthread_mutexattr_settype
 import platform.posix.pthread_mutexattr_t
-
 /**
  * Wrapper for platform.posix.PTHREAD_MUTEX_RECURSIVE which
  * is represented as kotlin.Int on darwin platforms and kotlin.UInt on linuxX64
@@ -38,26 +36,24 @@
  */
 internal expect val PTHREAD_MUTEX_RECURSIVE: Int
 
-internal actual class Lock actual constructor() {
+internal actual class SynchronizedObject actual constructor() {
 
     private val resource = Resource()
 
     @Suppress("unused") // The returned Cleaner must be assigned to a property
     @OptIn(ExperimentalStdlibApi::class)
-    private val cleaner = createCleaner(resource, Resource::destroy)
+    private val cleaner = createCleaner(resource, Resource::dispose)
 
-    actual inline fun <T> withLock(crossinline block: () -> T): T {
+    fun lock() {
         resource.lock()
-        return try {
-            block()
-        } finally {
-            resource.unlock()
-        }
+    }
+
+    fun unlock() {
+        resource.unlock()
     }
 
     @OptIn(ExperimentalForeignApi::class)
-    @PublishedApi
-    internal class Resource {
+    private class Resource {
         private val arena: Arena = Arena()
         private val attr: pthread_mutexattr_t = arena.alloc()
         private val mutex: pthread_mutex_t = arena.alloc()
@@ -68,17 +64,26 @@
             pthread_mutex_init(mutex.ptr, attr.ptr)
         }
 
-        @PublishedApi
-        internal fun lock(): Int = pthread_mutex_lock(mutex.ptr)
+        fun lock(): Int = pthread_mutex_lock(mutex.ptr)
 
-        @PublishedApi
-        internal fun unlock(): Int = pthread_mutex_unlock(mutex.ptr)
+        fun unlock(): Int = pthread_mutex_unlock(mutex.ptr)
 
-        @PublishedApi
-        internal fun destroy() {
+        fun dispose() {
             pthread_mutex_destroy(mutex.ptr)
             pthread_mutexattr_destroy(attr.ptr)
             arena.clear()
         }
     }
 }
+
+internal actual inline fun <T> synchronizedImpl(
+    lock: SynchronizedObject,
+    crossinline action: () -> T
+): T {
+    lock.lock()
+    return try {
+        action()
+    } finally {
+        lock.unlock()
+    }
+}
diff --git a/lint-checks/integration-tests/src/main/java/androidx/ObsoleteCompatMethodMissingMultiLineReplaceWith.java b/lint-checks/integration-tests/src/main/java/androidx/ObsoleteCompatMethodMissingMultiLineReplaceWith.java
new file mode 100644
index 0000000..1af72c9
--- /dev/null
+++ b/lint-checks/integration-tests/src/main/java/androidx/ObsoleteCompatMethodMissingMultiLineReplaceWith.java
@@ -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;
+
+public class ObsoleteCompatMethodMissingMultiLineReplaceWith {
+    private ObsoleteCompatMethodMissingMultiLineReplaceWith() {
+        // This class is non-instantiable.
+    }
+
+    /**
+     * Return the object's hash code.
+     *
+     * @param obj the object
+     * @return the hash code
+     * @deprecated Call {@link Object#hashCode()} directly.
+     */
+    @Deprecated
+    public static long hashCode(Object obj) {
+        return obj.hashCode(
+
+        );
+    }
+}
diff --git a/lint-checks/src/main/java/androidx/build/lint/ObsoleteCompatDetector.kt b/lint-checks/src/main/java/androidx/build/lint/ObsoleteCompatDetector.kt
index ef7fbcf..39652e2 100644
--- a/lint-checks/src/main/java/androidx/build/lint/ObsoleteCompatDetector.kt
+++ b/lint-checks/src/main/java/androidx/build/lint/ObsoleteCompatDetector.kt
@@ -131,7 +131,9 @@
         }
 
         if (!hasReplaceWith) {
-            val replacement = expression.javaPsi!!.text!!.replace("\"", "\\\"")
+            val replacement = expression.javaPsi!!.text!!
+                .replace("\"", "\\\"")
+                .replace(Regex("\n\\s*"), "")
             lintFix.add(
                 LintFix.create()
                     .name("Annotate with @ReplaceWith")
diff --git a/lint-checks/src/main/java/androidx/build/lint/PrereleaseSdkCoreDependencyDetector.kt b/lint-checks/src/main/java/androidx/build/lint/PrereleaseSdkCoreDependencyDetector.kt
index 470dce6..42e64c2 100644
--- a/lint-checks/src/main/java/androidx/build/lint/PrereleaseSdkCoreDependencyDetector.kt
+++ b/lint-checks/src/main/java/androidx/build/lint/PrereleaseSdkCoreDependencyDetector.kt
@@ -69,7 +69,11 @@
             val coordinates = library.resolvedCoordinates
             return coordinates.artifactId == "core" &&
                 coordinates.groupId == "androidx.core" &&
-                coordinates.version != "unspecified"
+                // The dependency is invalid if it was listed using a versioned instead of project
+                // dependency. The coordinates of a project dependency may have been resolved to the
+                // current version in the coordinates, but the identifier describing this dependency
+                // won't contain the version (it will be something like ":@@:core:core::debug").
+                (coordinates.version != "unspecified" && coordinates.version in identifier)
         }
     }
 
diff --git a/lint-checks/src/test/java/androidx/build/lint/ObsoleteCompatDetectorTest.kt b/lint-checks/src/test/java/androidx/build/lint/ObsoleteCompatDetectorTest.kt
index 2143e46b..c71313d 100644
--- a/lint-checks/src/test/java/androidx/build/lint/ObsoleteCompatDetectorTest.kt
+++ b/lint-checks/src/test/java/androidx/build/lint/ObsoleteCompatDetectorTest.kt
@@ -108,6 +108,32 @@
     }
 
     @Test
+    fun `Obsolete compat method missing multi-line @ReplaceWith`() {
+        val input = arrayOf(
+            javaSample("androidx.ObsoleteCompatMethodMissingMultiLineReplaceWith"),
+        )
+
+        /* ktlint-disable max-line-length */
+        val expected = """
+src/androidx/ObsoleteCompatMethodMissingMultiLineReplaceWith.java:32: Error: Obsolete compat method should provide replacement [ObsoleteCompatMethod]
+    public static long hashCode(Object obj) {
+                       ~~~~~~~~
+1 errors, 0 warnings
+        """.trimIndent()
+
+        val expectedAutoFix = """
+Autofix for src/androidx/ObsoleteCompatMethodMissingMultiLineReplaceWith.java line 32: Replace obsolete compat method:
+@@ -18 +18
++ import androidx.annotation.ReplaceWith;
+@@ -31 +32
++     @ReplaceWith(expression = "obj.hashCode()")
+        """.trimIndent()
+        /* ktlint-enable max-line-length */
+
+        check(*input).expect(expected).expectFixDiffs(expectedAutoFix)
+    }
+
+    @Test
     fun `Obsolete compat methods missing @Deprecated`() {
         val input = arrayOf(
             javaSample("androidx.ObsoleteCompatMethodMissingDeprecated"),
diff --git a/mediarouter/mediarouter/src/main/res/values-te/strings.xml b/mediarouter/mediarouter/src/main/res/values-te/strings.xml
index 290e656..85ae80a 100644
--- a/mediarouter/mediarouter/src/main/res/values-te/strings.xml
+++ b/mediarouter/mediarouter/src/main/res/values-te/strings.xml
@@ -27,7 +27,7 @@
     <string name="mr_chooser_looking_for_devices" msgid="4257319068277776035">"పరికరాల కోసం వెతుకుతోంది..."</string>
     <string name="mr_controller_disconnect" msgid="7812275474138309497">"డిస్‌కనెక్ట్ చేయి"</string>
     <string name="mr_controller_stop_casting" msgid="804210341192624074">"ప్రసారాన్ని ఆపివేయి"</string>
-    <string name="mr_controller_close_description" msgid="5684434439232634509">"మూసివేయి"</string>
+    <string name="mr_controller_close_description" msgid="5684434439232634509">"మూసివేయండి"</string>
     <string name="mr_controller_play" msgid="1253345086594430054">"ప్లే చేయి"</string>
     <string name="mr_controller_pause" msgid="747801650871398383">"పాజ్ చేయి"</string>
     <string name="mr_controller_stop" msgid="5497722768305745508">"ఆపు"</string>
diff --git a/navigation/navigation-common/api/current.txt b/navigation/navigation-common/api/current.txt
index 5bffb80..c6c9308 100644
--- a/navigation/navigation-common/api/current.txt
+++ b/navigation/navigation-common/api/current.txt
@@ -257,14 +257,17 @@
     ctor public NavDestinationBuilder(androidx.navigation.Navigator<? extends D> navigator, String? route);
     ctor @SuppressCompatibility @androidx.navigation.ExperimentalSafeArgsApi public NavDestinationBuilder(androidx.navigation.Navigator<? extends D> navigator, kotlin.reflect.KClass<?>? route, java.util.Map<kotlin.reflect.KType,androidx.navigation.NavType<?>> typeMap);
     method @Deprecated public final void action(int actionId, kotlin.jvm.functions.Function1<? super androidx.navigation.NavActionBuilder,kotlin.Unit> actionBuilder);
+    method public final void argument(String name, androidx.navigation.NavArgument argument);
     method public final void argument(String name, kotlin.jvm.functions.Function1<? super androidx.navigation.NavArgumentBuilder,kotlin.Unit> argumentBuilder);
     method public D build();
+    method public final void deepLink(androidx.navigation.NavDeepLink navDeepLink);
     method public final void deepLink(String uriPattern);
     method public final void deepLink(kotlin.jvm.functions.Function1<? super androidx.navigation.NavDeepLinkDslBuilder,kotlin.Unit> navDeepLink);
     method public final int getId();
     method public final CharSequence? getLabel();
     method protected final androidx.navigation.Navigator<? extends D> getNavigator();
     method public final String? getRoute();
+    method protected D instantiateDestination();
     method public final void setLabel(CharSequence?);
     property public final int id;
     property public final CharSequence? label;
diff --git a/navigation/navigation-common/api/restricted_current.txt b/navigation/navigation-common/api/restricted_current.txt
index 5bffb80..c6c9308 100644
--- a/navigation/navigation-common/api/restricted_current.txt
+++ b/navigation/navigation-common/api/restricted_current.txt
@@ -257,14 +257,17 @@
     ctor public NavDestinationBuilder(androidx.navigation.Navigator<? extends D> navigator, String? route);
     ctor @SuppressCompatibility @androidx.navigation.ExperimentalSafeArgsApi public NavDestinationBuilder(androidx.navigation.Navigator<? extends D> navigator, kotlin.reflect.KClass<?>? route, java.util.Map<kotlin.reflect.KType,androidx.navigation.NavType<?>> typeMap);
     method @Deprecated public final void action(int actionId, kotlin.jvm.functions.Function1<? super androidx.navigation.NavActionBuilder,kotlin.Unit> actionBuilder);
+    method public final void argument(String name, androidx.navigation.NavArgument argument);
     method public final void argument(String name, kotlin.jvm.functions.Function1<? super androidx.navigation.NavArgumentBuilder,kotlin.Unit> argumentBuilder);
     method public D build();
+    method public final void deepLink(androidx.navigation.NavDeepLink navDeepLink);
     method public final void deepLink(String uriPattern);
     method public final void deepLink(kotlin.jvm.functions.Function1<? super androidx.navigation.NavDeepLinkDslBuilder,kotlin.Unit> navDeepLink);
     method public final int getId();
     method public final CharSequence? getLabel();
     method protected final androidx.navigation.Navigator<? extends D> getNavigator();
     method public final String? getRoute();
+    method protected D instantiateDestination();
     method public final void setLabel(CharSequence?);
     property public final int id;
     property public final CharSequence? label;
diff --git a/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavDestinationBuilderTest.kt b/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavDestinationBuilderTest.kt
index 540df8d..860d0a9 100644
--- a/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavDestinationBuilderTest.kt
+++ b/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavDestinationBuilderTest.kt
@@ -115,6 +115,7 @@
             argument("testArg2") {
                 type = NavType.StringType
             }
+            argument("testArg3", NavArgument.Builder().setDefaultValue("123").build())
         }
         assertWithMessage("NavDestination should have default arguments set")
             .that(destination.arguments.get("testArg")?.defaultValue)
@@ -122,6 +123,9 @@
         assertWithMessage("NavArgument shouldn't have a default value")
             .that(destination.arguments.get("testArg2")?.isDefaultValuePresent)
             .isFalse()
+        assertWithMessage("NavDestination should have implicit default arguments set")
+            .that(destination.arguments.get("testArg3")?.defaultValue)
+            .isEqualTo("123")
     }
 
     @Test
diff --git a/navigation/navigation-common/src/main/java/androidx/navigation/NavDestinationBuilder.kt b/navigation/navigation-common/src/main/java/androidx/navigation/NavDestinationBuilder.kt
index ab06664..0ef8b28 100644
--- a/navigation/navigation-common/src/main/java/androidx/navigation/NavDestinationBuilder.kt
+++ b/navigation/navigation-common/src/main/java/androidx/navigation/NavDestinationBuilder.kt
@@ -34,7 +34,8 @@
 @NavDestinationDsl
 public open class NavDestinationBuilder<out D : NavDestination> internal constructor(
     /**
-     * The navigator the destination was created from
+     * The navigator the destination that will be used in [instantiateDestination]
+     * to create the destination.
      */
     protected val navigator: Navigator<out D>,
     /**
@@ -121,6 +122,14 @@
         arguments[name] = NavArgumentBuilder().apply(argumentBuilder).build()
     }
 
+    /**
+     * Add a [NavArgument] to this destination.
+     */
+    @Suppress("BuilderSetStyle")
+    public fun argument(name: String, argument: NavArgument) {
+        arguments[name] = argument
+    }
+
     private var deepLinks = mutableListOf<NavDeepLink>()
 
     /**
@@ -166,6 +175,28 @@
         deepLinks.add(NavDeepLinkDslBuilder().apply(navDeepLink).build())
     }
 
+    /**
+     * Add a deep link to this destination.
+     *
+     * In addition to a direct Uri match, the following features are supported:
+     *
+     * *    Uris without a scheme are assumed as http and https. For example,
+     *      `www.example.com` will match `http://www.example.com` and
+     *      `https://www.example.com`.
+     * *    Placeholders in the form of `{placeholder_name}` matches 1 or more
+     *      characters. The String value of the placeholder will be available in the arguments
+     *      [Bundle] with a key of the same name. For example,
+     *      `http://www.example.com/users/{id}` will match
+     *      `http://www.example.com/users/4`.
+     * *    The `.*` wildcard can be used to match 0 or more characters.
+     *
+     * @param navDeepLink the NavDeepLink to be added to this destination
+     */
+    @Suppress("BuilderSetStyle")
+    public fun deepLink(navDeepLink: NavDeepLink) {
+        deepLinks.add(navDeepLink)
+    }
+
     private var actions = mutableMapOf<Int, NavAction>()
 
     /**
@@ -180,10 +211,19 @@
     }
 
     /**
+     * Instantiate a new instance of [D] that will be passed to [build].
+     *
+     * By default, this calls [Navigator.createDestination] on [navigator], but can
+     * be overridden to call a custom constructor, etc.
+     */
+    @Suppress("BuilderSetStyle")
+    protected open fun instantiateDestination(): D = navigator.createDestination()
+
+    /**
      * Build the NavDestination by calling [Navigator.createDestination].
      */
     public open fun build(): D {
-        return navigator.createDestination().also { destination ->
+        return instantiateDestination().also { destination ->
             destination.label = label
             arguments.forEach { (name, argument) ->
                 destination.addArgument(name, argument)
diff --git a/navigation/navigation-compose/api/current.txt b/navigation/navigation-compose/api/current.txt
index fb10176..64b8e18 100644
--- a/navigation/navigation-compose/api/current.txt
+++ b/navigation/navigation-compose/api/current.txt
@@ -15,6 +15,27 @@
     ctor public ComposeNavigator.Destination(androidx.navigation.compose.ComposeNavigator navigator, kotlin.jvm.functions.Function2<? super androidx.compose.animation.AnimatedContentScope,androidx.navigation.NavBackStackEntry,kotlin.Unit> content);
   }
 
+  @androidx.navigation.NavDestinationDsl public final class ComposeNavigatorDestinationBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.compose.ComposeNavigator.Destination> {
+    ctor public ComposeNavigatorDestinationBuilder(androidx.navigation.compose.ComposeNavigator navigator, String route, kotlin.jvm.functions.Function2<? super androidx.compose.animation.AnimatedContentScope,? super androidx.navigation.NavBackStackEntry,kotlin.Unit> content);
+    method public androidx.navigation.compose.ComposeNavigator.Destination build();
+    method public kotlin.jvm.functions.Function1<androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,androidx.compose.animation.EnterTransition?>? getEnterTransition();
+    method public kotlin.jvm.functions.Function1<androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,androidx.compose.animation.ExitTransition?>? getExitTransition();
+    method public kotlin.jvm.functions.Function1<androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,androidx.compose.animation.EnterTransition?>? getPopEnterTransition();
+    method public kotlin.jvm.functions.Function1<androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,androidx.compose.animation.ExitTransition?>? getPopExitTransition();
+    method public kotlin.jvm.functions.Function1<androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,androidx.compose.animation.SizeTransform?>? getSizeTransform();
+    method protected androidx.navigation.compose.ComposeNavigator.Destination instantiateDestination();
+    method public void setEnterTransition(kotlin.jvm.functions.Function1<androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,androidx.compose.animation.EnterTransition?>?);
+    method public void setExitTransition(kotlin.jvm.functions.Function1<androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,androidx.compose.animation.ExitTransition?>?);
+    method public void setPopEnterTransition(kotlin.jvm.functions.Function1<androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,androidx.compose.animation.EnterTransition?>?);
+    method public void setPopExitTransition(kotlin.jvm.functions.Function1<androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,androidx.compose.animation.ExitTransition?>?);
+    method public void setSizeTransform(kotlin.jvm.functions.Function1<androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,androidx.compose.animation.SizeTransform?>?);
+    property public final kotlin.jvm.functions.Function1<androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,androidx.compose.animation.EnterTransition?>? enterTransition;
+    property public final kotlin.jvm.functions.Function1<androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,androidx.compose.animation.ExitTransition?>? exitTransition;
+    property public final kotlin.jvm.functions.Function1<androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,androidx.compose.animation.EnterTransition?>? popEnterTransition;
+    property public final kotlin.jvm.functions.Function1<androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,androidx.compose.animation.ExitTransition?>? popExitTransition;
+    property public final kotlin.jvm.functions.Function1<androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,androidx.compose.animation.SizeTransform?>? sizeTransform;
+  }
+
   public final class DialogHostKt {
     method @androidx.compose.runtime.Composable public static void DialogHost(androidx.navigation.compose.DialogNavigator dialogNavigator);
   }
@@ -28,6 +49,11 @@
     ctor public DialogNavigator.Destination(androidx.navigation.compose.DialogNavigator navigator, optional androidx.compose.ui.window.DialogProperties dialogProperties, kotlin.jvm.functions.Function1<? super androidx.navigation.NavBackStackEntry,kotlin.Unit> content);
   }
 
+  @androidx.navigation.NavDestinationDsl public final class DialogNavigatorDestinationBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.compose.DialogNavigator.Destination> {
+    ctor public DialogNavigatorDestinationBuilder(androidx.navigation.compose.DialogNavigator navigator, String route, androidx.compose.ui.window.DialogProperties dialogProperties, kotlin.jvm.functions.Function1<? super androidx.navigation.NavBackStackEntry,kotlin.Unit> content);
+    method protected androidx.navigation.compose.DialogNavigator.Destination instantiateDestination();
+  }
+
   public final class NavBackStackEntryProviderKt {
     method @androidx.compose.runtime.Composable public static void LocalOwnersProvider(androidx.navigation.NavBackStackEntry, androidx.compose.runtime.saveable.SaveableStateHolder saveableStateHolder, kotlin.jvm.functions.Function0<kotlin.Unit> content);
   }
diff --git a/navigation/navigation-compose/api/restricted_current.txt b/navigation/navigation-compose/api/restricted_current.txt
index fb10176..64b8e18 100644
--- a/navigation/navigation-compose/api/restricted_current.txt
+++ b/navigation/navigation-compose/api/restricted_current.txt
@@ -15,6 +15,27 @@
     ctor public ComposeNavigator.Destination(androidx.navigation.compose.ComposeNavigator navigator, kotlin.jvm.functions.Function2<? super androidx.compose.animation.AnimatedContentScope,androidx.navigation.NavBackStackEntry,kotlin.Unit> content);
   }
 
+  @androidx.navigation.NavDestinationDsl public final class ComposeNavigatorDestinationBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.compose.ComposeNavigator.Destination> {
+    ctor public ComposeNavigatorDestinationBuilder(androidx.navigation.compose.ComposeNavigator navigator, String route, kotlin.jvm.functions.Function2<? super androidx.compose.animation.AnimatedContentScope,? super androidx.navigation.NavBackStackEntry,kotlin.Unit> content);
+    method public androidx.navigation.compose.ComposeNavigator.Destination build();
+    method public kotlin.jvm.functions.Function1<androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,androidx.compose.animation.EnterTransition?>? getEnterTransition();
+    method public kotlin.jvm.functions.Function1<androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,androidx.compose.animation.ExitTransition?>? getExitTransition();
+    method public kotlin.jvm.functions.Function1<androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,androidx.compose.animation.EnterTransition?>? getPopEnterTransition();
+    method public kotlin.jvm.functions.Function1<androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,androidx.compose.animation.ExitTransition?>? getPopExitTransition();
+    method public kotlin.jvm.functions.Function1<androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,androidx.compose.animation.SizeTransform?>? getSizeTransform();
+    method protected androidx.navigation.compose.ComposeNavigator.Destination instantiateDestination();
+    method public void setEnterTransition(kotlin.jvm.functions.Function1<androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,androidx.compose.animation.EnterTransition?>?);
+    method public void setExitTransition(kotlin.jvm.functions.Function1<androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,androidx.compose.animation.ExitTransition?>?);
+    method public void setPopEnterTransition(kotlin.jvm.functions.Function1<androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,androidx.compose.animation.EnterTransition?>?);
+    method public void setPopExitTransition(kotlin.jvm.functions.Function1<androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,androidx.compose.animation.ExitTransition?>?);
+    method public void setSizeTransform(kotlin.jvm.functions.Function1<androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,androidx.compose.animation.SizeTransform?>?);
+    property public final kotlin.jvm.functions.Function1<androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,androidx.compose.animation.EnterTransition?>? enterTransition;
+    property public final kotlin.jvm.functions.Function1<androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,androidx.compose.animation.ExitTransition?>? exitTransition;
+    property public final kotlin.jvm.functions.Function1<androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,androidx.compose.animation.EnterTransition?>? popEnterTransition;
+    property public final kotlin.jvm.functions.Function1<androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,androidx.compose.animation.ExitTransition?>? popExitTransition;
+    property public final kotlin.jvm.functions.Function1<androidx.compose.animation.AnimatedContentTransitionScope<androidx.navigation.NavBackStackEntry>,androidx.compose.animation.SizeTransform?>? sizeTransform;
+  }
+
   public final class DialogHostKt {
     method @androidx.compose.runtime.Composable public static void DialogHost(androidx.navigation.compose.DialogNavigator dialogNavigator);
   }
@@ -28,6 +49,11 @@
     ctor public DialogNavigator.Destination(androidx.navigation.compose.DialogNavigator navigator, optional androidx.compose.ui.window.DialogProperties dialogProperties, kotlin.jvm.functions.Function1<? super androidx.navigation.NavBackStackEntry,kotlin.Unit> content);
   }
 
+  @androidx.navigation.NavDestinationDsl public final class DialogNavigatorDestinationBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.compose.DialogNavigator.Destination> {
+    ctor public DialogNavigatorDestinationBuilder(androidx.navigation.compose.DialogNavigator navigator, String route, androidx.compose.ui.window.DialogProperties dialogProperties, kotlin.jvm.functions.Function1<? super androidx.navigation.NavBackStackEntry,kotlin.Unit> content);
+    method protected androidx.navigation.compose.DialogNavigator.Destination instantiateDestination();
+  }
+
   public final class NavBackStackEntryProviderKt {
     method @androidx.compose.runtime.Composable public static void LocalOwnersProvider(androidx.navigation.NavBackStackEntry, androidx.compose.runtime.saveable.SaveableStateHolder saveableStateHolder, kotlin.jvm.functions.Function0<kotlin.Unit> content);
   }
diff --git a/navigation/navigation-compose/src/main/java/androidx/navigation/compose/ComposeNavigatorDestinationBuilder.kt b/navigation/navigation-compose/src/main/java/androidx/navigation/compose/ComposeNavigatorDestinationBuilder.kt
new file mode 100644
index 0000000..af2b21b
--- /dev/null
+++ b/navigation/navigation-compose/src/main/java/androidx/navigation/compose/ComposeNavigatorDestinationBuilder.kt
@@ -0,0 +1,83 @@
+/*
+ * 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.navigation.compose
+
+import androidx.compose.animation.AnimatedContentScope
+import androidx.compose.animation.AnimatedContentTransitionScope
+import androidx.compose.animation.EnterTransition
+import androidx.compose.animation.ExitTransition
+import androidx.compose.animation.SizeTransform
+import androidx.compose.runtime.Composable
+import androidx.navigation.NavBackStackEntry
+import androidx.navigation.NavDestinationBuilder
+import androidx.navigation.NavDestinationDsl
+
+/**
+ * DSL for constructing a new [ComposeNavigator.Destination]
+ */
+@NavDestinationDsl
+public class ComposeNavigatorDestinationBuilder :
+    NavDestinationBuilder<ComposeNavigator.Destination> {
+
+    private val composeNavigator: ComposeNavigator
+    private val content: @Composable (AnimatedContentScope.(NavBackStackEntry) -> Unit)
+
+    var enterTransition: (@JvmSuppressWildcards
+    AnimatedContentTransitionScope<NavBackStackEntry>.() -> EnterTransition?)? = null
+
+    var exitTransition: (@JvmSuppressWildcards
+    AnimatedContentTransitionScope<NavBackStackEntry>.() -> ExitTransition?)? = null
+
+    var popEnterTransition: (@JvmSuppressWildcards
+    AnimatedContentTransitionScope<NavBackStackEntry>.() -> EnterTransition?)? = null
+
+    var popExitTransition: (@JvmSuppressWildcards
+    AnimatedContentTransitionScope<NavBackStackEntry>.() -> ExitTransition?)? = null
+
+    var sizeTransform: (@JvmSuppressWildcards
+    AnimatedContentTransitionScope<NavBackStackEntry>.() -> SizeTransform?)? = null
+
+    /**
+     * DSL for constructing a new [ComposeNavigator.Destination]
+     *
+     * @param navigator navigator used to create the destination
+     * @param route the destination's unique route
+     * @param content composable for the destination
+     */
+    public constructor(
+        navigator: ComposeNavigator,
+        route: String,
+        content: @Composable AnimatedContentScope.(NavBackStackEntry) -> Unit
+    ) : super(navigator, route) {
+        this.composeNavigator = navigator
+        this.content = content
+    }
+
+    override fun instantiateDestination(): ComposeNavigator.Destination {
+        return ComposeNavigator.Destination(composeNavigator, content)
+    }
+
+    override fun build(): ComposeNavigator.Destination {
+        return super.build().also { destination ->
+            destination.enterTransition = enterTransition
+            destination.exitTransition = exitTransition
+            destination.popEnterTransition = popEnterTransition
+            destination.popExitTransition = popExitTransition
+            destination.sizeTransform = sizeTransform
+        }
+    }
+}
diff --git a/navigation/navigation-compose/src/main/java/androidx/navigation/compose/DialogNavigatorDestinationBuilder.kt b/navigation/navigation-compose/src/main/java/androidx/navigation/compose/DialogNavigatorDestinationBuilder.kt
new file mode 100644
index 0000000..d98e377
--- /dev/null
+++ b/navigation/navigation-compose/src/main/java/androidx/navigation/compose/DialogNavigatorDestinationBuilder.kt
@@ -0,0 +1,59 @@
+/*
+ * 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.navigation.compose
+
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.window.DialogProperties
+import androidx.navigation.NavBackStackEntry
+import androidx.navigation.NavDestinationBuilder
+import androidx.navigation.NavDestinationDsl
+
+/**
+ * DSL for constructing a new [DialogNavigator.Destination]
+ */
+@NavDestinationDsl
+public class DialogNavigatorDestinationBuilder :
+    NavDestinationBuilder<DialogNavigator.Destination> {
+
+    private val dialogNavigator: DialogNavigator
+    private val dialogProperties: DialogProperties
+    private val content: @Composable (NavBackStackEntry) -> Unit
+
+    /**
+     * DSL for constructing a new [DialogNavigator.Destination]
+     *
+     * @param navigator navigator used to create the destination
+     * @param route the destination's unique route
+     * @param dialogProperties properties that should be passed to
+     * [androidx.compose.ui.window.Dialog].
+     * @param content composable for the destination
+     */
+    public constructor(
+        navigator: DialogNavigator,
+        route: String,
+        dialogProperties: DialogProperties,
+        content: @Composable (NavBackStackEntry) -> Unit
+    ) : super(navigator, route) {
+        this.dialogNavigator = navigator
+        this.dialogProperties = dialogProperties
+        this.content = content
+    }
+
+    override fun instantiateDestination(): DialogNavigator.Destination {
+        return DialogNavigator.Destination(dialogNavigator, dialogProperties, content)
+    }
+}
diff --git a/navigation/navigation-compose/src/main/java/androidx/navigation/compose/NavGraphBuilder.kt b/navigation/navigation-compose/src/main/java/androidx/navigation/compose/NavGraphBuilder.kt
index cf5a320..08f2da3 100644
--- a/navigation/navigation-compose/src/main/java/androidx/navigation/compose/NavGraphBuilder.kt
+++ b/navigation/navigation-compose/src/main/java/androidx/navigation/compose/NavGraphBuilder.kt
@@ -96,17 +96,17 @@
             exitTransition,
     content: @Composable AnimatedContentScope.(NavBackStackEntry) -> Unit
 ) {
-    addDestination(
-        ComposeNavigator.Destination(
+    destination(
+        ComposeNavigatorDestinationBuilder(
             provider[ComposeNavigator::class],
+            route,
             content
         ).apply {
-            this.route = route
             arguments.forEach { (argumentName, argument) ->
-                addArgument(argumentName, argument)
+                argument(argumentName, argument)
             }
             deepLinks.forEach { deepLink ->
-                addDeepLink(deepLink)
+                deepLink(deepLink)
             }
             this.enterTransition = enterTransition
             this.exitTransition = exitTransition
@@ -147,17 +147,17 @@
     AnimatedContentTransitionScope<NavBackStackEntry>.() -> SizeTransform?)? = null,
     content: @Composable AnimatedContentScope.(NavBackStackEntry) -> Unit
 ) {
-    addDestination(
-        ComposeNavigator.Destination(
+    destination(
+        ComposeNavigatorDestinationBuilder(
             provider[ComposeNavigator::class],
+            route,
             content
         ).apply {
-            this.route = route
             arguments.forEach { (argumentName, argument) ->
-                addArgument(argumentName, argument)
+                argument(argumentName, argument)
             }
             deepLinks.forEach { deepLink ->
-                addDeepLink(deepLink)
+                deepLink(deepLink)
             }
             this.enterTransition = enterTransition
             this.exitTransition = exitTransition
@@ -313,18 +313,18 @@
     dialogProperties: DialogProperties = DialogProperties(),
     content: @Composable (NavBackStackEntry) -> Unit
 ) {
-    addDestination(
-        DialogNavigator.Destination(
+    destination(
+        DialogNavigatorDestinationBuilder(
             provider[DialogNavigator::class],
+            route,
             dialogProperties,
             content
         ).apply {
-            this.route = route
             arguments.forEach { (argumentName, argument) ->
-                addArgument(argumentName, argument)
+                argument(argumentName, argument)
             }
             deepLinks.forEach { deepLink ->
-                addDeepLink(deepLink)
+                deepLink(deepLink)
             }
         }
     )
diff --git a/preference/preference/res/values-ar/strings.xml b/preference/preference/res/values-ar/strings.xml
index c1f2e6c..2b35f9f 100644
--- a/preference/preference/res/values-ar/strings.xml
+++ b/preference/preference/res/values-ar/strings.xml
@@ -2,7 +2,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="v7_preference_on" msgid="89551595707643515">"مفعّلة"</string>
-    <string name="v7_preference_off" msgid="3140233346420563315">"إيقاف"</string>
+    <string name="v7_preference_off" msgid="3140233346420563315">"غير مفعّل"</string>
     <string name="expand_button_title" msgid="2427401033573778270">"إعدادات متقدمة"</string>
     <string name="summary_collapsed_preference_list" msgid="9167775378838880170">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>، <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
     <string name="copy" msgid="6083905920877235314">"نسخ"</string>
diff --git a/privacysandbox/activity/activity-core/src/main/java/androidx/privacysandbox/activity/core/SdkActivityLauncher.kt b/privacysandbox/activity/activity-core/src/main/java/androidx/privacysandbox/activity/core/SdkActivityLauncher.kt
index 8fe6567..9b3f4da 100644
--- a/privacysandbox/activity/activity-core/src/main/java/androidx/privacysandbox/activity/core/SdkActivityLauncher.kt
+++ b/privacysandbox/activity/activity-core/src/main/java/androidx/privacysandbox/activity/core/SdkActivityLauncher.kt
@@ -30,16 +30,18 @@
  * and send the resulting bundle.
  *
  * SDKs can create launchers from an app-provided bundle by calling
- * [createFromLauncherInfo][androidx.privacysandbox.activity.provider.SdkActivityLauncherFactory.createFromLauncherInfo].
+ * [fromLauncherInfo][androidx.privacysandbox.activity.provider.SdkActivityLauncherFactory.fromLauncherInfo].
  */
 interface SdkActivityLauncher {
 
     /**
-     * Tries to launch a new SDK activity using the given [sdkActivityHandlerToken],
-     * assumed to be registered in the [SdkSandboxControllerCompat][androidx.privacysandbox.sdkruntime.core.controller.SdkSandboxControllerCompat].
+     * Tries to launch a new SDK activity using the given [sdkActivityHandlerToken].
      *
      * Returns true if the SDK activity intent was sent, false if the launch was rejected for any
      * reason.
+     *
+     * A valid [sdkActivityHandlerToken] can be obtained by registering an SDK activity with
+     * [registerSdkSandboxActivityHandler][androidx.privacysandbox.sdkruntime.core.controller.SdkSandboxControllerCompat.registerSdkSandboxActivityHandler].
      */
     suspend fun launchSdkActivity(sdkActivityHandlerToken: IBinder): Boolean
 }
diff --git a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/LegacyIdentityHashTest.java b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/LegacyIdentityHashTest.java
new file mode 100644
index 0000000..ed0eee1
--- /dev/null
+++ b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/LegacyIdentityHashTest.java
@@ -0,0 +1,82 @@
+/*
+ * 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.room.integration.testapp.test;
+
+import android.content.Context;
+
+import androidx.room.Database;
+import androidx.room.Entity;
+import androidx.room.PrimaryKey;
+import androidx.room.Room;
+import androidx.room.RoomDatabase;
+import androidx.room.RoomMasterTable;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class LegacyIdentityHashTest {
+
+    private Context mTargetContext =
+            InstrumentationRegistry.getInstrumentation().getTargetContext();
+    private String mDatabaseName = "legacy-test.db";
+
+    @Before
+    public void setup() {
+        mTargetContext.deleteDatabase(mDatabaseName);
+    }
+
+    @After
+    public void teardown() {
+        mTargetContext.deleteDatabase(mDatabaseName);
+    }
+
+    @Test
+    public void openDatabaseWithLegacyHash() {
+        RoomDatabase.Builder<LegacyDatabase> dbBuilder = Room.databaseBuilder(
+                InstrumentationRegistry.getInstrumentation().getTargetContext(),
+                LegacyDatabase.class,
+                "legacy-test.db"
+        );
+
+        LegacyDatabase newDb = dbBuilder.build();
+        String insertQuery =
+                RoomMasterTable.createInsertQuery("d5249b2a35eb34d6c54d25ca1b7b9b74");
+        newDb.getOpenHelper().getWritableDatabase().execSQL(insertQuery);
+        newDb.close();
+
+        LegacyDatabase legacyDb = dbBuilder.build();
+        legacyDb.getOpenHelper().getWritableDatabase(); // force open db
+        legacyDb.close();
+    }
+
+    @Database(entities = TestDataEntity.class, version = 1, exportSchema = false)
+    abstract static class LegacyDatabase extends RoomDatabase {
+
+    }
+
+    @Entity
+    static class TestDataEntity {
+        @PrimaryKey @SuppressWarnings("unused") Long mId;
+    }
+}
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeElementTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeElementTest.kt
index 3c223df..4b190b5 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeElementTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeElementTest.kt
@@ -741,8 +741,11 @@
         val src = Source.kotlin(
             "Foo.kt",
             """
+            annotation class MyAnnotation
             interface MyInterface {
-                var x:Int
+                var x: Int
+                var y: Int
+                  @MyAnnotation get
             }
             """.trimIndent()
         )
@@ -755,6 +758,14 @@
             element.getMethodByJvmName("setX").let {
                 assertThat(it.isAbstract()).isTrue()
             }
+            element.getMethodByJvmName("getY").let {
+                if (!isPreCompiled && invocation.isKsp) {
+                  // The modifier set is empty for both the property and accessor
+                  assertThat(it.isAbstract()).isFalse()
+                } else {
+                  assertThat(it.isAbstract()).isTrue()
+                }
+            }
         }
     }
 
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/writer/OpenDelegateWriter.kt b/room/room-compiler/src/main/kotlin/androidx/room/writer/OpenDelegateWriter.kt
index fa8d172..c7d43dd 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/writer/OpenDelegateWriter.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/writer/OpenDelegateWriter.kt
@@ -55,7 +55,11 @@
 
     private fun createOpenDelegate(scope: CodeGenScope): XTypeSpec {
         return XTypeSpec.anonymousClassBuilder(
-            scope.language, "%L, %S", database.version, database.identityHash
+            scope.language,
+            "%L, %S, %S",
+            database.version,
+            database.identityHash,
+            database.legacyIdentityHash
         ).apply {
             superclass(RoomTypeNames.ROOM_OPEN_DELEGATE)
             addFunction(createCreateAllTables(scope))
diff --git a/room/room-compiler/src/test/test-data/databasewriter/output/ComplexDatabase.java b/room/room-compiler/src/test/test-data/databasewriter/output/ComplexDatabase.java
index 5daa9b8..a15107e 100644
--- a/room/room-compiler/src/test/test-data/databasewriter/output/ComplexDatabase.java
+++ b/room/room-compiler/src/test/test-data/databasewriter/output/ComplexDatabase.java
@@ -30,7 +30,7 @@
     @Override
     @NonNull
     protected RoomOpenDelegate createOpenDelegate() {
-        final RoomOpenDelegate _openDelegate = new RoomOpenDelegate(1923, "12b646c55443feeefb567521e2bece85") {
+        final RoomOpenDelegate _openDelegate = new RoomOpenDelegate(1923, "12b646c55443feeefb567521e2bece85", "2f1dbf49584f5d6c91cb44f8a6ecfee2") {
             @Override
             public void createAllTables(@NonNull final SQLiteConnection connection) {
                 SQLiteKt.execSQL(connection, "CREATE TABLE IF NOT EXISTS `User` (`uid` INTEGER NOT NULL, `name` TEXT, `lastName` TEXT, `ageColumn` INTEGER NOT NULL, PRIMARY KEY(`uid`))");
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/database_internalVisibility.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/database_internalVisibility.kt
index fdf7b86..3febf79 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/database_internalVisibility.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/database_internalVisibility.kt
@@ -33,7 +33,7 @@
 
   protected override fun createOpenDelegate(): RoomOpenDelegate {
     val _openDelegate: RoomOpenDelegate = object : RoomOpenDelegate(1,
-        "195d7974660177325bd1a32d2c7b8b8c") {
+        "195d7974660177325bd1a32d2c7b8b8c", "7458a901120796c5bbc554e2fefd262f") {
       public override fun createAllTables(connection: SQLiteConnection) {
         connection.execSQL("CREATE TABLE IF NOT EXISTS `MyEntity` (`pk` INTEGER NOT NULL, PRIMARY KEY(`pk`))")
         connection.execSQL("CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)")
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/database_simple.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/database_simple.kt
index 3bfeeb8..ead51a6 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/database_simple.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/database_simple.kt
@@ -33,7 +33,7 @@
 
   protected override fun createOpenDelegate(): RoomOpenDelegate {
     val _openDelegate: RoomOpenDelegate = object : RoomOpenDelegate(1,
-        "195d7974660177325bd1a32d2c7b8b8c") {
+        "195d7974660177325bd1a32d2c7b8b8c", "7458a901120796c5bbc554e2fefd262f") {
       public override fun createAllTables(connection: SQLiteConnection) {
         connection.execSQL("CREATE TABLE IF NOT EXISTS `MyEntity` (`pk` INTEGER NOT NULL, PRIMARY KEY(`pk`))")
         connection.execSQL("CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)")
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/database_withFtsAndView.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/database_withFtsAndView.kt
index cf6ffd19..092892d 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/database_withFtsAndView.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/database_withFtsAndView.kt
@@ -37,7 +37,7 @@
 
   protected override fun createOpenDelegate(): RoomOpenDelegate {
     val _openDelegate: RoomOpenDelegate = object : RoomOpenDelegate(1,
-        "89ba16fb8b062b50acf0eb06c853efcb") {
+        "89ba16fb8b062b50acf0eb06c853efcb", "8a71a68e07bdd62aa8c8324d870cf804") {
       public override fun createAllTables(connection: SQLiteConnection) {
         connection.execSQL("CREATE TABLE IF NOT EXISTS `MyParentEntity` (`parentKey` INTEGER NOT NULL, PRIMARY KEY(`parentKey`))")
         connection.execSQL("CREATE TABLE IF NOT EXISTS `MyEntity` (`pk` INTEGER NOT NULL, `indexedCol` TEXT NOT NULL, PRIMARY KEY(`pk`), FOREIGN KEY(`indexedCol`) REFERENCES `MyParentEntity`(`parentKey`) ON UPDATE NO ACTION ON DELETE CASCADE )")
diff --git a/room/room-runtime/src/androidInstrumentedTest/kotlin/androidx/room/CoroutineRoomCancellationTest.kt b/room/room-runtime/src/androidInstrumentedTest/kotlin/androidx/room/CoroutineRoomCancellationTest.kt
index 19995f7..0d8cebe 100644
--- a/room/room-runtime/src/androidInstrumentedTest/kotlin/androidx/room/CoroutineRoomCancellationTest.kt
+++ b/room/room-runtime/src/androidInstrumentedTest/kotlin/androidx/room/CoroutineRoomCancellationTest.kt
@@ -197,7 +197,7 @@
     private class TestDatabase : RoomDatabase() {
 
         override fun createOpenDelegate(): RoomOpenDelegate {
-            return object : RoomOpenDelegate(1, "") {
+            return object : RoomOpenDelegate(1, "", "") {
                 override fun onCreate(connection: SQLiteConnection) {}
                 override fun onPreMigrate(connection: SQLiteConnection) {}
                 override fun onValidateSchema(connection: SQLiteConnection): ValidationResult {
diff --git a/room/room-runtime/src/androidMain/kotlin/androidx/room/RoomConnectionManager.android.kt b/room/room-runtime/src/androidMain/kotlin/androidx/room/RoomConnectionManager.android.kt
index 1e6b4ec..e8f7d67 100644
--- a/room/room-runtime/src/androidMain/kotlin/androidx/room/RoomConnectionManager.android.kt
+++ b/room/room-runtime/src/androidMain/kotlin/androidx/room/RoomConnectionManager.android.kt
@@ -164,7 +164,7 @@
      * A no op implementation of [RoomOpenDelegate] used in compatibility mode with old gen code
      * that relies on [RoomOpenHelper].
      */
-    private class NoOpOpenDelegate : RoomOpenDelegate(-1, "") {
+    private class NoOpOpenDelegate : RoomOpenDelegate(-1, "", "") {
         override fun onCreate(connection: SQLiteConnection) {
             error("NOP delegate should never be called")
         }
diff --git a/room/room-runtime/src/androidUnitTest/kotlin/androidx/room/InvalidationTrackerTest.kt b/room/room-runtime/src/androidUnitTest/kotlin/androidx/room/InvalidationTrackerTest.kt
index f3f192c..4fbcdc5 100644
--- a/room/room-runtime/src/androidUnitTest/kotlin/androidx/room/InvalidationTrackerTest.kt
+++ b/room/room-runtime/src/androidUnitTest/kotlin/androidx/room/InvalidationTrackerTest.kt
@@ -564,7 +564,7 @@
         }
 
         override fun createOpenDelegate(): RoomOpenDelegateMarker {
-            return object : RoomOpenDelegate(0, "") {
+            return object : RoomOpenDelegate(0, "", "") {
                 override fun onCreate(connection: SQLiteConnection) {}
                 override fun onPreMigrate(connection: SQLiteConnection) {}
                 override fun onValidateSchema(connection: SQLiteConnection) =
diff --git a/room/room-runtime/src/commonMain/kotlin/androidx/room/RoomConnectionManager.kt b/room/room-runtime/src/commonMain/kotlin/androidx/room/RoomConnectionManager.kt
index e8d3c30..8191c55 100644
--- a/room/room-runtime/src/commonMain/kotlin/androidx/room/RoomConnectionManager.kt
+++ b/room/room-runtime/src/commonMain/kotlin/androidx/room/RoomConnectionManager.kt
@@ -194,8 +194,10 @@
                     null
                 }
             }
-
-            if (openDelegate.identityHash != identityHash) {
+            if (
+                openDelegate.identityHash != identityHash &&
+                openDelegate.legacyIdentityHash != identityHash
+            ) {
                 error(
                     "Room cannot verify the data integrity. Looks like" +
                         " you've changed schema but forgot to update the version number. You can" +
diff --git a/room/room-runtime/src/commonMain/kotlin/androidx/room/RoomOpenDelegate.kt b/room/room-runtime/src/commonMain/kotlin/androidx/room/RoomOpenDelegate.kt
index 9211d50..62ac8db 100644
--- a/room/room-runtime/src/commonMain/kotlin/androidx/room/RoomOpenDelegate.kt
+++ b/room/room-runtime/src/commonMain/kotlin/androidx/room/RoomOpenDelegate.kt
@@ -33,6 +33,7 @@
 abstract class RoomOpenDelegate(
     val version: Int,
     val identityHash: String,
+    val legacyIdentityHash: String
 ) : RoomOpenDelegateMarker {
     abstract fun onCreate(connection: SQLiteConnection)
     abstract fun onPreMigrate(connection: SQLiteConnection)
diff --git a/room/room-runtime/src/nativeTest/kotlin/androidx.room/BuilderTest_TestDatabase_Impl.kt b/room/room-runtime/src/nativeTest/kotlin/androidx.room/BuilderTest_TestDatabase_Impl.kt
index 9d3f9c2..228e10d 100644
--- a/room/room-runtime/src/nativeTest/kotlin/androidx.room/BuilderTest_TestDatabase_Impl.kt
+++ b/room/room-runtime/src/nativeTest/kotlin/androidx.room/BuilderTest_TestDatabase_Impl.kt
@@ -23,7 +23,7 @@
 
 internal class BuilderTest_TestDatabase_Impl : BuilderTest.TestDatabase() {
     override fun createOpenDelegate(): RoomOpenDelegateMarker {
-        return object : RoomOpenDelegate(0, "") {
+        return object : RoomOpenDelegate(0, "", "") {
             override fun onCreate(connection: SQLiteConnection) { }
             override fun onPreMigrate(connection: SQLiteConnection) { }
             override fun onValidateSchema(connection: SQLiteConnection): ValidationResult {
diff --git a/room/room-testing/src/commonMain/kotlin/androidx/room/testing/MigrationTestHelper.kt b/room/room-testing/src/commonMain/kotlin/androidx/room/testing/MigrationTestHelper.kt
index 64ccb0d..c13e68f 100644
--- a/room/room-testing/src/commonMain/kotlin/androidx/room/testing/MigrationTestHelper.kt
+++ b/room/room-testing/src/commonMain/kotlin/androidx/room/testing/MigrationTestHelper.kt
@@ -224,7 +224,11 @@
 
 private sealed class TestOpenDelegate(
     databaseBundle: DatabaseBundle
-) : RoomOpenDelegate(databaseBundle.version, databaseBundle.identityHash) {
+) : RoomOpenDelegate(
+    version = databaseBundle.version,
+    identityHash = databaseBundle.identityHash,
+    legacyIdentityHash = databaseBundle.identityHash
+) {
     override fun onCreate(connection: SQLiteConnection) {}
     override fun onPreMigrate(connection: SQLiteConnection) {}
     override fun onPostMigrate(connection: SQLiteConnection) {}
diff --git a/slice/slice-view/src/main/res/values-ky/strings.xml b/slice/slice-view/src/main/res/values-ky/strings.xml
index f3b7450..3de3fc3 100644
--- a/slice/slice-view/src/main/res/values-ky/strings.xml
+++ b/slice/slice-view/src/main/res/values-ky/strings.xml
@@ -20,7 +20,7 @@
     <string name="abc_slice_more_content" msgid="7841223363798860154">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="4299234410808450900">"Дагы"</string>
     <string name="abc_slice_show_more" msgid="1112789899890391107">"Дагы көрсөтүү"</string>
-    <string name="abc_slice_updated" msgid="7932359091871934205">"<xliff:g id="TIME">%1$s</xliff:g> жаңыртылды"</string>
+    <string name="abc_slice_updated" msgid="7932359091871934205">"<xliff:g id="TIME">%1$s</xliff:g> жаңырды"</string>
     <plurals name="abc_slice_duration_min" formatted="false" msgid="7664017844210142826">
       <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> мүн. мурун</item>
       <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> мүн. мурун</item>
diff --git a/slidingpanelayout/slidingpanelayout/src/androidTest/java/androidx/slidingpanelayout/widget/UserResizeModeTest.kt b/slidingpanelayout/slidingpanelayout/src/androidTest/java/androidx/slidingpanelayout/widget/UserResizeModeTest.kt
index c4bc17b..77631a9 100644
--- a/slidingpanelayout/slidingpanelayout/src/androidTest/java/androidx/slidingpanelayout/widget/UserResizeModeTest.kt
+++ b/slidingpanelayout/slidingpanelayout/src/androidTest/java/androidx/slidingpanelayout/widget/UserResizeModeTest.kt
@@ -415,6 +415,48 @@
             .that(hasNonTransparentPixel)
             .isTrue()
     }
+
+    @Test
+    fun skippedMeasurePassIsCorrected() {
+        val context = InstrumentationRegistry.getInstrumentation().context
+        val spl = createTestSpl(context, collapsibleContentViews = true)
+
+        fun assertAdjacentSiblings(message: String) {
+            val (leftChild, rightChild) = spl.leftAndRightViews()
+            assertWithMessage("adjacent view edges: $message")
+                .that(rightChild.left)
+                .isEqualTo(leftChild.right)
+        }
+
+        assertAdjacentSiblings("initial layout")
+
+        spl.splitDividerPosition = 0
+        spl.measureAndLayoutForTest()
+
+        assertAdjacentSiblings("with splitDividerPosition = 0")
+
+        val (left, right) = spl.leftAndRightViews()
+        assertWithMessage("left child width")
+            .that(left.width)
+            .isEqualTo(0)
+        assertWithMessage("right child width")
+            .that(right.width)
+            .isEqualTo(100)
+    }
+}
+
+private fun SlidingPaneLayout.leftAndRightViews(): Pair<View, View> {
+    val isRtl = this.layoutDirection == View.LAYOUT_DIRECTION_RTL
+    val leftChild: View
+    val rightChild: View
+    if (isRtl) {
+        leftChild = this[1]
+        rightChild = this[0]
+    } else {
+        leftChild = this[0]
+        rightChild = this[1]
+    }
+    return leftChild to rightChild
 }
 
 private fun View.drawToBitmap(): Bitmap {
@@ -427,24 +469,37 @@
 private fun createTestSpl(
     context: Context,
     setDividerDrawable: Boolean = true,
-    childPanesAcceptTouchEvents: Boolean = false
+    childPanesAcceptTouchEvents: Boolean = false,
+    collapsibleContentViews: Boolean = false
 ): SlidingPaneLayout = SlidingPaneLayout(context).apply {
     addView(
         TestPaneView(context).apply {
-            minimumWidth = 30
+            val lpWidth: Int
+            if (collapsibleContentViews) {
+                lpWidth = 0
+            } else {
+                minimumWidth = 30
+                lpWidth = LayoutParams.WRAP_CONTENT
+            }
             acceptTouchEvents = childPanesAcceptTouchEvents
             layoutParams = SlidingPaneLayout.LayoutParams(
-                LayoutParams.WRAP_CONTENT,
+                lpWidth,
                 LayoutParams.MATCH_PARENT
             ).apply { weight = 1f }
         }
     )
     addView(
         TestPaneView(context).apply {
-            minimumWidth = 30
+            val lpWidth: Int
+            if (collapsibleContentViews) {
+                lpWidth = 0
+            } else {
+                minimumWidth = 30
+                lpWidth = LayoutParams.WRAP_CONTENT
+            }
             acceptTouchEvents = childPanesAcceptTouchEvents
             layoutParams = SlidingPaneLayout.LayoutParams(
-                LayoutParams.WRAP_CONTENT,
+                lpWidth,
                 LayoutParams.MATCH_PARENT
             ).apply { weight = 1f }
         }
diff --git a/slidingpanelayout/slidingpanelayout/src/main/java/androidx/slidingpanelayout/widget/SlidingPaneLayout.kt b/slidingpanelayout/slidingpanelayout/src/main/java/androidx/slidingpanelayout/widget/SlidingPaneLayout.kt
index 319ff8f..3d3dc38 100644
--- a/slidingpanelayout/slidingpanelayout/src/main/java/androidx/slidingpanelayout/widget/SlidingPaneLayout.kt
+++ b/slidingpanelayout/slidingpanelayout/src/main/java/androidx/slidingpanelayout/widget/SlidingPaneLayout.kt
@@ -187,8 +187,19 @@
     }
 }
 
+/**
+ * Pulls the string interpolation and exception throwing bytecode out of the inlined
+ * [spLayoutParams] property at each call site
+ */
+private fun layoutParamsError(childView: View, layoutParams: LayoutParams?): Nothing {
+    error("SlidingPaneLayout child $childView had unexpected LayoutParams $layoutParams")
+}
+
 private inline val View.spLayoutParams: SlidingPaneLayout.LayoutParams
-    get() = layoutParams as SlidingPaneLayout.LayoutParams
+    get() = when (val layoutParams = layoutParams) {
+        is SlidingPaneLayout.LayoutParams -> layoutParams
+        else -> layoutParamsError(this, layoutParams)
+    }
 
 /**
  * SlidingPaneLayout provides a horizontal, multi-pane layout for use at the top level
@@ -459,7 +470,7 @@
      * Position of the division between split panes when [isSlideable] is `false`.
      * When the value is < 0 it should be one of the `SPLIT_DIVIDER_POSITION_*` constants,
      * e.g. [SPLIT_DIVIDER_POSITION_AUTO]. When the value is >= 0 it represents a value in pixels
-     * between 0 and [getWidth].
+     * between 0 and [getWidth]. The default value is [SPLIT_DIVIDER_POSITION_AUTO].
      *
      * Changing this property will result in a [requestLayout] and relayout of the contents
      * of the [SlidingPaneLayout].
@@ -995,7 +1006,7 @@
                 if (child.visibility == GONE) return@forEachIndexed
                 val lp = child.spLayoutParams
                 val skippedFirstPass = !lp.canInfluenceParentSize || lp.weightOnlyWidth
-                val measuredWidth = if (skippedFirstPass) 0 else child.measuredWidth
+                val firstPassMeasuredWidth = if (skippedFirstPass) 0 else child.measuredWidth
                 val newWidth = when {
                     // Child view consumes available space if the combined width cannot fit into
                     // the layout available width.
@@ -1007,7 +1018,7 @@
                             val widthToDistribute = widthRemaining.coerceAtLeast(0)
                             val addedWidth =
                                 (lp.weight * widthToDistribute / weightSum).roundToInt()
-                            measuredWidth + addedWidth
+                            firstPassMeasuredWidth + addedWidth
                         } else { // Explicit dividing line is defined
                             val clampedPos = dividerPos.coerceAtMost(width - paddingRight)
                                 .coerceAtLeast(paddingLeft)
@@ -1025,9 +1036,9 @@
                         widthAvailable - lp.horizontalMargin - totalMeasuredWidth
                     }
                     lp.width > 0 -> lp.width
-                    else -> measuredWidth
+                    else -> firstPassMeasuredWidth
                 }
-                if (measuredWidth != newWidth) {
+                if (newWidth != child.measuredWidth) {
                     val childWidthSpec = MeasureSpec.makeMeasureSpec(newWidth, MeasureSpec.EXACTLY)
                     val childHeightSpec = getChildHeightMeasureSpec(
                         child,
diff --git a/transition/transition/src/androidTest/java/androidx/transition/FragmentTransitionSeekingTest.kt b/transition/transition/src/androidTest/java/androidx/transition/FragmentTransitionSeekingTest.kt
index 71e1465..d10ab54 100644
--- a/transition/transition/src/androidTest/java/androidx/transition/FragmentTransitionSeekingTest.kt
+++ b/transition/transition/src/androidTest/java/androidx/transition/FragmentTransitionSeekingTest.kt
@@ -17,6 +17,7 @@
 package androidx.transition
 
 import android.os.Build
+import android.view.View
 import android.window.BackEvent
 import androidx.activity.BackEventCompat
 import androidx.lifecycle.Lifecycle
@@ -217,6 +218,8 @@
                     }
                 })
             })
+            fragment1.sharedElementEnterTransition = null
+            fragment1.sharedElementReturnTransition = null
 
             fm1.beginTransaction()
                 .replace(R.id.fragmentContainer, fragment1, "1")
@@ -236,6 +239,8 @@
                     }
                 })
             })
+            fragment2.sharedElementEnterTransition = null
+            fragment2.sharedElementReturnTransition = null
 
             fm1.beginTransaction()
                 .replace(R.id.fragmentContainer, fragment2, "2")
@@ -257,6 +262,8 @@
                     }
                 })
             })
+            fragment3.sharedElementEnterTransition = null
+            fragment3.sharedElementReturnTransition = null
 
             fm1.beginTransaction()
                 .replace(R.id.fragmentContainer, fragment3, "3")
@@ -563,4 +570,61 @@
             assertThat(resumedAfterOnBackStarted).isTrue()
         }
     }
+
+    @Test
+    fun GestureBackWithNonSeekableSharedElement() {
+        withUse(ActivityScenario.launch(FragmentTransitionTestActivity::class.java)) {
+            val fm1 = withActivity { supportFragmentManager }
+
+            val fragment1 = StrictViewFragment(R.layout.scene1)
+
+            fm1.beginTransaction()
+                .replace(R.id.fragmentContainer, fragment1, "1")
+                .setReorderingAllowed(true)
+                .addToBackStack(null)
+                .commit()
+            waitForExecution()
+
+            val fragment2 = TransitionFragment(R.layout.scene6)
+            fragment2.setEnterTransition(Fade())
+            fragment2.setReturnTransition(Fade())
+
+            val greenSquare = fragment1.requireView().findViewById<View>(R.id.greenSquare)
+
+            fm1.beginTransaction()
+                .replace(R.id.fragmentContainer, fragment2, "2")
+                .addSharedElement(greenSquare, "green")
+                .setReorderingAllowed(true)
+                .addToBackStack(null)
+                .commit()
+            waitForExecution()
+
+            fragment2.waitForTransition()
+
+            val dispatcher = withActivity { onBackPressedDispatcher }
+            withActivity {
+                dispatcher.dispatchOnBackStarted(
+                    BackEventCompat(
+                        0.1F,
+                        0.1F,
+                        0.1F,
+                        BackEvent.EDGE_LEFT
+                    )
+                )
+            }
+            executePendingTransactions()
+
+            withActivity {
+                dispatcher.onBackPressed()
+            }
+            executePendingTransactions()
+
+            assertThat(fragment2.isAdded).isFalse()
+            assertThat(fm1.findFragmentByTag("2"))
+                .isEqualTo(null)
+
+            // Make sure the original fragment was correctly readded to the container
+            assertThat(fragment1.requireView().parent).isNotNull()
+        }
+    }
 }
diff --git a/tv/samples/src/main/java/androidx/tv/samples/MaterialThemeMapping.kt b/tv/samples/src/main/java/androidx/tv/samples/MaterialThemeMapping.kt
index a6b0c73..da4047e 100644
--- a/tv/samples/src/main/java/androidx/tv/samples/MaterialThemeMapping.kt
+++ b/tv/samples/src/main/java/androidx/tv/samples/MaterialThemeMapping.kt
@@ -24,6 +24,7 @@
 @OptIn(ExperimentalTvMaterial3Api::class)
 @Composable
 fun mapColorScheme(tvColorScheme: TvColorScheme): ColorScheme {
+    @Suppress("Deprecation")
     return ColorScheme(
         primary = tvColorScheme.primary,
         onPrimary = tvColorScheme.onPrimary,
diff --git a/webkit/integration-tests/instrumentation/src/androidTest/java/androidx/webkit/WebSettingsCompatTest.java b/webkit/integration-tests/instrumentation/src/androidTest/java/androidx/webkit/WebSettingsCompatTest.java
index e45172f..3235df9 100644
--- a/webkit/integration-tests/instrumentation/src/androidTest/java/androidx/webkit/WebSettingsCompatTest.java
+++ b/webkit/integration-tests/instrumentation/src/androidTest/java/androidx/webkit/WebSettingsCompatTest.java
@@ -305,5 +305,10 @@
                 WebSettingsCompat.WEB_AUTHENTICATION_SUPPORT_APP);
         Assert.assertEquals(WebSettingsCompat.WEB_AUTHENTICATION_SUPPORT_APP,
                 WebSettingsCompat.getWebAuthenticationSupport(settings));
+
+        WebSettingsCompat.setWebAuthenticationSupport(settings,
+                WebSettingsCompat.WEB_AUTHENTICATION_SUPPORT_BROWSER);
+        Assert.assertEquals(WebSettingsCompat.WEB_AUTHENTICATION_SUPPORT_BROWSER,
+                WebSettingsCompat.getWebAuthenticationSupport(settings));
     }
 }
diff --git a/webkit/webkit/src/main/java/androidx/webkit/WebSettingsCompat.java b/webkit/webkit/src/main/java/androidx/webkit/WebSettingsCompat.java
index 413c0fc..a9eabaf 100644
--- a/webkit/webkit/src/main/java/androidx/webkit/WebSettingsCompat.java
+++ b/webkit/webkit/src/main/java/androidx/webkit/WebSettingsCompat.java
@@ -908,7 +908,8 @@
     }
 
     @IntDef({WEB_AUTHENTICATION_SUPPORT_NONE,
-            WEB_AUTHENTICATION_SUPPORT_APP})
+            WEB_AUTHENTICATION_SUPPORT_APP,
+            WEB_AUTHENTICATION_SUPPORT_BROWSER})
     @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
     @Retention(RetentionPolicy.SOURCE)
     @interface WebAuthenticationSupport {
@@ -933,6 +934,15 @@
             WebSettingsBoundaryInterface.WebauthnSupport.APP;
 
     /**
+     * The support level that allows apps to make WebAuthn calls for any website. See
+     * <a href="https://developer.android.com/training/sign-in/privileged-apps">Privileged apps</a>
+     * to learn how to make WebAuthn calls for any website.
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    public static final int WEB_AUTHENTICATION_SUPPORT_BROWSER =
+            WebSettingsBoundaryInterface.WebauthnSupport.BROWSER;
+
+    /**
      * Sets the support level for the given {@link WebSettings}.
      *
      * <p>
@@ -944,6 +954,7 @@
      * @param support  The new support level which this WebView will use.
      * @see #WEB_AUTHENTICATION_SUPPORT_NONE
      * @see #WEB_AUTHENTICATION_SUPPORT_APP
+     * @see #WEB_AUTHENTICATION_SUPPORT_BROWSER
      */
     @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
     @RequiresFeature(name = WebViewFeature.WEB_AUTHENTICATION,
@@ -972,6 +983,7 @@
      * @see #setWebAuthenticationSupport(WebSettings, int)
      * @see #WEB_AUTHENTICATION_SUPPORT_NONE
      * @see #WEB_AUTHENTICATION_SUPPORT_APP
+     * @see #WEB_AUTHENTICATION_SUPPORT_BROWSER
      */
     @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
     @RequiresFeature(name = WebViewFeature.WEB_AUTHENTICATION,
diff --git a/window/window-java/src/main/java/androidx/window/java/core/CallbackToFlowAdapter.kt b/window/window-java/src/main/java/androidx/window/java/core/CallbackToFlowAdapter.kt
index 175c1ada..5e641c9 100644
--- a/window/window-java/src/main/java/androidx/window/java/core/CallbackToFlowAdapter.kt
+++ b/window/window-java/src/main/java/androidx/window/java/core/CallbackToFlowAdapter.kt
@@ -16,6 +16,7 @@
 
 package androidx.window.java.core
 
+import androidx.annotation.GuardedBy
 import androidx.core.util.Consumer
 import java.util.concurrent.Executor
 import java.util.concurrent.locks.ReentrantLock
@@ -31,7 +32,9 @@
  */
 internal class CallbackToFlowAdapter {
 
-    private val lock = ReentrantLock()
+    private val globalLock = ReentrantLock()
+
+    @GuardedBy("globalLock")
     private val consumerToJobMap = mutableMapOf<Consumer<*>, Job>()
 
     /**
@@ -39,7 +42,7 @@
      * Registering the same [Consumer] is a no-op.
      */
     fun <T : Any> connect(executor: Executor, consumer: Consumer<T>, flow: Flow<T>) {
-        lock.withLock {
+        globalLock.withLock {
             if (consumerToJobMap[consumer] == null) {
                 val scope = CoroutineScope(executor.asCoroutineDispatcher())
                 consumerToJobMap[consumer] = scope.launch {
@@ -56,7 +59,7 @@
      * no-op.
      */
     fun disconnect(consumer: Consumer<*>) {
-        lock.withLock {
+        globalLock.withLock {
             consumerToJobMap[consumer]?.cancel()
             consumerToJobMap.remove(consumer)
         }
diff --git a/window/window/src/main/java/androidx/window/layout/adapter/extensions/ExtensionWindowBackendApi1.kt b/window/window/src/main/java/androidx/window/layout/adapter/extensions/ExtensionWindowBackendApi1.kt
index 1446a39..afb37df 100644
--- a/window/window/src/main/java/androidx/window/layout/adapter/extensions/ExtensionWindowBackendApi1.kt
+++ b/window/window/src/main/java/androidx/window/layout/adapter/extensions/ExtensionWindowBackendApi1.kt
@@ -36,14 +36,15 @@
     private val consumerAdapter: ConsumerAdapter
 ) : WindowBackend {
 
-    private val extensionWindowBackendLock = ReentrantLock()
-    @GuardedBy("lock")
+    private val globalLock = ReentrantLock()
+
+    @GuardedBy("globalLock")
     private val contextToListeners = mutableMapOf<Context, MulticastConsumer>()
 
-    @GuardedBy("lock")
+    @GuardedBy("globalLock")
     private val listenerToContext = mutableMapOf<Consumer<WindowLayoutInfo>, Context>()
 
-    @GuardedBy("lock")
+    @GuardedBy("globalLock")
     private val consumerToToken = mutableMapOf<MulticastConsumer, ConsumerAdapter.Subscription>()
 
     /**
@@ -60,7 +61,7 @@
         executor: Executor,
         callback: Consumer<WindowLayoutInfo>
     ) {
-        extensionWindowBackendLock.withLock {
+        globalLock.withLock {
             contextToListeners[context]?.let { listener ->
                 listener.addListener(callback)
                 listenerToContext[callback] = context
@@ -100,7 +101,7 @@
      * @param callback a listener that may have been registered
      */
     override fun unregisterLayoutChangeCallback(callback: Consumer<WindowLayoutInfo>) {
-        extensionWindowBackendLock.withLock {
+        globalLock.withLock {
             val context = listenerToContext[callback] ?: return
             val multicastListener = contextToListeners[context] ?: return
             multicastListener.removeListener(callback)
diff --git a/window/window/src/main/java/androidx/window/layout/adapter/extensions/ExtensionWindowBackendApi2.kt b/window/window/src/main/java/androidx/window/layout/adapter/extensions/ExtensionWindowBackendApi2.kt
index 1c60c33..bc6fb57 100644
--- a/window/window/src/main/java/androidx/window/layout/adapter/extensions/ExtensionWindowBackendApi2.kt
+++ b/window/window/src/main/java/androidx/window/layout/adapter/extensions/ExtensionWindowBackendApi2.kt
@@ -33,11 +33,12 @@
     private val component: WindowLayoutComponent
 ) : WindowBackend {
 
-    private val extensionWindowBackendLock = ReentrantLock()
-    @GuardedBy("lock")
+    private val globalLock = ReentrantLock()
+
+    @GuardedBy("globalLock")
     private val contextToListeners = mutableMapOf<Context, MulticastConsumer>()
 
-    @GuardedBy("lock")
+    @GuardedBy("globalLock")
     private val listenerToContext = mutableMapOf<Consumer<WindowLayoutInfo>, Context>()
 
     /**
@@ -55,7 +56,7 @@
         executor: Executor,
         callback: Consumer<WindowLayoutInfo>
     ) {
-        extensionWindowBackendLock.withLock {
+        globalLock.withLock {
             contextToListeners[context]?.let { listener ->
                 listener.addListener(callback)
                 listenerToContext[callback] = context
@@ -77,7 +78,7 @@
      * @param callback a listener that may have been registered
      */
     override fun unregisterLayoutChangeCallback(callback: Consumer<WindowLayoutInfo>) {
-        extensionWindowBackendLock.withLock {
+        globalLock.withLock {
             val context = listenerToContext[callback] ?: return
             val multicastListener = contextToListeners[context] ?: return
             multicastListener.removeListener(callback)
diff --git a/window/window/src/main/java/androidx/window/layout/adapter/extensions/MulticastConsumer.kt b/window/window/src/main/java/androidx/window/layout/adapter/extensions/MulticastConsumer.kt
index a5d2cc1..e122e1c 100644
--- a/window/window/src/main/java/androidx/window/layout/adapter/extensions/MulticastConsumer.kt
+++ b/window/window/src/main/java/androidx/window/layout/adapter/extensions/MulticastConsumer.kt
@@ -31,14 +31,15 @@
 internal class MulticastConsumer(
     private val context: Context
 ) : Consumer<OEMWindowLayoutInfo>, OEMConsumer<OEMWindowLayoutInfo> {
-    private val multicastConsumerLock = ReentrantLock()
-    @GuardedBy("lock")
+    private val globalLock = ReentrantLock()
+
+    @GuardedBy("globalLock")
     private var lastKnownValue: WindowLayoutInfo? = null
-    @GuardedBy("lock")
+    @GuardedBy("globalLock")
     private val registeredListeners = mutableSetOf<Consumer<WindowLayoutInfo>>()
 
     override fun accept(value: OEMWindowLayoutInfo) {
-        multicastConsumerLock.withLock {
+        globalLock.withLock {
             val newValue = ExtensionsWindowLayoutInfoAdapter.translate(context, value)
             lastKnownValue = newValue
             registeredListeners.forEach { consumer -> consumer.accept(newValue) }
@@ -46,14 +47,14 @@
     }
 
     fun addListener(listener: Consumer<WindowLayoutInfo>) {
-        multicastConsumerLock.withLock {
+        globalLock.withLock {
             lastKnownValue?.let { value -> listener.accept(value) }
             registeredListeners.add(listener)
         }
     }
 
     fun removeListener(listener: Consumer<WindowLayoutInfo>) {
-        multicastConsumerLock.withLock {
+        globalLock.withLock {
             registeredListeners.remove(listener)
         }
     }
diff --git a/window/window/src/main/java/androidx/window/layout/adapter/sidecar/SidecarCompat.kt b/window/window/src/main/java/androidx/window/layout/adapter/sidecar/SidecarCompat.kt
index 1e7dec9..fdaa0c2 100644
--- a/window/window/src/main/java/androidx/window/layout/adapter/sidecar/SidecarCompat.kt
+++ b/window/window/src/main/java/androidx/window/layout/adapter/sidecar/SidecarCompat.kt
@@ -371,19 +371,19 @@
     private class DistinctElementCallback(
         private val callbackInterface: ExtensionCallbackInterface
     ) : ExtensionCallbackInterface {
-        private val lock = ReentrantLock()
+        private val globalLock = ReentrantLock()
 
         /**
          * A map from [Activity] to the last computed [WindowLayoutInfo] for the
          * given activity. A [WeakHashMap] is used to avoid retaining the [Activity].
          */
-        @GuardedBy("mLock")
+        @GuardedBy("globalLock")
         private val activityWindowLayoutInfo = WeakHashMap<Activity, WindowLayoutInfo>()
         override fun onWindowLayoutChanged(
             activity: Activity,
             newLayout: WindowLayoutInfo
         ) {
-            lock.withLock {
+            globalLock.withLock {
                 val lastInfo = activityWindowLayoutInfo[activity]
                 if (newLayout == lastInfo) {
                     return
@@ -394,7 +394,7 @@
         }
 
         fun clearWindowLayoutInfo(activity: Activity) {
-            lock.withLock {
+            globalLock.withLock {
                 activityWindowLayoutInfo[activity] = null
             }
         }
diff --git a/window/window/src/main/java/androidx/window/layout/adapter/sidecar/SidecarWindowBackend.kt b/window/window/src/main/java/androidx/window/layout/adapter/sidecar/SidecarWindowBackend.kt
index d3ba19b..325c701 100644
--- a/window/window/src/main/java/androidx/window/layout/adapter/sidecar/SidecarWindowBackend.kt
+++ b/window/window/src/main/java/androidx/window/layout/adapter/sidecar/SidecarWindowBackend.kt
@@ -130,7 +130,7 @@
      * Checks if there are no more registered callbacks left for the activity and inform
      * extension if needed.
      */
-    @GuardedBy("sLock")
+    @GuardedBy("globalLock")
     private fun callbackRemovedForActivity(activity: Activity) {
         val hasRegisteredCallback = windowLayoutChangeCallbacks.any { wrapper ->
             wrapper.activity == activity
diff --git a/window/window/src/testUtil/java/androidx/window/layout/adapter/sidecar/SwitchOnUnregisterExtensionInterfaceCompat.kt b/window/window/src/testUtil/java/androidx/window/layout/adapter/sidecar/SwitchOnUnregisterExtensionInterfaceCompat.kt
index d902e75..69d82ee 100644
--- a/window/window/src/testUtil/java/androidx/window/layout/adapter/sidecar/SwitchOnUnregisterExtensionInterfaceCompat.kt
+++ b/window/window/src/testUtil/java/androidx/window/layout/adapter/sidecar/SwitchOnUnregisterExtensionInterfaceCompat.kt
@@ -27,7 +27,6 @@
 import androidx.window.layout.HardwareFoldingFeature.Type.Companion.HINGE
 import androidx.window.layout.WindowLayoutInfo
 import androidx.window.layout.adapter.sidecar.ExtensionInterfaceCompat.ExtensionCallbackInterface
-import java.util.concurrent.locks.Lock
 import java.util.concurrent.locks.ReentrantLock
 import kotlin.concurrent.withLock
 
@@ -37,11 +36,11 @@
  * unregister then register again.
  */
 internal class SwitchOnUnregisterExtensionInterfaceCompat : ExtensionInterfaceCompat {
-    private val lock: Lock = ReentrantLock()
+    private val globalLock = ReentrantLock()
     private val foldBounds = Rect(0, 100, 200, 100)
-    @GuardedBy("mLock")
+    @GuardedBy("globalLock")
     private var callback: ExtensionCallbackInterface = EmptyExtensionCallbackInterface()
-    @GuardedBy("mLock")
+    @GuardedBy("globalLock")
     private var state = FLAT
 
     override fun validateExtensionInterface(): Boolean {
@@ -49,15 +48,15 @@
     }
 
     override fun setExtensionCallback(extensionCallback: ExtensionCallbackInterface) {
-        lock.withLock { callback = extensionCallback }
+        globalLock.withLock { callback = extensionCallback }
     }
 
     override fun onWindowLayoutChangeListenerAdded(activity: Activity) {
-        lock.withLock { callback.onWindowLayoutChanged(activity, currentWindowLayoutInfo()) }
+        globalLock.withLock { callback.onWindowLayoutChanged(activity, currentWindowLayoutInfo()) }
     }
 
     override fun onWindowLayoutChangeListenerRemoved(activity: Activity) {
-        lock.withLock { state = toggleState(state) }
+        globalLock.withLock { state = toggleState(state) }
     }
 
     fun currentWindowLayoutInfo(): WindowLayoutInfo {