Merge "Add a in-process and multi-process lock during database configuration." into androidx-main
diff --git a/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/consumer/BaselineProfileConsumerPlugin.kt b/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/consumer/BaselineProfileConsumerPlugin.kt
index 95106f9..04dc5489 100644
--- a/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/consumer/BaselineProfileConsumerPlugin.kt
+++ b/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/consumer/BaselineProfileConsumerPlugin.kt
@@ -40,6 +40,7 @@
 import com.android.build.api.dsl.ApplicationExtension
 import com.android.build.api.dsl.LibraryExtension
 import com.android.build.api.variant.ApplicationVariant
+import com.android.build.api.variant.ApplicationVariantBuilder
 import com.android.build.api.variant.Variant
 import org.gradle.api.GradleException
 import org.gradle.api.Plugin
@@ -154,6 +155,38 @@
         )
     }
 
+    override fun onApplicationBeforeVariants(variantBuilder: ApplicationVariantBuilder) {
+
+        // Note that the lifecycle is for each variant `beforeVariant`, `onVariant`. This means
+        // that the `onVariant` for the base variants of the module (for example `release`) will
+        // run before `beforeVariant` of `benchmarkRelease` and `nonMinifiedRelease`.
+        // Since we schedule some callbacks in for benchmark and nonMinified variants in the
+        // onVariant callback for the base variants, this is the place where we can remove them,
+        // in case the benchmark and nonMinified variants have been disabled.
+
+        val isBaselineProfilePluginCreatedBuildType = variantBuilder.buildType?.let {
+            it.startsWith(BUILD_TYPE_BASELINE_PROFILE_PREFIX) ||
+                it.startsWith(BUILD_TYPE_BENCHMARK_PREFIX)
+        } ?: false
+
+        // Note that the callback should be remove at the end, after all the variants
+        // have been processed. This is because the benchmark and nonMinified variants can be
+        // disabled at any point AFTER the plugin has been applied. So checking immediately here
+        // would tell us that the variant is enabled, while it could be disabled later.
+        afterVariants {
+            if (!variantBuilder.enable && isBaselineProfilePluginCreatedBuildType) {
+                removeOnVariantCallback(variantBuilder.name)
+                logger.info(
+                    "Variant `${variantBuilder.name}` is disabled. If this " +
+                        "is not intentional, please check your gradle configuration " +
+                        "for beforeVariants blocks. For more information on variant " +
+                        "filters checkout the docs at https://developer.android.com/" +
+                        "build/build-variants#filter-variants."
+                )
+            }
+        }
+    }
+
     @Suppress("UnstableApiUsage")
     override fun onVariants(variant: Variant) {
 
@@ -378,46 +411,30 @@
 
             if (isApplicationModule()) {
                 // Defines a function to apply the baseline profile source sets to a variant.
-                fun applySourceSets(variantName: String, variantBuildType: String?) {
+                fun applySourceSets(variantName: String) {
                     val taskName = camelCase("merge", variantName, "artProfile")
                     project
                         .tasks
                         .namedOrNull<Task>(taskName)
                         ?.configure { t ->
-
-                            // TODO: this causes a circular task dependency when the producer points
-                            //  to a consumer that does not have the appTarget plugin. (b/272851616)
+                            // This causes a circular task dependency when the producer points to
+                            // a consumer that does not have the appTarget plugin. (b/272851616)
                             if (automaticGeneration) {
                                 t.dependsOn(copyTaskProvider)
                             } else {
                                 t.mustRunAfter(copyTaskProvider)
                             }
                         }
-                        ?: throw IllegalStateException(
-                            "The task `$taskName` doesn't exist. This may be related to a " +
-                                "`beforeVariants` block filtering variants and disabling" +
-                                "`$variantName`. Please check your gradle configuration and make " +
-                                "sure variants with build type `$variantBuildType` are " +
-                                "enabled. For more information on variant filters check out the " +
-                                "docs at https://developer.android.com/build/build-variants#" +
-                                "filter-variants."
-                        )
                 }
 
                 afterVariants {
 
                     // Apply the source sets to the variant.
-                    applySourceSets(
-                        variant.name,
-                        variant.buildType
-                    )
+                    applySourceSets(variant.name)
 
                     // Apply the source sets to the benchmark variant if supported.
                     if (supportsFeature(AgpFeature.TEST_MODULE_SUPPORTS_MULTIPLE_BUILD_TYPES)) {
-                        applySourceSets(
-                            variant.benchmarkVariantName,
-                            variant.benchmarkBuildType
-                        )
+                        applySourceSets(variant.benchmarkVariantName)
                     }
                 }
             }
diff --git a/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/utils/Agp.kt b/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/utils/Agp.kt
index 9f8caaf..5b2b40b 100644
--- a/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/utils/Agp.kt
+++ b/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/utils/Agp.kt
@@ -86,8 +86,11 @@
 @Suppress("UnstableApiUsage")
 internal object TestedApksAgp83 {
     fun getTargetAppApplicationId(variant: TestVariant): Provider<String> {
+        // Note that retrieving the BuildArtifactsLoader from within the lambda causes an issue
+        // with serialization (see b/325886853#comment13).
+        val buildArtifactLoader = variant.artifacts.getBuiltArtifactsLoader()
         return variant.testedApks.map {
-            variant.artifacts.getBuiltArtifactsLoader().load(it)?.applicationId ?: ""
+            buildArtifactLoader.load(it)?.applicationId ?: ""
         }
     }
 }
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 583f424..fd7ee6a 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
@@ -222,6 +222,13 @@
     protected fun onVariant(variantName: String, block: (TestVariant) -> (Unit)) =
         onTestVariantBlockScheduler.executeOrScheduleOnVariantBlock(variantName, block)
 
+    protected fun removeOnVariantCallback(variantName: String) {
+        onVariantBlockScheduler.removeOnVariantCallback(variantName)
+        onAppVariantBlockScheduler.removeOnVariantCallback(variantName)
+        onLibraryVariantBlockScheduler.removeOnVariantCallback(variantName)
+        onTestVariantBlockScheduler.removeOnVariantCallback(variantName)
+    }
+
     protected fun agpVersion() = project.agpVersion()
 
     private fun checkAgpVersion() {
@@ -372,6 +379,10 @@
         }
     }
 
+    fun removeOnVariantCallback(variantName: String) {
+        onVariantBlocks.remove(variantName)
+    }
+
     fun onVariant(variant: T) {
 
         // This error cannot be thrown because of a user configuration but only an error when
diff --git a/benchmark/baseline-profile-gradle-plugin/src/test/kotlin/androidx/baselineprofile/gradle/consumer/BaselineProfileConsumerPluginTest.kt b/benchmark/baseline-profile-gradle-plugin/src/test/kotlin/androidx/baselineprofile/gradle/consumer/BaselineProfileConsumerPluginTest.kt
index d296d1e..92750a7 100644
--- a/benchmark/baseline-profile-gradle-plugin/src/test/kotlin/androidx/baselineprofile/gradle/consumer/BaselineProfileConsumerPluginTest.kt
+++ b/benchmark/baseline-profile-gradle-plugin/src/test/kotlin/androidx/baselineprofile/gradle/consumer/BaselineProfileConsumerPluginTest.kt
@@ -1308,7 +1308,7 @@
     }
 
     @Test
-    fun whenBenchmarkVariantsAreDisabledShouldThrowException() {
+    fun whenBenchmarkVariantsAreDisabledShouldNotify() {
         // Note that this test doesn't works only on AGP > 8.0.0 because in previous versions
         // the benchmark variant is not created.
         assumeTrue(agpVersion != TEST_AGP_VERSION_8_0_0)
@@ -1341,15 +1341,8 @@
             )
         )
 
-        gradleRunner.buildAndFailAndAssertThatOutput("generateBaselineProfile") {
-            contains(
-                "java.lang.IllegalStateException: The task `mergeBenchmarkReleaseArtProfile` " +
-                    "doesn't exist. This may be related to a `beforeVariants` block filtering " +
-                    "variants and disabling`benchmarkRelease`. Please check your gradle " +
-                    "configuration and make sure variants with build type `benchmarkRelease` are " +
-                    "enabled. For more information on variant filters check out the docs at " +
-                    "https://developer.android.com/build/build-variants#filter-variants."
-            )
+        gradleRunner.buildAndAssertThatOutput("tasks", "--info") {
+            contains("Variant `benchmarkRelease` is disabled.")
         }
     }
 }
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 7eda4fc..538cba8 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
@@ -108,8 +108,44 @@
             )
         }
     }
+
+    /**
+     * Only used by group-internal tests
+     *
+     * Most minimal config possible
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    class MinimalTest(
+        private val appTagPackages: List<String>
+    ) : PerfettoConfig(isTextProto = false) {
+        @RequiresApi(23)
+        override fun writeTo(file: File) {
+            file.writeBytes(
+                configOf(
+                    listOf(
+                        minimalAtraceDataSource(atraceApps = appTagPackages)
+                    )
+                ).validateAndEncode()
+            )
+        }
+    }
 }
 
+private fun minimalAtraceDataSource(
+    atraceApps: List<String>
+) = TraceConfig.DataSource(
+    config = DataSourceConfig(
+        name = "linux.ftrace",
+        target_buffer = 0,
+        ftrace_config = FtraceConfig(
+            ftrace_events = emptyList(),
+            atrace_categories = emptyList(),
+            atrace_apps = atraceApps,
+            compact_sched = null
+        )
+    )
+)
+
 private fun ftraceDataSource(
     atraceApps: List<String>
 ) = TraceConfig.DataSource(
@@ -315,6 +351,27 @@
     return sources
 }
 
+private fun configOf(
+    dataSources: List<TraceConfig.DataSource>
+) = TraceConfig(
+    buffers = listOf(
+        BufferConfig(size_kb = 32768, FillPolicy.RING_BUFFER),
+        BufferConfig(size_kb = 4096, FillPolicy.RING_BUFFER)
+    ),
+    data_sources = dataSources,
+    // periodically dump to file, so we don't overrun our ring buffer
+    // buffers are expected to be big enough for 5 seconds, so conservatively set 2.5 dump
+    write_into_file = true,
+    file_write_period_ms = 2500,
+
+    // multiple of file_write_period_ms, enables trace processor to work in batches
+    flush_period_ms = 5000,
+
+    // reduce timeout to reduce trace capture overhead when devices have data source issues
+    // See b/323601788 and b/307649002.
+    data_source_stop_timeout_ms = 2500,
+)
+
 /**
  * Config for perfetto.
  *
@@ -346,24 +403,7 @@
             config = stackSamplingConfig
         )
     }
-    return TraceConfig(
-        buffers = listOf(
-            BufferConfig(size_kb = 32768, FillPolicy.RING_BUFFER),
-            BufferConfig(size_kb = 4096, FillPolicy.RING_BUFFER)
-        ),
-        data_sources = dataSources,
-        // periodically dump to file, so we don't overrun our ring buffer
-        // buffers are expected to be big enough for 5 seconds, so conservatively set 2.5 dump
-        write_into_file = true,
-        file_write_period_ms = 2500,
-
-        // multiple of file_write_period_ms, enables trace processor to work in batches
-        flush_period_ms = 5000,
-
-        // reduce timeout to reduce trace capture overhead when devices have data source issues
-        // See b/323601788 and b/307649002.
-        data_source_stop_timeout_ms = 2500,
-    )
+    return configOf(dataSources)
 }
 
 @RequiresApi(21) // needed for shell access
diff --git a/benchmark/benchmark-macro-junit4/api/current.txt b/benchmark/benchmark-macro-junit4/api/current.txt
index d4c3495..e06bf57 100644
--- a/benchmark/benchmark-macro-junit4/api/current.txt
+++ b/benchmark/benchmark-macro-junit4/api/current.txt
@@ -19,6 +19,10 @@
     method public void measureRepeated(String packageName, java.util.List<? extends androidx.benchmark.macro.Metric> metrics, optional androidx.benchmark.macro.CompilationMode compilationMode, optional androidx.benchmark.macro.StartupMode? startupMode, @IntRange(from=1L) int iterations, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> measureBlock);
     method public void measureRepeated(String packageName, java.util.List<? extends androidx.benchmark.macro.Metric> metrics, optional androidx.benchmark.macro.CompilationMode compilationMode, optional androidx.benchmark.macro.StartupMode? startupMode, @IntRange(from=1L) int iterations, optional kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> setupBlock, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> measureBlock);
     method public void measureRepeated(String packageName, java.util.List<? extends androidx.benchmark.macro.Metric> metrics, optional androidx.benchmark.macro.CompilationMode compilationMode, @IntRange(from=1L) int iterations, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> measureBlock);
+    method @SuppressCompatibility @androidx.benchmark.perfetto.ExperimentalPerfettoCaptureApi public void measureRepeated(String packageName, java.util.List<? extends androidx.benchmark.macro.Metric> metrics, @IntRange(from=1L) int iterations, androidx.benchmark.perfetto.PerfettoConfig perfettoConfig, optional androidx.benchmark.macro.CompilationMode compilationMode, optional androidx.benchmark.macro.StartupMode? startupMode, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> measureBlock);
+    method @SuppressCompatibility @androidx.benchmark.perfetto.ExperimentalPerfettoCaptureApi public void measureRepeated(String packageName, java.util.List<? extends androidx.benchmark.macro.Metric> metrics, @IntRange(from=1L) int iterations, androidx.benchmark.perfetto.PerfettoConfig perfettoConfig, optional androidx.benchmark.macro.CompilationMode compilationMode, optional androidx.benchmark.macro.StartupMode? startupMode, optional kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> setupBlock, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> measureBlock);
+    method @SuppressCompatibility @androidx.benchmark.perfetto.ExperimentalPerfettoCaptureApi public void measureRepeated(String packageName, java.util.List<? extends androidx.benchmark.macro.Metric> metrics, @IntRange(from=1L) int iterations, androidx.benchmark.perfetto.PerfettoConfig perfettoConfig, optional androidx.benchmark.macro.CompilationMode compilationMode, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> measureBlock);
+    method @SuppressCompatibility @androidx.benchmark.perfetto.ExperimentalPerfettoCaptureApi public void measureRepeated(String packageName, java.util.List<? extends androidx.benchmark.macro.Metric> metrics, @IntRange(from=1L) int iterations, androidx.benchmark.perfetto.PerfettoConfig perfettoConfig, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> measureBlock);
     method public void measureRepeated(String packageName, java.util.List<? extends androidx.benchmark.macro.Metric> metrics, @IntRange(from=1L) int iterations, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> measureBlock);
   }
 
diff --git a/benchmark/benchmark-macro-junit4/api/restricted_current.txt b/benchmark/benchmark-macro-junit4/api/restricted_current.txt
index d4c3495..e06bf57 100644
--- a/benchmark/benchmark-macro-junit4/api/restricted_current.txt
+++ b/benchmark/benchmark-macro-junit4/api/restricted_current.txt
@@ -19,6 +19,10 @@
     method public void measureRepeated(String packageName, java.util.List<? extends androidx.benchmark.macro.Metric> metrics, optional androidx.benchmark.macro.CompilationMode compilationMode, optional androidx.benchmark.macro.StartupMode? startupMode, @IntRange(from=1L) int iterations, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> measureBlock);
     method public void measureRepeated(String packageName, java.util.List<? extends androidx.benchmark.macro.Metric> metrics, optional androidx.benchmark.macro.CompilationMode compilationMode, optional androidx.benchmark.macro.StartupMode? startupMode, @IntRange(from=1L) int iterations, optional kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> setupBlock, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> measureBlock);
     method public void measureRepeated(String packageName, java.util.List<? extends androidx.benchmark.macro.Metric> metrics, optional androidx.benchmark.macro.CompilationMode compilationMode, @IntRange(from=1L) int iterations, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> measureBlock);
+    method @SuppressCompatibility @androidx.benchmark.perfetto.ExperimentalPerfettoCaptureApi public void measureRepeated(String packageName, java.util.List<? extends androidx.benchmark.macro.Metric> metrics, @IntRange(from=1L) int iterations, androidx.benchmark.perfetto.PerfettoConfig perfettoConfig, optional androidx.benchmark.macro.CompilationMode compilationMode, optional androidx.benchmark.macro.StartupMode? startupMode, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> measureBlock);
+    method @SuppressCompatibility @androidx.benchmark.perfetto.ExperimentalPerfettoCaptureApi public void measureRepeated(String packageName, java.util.List<? extends androidx.benchmark.macro.Metric> metrics, @IntRange(from=1L) int iterations, androidx.benchmark.perfetto.PerfettoConfig perfettoConfig, optional androidx.benchmark.macro.CompilationMode compilationMode, optional androidx.benchmark.macro.StartupMode? startupMode, optional kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> setupBlock, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> measureBlock);
+    method @SuppressCompatibility @androidx.benchmark.perfetto.ExperimentalPerfettoCaptureApi public void measureRepeated(String packageName, java.util.List<? extends androidx.benchmark.macro.Metric> metrics, @IntRange(from=1L) int iterations, androidx.benchmark.perfetto.PerfettoConfig perfettoConfig, optional androidx.benchmark.macro.CompilationMode compilationMode, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> measureBlock);
+    method @SuppressCompatibility @androidx.benchmark.perfetto.ExperimentalPerfettoCaptureApi public void measureRepeated(String packageName, java.util.List<? extends androidx.benchmark.macro.Metric> metrics, @IntRange(from=1L) int iterations, androidx.benchmark.perfetto.PerfettoConfig perfettoConfig, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> measureBlock);
     method public void measureRepeated(String packageName, java.util.List<? extends androidx.benchmark.macro.Metric> metrics, @IntRange(from=1L) int iterations, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> measureBlock);
   }
 
diff --git a/benchmark/benchmark-macro-junit4/build.gradle b/benchmark/benchmark-macro-junit4/build.gradle
index c99550b..f2f45e0 100644
--- a/benchmark/benchmark-macro-junit4/build.gradle
+++ b/benchmark/benchmark-macro-junit4/build.gradle
@@ -59,6 +59,17 @@
     // DexMaker has it"s own MockMaker
 }
 
+tasks.withType(KotlinCompile).configureEach {
+    kotlinOptions {
+        // Enable using experimental APIs from within same version group
+        freeCompilerArgs += [
+                "-opt-in=androidx.benchmark.macro.ExperimentalMetricApi",
+                "-opt-in=androidx.benchmark.perfetto.ExperimentalPerfettoTraceProcessorApi",
+                "-opt-in=androidx.benchmark.perfetto.ExperimentalPerfettoCaptureApi"
+        ]
+    }
+}
+
 androidx {
     name = "Benchmark - Macrobenchmark JUnit4"
     publish = Publish.SNAPSHOT_AND_RELEASE
diff --git a/benchmark/benchmark-macro-junit4/src/main/java/androidx/benchmark/macro/junit4/MacrobenchmarkRule.kt b/benchmark/benchmark-macro-junit4/src/main/java/androidx/benchmark/macro/junit4/MacrobenchmarkRule.kt
index d8a01b7..6ca8df5 100644
--- a/benchmark/benchmark-macro-junit4/src/main/java/androidx/benchmark/macro/junit4/MacrobenchmarkRule.kt
+++ b/benchmark/benchmark-macro-junit4/src/main/java/androidx/benchmark/macro/junit4/MacrobenchmarkRule.kt
@@ -24,6 +24,8 @@
 import androidx.benchmark.macro.Metric
 import androidx.benchmark.macro.StartupMode
 import androidx.benchmark.macro.macrobenchmarkWithStartupMode
+import androidx.benchmark.perfetto.ExperimentalPerfettoCaptureApi
+import androidx.benchmark.perfetto.PerfettoConfig
 import androidx.test.rule.GrantPermissionRule
 import org.junit.Assume.assumeTrue
 import org.junit.rules.RuleChain
@@ -94,7 +96,7 @@
      * @param measureBlock The block performing app actions to benchmark each iteration.
      */
     @JvmOverloads
-    public fun measureRepeated(
+    fun measureRepeated(
         packageName: String,
         metrics: List<Metric>,
         compilationMode: CompilationMode = CompilationMode.DEFAULT,
@@ -113,6 +115,78 @@
             compilationMode = compilationMode,
             iterations = iterations,
             startupMode = startupMode,
+            perfettoConfig = null,
+            setupBlock = setupBlock,
+            measureBlock = measureBlock
+        )
+    }
+
+    /**
+     * Measure behavior of the specified [packageName] given a set of [metrics], with a custom
+     * [PerfettoConfig].
+     *
+     * This performs a macrobenchmark with the below control flow:
+     * ```
+     *     resetAppCompilation()
+     *     compile(compilationMode)
+     *     repeat(iterations) {
+     *         setupBlock()
+     *         captureTraceAndMetrics {
+     *             measureBlock()
+     *         }
+     *     }
+     * ```
+     *
+     * Note that a custom [PerfettoConfig]s may result in built-in [Metric]s not working.
+     *
+     * You can see the PerfettoConfig used by a trace (as a text proto) by opening the trace in
+     * [ui.perfetto.dev](http://ui.perfetto.dev), and selecting `Info and Stats` view on the left
+     * panel. You can also generate a custom text proto config by selecting `Record new trace` on
+     * the same panel, selecting recording options, and then clicking `Recording command` to access
+     * the generated text proto.
+     *
+     * @param packageName ApplicationId / Application manifest package name of the app for
+     *   which profiles are generated.
+     * @param metrics List of metrics to measure.
+     * @param compilationMode Mode of compilation used before capturing measurement, such as
+     * [CompilationMode.Partial], defaults to [CompilationMode.DEFAULT].
+     * @param startupMode Optional mode to force app launches performed with
+     * [MacrobenchmarkScope.startActivityAndWait] (and similar variants) to be of the assigned
+     * type. For example, `COLD` launches kill the process before the measureBlock, to ensure
+     * startups will go through full process creation. Generally, leave as null for non-startup
+     * benchmarks.
+     * @param iterations Number of times the [measureBlock] will be run during measurement. Note
+     * that total iteration count may not match, due to warmup iterations needed for the
+     * [compilationMode].
+     * @param perfettoConfig Configuration for Perfetto trace capture during each iteration. Note
+     * that insufficient or invalid configs may result in built-in [Metric]s not working.
+     * @param setupBlock The block performing app actions each iteration, prior to the
+     * [measureBlock]. For example, navigating to a UI where scrolling will be measured.
+     * @param measureBlock The block performing app actions to benchmark each iteration.
+     */
+    @ExperimentalPerfettoCaptureApi
+    @JvmOverloads
+    fun measureRepeated(
+        packageName: String,
+        metrics: List<Metric>,
+        @IntRange(from = 1)
+        iterations: Int,
+        perfettoConfig: PerfettoConfig,
+        compilationMode: CompilationMode = CompilationMode.DEFAULT,
+        startupMode: StartupMode? = null,
+        setupBlock: MacrobenchmarkScope.() -> Unit = {},
+        measureBlock: MacrobenchmarkScope.() -> Unit,
+    ) {
+        macrobenchmarkWithStartupMode(
+            uniqueName = currentDescription.toUniqueName(),
+            className = currentDescription.className,
+            testName = currentDescription.methodName,
+            packageName = packageName,
+            metrics = metrics,
+            compilationMode = compilationMode,
+            iterations = iterations,
+            perfettoConfig = perfettoConfig,
+            startupMode = startupMode,
             setupBlock = setupBlock,
             measureBlock = measureBlock
         )
diff --git a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/MacrobenchmarkTest.kt b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/MacrobenchmarkTest.kt
index 09a6c7d..50b1662 100644
--- a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/MacrobenchmarkTest.kt
+++ b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/MacrobenchmarkTest.kt
@@ -16,8 +16,10 @@
 
 package androidx.benchmark.macro
 
+import android.annotation.SuppressLint
 import androidx.annotation.RequiresApi
 import androidx.benchmark.DeviceInfo
+import androidx.benchmark.perfetto.PerfettoConfig
 import androidx.benchmark.perfetto.PerfettoHelper
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
@@ -55,6 +57,7 @@
                 compilationMode = CompilationMode.Ignore(),
                 iterations = 1,
                 startupMode = null,
+                perfettoConfig = null,
                 setupBlock = {},
                 measureBlock = {}
             )
@@ -74,6 +77,7 @@
                 compilationMode = CompilationMode.Ignore(),
                 iterations = 0, // invalid
                 startupMode = null,
+                perfettoConfig = null,
                 setupBlock = {},
                 measureBlock = {}
             )
@@ -101,6 +105,7 @@
             compilationMode = CompilationMode.DEFAULT,
             iterations = 2,
             startupMode = startupMode,
+            perfettoConfig = null,
             setupBlock = {
                 opOrder += Block.Setup
                 setupIterations += iteration
@@ -157,6 +162,49 @@
     @Test
     fun callbackBehavior_hot() = validateCallbackBehavior(StartupMode.HOT)
 
+    @SuppressLint("BanThreadSleep") // need non-zero duration to assert sum, regardless of clock
+    private fun validateSlicesCustomConfig(includeMacroAppTag: Boolean) {
+        val atraceApps = if (includeMacroAppTag) {
+            listOf(Packages.TEST)
+        } else {
+            emptyList()
+        }
+        val measurements = macrobenchmarkWithStartupMode(
+            uniqueName = "MacrobenchmarkTest#validateSlicesCustomConfig",
+            className = "MacrobenchmarkTest",
+            testName = "validateCallbackBehavior",
+            packageName = Packages.TARGET,
+            // disable targetPackageOnly filter, since this process emits the event
+            metrics = listOf(TraceSectionMetric(TRACE_LABEL, targetPackageOnly = false)),
+            compilationMode = CompilationMode.DEFAULT,
+            iterations = 3,
+            startupMode = null,
+            perfettoConfig = PerfettoConfig.MinimalTest(atraceApps),
+            setupBlock = { },
+            measureBlock = {
+                trace(TRACE_LABEL) {
+                    Thread.sleep(2)
+                }
+            }
+        ).metrics[TRACE_LABEL + "SumMs"]!!.runs
+
+        assertEquals(3, measurements.size)
+
+        if (includeMacroAppTag) {
+            assertTrue(measurements.all { it > 0.0 })
+        } else {
+            assertEquals(listOf(0.0, 0.0, 0.0), measurements)
+        }
+    }
+
+    @LargeTest
+    @Test
+    fun customConfig_thisProcess() = validateSlicesCustomConfig(includeMacroAppTag = true)
+
+    @LargeTest
+    @Test
+    fun customConfig_noProcess() = validateSlicesCustomConfig(includeMacroAppTag = false)
+
     companion object {
         const val TRACE_LABEL = "MacrobencharkTestTraceLabel"
     }
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Macrobenchmark.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Macrobenchmark.kt
index 8203ef7..92eecb5 100644
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Macrobenchmark.kt
+++ b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Macrobenchmark.kt
@@ -35,6 +35,7 @@
 import androidx.benchmark.conditionalError
 import androidx.benchmark.inMemoryTrace
 import androidx.benchmark.json.BenchmarkData
+import androidx.benchmark.perfetto.ExperimentalPerfettoCaptureApi
 import androidx.benchmark.perfetto.PerfettoCapture.PerfettoSdkConfig
 import androidx.benchmark.perfetto.PerfettoCapture.PerfettoSdkConfig.InitialProcessState
 import androidx.benchmark.perfetto.PerfettoCaptureWrapper
@@ -190,6 +191,7 @@
  *
  * This function is a building block for public testing APIs
  */
+@ExperimentalPerfettoCaptureApi
 private fun macrobenchmark(
     uniqueName: String,
     className: String,
@@ -200,10 +202,11 @@
     iterations: Int,
     launchWithClearTask: Boolean,
     startupModeMetricHint: StartupMode?,
+    perfettoConfig: PerfettoConfig?,
     perfettoSdkConfig: PerfettoSdkConfig?,
     setupBlock: MacrobenchmarkScope.() -> Unit,
     measureBlock: MacrobenchmarkScope.() -> Unit
-) {
+): BenchmarkData.TestResult {
     require(iterations > 0) {
         "Require iterations > 0 (iterations = $iterations)"
     }
@@ -276,7 +279,7 @@
                 val fileLabel = "${uniqueName}_iter$iterString"
                 val tracePath = perfettoCollector.record(
                     fileLabel = fileLabel,
-                    config = PerfettoConfig.Benchmark(
+                    config = perfettoConfig ?: PerfettoConfig.Benchmark(
                         /**
                          * Prior to API 24, every package name was joined into a single setprop
                          * which can overflow, and disable *ALL* app level tracing.
@@ -405,18 +408,18 @@
         } + methodTracingResultFiles).map {
             BenchmarkData.TestResult.ProfilerOutput(it)
         }
-        ResultWriter.appendTestResult(
-            BenchmarkData.TestResult(
-                className = className,
-                name = testName,
-                totalRunTimeNs = System.nanoTime() - startTime,
-                metrics = measurements.singleMetrics + measurements.sampledMetrics,
-                repeatIterations = iterations,
-                thermalThrottleSleepSeconds = 0,
-                warmupIterations = warmupIterations,
-                profilerOutputs = mergedProfilerOutputs
-            )
+        val testResult = BenchmarkData.TestResult(
+            className = className,
+            name = testName,
+            totalRunTimeNs = System.nanoTime() - startTime,
+            metrics = measurements.singleMetrics + measurements.sampledMetrics,
+            repeatIterations = iterations,
+            thermalThrottleSleepSeconds = 0,
+            warmupIterations = warmupIterations,
+            profilerOutputs = mergedProfilerOutputs
         )
+        ResultWriter.appendTestResult(testResult)
+        return testResult
     } finally {
         scope.killProcess()
     }
@@ -426,6 +429,7 @@
  * Run a macrobenchmark with the specified StartupMode
  */
 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+@ExperimentalPerfettoCaptureApi
 fun macrobenchmarkWithStartupMode(
     uniqueName: String,
     className: String,
@@ -434,10 +438,11 @@
     metrics: List<Metric>,
     compilationMode: CompilationMode,
     iterations: Int,
+    perfettoConfig: PerfettoConfig?,
     startupMode: StartupMode?,
     setupBlock: MacrobenchmarkScope.() -> Unit,
     measureBlock: MacrobenchmarkScope.() -> Unit
-) {
+): BenchmarkData.TestResult {
     val perfettoSdkConfig =
         if (Arguments.perfettoSdkTracingEnable && Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
             PerfettoSdkConfig(
@@ -449,7 +454,7 @@
                 }
             )
         } else null
-    macrobenchmark(
+    return macrobenchmark(
         uniqueName = uniqueName,
         className = className,
         testName = testName,
@@ -458,6 +463,7 @@
         compilationMode = compilationMode,
         iterations = iterations,
         startupModeMetricHint = startupMode,
+        perfettoConfig = perfettoConfig,
         perfettoSdkConfig = perfettoSdkConfig,
         setupBlock = {
             if (startupMode == StartupMode.COLD) {
diff --git a/biometric/biometric/src/main/res/values-ja/strings.xml b/biometric/biometric/src/main/res/values-ja/strings.xml
index 8fb1180..b0742f2 100644
--- a/biometric/biometric/src/main/res/values-ja/strings.xml
+++ b/biometric/biometric/src/main/res/values-ja/strings.xml
@@ -23,7 +23,7 @@
     <string name="fingerprint_error_no_fingerprints" msgid="7520712796891883488">"指紋が登録されていません。"</string>
     <string name="fingerprint_error_hw_not_present" msgid="6306988885793029438">"このデバイスには指紋認証センサーがありません"</string>
     <string name="fingerprint_error_user_canceled" msgid="7627716295344353987">"指紋認証操作がユーザーによりキャンセルされました。"</string>
-    <string name="fingerprint_error_lockout" msgid="7291787166416782245">"入力回数が上限を超えました。しばらくしてからもう一度お試しください。"</string>
+    <string name="fingerprint_error_lockout" msgid="7291787166416782245">"試行回数が上限に達しました。しばらくしてからもう一度お試しください。"</string>
     <string name="default_error_msg" msgid="4776854077120974966">"不明なエラーです"</string>
     <string name="generic_error_user_canceled" msgid="7309881387583143581">"認証はユーザーによりキャンセルされました。"</string>
     <string name="confirm_device_credential_password" msgid="5912733858573823945">"パスワードを使用"</string>
diff --git a/buildSrc-tests/lint-baseline.xml b/buildSrc-tests/lint-baseline.xml
index e3a6f65..46f896e 100644
--- a/buildSrc-tests/lint-baseline.xml
+++ b/buildSrc-tests/lint-baseline.xml
@@ -85,15 +85,6 @@
     <issue
         id="EagerGradleConfiguration"
         message="Use configureEach instead of all"
-        errorLine1="        buildTypes.all { buildType ->"
-        errorLine2="                   ~~~">
-        <location
-            file="${:buildSrc-tests*main*MAIN*sourceProvider*0*javaDir*4}/androidx/build/AndroidXImplPlugin.kt"/>
-    </issue>
-
-    <issue
-        id="EagerGradleConfiguration"
-        message="Use configureEach instead of all"
         errorLine1="        project.configurations.all { configuration ->"
         errorLine2="                               ~~~">
         <location
@@ -121,24 +112,6 @@
     <issue
         id="EagerGradleConfiguration"
         message="Use configureEach instead of all"
-        errorLine1="            kotlinTarget.compilations.all {"
-        errorLine2="                                      ~~~">
-        <location
-            file="${:buildSrc-tests*main*MAIN*sourceProvider*0*javaDir*4}/androidx/build/AndroidXImplPlugin.kt"/>
-    </issue>
-
-    <issue
-        id="EagerGradleConfiguration"
-        message="Use configureEach instead of all"
-        errorLine1="            project.configurations.all { config ->"
-        errorLine2="                                   ~~~">
-        <location
-            file="${:buildSrc-tests*main*MAIN*sourceProvider*0*javaDir*4}/androidx/build/AndroidXImplPlugin.kt"/>
-    </issue>
-
-    <issue
-        id="EagerGradleConfiguration"
-        message="Use configureEach instead of all"
         errorLine1="    configurations.all { configuration ->"
         errorLine2="                   ~~~">
         <location
@@ -291,18 +264,9 @@
 
     <issue
         id="EagerGradleConfiguration"
-        message="Use configureEach instead of all"
-        errorLine1="    libraryVariants.all { variant ->"
-        errorLine2="                    ~~~">
-        <location
-            file="${:buildSrc-tests*main*MAIN*sourceProvider*0*javaDir*4}/androidx/build/Release.kt"/>
-    </issue>
-
-    <issue
-        id="EagerGradleConfiguration"
         message="Use configureEach instead of whenObjectAdded"
-        errorLine1="        configurations.whenObjectAdded {"
-        errorLine2="                       ~~~~~~~~~~~~~~~">
+        errorLine1="    configurations.whenObjectAdded {"
+        errorLine2="                   ~~~~~~~~~~~~~~~">
         <location
             file="${:buildSrc-tests*main*MAIN*sourceProvider*0*javaDir*4}/androidx/build/SourceJarTaskHelper.kt"/>
     </issue>
@@ -310,8 +274,8 @@
     <issue
         id="EagerGradleConfiguration"
         message="Use configureEach instead of whenObjectAdded"
-        errorLine1="                it.artifacts.whenObjectAdded { _ ->"
-        errorLine2="                             ~~~~~~~~~~~~~~~">
+        errorLine1="            it.artifacts.whenObjectAdded { _ ->"
+        errorLine2="                         ~~~~~~~~~~~~~~~">
         <location
             file="${:buildSrc-tests*main*MAIN*sourceProvider*0*javaDir*4}/androidx/build/SourceJarTaskHelper.kt"/>
     </issue>
@@ -373,8 +337,17 @@
     <issue
         id="GradleProjectIsolation"
         message="Use providers.gradleProperty instead of findProperty"
-        errorLine1="    override val compileSdk: String by lazy { project.findProperty(COMPILE_SDK_VERSION).toString() }"
-        errorLine2="                                                      ~~~~~~~~~~~~">
+        errorLine1="    override val compileSdk: Int by lazy { project.findProperty(COMPILE_SDK).toString().toInt() }"
+        errorLine2="                                                   ~~~~~~~~~~~~">
+        <location
+            file="${:buildSrc-tests*main*MAIN*sourceProvider*0*javaDir*3}/androidx/build/AndroidXConfig.kt"/>
+    </issue>
+
+    <issue
+        id="GradleProjectIsolation"
+        message="Use providers.gradleProperty instead of findProperty"
+        errorLine1="        project.findProperty(COMPILE_SDK_EXTENSION) as Int?"
+        errorLine2="                ~~~~~~~~~~~~">
         <location
             file="${:buildSrc-tests*main*MAIN*sourceProvider*0*javaDir*3}/androidx/build/AndroidXConfig.kt"/>
     </issue>
@@ -685,13 +658,4 @@
             file="${:buildSrc-tests*main*MAIN*sourceProvider*0*javaDir*4}/androidx/build/AndroidXImplPlugin.kt"/>
     </issue>
 
-    <issue
-        id="WithTypeWithoutConfigureEach"
-        message="Avoid passing a closure to withType, use withType().configureEach instead"
-        errorLine1="        project.tasks.withType(Test::class.java) { task -> configureJvmTestTask(project, task) }"
-        errorLine2="                      ~~~~~~~~">
-        <location
-            file="${:buildSrc-tests*main*MAIN*sourceProvider*0*javaDir*4}/androidx/build/AndroidXImplPlugin.kt"/>
-    </issue>
-
 </issues>
diff --git a/buildSrc-tests/src/test/java/androidx/build/AndroidXImplPluginTest.kt b/buildSrc-tests/src/test/java/androidx/build/AndroidXImplPluginTest.kt
deleted file mode 100644
index d3b6f57..0000000
--- a/buildSrc-tests/src/test/java/androidx/build/AndroidXImplPluginTest.kt
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.build
-
-import org.junit.Assert
-import org.junit.Test
-
-class AndroidXImplPluginTest {
-
-    @Test
-    fun testRemoveTargetSdkVersion() {
-        /* ktlint-disable max-line-length */
-        val manifest = """
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="androidx.core" >
-
-    <uses-sdk
-        android:minSdkVersion="14"
-        android:targetSdkVersion="31" />
-
-    <application android:appComponentFactory="androidx.core.app.CoreComponentFactory" />
-
-</manifest>
-        """
-
-        // Expect that the android:targetSdkVersion element is removed.
-        val expected = """
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="androidx.core" >
-
-    <uses-sdk
-        android:minSdkVersion="14" />
-
-    <application android:appComponentFactory="androidx.core.app.CoreComponentFactory" />
-
-</manifest>
-        """
-        /* ktlint-enable max-line-length */
-
-        val actual = removeTargetSdkVersion(manifest)
-        Assert.assertEquals(expected, actual)
-    }
-}
diff --git a/buildSrc-tests/src/test/java/androidx/build/SdkResourceGeneratorTest.kt b/buildSrc-tests/src/test/java/androidx/build/SdkResourceGeneratorTest.kt
index 37ad297..7c78075 100644
--- a/buildSrc-tests/src/test/java/androidx/build/SdkResourceGeneratorTest.kt
+++ b/buildSrc-tests/src/test/java/androidx/build/SdkResourceGeneratorTest.kt
@@ -46,6 +46,7 @@
         project.setSupportRootFolder(File("files/support"))
         val extension = project.rootProject.property("ext") as ExtraPropertiesExtension
         extension.set("prebuiltsRoot", project.projectDir.resolve("relative/prebuilts"))
+        extension.set("androidx.compileSdk", 33)
 
         val taskProvider = SdkResourceGenerator.registerSdkResourceGeneratorTask(project)
         val tasks = project.getTasksByName(SdkResourceGenerator.TASK_NAME, false)
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/AarManifestTransformerTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/AarManifestTransformerTask.kt
deleted file mode 100644
index 6dde7c7..0000000
--- a/buildSrc/private/src/main/kotlin/androidx/build/AarManifestTransformerTask.kt
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.build
-
-import java.io.File
-import java.nio.file.Files
-import java.nio.file.attribute.FileTime
-import org.apache.tools.zip.ZipEntry
-import org.apache.tools.zip.ZipFile
-import org.apache.tools.zip.ZipOutputStream
-import org.gradle.api.DefaultTask
-import org.gradle.api.file.RegularFileProperty
-import org.gradle.api.tasks.CacheableTask
-import org.gradle.api.tasks.InputFile
-import org.gradle.api.tasks.OutputFile
-import org.gradle.api.tasks.PathSensitive
-import org.gradle.api.tasks.PathSensitivity
-import org.gradle.api.tasks.TaskAction
-
-/** Transforms an AAR by removing the `android:targetSdkVersion` element from the manifest. */
-@CacheableTask
-abstract class AarManifestTransformerTask : DefaultTask() {
-    @get:InputFile
-    @get:PathSensitive(PathSensitivity.RELATIVE)
-    abstract val aarFile: RegularFileProperty
-
-    @get:OutputFile abstract val updatedAarFile: RegularFileProperty
-
-    @TaskAction
-    fun taskAction() {
-        val aar = aarFile.get().asFile
-        val updatedAar = updatedAarFile.get().asFile
-        val tempDir = Files.createTempDirectory("${name}Unzip").toFile()
-        tempDir.deleteOnExit()
-
-        ZipFile(aar).use { aarFile -> aarFile.unzipTo(tempDir) }
-
-        val manifestFile = File(tempDir, "AndroidManifest.xml")
-        manifestFile.writeText(removeTargetSdkVersion(manifestFile.readText()))
-
-        tempDir.zipTo(updatedAar)
-        tempDir.deleteRecursively()
-    }
-}
-
-/** Removes the `android:targetSdkVersion` element from the [manifest]. */
-fun removeTargetSdkVersion(manifest: String): String =
-    manifest.replace("\\s*android:targetSdkVersion=\".+?\"".toRegex(), "")
-
-private fun ZipFile.unzipTo(tempDir: File) {
-    entries.iterator().forEach { entry ->
-        if (entry.isDirectory) {
-            File(tempDir, entry.name).mkdirs()
-        } else {
-            val file = File(tempDir, entry.name)
-            file.parentFile.mkdirs()
-            getInputStream(entry).use { stream -> file.writeBytes(stream.readBytes()) }
-        }
-    }
-}
-
-private fun File.zipTo(outZip: File) {
-    ZipOutputStream(outZip.outputStream()).use { stream ->
-        listFiles()!!.forEach { file -> stream.addFileRecursive(null, file) }
-    }
-}
-
-private fun ZipOutputStream.addFileRecursive(parentPath: String?, file: File) {
-    val entryPath = if (parentPath != null) "$parentPath/${file.name}" else file.name
-    val entry = ZipEntry(file, entryPath)
-
-    // Reset creation time of entry to make it deterministic.
-    entry.time = 0
-    entry.creationTime = FileTime.fromMillis(0)
-
-    if (file.isFile) {
-        putNextEntry(entry)
-        file.inputStream().use { stream -> stream.copyTo(this) }
-        closeEntry()
-    } else if (file.isDirectory) {
-        val listFiles = file.listFiles()
-        if (!listFiles.isNullOrEmpty()) {
-            putNextEntry(entry)
-            closeEntry()
-            listFiles.forEach { containedFile -> addFileRecursive(entryPath, containedFile) }
-        }
-    }
-}
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXComposeImplPlugin.kt b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXComposeImplPlugin.kt
index dbbc781..51df347 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXComposeImplPlugin.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXComposeImplPlugin.kt
@@ -340,6 +340,6 @@
     SourceOption(ComposePluginId, "sourceInformation"),
     MetricsOption(ComposePluginId, "metricsDestination"),
     ReportsOption(ComposePluginId, "reportsDestination"),
-    StrongSkippingOption(ComposePluginId, "experimentalStrongSkipping"),
+    StrongSkippingOption(ComposePluginId, "strongSkipping"),
     NonSkippingGroupOption(ComposePluginId, "nonSkippingGroupOptimization")
 }
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt
index 571be0f..8adad31 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt
@@ -39,13 +39,14 @@
 import androidx.build.testConfiguration.configureTestConfigGeneration
 import androidx.build.uptodatedness.TaskUpToDateValidator
 import androidx.build.uptodatedness.cacheEvenIfNoOutputs
-import com.android.build.api.artifact.Artifacts
 import com.android.build.api.artifact.SingleArtifact
 import com.android.build.api.dsl.ApplicationExtension
+import com.android.build.api.dsl.CommonExtension
 import com.android.build.api.dsl.KotlinMultiplatformAndroidTarget
 import com.android.build.api.dsl.KotlinMultiplatformAndroidTestOnDeviceCompilation
 import com.android.build.api.dsl.KotlinMultiplatformAndroidTestOnJvmCompilation
 import com.android.build.api.dsl.PrivacySandboxSdkExtension
+import com.android.build.api.dsl.TestExtension
 import com.android.build.api.variant.AndroidComponentsExtension
 import com.android.build.api.variant.ApplicationAndroidComponentsExtension
 import com.android.build.api.variant.HasDeviceTests
@@ -53,12 +54,9 @@
 import com.android.build.api.variant.KotlinMultiplatformAndroidComponentsExtension
 import com.android.build.api.variant.LibraryAndroidComponentsExtension
 import com.android.build.api.variant.Variant
-import com.android.build.gradle.AppExtension
 import com.android.build.gradle.AppPlugin
-import com.android.build.gradle.BaseExtension
 import com.android.build.gradle.LibraryExtension
 import com.android.build.gradle.LibraryPlugin
-import com.android.build.gradle.TestExtension
 import com.android.build.gradle.TestPlugin
 import com.android.build.gradle.TestedExtension
 import com.android.build.gradle.api.KotlinMultiplatformAndroidPlugin
@@ -185,7 +183,10 @@
         project.tasks.withType(AbstractTestTask::class.java) { task ->
             configureTestTask(project, task, allHostTests)
         }
-        project.tasks.withType(Test::class.java) { task -> configureJvmTestTask(project, task) }
+
+        project.tasks.withType(Test::class.java).configureEach { task ->
+            configureJvmTestTask(project, task)
+        }
 
         project.configureTaskTimeouts()
         project.configureMavenArtifactUpload(
@@ -219,7 +220,6 @@
 
         project.workaroundPrebuiltTakingPrecedenceOverProject()
     }
-
     private fun Project.registerProjectOrArtifact() {
         // Add a method for each sub project where they can declare an optional
         // dependency on a project or its latest snapshot artifact.
@@ -572,13 +572,18 @@
     }
 
     private fun configureWithAppPlugin(project: Project, androidXExtension: AndroidXExtension) {
-        project.extensions.getByType<AppExtension>().apply {
-            configureAndroidBaseOptions(project, androidXExtension)
-            excludeVersionFiles(packagingOptions.resources)
-        }
-
         project.extensions.getByType<ApplicationExtension>().apply {
+            configureAndroidBaseOptions(project, androidXExtension)
+            defaultConfig.targetSdk = project.defaultAndroidConfig.targetSdk
+            val debugSigningConfig = signingConfigs.getByName("debug")
+            // Use a local debug keystore to avoid build server issues.
+            debugSigningConfig.storeFile = project.getKeystore()
+            buildTypes.configureEach { buildType ->
+                // Sign all the builds (including release) with debug key
+                buildType.signingConfig = debugSigningConfig
+            }
             configureAndroidApplicationOptions(project, androidXExtension)
+            excludeVersionFiles(packaging.resources)
         }
 
         project.extensions.getByType<ApplicationAndroidComponentsExtension>().apply {
@@ -602,12 +607,17 @@
     private fun configureWithTestPlugin(project: Project, androidXExtension: AndroidXExtension) {
         project.extensions.getByType<TestExtension>().apply {
             configureAndroidBaseOptions(project, androidXExtension)
-            excludeVersionFiles(packagingOptions.resources)
-        }
-
-        project.extensions.getByType<com.android.build.api.dsl.TestExtension>().apply {
+            defaultConfig.targetSdk = project.defaultAndroidConfig.targetSdk
+            val debugSigningConfig = signingConfigs.getByName("debug")
+            // Use a local debug keystore to avoid build server issues.
+            debugSigningConfig.storeFile = project.getKeystore()
+            buildTypes.configureEach { buildType ->
+                // Sign all the builds (including release) with debug key
+                buildType.signingConfig = debugSigningConfig
+            }
             project.configureTestConfigGeneration(this)
             project.addAppApkToTestConfigGeneration(androidXExtension)
+            excludeVersionFiles(packaging.resources)
         }
 
         project.configureJavaCompilationWarnings(androidXExtension)
@@ -637,10 +647,6 @@
             androidXExtension
         )
 
-        kotlinMultiplatformAndroidComponentsExtension.onVariant { variant ->
-            project.createVariantAarManifestTransformerTask(variant.name, variant.artifacts)
-        }
-
         kotlinMultiplatformAndroidComponentsExtension.onVariant {
             it.configureTests()
         }
@@ -802,54 +808,65 @@
         experimentalProperties.put(ASB_SIGNING_CONFIG_PROPERTY_NAME, keyStore.absolutePath)
     }
 
-    @Suppress("DEPRECATION") // AGP DSL APIs
     private fun configureWithLibraryPlugin(project: Project, androidXExtension: AndroidXExtension) {
-        project.extensions.getByType<LibraryExtension>().apply {
-            configureAndroidBaseOptions(project, androidXExtension)
-            configureAndroidLibraryOptions(project, androidXExtension)
+        project.extensions.getByType<com.android.build.api.dsl.LibraryExtension>().apply {
+            publishing { singleVariant(DEFAULT_PUBLISH_CONFIG) }
 
-            // Make sure the main Kotlin source set doesn't contain anything under
-            // src/main/kotlin.
-            val mainKotlinSrcDir =
-                (sourceSets.findByName("main")?.kotlin
-                        as com.android.build.gradle.api.AndroidSourceDirectorySet)
-                    .srcDirs
-                    .filter { it.name == "kotlin" }
-                    .getOrNull(0)
-            if (mainKotlinSrcDir?.isDirectory == true) {
-                throw GradleException(
-                    "Invalid project structure! AndroidX does not support \"kotlin\" as a " +
-                        "top-level source directory for libraries, use \"java\" instead: " +
-                        mainKotlinSrcDir.path
-                )
+            configureAndroidBaseOptions(project, androidXExtension)
+
+            // Move to api that allows settings of targetSdk on each variant's androidTest when
+            // b/335257447 is fixed
+            @Suppress("DEPRECATION")
+            defaultConfig.targetSdk = project.defaultAndroidConfig.targetSdk
+
+            val debugSigningConfig = signingConfigs.getByName("debug")
+            // Use a local debug keystore to avoid build server issues.
+            debugSigningConfig.storeFile = project.getKeystore()
+            buildTypes.configureEach { buildType ->
+                // Sign all the builds (including release) with debug key
+                buildType.signingConfig = debugSigningConfig
             }
+            project.configureTestConfigGeneration(this)
+            project.addAppApkToTestConfigGeneration(androidXExtension)
         }
 
         val libraryAndroidComponentsExtension =
             project.extensions.getByType<LibraryAndroidComponentsExtension>()
 
-        // Remove the android:targetSdkVersion element from the manifest used for AARs.
-        libraryAndroidComponentsExtension.onVariants { variant ->
-            project.createVariantAarManifestTransformerTask(variant.name, variant.artifacts)
-        }
-
-        project.extensions.getByType<com.android.build.api.dsl.LibraryExtension>().apply {
-            publishing { singleVariant(DEFAULT_PUBLISH_CONFIG) }
-            project.configureTestConfigGeneration(this)
-            project.addAppApkToTestConfigGeneration(androidXExtension)
-        }
-
         libraryAndroidComponentsExtension.apply {
-            beforeVariants(selector().withBuildType("release")) { variant ->
-                variant.enableUnitTest = false
+            finalizeDsl {
+                // Propagate the compileSdk value into minCompileSdk. Don't propagate
+                // compileSdkExtension, since only one library actually depends on the extension
+                // APIs and they can explicitly declare that in their build.gradle. Note that when
+                // we're using a preview SDK, the value for compileSdk will be null and the
+                // resulting AAR metadata won't have a minCompileSdk --
+                // this is okay because AGP automatically embeds forceCompileSdkPreview in the AAR
+                // metadata and uses it instead of minCompileSdk.
+                it.defaultConfig.aarMetadata.minCompileSdk = it.compileSdk
             }
-            onVariants {
-                it.configureTests()
-                it.aotCompileMicrobenchmarks(project)
-                it.enableLongMethodTracingInMicrobenchmark(project)
+            beforeVariants(selector().withBuildType("release")) { variant ->
+                (variant as HasUnitTestBuilder).enableUnitTest = false
+            }
+            onVariants { variant ->
+                // Make sure the main Kotlin source set doesn't contain anything under
+                // src/main/kotlin.
+                val mainKotlinSrcDir = variant.sources.kotlin?.static?.get()?.map { it.asFile }
+                    ?.filter { it.path.contains("src/main/kotlin") }?.getOrNull(0)
+                if (mainKotlinSrcDir?.isDirectory == true) {
+                    throw GradleException(
+                        "Invalid project structure! AndroidX does not support \"kotlin\" as a " +
+                            "top-level source directory for libraries, use \"java\" instead: " +
+                            mainKotlinSrcDir.path
+                    )
+                }
+                variant.configureTests()
+                variant.aotCompileMicrobenchmarks(project)
+                variant.enableLongMethodTracingInMicrobenchmark(project)
             }
         }
 
+        project.disableStrictVersionConstraints()
+        project.setPublishProperty(androidXExtension)
         project.configureVersionFileWriter(libraryAndroidComponentsExtension, androidXExtension)
         project.configureJavaCompilationWarnings(androidXExtension)
 
@@ -1022,7 +1039,7 @@
         afterEvaluate { androidXExtension.validateMavenVersion() }
     }
 
-    private fun BaseExtension.configureAndroidBaseOptions(
+    private fun CommonExtension<*, *, *, *, *, *>.configureAndroidBaseOptions(
         project: Project,
         androidXExtension: AndroidXExtension
     ) {
@@ -1032,20 +1049,18 @@
         }
         project.disableJava8TargetObsoleteWarnings()
 
-        val defaultMinSdkVersion = project.defaultAndroidConfig.minSdk
-        val defaultCompileSdkVersion = project.defaultAndroidConfig.compileSdk
+        val defaultMinSdk = project.defaultAndroidConfig.minSdk
+        val defaultCompileSdk = project.defaultAndroidConfig.compileSdk
 
         // Suppress output of android:compileSdkVersion and related attributes (b/277836549).
-        aaptOptions.additionalParameters += "--no-compile-sdk-metadata"
+        androidResources.additionalParameters += "--no-compile-sdk-metadata"
 
-        // Specify default values. The client may attempt to override these in their build.gradle,
-        // so we'll need to perform validation in afterEvaluate().
-        compileSdkVersion(defaultCompileSdkVersion)
+        compileSdk = project.defaultAndroidConfig.compileSdk
+
         buildToolsVersion = project.defaultAndroidConfig.buildToolsVersion
         ndkVersion = project.defaultAndroidConfig.ndkVersion
 
-        defaultConfig.minSdk = defaultMinSdkVersion
-        defaultConfig.targetSdk = project.defaultAndroidConfig.targetSdk
+        defaultConfig.minSdk = defaultMinSdk
         defaultConfig.testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
 
         testOptions.animationsDisabled = !project.isMacrobenchmark()
@@ -1059,14 +1074,15 @@
 
         project.afterEvaluate {
             val minSdkVersion = defaultConfig.minSdk!!
-            check(minSdkVersion >= defaultMinSdkVersion) {
-                "minSdkVersion $minSdkVersion lower than the default of $defaultMinSdkVersion"
+            check(minSdkVersion >= defaultMinSdk) {
+                "minSdkVersion $minSdkVersion lower than the default of $defaultMinSdk"
             }
             check(
-                compileSdkVersion == defaultCompileSdkVersion || project.isCustomCompileSdkAllowed()
+                compileSdk == defaultCompileSdk || project.isCustomCompileSdkAllowed()
             ) {
-                "compileSdkVersion must not be explicitly specified, was \"$compileSdkVersion\""
+                "compileSdk must not be explicitly specified, was \"$compileSdk\""
             }
+
            project.enforceBanOnVersionRanges()
 
             if (androidXExtension.type.compilationTarget != CompilationTarget.DEVICE) {
@@ -1077,14 +1093,6 @@
             }
         }
 
-        val debugSigningConfig = signingConfigs.getByName("debug")
-        // Use a local debug keystore to avoid build server issues.
-        debugSigningConfig.storeFile = project.getKeystore()
-        buildTypes.all { buildType ->
-            // Sign all the builds (including release) with debug key
-            buildType.signingConfig = debugSigningConfig
-        }
-
         project.configureErrorProneForAndroid()
 
         // workaround for b/120487939
@@ -1118,9 +1126,9 @@
         componentsExtension: KotlinMultiplatformAndroidComponentsExtension
     ) {
         val defaultMinSdkVersion = project.defaultAndroidConfig.minSdk
-        val defaultCompileSdkVersion = project.defaultAndroidConfig.compileSdkInt()
+        val defaultCompileSdk = project.defaultAndroidConfig.compileSdk
 
-        compileSdk = defaultCompileSdkVersion
+        compileSdk = defaultCompileSdk
         buildToolsVersion = project.defaultAndroidConfig.buildToolsVersion
 
         minSdk = defaultMinSdkVersion
@@ -1151,9 +1159,9 @@
                 "minSdkVersion $minSdkVersion lower than the default of $defaultMinSdkVersion"
             }
             check(
-                compileSdk == defaultCompileSdkVersion || project.isCustomCompileSdkAllowed()
+                compileSdk == defaultCompileSdk || project.isCustomCompileSdkAllowed()
             ) {
-                "compileSdkVersion must not be explicitly specified, was \"$compileSdk\""
+                "compileSdk must not be explicitly specified, was \"$compileSdk\""
             }
             project.enforceBanOnVersionRanges()
         }
@@ -1165,24 +1173,6 @@
         project.configureFtlRunner(componentsExtension)
     }
 
-    @Suppress("UnstableApiUsage") // finalizeDsl, minCompileSdkExtension
-    private fun LibraryExtension.configureAndroidLibraryOptions(
-        project: Project,
-        androidXExtension: AndroidXExtension
-    ) {
-        // Propagate the compileSdk value into minCompileSdk. Don't propagate compileSdkExtension,
-        // since only one library actually depends on the extension APIs and they can explicitly
-        // declare that in their build.gradle. Note that when we're using a preview SDK, the value
-        // for compileSdk will be null and the resulting AAR metadata won't have a minCompileSdk --
-        // this is okay because AGP automatically embeds forceCompileSdkPreview in the AAR metadata
-        // and uses it instead of minCompileSdk.
-        project.extensions.findByType<LibraryAndroidComponentsExtension>()!!.finalizeDsl {
-            it.defaultConfig.aarMetadata.minCompileSdk = it.compileSdk
-        }
-        project.disableStrictVersionConstraints()
-        project.setPublishProperty(androidXExtension)
-    }
-
     private fun KotlinMultiplatformAndroidTarget.configureAndroidLibraryOptions(
         project: Project,
         androidXExtension: AndroidXExtension
@@ -1270,7 +1260,7 @@
         // Configure all KMP targets to allow expect/actual classes that are not stable.
         // (see https://youtrack.jetbrains.com/issue/KT-61573)
         kmpExtension.targets.all { kotlinTarget ->
-            kotlinTarget.compilations.all {
+            kotlinTarget.compilations.configureEach {
                 it.compilerOptions.options.freeCompilerArgs.add("-Xexpect-actual-classes")
             }
         }
@@ -1381,11 +1371,11 @@
             }
 
             // disallow duplicate constraints
-            project.configurations.all { config ->
+            project.configurations.configureEach { config ->
                 // Allow duplicate constraints in test configurations. This is partially a
                 // workaround for duplication due to downgrading strict-type dependencies to
                 // required-type, but also we don't care if tests have duplicate constraints.
-                if (config.isTest()) return@all
+                if (config.isTest()) return@configureEach
 
                 // find all constraints contributed by this Configuration and its ancestors
                 val configurationConstraints: MutableSet<String> = mutableSetOf()
@@ -1427,27 +1417,6 @@
         return true
     }
 
-    private fun Project.createVariantAarManifestTransformerTask(
-        variantName: String,
-        artifacts: Artifacts
-    ) {
-        // Remove the android:targetSdkVersion element from the manifest used for AARs.
-        tasks
-            .register(
-                variantName + "AarManifestTransformer",
-                AarManifestTransformerTask::class.java
-            )
-            .let { taskProvider ->
-                artifacts
-                    .use(taskProvider)
-                    .wiredWithFiles(
-                        AarManifestTransformerTask::aarFile,
-                        AarManifestTransformerTask::updatedAarFile
-                    )
-                    .toTransform(SingleArtifact.AAR)
-            }
-    }
-
     companion object {
         const val CREATE_LIBRARY_BUILD_INFO_FILES_TASK = "createLibraryBuildInfoFiles"
         const val GENERATE_TEST_CONFIGURATION_TASK = "GenerateTestConfiguration"
@@ -1683,8 +1652,6 @@
     }
 }
 
-private fun AndroidConfig.compileSdkInt() = compileSdk.removePrefix("android-").toInt()
-
 private fun Test.configureForRobolectric() {
     // https://github.com/robolectric/robolectric/issues/7456
     jvmArgs =
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/dackka/DackkaTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/dackka/DackkaTask.kt
index 3eaafa9..ccc74a1 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/dackka/DackkaTask.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/dackka/DackkaTask.kt
@@ -67,9 +67,18 @@
     @get:[InputFiles PathSensitive(PathSensitivity.RELATIVE)]
     abstract val frameworkSamplesDir: DirectoryProperty
 
-    // Directory containing the code samples
+    // Directory containing the code samples derived via the old method. This will be removed
+    // as soon as all libraries have been published with samples. b/329424152
     @get:[InputFiles PathSensitive(PathSensitivity.RELATIVE)]
-    abstract val samplesDir: DirectoryProperty
+    abstract val samplesDeprecatedDir: DirectoryProperty
+
+    // Directory containing the code samples for non-KMP libraries
+    @get:[InputFiles PathSensitive(PathSensitivity.RELATIVE)]
+    abstract val samplesJvmDir: DirectoryProperty
+
+    // Directory containing the code samples for KMP libraries
+    @get:[InputFiles PathSensitive(PathSensitivity.RELATIVE)]
+    abstract val samplesKmpDir: DirectoryProperty
 
     // Directory containing the JVM source code for Dackka to process
     @get:[InputFiles PathSensitive(PathSensitivity.RELATIVE)]
@@ -153,7 +162,9 @@
                             // samples are in common
                             samples = if (analysisPlatform == DokkaAnalysisPlatform.COMMON) {
                                 objects.fileCollection().from(
-                                    samplesDir,
+                                    samplesDeprecatedDir,
+                                    samplesJvmDir,
+                                    samplesKmpDir,
                                     frameworkSamplesDir.get().asFile
                                 )
                             } else {
@@ -179,7 +190,9 @@
                 analysisPlatform = "jvm",
                 sourceRoots = objects.fileCollection().from(jvmSourcesDir),
                 samples = objects.fileCollection().from(
-                    samplesDir,
+                    samplesDeprecatedDir,
+                    samplesJvmDir,
+                    samplesKmpDir,
                     frameworkSamplesDir.get().asFile
                 ),
                 includes = objects.fileCollection().from(includesFiles(jvmSourcesDir.get().asFile)),
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 4cd160c..c73c126 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/docs/AndroidXDocsImplPlugin.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/docs/AndroidXDocsImplPlugin.kt
@@ -32,13 +32,14 @@
 import androidx.build.versionCatalog
 import androidx.build.workaroundPrebuiltTakingPrecedenceOverProject
 import com.android.build.api.attributes.BuildTypeAttr
-import com.android.build.gradle.LibraryExtension
+import com.android.build.api.dsl.LibraryExtension
 import com.android.build.gradle.LibraryPlugin
 import com.google.gson.GsonBuilder
 import java.io.File
 import java.io.FileNotFoundException
 import java.time.Duration
 import java.time.LocalDateTime
+import java.util.concurrent.TimeUnit
 import javax.inject.Inject
 import org.gradle.api.DefaultTask
 import org.gradle.api.Plugin
@@ -103,7 +104,7 @@
             when (plugin) {
                 is LibraryPlugin -> {
                     val libraryExtension = project.extensions.getByType<LibraryExtension>()
-                    libraryExtension.compileSdkVersion = project.defaultAndroidConfig.compileSdk
+                    libraryExtension.compileSdk = project.defaultAndroidConfig.compileSdk
                     libraryExtension.buildToolsVersion =
                         project.defaultAndroidConfig.buildToolsVersion
 
@@ -126,15 +127,19 @@
                 distributionDirectory = project.getDistributionDirectory()
             }
 
-        val unzippedSamplesSources = project.layout.buildDirectory.dir("unzippedSampleSources")
-        val unzipSamplesTask =
+        val unzippedDeprecatedSamplesSources =
+            project.layout.buildDirectory.dir("unzippedDeprecatedSampleSources")
+        val deprecatedUnzipSamplesTask =
             configureUnzipTask(
                 project,
-                "unzipSampleSources",
-                unzippedSamplesSources,
+                "unzipSampleSourcesDeprecated",
+                unzippedDeprecatedSamplesSources,
                 samplesSourcesConfiguration
             )
-
+        val unzippedKmpSamplesSourcesDirectory =
+            project.layout.buildDirectory.dir("unzippedMultiplatformSampleSources")
+        val unzippedJvmSamplesSourcesDirectory =
+            project.layout.buildDirectory.dir("unzippedJvmSampleSources")
         val unzippedJvmSourcesDirectory = project.layout.buildDirectory.dir("unzippedJvmSources")
         val unzippedMultiplatformSourcesDirectory =
             project.layout.buildDirectory.dir("unzippedMultiplatformSources")
@@ -142,33 +147,38 @@
             project.layout.buildDirectory.file(
                 "project_metadata/$PROJECT_STRUCTURE_METADATA_FILENAME"
             )
-        val unzipJvmSourcesTask =
+        val (unzipJvmSourcesTask, unzipJvmSamplesTask) =
             configureUnzipJvmSourcesTasks(
                 project,
                 unzippedJvmSourcesDirectory,
+                unzippedJvmSamplesSourcesDirectory,
                 docsSourcesConfiguration
             )
         val configureMultiplatformSourcesTask =
             configureMultiplatformInputsTasks(
                 project,
                 unzippedMultiplatformSourcesDirectory,
+                unzippedKmpSamplesSourcesDirectory,
                 multiplatformDocsSourcesConfiguration,
                 mergedProjectMetadata
             )
 
         configureDackka(
-            project,
-            unzippedJvmSourcesDirectory,
-            unzippedMultiplatformSourcesDirectory,
-            unzipJvmSourcesTask,
-            configureMultiplatformSourcesTask,
-            unzippedSamplesSources,
-            unzipSamplesTask,
-            dependencyClasspath,
-            buildOnServer,
-            docsSourcesConfiguration,
-            multiplatformDocsSourcesConfiguration,
-            mergedProjectMetadata
+            project = project,
+            unzippedJvmSourcesDirectory = unzippedJvmSourcesDirectory,
+            unzippedMultiplatformSourcesDirectory = unzippedMultiplatformSourcesDirectory,
+            unzipJvmSourcesTask = unzipJvmSourcesTask,
+            configureMultiplatformSourcesTask = configureMultiplatformSourcesTask,
+            unzippedDeprecatedSamplesSources = unzippedDeprecatedSamplesSources,
+            unzipDeprecatedSamplesTask = deprecatedUnzipSamplesTask,
+            unzippedJvmSamplesSources = unzippedJvmSamplesSourcesDirectory,
+            unzipJvmSamplesTask = unzipJvmSamplesTask,
+            unzippedKmpSamplesSources = unzippedKmpSamplesSourcesDirectory,
+            dependencyClasspath = dependencyClasspath,
+            buildOnServer = buildOnServer,
+            docsConfiguration = docsSourcesConfiguration,
+            multiplatformDocsConfiguration = multiplatformDocsSourcesConfiguration,
+            mergedProjectMetadata = mergedProjectMetadata
         )
 
         project.configureTaskTimeouts()
@@ -214,36 +224,45 @@
     }
 
     /**
-     * Creates and configures a task that will build a list of select sources from jars and places
-     * them in [destinationDirectory].
+     * Creates and configures a task that builds a list of select sources from jars and places them
+     * in [sourcesDestinationDirectory], partitioning samples into [samplesDestinationDirectory].
      *
      * This is a modified version of [configureUnzipTask], customized for Dackka usage.
      */
     private fun configureUnzipJvmSourcesTasks(
         project: Project,
-        destinationDirectory: Provider<Directory>,
+        sourcesDestinationDirectory: Provider<Directory>,
+        samplesDestinationDirectory: Provider<Directory>,
         docsConfiguration: Configuration
-    ): TaskProvider<Sync> {
+    ): Pair<TaskProvider<Sync>, TaskProvider<Sync>> {
+        val pairProvider = docsConfiguration.incoming.artifactView {}.files.elements.map {
+            it.map { it.asFile }.toSortedSet().partition { "samples" !in it.toString() }
+        }
         return project.tasks.register("unzipJvmSources", Sync::class.java) { task ->
-            val sources = docsConfiguration.incoming.artifactView {}.files
-
             // Store archiveOperations into a local variable to prevent access to the plugin
             // during the task execution, as that breaks configuration caching.
             val localVar = archiveOperations
-            task.into(destinationDirectory)
+            task.into(sourcesDestinationDirectory)
             task.from(
-                sources.elements.map { jars ->
-                    // Now that we publish sample jars, they can get confused with normal source
-                    // jars. We want to handle sample jars separately, so filter by the name.
-                    jars.filter { "samples" !in it.toString() }
-                        .map { it.asFile }.toSortedSet().map { jar ->
-                        localVar.zipTree(jar).matching { it.exclude("**/META-INF/MANIFEST.MF") }
-                    }
-                }
+                pairProvider.map { it.first }.map { it.map { jar ->
+                    localVar.zipTree(jar).matching { it.exclude("**/META-INF/MANIFEST.MF") }
+                } }
             )
             // Files with the same path in different source jars of the same library will lead to
             // some classes/methods not appearing in the docs.
             task.duplicatesStrategy = DuplicatesStrategy.WARN
+        } to project.tasks.register("unzipSampleSources", Sync::class.java) { task ->
+            // Store archiveOperations into a local variable to prevent access to the plugin
+            // during the task execution, as that breaks configuration caching.
+            val localVar = archiveOperations
+            task.into(samplesDestinationDirectory)
+            task.from(
+                pairProvider.map { it.second }.map { it.map { jar ->
+                    localVar.zipTree(jar).matching { it.exclude("**/META-INF/MANIFEST.MF") }
+                } }
+            )
+            // We expect this to happen when multiple libraries use the same sample, e.g. paging.
+            task.duplicatesStrategy = DuplicatesStrategy.INCLUDE
         }
     }
 
@@ -254,6 +273,7 @@
     private fun configureMultiplatformInputsTasks(
         project: Project,
         unzippedMultiplatformSourcesDirectory: Provider<Directory>,
+        unzippedMultiplatformSamplesDirectory: Provider<Directory>,
         multiplatformDocsSourcesConfiguration: Configuration,
         mergedProjectMetadata: Provider<RegularFile>
     ): TaskProvider<MergeMultiplatformMetadataTask> {
@@ -270,6 +290,7 @@
                 )
                 it.metadataOutput.set(tempMultiplatformMetadataDirectory)
                 it.sourceOutput.set(unzippedMultiplatformSourcesDirectory)
+                it.samplesOutput.set(unzippedMultiplatformSamplesDirectory)
             }
         // merge all the metadata files from the individual project dirs
         return project.tasks.register(
@@ -457,8 +478,11 @@
         unzippedMultiplatformSourcesDirectory: Provider<Directory>,
         unzipJvmSourcesTask: TaskProvider<Sync>,
         configureMultiplatformSourcesTask: TaskProvider<MergeMultiplatformMetadataTask>,
-        unzippedSamplesSources: Provider<Directory>,
-        unzipSamplesTask: TaskProvider<Sync>,
+        unzippedDeprecatedSamplesSources: Provider<Directory>,
+        unzipDeprecatedSamplesTask: TaskProvider<Sync>,
+        unzippedJvmSamplesSources: Provider<Directory>,
+        unzipJvmSamplesTask: TaskProvider<Sync>,
+        unzippedKmpSamplesSources: Provider<Directory>,
         dependencyClasspath: FileCollection,
         buildOnServer: TaskProvider<*>,
         docsConfiguration: Configuration,
@@ -506,7 +530,8 @@
                     // Use samplesDir.set(unzipSamplesTask.flatMap { it.destinationDirectory })
                     // https://github.com/gradle/gradle/issues/25824
                     dependsOn(unzipJvmSourcesTask)
-                    dependsOn(unzipSamplesTask)
+                    dependsOn(unzipJvmSamplesTask)
+                    dependsOn(unzipDeprecatedSamplesTask)
                     dependsOn(configureMultiplatformSourcesTask)
 
                     description =
@@ -519,7 +544,9 @@
                     frameworkSamplesDir.set(
                         project.rootProject.layout.projectDirectory.dir("samples")
                     )
-                    samplesDir.set(unzippedSamplesSources)
+                    samplesDeprecatedDir.set(unzippedDeprecatedSamplesSources)
+                    samplesJvmDir.set(unzippedJvmSamplesSources)
+                    samplesKmpDir.set(unzippedKmpSamplesSources)
                     jvmSourcesDir.set(unzippedJvmSourcesDirectory)
                     multiplatformSourcesDir.set(unzippedMultiplatformSourcesDirectory)
                     projectListsDirectory.set(
@@ -551,6 +578,18 @@
                     )
                     task.doFirst { taskStartTime = LocalDateTime.now() }
                     task.doLast {
+                        val cpus = try {
+                            ProcessBuilder("lscpu").start()
+                                .apply { waitFor(100L, TimeUnit.MILLISECONDS) }
+                                .inputStream.bufferedReader().readLines()
+                                .filter { it.startsWith("CPU(s):") }.singleOrNull()
+                                ?.split(" ")?.last()?.toInt()
+                        } catch (e: java.io.IOException) { null } // not running on linux
+                        if (cpus != 64) { // Keep stddev of build metrics low b/334867245
+                            println("$cpus cpus, so not storing build metrics.")
+                            return@doLast
+                        }
+                        println("$cpus cpus, so storing build metrics.")
                         val taskEndTime = LocalDateTime.now()
                         val duration = Duration.between(taskStartTime, taskEndTime).toMillis()
                         metricsFile
@@ -759,24 +798,33 @@
     @get:OutputDirectory abstract val metadataOutput: DirectoryProperty
 
     @get:OutputDirectory abstract val sourceOutput: DirectoryProperty
+    @get:OutputDirectory abstract val samplesOutput: DirectoryProperty
 
     @get:Inject abstract val fileSystemOperations: FileSystemOperations
     @get:Inject abstract val archiveOperations: ArchiveOperations
 
     @TaskAction
     fun execute() {
-        val sources = inputJars.get()
+        val (sources, samples) = inputJars.get()
+            .associate { it.name to archiveOperations.zipTree(it) }.toSortedMap()
             // Now that we publish sample jars, they can get confused with normal source
             // jars. We want to handle sample jars separately, so filter by the name.
-            .filter { "samples" !in it.toString() }
-            .associate { it.name to archiveOperations.zipTree(it) }
-            .toSortedMap()
+            .partition { name -> "samples" !in name }
         fileSystemOperations.sync {
             it.duplicatesStrategy = DuplicatesStrategy.FAIL
             it.from(sources.values)
             it.into(sourceOutput)
             it.exclude("META-INF/*")
         }
+        fileSystemOperations.sync {
+            // Some libraries share samples, e.g. paging. This can be an issue if and only if the
+            // consumer libraries have pinned samples version or are not in an atomic group.
+            // We don't have anything matching this case now, but should enforce better. b/334825580
+            it.duplicatesStrategy = DuplicatesStrategy.INCLUDE
+            it.from(samples.values)
+            it.into(samplesOutput)
+            it.exclude("META-INF/*")
+        }
         sources.forEach { (name, fileTree) ->
             fileSystemOperations.sync {
                 it.from(fileTree)
@@ -786,6 +834,8 @@
         }
     }
 }
+private fun <K, V> Map<K, V>.partition(condition: (K) -> Boolean): Pair<Map<K, V>, Map<K, V>> =
+    this.toList().partition { (k, _) -> condition(k) }.let { it.first.toMap() to it.second.toMap() }
 
 /** Merges multiplatform metadata files created by [CreateMultiplatformMetadata] */
 @CacheableTask
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/docs/CheckTipOfTreeDocsTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/docs/CheckTipOfTreeDocsTask.kt
index 46685ce..1d52976 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/docs/CheckTipOfTreeDocsTask.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/docs/CheckTipOfTreeDocsTask.kt
@@ -138,7 +138,6 @@
          * unless opted-out with [AndroidXExtension.doNotDocumentReason]
          */
         fun AndroidXExtension.requiresDocs() =
-            (shouldConfigureApiTasks() || type == LibraryType.SAMPLES) &&
-                doNotDocumentReason == null
+            shouldConfigureApiTasks() && doNotDocumentReason == null
     }
 }
diff --git a/buildSrc/public/src/main/kotlin/androidx/build/AndroidXConfig.kt b/buildSrc/public/src/main/kotlin/androidx/build/AndroidXConfig.kt
index 32459f5..4556a22 100644
--- a/buildSrc/public/src/main/kotlin/androidx/build/AndroidXConfig.kt
+++ b/buildSrc/public/src/main/kotlin/androidx/build/AndroidXConfig.kt
@@ -26,7 +26,7 @@
 abstract class AndroidConfigImpl(private val project: Project) : AndroidConfig {
     override val buildToolsVersion: String = "35.0.0-rc1"
 
-    override val compileSdk: String by lazy { project.findProperty(COMPILE_SDK_VERSION).toString() }
+    override val compileSdk: Int by lazy { project.findProperty(COMPILE_SDK).toString().toInt() }
 
     override val minSdk: Int = 19
     override val ndkVersion: String = "25.2.9519653"
@@ -36,7 +36,7 @@
     }
 
     companion object {
-        private const val COMPILE_SDK_VERSION = "androidx.compileSdkVersion"
+        private const val COMPILE_SDK = "androidx.compileSdk"
         private const val TARGET_SDK_VERSION = "androidx.targetSdkVersion"
 
         /**
@@ -45,7 +45,7 @@
          */
         val GRADLE_PROPERTIES =
             listOf(
-                COMPILE_SDK_VERSION,
+                COMPILE_SDK,
                 TARGET_SDK_VERSION,
             )
     }
@@ -53,7 +53,7 @@
 
 /**
  * Configuration values for various aspects of the AndroidX plugin, including default values for
- * [com.android.build.gradle.BaseExtension].
+ * [com.android.build.api.dsl.CommonExtension].
  */
 interface AndroidConfig {
     /** Build tools version used for AndroidX projects. */
@@ -62,9 +62,9 @@
     /**
      * Default compile SDK version used for AndroidX projects.
      *
-     * This may be specified in `gradle.properties` using `androidx.compileSdkVersion`.
+     * This may be specified in `gradle.properties` using `androidx.compileSdk`.
      */
-    val compileSdk: String
+    val compileSdk: Int
 
     /** Default minimum SDK version used for AndroidX projects. */
     val minSdk: Int
@@ -100,7 +100,7 @@
 
 /** @return the project's Android SDK stub JAR as a File. */
 fun Project.getAndroidJar(): FileCollection {
-    val compileSdk = project.defaultAndroidConfig.compileSdk
+    val compileSdk = "android-${project.defaultAndroidConfig.compileSdk}"
     return files(
         arrayOf(
             File(getSdkPath(), "platforms/$compileSdk/android.jar"),
diff --git a/buildSrc/public/src/main/kotlin/androidx/build/SdkHelper.kt b/buildSrc/public/src/main/kotlin/androidx/build/SdkHelper.kt
index 447a6f1..9b9c338 100644
--- a/buildSrc/public/src/main/kotlin/androidx/build/SdkHelper.kt
+++ b/buildSrc/public/src/main/kotlin/androidx/build/SdkHelper.kt
@@ -43,7 +43,7 @@
 
 /** Returns a file tree representing the platform SDK suitable for use as a dependency. */
 fun Project.getSdkDependency(): FileTree =
-    fileTree("${getSdkPath()}/platforms/${project.defaultAndroidConfig.compileSdk}/") {
+    fileTree("${getSdkPath()}/platforms/android-${project.defaultAndroidConfig.compileSdk}/") {
         it.include("android.jar")
     }
 
@@ -99,7 +99,7 @@
 
 /** Sets the path to the canonical root project directory, e.g. {@code frameworks/support}. */
 fun Project.setSupportRootFolder(rootDir: File?) {
-    val extension = project.rootProject.property("ext") as ExtraPropertiesExtension
+    val extension = project.property("ext") as ExtraPropertiesExtension
     return extension.set("supportRootFolder", rootDir)
 }
 
@@ -110,7 +110,7 @@
  * because it is generalized to also work for the "ui" project and playground projects.
  */
 fun Project.getSupportRootFolder(): File {
-    val extension = project.rootProject.property("ext") as ExtraPropertiesExtension
+    val extension = project.property("ext") as ExtraPropertiesExtension
     return extension.get("supportRootFolder") as File
 }
 
diff --git a/buildSrc/public/src/main/kotlin/androidx/build/SdkResourceGenerator.kt b/buildSrc/public/src/main/kotlin/androidx/build/SdkResourceGenerator.kt
index 0621449..210112c 100644
--- a/buildSrc/public/src/main/kotlin/androidx/build/SdkResourceGenerator.kt
+++ b/buildSrc/public/src/main/kotlin/androidx/build/SdkResourceGenerator.kt
@@ -46,7 +46,7 @@
     @get:[InputFile PathSensitive(PathSensitivity.NONE)]
     abstract val debugKeystore: RegularFileProperty
 
-    @get:Input abstract val compileSdkVersion: Property<String>
+    @get:Input abstract val compileSdk: Property<Int>
 
     @get:Input abstract val buildToolsVersion: Property<String>
 
@@ -101,7 +101,7 @@
             writer.write("agpDependency=$agpDependency\n")
             writer.write("navigationRuntime=$navigationRuntime\n")
             writer.write("kotlinStdlib=${kotlinStdlib.get()}\n")
-            writer.write("compileSdkVersion=${compileSdkVersion.get()}\n")
+            writer.write("compileSdk=${compileSdk.get()}\n")
             writer.write("buildToolsVersion=${buildToolsVersion.get()}\n")
             writer.write("minSdkVersion=${minSdkVersion.get()}\n")
             writer.write("kgpVersion=${kgpVersion.get()}\n")
@@ -135,7 +135,7 @@
                     project.provider { project.defaultAndroidConfig.buildToolsVersion }
                 )
                 it.minSdkVersion.set(project.defaultAndroidConfig.minSdk)
-                it.compileSdkVersion.set(project.defaultAndroidConfig.compileSdk)
+                it.compileSdk.set(project.defaultAndroidConfig.compileSdk)
                 it.kotlinStdlib.set(
                     project.androidXConfiguration.kotlinBomVersion.map { version ->
                         "org.jetbrains.kotlin:kotlin-stdlib:$version"
diff --git a/busytown/androidx_incremental.sh b/busytown/androidx_incremental.sh
index fa615c8..810d4e4 100755
--- a/busytown/androidx_incremental.sh
+++ b/busytown/androidx_incremental.sh
@@ -10,7 +10,7 @@
 if [ "$DIST_DIR" == "" ]; then
   DIST_DIR="$OUT_DIR/dist"
 fi
-if [ "$MANIFEST" == "" ]; then
+if [ "$MANIFEST" == "" -a "$CHANGE_INFO" != "" ]; then
   export MANIFEST="$DIST_DIR/manifest_${BUILD_NUMBER}.xml"
 fi
 # move OUT_DIR and DIST_DIR into subdirectories so that if anything deletes them, it doesn't interfere with any files generated by buildbot code
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
index da5bda2..a8b4d15 100644
--- 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
@@ -17,7 +17,9 @@
 package androidx.camera.camera2.pipe.integration.adapter
 
 import android.annotation.SuppressLint
+import android.hardware.camera2.CameraCharacteristics
 import android.util.Range
+import android.view.Surface
 import androidx.annotation.RequiresApi
 import androidx.camera.camera2.pipe.UnsafeWrapper
 import androidx.camera.camera2.pipe.integration.impl.CameraProperties
@@ -31,6 +33,7 @@
 import androidx.camera.core.ExposureState
 import androidx.camera.core.FocusMeteringAction
 import androidx.camera.core.ZoomState
+import androidx.camera.core.impl.utils.CameraOrientationUtil
 import androidx.lifecycle.LiveData
 import kotlin.reflect.KClass
 
@@ -38,6 +41,9 @@
  * Implementation of [CameraInfo] for physical camera. In comparison,
  * [CameraInfoAdapter] is the version of logical camera.
  */
+@SuppressLint(
+    "UnsafeOptInUsageError" // Suppressed due to experimental API
+)
 @RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
 class PhysicalCameraInfoAdapter(
     private val cameraProperties: CameraProperties
@@ -48,12 +54,23 @@
         Camera2CameraInfo.create(cameraProperties)
     }
 
-    override fun getSensorRotationDegrees(): Int {
-        throw UnsupportedOperationException("Physical camera doesn't support this function")
-    }
+    override fun getSensorRotationDegrees(): Int = getSensorRotationDegrees(Surface.ROTATION_0)
 
     override fun getSensorRotationDegrees(relativeRotation: Int): Int {
-        throw UnsupportedOperationException("Physical camera doesn't support this function")
+        val sensorOrientation: Int =
+            cameraProperties.metadata[CameraCharacteristics.SENSOR_ORIENTATION]!!
+        val relativeRotationDegrees =
+            CameraOrientationUtil.surfaceRotationToDegrees(relativeRotation)
+        // Currently this assumes that a back-facing camera is always opposite to the screen.
+        // This may not be the case for all devices, so in the future we may need to handle that
+        // scenario.
+        val lensFacing = lensFacing
+        val isOppositeFacingScreen = CameraSelector.LENS_FACING_BACK == lensFacing
+        return CameraOrientationUtil.getRelativeImageRotation(
+            relativeRotationDegrees,
+            sensorOrientation,
+            isOppositeFacingScreen
+        )
     }
 
     override fun hasFlashUnit(): Boolean {
@@ -84,9 +101,8 @@
         throw UnsupportedOperationException("Physical camera doesn't support this function")
     }
 
-    override fun getLensFacing(): Int {
-        throw UnsupportedOperationException("Physical camera doesn't support this function")
-    }
+    override fun getLensFacing(): Int =
+        getCameraSelectorLensFacing(cameraProperties.metadata[CameraCharacteristics.LENS_FACING]!!)
 
     override fun getIntrinsicZoomRatio(): Float {
         throw UnsupportedOperationException("Physical camera doesn't support this function")
@@ -132,4 +148,16 @@
             else -> cameraProperties.metadata.unwrapAs(type)
         }
     }
+
+    @CameraSelector.LensFacing
+    private fun getCameraSelectorLensFacing(lensFacingInt: Int): Int {
+        return when (lensFacingInt) {
+            CameraCharacteristics.LENS_FACING_FRONT -> CameraSelector.LENS_FACING_FRONT
+            CameraCharacteristics.LENS_FACING_BACK -> CameraSelector.LENS_FACING_BACK
+            CameraCharacteristics.LENS_FACING_EXTERNAL -> CameraSelector.LENS_FACING_EXTERNAL
+            else -> throw IllegalArgumentException(
+                "The specified lens facing integer $lensFacingInt can not be recognized."
+            )
+        }
+    }
 }
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/ApiCompat.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/ApiCompat.kt
new file mode 100644
index 0000000..8278f79
--- /dev/null
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/ApiCompat.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.camera2.pipe.integration.compat
+
+import android.hardware.camera2.CameraCaptureSession
+import android.hardware.camera2.CaptureRequest
+import android.os.Build
+import android.view.Surface
+import androidx.annotation.DoNotInline
+import androidx.annotation.RequiresApi
+
+@RequiresApi(Build.VERSION_CODES.N)
+internal object Api24Compat {
+    @DoNotInline
+    @JvmStatic
+    fun onCaptureBufferLost(
+        callback: CameraCaptureSession.CaptureCallback,
+        session: CameraCaptureSession,
+        request: CaptureRequest,
+        surface: Surface,
+        frameNumber: Long
+    ) {
+        callback.onCaptureBufferLost(
+            session, request, surface, frameNumber
+        )
+    }
+}
+
+@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+internal object Api34Compat {
+    @DoNotInline
+    @JvmStatic
+    fun onReadoutStarted(
+        callback: CameraCaptureSession.CaptureCallback,
+        session: CameraCaptureSession,
+        request: CaptureRequest,
+        timestamp: Long,
+        frameNumber: Long
+    ) {
+        callback.onReadoutStarted(
+            session, request, timestamp, frameNumber
+        )
+    }
+}
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/CameraCallbackMap.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/CameraCallbackMap.kt
index 10ac90e..534e582 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/CameraCallbackMap.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/CameraCallbackMap.kt
@@ -23,7 +23,6 @@
 import android.hardware.camera2.TotalCaptureResult
 import android.os.Build
 import android.view.Surface
-import androidx.annotation.DoNotInline
 import androidx.annotation.RequiresApi
 import androidx.camera.camera2.pipe.CameraTimestamp
 import androidx.camera.camera2.pipe.FrameInfo
@@ -32,9 +31,12 @@
 import androidx.camera.camera2.pipe.Request
 import androidx.camera.camera2.pipe.RequestFailure
 import androidx.camera.camera2.pipe.RequestMetadata
+import androidx.camera.camera2.pipe.SensorTimestamp
 import androidx.camera.camera2.pipe.StreamId
 import androidx.camera.camera2.pipe.integration.adapter.CameraUseCaseAdapter
 import androidx.camera.camera2.pipe.integration.adapter.CaptureResultAdapter
+import androidx.camera.camera2.pipe.integration.compat.Api24Compat
+import androidx.camera.camera2.pipe.integration.compat.Api34Compat
 import androidx.camera.camera2.pipe.integration.config.CameraScope
 import androidx.camera.core.impl.CameraCaptureCallback
 import androidx.camera.core.impl.CameraCaptureFailure
@@ -85,7 +87,7 @@
                 val surface: Surface? = requestMetadata.streams[stream]
                 if (session != null && request != null && surface != null) {
                     executor.execute {
-                        Api24CompatImpl.onCaptureBufferLost(
+                        Api24Compat.onCaptureBufferLost(
                             callback.captureCallback, session, request, surface, frameNumber.value
                         )
                     }
@@ -253,20 +255,31 @@
         }
     }
 
-    @RequiresApi(24)
-    private object Api24CompatImpl {
-        @DoNotInline
-        @JvmStatic
-        fun onCaptureBufferLost(
-            callback: CameraCaptureSession.CaptureCallback,
-            session: CameraCaptureSession,
-            request: CaptureRequest,
-            surface: Surface,
-            frameNumber: Long
-        ) {
-            callback.onCaptureBufferLost(
-                session, request, surface, frameNumber
-            )
+    override fun onReadoutStarted(
+        requestMetadata: RequestMetadata,
+        frameNumber: FrameNumber,
+        timestamp: SensorTimestamp
+    ) {
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
+            return
+        }
+        for ((callback, executor) in callbacks) {
+            if (callback is CameraUseCaseAdapter.CaptureCallbackContainer) {
+                val session: CameraCaptureSession? =
+                    requestMetadata.unwrapAs(CameraCaptureSession::class)
+                val request: CaptureRequest? = requestMetadata.unwrapAs(CaptureRequest::class)
+                if (session != null && request != null) {
+                    executor.execute {
+                        Api34Compat.onReadoutStarted(
+                            callback.captureCallback,
+                            session,
+                            request,
+                            timestamp.value,
+                            frameNumber.value
+                        )
+                    }
+                }
+            }
         }
     }
 
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/Requests.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/Requests.kt
index 6e00d10..502465c 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/Requests.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/Requests.kt
@@ -164,6 +164,23 @@
         }
 
         /**
+         * onReadoutStarted occurs when the camera device has started reading out the output image
+         * for the request, at the beginning of the sensor image readout. Concretely, it is invoked
+         * right after onCaptureStarted.
+         *
+         * @param requestMetadata the data about the camera2 request that was sent to the camera.
+         * @param frameNumber the android frame number for this capture.
+         * @param timestamp the android timestamp in nanos at the start of camera data readout.
+         * @see android.hardware.camera2.CameraCaptureSession.CaptureCallback.onReadoutStarted
+         */
+        fun onReadoutStarted(
+            requestMetadata: RequestMetadata,
+            frameNumber: FrameNumber,
+            timestamp: SensorTimestamp
+        ) {
+        }
+
+        /**
          * onBufferLost occurs when a CaptureRequest failed to create an image for a given output
          * stream. This method may be invoked multiple times per frame if multiple buffers were
          * lost. This method may not be invoked when an image is lost in some situations.
@@ -362,6 +379,14 @@
 @JvmInline
 value class CameraTimestamp(val value: Long)
 
+/**
+ * This is a timestamp happen at start of readout for a regular request, or the timestamp at the
+ * input image's start of readout for a reprocess request, in nanoseconds.
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+@JvmInline
+value class SensorTimestamp(val value: Long)
+
 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
 fun <T> Request.getOrDefault(key: Metadata.Key<T>, default: T): T = this[key] ?: default
 
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2CaptureSequence.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2CaptureSequence.kt
index 5fd7fcc..a6a1629 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2CaptureSequence.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2CaptureSequence.kt
@@ -33,6 +33,7 @@
 import androidx.camera.camera2.pipe.RequestFailure
 import androidx.camera.camera2.pipe.RequestMetadata
 import androidx.camera.camera2.pipe.RequestNumber
+import androidx.camera.camera2.pipe.SensorTimestamp
 import androidx.camera.camera2.pipe.StreamId
 import kotlinx.coroutines.CompletableDeferred
 
@@ -127,6 +128,23 @@
         invokeOnRequest(request) { it.onPartialCaptureResult(request, frameNumber, frameMetadata) }
     }
 
+    override fun onReadoutStarted(
+        session: CameraCaptureSession,
+        captureRequest: CaptureRequest,
+        captureTimestamp: Long,
+        captureFrameNumber: Long
+    ) {
+        val requestNumber = readRequestNumber(captureRequest)
+        val readoutTimestamp = SensorTimestamp(captureTimestamp)
+        val frameNumber = FrameNumber(captureFrameNumber)
+
+        // Load the request and throw if we are not able to find an associated request. Under
+        // normal circumstances this should never happen.
+        val request = readRequestMetadata(requestNumber)
+
+        invokeOnRequest(request) { it.onReadoutStarted(request, frameNumber, readoutTimestamp) }
+    }
+
     override fun onCaptureCompleted(
         captureSession: CameraCaptureSession,
         captureRequest: CaptureRequest,
diff --git a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/compat/Camera2CaptureSequenceTest.kt b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/compat/Camera2CaptureSequenceTest.kt
index b408819..e40b8d4 100644
--- a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/compat/Camera2CaptureSequenceTest.kt
+++ b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/compat/Camera2CaptureSequenceTest.kt
@@ -32,6 +32,7 @@
 import androidx.camera.camera2.pipe.RequestFailure
 import androidx.camera.camera2.pipe.RequestMetadata
 import androidx.camera.camera2.pipe.RequestNumber
+import androidx.camera.camera2.pipe.SensorTimestamp
 import androidx.camera.camera2.pipe.StreamId
 import androidx.camera.camera2.pipe.testing.FakeRequestMetadata
 import androidx.camera.camera2.pipe.testing.RobolectricCameraPipeTestRunner
@@ -88,6 +89,16 @@
     }
 
     @Test
+    fun onReadoutStartedTest() {
+        val timestamp: Long = 123456789
+        camera2CaptureSequence.onReadoutStarted(
+            captureSession, captureRequest, timestamp, frameNumber
+        )
+        assertThat(listener.lastFrameNumber?.value).isEqualTo(frameNumber)
+        assertThat(listener.lastSensorTimeStamp?.value).isEqualTo(timestamp)
+    }
+
+    @Test
     fun onCaptureCompletedTest() {
         val totalCaptureResult: TotalCaptureResult = mock()
         whenever(totalCaptureResult.frameNumber).thenReturn(frameNumber)
@@ -119,6 +130,7 @@
         var lastTimeStamp: CameraTimestamp? = null
         var lastFrameInfo: FrameInfo? = null
         var lastRequestFailure: RequestFailure? = null
+        var lastSensorTimeStamp: SensorTimestamp? = null
 
         override fun onStarted(
             requestMetadata: RequestMetadata,
@@ -146,5 +158,14 @@
             lastFrameNumber = frameNumber
             lastRequestFailure = requestFailure
         }
+
+        override fun onReadoutStarted(
+            requestMetadata: RequestMetadata,
+            frameNumber: FrameNumber,
+            timestamp: SensorTimestamp
+        ) {
+            lastFrameNumber = frameNumber
+            lastSensorTimeStamp = timestamp
+        }
     }
 }
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2PhysicalCameraInfoImpl.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2PhysicalCameraInfoImpl.java
index a0050b6..d28e299 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2PhysicalCameraInfoImpl.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2PhysicalCameraInfoImpl.java
@@ -17,7 +17,9 @@
 package androidx.camera.camera2.internal;
 
 import android.annotation.SuppressLint;
+import android.hardware.camera2.CameraCharacteristics;
 import android.util.Range;
+import android.view.Surface;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.RequiresApi;
@@ -34,6 +36,8 @@
 import androidx.camera.core.ExposureState;
 import androidx.camera.core.FocusMeteringAction;
 import androidx.camera.core.ZoomState;
+import androidx.camera.core.impl.utils.CameraOrientationUtil;
+import androidx.core.util.Preconditions;
 import androidx.lifecycle.LiveData;
 
 import java.util.Set;
@@ -73,12 +77,23 @@
 
     @Override
     public int getSensorRotationDegrees() {
-        throw new UnsupportedOperationException("Physical camera doesn't support this function");
+        return getSensorRotationDegrees(Surface.ROTATION_0);
     }
 
     @Override
     public int getSensorRotationDegrees(int relativeRotation) {
-        throw new UnsupportedOperationException("Physical camera doesn't support this function");
+        int sensorOrientation = getSensorOrientation();
+        int relativeRotationDegrees =
+                CameraOrientationUtil.surfaceRotationToDegrees(relativeRotation);
+        // Currently this assumes that a back-facing camera is always opposite to the screen.
+        // This may not be the case for all devices, so in the future we may need to handle that
+        // scenario.
+        final int lensFacing = getLensFacing();
+        boolean isOppositeFacingScreen = CameraSelector.LENS_FACING_BACK == lensFacing;
+        return CameraOrientationUtil.getRelativeImageRotation(
+                relativeRotationDegrees,
+                sensorOrientation,
+                isOppositeFacingScreen);
     }
 
     @Override
@@ -124,7 +139,10 @@
 
     @Override
     public int getLensFacing() {
-        throw new UnsupportedOperationException("Physical camera doesn't support this function");
+        Integer lensFacing = mCameraCharacteristicsCompat.get(CameraCharacteristics.LENS_FACING);
+        Preconditions.checkArgument(lensFacing != null, "Unable to get the lens facing of the "
+                + "camera.");
+        return LensFacingUtil.getCameraSelectorLensFacing(lensFacing);
     }
 
     @Override
@@ -172,4 +190,11 @@
     public Set<CameraInfo> getPhysicalCameraInfos() {
         throw new UnsupportedOperationException("Physical camera doesn't support this function");
     }
+
+    int getSensorOrientation() {
+        Integer sensorOrientation =
+                mCameraCharacteristicsCompat.get(CameraCharacteristics.SENSOR_ORIENTATION);
+        Preconditions.checkNotNull(sensorOrientation);
+        return sensorOrientation;
+    }
 }
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/impl/CameraValidator.java b/camera/camera-core/src/main/java/androidx/camera/core/impl/CameraValidator.java
index 43242b4..5a33d24 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/impl/CameraValidator.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/impl/CameraValidator.java
@@ -113,9 +113,9 @@
         try {
             // Verifies the EXTERNAL camera.
             EXTERNAL_LENS_FACING.select(cameraRepository.getCameras());
+            Logger.d(TAG, "Found a LENS_FACING_EXTERNAL camera");
             availableCameraCount++;
         } catch (IllegalArgumentException e) {
-            Logger.d(TAG, "No camera with LENS_FACING_EXTERNAL characteristic detected", e);
         }
 
         if (exception != null) {
diff --git a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ImageCaptureTest.kt b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ImageCaptureTest.kt
index c77e1e9..315107f 100644
--- a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ImageCaptureTest.kt
+++ b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ImageCaptureTest.kt
@@ -42,6 +42,7 @@
 import androidx.camera.testing.impl.ExifUtil
 import androidx.camera.testing.impl.SurfaceTextureProvider
 import androidx.camera.testing.impl.SurfaceTextureProvider.SurfaceTextureCallback
+import androidx.camera.testing.impl.WakelockEmptyActivityRule
 import androidx.camera.testing.impl.fakes.FakeLifecycleOwner
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.filters.LargeTest
@@ -59,7 +60,6 @@
 import org.junit.Assert.assertTrue
 import org.junit.Assume.assumeTrue
 import org.junit.Before
-import org.junit.Ignore
 import org.junit.Rule
 import org.junit.Test
 import org.junit.rules.TemporaryFolder
@@ -91,6 +91,9 @@
     )
 
     @get:Rule
+    var wakelockEmptyActivityRule = WakelockEmptyActivityRule()
+
+    @get:Rule
     val temporaryFolder = TemporaryFolder(context.cacheDir)
 
     private lateinit var cameraProvider: ProcessCameraProvider
@@ -158,7 +161,6 @@
     }
 
     @Test
-    @Ignore("b/331617278")
     fun canBindToLifeCycleAndTakePicture(): Unit = runBlocking {
         val mockOnImageCapturedCallback = Mockito.mock(
             ImageCapture.OnImageCapturedCallback::class.java
@@ -302,7 +304,6 @@
     }
 
     @Test
-    @Ignore("b/331617278")
     fun canBindToLifeCycleAndTakePicture_diskIo(): Unit = runBlocking {
         val mockOnImageSavedCallback = Mockito.mock(
             ImageCapture.OnImageSavedCallback::class.java
@@ -488,7 +489,6 @@
     }
 
     @Test
-    @Ignore("b/331617278")
     fun canBindToLifeCycleAndTakePictureWithCaptureProcessProgress(): Unit = runBlocking {
         assumeTrue(isCaptureProcessProgressSupported())
 
@@ -525,7 +525,6 @@
     }
 
     @Test
-    @Ignore("b/331617278")
     fun canBindToLifeCycleAndTakePictureWithCaptureProcessProgress_diskIo(): Unit = runBlocking {
         assumeTrue(isCaptureProcessProgressSupported())
 
@@ -564,7 +563,6 @@
         ExifRotationAvailability().isRotationOptionSupported
 
     @Test
-    @Ignore("b/331617278")
     fun canBindToLifeCycleAndTakePictureWithPostview(): Unit = runBlocking {
         assumeTrue(isPostviewSupported())
 
@@ -618,7 +616,6 @@
     }
 
     @Test
-    @Ignore("b/331617278")
     fun canBindToLifeCycleAndTakePictureWithPostview_diskIo(): Unit = runBlocking {
         assumeTrue(isPostviewSupported())
 
@@ -665,7 +662,6 @@
     }
 
     @Test
-    @Ignore("b/331617278")
     fun highResolutionDisabled_whenExtensionsEnabled(): Unit = runBlocking {
         val imageCapture = ImageCapture.Builder().build()
 
diff --git a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/AdvancedSessionProcessorTest.kt b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/AdvancedSessionProcessorTest.kt
index 4cfc33f..3114f4b 100644
--- a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/AdvancedSessionProcessorTest.kt
+++ b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/AdvancedSessionProcessorTest.kt
@@ -90,7 +90,6 @@
 import org.junit.Assume.assumeFalse
 import org.junit.Assume.assumeTrue
 import org.junit.Before
-import org.junit.Ignore
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -171,7 +170,6 @@
     }
 
     @Test
-    @Ignore("b/331617278")
     fun useCasesCanWork_directlyUseOutputSurface() = runBlocking {
         val fakeSessionProcessImpl = FakeSessionProcessImpl(
             // Directly use output surface
@@ -201,7 +199,6 @@
     }
 
     @Test
-    @Ignore("b/331617278")
     fun canInvokeStartTrigger() = runBlocking {
         assumeTrue(ExtensionVersion.isMinimumCompatibleVersion(Version.VERSION_1_3))
         val fakeSessionProcessImpl = FakeSessionProcessImpl()
@@ -227,7 +224,6 @@
     }
 
     @Test
-    @Ignore("b/331617278")
     fun getRealtimeLatencyEstimate_advancedSessionProcessorInvokesSessionProcessorImpl() =
         runBlocking {
             assumeTrue(ExtensionVersion.isMinimumCompatibleVersion(Version.VERSION_1_4))
@@ -248,7 +244,6 @@
 
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
     @Test
-    @Ignore("b/331617278")
     fun isCurrentExtensionTypeAvailableReturnsCorrectFalseValue() =
         runBlocking {
             assumeTrue(ExtensionVersion.isMinimumCompatibleVersion(Version.VERSION_1_4))
@@ -266,7 +261,6 @@
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
     @Suppress("UNCHECKED_CAST")
     @Test
-    @Ignore("b/331617278")
     fun isCurrentExtensionTypeAvailableReturnsCorrectTrueValue() =
         runBlocking {
             assumeTrue(ExtensionVersion.isMinimumCompatibleVersion(Version.VERSION_1_4))
@@ -289,7 +283,6 @@
 
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
     @Test
-    @Ignore("b/331617278")
     fun isExtensionStrengthAvailableReturnsCorrectFalseValue() =
         runBlocking {
             assumeTrue(ExtensionVersion.isMinimumCompatibleVersion(Version.VERSION_1_4))
@@ -307,7 +300,6 @@
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
     @Suppress("UNCHECKED_CAST")
     @Test
-    @Ignore("b/331617278")
     fun isExtensionStrengthAvailableReturnsCorrectTrueValue() =
         runBlocking {
             assumeTrue(ExtensionVersion.isMinimumCompatibleVersion(Version.VERSION_1_4))
@@ -372,7 +364,6 @@
 
     @Test
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
-    @Ignore("b/331617278")
     fun getCurrentExtensionType_advancedSessionProcessorMonitorSessionProcessorImplResults(): Unit =
         runBlocking {
             assumeTrue(ExtensionVersion.isMinimumCompatibleVersion(Version.VERSION_1_4))
@@ -429,7 +420,6 @@
 
     @Test
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
-    @Ignore("b/331617278")
     fun setExtensionStrength_advancedSessionProcessorInvokesSessionProcessorImpl() =
         runBlocking {
             assumeTrue(ExtensionVersion.isMinimumCompatibleVersion(Version.VERSION_1_4))
@@ -511,7 +501,6 @@
     // Surface sharing of YUV format is supported after API 28.
     @SdkSuppress(minSdkVersion = 28)
     @Test
-    @Ignore("b/331617278")
     fun useCasesCanWork_hasSharedSurfaceOutput() = runBlocking {
         assumeAllowsSharedSurface()
         var sharedConfigId = -1
@@ -568,7 +557,6 @@
     // Test if physicalCameraId is set and returned in the image received in the image processor.
     @SdkSuppress(minSdkVersion = 28) // physical camera id is supported in API28+
     @Test
-    @Ignore("b/331617278")
     fun useCasesCanWork_setPhysicalCameraId() = runBlocking {
         assumeAllowsSharedSurface()
         val physicalCameraIdList = getPhysicalCameraId(cameraSelector)
@@ -643,7 +631,6 @@
     }
 
     @Test
-    @Ignore("b/331617278")
     fun canSetSessionTypeFromOemImpl() {
         assumeTrue(ClientVersion.isMinimumCompatibleVersion(Version.VERSION_1_4) &&
             ExtensionVersion.isMinimumCompatibleVersion(Version.VERSION_1_4))
@@ -668,7 +655,6 @@
     }
 
     @Test
-    @Ignore("b/331617278")
     fun defaultSessionType() {
         // 1. Arrange.
         val fakeSessionProcessImpl = FakeSessionProcessImpl()
@@ -690,7 +676,6 @@
     }
 
     @Test
-    @Ignore("b/331617278")
     fun getSupportedPostviewSizeIsCorrect() {
         // 1. Arrange
         val postviewSizes = mutableMapOf(
diff --git a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/sessionprocessor/BasicExtenderSessionProcessorTest.kt b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/sessionprocessor/BasicExtenderSessionProcessorTest.kt
index 301af04..ee5937f 100644
--- a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/sessionprocessor/BasicExtenderSessionProcessorTest.kt
+++ b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/sessionprocessor/BasicExtenderSessionProcessorTest.kt
@@ -101,7 +101,6 @@
 import org.junit.Assume.assumeFalse
 import org.junit.Assume.assumeTrue
 import org.junit.Before
-import org.junit.Ignore
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -206,7 +205,6 @@
     }
 
     @Test
-    @Ignore("b/331617278")
     fun canOutputCorrectly(): Unit = runBlocking {
         val preview = Preview.Builder().build()
         val imageCapture = ImageCapture.Builder().build()
@@ -228,7 +226,6 @@
     }
 
     @Test
-    @Ignore("b/331617278")
     fun canSetSessionTypeFromOem() {
         assumeTrue(ClientVersion.isMinimumCompatibleVersion(Version.VERSION_1_4) &&
             ExtensionVersion.isMinimumCompatibleVersion(Version.VERSION_1_4))
@@ -249,7 +246,6 @@
     }
 
     @Test
-    @Ignore("b/331617278")
     fun setDifferentSessionTypes_throwException() {
         assumeTrue(ClientVersion.isMinimumCompatibleVersion(Version.VERSION_1_4) &&
             ExtensionVersion.isMinimumCompatibleVersion(Version.VERSION_1_4))
@@ -269,7 +265,6 @@
     }
 
     @Test
-    @Ignore("b/331617278")
     fun defaultSessionType() {
         assumeTrue(ClientVersion.isMinimumCompatibleVersion(Version.VERSION_1_4) &&
             ExtensionVersion.isMinimumCompatibleVersion(Version.VERSION_1_4))
@@ -289,7 +284,6 @@
     }
 
     @Test
-    @Ignore("b/331617278")
     fun imageCaptureError(): Unit = runBlocking {
         assumeTrue(hasCaptureProcessor)
         fakeCaptureExtenderImpl = FakeImageCaptureExtenderImpl(
@@ -309,7 +303,6 @@
     }
 
     @Test
-    @Ignore("b/331617278")
     fun canOutputCorrectly_withoutAnalysis(): Unit = runBlocking {
         val preview = Preview.Builder().build()
         val imageCapture = ImageCapture.Builder().build()
@@ -329,7 +322,6 @@
     }
 
     @Test
-    @Ignore("b/331617278")
     fun canOutputCorrectly_setTargetRotation(): Unit = runBlocking {
         assumeTrue(hasCaptureProcessor)
         val preview = Preview.Builder().build()
@@ -346,7 +338,6 @@
     }
 
     @Test
-    @Ignore("b/331617278")
     fun canOutputCorrectlyAfterStopStart(): Unit = runBlocking {
         val preview = Preview.Builder().build()
         val imageCapture = ImageCapture.Builder().build()
@@ -378,7 +369,6 @@
         verifyStillCapture(imageCapture)
     }
 
-    @Ignore("b/331617278")
     @Test
     fun canInvokeEventsInOrder(): Unit = runBlocking {
         val preview = Preview.Builder().build()
@@ -431,7 +421,6 @@
     }
 
     @Test
-    @Ignore("b/331617278")
     fun getRealtimeCaptureLatencyEstimate_invokesCaptureExtenderImpl(): Unit = runBlocking {
         assumeTrue(hasCaptureProcessor)
         assumeTrue(ExtensionVersion.isMinimumCompatibleVersion(Version.VERSION_1_4))
@@ -473,7 +462,6 @@
     }
 
     @Test
-    @Ignore("b/331617278")
     fun repeatingRequest_containsPreviewCaptureStagesParameters(): Unit = runBlocking {
         val previewBuilder = Preview.Builder()
         val resultMonitor = ResultMonitor()
@@ -516,7 +504,6 @@
     }
 
     @Test
-    @Ignore("b/331617278")
     fun processorRequestUpdateOnly_canUpdateRepeating(): Unit = runBlocking {
         assumeTrue(previewProcessorType == PROCESSOR_TYPE_REQUEST_UPDATE_ONLY)
         val previewBuilder = Preview.Builder()
@@ -562,7 +549,6 @@
     }
 
     @Test
-    @Ignore("b/331617278")
     fun imageCapture_captureRequestParametersAreCorrect(): Unit = runBlocking {
         initBasicExtenderSessionProcessor().use {
             fakeCaptureExtenderImpl.captureStages = listOf(
@@ -616,7 +602,6 @@
     }
 
     @Test
-    @Ignore("b/331617278")
     fun onEnableDisableRequestsAreSent(): Unit = runBlocking {
         initBasicExtenderSessionProcessor().use {
             // Verify onEnableSession
@@ -672,7 +657,6 @@
     }
 
     @Test
-    @Ignore("b/331617278")
     fun getSupportedPostviewSizeIsCorrect() {
         assumeTrue(ClientVersion.isMinimumCompatibleVersion(Version.VERSION_1_4) &&
             ExtensionVersion.isMinimumCompatibleVersion(Version.VERSION_1_4))
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/sessionprocessor/PreviewProcessor.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/sessionprocessor/PreviewProcessor.java
index 337a01e..ab4a264 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/sessionprocessor/PreviewProcessor.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/sessionprocessor/PreviewProcessor.java
@@ -96,29 +96,33 @@
                             Logger.d(TAG, "Ignore image in closed or paused state");
                             return;
                         }
-                        if (ClientVersion.isMinimumCompatibleVersion(Version.VERSION_1_3)
-                                && ExtensionVersion
-                                .isMinimumCompatibleVersion(Version.VERSION_1_3)) {
-                            mPreviewImageProcessor.process(imageReference.get(), totalCaptureResult,
-                                    new ProcessResultImpl() {
-                                        @Override
-                                        public void onCaptureCompleted(long shutterTimestamp,
-                                                @NonNull List<Pair<CaptureResult.Key, Object>>
-                                                        result) {
-                                            onResultCallback.onCaptureResult(shutterTimestamp,
-                                                    result);
-                                        }
+                        try {
+                            if (ClientVersion.isMinimumCompatibleVersion(Version.VERSION_1_3)
+                                    && ExtensionVersion
+                                    .isMinimumCompatibleVersion(Version.VERSION_1_3)) {
+                                mPreviewImageProcessor.process(imageReference.get(),
+                                        totalCaptureResult,
+                                        new ProcessResultImpl() {
+                                            @Override
+                                            public void onCaptureCompleted(long shutterTimestamp,
+                                                    @NonNull List<Pair<CaptureResult.Key, Object>>
+                                                            result) {
+                                                onResultCallback.onCaptureResult(shutterTimestamp,
+                                                        result);
+                                            }
 
-                                        @Override
-                                        public void onCaptureProcessProgressed(int progress) {
+                                            @Override
+                                            public void onCaptureProcessProgressed(int progress) {
 
-                                        }
-                                    }, CameraXExecutors.ioExecutor());
-                        } else {
-                            mPreviewImageProcessor.process(imageReference.get(),
-                                    totalCaptureResult);
+                                            }
+                                        }, CameraXExecutors.ioExecutor());
+                            } else {
+                                mPreviewImageProcessor.process(imageReference.get(),
+                                        totalCaptureResult);
+                            }
+                        } finally {
+                            imageReference.decrement();
                         }
-                        imageReference.decrement();
                     }
                 });
     }
diff --git a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/GLImage2SurfaceRenderer.java b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/GLImage2SurfaceRenderer.java
index f35a47c..4a98977 100644
--- a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/GLImage2SurfaceRenderer.java
+++ b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/GLImage2SurfaceRenderer.java
@@ -79,6 +79,7 @@
     private EGLContext mEGLContext;
     private EGLSurface mEGLPbufferSurface;
     private EGLSurface mWindowSurface;
+    private int mTextureId;
 
     private int mProgram;
     private int mPositionHandle;
@@ -187,7 +188,7 @@
 
         int[] textureIds = new int[1];
         GLES20.glGenTextures(1, textureIds, 0);
-
+        mTextureId = textureIds[0];
         GLES20.glUniform1i(mTextureYHandle, 0);
 
         initVertexBuffer();
@@ -242,6 +243,15 @@
         GLES20.glEnableVertexAttribArray(mPositionHandle);
     }
 
+    public static ByteBuffer clone(ByteBuffer original) {
+        ByteBuffer clone = ByteBuffer.allocate(original.capacity());
+        original.rewind();
+        clone.put(original);
+        original.rewind();
+        clone.flip();
+        return clone;
+    }
+
     void renderTexture(Image image) {
         GLES20.glUseProgram(mProgram);
         GLES20.glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
@@ -249,10 +259,13 @@
 
         // Bind Y texture
         GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
-        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
+        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureId);
+
+        // ByteBuffer needs to be cloned otherwise it might cause failure in emulator.
+        ByteBuffer clonedBuffer = clone(image.getPlanes()[0].getBuffer());
         GLES20.glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, mInputSize.getWidth(),
                 mInputSize.getHeight(), 0, GL_LUMINANCE, GL_UNSIGNED_BYTE,
-                image.getPlanes()[0].getBuffer());
+                clonedBuffer);
         GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
                 GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
         GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
diff --git a/camera/camera-video/src/main/java/androidx/camera/video/VideoCapture.java b/camera/camera-video/src/main/java/androidx/camera/video/VideoCapture.java
index 34e5bb3..56bba47 100644
--- a/camera/camera-video/src/main/java/androidx/camera/video/VideoCapture.java
+++ b/camera/camera-video/src/main/java/androidx/camera/video/VideoCapture.java
@@ -1356,10 +1356,10 @@
 
         // Get corresponded resolutions for the target aspect ratio.
         int aspectRatio = videoSpec.getAspectRatio();
-        Map<Quality, Size> sizeMap = getQualityToResolutionMap(videoCapabilities,
+        Map<Quality, Size> supportedQualityToSizeMap = getQualityToResolutionMap(videoCapabilities,
                 requestedDynamicRange);
         QualityRatioToResolutionsTable qualityRatioTable = new QualityRatioToResolutionsTable(
-                cameraInfo.getSupportedResolutions(getImageFormat()), sizeMap);
+                cameraInfo.getSupportedResolutions(getImageFormat()), supportedQualityToSizeMap);
         List<Size> customOrderedResolutions = new ArrayList<>();
         for (Quality selectedQuality : selectedQualities) {
             customOrderedResolutions.addAll(
@@ -1367,7 +1367,8 @@
         }
         List<Size> filteredCustomOrderedResolutions = filterOutEncoderUnsupportedResolutions(
                 (VideoCaptureConfig<T>) builder.getUseCaseConfig(), mediaSpec,
-                requestedDynamicRange, videoCapabilities, customOrderedResolutions);
+                requestedDynamicRange, videoCapabilities, customOrderedResolutions,
+                supportedQualityToSizeMap);
         Logger.d(TAG, "Set custom ordered resolutions = " + filteredCustomOrderedResolutions);
         builder.getMutableConfig().insertOption(OPTION_CUSTOM_ORDERED_RESOLUTIONS,
                 filteredCustomOrderedResolutions);
@@ -1379,7 +1380,8 @@
             @NonNull MediaSpec mediaSpec,
             @NonNull DynamicRange dynamicRange,
             @NonNull VideoCapabilities videoCapabilities,
-            @NonNull List<Size> resolutions
+            @NonNull List<Size> resolutions,
+            @NonNull Map<Quality, Size> supportedQualityToSizeMap
     ) {
         if (resolutions.isEmpty()) {
             return resolutions;
@@ -1388,6 +1390,11 @@
         Iterator<Size> iterator = resolutions.iterator();
         while (iterator.hasNext()) {
             Size resolution = iterator.next();
+            // To improve performance, there is no need to check for supported qualities'
+            // resolutions because the encoder should support them.
+            if (supportedQualityToSizeMap.containsValue(resolution)) {
+                continue;
+            }
             // We must find EncoderProfiles for each resolution because the EncoderProfiles found
             // by resolution may contain different video mine type which leads to different codec.
             VideoValidatedEncoderProfilesProxy encoderProfiles =
diff --git a/collection/collection/src/commonMain/kotlin/androidx/collection/DoubleList.kt b/collection/collection/src/commonMain/kotlin/androidx/collection/DoubleList.kt
index 9ba38be..d3b2bbf 100644
--- a/collection/collection/src/commonMain/kotlin/androidx/collection/DoubleList.kt
+++ b/collection/collection/src/commonMain/kotlin/androidx/collection/DoubleList.kt
@@ -34,7 +34,8 @@
 /**
  * [DoubleList] is a [List]-like collection for [Double] values. It allows retrieving
  * the elements without boxing. [DoubleList] is always backed by a [MutableDoubleList],
- * its [MutableList]-like subclass.
+ * its [MutableList]-like subclass. The purpose of this class is to avoid the performance
+ * overhead of auto-boxing due to generics since [Collection] classes all operate on objects.
  *
  * This implementation is not thread-safe: if multiple threads access this
  * container concurrently, and one or more threads modify the structure of
diff --git a/collection/collection/src/commonMain/kotlin/androidx/collection/FloatList.kt b/collection/collection/src/commonMain/kotlin/androidx/collection/FloatList.kt
index 391aa06..93071fc 100644
--- a/collection/collection/src/commonMain/kotlin/androidx/collection/FloatList.kt
+++ b/collection/collection/src/commonMain/kotlin/androidx/collection/FloatList.kt
@@ -34,7 +34,8 @@
 /**
  * [FloatList] is a [List]-like collection for [Float] values. It allows retrieving
  * the elements without boxing. [FloatList] is always backed by a [MutableFloatList],
- * its [MutableList]-like subclass.
+ * its [MutableList]-like subclass. The purpose of this class is to avoid the performance
+ * overhead of auto-boxing due to generics since [Collection] classes all operate on objects.
  *
  * This implementation is not thread-safe: if multiple threads access this
  * container concurrently, and one or more threads modify the structure of
diff --git a/collection/collection/src/commonMain/kotlin/androidx/collection/IntList.kt b/collection/collection/src/commonMain/kotlin/androidx/collection/IntList.kt
index 0709d1c..7bfd160 100644
--- a/collection/collection/src/commonMain/kotlin/androidx/collection/IntList.kt
+++ b/collection/collection/src/commonMain/kotlin/androidx/collection/IntList.kt
@@ -34,7 +34,8 @@
 /**
  * [IntList] is a [List]-like collection for [Int] values. It allows retrieving
  * the elements without boxing. [IntList] is always backed by a [MutableIntList],
- * its [MutableList]-like subclass.
+ * its [MutableList]-like subclass. The purpose of this class is to avoid the performance
+ * overhead of auto-boxing due to generics since [Collection] classes all operate on objects.
  *
  * This implementation is not thread-safe: if multiple threads access this
  * container concurrently, and one or more threads modify the structure of
diff --git a/collection/collection/src/commonMain/kotlin/androidx/collection/LongList.kt b/collection/collection/src/commonMain/kotlin/androidx/collection/LongList.kt
index 56e15d1..ce7aa97 100644
--- a/collection/collection/src/commonMain/kotlin/androidx/collection/LongList.kt
+++ b/collection/collection/src/commonMain/kotlin/androidx/collection/LongList.kt
@@ -34,7 +34,8 @@
 /**
  * [LongList] is a [List]-like collection for [Long] values. It allows retrieving
  * the elements without boxing. [LongList] is always backed by a [MutableLongList],
- * its [MutableList]-like subclass.
+ * its [MutableList]-like subclass. The purpose of this class is to avoid the performance
+ * overhead of auto-boxing due to generics since [Collection] classes all operate on objects.
  *
  * This implementation is not thread-safe: if multiple threads access this
  * container concurrently, and one or more threads modify the structure of
diff --git a/collection/collection/template/PKeyList.kt.template b/collection/collection/template/PKeyList.kt.template
index 1bf836e..dacc266 100644
--- a/collection/collection/template/PKeyList.kt.template
+++ b/collection/collection/template/PKeyList.kt.template
@@ -34,7 +34,8 @@
 /**
  * [PKeyList] is a [List]-like collection for [PKey] values. It allows retrieving
  * the elements without boxing. [PKeyList] is always backed by a [MutablePKeyList],
- * its [MutableList]-like subclass.
+ * its [MutableList]-like subclass. The purpose of this class is to avoid the performance
+ * overhead of auto-boxing due to generics since [Collection] classes all operate on objects.
  *
  * This implementation is not thread-safe: if multiple threads access this
  * container concurrently, and one or more threads modify the structure of
diff --git a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/RenderInTransitionOverlayNodeElement.kt b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/RenderInTransitionOverlayNodeElement.kt
index 74e4d20..e9118d6 100644
--- a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/RenderInTransitionOverlayNodeElement.kt
+++ b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/RenderInTransitionOverlayNodeElement.kt
@@ -66,9 +66,9 @@
     override fun equals(other: Any?): Boolean {
         if (other is RenderInTransitionOverlayNodeElement) {
             return sharedTransitionScope == other.sharedTransitionScope &&
-                renderInOverlay == other.renderInOverlay &&
+                renderInOverlay === other.renderInOverlay &&
                 zIndexInOverlay == other.zIndexInOverlay &&
-                clipInOverlay == other.clipInOverlay
+                clipInOverlay === other.clipInOverlay
         }
         return false
     }
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeIrGenerationExtension.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeIrGenerationExtension.kt
index 324e4b7..6d1df04 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeIrGenerationExtension.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeIrGenerationExtension.kt
@@ -261,7 +261,7 @@
                 pluginContext,
                 symbolRemapper,
                 metrics,
-                idSignatureBuilder!!,
+                idSignatureBuilder,
                 stabilityInferencer,
                 decoysEnabled
             ).lower(moduleFragment)
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposePlugin.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposePlugin.kt
index 4be9688..c445253 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposePlugin.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposePlugin.kt
@@ -166,9 +166,16 @@
             allowMultipleOccurrences = false
         )
         val STRONG_SKIPPING_OPTION = CliOption(
+            "strongSkipping",
+            "<true|false>",
+            "Enable strong skipping mode",
+            required = false,
+            allowMultipleOccurrences = false
+        )
+        val EXPERIMENTAL_STRONG_SKIPPING_OPTION = CliOption(
             "experimentalStrongSkipping",
             "<true|false>",
-            "Enable experimental strong skipping mode",
+            "Deprecated - Use strongSkipping instead",
             required = false,
             allowMultipleOccurrences = false
         )
@@ -200,6 +207,7 @@
         NON_SKIPPING_GROUP_OPTIMIZATION_ENABLED_OPTION,
         SUPPRESS_KOTLIN_VERSION_CHECK_ENABLED_OPTION,
         DECOYS_ENABLED_OPTION,
+        EXPERIMENTAL_STRONG_SKIPPING_OPTION,
         STRONG_SKIPPING_OPTION,
         STABLE_CONFIG_PATH_OPTION,
         TRACE_MARKERS_OPTION,
@@ -250,6 +258,18 @@
             ComposeConfiguration.DECOYS_ENABLED_KEY,
             value == "true"
         )
+        EXPERIMENTAL_STRONG_SKIPPING_OPTION -> {
+            val msgCollector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
+            msgCollector?.report(
+                CompilerMessageSeverity.WARNING,
+                "${EXPERIMENTAL_STRONG_SKIPPING_OPTION.optionName} is deprecated." +
+                    " Use ${STRONG_SKIPPING_OPTION.optionName} instead."
+            )
+            configuration.put(
+                ComposeConfiguration.STRONG_SKIPPING_ENABLED_KEY,
+                value == "true"
+            )
+        }
         STRONG_SKIPPING_OPTION -> configuration.put(
             ComposeConfiguration.STRONG_SKIPPING_ENABLED_KEY,
             value == "true"
@@ -473,6 +493,7 @@
             )
 
             val useK2 = configuration.languageVersionSettings.languageVersion.usesK2
+
             val strongSkippingEnabled = configuration.get(
                 ComposeConfiguration.STRONG_SKIPPING_ENABLED_KEY,
                 false
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/WrapJsComposableLambdaLowering.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/WrapJsComposableLambdaLowering.kt
index 27386ba..af87015 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/WrapJsComposableLambdaLowering.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/WrapJsComposableLambdaLowering.kt
@@ -20,7 +20,6 @@
 import androidx.compose.compiler.plugins.kotlin.ComposeClassIds
 import androidx.compose.compiler.plugins.kotlin.ModuleMetrics
 import androidx.compose.compiler.plugins.kotlin.analysis.StabilityInferencer
-import androidx.compose.compiler.plugins.kotlin.lower.decoys.AbstractDecoysLowering
 import androidx.compose.compiler.plugins.kotlin.lower.decoys.CreateDecoysTransformer
 import androidx.compose.compiler.plugins.kotlin.lower.decoys.isDecoy
 import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
@@ -85,15 +84,14 @@
     context: IrPluginContext,
     symbolRemapper: DeepCopySymbolRemapper,
     metrics: ModuleMetrics,
-    signatureBuilder: IdSignatureSerializer,
+    signatureBuilder: IdSignatureSerializer?,
     stabilityInferencer: StabilityInferencer,
     private val decoysEnabled: Boolean
-) : AbstractDecoysLowering(
+) : AbstractComposeLowering(
     context,
     symbolRemapper,
     metrics,
     stabilityInferencer,
-    signatureBuilder
 ) {
     private val rememberFunSymbol by lazy {
         val composerParamTransformer = ComposerParamTransformer(
@@ -104,21 +102,25 @@
                 it.valueParameters.size == 2 && !it.valueParameters.first().isVararg
             }.symbol
         ).owner.let {
-            if (!decoysEnabled) {
+            if (!decoysEnabled || signatureBuilder == null) {
                 composerParamTransformer.visitSimpleFunction(it) as IrSimpleFunction
-            } else if (!it.isDecoy()) {
+            } else {
                 // If a module didn't have any explicit remember calls,
                 // so `fun remember` wasn't transformed yet, then we have to transform it now.
                 val createDecoysTransformer = CreateDecoysTransformer(
                     context, symbolRemapper, signatureBuilder, stabilityInferencer, metrics
                 )
-                createDecoysTransformer.visitSimpleFunction(it) as IrSimpleFunction
-                createDecoysTransformer.updateParents()
-                composerParamTransformer.visitSimpleFunction(
-                    it.getComposableForDecoy().owner as IrSimpleFunction
-                ) as IrSimpleFunction
-            } else {
-                it.getComposableForDecoy().owner as IrSimpleFunction
+                with(createDecoysTransformer) {
+                    if (!it.isDecoy()) {
+                        visitSimpleFunction(it) as IrSimpleFunction
+                        updateParents()
+                        composerParamTransformer.visitSimpleFunction(
+                            it.getComposableForDecoy().owner as IrSimpleFunction
+                        ) as IrSimpleFunction
+                    } else {
+                        it.getComposableForDecoy().owner as IrSimpleFunction
+                    }
+                }
             }
         }.symbol
     }
diff --git a/compose/compiler/compiler/integration-tests/src/test/kotlin/androidx/compose/compiler/test/CompilerPluginRuntimeVersionCheckTest.kt b/compose/compiler/compiler/integration-tests/src/test/kotlin/androidx/compose/compiler/test/CompilerPluginRuntimeVersionCheckTest.kt
index 79b0f58..efb35c5 100644
--- a/compose/compiler/compiler/integration-tests/src/test/kotlin/androidx/compose/compiler/test/CompilerPluginRuntimeVersionCheckTest.kt
+++ b/compose/compiler/compiler/integration-tests/src/test/kotlin/androidx/compose/compiler/test/CompilerPluginRuntimeVersionCheckTest.kt
@@ -154,7 +154,7 @@
 
             android {
                 namespace "androidx.compose.compiler.test"
-                compileSdkVersion ${projectSetup.props.compileSdkVersion}
+                compileSdk ${projectSetup.props.compileSdk}
                 buildToolsVersion "${projectSetup.props.buildToolsVersion}"
                 defaultConfig {
                     minSdkVersion 21
diff --git a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Offset.kt b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Offset.kt
index 4fa34b4..3fc7a65 100644
--- a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Offset.kt
+++ b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Offset.kt
@@ -217,7 +217,7 @@
         if (this === other) return true
         val otherModifier = other as? OffsetPxElement ?: return false
 
-        return offset == otherModifier.offset &&
+        return offset === otherModifier.offset &&
             rtlAware == otherModifier.rtlAware
     }
 
diff --git a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/RowColumnImpl.kt b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/RowColumnImpl.kt
index e011e59..7467caf 100644
--- a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/RowColumnImpl.kt
+++ b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/RowColumnImpl.kt
@@ -559,7 +559,7 @@
     override fun equals(other: Any?): Boolean {
         if (this === other) return true
         val otherModifier = other as? WithAlignmentLineBlockElement ?: return false
-        return block == otherModifier.block
+        return block === otherModifier.block
     }
 
     override fun hashCode(): Int = block.hashCode()
diff --git a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/WindowInsetsPadding.kt b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/WindowInsetsPadding.kt
index 2a93e7a..e35dd4b 100644
--- a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/WindowInsetsPadding.kt
+++ b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/WindowInsetsPadding.kt
@@ -249,7 +249,7 @@
             return false
         }
 
-        return other.block == block
+        return other.block === block
     }
 
     override fun hashCode(): Int = block.hashCode()
diff --git a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/WindowInsetsSize.kt b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/WindowInsetsSize.kt
index 9c83dd3..4d2cc98 100644
--- a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/WindowInsetsSize.kt
+++ b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/WindowInsetsSize.kt
@@ -161,7 +161,7 @@
         if (other !is DerivedWidthModifier) {
             return false
         }
-        return insets == other.insets && widthCalc == other.widthCalc
+        return insets == other.insets && widthCalc === other.widthCalc
     }
 
     override fun hashCode(): Int = 31 * insets.hashCode() + widthCalc.hashCode()
@@ -206,7 +206,7 @@
         if (other !is DerivedHeightModifier) {
             return false
         }
-        return insets == other.insets && heightCalc == other.heightCalc
+        return insets == other.insets && heightCalc === other.heightCalc
     }
 
     override fun hashCode(): Int = 31 * insets.hashCode() + heightCalc.hashCode()
diff --git a/compose/foundation/foundation/api/current.txt b/compose/foundation/foundation/api/current.txt
index 012b6e4..b6acb3d 100644
--- a/compose/foundation/foundation/api/current.txt
+++ b/compose/foundation/foundation/api/current.txt
@@ -362,29 +362,6 @@
 
 }
 
-package androidx.compose.foundation.contextmenu {
-
-  @androidx.compose.runtime.Stable public final class ContextMenuColors {
-    ctor public ContextMenuColors(long backgroundColor, long textColor, long iconColor, long disabledTextColor, long disabledIconColor);
-    method public long getBackgroundColor();
-    method public long getDisabledIconColor();
-    method public long getDisabledTextColor();
-    method public long getIconColor();
-    method public long getTextColor();
-    property public final long backgroundColor;
-    property public final long disabledIconColor;
-    property public final long disabledTextColor;
-    property public final long iconColor;
-    property public final long textColor;
-  }
-
-  public final class ContextMenuUiKt {
-    method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.foundation.contextmenu.ContextMenuColors?> getLocalContextMenuColors();
-    property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.foundation.contextmenu.ContextMenuColors?> LocalContextMenuColors;
-  }
-
-}
-
 package androidx.compose.foundation.draganddrop {
 
   public final class AndroidDragAndDropSource_androidKt {
diff --git a/compose/foundation/foundation/api/restricted_current.txt b/compose/foundation/foundation/api/restricted_current.txt
index 684d597..1c7c09d 100644
--- a/compose/foundation/foundation/api/restricted_current.txt
+++ b/compose/foundation/foundation/api/restricted_current.txt
@@ -364,29 +364,6 @@
 
 }
 
-package androidx.compose.foundation.contextmenu {
-
-  @androidx.compose.runtime.Stable public final class ContextMenuColors {
-    ctor public ContextMenuColors(long backgroundColor, long textColor, long iconColor, long disabledTextColor, long disabledIconColor);
-    method public long getBackgroundColor();
-    method public long getDisabledIconColor();
-    method public long getDisabledTextColor();
-    method public long getIconColor();
-    method public long getTextColor();
-    property public final long backgroundColor;
-    property public final long disabledIconColor;
-    property public final long disabledTextColor;
-    property public final long iconColor;
-    property public final long textColor;
-  }
-
-  public final class ContextMenuUiKt {
-    method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.foundation.contextmenu.ContextMenuColors?> getLocalContextMenuColors();
-    property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.foundation.contextmenu.ContextMenuColors?> LocalContextMenuColors;
-  }
-
-}
-
 package androidx.compose.foundation.draganddrop {
 
   public final class AndroidDragAndDropSource_androidKt {
diff --git a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/LongScreenshotsDemos.kt b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/LongScreenshotsDemos.kt
index 15d9452..f40115d 100644
--- a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/LongScreenshotsDemos.kt
+++ b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/LongScreenshotsDemos.kt
@@ -32,6 +32,7 @@
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.heightIn
 import androidx.compose.foundation.layout.imePadding
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.wrapContentHeight
@@ -79,6 +80,7 @@
     ComposableDemo("TextField in scrollable") { TextFieldInScrollableDemo() },
     ComposableDemo("Single giant text field") { SingleGiantTextFieldDemo() },
     ComposableDemo("Lazy list with sticky headers") { LazyListWithStickiesDemo() },
+    ComposableDemo("Reverse layout") { ReverseScrollingCaptureDemo() },
 )
 
 @Composable
@@ -170,17 +172,15 @@
 
 @Composable
 private fun SingleFullScreenListDemo() {
-    Column {
-        LazyColumn(Modifier.fillMaxSize()) {
-            items(50) { index ->
-                Button(
-                    onClick = {},
-                    Modifier
-                        .padding(8.dp)
-                        .fillMaxWidth()
-                ) {
-                    Text("Button $index")
-                }
+    LazyColumn(Modifier.fillMaxSize()) {
+        items(50) { index ->
+            Button(
+                onClick = {},
+                Modifier
+                    .padding(8.dp)
+                    .fillMaxWidth()
+            ) {
+                Text("Button $index")
             }
         }
     }
@@ -188,39 +188,37 @@
 
 @Composable
 private fun LazyListContentPaddingDemo() {
-    Column {
-        Scaffold(
+    Scaffold(
+        modifier = Modifier
+            .padding(8.dp)
+            .border(1.dp, Color.Black),
+        topBar = {
+            TopAppBar(
+                title = { Text("Top bar") },
+                backgroundColor = MaterialTheme.colors.primarySurface.copy(alpha = 0.5f)
+            )
+        },
+        bottomBar = {
+            BottomAppBar(
+                backgroundColor = MaterialTheme.colors.primarySurface.copy(alpha = 0.5f)
+            ) { Text("Bottom bar") }
+        }
+    ) { contentPadding ->
+        LazyColumn(
             modifier = Modifier
-                .padding(8.dp)
-                .border(1.dp, Color.Black),
-            topBar = {
-                TopAppBar(
-                    title = { Text("Top bar") },
-                    backgroundColor = MaterialTheme.colors.primarySurface.copy(alpha = 0.5f)
-                )
-            },
-            bottomBar = {
-                BottomAppBar(
-                    backgroundColor = MaterialTheme.colors.primarySurface.copy(alpha = 0.5f)
-                ) { Text("Bottom bar") }
-            }
-        ) { contentPadding ->
-            LazyColumn(
-                modifier = Modifier
-                    .fillMaxSize()
-                    .background(Color.Red),
-                contentPadding = contentPadding
-            ) {
-                items(15) { index ->
-                    Button(
-                        onClick = {},
-                        Modifier
-                            .background(Color.LightGray)
-                            .padding(8.dp)
-                            .fillMaxWidth()
-                    ) {
-                        Text("Button $index")
-                    }
+                .fillMaxSize()
+                .background(Color.Red),
+            contentPadding = contentPadding
+        ) {
+            items(15) { index ->
+                Button(
+                    onClick = {},
+                    Modifier
+                        .background(Color.LightGray)
+                        .padding(8.dp)
+                        .fillMaxWidth()
+                ) {
+                    Text("Button $index")
                 }
             }
         }
@@ -505,3 +503,22 @@
         }
     }
 }
+
+@Composable
+private fun ReverseScrollingCaptureDemo() {
+    Column(
+        horizontalAlignment = Alignment.CenterHorizontally,
+        modifier = Modifier
+            .fillMaxSize()
+            .verticalScroll(rememberScrollState(), reverseScrolling = true)
+    ) {
+        repeat(50) { index ->
+            Text(
+                "Row $index",
+                Modifier
+                    .heightIn(min = 40.dp)
+                    .padding(8.dp)
+            )
+        }
+    }
+}
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 90f9d1e..7a75d11 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
@@ -28,6 +28,7 @@
 import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.interaction.PressInteraction
 import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.BoxWithConstraints
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.requiredHeight
 import androidx.compose.foundation.layout.requiredWidth
@@ -36,6 +37,8 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.CompositionLocalProvider
 import androidx.compose.runtime.getValue
+import androidx.compose.runtime.key
+import androidx.compose.runtime.movableContentOf
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.rememberCoroutineScope
@@ -69,9 +72,11 @@
 import androidx.compose.ui.platform.isDebugInspectorInfoEnabled
 import androidx.compose.ui.platform.testTag
 import androidx.compose.ui.semantics.Role
+import androidx.compose.ui.semantics.SemanticsActions
 import androidx.compose.ui.semantics.SemanticsProperties
 import androidx.compose.ui.test.ExperimentalTestApi
 import androidx.compose.ui.test.SemanticsMatcher
+import androidx.compose.ui.test.SemanticsNodeInteraction
 import androidx.compose.ui.test.assert
 import androidx.compose.ui.test.assertHasClickAction
 import androidx.compose.ui.test.assertHeightIsEqualTo
@@ -3527,6 +3532,44 @@
         rule.onNodeWithTag(tag).requestFocus()
         rule.onNodeWithTag(tag).assertIsFocused()
     }
+
+    // Regression test for b/332814226
+    @Test
+    fun movableContentWithSubcomposition_updatingSemanticsShouldNotCrash() {
+        var moveContent by mutableStateOf(false)
+        rule.setContent {
+            val content = remember {
+                movableContentOf {
+                    BoxWithConstraints {
+                        BasicText("ClickableText",
+                            modifier = Modifier
+                                .testTag("clickable")
+                                .clickable(
+                                    role = if (moveContent) Role.Button else Role.Checkbox,
+                                    onClickLabel = moveContent.toString()
+                                ) {}
+                        )
+                    }
+                }
+            }
+
+            key(moveContent) {
+                content()
+            }
+        }
+
+        rule.onNodeWithTag("clickable")
+            .assert(SemanticsMatcher.expectValue(SemanticsProperties.Role, Role.Checkbox))
+            .assertOnClickLabelMatches("false")
+
+        rule.runOnIdle {
+            moveContent = true
+        }
+
+        rule.onNodeWithTag("clickable")
+            .assert(SemanticsMatcher.expectValue(SemanticsProperties.Role, Role.Button))
+            .assertOnClickLabelMatches("true")
+    }
 }
 
 /**
@@ -3585,3 +3628,10 @@
         return onAttach.hashCode()
     }
 }
+
+internal fun SemanticsNodeInteraction.assertOnClickLabelMatches(expectedValue: String):
+    SemanticsNodeInteraction {
+        return assert(SemanticsMatcher("onClickLabel = '$expectedValue'") {
+            it.config.getOrElseNullable(SemanticsActions.OnClick) { null }?.label == expectedValue
+        })
+    }
diff --git a/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/CombinedClickableTest.kt b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/CombinedClickableTest.kt
index 4b0debf..b67d4b3 100644
--- a/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/CombinedClickableTest.kt
+++ b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/CombinedClickableTest.kt
@@ -26,6 +26,7 @@
 import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.interaction.PressInteraction
 import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.BoxWithConstraints
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.requiredHeight
 import androidx.compose.foundation.layout.requiredWidth
@@ -33,6 +34,8 @@
 import androidx.compose.foundation.text.BasicText
 import androidx.compose.runtime.CompositionLocalProvider
 import androidx.compose.runtime.getValue
+import androidx.compose.runtime.key
+import androidx.compose.runtime.movableContentOf
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.rememberCoroutineScope
@@ -59,10 +62,12 @@
 import androidx.compose.ui.platform.LocalInputModeManager
 import androidx.compose.ui.platform.isDebugInspectorInfoEnabled
 import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.semantics.Role
 import androidx.compose.ui.semantics.SemanticsActions
 import androidx.compose.ui.semantics.SemanticsProperties
 import androidx.compose.ui.test.ExperimentalTestApi
 import androidx.compose.ui.test.SemanticsMatcher
+import androidx.compose.ui.test.SemanticsNodeInteraction
 import androidx.compose.ui.test.assert
 import androidx.compose.ui.test.assertHasClickAction
 import androidx.compose.ui.test.assertHeightIsEqualTo
@@ -2429,4 +2434,53 @@
             assertThat(pressInteractions.last()).isInstanceOf(PressInteraction.Cancel::class.java)
         }
     }
+
+    // Regression test for b/332814226
+    @Test
+    fun movableContentWithSubcomposition_updatingSemanticsShouldNotCrash() {
+        var moveContent by mutableStateOf(false)
+        rule.setContent {
+            val content = remember {
+                movableContentOf {
+                    BoxWithConstraints {
+                        BasicText("ClickableText",
+                            modifier = Modifier
+                                .testTag("clickable")
+                                .combinedClickable(
+                                    role = if (moveContent) Role.Button else Role.Checkbox,
+                                    onClickLabel = moveContent.toString(),
+                                    onLongClick = {},
+                                    onLongClickLabel = moveContent.toString()
+                                ) {}
+                        )
+                    }
+                }
+            }
+
+            key(moveContent) {
+                content()
+            }
+        }
+
+        rule.onNodeWithTag("clickable")
+            .assert(SemanticsMatcher.expectValue(SemanticsProperties.Role, Role.Checkbox))
+            .assertOnClickLabelMatches("false")
+            .assertOnLongClickLabelMatches("false")
+
+        rule.runOnIdle {
+            moveContent = true
+        }
+
+        rule.onNodeWithTag("clickable")
+            .assert(SemanticsMatcher.expectValue(SemanticsProperties.Role, Role.Button))
+            .assertOnClickLabelMatches("true")
+            .assertOnLongClickLabelMatches("true")
+    }
+}
+
+private fun SemanticsNodeInteraction.assertOnLongClickLabelMatches(expectedValue: String):
+    SemanticsNodeInteraction {
+    return assert(SemanticsMatcher("onLongClickLabel = '$expectedValue'") {
+        it.config.getOrElseNullable(SemanticsActions.OnLongClick) { null }?.label == expectedValue
+    })
 }
diff --git a/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/contextmenu/ContextMenuCommon.kt b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/contextmenu/ContextMenuCommon.kt
index 458ae84..386d59f 100644
--- a/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/contextmenu/ContextMenuCommon.kt
+++ b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/contextmenu/ContextMenuCommon.kt
@@ -17,13 +17,9 @@
 package androidx.compose.foundation.contextmenu
 
 import androidx.compose.foundation.contextmenu.ContextMenuState.Status
-import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.graphics.Color
-import com.google.common.truth.Correspondence
 import com.google.common.truth.FailureMetadata
-import com.google.common.truth.IterableSubject
 import com.google.common.truth.Subject
 import com.google.common.truth.Subject.Factory
 import com.google.common.truth.Truth.assertAbout
@@ -36,15 +32,11 @@
 internal fun ContextMenuScope.testItem(
     label: String = "Item",
     modifier: Modifier = Modifier,
-    enabled: Boolean = true,
-    leadingIcon: @Composable ((iconColor: Color) -> Unit)? = null,
     onClick: () -> Unit = {},
 ) {
     item(
         label = label,
         modifier = modifier,
-        enabled = enabled,
-        leadingIcon = leadingIcon,
         onClick = onClick,
     )
 }
@@ -71,23 +63,3 @@
         assertThat(subject.status).isInstanceOf(Status.Closed::class.java)
     }
 }
-
-internal fun assertThatColors(
-    colors: Set<Color>,
-    tolerance: Double = 0.02,
-): IterableSubject.UsingCorrespondence<Color, Color> =
-    assertThat(colors).comparingElementsUsing(colorCorrespondence(tolerance))
-
-internal fun colorCorrespondence(tolerance: Double = 0.02): Correspondence<Color, Color> {
-    val floatingPointCorrespondence = Correspondence.tolerance(tolerance)
-    return Correspondence.from(
-        { actual: Color?, expected: Color? ->
-            if (expected == null || actual == null) return@from actual == expected
-            floatingPointCorrespondence.compare(actual.red, expected.red) &&
-                floatingPointCorrespondence.compare(actual.green, expected.green) &&
-                floatingPointCorrespondence.compare(actual.blue, expected.blue) &&
-                floatingPointCorrespondence.compare(actual.alpha, expected.alpha)
-        },
-        /* description = */ "equals",
-    )
-}
diff --git a/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/contextmenu/ContextMenuUiTest.kt b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/contextmenu/ContextMenuUiTest.kt
index 1d8b970..99fd744 100644
--- a/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/contextmenu/ContextMenuUiTest.kt
+++ b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/contextmenu/ContextMenuUiTest.kt
@@ -17,7 +17,6 @@
 package androidx.compose.foundation.contextmenu
 
 import android.os.Build
-import androidx.annotation.RequiresApi
 import androidx.compose.foundation.background
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.IntrinsicSize
@@ -28,13 +27,14 @@
 import androidx.compose.foundation.text.ceilToIntPx
 import androidx.compose.foundation.text.selection.fetchTextLayoutResult
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.CompositionLocalProvider
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.setValue
 import androidx.compose.testutils.assertIsEqualTo
+import androidx.compose.testutils.assertPixelColor
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.drawWithContent
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.toPixelMap
@@ -75,14 +75,6 @@
 private fun IntOffset.dx(dx: Int): IntOffset = copy(x = x + dx)
 private fun IntOffset.dy(dy: Int): IntOffset = copy(y = y + dy)
 
-private val TestColors = ContextMenuColors(
-    backgroundColor = Color.White,
-    textColor = Color.Black,
-    iconColor = Color.Blue,
-    disabledTextColor = Color.Red,
-    disabledIconColor = Color.Green,
-)
-
 @RunWith(AndroidJUnit4::class)
 @MediumTest
 class ContextMenuUiTest {
@@ -92,27 +84,11 @@
     private val tag = "testTag"
     private val longText = "M ".repeat(200).trimEnd()
 
-    @Composable
-    private fun TestColumn(
-        colors: ContextMenuColors = TestColors,
-        contextMenuBuilderBlock: ContextMenuScope.() -> Unit,
-    ) {
-        ContextMenuColumn(colors, Modifier.testTag(tag)) {
-            val scope = remember { ContextMenuScope() }
-            with(scope) {
-                clear()
-                contextMenuBuilderBlock()
-                Content(colors)
-            }
-        }
-    }
-
     // region ContextMenuItem Tests
     @Composable
     private fun TestItem(
         label: String = "Item",
         enabled: Boolean = true,
-        colors: ContextMenuColors = TestColors,
         modifier: Modifier = Modifier.testTag(tag),
         leadingIcon: @Composable ((iconColor: Color) -> Unit)? = null,
         onClick: () -> Unit = {},
@@ -120,7 +96,6 @@
         ContextMenuItem(
             label = label,
             enabled = enabled,
-            colors = colors,
             modifier = modifier,
             leadingIcon = leadingIcon,
             onClick = onClick
@@ -306,12 +281,8 @@
         textNode.assertExists("Text does not exist.")
 
         val textStyle = textNode.fetchTextLayoutResult().layoutInput.style
-        assertThat(textStyle.color).isEqualTo(TestColors.textColor)
+        assertThat(textStyle.color).isEqualTo(ContextMenuSpec.TextColor)
         assertThat(textStyle.textAlign).isEqualTo(ContextMenuSpec.LabelHorizontalTextAlignment)
-        assertThat(textStyle.fontSize).isEqualTo(ContextMenuSpec.FontSize)
-        assertThat(textStyle.fontWeight).isEqualTo(ContextMenuSpec.FontWeight)
-        assertThat(textStyle.lineHeight).isEqualTo(ContextMenuSpec.LineHeight)
-        assertThat(textStyle.letterSpacing).isEqualTo(ContextMenuSpec.LetterSpacing)
     }
 
     @Test
@@ -322,19 +293,15 @@
         textNode.assertExists("Text does not exist.")
 
         val textStyle = textNode.fetchTextLayoutResult().layoutInput.style
-        assertThat(textStyle.color).isEqualTo(TestColors.disabledTextColor)
+        assertThat(textStyle.color).isEqualTo(ContextMenuSpec.DisabledColor)
         assertThat(textStyle.textAlign).isEqualTo(ContextMenuSpec.LabelHorizontalTextAlignment)
-        assertThat(textStyle.fontSize).isEqualTo(ContextMenuSpec.FontSize)
-        assertThat(textStyle.fontWeight).isEqualTo(ContextMenuSpec.FontWeight)
-        assertThat(textStyle.lineHeight).isEqualTo(ContextMenuSpec.LineHeight)
-        assertThat(textStyle.letterSpacing).isEqualTo(ContextMenuSpec.LetterSpacing)
     }
 
     @Test
     fun whenContextMenuItem_enabled_correctIconColor() {
         var iconColor: Color? = null
         rule.setContent { TestItem(label = longText, leadingIcon = { iconColor = it }) }
-        assertThat(iconColor).isEqualTo(TestColors.iconColor)
+        assertThat(iconColor).isEqualTo(ContextMenuSpec.IconColor)
     }
 
     @Test
@@ -343,11 +310,25 @@
         rule.setContent {
             TestItem(label = longText, enabled = false, leadingIcon = { iconColor = it })
         }
-        assertThat(iconColor).isEqualTo(TestColors.disabledIconColor)
+        assertThat(iconColor).isEqualTo(ContextMenuSpec.DisabledColor)
     }
     // endregion ContextMenuItem Tests
 
     // region ContextMenuColumn Tests
+    @Composable
+    private fun TestColumn(
+        contextMenuBuilderBlock: ContextMenuScope.() -> Unit,
+    ) {
+        ContextMenuColumn(Modifier.testTag(tag)) {
+            val scope = remember { ContextMenuScope() }
+            with(scope) {
+                clear()
+                contextMenuBuilderBlock()
+                Content()
+            }
+        }
+    }
+
     @Test
     fun whenContextMenuColumn_usedNormally_allInputItemsAreRendered() {
         val labelFunction: (Int) -> String = { "Item $it" }
@@ -363,6 +344,42 @@
 
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
     @Test
+    fun whenContextMenuColumn_usedNormally_backgroundColorIsAsExpected() {
+        rule.setContent {
+            TestColumn {
+                // small label to keep text out of the way
+                testItem(
+                    label = "Item",
+                    modifier = Modifier.drawWithContent {
+                        // Don't draw content, only the column will draw.
+                        // Layout will still fill space.
+                    }
+                )
+            }
+        }
+
+        val node = rule.onNodeWithTag(tag)
+        val bitmap = node.captureToImage()
+        val density = node.fetchSemanticsNode().layoutInfo.density
+
+        // Ignore some padding around the edges where the shadow/rounded corners are.
+        val padding = with(density) { ContextMenuSpec.CornerRadius.toPx().ceilToIntPx() }
+        val pixelMap = bitmap.toPixelMap(
+            startX = padding,
+            startY = padding,
+            width = bitmap.width - padding * 2,
+            height = bitmap.height - padding * 2,
+        )
+
+        for (x in 0 until pixelMap.width) {
+            for (y in 0 until pixelMap.height) {
+                pixelMap.assertPixelColor(ContextMenuSpec.BackgroundColor, x, y)
+            }
+        }
+    }
+
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+    @Test
     fun whenContextMenuColumn_usedNormally_hasExpectedShadow() {
         val containerTag = "containerTag"
         rule.setContent {
@@ -371,7 +388,10 @@
                     .testTag(containerTag)
                     .padding(ContextMenuSpec.MenuContainerElevation)
             ) {
-                TestColumn { testItem() }
+                TestColumn {
+                    // small label to keep text out of the way
+                    testItem(label = ".")
+                }
             }
         }
 
@@ -388,8 +408,9 @@
         fun assertShadowAt(offset: IntOffset) {
             val (x, y) = offset
             val pixelColor = pixelMap[x, y]
-            val message = "Expected pixel at [$x, $y] to not be ${TestColors.backgroundColor}."
-            assertWithMessage(message).that(pixelColor).isNotEqualTo(TestColors.backgroundColor)
+            val message = "Expected pixel at [$x, $y] to not be ${ContextMenuSpec.BackgroundColor}."
+            assertWithMessage(message)
+                .that(pixelColor).isNotEqualTo(ContextMenuSpec.BackgroundColor)
         }
 
         assertShadowAt(columnBoundsInParent.centerLeft.dx(-1))
@@ -502,178 +523,6 @@
     }
     // endregion ContextMenuColumn Tests
 
-    // region ContextMenuColor Tests
-    private val testColor = Color.Red
-
-    /** Without a baseline background color, the background color is non-deterministic. */
-    private val testBackgroundColor = Color.White
-
-    private fun transparentColors(
-        backgroundColor: Color = testBackgroundColor,
-        textColor: Color = Color.Transparent,
-        iconColor: Color = Color.Transparent,
-        disabledTextColor: Color = Color.Transparent,
-        disabledIconColor: Color = Color.Transparent,
-    ): ContextMenuColors = ContextMenuColors(
-        backgroundColor = backgroundColor,
-        textColor = textColor,
-        iconColor = iconColor,
-        disabledTextColor = disabledTextColor,
-        disabledIconColor = disabledIconColor,
-    )
-
-    /**
-     * Threshold % of pixels that must match a certain color.
-     * This filters out outlier colors resulting from anti-aliasing.
-     */
-    private val filterThresholdPercentage = 0.02f
-
-    /**
-     * Gets all the colors in the tagged node.
-     * Removes any padding and outlier colors from anti-aliasing from the result.
-     */
-    @RequiresApi(Build.VERSION_CODES.O)
-    private fun getColors(): Set<Color> {
-        val node = rule.onNodeWithTag(tag)
-        val bitmap = node.captureToImage()
-        val density = node.fetchSemanticsNode().layoutInfo.density
-
-        // Ignore some padding around the edges where the shadow/rounded corners are.
-        val padding = with(density) {
-            ContextMenuSpec.CornerRadius.toPx().times(4f).ceilToIntPx()
-        }
-
-        val pixelMap = bitmap.toPixelMap(
-            startX = padding,
-            startY = padding,
-            width = bitmap.width - padding,
-            height = bitmap.height - padding,
-        )
-
-        val pixelColorHistogram = buildMap<Color, Int> {
-            for (x in 0 until pixelMap.width) {
-                for (y in 0 until pixelMap.height) {
-                    val pixelColor = pixelMap[x, y]
-                    merge(pixelColor, 1) { old, new -> old + new }
-                }
-            }
-        }
-
-        val threshold = pixelMap.width * pixelMap.height * filterThresholdPercentage
-        return pixelColorHistogram.filterValues { it >= threshold }.keys
-    }
-
-    @RequiresApi(Build.VERSION_CODES.O)
-    private fun getNonBackgroundColors(): Set<Color> = getColors() - testBackgroundColor
-
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
-    @Test
-    fun whenContextMenuColors_transparentExceptBackground_backgroundColorIsAsExpected() {
-        val colors = transparentColors(backgroundColor = testColor)
-        rule.setContent { TestColumn(colors) { testItem() } }
-        assertThatColors(getColors()).containsExactly(testColor)
-    }
-
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
-    @Test
-    fun whenContextMenuColors_transparentExceptText_textColorIsAsExpected() {
-        val colors = transparentColors(textColor = testColor)
-        rule.setContent { TestColumn(colors) { testItem(label = "M".repeat(10)) } }
-        assertThatColors(getNonBackgroundColors()).containsExactly(testColor)
-    }
-
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
-    @Test
-    fun whenContextMenuColors_transparentExceptDisabledText_textColorIsAsExpected() {
-        val colors = transparentColors(disabledTextColor = testColor)
-        rule.setContent {
-            TestColumn(colors) { testItem(label = "M".repeat(10), enabled = false) }
-        }
-        assertThatColors(getNonBackgroundColors()).containsExactly(testColor)
-    }
-
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
-    @Test
-    fun whenContextMenuColors_transparentExceptIcon_iconColorIsAsExpected() {
-        val colors = transparentColors(iconColor = testColor)
-        rule.setContent {
-            TestColumn(colors) {
-                testItem(
-                    leadingIcon = { iconColor ->
-                        Box(
-                            Modifier
-                                .background(iconColor)
-                                .fillMaxSize()
-                        )
-                    },
-                )
-            }
-        }
-        assertThatColors(getNonBackgroundColors()).containsExactly(testColor)
-    }
-
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
-    @Test
-    fun whenContextMenuColors_transparentExceptDisabledIcon_iconColorIsAsExpected() {
-        val colors = transparentColors(disabledIconColor = testColor)
-        rule.setContent {
-            TestColumn(colors) {
-                testItem(
-                    enabled = false,
-                    leadingIcon = { iconColor ->
-                        Box(
-                            Modifier
-                                .background(iconColor)
-                                .fillMaxSize()
-                        )
-                    },
-                )
-            }
-        }
-        assertThatColors(getNonBackgroundColors()).containsExactly(testColor)
-    }
-
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
-    @Test
-    fun whenContextMenuColors_enabledToggled_colorsChangeAsExpected() {
-        val enabledColor = Color.Red
-        val disabledColor = Color.Blue
-        val colors = transparentColors(
-            textColor = enabledColor,
-            iconColor = enabledColor,
-            disabledTextColor = disabledColor,
-            disabledIconColor = disabledColor,
-        )
-
-        var enabled by mutableStateOf(true)
-        rule.setContent {
-            TestColumn(colors) {
-                testItem(
-                    label = "M".repeat(5),
-                    enabled = enabled,
-                    leadingIcon = { iconColor ->
-                        Box(
-                            Modifier
-                                .background(iconColor)
-                                .fillMaxSize()
-                        )
-                    },
-                )
-            }
-        }
-
-        repeat(2) {
-            enabled = true
-            rule.waitForIdle()
-            assertThatColors(getNonBackgroundColors()).containsExactly(enabledColor)
-
-            enabled = false
-            rule.waitForIdle()
-            assertThatColors(getNonBackgroundColors()).containsExactly(disabledColor)
-        }
-    }
-    // endregion ContextMenuColor Tests
-
     // region ContextMenuPopup Tests
     private val centeringPopupPositionProvider = object : PopupPositionProvider {
         override fun calculatePosition(
@@ -714,50 +563,5 @@
             rule.onNodeWithTag(itemTag).assertExists()
         }
     }
-
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
-    @Test
-    fun whenContextMenuPopup_enabledDisabled_colorsAreAsExpected() {
-        var enabled by mutableStateOf(true)
-        rule.setContent {
-            CompositionLocalProvider(LocalContextMenuColors provides TestColors) {
-                ContextMenuPopup(
-                    modifier = Modifier.testTag(tag),
-                    popupPositionProvider = centeringPopupPositionProvider,
-                    onDismiss = {},
-                ) {
-                    testItem(
-                        label = "M".repeat(10),
-                        enabled = enabled,
-                        leadingIcon = { iconColor ->
-                            Box(
-                                Modifier
-                                    .background(iconColor)
-                                    .fillMaxSize()
-                            )
-                        },
-                    )
-                }
-            }
-        }
-
-        repeat(2) {
-            enabled = true
-            rule.waitForIdle()
-            assertThatColors(getColors()).containsExactly(
-                TestColors.backgroundColor,
-                TestColors.textColor,
-                TestColors.iconColor
-            )
-
-            enabled = false
-            rule.waitForIdle()
-            assertThatColors(getColors()).containsExactly(
-                TestColors.backgroundColor,
-                TestColors.disabledTextColor,
-                TestColors.disabledIconColor
-            )
-        }
-    }
     // endregion ContextMenuPopup Tests
 }
diff --git a/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/text/CoreTextFieldHandwritingTest.kt b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/text/CoreTextFieldHandwritingTest.kt
index 2f008d6..3dc1a55 100644
--- a/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/text/CoreTextFieldHandwritingTest.kt
+++ b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/text/CoreTextFieldHandwritingTest.kt
@@ -26,11 +26,14 @@
 import androidx.compose.foundation.text.input.internal.inputMethodManagerFactory
 import androidx.compose.foundation.text.matchers.isZero
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalWindowInfo
+import androidx.compose.ui.platform.WindowInfo
 import androidx.compose.ui.platform.testTag
 import androidx.compose.ui.test.SemanticsNodeInteraction
 import androidx.compose.ui.test.junit4.createComposeRule
@@ -201,6 +204,42 @@
         performHandwritingAndExpect(stylusHandwritingStarted = true)
     }
 
+    @Test
+    fun coreTextField_toggleWindowFocus_startStylusHandwriting() {
+        inputMethodManagerFactory = { fakeImm }
+
+        val focusWindow = mutableStateOf(true)
+        fun createWindowInfo(focused: Boolean) = object : WindowInfo {
+            override val isWindowFocused: Boolean
+                get() = focused
+        }
+
+        setContent {
+            CompositionLocalProvider(
+                LocalWindowInfo provides createWindowInfo(focusWindow.value)
+            ) {
+                val value = remember { TextFieldValue() }
+                CoreTextField(
+                    value = value,
+                    onValueChange = { },
+                    modifier = Modifier
+                        .fillMaxSize()
+                        .testTag(Tag),
+                )
+            }
+        }
+
+        performHandwritingAndExpect(stylusHandwritingStarted = true)
+
+        focusWindow.value = false
+        rule.waitForIdle()
+        performHandwritingAndExpect(stylusHandwritingStarted = false)
+
+        focusWindow.value = true
+        rule.waitForIdle()
+        performHandwritingAndExpect(stylusHandwritingStarted = true)
+    }
+
     private fun testStylusHandwriting(
         stylusHandwritingStarted: Boolean,
         interaction: SemanticsNodeInteraction.() -> Unit
diff --git a/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/text/CoreTextFieldInputServiceIntegrationTest.kt b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/text/CoreTextFieldInputServiceIntegrationTest.kt
index e3f3e01..ba05692 100644
--- a/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/text/CoreTextFieldInputServiceIntegrationTest.kt
+++ b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/text/CoreTextFieldInputServiceIntegrationTest.kt
@@ -42,7 +42,9 @@
 import androidx.compose.ui.graphics.toComposeIntRect
 import androidx.compose.ui.platform.LocalFocusManager
 import androidx.compose.ui.platform.LocalSoftwareKeyboardController
+import androidx.compose.ui.platform.LocalWindowInfo
 import androidx.compose.ui.platform.SoftwareKeyboardController
+import androidx.compose.ui.platform.WindowInfo
 import androidx.compose.ui.platform.testTag
 import androidx.compose.ui.test.junit4.createComposeRule
 import androidx.compose.ui.test.onNodeWithTag
@@ -519,6 +521,48 @@
         }
     }
 
+    @Test
+    fun textField_stopAndStartInput_whenToggleWindowFocus() {
+        val value = TextFieldValue("abc")
+        val focusRequester = FocusRequester()
+
+        val focusWindow = mutableStateOf(true)
+        fun createWindowInfo(focused: Boolean) = object : WindowInfo {
+            override val isWindowFocused: Boolean
+                get() = focused
+        }
+
+        setContent {
+            CompositionLocalProvider(
+                LocalWindowInfo provides createWindowInfo(focusWindow.value)
+            ) {
+                CoreTextField(
+                    value = value,
+                    onValueChange = {},
+                    modifier = Modifier.focusRequester(focusRequester)
+                )
+            }
+        }
+
+        rule.runOnUiThread {
+            focusRequester.requestFocus()
+        }
+
+        rule.runOnIdle {
+            inputMethodInterceptor.assertSessionActive()
+        }
+
+        focusWindow.value = false
+        rule.runOnIdle {
+            inputMethodInterceptor.assertNoSessionActive()
+        }
+
+        focusWindow.value = true
+        rule.runOnIdle {
+            inputMethodInterceptor.assertSessionActive()
+        }
+    }
+
     private fun setContent(
         extraItemForInitialFocus: Boolean = true,
         content: @Composable () -> Unit
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/Magnifier.android.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/Magnifier.android.kt
index 59e1459..186bdd2 100644
--- a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/Magnifier.android.kt
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/Magnifier.android.kt
@@ -199,15 +199,15 @@
         if (this === other) return true
         if (other !is MagnifierElement) return false
 
-        if (sourceCenter != other.sourceCenter) return false
-        if (magnifierCenter != other.magnifierCenter) return false
+        if (sourceCenter !== other.sourceCenter) return false
+        if (magnifierCenter !== other.magnifierCenter) return false
         if (zoom != other.zoom) return false
         if (useTextDefault != other.useTextDefault) return false
         if (size != other.size) return false
         if (cornerRadius != other.cornerRadius) return false
         if (elevation != other.elevation) return false
         if (clippingEnabled != other.clippingEnabled) return false
-        if (onSizeChanged != other.onSizeChanged) return false
+        if (onSizeChanged !== other.onSizeChanged) return false
         if (platformMagnifierFactory != other.platformMagnifierFactory) return false
 
         return true
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/PreferKeepClear.android.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/PreferKeepClear.android.kt
index 346ba634b..e6bd917 100644
--- a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/PreferKeepClear.android.kt
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/PreferKeepClear.android.kt
@@ -84,7 +84,7 @@
 
     override fun equals(other: Any?): Boolean {
         if (other !is PreferKeepClearNode) return false
-        return clearRect == other.rect
+        return clearRect === other.rect
     }
 
     override fun InspectorInfo.inspectableProperties() {
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/SystemGestureExclusion.android.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/SystemGestureExclusion.android.kt
index a9b7f5d..77699fa 100644
--- a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/SystemGestureExclusion.android.kt
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/SystemGestureExclusion.android.kt
@@ -84,7 +84,7 @@
 
     override fun equals(other: Any?): Boolean {
         if (other !is ExcludeFromSystemGestureElement) return false
-        return exclusion == other.exclusion
+        return exclusion === other.exclusion
     }
 
     override fun InspectorInfo.inspectableProperties() {
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/contextmenu/ContextMenuArea.android.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/contextmenu/ContextMenuArea.android.kt
index d585346..bb0792d 100644
--- a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/contextmenu/ContextMenuArea.android.kt
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/contextmenu/ContextMenuArea.android.kt
@@ -22,12 +22,7 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.remember
 import androidx.compose.ui.Modifier
-import androidx.compose.ui.unit.IntOffset
-import androidx.compose.ui.unit.IntRect
-import androidx.compose.ui.unit.IntSize
-import androidx.compose.ui.unit.LayoutDirection
 import androidx.compose.ui.unit.round
-import androidx.compose.ui.window.PopupPositionProvider
 
 /**
  * Wraps [content] with the necessary components to show a context menu in it.
@@ -67,7 +62,9 @@
     val status = state.status
     if (status !is Status.Open) return
 
-    val popupPositionProvider = remember(status) { StaticPositionProvider(status.offset.round()) }
+    val popupPositionProvider = remember(status) {
+        ContextMenuPopupPositionProvider(status.offset.round())
+    }
 
     ContextMenuPopup(
         modifier = modifier,
@@ -76,18 +73,3 @@
         contextMenuBuilderBlock = contextMenuBuilderBlock,
     )
 }
-
-// TODO(b/331958453) Create a smarter provider that will handle
-//  moving the menu outside of the click position when
-//  the menu is in the bottom right corner.
-private class StaticPositionProvider(
-    // The position should be local to the layout the popup is attached to.
-    private val localPosition: IntOffset,
-) : PopupPositionProvider {
-    override fun calculatePosition(
-        anchorBounds: IntRect,
-        windowSize: IntSize,
-        layoutDirection: LayoutDirection,
-        popupContentSize: IntSize
-    ): IntOffset = anchorBounds.topLeft + localPosition
-}
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/contextmenu/ContextMenuPopupPositionProvider.android.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/contextmenu/ContextMenuPopupPositionProvider.android.kt
new file mode 100644
index 0000000..82dbe14
--- /dev/null
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/contextmenu/ContextMenuPopupPositionProvider.android.kt
@@ -0,0 +1,136 @@
+/*
+ * 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.foundation.contextmenu
+
+import androidx.annotation.VisibleForTesting
+import androidx.compose.ui.unit.IntOffset
+import androidx.compose.ui.unit.IntRect
+import androidx.compose.ui.unit.IntSize
+import androidx.compose.ui.unit.LayoutDirection
+import androidx.compose.ui.window.PopupPositionProvider
+
+/**
+ * A [PopupPositionProvider] which places the context menu fully within the window,
+ * aligning a corner of the popup menu with the cursor. For each x/y dimension it will:
+ *
+ * * In cases where the popup length is too small for the window length, it aligns the
+ * start edges of the popup and the window.
+ * * In cases where there is enough length between the click position and the end of
+ * the window for entire popup length, it will align the start edge of the popup with the
+ * [localPosition].
+ * * In cases where there is not enough length between the click position and the end of
+ * the window for entire popup length, but there is between the click position and the
+ * start of the window, it will align the end edge of the popup with the [localPosition].
+ * * In the final case: the window length is wide enough for the popup, but there isn't enough
+ * length on either side of click position to fit an edge of the popup with the click position.
+ * It will align the end edges of the popup and window.
+ *
+ * @param localPosition The [IntOffset] to align to. This should be in the same coordinates that
+ * the `Popup` is anchored to.
+ */
+internal class ContextMenuPopupPositionProvider(
+    private val localPosition: IntOffset,
+) : PopupPositionProvider {
+    // TODO(b/256233441) anchorBounds should be positioned within the window that
+    //  windowSize is derived from. However, it seems that windowSize's
+    //  bounds do not include the top decoration, while the window anchorBounds
+    //  is derived from does include the top decoration. This causes the
+    //  resulting calculation to be off when approaching the bottom of the screen.
+    override fun calculatePosition(
+        anchorBounds: IntRect,
+        windowSize: IntSize,
+        layoutDirection: LayoutDirection,
+        popupContentSize: IntSize
+    ): IntOffset = IntOffset(
+        x = alignPopupAxis(
+            position = anchorBounds.left + localPosition.x,
+            popupLength = popupContentSize.width,
+            windowLength = windowSize.width,
+            closeAffinity = layoutDirection == LayoutDirection.Ltr
+        ),
+        y = alignPopupAxis(
+            position = anchorBounds.top + localPosition.y,
+            popupLength = popupContentSize.height,
+            windowLength = windowSize.height,
+        )
+    )
+}
+
+/**
+ * Align the popup to the position along an axis.
+ *
+ * @param position The position to align to along the window's axis
+ * @param popupLength The length of the popup along this axis
+ * @param windowLength The length of the window along this axis
+ * @param closeAffinity Whether the start side is the close edge (`0`)
+ * or the far edge ([windowLength])
+ * @return the coordinate along this axis that best aligns the popup to the position
+ */
+@VisibleForTesting
+internal fun alignPopupAxis(
+    position: Int,
+    popupLength: Int,
+    windowLength: Int,
+    closeAffinity: Boolean = true,
+): Int = when {
+    popupLength >= windowLength -> alignStartEdges(popupLength, windowLength, closeAffinity)
+
+    popupFitsBetweenPositionAndEndEdge(position, popupLength, windowLength, closeAffinity) ->
+        alignPopupStartEdgeToPosition(position, popupLength, closeAffinity)
+
+    popupFitsBetweenPositionAndStartEdge(position, popupLength, windowLength, closeAffinity) ->
+        alignPopupEndEdgeToPosition(position, popupLength, closeAffinity)
+
+    else -> alignEndEdges(popupLength, windowLength, closeAffinity)
+}
+
+private fun popupFitsBetweenPositionAndStartEdge(
+    position: Int,
+    popupLength: Int,
+    windowLength: Int,
+    closeAffinity: Boolean,
+): Boolean = if (closeAffinity) {
+    popupLength <= position
+} else {
+    windowLength - popupLength > position
+}
+
+private fun popupFitsBetweenPositionAndEndEdge(
+    position: Int,
+    popupLength: Int,
+    windowLength: Int,
+    closeAffinity: Boolean,
+): Boolean =
+    popupFitsBetweenPositionAndStartEdge(position, popupLength, windowLength, !closeAffinity)
+
+private fun alignPopupStartEdgeToPosition(
+    position: Int,
+    popupLength: Int,
+    closeAffinity: Boolean,
+): Int = if (closeAffinity) position else position - popupLength
+
+private fun alignPopupEndEdgeToPosition(
+    position: Int,
+    popupLength: Int,
+    closeAffinity: Boolean,
+): Int = alignPopupStartEdgeToPosition(position, popupLength, !closeAffinity)
+
+private fun alignStartEdges(popupLength: Int, windowLength: Int, closeAffinity: Boolean): Int =
+    if (closeAffinity) 0 else windowLength - popupLength
+
+private fun alignEndEdges(popupLength: Int, windowLength: Int, closeAffinity: Boolean): Int =
+    alignStartEdges(popupLength, windowLength, !closeAffinity)
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/contextmenu/ContextMenuUi.android.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/contextmenu/ContextMenuUi.android.kt
index 1f20fdd..0056666 100644
--- a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/contextmenu/ContextMenuUi.android.kt
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/contextmenu/ContextMenuUi.android.kt
@@ -36,28 +36,33 @@
 import androidx.compose.foundation.text.BasicText
 import androidx.compose.foundation.verticalScroll
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.mutableStateListOf
 import androidx.compose.runtime.remember
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.draw.shadow
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.text.TextStyle
-import androidx.compose.ui.text.font.FontWeight.Companion.Medium
 import androidx.compose.ui.text.style.TextAlign
 import androidx.compose.ui.unit.dp
-import androidx.compose.ui.unit.sp
 import androidx.compose.ui.util.fastForEach
 import androidx.compose.ui.window.Popup
 import androidx.compose.ui.window.PopupPositionProvider
 import androidx.compose.ui.window.PopupProperties
 
-/**
- * Layout constants from the [Material 3 Menu Spec](https://m3.material.io/components/menus/specs).
- */
+private const val DisabledAlpha = 0.38f
+private const val IconAlpha = 0.6f
+
 @VisibleForTesting
 internal object ContextMenuSpec {
-    // dimensions
+    // TODO(b/331955999) Determine colors/theming
+    private val PrimaryColor = Color.Black
+    val BackgroundColor = Color.White
+
+    val TextColor = PrimaryColor
+    val IconColor = PrimaryColor.copy(alpha = IconAlpha)
+    val DisabledColor = PrimaryColor.copy(DisabledAlpha)
+
+    // Layout constants from https://m3.material.io/components/menus/specs
     val ContainerWidthMin = 112.dp
     val ContainerWidthMax = 280.dp
     val ListItemHeight = 48.dp
@@ -68,20 +73,6 @@
     val HorizontalPadding = 12.dp // left/right of column and between elements in rows
     val VerticalPadding = 8.dp // top/bottom of column and around dividers
     val IconSize = 24.dp
-
-    // text
-    val FontSize = 14.sp
-    val FontWeight = Medium
-    val LineHeight = 20.sp
-    val LetterSpacing = 0.1f.sp
-    fun textStyle(color: Color): TextStyle = TextStyle(
-        color = color,
-        textAlign = LabelHorizontalTextAlignment,
-        fontSize = FontSize,
-        fontWeight = FontWeight,
-        lineHeight = LineHeight,
-        letterSpacing = LetterSpacing,
-    )
 }
 
 private val DefaultPopupProperties = PopupProperties(focusable = true)
@@ -98,13 +89,12 @@
         onDismissRequest = onDismiss,
         properties = DefaultPopupProperties,
     ) {
-        val colors = LocalContextMenuColors.current ?: DefaultContextMenuColors
-        ContextMenuColumn(colors, modifier) {
+        ContextMenuColumn(modifier) {
             val scope = remember { ContextMenuScope() }
             with(scope) {
                 clear()
                 contextMenuBuilderBlock()
-                Content(colors)
+                Content()
             }
         }
     }
@@ -113,7 +103,6 @@
 @VisibleForTesting
 @Composable
 internal fun ContextMenuColumn(
-    colors: ContextMenuColors,
     modifier: Modifier = Modifier,
     content: @Composable ColumnScope.() -> Unit,
 ) {
@@ -123,7 +112,7 @@
                 ContextMenuSpec.MenuContainerElevation,
                 RoundedCornerShape(ContextMenuSpec.CornerRadius)
             )
-            .background(colors.backgroundColor)
+            .background(ContextMenuSpec.BackgroundColor)
             .width(IntrinsicSize.Max)
             .padding(vertical = ContextMenuSpec.VerticalPadding)
             .verticalScroll(rememberScrollState()),
@@ -138,7 +127,6 @@
 internal fun ContextMenuItem(
     label: String,
     enabled: Boolean,
-    colors: ContextMenuColors,
     modifier: Modifier = Modifier,
     /**
      * Icon to place in front of the label. If null, the icon will not be rendered
@@ -182,12 +170,13 @@
                     maxWidth = ContextMenuSpec.IconSize,
                     maxHeight = ContextMenuSpec.IconSize,
                 )
-            ) { icon(if (enabled) colors.iconColor else colors.disabledIconColor) }
+            ) { icon(if (enabled) ContextMenuSpec.IconColor else ContextMenuSpec.DisabledColor) }
         }
         BasicText(
             text = label,
-            style = ContextMenuSpec.textStyle(
-                color = if (enabled) colors.textColor else colors.disabledTextColor,
+            style = TextStyle(
+                color = if (enabled) ContextMenuSpec.TextColor else ContextMenuSpec.DisabledColor,
+                textAlign = ContextMenuSpec.LabelHorizontalTextAlignment,
             ),
             maxLines = 1,
             modifier = Modifier.weight(1f, fill = true)
@@ -202,11 +191,11 @@
 // arbitrary composables into a context menu. Instead, we expose this API which then maps to
 // context menu composables.
 internal class ContextMenuScope internal constructor() {
-    private val composables = mutableStateListOf<@Composable (colors: ContextMenuColors) -> Unit>()
+    private val composables = mutableListOf<@Composable () -> Unit>()
 
     @Composable
-    internal fun Content(colors: ContextMenuColors) {
-        composables.fastForEach { composable -> composable(colors) }
+    internal fun Content() {
+        composables.fastForEach { composable -> composable() }
     }
 
     internal fun clear() {
@@ -234,8 +223,7 @@
         /**
          * Icon to place in front of the label. If null, the icon will not be rendered
          * and the text will instead be further towards the start. The `iconColor` will
-         * change based on whether the item is disabled or not. The size of this composable
-         * will be [ContextMenuSpec.IconSize].
+         * change based on whether the item is disabled or not.
          */
         leadingIcon: @Composable ((iconColor: Color) -> Unit)? = null,
         /**
@@ -247,26 +235,14 @@
         onClick: () -> Unit,
     ) {
         check(label.isNotBlank()) { "Label must not be blank" }
-        composables += { colors ->
+        composables += {
             ContextMenuItem(
                 modifier = modifier,
                 label = label,
                 enabled = enabled,
-                colors = colors,
                 leadingIcon = leadingIcon,
                 onClick = onClick
             )
         }
     }
 }
-
-private const val DisabledAlpha = 0.38f
-private const val IconAlpha = 0.6f
-
-private val DefaultContextMenuColors = ContextMenuColors(
-    backgroundColor = Color.White,
-    textColor = Color.Black,
-    iconColor = Color.Black.copy(alpha = IconAlpha),
-    disabledTextColor = Color.Black.copy(alpha = DisabledAlpha),
-    disabledIconColor = Color.Black.copy(alpha = DisabledAlpha),
-)
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text/handwriting/HandwritingDelegator.android.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text/handwriting/HandwritingDelegator.android.kt
index b4a18c5..4545e0a 100644
--- a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text/handwriting/HandwritingDelegator.android.kt
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text/handwriting/HandwritingDelegator.android.kt
@@ -65,7 +65,7 @@
     override fun hashCode() = 31 * callback.hashCode()
 
     override fun equals(other: Any?) =
-        (this === other) or ((other is HandwritingDelegatorElement) && callback == other.callback)
+        (this === other) or ((other is HandwritingDelegatorElement) && callback === other.callback)
 
     override fun InspectorInfo.inspectableProperties() {
         name = "handwritingDelegator"
diff --git a/compose/foundation/foundation/src/androidUnitTest/kotlin/androidx/compose/foundation/contextmenu/ContextMenuPopupPositionProviderTest.kt b/compose/foundation/foundation/src/androidUnitTest/kotlin/androidx/compose/foundation/contextmenu/ContextMenuPopupPositionProviderTest.kt
new file mode 100644
index 0000000..e762655
--- /dev/null
+++ b/compose/foundation/foundation/src/androidUnitTest/kotlin/androidx/compose/foundation/contextmenu/ContextMenuPopupPositionProviderTest.kt
@@ -0,0 +1,227 @@
+/*
+ * 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.foundation.contextmenu
+
+import androidx.compose.ui.unit.IntOffset
+import androidx.compose.ui.unit.IntRect
+import androidx.compose.ui.unit.IntSize
+import androidx.compose.ui.unit.LayoutDirection
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+
+class ContextMenuPopupPositionProviderTest {
+    //region ContextMenuPopupPositionProvider Tests
+    @Test
+    fun calculatePosition_onlyFitsInXDirection() {
+        val layoutDirection = LayoutDirection.Ltr
+        val windowSize = IntSize(width = 100, height = 100)
+        val anchorBounds = IntRect(left = 10, top = 20, right = 90, bottom = 80)
+        val position = IntOffset(x = 40, y = 30) // 50, 50 when translated to window
+        val popupContentSize = IntSize(width = 10, height = 200)
+
+        val subject = ContextMenuPopupPositionProvider(position)
+        val actual =
+            subject.calculatePosition(anchorBounds, windowSize, layoutDirection, popupContentSize)
+
+        assertThat(actual).isEqualTo(IntOffset(50, 0))
+    }
+
+    @Test
+    fun calculatePosition_onlyFitsInYDirection() {
+        val layoutDirection = LayoutDirection.Ltr
+        val windowSize = IntSize(width = 100, height = 100)
+        val anchorBounds = IntRect(left = 10, top = 20, right = 90, bottom = 80)
+        val position = IntOffset(x = 40, y = 30) // 50, 50 when translated to window
+        val popupContentSize = IntSize(width = 200, height = 10)
+
+        val subject = ContextMenuPopupPositionProvider(position)
+        val actual =
+            subject.calculatePosition(anchorBounds, windowSize, layoutDirection, popupContentSize)
+
+        assertThat(actual).isEqualTo(IntOffset(0, 50))
+    }
+
+    @Test
+    fun calculatePosition_windowIsAccountedFor_ltr() {
+        val layoutDirection = LayoutDirection.Ltr
+        val windowSize = IntSize(width = 100, height = 100)
+        val anchorBounds = IntRect(left = 10, top = 20, right = 90, bottom = 80)
+        val position = IntOffset(x = 40, y = 30) // 50, 50 when translated to window
+        val popupContentSize = IntSize(width = 10, height = 10)
+
+        val subject = ContextMenuPopupPositionProvider(position)
+        val actual =
+            subject.calculatePosition(anchorBounds, windowSize, layoutDirection, popupContentSize)
+
+        assertThat(actual).isEqualTo(IntOffset(50, 50))
+    }
+
+    @Test
+    fun calculatePosition_windowIsAccountedFor_rtl() {
+        val layoutDirection = LayoutDirection.Rtl
+        val windowSize = IntSize(width = 100, height = 100)
+        val anchorBounds = IntRect(left = 10, top = 20, right = 90, bottom = 80)
+        val position = IntOffset(x = 40, y = 30) // 50, 50 when translated to window
+        val popupContentSize = IntSize(width = 10, height = 10)
+
+        val subject = ContextMenuPopupPositionProvider(position)
+        val actual =
+            subject.calculatePosition(anchorBounds, windowSize, layoutDirection, popupContentSize)
+
+        assertThat(actual).isEqualTo(IntOffset(40, 50))
+    }
+    //endregion ContextMenuPopupPositionProvider Tests
+
+    //region alignPopupAxis Tests
+    @Test
+    fun alignPopupAxis_closeAffinity_popupLargerThanWindow() = alignPopupAxisTest(
+        position = 50,
+        popupLength = 200,
+        closeAffinity = true,
+        expected = 0
+    )
+
+    @Test
+    fun alignPopupAxis_closeAffinity_popupFitsNeitherSide() = alignPopupAxisTest(
+        position = 50,
+        popupLength = 75,
+        closeAffinity = true,
+        expected = 25
+    )
+
+    @Test
+    fun alignPopupAxis_closeAffinity_popupFitsCloseSide() = alignPopupAxisTest(
+        position = 90,
+        popupLength = 30,
+        closeAffinity = true,
+        expected = 60
+    )
+
+    @Test
+    fun alignPopupAxis_closeAffinity_popupFitsFarSide() = alignPopupAxisTest(
+        position = 20,
+        popupLength = 30,
+        closeAffinity = true,
+        expected = 20
+    )
+
+    @Test
+    fun alignPopupAxis_closeAffinity_popupFitsEitherSide() = alignPopupAxisTest(
+        position = 50,
+        popupLength = 10,
+        closeAffinity = true,
+        expected = 50
+    )
+
+    @Test
+    fun alignPopupAxis_farAffinity_popupLargerThanWindow() = alignPopupAxisTest(
+        position = 50,
+        popupLength = 200,
+        closeAffinity = false,
+        expected = -100
+    )
+
+    @Test
+    fun alignPopupAxis_farAffinity_popupFitsNeitherSide() = alignPopupAxisTest(
+        position = 50,
+        popupLength = 75,
+        closeAffinity = false,
+        expected = 0
+    )
+
+    @Test
+    fun alignPopupAxis_farAffinity_popupFitsCloseSide() = alignPopupAxisTest(
+        position = 90,
+        popupLength = 30,
+        closeAffinity = false,
+        expected = 60
+    )
+
+    @Test
+    fun alignPopupAxis_farAffinity_popupFitsFarSide() = alignPopupAxisTest(
+        position = 20,
+        popupLength = 30,
+        closeAffinity = false,
+        expected = 20
+    )
+
+    @Test
+    fun alignPopupAxis_farAffinity_popupFitsEitherSide() = alignPopupAxisTest(
+        position = 50,
+        popupLength = 10,
+        closeAffinity = false,
+        expected = 40
+    )
+
+    private fun alignPopupAxisTest(
+        position: Int,
+        popupLength: Int,
+        closeAffinity: Boolean,
+        expected: Int
+    ) {
+        val actual = alignPopupAxis(
+            position = position,
+            popupLength = popupLength,
+            windowLength = 100,
+            closeAffinity = closeAffinity
+        )
+        assertThat(actual).isEqualTo(expected)
+    }
+
+    @Test
+    fun alignPopupAxis_popupBarelyFitsInAfterSpace() {
+        val actual = alignPopupAxis(
+            position = 74,
+            popupLength = 25,
+            windowLength = 100,
+        )
+        assertThat(actual).isEqualTo(74)
+    }
+
+    @Test
+    fun alignPopupAxis_popupBarelyDoesNotFitInAfterSpace() {
+        val actual = alignPopupAxis(
+            position = 75,
+            popupLength = 25,
+            windowLength = 100,
+        )
+        assertThat(actual).isEqualTo(50)
+    }
+
+    @Test
+    fun alignPopupAxis_popupBarelyFitsInBeforeSpace() {
+        val actual = alignPopupAxis(
+            position = 25,
+            popupLength = 25,
+            windowLength = 100,
+            closeAffinity = false
+        )
+        assertThat(actual).isEqualTo(0)
+    }
+
+    @Test
+    fun alignPopupAxis_popupBarelyDoesNotFitInBeforeSpace() {
+        val actual = alignPopupAxis(
+            position = 24,
+            popupLength = 25,
+            windowLength = 100,
+            closeAffinity = false
+        )
+        assertThat(actual).isEqualTo(24)
+    }
+    //endregion alignPopupAxis Tests
+}
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Clickable.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Clickable.kt
index 3981ac6..2cea5ef 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Clickable.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Clickable.kt
@@ -514,7 +514,7 @@
         if (enabled != other.enabled) return false
         if (onClickLabel != other.onClickLabel) return false
         if (role != other.role) return false
-        if (onClick != other.onClick) return false
+        if (onClick !== other.onClick) return false
 
         return true
     }
@@ -592,10 +592,10 @@
         if (enabled != other.enabled) return false
         if (onClickLabel != other.onClickLabel) return false
         if (role != other.role) return false
-        if (onClick != other.onClick) return false
+        if (onClick !== other.onClick) return false
         if (onLongClickLabel != other.onLongClickLabel) return false
-        if (onLongClick != other.onLongClick) return false
-        if (onDoubleClick != other.onDoubleClick) return false
+        if (onLongClick !== other.onLongClick) return false
+        if (onDoubleClick !== other.onDoubleClick) return false
 
         return true
     }
@@ -826,7 +826,7 @@
             resetPointerInputHandling = true
         }
 
-        if (this.onLongClick != onLongClick) {
+        if (this.onLongClick !== onLongClick) {
             this.onLongClick = onLongClick
             invalidateSemantics()
         }
@@ -1225,9 +1225,9 @@
         if (enabled != other.enabled) return false
         if (role != other.role) return false
         if (onLongClickLabel != other.onLongClickLabel) return false
-        if (onLongClick != other.onLongClick) return false
+        if (onLongClick !== other.onLongClick) return false
         if (onClickLabel != other.onClickLabel) return false
-        if (onClick != other.onClick) return false
+        if (onClick !== other.onClick) return false
 
         return true
     }
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/FocusedBounds.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/FocusedBounds.kt
index 01f5f64..df7af80 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/FocusedBounds.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/FocusedBounds.kt
@@ -55,7 +55,7 @@
     override fun equals(other: Any?): Boolean {
         if (this === other) return true
         val otherModifier = other as? FocusedBoundsObserverElement ?: return false
-        return onPositioned == otherModifier.onPositioned
+        return onPositioned === otherModifier.onPositioned
     }
 
     override fun InspectorInfo.inspectableProperties() {
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/contextmenu/ContextMenuUi.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/contextmenu/ContextMenuUi.kt
deleted file mode 100644
index 1ff9031..0000000
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/contextmenu/ContextMenuUi.kt
+++ /dev/null
@@ -1,79 +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.foundation.contextmenu
-
-import androidx.compose.runtime.CompositionLocalProvider
-import androidx.compose.runtime.ProvidableCompositionLocal
-import androidx.compose.runtime.Stable
-import androidx.compose.runtime.compositionLocalOf
-import androidx.compose.ui.graphics.Color
-
-/**
- * Provides the colors for the context menu.
- *
- * Use with [CompositionLocalProvider] to apply your custom colors to the context menu.
- */
-val LocalContextMenuColors: ProvidableCompositionLocal<ContextMenuColors?> =
-    compositionLocalOf { null }
-
-/**
- * Colors to be provided to [LocalContextMenuColors] to apply the colors to the context menu.
- *
- * @param backgroundColor Color of the background in the context menu
- * @param textColor Color of the text in context menu items
- * @param iconColor Color of any icons in context menu items
- * @param disabledTextColor Color of disabled text in context menu items
- * @param disabledIconColor Color of any disabled icons in context menu items
- */
-@Stable
-class ContextMenuColors(
-    val backgroundColor: Color,
-    val textColor: Color,
-    val iconColor: Color,
-    val disabledTextColor: Color,
-    val disabledIconColor: Color,
-) {
-    override fun equals(other: Any?): Boolean {
-        if (this === other) return true
-        if (other == null || other !is ContextMenuColors) return false
-
-        if (this.backgroundColor != other.backgroundColor) return false
-        if (this.textColor != other.textColor) return false
-        if (this.iconColor != other.iconColor) return false
-        if (this.disabledTextColor != other.disabledTextColor) return false
-        if (this.disabledIconColor != other.disabledIconColor) return false
-
-        return true
-    }
-
-    override fun hashCode(): Int {
-        var result = backgroundColor.hashCode()
-        result = 31 * result + textColor.hashCode()
-        result = 31 * result + iconColor.hashCode()
-        result = 31 * result + disabledTextColor.hashCode()
-        result = 31 * result + disabledIconColor.hashCode()
-        return result
-    }
-
-    override fun toString(): String = "ContextMenuColors(" +
-        "backgroundColor=$backgroundColor, " +
-        "textColor=$textColor, " +
-        "iconColor=$iconColor, " +
-        "disabledTextColor=$disabledTextColor, " +
-        "disabledIconColor=$disabledIconColor" +
-        ")"
-}
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/draganddrop/DragAndDropTarget.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/draganddrop/DragAndDropTarget.kt
index 2a082d1..2a14342 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/draganddrop/DragAndDropTarget.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/draganddrop/DragAndDropTarget.kt
@@ -79,7 +79,7 @@
         if (other !is DropTargetElement) return false
         if (target != other.target) return false
 
-        return shouldStartDragAndDrop == other.shouldStartDragAndDrop
+        return shouldStartDragAndDrop === other.shouldStartDragAndDrop
     }
 
     override fun hashCode(): Int {
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/Transformable.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/Transformable.kt
index 1e4abd9..297c21c 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/Transformable.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/Transformable.kt
@@ -116,7 +116,7 @@
         other as TransformableElement
 
         if (state != other.state) return false
-        if (canPan != other.canPan) return false
+        if (canPan !== other.canPan) return false
         if (lockRotationOnZoomPan != other.lockRotationOnZoomPan) return false
         if (enabled != other.enabled) return false
 
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutSemantics.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutSemantics.kt
index 18a65d3..1920744 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutSemantics.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutSemantics.kt
@@ -89,7 +89,7 @@
         if (this === other) return true
         if (other !is LazyLayoutSemanticsModifier) return false
 
-        if (itemProviderLambda != other.itemProviderLambda) return false
+        if (itemProviderLambda !== other.itemProviderLambda) return false
         if (state != other.state) return false
         if (orientation != other.orientation) return false
         if (userScrollEnabled != other.userScrollEnabled) return false
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/selection/Selectable.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/selection/Selectable.kt
index caa756a..70d94a9 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/selection/Selectable.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/selection/Selectable.kt
@@ -203,7 +203,7 @@
         if (indicationNodeFactory != other.indicationNodeFactory) return false
         if (enabled != other.enabled) return false
         if (role != other.role) return false
-        if (onClick != other.onClick) return false
+        if (onClick !== other.onClick) return false
 
         return true
     }
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/selection/Toggleable.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/selection/Toggleable.kt
index b75e3c1..bcaa2ed 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/selection/Toggleable.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/selection/Toggleable.kt
@@ -197,7 +197,7 @@
         if (indicationNodeFactory != other.indicationNodeFactory) return false
         if (enabled != other.enabled) return false
         if (role != other.role) return false
-        if (onValueChange != other.onValueChange) return false
+        if (onValueChange !== other.onValueChange) return false
 
         return true
     }
@@ -433,7 +433,7 @@
         if (indicationNodeFactory != other.indicationNodeFactory) return false
         if (enabled != other.enabled) return false
         if (role != other.role) return false
-        if (onClick != other.onClick) return false
+        if (onClick !== other.onClick) return false
 
         return true
     }
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/shape/GenericShape.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/shape/GenericShape.kt
index e3a65a3..79ca230 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/shape/GenericShape.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/shape/GenericShape.kt
@@ -46,7 +46,7 @@
 
     override fun equals(other: Any?): Boolean {
         if (this === other) return true
-        return (other as? GenericShape)?.builder == builder
+        return (other as? GenericShape)?.builder === builder
     }
 
     override fun hashCode(): Int {
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/CoreTextField.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/CoreTextField.kt
index ccd7d9f..5b64b4b 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/CoreTextField.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/CoreTextField.kt
@@ -349,7 +349,7 @@
     }
 
     // Hide the keyboard if made disabled or read-only while focused (b/237308379).
-    val writeable by rememberUpdatedState(enabled && !readOnly)
+    val writeable by rememberUpdatedState(enabled && !readOnly && windowInfo.isWindowFocused)
     LaunchedEffect(Unit) {
         try {
             snapshotFlow { writeable }.collect { writeable ->
@@ -405,8 +405,8 @@
         .pointerHoverIcon(textPointerIcon)
         .then(
             if (isStylusHandwritingSupported) {
-                Modifier.pointerInput(enabled, readOnly) {
-                    if (enabled && !readOnly) {
+                Modifier.pointerInput(writeable) {
+                    if (writeable) {
                         detectStylusHandwriting {
                             if (!state.hasFocus) {
                                 focusRequester.requestFocus()
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/KeyboardActions.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/KeyboardActions.kt
index d5112f2..428c7b8 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/KeyboardActions.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/KeyboardActions.kt
@@ -74,12 +74,12 @@
         if (this === other) return true
         if (other !is KeyboardActions) return false
 
-        return onDone == other.onDone &&
-            onGo == other.onGo &&
-            onNext == other.onNext &&
-            onPrevious == other.onPrevious &&
-            onSearch == other.onSearch &&
-            onSend == other.onSend
+        return onDone === other.onDone &&
+            onGo === other.onGo &&
+            onNext === other.onNext &&
+            onPrevious === other.onPrevious &&
+            onSearch === other.onSearch &&
+            onSend === other.onSend
     }
 
     override fun hashCode(): Int {
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/SelectableTextAnnotatedStringElement.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/SelectableTextAnnotatedStringElement.kt
index fd739d6..7a1cd33 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/SelectableTextAnnotatedStringElement.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/SelectableTextAnnotatedStringElement.kt
@@ -93,14 +93,14 @@
 
         // these are equally unlikely to change
         if (fontFamilyResolver != other.fontFamilyResolver) return false
-        if (onTextLayout != other.onTextLayout) return false
+        if (onTextLayout !== other.onTextLayout) return false
         if (overflow != other.overflow) return false
         if (softWrap != other.softWrap) return false
         if (maxLines != other.maxLines) return false
         if (minLines != other.minLines) return false
 
         // these never change, but check anyway for correctness
-        if (onPlaceholderLayout != other.onPlaceholderLayout) return false
+        if (onPlaceholderLayout !== other.onPlaceholderLayout) return false
         if (selectionController != other.selectionController) return false
 
         return true
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/TextAnnotatedStringElement.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/TextAnnotatedStringElement.kt
index f8853ad..6525c51 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/TextAnnotatedStringElement.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/TextAnnotatedStringElement.kt
@@ -102,15 +102,15 @@
 
         // these are equally unlikely to change
         if (fontFamilyResolver != other.fontFamilyResolver) return false
-        if (onTextLayout != other.onTextLayout) return false
-        if (onShowTranslation != other.onShowTranslation) return false
+        if (onTextLayout !== other.onTextLayout) return false
+        if (onShowTranslation !== other.onShowTranslation) return false
         if (overflow != other.overflow) return false
         if (softWrap != other.softWrap) return false
         if (maxLines != other.maxLines) return false
         if (minLines != other.minLines) return false
 
         // these never change, but check anyway for correctness
-        if (onPlaceholderLayout != other.onPlaceholderLayout) return false
+        if (onPlaceholderLayout !== other.onPlaceholderLayout) return false
         if (selectionController != other.selectionController) return false
 
         return true
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/TextAnnotatedStringNode.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/TextAnnotatedStringNode.kt
index aa99015..9c3e8a6 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/TextAnnotatedStringNode.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/TextAnnotatedStringNode.kt
@@ -209,12 +209,12 @@
     ): Boolean {
         var changed = false
 
-        if (this.onTextLayout != onTextLayout) {
+        if (this.onTextLayout !== onTextLayout) {
             this.onTextLayout = onTextLayout
             changed = true
         }
 
-        if (this.onPlaceholderLayout != onPlaceholderLayout) {
+        if (this.onPlaceholderLayout !== onPlaceholderLayout) {
             this.onPlaceholderLayout = onPlaceholderLayout
             changed = true
         }
@@ -224,7 +224,7 @@
             changed = true
         }
 
-        if (this.onShowTranslation != onShowTranslation) {
+        if (this.onShowTranslation !== onShowTranslation) {
             this.onShowTranslation = onShowTranslation
             changed = true
         }
diff --git a/compose/lint/internal-lint-checks/src/main/java/androidx/compose/lint/ComposeIssueRegistry.kt b/compose/lint/internal-lint-checks/src/main/java/androidx/compose/lint/ComposeIssueRegistry.kt
index 43f6253..36ecaff 100644
--- a/compose/lint/internal-lint-checks/src/main/java/androidx/compose/lint/ComposeIssueRegistry.kt
+++ b/compose/lint/internal-lint-checks/src/main/java/androidx/compose/lint/ComposeIssueRegistry.kt
@@ -37,6 +37,7 @@
             CommonModuleIncompatibilityDetector.REFERENCE_ISSUE,
             CommonModuleIncompatibilityDetector.EXTENDS_LAMBDA_ISSUE,
             PrimitiveInCollectionDetector.ISSUE,
+            LambdaStructuralEqualityDetector.ISSUE
         )
     }
     override val vendor = Vendor(
diff --git a/compose/lint/internal-lint-checks/src/main/java/androidx/compose/lint/LambdaStructuralEqualityDetector.kt b/compose/lint/internal-lint-checks/src/main/java/androidx/compose/lint/LambdaStructuralEqualityDetector.kt
new file mode 100644
index 0000000..6d7c0c0
--- /dev/null
+++ b/compose/lint/internal-lint-checks/src/main/java/androidx/compose/lint/LambdaStructuralEqualityDetector.kt
@@ -0,0 +1,118 @@
+/*
+ * 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.lint
+
+import com.android.tools.lint.client.api.UElementHandler
+import com.android.tools.lint.detector.api.Category
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Implementation
+import com.android.tools.lint.detector.api.Issue
+import com.android.tools.lint.detector.api.JavaContext
+import com.android.tools.lint.detector.api.LintFix
+import com.android.tools.lint.detector.api.Scope
+import com.android.tools.lint.detector.api.Severity
+import com.android.tools.lint.detector.api.SourceCodeScanner
+import java.util.EnumSet
+import org.jetbrains.kotlin.analysis.api.analyze
+import org.jetbrains.kotlin.psi.KtExpression
+import org.jetbrains.uast.UBinaryExpression
+import org.jetbrains.uast.UCallExpression
+import org.jetbrains.uast.UastBinaryOperator
+
+/**
+ * Lint [Detector] to ensure that lambda instances are compared referentially, instead of
+ * structurally.
+ *
+ * This is needed as function references (::lambda) do not consider their capture scope in their
+ * equals implementation. This means that structural equality can return true, even if the lambdas
+ * are different references with a different capture scope. Instead, lambdas should be compared
+ * referentially (=== or !==) to avoid this issue.
+ */
+class LambdaStructuralEqualityDetector : Detector(), SourceCodeScanner {
+    override fun getApplicableUastTypes() = listOf(
+        UBinaryExpression::class.java,
+        UCallExpression::class.java
+    )
+
+    override fun createUastHandler(context: JavaContext) = object : UElementHandler() {
+        override fun visitBinaryExpression(node: UBinaryExpression) {
+            val op = node.operator
+            if (op == UastBinaryOperator.EQUALS ||
+                op == UastBinaryOperator.NOT_EQUALS) {
+                val left = node.leftOperand.sourcePsi as? KtExpression ?: return
+                val right = node.rightOperand.sourcePsi as? KtExpression ?: return
+                if (left.isFunctionType() && right.isFunctionType()) {
+                    val replacement = if (op == UastBinaryOperator.EQUALS) "===" else "!=="
+                    context.report(
+                        ISSUE,
+                        node.operatorIdentifier,
+                        context.getNameLocation(node.operatorIdentifier ?: node),
+                        BriefDescription,
+                        LintFix.create()
+                            .replace()
+                            .name("Change to $replacement")
+                            .text(op.text)
+                            .with(replacement)
+                            .autoFix()
+                            .build()
+                    )
+                }
+            }
+        }
+
+        override fun visitCallExpression(node: UCallExpression) {
+            if (node.methodName == "equals") {
+                val left = node.receiver?.sourcePsi as? KtExpression ?: return
+                val right = node.valueArguments.firstOrNull()?.sourcePsi as? KtExpression ?: return
+                if (left.isFunctionType() && right.isFunctionType()) {
+                    context.report(
+                        ISSUE,
+                        node,
+                        context.getNameLocation(node),
+                        BriefDescription
+                    )
+                }
+            }
+        }
+    }
+
+    private fun KtExpression.isFunctionType(): Boolean = analyze(this) {
+        getKtType()?.isFunctionType == true
+    }
+
+    companion object {
+        private const val BriefDescription = "Checking lambdas for structural equality, instead " +
+            "of checking for referential equality"
+        private const val Explanation =
+            "Checking structural equality on lambdas can lead to issues, as function references " +
+                "(::lambda) do not consider their capture scope in their equals implementation. " +
+                "This means that structural equality can return true, even if the lambdas are " +
+                "different references with a different capture scope. Instead, lambdas should be" +
+                "compared referentially (=== or !==) to avoid this issue."
+
+        val ISSUE = Issue.create(
+            "LambdaStructuralEquality",
+            BriefDescription,
+            Explanation,
+            Category.CORRECTNESS, 5, Severity.ERROR,
+            Implementation(
+                LambdaStructuralEqualityDetector::class.java,
+                EnumSet.of(Scope.JAVA_FILE, Scope.TEST_SOURCES)
+            )
+        )
+    }
+}
diff --git a/compose/lint/internal-lint-checks/src/test/java/androidx/compose/lint/LambdaStructuralEqualityDetectorTest.kt b/compose/lint/internal-lint-checks/src/test/java/androidx/compose/lint/LambdaStructuralEqualityDetectorTest.kt
new file mode 100644
index 0000000..0206fd9
--- /dev/null
+++ b/compose/lint/internal-lint-checks/src/test/java/androidx/compose/lint/LambdaStructuralEqualityDetectorTest.kt
@@ -0,0 +1,110 @@
+/*
+ * 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.
+ */
+
+@file:Suppress("UnstableApiUsage")
+
+package androidx.compose.lint
+
+import com.android.tools.lint.checks.infrastructure.LintDetectorTest
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Issue
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+/* ktlint-disable max-line-length */
+@RunWith(JUnit4::class)
+class LambdaStructuralEqualityDetectorTest : LintDetectorTest() {
+    override fun getDetector(): Detector = LambdaStructuralEqualityDetector()
+
+    override fun getIssues(): MutableList<Issue> = mutableListOf(
+        LambdaStructuralEqualityDetector.ISSUE
+    )
+
+    @Test
+    fun noErrors() {
+        lint().files(
+            kotlin(
+                """
+                package test
+
+                val lambda1 = { 1 }
+                val lambda2 = { 2 }
+
+                fun test() {
+                    lambda1 === lambda2
+                    lambda1 !== lambda2
+                }
+            """
+            )
+        )
+            .run()
+            .expectClean()
+    }
+
+    @Test
+    fun errors() {
+        lint().files(
+            kotlin(
+                """
+                package test
+
+                val lambda1 = { 1 }
+                val lambda2 = { 2 }
+                val lambda3: (() -> Unit)? = null
+
+                fun test() {
+                    lambda1 == lambda2
+                    lambda1 != lambda2
+                    lambda1.equals(lambda2)
+                    lambda3?.equals(lambda2)
+                }
+            """
+            )
+        )
+            .run()
+            .expect(
+                """
+src/test/test.kt:9: Error: Checking lambdas for structural equality, instead of checking for referential equality [LambdaStructuralEquality]
+                    lambda1 == lambda2
+                            ~~
+src/test/test.kt:10: Error: Checking lambdas for structural equality, instead of checking for referential equality [LambdaStructuralEquality]
+                    lambda1 != lambda2
+                            ~~
+src/test/test.kt:11: Error: Checking lambdas for structural equality, instead of checking for referential equality [LambdaStructuralEquality]
+                    lambda1.equals(lambda2)
+                            ~~~~~~
+src/test/test.kt:12: Error: Checking lambdas for structural equality, instead of checking for referential equality [LambdaStructuralEquality]
+                    lambda3?.equals(lambda2)
+                             ~~~~~~
+4 errors, 0 warnings
+            """
+            )
+            .expectFixDiffs(
+                """
+Autofix for src/test/test.kt line 9: Change to ===:
+@@ -9 +9
+-                     lambda1 == lambda2
++                     lambda1 === lambda2
+Autofix for src/test/test.kt line 10: Change to !==:
+@@ -10 +10
+-                     lambda1 != lambda2
++                     lambda1 !== lambda2
+                """
+            )
+    }
+}
+/* ktlint-enable max-line-length */
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/AnchoredDraggable.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/AnchoredDraggable.kt
index d90d9b3..307d512 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/AnchoredDraggable.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/AnchoredDraggable.kt
@@ -838,7 +838,7 @@
         if (other !is DraggableAnchorsElement<*>) return false
 
         if (state != other.state) return false
-        if (anchors != other.anchors) return false
+        if (anchors !== other.anchors) return false
         if (orientation != other.orientation) return false
 
         return true
diff --git a/compose/material3/adaptive/adaptive-navigation/api/current.txt b/compose/material3/adaptive/adaptive-navigation/api/current.txt
index 4a99882..3388cc4 100644
--- a/compose/material3/adaptive/adaptive-navigation/api/current.txt
+++ b/compose/material3/adaptive/adaptive-navigation/api/current.txt
@@ -2,24 +2,32 @@
 package androidx.compose.material3.adaptive.navigation {
 
   public final class AndroidThreePaneScaffold_androidKt {
-    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static void NavigableListDetailPaneScaffold(androidx.compose.material3.adaptive.navigation.ThreePaneScaffoldNavigator<java.lang.Object> navigator, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit> listPane, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit> detailPane, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit>? extraPane, optional androidx.compose.material3.adaptive.navigation.BackNavigationBehavior defaultBackBehavior);
-    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static void NavigableSupportingPaneScaffold(androidx.compose.material3.adaptive.navigation.ThreePaneScaffoldNavigator<java.lang.Object> navigator, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit> mainPane, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit> supportingPane, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit>? extraPane, optional androidx.compose.material3.adaptive.navigation.BackNavigationBehavior defaultBackBehavior);
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static void NavigableListDetailPaneScaffold(androidx.compose.material3.adaptive.navigation.ThreePaneScaffoldNavigator<java.lang.Object> navigator, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit> listPane, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit> detailPane, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit>? extraPane, optional String defaultBackBehavior);
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static void NavigableSupportingPaneScaffold(androidx.compose.material3.adaptive.navigation.ThreePaneScaffoldNavigator<java.lang.Object> navigator, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit> mainPane, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit> supportingPane, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit>? extraPane, optional String defaultBackBehavior);
   }
 
-  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public enum BackNavigationBehavior {
-    enum_constant public static final androidx.compose.material3.adaptive.navigation.BackNavigationBehavior PopLatest;
-    enum_constant public static final androidx.compose.material3.adaptive.navigation.BackNavigationBehavior PopUntilContentChange;
-    enum_constant public static final androidx.compose.material3.adaptive.navigation.BackNavigationBehavior PopUntilCurrentDestinationChange;
-    enum_constant public static final androidx.compose.material3.adaptive.navigation.BackNavigationBehavior PopUntilScaffoldValueChange;
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @kotlin.jvm.JvmInline public final value class BackNavigationBehavior {
+    field public static final androidx.compose.material3.adaptive.navigation.BackNavigationBehavior.Companion Companion;
+  }
+
+  public static final class BackNavigationBehavior.Companion {
+    method public String getPopLatest();
+    method public String getPopUntilContentChange();
+    method public String getPopUntilCurrentDestinationChange();
+    method public String getPopUntilScaffoldValueChange();
+    property public final String PopLatest;
+    property public final String PopUntilContentChange;
+    property public final String PopUntilCurrentDestinationChange;
+    property public final String PopUntilScaffoldValueChange;
   }
 
   @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Stable public interface ThreePaneScaffoldNavigator<T> {
-    method public boolean canNavigateBack(optional androidx.compose.material3.adaptive.navigation.BackNavigationBehavior backNavigationBehavior);
+    method public boolean canNavigateBack(optional String backNavigationBehavior);
     method public androidx.compose.material3.adaptive.layout.ThreePaneScaffoldDestinationItem<T>? getCurrentDestination();
     method public androidx.compose.material3.adaptive.layout.PaneScaffoldDirective getScaffoldDirective();
     method public androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue getScaffoldValue();
     method public boolean isDestinationHistoryAware();
-    method public boolean navigateBack(optional androidx.compose.material3.adaptive.navigation.BackNavigationBehavior backNavigationBehavior);
+    method public boolean navigateBack(optional String backNavigationBehavior);
     method public void navigateTo(androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole pane, optional T? content);
     method public void setDestinationHistoryAware(boolean);
     property public abstract androidx.compose.material3.adaptive.layout.ThreePaneScaffoldDestinationItem<T>? currentDestination;
diff --git a/compose/material3/adaptive/adaptive-navigation/api/restricted_current.txt b/compose/material3/adaptive/adaptive-navigation/api/restricted_current.txt
index 4a99882..3388cc4 100644
--- a/compose/material3/adaptive/adaptive-navigation/api/restricted_current.txt
+++ b/compose/material3/adaptive/adaptive-navigation/api/restricted_current.txt
@@ -2,24 +2,32 @@
 package androidx.compose.material3.adaptive.navigation {
 
   public final class AndroidThreePaneScaffold_androidKt {
-    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static void NavigableListDetailPaneScaffold(androidx.compose.material3.adaptive.navigation.ThreePaneScaffoldNavigator<java.lang.Object> navigator, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit> listPane, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit> detailPane, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit>? extraPane, optional androidx.compose.material3.adaptive.navigation.BackNavigationBehavior defaultBackBehavior);
-    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static void NavigableSupportingPaneScaffold(androidx.compose.material3.adaptive.navigation.ThreePaneScaffoldNavigator<java.lang.Object> navigator, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit> mainPane, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit> supportingPane, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit>? extraPane, optional androidx.compose.material3.adaptive.navigation.BackNavigationBehavior defaultBackBehavior);
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static void NavigableListDetailPaneScaffold(androidx.compose.material3.adaptive.navigation.ThreePaneScaffoldNavigator<java.lang.Object> navigator, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit> listPane, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit> detailPane, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit>? extraPane, optional String defaultBackBehavior);
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static void NavigableSupportingPaneScaffold(androidx.compose.material3.adaptive.navigation.ThreePaneScaffoldNavigator<java.lang.Object> navigator, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit> mainPane, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit> supportingPane, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,kotlin.Unit>? extraPane, optional String defaultBackBehavior);
   }
 
-  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public enum BackNavigationBehavior {
-    enum_constant public static final androidx.compose.material3.adaptive.navigation.BackNavigationBehavior PopLatest;
-    enum_constant public static final androidx.compose.material3.adaptive.navigation.BackNavigationBehavior PopUntilContentChange;
-    enum_constant public static final androidx.compose.material3.adaptive.navigation.BackNavigationBehavior PopUntilCurrentDestinationChange;
-    enum_constant public static final androidx.compose.material3.adaptive.navigation.BackNavigationBehavior PopUntilScaffoldValueChange;
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @kotlin.jvm.JvmInline public final value class BackNavigationBehavior {
+    field public static final androidx.compose.material3.adaptive.navigation.BackNavigationBehavior.Companion Companion;
+  }
+
+  public static final class BackNavigationBehavior.Companion {
+    method public String getPopLatest();
+    method public String getPopUntilContentChange();
+    method public String getPopUntilCurrentDestinationChange();
+    method public String getPopUntilScaffoldValueChange();
+    property public final String PopLatest;
+    property public final String PopUntilContentChange;
+    property public final String PopUntilCurrentDestinationChange;
+    property public final String PopUntilScaffoldValueChange;
   }
 
   @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Stable public interface ThreePaneScaffoldNavigator<T> {
-    method public boolean canNavigateBack(optional androidx.compose.material3.adaptive.navigation.BackNavigationBehavior backNavigationBehavior);
+    method public boolean canNavigateBack(optional String backNavigationBehavior);
     method public androidx.compose.material3.adaptive.layout.ThreePaneScaffoldDestinationItem<T>? getCurrentDestination();
     method public androidx.compose.material3.adaptive.layout.PaneScaffoldDirective getScaffoldDirective();
     method public androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue getScaffoldValue();
     method public boolean isDestinationHistoryAware();
-    method public boolean navigateBack(optional androidx.compose.material3.adaptive.navigation.BackNavigationBehavior backNavigationBehavior);
+    method public boolean navigateBack(optional String backNavigationBehavior);
     method public void navigateTo(androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole pane, optional T? content);
     method public void setDestinationHistoryAware(boolean);
     property public abstract androidx.compose.material3.adaptive.layout.ThreePaneScaffoldDestinationItem<T>? currentDestination;
diff --git a/compose/material3/adaptive/adaptive-navigation/src/commonMain/kotlin/androidx/compose/material3/adaptive/navigation/BackNavigationBehavior.kt b/compose/material3/adaptive/adaptive-navigation/src/commonMain/kotlin/androidx/compose/material3/adaptive/navigation/BackNavigationBehavior.kt
index 3ae80e2..6d0a096 100644
--- a/compose/material3/adaptive/adaptive-navigation/src/commonMain/kotlin/androidx/compose/material3/adaptive/navigation/BackNavigationBehavior.kt
+++ b/compose/material3/adaptive/adaptive-navigation/src/commonMain/kotlin/androidx/compose/material3/adaptive/navigation/BackNavigationBehavior.kt
@@ -25,34 +25,42 @@
  * A class to control how back navigation should behave in a [ThreePaneScaffoldNavigator].
  */
 @ExperimentalMaterial3AdaptiveApi
-enum class BackNavigationBehavior {
-    /** Pop the latest destination from the backstack. */
-    PopLatest,
+@JvmInline
+value class BackNavigationBehavior private constructor(private val description: String) {
+    override fun toString(): String = this.description
 
-    /**
-     * Pop destinations from the backstack until there is a change in the scaffold value.
-     *
-     * For example, in a single-pane layout, this will skip entries until the current destination
-     * is a different [ThreePaneScaffoldRole]. In a multi-pane layout, this will skip entries until
-     * the [PaneAdaptedValue] of any pane changes.
-     */
-    PopUntilScaffoldValueChange,
+    companion object {
+        /** Pop the latest destination from the backstack. */
+        val PopLatest = BackNavigationBehavior("PopLatest")
 
-    /**
-     * Pop destinations from the backstack until there is a change in the current destination pane.
-     *
-     * In a single-pane layout, this should behave similarly to [PopUntilScaffoldValueChange]. In a
-     * multi-pane layout, it is possible for both the current destination and previous destination
-     * to be showing at the same time, so this may not result in a visual change in the scaffold.
-     */
-    PopUntilCurrentDestinationChange,
+        /**
+         * Pop destinations from the backstack until there is a change in the scaffold value.
+         *
+         * For example, in a single-pane layout, this will skip entries until the current
+         * destination is a different [ThreePaneScaffoldRole]. In a multi-pane layout, this will
+         * skip entries until the [PaneAdaptedValue] of any pane changes.
+         */
+        val PopUntilScaffoldValueChange = BackNavigationBehavior("PopUntilScaffoldValueChange")
 
-    /**
-     * Pop destinations from the backstack until there is a content change.
-     *
-     * A "content change" is defined as either a change in the content of the current
-     * [ThreePaneScaffoldDestinationItem], or a change in the scaffold value (similar to
-     * [PopUntilScaffoldValueChange]).
-     */
-    PopUntilContentChange,
+        /**
+         * Pop destinations from the backstack until there is a change in the current destination
+         * pane.
+         *
+         * In a single-pane layout, this should behave similarly to [PopUntilScaffoldValueChange].
+         * In a multi-pane layout, it is possible for both the current destination and previous
+         * destination to be showing at the same time, so this may not result in a visual change
+         * in the scaffold.
+         */
+        val PopUntilCurrentDestinationChange =
+            BackNavigationBehavior("PopUntilCurrentDestinationChange")
+
+        /**
+         * Pop destinations from the backstack until there is a content change.
+         *
+         * A "content change" is defined as either a change in the content of the current
+         * [ThreePaneScaffoldDestinationItem], or a change in the scaffold value (similar to
+         * [PopUntilScaffoldValueChange]).
+         */
+        val PopUntilContentChange = BackNavigationBehavior("PopUntilContentChange")
+    }
 }
diff --git a/compose/material3/adaptive/adaptive/src/commonMain/kotlin/androidx/compose/material3/adaptive/Posture.kt b/compose/material3/adaptive/adaptive/src/commonMain/kotlin/androidx/compose/material3/adaptive/Posture.kt
index 6455c51..efbd340 100644
--- a/compose/material3/adaptive/adaptive/src/commonMain/kotlin/androidx/compose/material3/adaptive/Posture.kt
+++ b/compose/material3/adaptive/adaptive/src/commonMain/kotlin/androidx/compose/material3/adaptive/Posture.kt
@@ -47,6 +47,7 @@
         if (this === other) return true
         if (other !is Posture) return false
         if (isTabletop != other.isTabletop) return false
+        if (hingeList != other.hingeList) return false
         return true
     }
 
diff --git a/compose/material3/material3-common/build.gradle b/compose/material3/material3-common/build.gradle
index 32cbf10..f41127b 100644
--- a/compose/material3/material3-common/build.gradle
+++ b/compose/material3/material3-common/build.gradle
@@ -112,7 +112,6 @@
     name = "Compose Material 3 Common"
     mavenVersion = LibraryVersions.COMPOSE_MATERIAL3_COMMON
     type = LibraryType.PUBLISHED_KOTLIN_ONLY_LIBRARY
-    publish = Publish.SNAPSHOT_AND_RELEASE
     inceptionYear = "2023"
     description = "Compose Material 3 Common Library. This library contains foundational, themeless " +
             "components that can be shared between different Material libraries or used by app" +
diff --git a/compose/material3/material3-window-size-class/build.gradle b/compose/material3/material3-window-size-class/build.gradle
index f3d4c53..28239af 100644
--- a/compose/material3/material3-window-size-class/build.gradle
+++ b/compose/material3/material3-window-size-class/build.gradle
@@ -122,6 +122,7 @@
     type = LibraryType.PUBLISHED_KOTLIN_ONLY_LIBRARY
     inceptionYear = "2022"
     description = "Provides window size classes for building responsive UIs"
+    samples(project(":compose:material3:material3-window-size-class:material3-window-size-class-samples"))
 }
 
 android {
diff --git a/compose/material3/material3/api/current.txt b/compose/material3/material3/api/current.txt
index 21ff711..6d5fb74 100644
--- a/compose/material3/material3/api/current.txt
+++ b/compose/material3/material3/api/current.txt
@@ -1151,7 +1151,7 @@
   }
 
   public final class ProgressIndicatorDefaults {
-    method public void drawStopIndicator(androidx.compose.ui.graphics.drawscope.DrawScope, float stopSize, long color, int strokeCap);
+    method public void drawStopIndicator(androidx.compose.ui.graphics.drawscope.DrawScope drawScope, float stopSize, long color, int strokeCap);
     method @androidx.compose.runtime.Composable public long getCircularColor();
     method public int getCircularDeterminateStrokeCap();
     method @androidx.compose.runtime.Composable public long getCircularDeterminateTrackColor();
@@ -1196,7 +1196,7 @@
     method @Deprecated @androidx.compose.runtime.Composable public static void LinearProgressIndicator(float progress, optional androidx.compose.ui.Modifier modifier, optional long color, optional long trackColor);
     method @Deprecated @androidx.compose.runtime.Composable public static void LinearProgressIndicator(float progress, optional androidx.compose.ui.Modifier modifier, optional long color, optional long trackColor, optional int strokeCap);
     method @Deprecated @androidx.compose.runtime.Composable public static void LinearProgressIndicator(kotlin.jvm.functions.Function0<java.lang.Float> progress, optional androidx.compose.ui.Modifier modifier, optional long color, optional long trackColor, optional int strokeCap);
-    method @androidx.compose.runtime.Composable public static void LinearProgressIndicator(kotlin.jvm.functions.Function0<java.lang.Float> progress, optional androidx.compose.ui.Modifier modifier, optional long color, optional long trackColor, optional int strokeCap, optional float gapSize, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit>? drawStopIndicator);
+    method @androidx.compose.runtime.Composable public static void LinearProgressIndicator(kotlin.jvm.functions.Function0<java.lang.Float> progress, optional androidx.compose.ui.Modifier modifier, optional long color, optional long trackColor, optional int strokeCap, optional float gapSize, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> drawStopIndicator);
   }
 
   @androidx.compose.runtime.Immutable public final class RadioButtonColors {
@@ -1498,10 +1498,10 @@
   @androidx.compose.runtime.Stable public final class SliderDefaults {
     method @androidx.compose.runtime.Composable public void Thumb(androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.SliderColors colors, optional boolean enabled, optional long thumbSize);
     method @Deprecated @androidx.compose.runtime.Composable public void Track(androidx.compose.material3.RangeSliderState rangeSliderState, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.SliderColors colors, optional boolean enabled);
-    method @androidx.compose.runtime.Composable public void Track(androidx.compose.material3.RangeSliderState rangeSliderState, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.SliderColors colors, optional kotlin.jvm.functions.Function2<? super androidx.compose.ui.graphics.drawscope.DrawScope,? super androidx.compose.ui.geometry.Offset,kotlin.Unit>? drawStopIndicator, optional kotlin.jvm.functions.Function3<? super androidx.compose.ui.graphics.drawscope.DrawScope,? super androidx.compose.ui.geometry.Offset,? super androidx.compose.ui.graphics.Color,kotlin.Unit>? drawTick, optional float thumbTrackGapSize, optional float trackInsideCornerSize);
+    method @androidx.compose.runtime.Composable public void Track(androidx.compose.material3.RangeSliderState rangeSliderState, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.SliderColors colors, optional kotlin.jvm.functions.Function2<? super androidx.compose.ui.graphics.drawscope.DrawScope,? super androidx.compose.ui.geometry.Offset,kotlin.Unit>? drawStopIndicator, optional kotlin.jvm.functions.Function3<? super androidx.compose.ui.graphics.drawscope.DrawScope,? super androidx.compose.ui.geometry.Offset,? super androidx.compose.ui.graphics.Color,kotlin.Unit> drawTick, optional float thumbTrackGapSize, optional float trackInsideCornerSize);
     method @Deprecated @androidx.compose.runtime.Composable public void Track(androidx.compose.material3.SliderPositions sliderPositions, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.SliderColors colors, optional boolean enabled);
     method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void Track(androidx.compose.material3.SliderState sliderState, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.SliderColors colors, optional boolean enabled);
-    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void Track(androidx.compose.material3.SliderState sliderState, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.SliderColors colors, optional kotlin.jvm.functions.Function2<? super androidx.compose.ui.graphics.drawscope.DrawScope,? super androidx.compose.ui.geometry.Offset,kotlin.Unit>? drawStopIndicator, optional kotlin.jvm.functions.Function3<? super androidx.compose.ui.graphics.drawscope.DrawScope,? super androidx.compose.ui.geometry.Offset,? super androidx.compose.ui.graphics.Color,kotlin.Unit>? drawTick, optional float thumbTrackGapSize, optional float trackInsideCornerSize);
+    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void Track(androidx.compose.material3.SliderState sliderState, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.SliderColors colors, optional kotlin.jvm.functions.Function2<? super androidx.compose.ui.graphics.drawscope.DrawScope,? super androidx.compose.ui.geometry.Offset,kotlin.Unit>? drawStopIndicator, optional kotlin.jvm.functions.Function3<? super androidx.compose.ui.graphics.drawscope.DrawScope,? super androidx.compose.ui.geometry.Offset,? super androidx.compose.ui.graphics.Color,kotlin.Unit> drawTick, optional float thumbTrackGapSize, optional float trackInsideCornerSize);
     method @androidx.compose.runtime.Composable public androidx.compose.material3.SliderColors colors();
     method @androidx.compose.runtime.Composable public androidx.compose.material3.SliderColors colors(optional long thumbColor, optional long activeTrackColor, optional long activeTickColor, optional long inactiveTrackColor, optional long inactiveTickColor, optional long disabledThumbColor, optional long disabledActiveTrackColor, optional long disabledActiveTickColor, optional long disabledInactiveTrackColor, optional long disabledInactiveTickColor);
     method public float getTickSize();
diff --git a/compose/material3/material3/api/restricted_current.txt b/compose/material3/material3/api/restricted_current.txt
index 21ff711..6d5fb74 100644
--- a/compose/material3/material3/api/restricted_current.txt
+++ b/compose/material3/material3/api/restricted_current.txt
@@ -1151,7 +1151,7 @@
   }
 
   public final class ProgressIndicatorDefaults {
-    method public void drawStopIndicator(androidx.compose.ui.graphics.drawscope.DrawScope, float stopSize, long color, int strokeCap);
+    method public void drawStopIndicator(androidx.compose.ui.graphics.drawscope.DrawScope drawScope, float stopSize, long color, int strokeCap);
     method @androidx.compose.runtime.Composable public long getCircularColor();
     method public int getCircularDeterminateStrokeCap();
     method @androidx.compose.runtime.Composable public long getCircularDeterminateTrackColor();
@@ -1196,7 +1196,7 @@
     method @Deprecated @androidx.compose.runtime.Composable public static void LinearProgressIndicator(float progress, optional androidx.compose.ui.Modifier modifier, optional long color, optional long trackColor);
     method @Deprecated @androidx.compose.runtime.Composable public static void LinearProgressIndicator(float progress, optional androidx.compose.ui.Modifier modifier, optional long color, optional long trackColor, optional int strokeCap);
     method @Deprecated @androidx.compose.runtime.Composable public static void LinearProgressIndicator(kotlin.jvm.functions.Function0<java.lang.Float> progress, optional androidx.compose.ui.Modifier modifier, optional long color, optional long trackColor, optional int strokeCap);
-    method @androidx.compose.runtime.Composable public static void LinearProgressIndicator(kotlin.jvm.functions.Function0<java.lang.Float> progress, optional androidx.compose.ui.Modifier modifier, optional long color, optional long trackColor, optional int strokeCap, optional float gapSize, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit>? drawStopIndicator);
+    method @androidx.compose.runtime.Composable public static void LinearProgressIndicator(kotlin.jvm.functions.Function0<java.lang.Float> progress, optional androidx.compose.ui.Modifier modifier, optional long color, optional long trackColor, optional int strokeCap, optional float gapSize, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> drawStopIndicator);
   }
 
   @androidx.compose.runtime.Immutable public final class RadioButtonColors {
@@ -1498,10 +1498,10 @@
   @androidx.compose.runtime.Stable public final class SliderDefaults {
     method @androidx.compose.runtime.Composable public void Thumb(androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.SliderColors colors, optional boolean enabled, optional long thumbSize);
     method @Deprecated @androidx.compose.runtime.Composable public void Track(androidx.compose.material3.RangeSliderState rangeSliderState, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.SliderColors colors, optional boolean enabled);
-    method @androidx.compose.runtime.Composable public void Track(androidx.compose.material3.RangeSliderState rangeSliderState, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.SliderColors colors, optional kotlin.jvm.functions.Function2<? super androidx.compose.ui.graphics.drawscope.DrawScope,? super androidx.compose.ui.geometry.Offset,kotlin.Unit>? drawStopIndicator, optional kotlin.jvm.functions.Function3<? super androidx.compose.ui.graphics.drawscope.DrawScope,? super androidx.compose.ui.geometry.Offset,? super androidx.compose.ui.graphics.Color,kotlin.Unit>? drawTick, optional float thumbTrackGapSize, optional float trackInsideCornerSize);
+    method @androidx.compose.runtime.Composable public void Track(androidx.compose.material3.RangeSliderState rangeSliderState, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.SliderColors colors, optional kotlin.jvm.functions.Function2<? super androidx.compose.ui.graphics.drawscope.DrawScope,? super androidx.compose.ui.geometry.Offset,kotlin.Unit>? drawStopIndicator, optional kotlin.jvm.functions.Function3<? super androidx.compose.ui.graphics.drawscope.DrawScope,? super androidx.compose.ui.geometry.Offset,? super androidx.compose.ui.graphics.Color,kotlin.Unit> drawTick, optional float thumbTrackGapSize, optional float trackInsideCornerSize);
     method @Deprecated @androidx.compose.runtime.Composable public void Track(androidx.compose.material3.SliderPositions sliderPositions, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.SliderColors colors, optional boolean enabled);
     method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void Track(androidx.compose.material3.SliderState sliderState, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.SliderColors colors, optional boolean enabled);
-    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void Track(androidx.compose.material3.SliderState sliderState, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.SliderColors colors, optional kotlin.jvm.functions.Function2<? super androidx.compose.ui.graphics.drawscope.DrawScope,? super androidx.compose.ui.geometry.Offset,kotlin.Unit>? drawStopIndicator, optional kotlin.jvm.functions.Function3<? super androidx.compose.ui.graphics.drawscope.DrawScope,? super androidx.compose.ui.geometry.Offset,? super androidx.compose.ui.graphics.Color,kotlin.Unit>? drawTick, optional float thumbTrackGapSize, optional float trackInsideCornerSize);
+    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void Track(androidx.compose.material3.SliderState sliderState, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.SliderColors colors, optional kotlin.jvm.functions.Function2<? super androidx.compose.ui.graphics.drawscope.DrawScope,? super androidx.compose.ui.geometry.Offset,kotlin.Unit>? drawStopIndicator, optional kotlin.jvm.functions.Function3<? super androidx.compose.ui.graphics.drawscope.DrawScope,? super androidx.compose.ui.geometry.Offset,? super androidx.compose.ui.graphics.Color,kotlin.Unit> drawTick, optional float thumbTrackGapSize, optional float trackInsideCornerSize);
     method @androidx.compose.runtime.Composable public androidx.compose.material3.SliderColors colors();
     method @androidx.compose.runtime.Composable public androidx.compose.material3.SliderColors colors(optional long thumbColor, optional long activeTrackColor, optional long activeTickColor, optional long inactiveTrackColor, optional long inactiveTickColor, optional long disabledThumbColor, optional long disabledActiveTrackColor, optional long disabledActiveTickColor, optional long disabledInactiveTrackColor, optional long disabledInactiveTickColor);
     method public float getTickSize();
diff --git a/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/ProgressIndicatorSamples.kt b/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/ProgressIndicatorSamples.kt
index 792b4a6..8e2c00b 100644
--- a/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/ProgressIndicatorSamples.kt
+++ b/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/ProgressIndicatorSamples.kt
@@ -80,7 +80,7 @@
             trackColor = MaterialTheme.colorScheme.surfaceVariant,
             strokeCap = StrokeCap.Butt,
             gapSize = 0.dp,
-            drawStopIndicator = null
+            drawStopIndicator = {}
         )
         Spacer(Modifier.requiredHeight(30.dp))
         Text("Set progress:")
diff --git a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/ProgressIndicatorScreenshotTest.kt b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/ProgressIndicatorScreenshotTest.kt
index 84c6532..6a6af69 100644
--- a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/ProgressIndicatorScreenshotTest.kt
+++ b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/ProgressIndicatorScreenshotTest.kt
@@ -80,7 +80,7 @@
             Box(wrap.testTag(wrapperTestTag)) {
                 LinearProgressIndicator(
                     progress = { 0.5f },
-                    drawStopIndicator = null
+                    drawStopIndicator = {}
                 )
             }
         }
diff --git a/compose/material3/material3/src/androidMain/res/values-be/strings.xml b/compose/material3/material3/src/androidMain/res/values-be/strings.xml
index ae2754d..e434ece 100644
--- a/compose/material3/material3/src/androidMain/res/values-be/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-be/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"Дыялогавае акно"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Разгорнута"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Згорнута"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Уключыць (выключыць) выпадное меню"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Закрыць"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"Пошук"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"Прапановы ўнізе"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-bg/strings.xml b/compose/material3/material3/src/androidMain/res/values-bg/strings.xml
index 4558f92..124dad0 100644
--- a/compose/material3/material3/src/androidMain/res/values-bg/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-bg/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"Диалогов прозорец"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Разгънато"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Свито"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Превключване на падащото меню"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Отхвърляне"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"Лента за търсене"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"Предложенията са по-долу"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-bn/strings.xml b/compose/material3/material3/src/androidMain/res/values-bn/strings.xml
index 9b9a91a..b74dd78 100644
--- a/compose/material3/material3/src/androidMain/res/values-bn/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-bn/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"ডায়ালগ"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"বড় করা হয়েছে"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"আড়াল করা হয়েছে"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"ড্রপডাউন মেনু টগল করুন"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"বাতিল করুন"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"সার্চ করুন"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"নিচে দেওয়া সাজেশন"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-bs/strings.xml b/compose/material3/material3/src/androidMain/res/values-bs/strings.xml
index e6cc97c..5d5d633 100644
--- a/compose/material3/material3/src/androidMain/res/values-bs/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-bs/strings.xml
@@ -20,7 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"Dijaloški okvir"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Prošireno"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Suženo"</string>
-    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Prekidač za padajući izbornik"</string>
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Uključivanje/isključivanje padajućeg menija"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Odbacivanje"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"Pretraživanje"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"Prijedlozi su u nastavku"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-ca/strings.xml b/compose/material3/material3/src/androidMain/res/values-ca/strings.xml
index 3c04f34..ef12ec8 100644
--- a/compose/material3/material3/src/androidMain/res/values-ca/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-ca/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"Quadre de diàleg"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"S\'ha desplegat"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"S\'ha replegat"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Commuta el menú desplegable"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Ignora"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"Cerca"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"Suggeriments a continuació"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-cs/strings.xml b/compose/material3/material3/src/androidMain/res/values-cs/strings.xml
index 5a82875..3e7d316 100644
--- a/compose/material3/material3/src/androidMain/res/values-cs/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-cs/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"Dialogové okno"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Rozbaleno"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Sbaleno"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Přepnout rozbalovací nabídku"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Zavřít"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"Vyhledávání"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"Níže jsou k dispozici návrhy"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-da/strings.xml b/compose/material3/material3/src/androidMain/res/values-da/strings.xml
index a45b72a..d4032f7 100644
--- a/compose/material3/material3/src/androidMain/res/values-da/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-da/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"Dialogboks"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Udvidet"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Skjult"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Skift visningen af rullemenuen"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Afvis"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"Søg"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"Forslag nedenfor"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-de/strings.xml b/compose/material3/material3/src/androidMain/res/values-de/strings.xml
index 57b1135..f5a97c9 100644
--- a/compose/material3/material3/src/androidMain/res/values-de/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-de/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"Dialogfeld"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Maximiert"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Minimiert"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Drop-down-Menü maximieren/minimieren"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Schließen"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"Suche"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"Vorschläge unten"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-el/strings.xml b/compose/material3/material3/src/androidMain/res/values-el/strings.xml
index be85d0b..aa67f3f 100644
--- a/compose/material3/material3/src/androidMain/res/values-el/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-el/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"Παράθυρο διαλόγου"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Αναπτυγμένο"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Συμπτυγμένο"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Εναλλαγή αναπτυσσόμενου μενού"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Παράβλεψη"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"Αναζήτηση"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"Προτάσεις παρακάτω"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-en-rAU/strings.xml b/compose/material3/material3/src/androidMain/res/values-en-rAU/strings.xml
index 2a911184..f95be07 100644
--- a/compose/material3/material3/src/androidMain/res/values-en-rAU/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-en-rAU/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"Dialogue"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Expanded"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Collapsed"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Toggle drop-down menu"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Dismiss"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"Search"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"Suggestions below"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-en-rGB/strings.xml b/compose/material3/material3/src/androidMain/res/values-en-rGB/strings.xml
index 2a911184..f95be07 100644
--- a/compose/material3/material3/src/androidMain/res/values-en-rGB/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-en-rGB/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"Dialogue"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Expanded"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Collapsed"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Toggle drop-down menu"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Dismiss"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"Search"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"Suggestions below"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-en-rIN/strings.xml b/compose/material3/material3/src/androidMain/res/values-en-rIN/strings.xml
index 2a911184..f95be07 100644
--- a/compose/material3/material3/src/androidMain/res/values-en-rIN/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-en-rIN/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"Dialogue"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Expanded"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Collapsed"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Toggle drop-down menu"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Dismiss"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"Search"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"Suggestions below"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-es-rUS/strings.xml b/compose/material3/material3/src/androidMain/res/values-es-rUS/strings.xml
index 64be6ea..5f613de 100644
--- a/compose/material3/material3/src/androidMain/res/values-es-rUS/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-es-rUS/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"Diálogo"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Expandido"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Contraído"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Activar o desactivar menú desplegable"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Descartar"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"Buscar"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"Sugerencias a continuación"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-es/strings.xml b/compose/material3/material3/src/androidMain/res/values-es/strings.xml
index a770326..063f711 100644
--- a/compose/material3/material3/src/androidMain/res/values-es/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-es/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"Cuadro de diálogo"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Desplegado"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Contraído"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Mostrar/ocultar menú desplegable"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Cerrar"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"Buscar"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"Sugerencias a continuación"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-et/strings.xml b/compose/material3/material3/src/androidMain/res/values-et/strings.xml
index dface1c..512cc41 100644
--- a/compose/material3/material3/src/androidMain/res/values-et/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-et/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"Dialoog"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Laiendatud"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Ahendatud"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Rippmenüü lülitamine"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Loobu"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"Otsing"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"Soovitused on allpool"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-eu/strings.xml b/compose/material3/material3/src/androidMain/res/values-eu/strings.xml
index 2487d99..5353c99 100644
--- a/compose/material3/material3/src/androidMain/res/values-eu/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-eu/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"Leihoa"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Zabalduta"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Tolestuta"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Zabaldu/Tolestu goitibeherako menua"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Baztertu"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"Bilatu"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"Iradokizunak daude behean"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-fi/strings.xml b/compose/material3/material3/src/androidMain/res/values-fi/strings.xml
index e3fb5e9..ca77732 100644
--- a/compose/material3/material3/src/androidMain/res/values-fi/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-fi/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"Valintaikkuna"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Laajennettu"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Tiivistetty"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Laita avattava valikko päälle"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Ohita"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"Hae"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"Ehdotuksia alla"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-fr-rCA/strings.xml b/compose/material3/material3/src/androidMain/res/values-fr-rCA/strings.xml
index 57254bf..5548120 100644
--- a/compose/material3/material3/src/androidMain/res/values-fr-rCA/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-fr-rCA/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"Dialogue"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Développé"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Réduit"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Ouvrir ou fermer le menu déroulant"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Fermer"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"Recherche"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"Suggestions ci-dessous"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-fr/strings.xml b/compose/material3/material3/src/androidMain/res/values-fr/strings.xml
index aeedebb..9c4fdfc 100644
--- a/compose/material3/material3/src/androidMain/res/values-fr/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-fr/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"Boîte de dialogue"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Développé"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Réduit"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Activer/désactiver le menu déroulant"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Fermer"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"Rechercher"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"Suggestions ci-dessous"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-gl/strings.xml b/compose/material3/material3/src/androidMain/res/values-gl/strings.xml
index bb49fe7..5e96091 100644
--- a/compose/material3/material3/src/androidMain/res/values-gl/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-gl/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"Cadro de diálogo"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Despregado"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Contraído"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Activa ou desactiva o menú despregable"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Pechar"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"Buscar"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"Hai suxestións abaixo"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-hu/strings.xml b/compose/material3/material3/src/androidMain/res/values-hu/strings.xml
index 558e144..28d4863 100644
--- a/compose/material3/material3/src/androidMain/res/values-hu/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-hu/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"Párbeszédpanel"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Kibontva"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Összecsukva"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Legördülő menü átváltása"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Elvetés"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"Keresés"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"Javaslatok alább"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-hy/strings.xml b/compose/material3/material3/src/androidMain/res/values-hy/strings.xml
index c7111b0..bb0ef84 100644
--- a/compose/material3/material3/src/androidMain/res/values-hy/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-hy/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"Երկխոսության պատուհան"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Ծավալված է"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Ծալված է"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Բացել/փակել իջնող ցանկը"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Փակել"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"Որոնում"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"Առաջարկները հասանելի են ստորև"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-it/strings.xml b/compose/material3/material3/src/androidMain/res/values-it/strings.xml
index dca7866..c3f0b06 100644
--- a/compose/material3/material3/src/androidMain/res/values-it/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-it/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"Finestra di dialogo"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Espanso"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Compresso"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Attiva/disattiva menu a discesa"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Chiudi"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"Cerca"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"Suggerimenti sotto"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-iw/strings.xml b/compose/material3/material3/src/androidMain/res/values-iw/strings.xml
index 0bf5c61..4ce0a71 100644
--- a/compose/material3/material3/src/androidMain/res/values-iw/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-iw/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"תיבת דו-שיח"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"התפריט הנפתח מורחב"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"התפריט הנפתח מכווץ"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"החלפת המצב של התפריט הנפתח"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"סגירה"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"חיפוש"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"הצעות מופיעות למטה"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-ja/strings.xml b/compose/material3/material3/src/androidMain/res/values-ja/strings.xml
index 0a3593c..15894b9 100644
--- a/compose/material3/material3/src/androidMain/res/values-ja/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-ja/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"ダイアログ"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"開いています"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"閉じています"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"プルダウン メニューを切り替えます"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"閉じる"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"検索"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"検索候補は次のとおりです"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-ka/strings.xml b/compose/material3/material3/src/androidMain/res/values-ka/strings.xml
index acc03b8..bf58b02 100644
--- a/compose/material3/material3/src/androidMain/res/values-ka/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-ka/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"დიალოგი"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"გაფართოებული"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"ჩაკეცილი"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"გადართეთ ჩამოსაშლელი მენიუ"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"დახურვა"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"ძიება"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"შემოთავაზებები იხილეთ ქვემოთ"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-kk/strings.xml b/compose/material3/material3/src/androidMain/res/values-kk/strings.xml
index 8187675..8a1b7861 100644
--- a/compose/material3/material3/src/androidMain/res/values-kk/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-kk/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"Диалогтік терезе"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Жайылды"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Жиылды"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Ашылмалы мәзірді ауыстыру"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Жабу"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"Іздеу"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"Төмендегі ұсыныстар"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-kn/strings.xml b/compose/material3/material3/src/androidMain/res/values-kn/strings.xml
index 85008b6..5962fab 100644
--- a/compose/material3/material3/src/androidMain/res/values-kn/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-kn/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"ಡೈಲಾಗ್"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"ವಿಸ್ತರಿಸಲಾಗಿದೆ"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"ಕುಗ್ಗಿಸಲಾಗಿದೆ"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"ಡ್ರಾಪ್‌ಡೌನ್ ಮೆನುವನ್ನು ಟಾಗಲ್ ಮಾಡಿ"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"ವಜಾಗೊಳಿಸಿ"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"ಹುಡುಕಿ"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"ಸಲಹೆಗಳನ್ನು ಕೆಳಗೆ ನೀಡಲಾಗಿದೆ"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-ko/strings.xml b/compose/material3/material3/src/androidMain/res/values-ko/strings.xml
index bfdfeb2..e39a2e2 100644
--- a/compose/material3/material3/src/androidMain/res/values-ko/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-ko/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"대화상자"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"펼침"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"접힘"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"전환 드롭다운 메뉴"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"닫기"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"검색"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"아래의 추천 검색어"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-lt/strings.xml b/compose/material3/material3/src/androidMain/res/values-lt/strings.xml
index 9a96cc5..4157437 100644
--- a/compose/material3/material3/src/androidMain/res/values-lt/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-lt/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"Dialogo langas"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Išskleista"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Sutraukta"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Perjungti išskleidžiamąjį meniu"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Atsisakyti"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"Paieška"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"Pasiūlymai pateikti toliau"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-lv/strings.xml b/compose/material3/material3/src/androidMain/res/values-lv/strings.xml
index 7aaf2d9..fec1a52 100644
--- a/compose/material3/material3/src/androidMain/res/values-lv/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-lv/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"Dialoglodziņš"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Izvērsta"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Sakļauta"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Pārslēgt nolaižamo izvēlni"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Nerādīt"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"Meklēšana"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"Tālāk ir sniegti ieteikumi"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-mk/strings.xml b/compose/material3/material3/src/androidMain/res/values-mk/strings.xml
index 6d5f51b..87aeea6 100644
--- a/compose/material3/material3/src/androidMain/res/values-mk/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-mk/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"Дијалог"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Проширено"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Собрано"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Вклучување/исклучување паѓачко мени"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Отфрли"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"Пребарување"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"Предлозите се наведени подолу"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-mn/strings.xml b/compose/material3/material3/src/androidMain/res/values-mn/strings.xml
index 8df6c2d..419bc71 100644
--- a/compose/material3/material3/src/androidMain/res/values-mn/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-mn/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"Харилцах цонх"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Дэлгэсэн"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Хураасан"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Унадаг цэсийг асаах/унтраах"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Хаах"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"Хайх"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"Доорх зөвлөмжүүд"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-mr/strings.xml b/compose/material3/material3/src/androidMain/res/values-mr/strings.xml
index 141f0bb..70e68f9 100644
--- a/compose/material3/material3/src/androidMain/res/values-mr/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-mr/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"डायलॉग"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"विस्तारित केला आहे"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"कोलॅप्स केला आहे"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"ड्रॉपडाउन मेनू टॉगल करा"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"डिसमिस करा"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"शोधा"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"सूचना खाली आहेत"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-my/strings.xml b/compose/material3/material3/src/androidMain/res/values-my/strings.xml
index 9bca021..a94a4b3 100644
--- a/compose/material3/material3/src/androidMain/res/values-my/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-my/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"ဒိုင်ယာလော့"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"ချဲ့ထားသည်"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"ချုံ့ထားသည်"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"ဆွဲချမီနူးကို ပြောင်းရန်"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"ပယ်ရန်"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"ရှာရန်"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"အကြံပြုချက်များသည် အောက်တွင်ရှိသည်"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-nb/strings.xml b/compose/material3/material3/src/androidMain/res/values-nb/strings.xml
index f18afdb5..7b79658 100644
--- a/compose/material3/material3/src/androidMain/res/values-nb/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-nb/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"Dialogboks"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Vises"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Skjules"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Slå rullegardinmeny av/på"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Lukk"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"Søk"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"Du finner forslag nedenfor"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-nl/strings.xml b/compose/material3/material3/src/androidMain/res/values-nl/strings.xml
index 0dc1cb0..1070dab 100644
--- a/compose/material3/material3/src/androidMain/res/values-nl/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-nl/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"Dialoogvenster"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Uitgevouwen"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Samengevouwen"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Dropdownmenu aan-/uitzetten"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Sluiten"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"Zoeken"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"Suggesties hieronder"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-pa/strings.xml b/compose/material3/material3/src/androidMain/res/values-pa/strings.xml
index b70e23d..037b577 100644
--- a/compose/material3/material3/src/androidMain/res/values-pa/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-pa/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"ਡਾਇਲੌਗ"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"ਵਿਸਤਾਰ ਕੀਤਾ ਗਿਆ"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"ਸਮੇਟਿਆ ਗਿਆ"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"ਡ੍ਰੌਪ-ਡਾਊਨ ਮੀਨੂ ਨੂੰ ਟੌਗਲ ਕਰੋ"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"ਖਾਰਜ ਕਰੋ"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"ਖੋਜੋ"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"ਸੁਝਾਅ ਹੇਠਾਂ ਹਨ"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-pt-rBR/strings.xml b/compose/material3/material3/src/androidMain/res/values-pt-rBR/strings.xml
index bb753a8..828b251 100644
--- a/compose/material3/material3/src/androidMain/res/values-pt-rBR/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-pt-rBR/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"Caixa de diálogo"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Aberto"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Fechado"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Ativar/desativar o menu suspenso"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Dispensar"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"Pesquisar"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"Sugestões abaixo"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-pt/strings.xml b/compose/material3/material3/src/androidMain/res/values-pt/strings.xml
index bb753a8..828b251 100644
--- a/compose/material3/material3/src/androidMain/res/values-pt/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-pt/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"Caixa de diálogo"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Aberto"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Fechado"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Ativar/desativar o menu suspenso"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Dispensar"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"Pesquisar"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"Sugestões abaixo"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-ro/strings.xml b/compose/material3/material3/src/androidMain/res/values-ro/strings.xml
index 077bd43..2045997 100644
--- a/compose/material3/material3/src/androidMain/res/values-ro/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-ro/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"Dialog"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Extins"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Restrâns"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Comută meniul drop-down"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Închide"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"Caută"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"Sugestii mai jos"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-si/strings.xml b/compose/material3/material3/src/androidMain/res/values-si/strings.xml
index c638936..2dc21c0 100644
--- a/compose/material3/material3/src/androidMain/res/values-si/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-si/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"සංවාදය"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"දිග හරින ලදි"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"හකුළන ලදි"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"පතන මෙනුව ටොගල් කරන්න"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"අස් කරන්න"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"සෙවීම"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"පහත යෝජනා"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-sq/strings.xml b/compose/material3/material3/src/androidMain/res/values-sq/strings.xml
index 0465363..c76613d 100644
--- a/compose/material3/material3/src/androidMain/res/values-sq/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-sq/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"Dialogu"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Zgjeruar"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Palosur"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Zgjero/palos menynë me lëshim poshtë"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Hiq"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"Kërkimi"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"Sugjerimet më poshtë"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-sv/strings.xml b/compose/material3/material3/src/androidMain/res/values-sv/strings.xml
index 45a0038..59d9068 100644
--- a/compose/material3/material3/src/androidMain/res/values-sv/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-sv/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"Dialogruta"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Utökad"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Komprimerad"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Utöka/komprimera rullgardinsmeny"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Stäng"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"Sök"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"Se förslag nedan"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-ta/strings.xml b/compose/material3/material3/src/androidMain/res/values-ta/strings.xml
index cd65b2c..8ff4dbb 100644
--- a/compose/material3/material3/src/androidMain/res/values-ta/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-ta/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"உரையாடல்"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"விரிவாக்கப்பட்டது"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"சுருக்கப்பட்டது"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"கீழ்த்தோன்றல் மெனுவை நிலைமாற்றும்"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"நிராகரிக்கும்"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"தேடல்"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"பரிந்துரைகள் கீழே கிடைக்கும்"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-tr/strings.xml b/compose/material3/material3/src/androidMain/res/values-tr/strings.xml
index f5d84bf..110d0eb 100644
--- a/compose/material3/material3/src/androidMain/res/values-tr/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-tr/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"Dialog"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Genişletildi"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Daraltıldı"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Açılır menüyü açın/kapatın"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Kapat"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"Arama"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"Önerileri aşağıda bulabilirsiniz"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-uk/strings.xml b/compose/material3/material3/src/androidMain/res/values-uk/strings.xml
index 3f4fca4..3ce4e58 100644
--- a/compose/material3/material3/src/androidMain/res/values-uk/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-uk/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"Вікно"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Розгорнуто"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Згорнуто"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Згорнути або розгорнути спадне меню"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Закрити"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"Пошук"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"Підказки внизу"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-uz/strings.xml b/compose/material3/material3/src/androidMain/res/values-uz/strings.xml
index 36b567e..95be160 100644
--- a/compose/material3/material3/src/androidMain/res/values-uz/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-uz/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"Muloqot oynasi"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Yoyilgan"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Yigʻilgan"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Pastga ochiluvchi menyuni koʻrsatish/yashirish"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Yopish"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"Qidiruv"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"Takliflar quyida"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-vi/strings.xml b/compose/material3/material3/src/androidMain/res/values-vi/strings.xml
index cb322a4..33eb1a6 100644
--- a/compose/material3/material3/src/androidMain/res/values-vi/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-vi/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"Hộp thoại"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Đã mở rộng"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Đã thu gọn"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Bật/tắt trình đơn thả xuống"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Đóng"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"Tìm kiếm"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"Các đề xuất ở bên dưới"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-zh-rCN/strings.xml b/compose/material3/material3/src/androidMain/res/values-zh-rCN/strings.xml
index c2b04c2..839fc1b 100644
--- a/compose/material3/material3/src/androidMain/res/values-zh-rCN/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-zh-rCN/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"对话框"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"已展开"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"已收起"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"展开/收起下拉菜单"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"关闭"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"搜索"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"以下是搜索建议"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-zh-rHK/strings.xml b/compose/material3/material3/src/androidMain/res/values-zh-rHK/strings.xml
index 51b6d1c..d1e43fb 100644
--- a/compose/material3/material3/src/androidMain/res/values-zh-rHK/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-zh-rHK/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"對話框"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"已展開"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"已收合"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"切換下拉式選單"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"關閉"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"搜尋"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"建議如下"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-zh-rTW/strings.xml b/compose/material3/material3/src/androidMain/res/values-zh-rTW/strings.xml
index 39ce414..2c2dc9b 100644
--- a/compose/material3/material3/src/androidMain/res/values-zh-rTW/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-zh-rTW/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"對話方塊"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"已展開"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"已收合"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"切換鈕下拉式選單"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"關閉"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"搜尋"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"建議如下"</string>
diff --git a/compose/material3/material3/src/androidMain/res/values-zu/strings.xml b/compose/material3/material3/src/androidMain/res/values-zu/strings.xml
index ac7b6fa..cb3f162 100644
--- a/compose/material3/material3/src/androidMain/res/values-zu/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-zu/strings.xml
@@ -20,8 +20,7 @@
     <string name="m3c_dialog" msgid="7617233117134790350">"Ibhokisi"</string>
     <string name="m3c_dropdown_menu_expanded" msgid="2360841780724299882">"Kunwetshiwe"</string>
     <string name="m3c_dropdown_menu_collapsed" msgid="3177828188723359358">"Kugoqiwe"</string>
-    <!-- no translation found for m3c_dropdown_menu_toggle (8687821690726149911) -->
-    <skip />
+    <string name="m3c_dropdown_menu_toggle" msgid="8687821690726149911">"Guqula imenyu yokwehlayo"</string>
     <string name="m3c_snackbar_dismiss" msgid="6152755701819882931">"Chitha"</string>
     <string name="m3c_search_bar_search" msgid="6152806324422087846">"Sesha"</string>
     <string name="m3c_suggestions_available" msgid="7655536806087401899">"Iziphakamiso ngezansi"</string>
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/NavigationItem.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/NavigationItem.kt
index e3d9b77..ccb4c3a 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/NavigationItem.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/NavigationItem.kt
@@ -68,6 +68,7 @@
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.offset
 import androidx.compose.ui.util.fastFirst
+import androidx.compose.ui.util.fastFirstOrNull
 import kotlin.math.max
 import kotlin.math.roundToInt
 
@@ -474,11 +475,10 @@
     ): Int {
         val iconHeight = measurables.fastFirst { it.layoutId == IconLayoutIdTag }
             .maxIntrinsicHeight(width)
-        val labelHeight = measurables.fastFirst { it.layoutId == LabelLayoutIdTag }
-            .maxIntrinsicHeight(width)
-        val paddings =
-            (topIconItemVerticalPadding * 2 + indicatorVerticalPadding * 2 +
-                indicatorToLabelVerticalPadding).roundToPx()
+        val labelHeight = measurables.fastFirstOrNull { it.layoutId == LabelLayoutIdTag }
+            ?.maxIntrinsicHeight(width) ?: 0
+        val paddings = (topIconItemVerticalPadding * 2 + indicatorVerticalPadding * 2 +
+            indicatorToLabelVerticalPadding).roundToPx()
 
         return iconHeight + labelHeight + paddings
     }
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/ProgressIndicator.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/ProgressIndicator.kt
index d0bcba7..9381e45 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/ProgressIndicator.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/ProgressIndicator.kt
@@ -136,8 +136,9 @@
     trackColor: Color = ProgressIndicatorDefaults.linearTrackColor,
     strokeCap: StrokeCap = ProgressIndicatorDefaults.LinearStrokeCap,
     gapSize: Dp = ProgressIndicatorDefaults.LinearIndicatorTrackGapSize,
-    drawStopIndicator: (DrawScope.() -> Unit)? = {
+    drawStopIndicator: DrawScope.() -> Unit = {
         drawStopIndicator(
+            drawScope = this,
             stopSize = ProgressIndicatorDefaults.LinearTrackStopIndicatorSize,
             color = color,
             strokeCap = strokeCap
@@ -175,7 +176,7 @@
             0f, currentCoercedProgress, color, strokeWidth, strokeCap
         )
         // stop
-        drawStopIndicator?.invoke(this)
+        drawStopIndicator(this)
     }
 }
 
@@ -894,35 +895,40 @@
     /**
      * Draws the stop indicator at the end of the track.
      *
+     * @param drawScope the [DrawScope]
      * @param stopSize size of this stop indicator, it cannot be bigger than the track's height
      * @param color color of this stop indicator
      * @param strokeCap stroke cap to use for the ends of this stop indicator
      */
-    fun DrawScope.drawStopIndicator(
+    fun drawStopIndicator(
+        drawScope: DrawScope,
         stopSize: Dp,
         color: Color,
         strokeCap: StrokeCap,
     ) {
-        val adjustedStopSize = min(stopSize.toPx(), size.height) // Stop can't be bigger than track
-        val stopOffset = (size.height - adjustedStopSize) / 2 // Offset from end
-        if (strokeCap == StrokeCap.Round) {
-            drawCircle(
-                color = color,
-                radius = adjustedStopSize / 2f,
-                center = Offset(
-                    x = size.width - (adjustedStopSize / 2f) - stopOffset,
-                    y = size.height / 2f
+        with(drawScope) {
+            val adjustedStopSize =
+                min(stopSize.toPx(), size.height) // Stop can't be bigger than track
+            val stopOffset = (size.height - adjustedStopSize) / 2 // Offset from end
+            if (strokeCap == StrokeCap.Round) {
+                drawCircle(
+                    color = color,
+                    radius = adjustedStopSize / 2f,
+                    center = Offset(
+                        x = size.width - (adjustedStopSize / 2f) - stopOffset,
+                        y = size.height / 2f
+                    )
                 )
-            )
-        } else {
-            drawRect(
-                color = color,
-                topLeft = Offset(
-                    x = size.width - adjustedStopSize - stopOffset,
-                    y = (size.height - adjustedStopSize) / 2f
-                ),
-                size = Size(width = adjustedStopSize, height = adjustedStopSize)
-            )
+            } else {
+                drawRect(
+                    color = color,
+                    topLeft = Offset(
+                        x = size.width - adjustedStopSize - stopOffset,
+                        y = (size.height - adjustedStopSize) / 2f
+                    ),
+                    size = Size(width = adjustedStopSize, height = adjustedStopSize)
+                )
+            }
         }
     }
 }
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Slider.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Slider.kt
index 2bb7881..e69ce27 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Slider.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Slider.kt
@@ -1164,13 +1164,15 @@
         colors: SliderColors = colors(),
         drawStopIndicator: (DrawScope.(Offset) -> Unit)? = {
             drawStopIndicator(
+                drawScope = this,
                 offset = it,
                 color = colors.activeTrackColor,
                 size = TrackStopIndicatorSize
             )
         },
-        drawTick: (DrawScope.(Offset, Color) -> Unit)? = { offset, color ->
+        drawTick: DrawScope.(Offset, Color) -> Unit = { offset, color ->
             drawStopIndicator(
+                drawScope = this,
                 offset = offset,
                 color = color,
                 size = TickSize
@@ -1272,13 +1274,15 @@
         colors: SliderColors = colors(),
         drawStopIndicator: (DrawScope.(Offset) -> Unit)? = {
             drawStopIndicator(
+                drawScope = this,
                 offset = it,
                 color = colors.activeTrackColor,
                 size = TrackStopIndicatorSize
             )
         },
-        drawTick: (DrawScope.(Offset, Color) -> Unit)? = { offset, color ->
+        drawTick: DrawScope.(Offset, Color) -> Unit = { offset, color ->
             drawStopIndicator(
+                drawScope = this,
                 offset = offset,
                 color = color,
                 size = TickSize
@@ -1329,7 +1333,7 @@
         thumbTrackGapSize: Dp,
         trackInsideCornerSize: Dp,
         drawStopIndicator: (DrawScope.(Offset) -> Unit)?,
-        drawTick: (DrawScope.(Offset, Color) -> Unit)?,
+        drawTick: DrawScope.(Offset, Color) -> Unit,
         isRangeSlider: Boolean
     ) {
         val sliderStart = Offset(0f, center.y)
@@ -1412,7 +1416,7 @@
             if ((isRangeSlider && center.x in startGap) || center.x in endGap) {
                 return@forEachIndexed
             }
-            drawTick?.invoke(
+            drawTick(
                 this,
                 center, // offset
                 if (outsideFraction) inactiveTickColor else activeTickColor // color
@@ -1474,16 +1478,19 @@
         halfRectPath.rewind()
     }
 
-    private fun DrawScope.drawStopIndicator(
+    private fun drawStopIndicator(
+        drawScope: DrawScope,
         offset: Offset,
         size: Dp,
         color: Color
     ) {
-        drawCircle(
-            color = color,
-            center = offset,
-            radius = size.toPx() / 2f
-        )
+        with(drawScope) {
+            drawCircle(
+                color = color,
+                center = offset,
+                radius = size.toPx() / 2f
+            )
+        }
     }
 
     /**
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/internal/AnchoredDraggable.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/internal/AnchoredDraggable.kt
index cf714ea..7941e5a 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/internal/AnchoredDraggable.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/internal/AnchoredDraggable.kt
@@ -823,7 +823,7 @@
         if (other !is DraggableAnchorsElement<*>) return false
 
         if (state != other.state) return false
-        if (anchors != other.anchors) return false
+        if (anchors !== other.anchors) return false
         if (orientation != other.orientation) return false
 
         return true
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 5cf1202..0efe678 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
@@ -155,7 +155,7 @@
                     previous
                 else null
             is ComputedValueHolder ->
-                if (value.compute == previous.compute)
+                if (value.compute === previous.compute)
                     previous
                 else null
             else -> null
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/Snapshot.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/Snapshot.kt
index 6e6bb2b..28e609f 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/Snapshot.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/Snapshot.kt
@@ -1794,7 +1794,7 @@
 ): ((Any) -> Unit)? {
     @Suppress("NAME_SHADOWING")
     val parentObserver = if (mergeReadObserver) parentObserver else null
-    return if (readObserver != null && parentObserver != null && readObserver != parentObserver) {
+    return if (readObserver != null && parentObserver != null && readObserver !== parentObserver) {
         { state: Any ->
             readObserver(state)
             parentObserver(state)
@@ -1806,7 +1806,7 @@
     writeObserver: ((Any) -> Unit)?,
     parentObserver: ((Any) -> Unit)?
 ): ((Any) -> Unit)? =
-    if (writeObserver != null && parentObserver != null && writeObserver != parentObserver) {
+    if (writeObserver != null && parentObserver != null && writeObserver !== parentObserver) {
         { state: Any ->
             writeObserver(state)
             parentObserver(state)
diff --git a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/LayerManager.android.kt b/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/LayerManager.android.kt
index 1b87de9..23b14d9 100644
--- a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/LayerManager.android.kt
+++ b/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/LayerManager.android.kt
@@ -74,8 +74,12 @@
             ).also { imageReader = it }
             val surface = reader.surface
             val canvas = LockHardwareCanvasHelper.lockHardwareCanvas(surface)
-            canvasHolder.drawInto(canvas) {
-                layers.forEach { layer -> layer.draw(this, null) }
+            // on Robolectric even this canvas is not hardware accelerated and drawing render nodes
+            // are not supported
+            if (canvas.isHardwareAccelerated) {
+                canvasHolder.drawInto(canvas) {
+                    layers.forEach { layer -> layer.draw(this, null) }
+                }
             }
             surface.unlockCanvasAndPost(canvas)
         }
diff --git a/compose/ui/ui-inspection/generate-packages/compose_packages_list.txt b/compose/ui/ui-inspection/generate-packages/compose_packages_list.txt
index 46618a9..36c9a44 100644
--- a/compose/ui/ui-inspection/generate-packages/compose_packages_list.txt
+++ b/compose/ui/ui-inspection/generate-packages/compose_packages_list.txt
@@ -13,22 +13,26 @@
 androidx.compose.foundation.lazy.staggeredgrid
 androidx.compose.foundation.pager
 androidx.compose.foundation.text
+androidx.compose.foundation.text.input
 androidx.compose.foundation.text.selection
-androidx.compose.foundation.text2
-androidx.compose.foundation.text2.input
 androidx.compose.foundation.window
 androidx.compose.material
 androidx.compose.material.internal
+androidx.compose.material.navigation
 androidx.compose.material.pullrefresh
 androidx.compose.material.ripple
 androidx.compose.material3
 androidx.compose.material3.adaptive
-androidx.compose.material3.adaptive.navigation.suite
+androidx.compose.material3.adaptive.layout
+androidx.compose.material3.adaptive.navigation
+androidx.compose.material3.adaptive.navigationsuite
+androidx.compose.material3.carousel
 androidx.compose.material3.common
 androidx.compose.material3.internal
 androidx.compose.material3.pulltorefresh
 androidx.compose.material3.windowsizeclass
 androidx.compose.runtime
+androidx.compose.runtime.internal
 androidx.compose.runtime.livedata
 androidx.compose.runtime.mock
 androidx.compose.runtime.reflect
@@ -37,6 +41,8 @@
 androidx.compose.runtime.saveable
 androidx.compose.ui
 androidx.compose.ui.awt
+androidx.compose.ui.draw
+androidx.compose.ui.graphics
 androidx.compose.ui.graphics.benchmark
 androidx.compose.ui.graphics.vector
 androidx.compose.ui.layout
diff --git a/compose/ui/ui-inspection/generate-packages/generate_compose_packages.py b/compose/ui/ui-inspection/generate-packages/generate_compose_packages.py
index 371c02b..2a8df1b 100755
--- a/compose/ui/ui-inspection/generate-packages/generate_compose_packages.py
+++ b/compose/ui/ui-inspection/generate-packages/generate_compose_packages.py
@@ -107,6 +107,7 @@
     package = 'package androidx.compose.ui.inspection.inspector\n\n'
     imports = (
         'import androidx.annotation.VisibleForTesting\n'
+        'import androidx.collection.intSetOf\n'
         'import kotlin.math.absoluteValue\n\n'
     )
     package_name_hash_function = (
@@ -115,7 +116,7 @@
         '    packageName.fold(0) { hash, char -> hash * 31 + char.code }.absoluteValue\n\n'
     )
     system_packages_val = (
-        'val systemPackages = setOf(\n'
+        'val systemPackages = intSetOf(\n'
         '    -1,\n'
         '%s\n'
         ')\n' % (
diff --git a/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/inspector/PackageHashes.kt b/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/inspector/PackageHashes.kt
index df3b3cf..6bdbd8a 100644
--- a/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/inspector/PackageHashes.kt
+++ b/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/inspector/PackageHashes.kt
@@ -27,22 +27,26 @@
     packageNameHash("androidx.compose.foundation.lazy.staggeredgrid"),
     packageNameHash("androidx.compose.foundation.pager"),
     packageNameHash("androidx.compose.foundation.text"),
+    packageNameHash("androidx.compose.foundation.text.input"),
     packageNameHash("androidx.compose.foundation.text.selection"),
-    packageNameHash("androidx.compose.foundation.text2"),
-    packageNameHash("androidx.compose.foundation.text2.input"),
     packageNameHash("androidx.compose.foundation.window"),
     packageNameHash("androidx.compose.material"),
     packageNameHash("androidx.compose.material.internal"),
+    packageNameHash("androidx.compose.material.navigation"),
     packageNameHash("androidx.compose.material.pullrefresh"),
     packageNameHash("androidx.compose.material.ripple"),
     packageNameHash("androidx.compose.material3"),
     packageNameHash("androidx.compose.material3.adaptive"),
-    packageNameHash("androidx.compose.material3.adaptive.navigation.suite"),
+    packageNameHash("androidx.compose.material3.adaptive.layout"),
+    packageNameHash("androidx.compose.material3.adaptive.navigation"),
+    packageNameHash("androidx.compose.material3.adaptive.navigationsuite"),
+    packageNameHash("androidx.compose.material3.carousel"),
     packageNameHash("androidx.compose.material3.common"),
     packageNameHash("androidx.compose.material3.internal"),
     packageNameHash("androidx.compose.material3.pulltorefresh"),
     packageNameHash("androidx.compose.material3.windowsizeclass"),
     packageNameHash("androidx.compose.runtime"),
+    packageNameHash("androidx.compose.runtime.internal"),
     packageNameHash("androidx.compose.runtime.livedata"),
     packageNameHash("androidx.compose.runtime.mock"),
     packageNameHash("androidx.compose.runtime.reflect"),
@@ -51,6 +55,8 @@
     packageNameHash("androidx.compose.runtime.saveable"),
     packageNameHash("androidx.compose.ui"),
     packageNameHash("androidx.compose.ui.awt"),
+    packageNameHash("androidx.compose.ui.draw"),
+    packageNameHash("androidx.compose.ui.graphics"),
     packageNameHash("androidx.compose.ui.graphics.benchmark"),
     packageNameHash("androidx.compose.ui.graphics.vector"),
     packageNameHash("androidx.compose.ui.layout"),
diff --git a/compose/ui/ui-test/api/current.txt b/compose/ui/ui-test/api/current.txt
index 1ba2f23..e374fff 100644
--- a/compose/ui/ui-test/api/current.txt
+++ b/compose/ui/ui-test/api/current.txt
@@ -389,13 +389,18 @@
     method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void animateAlong(androidx.compose.ui.test.MouseInjectionScope, kotlin.jvm.functions.Function1<? super java.lang.Long,androidx.compose.ui.geometry.Offset> curve, optional long durationMillis);
     method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void animateBy(androidx.compose.ui.test.MouseInjectionScope, long delta, optional long durationMillis);
     method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void animateTo(androidx.compose.ui.test.MouseInjectionScope, long position, optional long durationMillis);
-    method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void click(androidx.compose.ui.test.MouseInjectionScope, optional long position);
-    method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void doubleClick(androidx.compose.ui.test.MouseInjectionScope, optional long position);
-    method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void dragAndDrop(androidx.compose.ui.test.MouseInjectionScope, long start, long end, optional long durationMillis);
-    method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void longClick(androidx.compose.ui.test.MouseInjectionScope, optional long position);
+    method @Deprecated @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void click(androidx.compose.ui.test.MouseInjectionScope, optional long position);
+    method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void click(androidx.compose.ui.test.MouseInjectionScope, optional long position, optional int button);
+    method @Deprecated @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void doubleClick(androidx.compose.ui.test.MouseInjectionScope, optional long position);
+    method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void doubleClick(androidx.compose.ui.test.MouseInjectionScope, optional long position, optional int button);
+    method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void dragAndDrop(androidx.compose.ui.test.MouseInjectionScope, long start, long end, optional int button, optional long durationMillis);
+    method @Deprecated @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void dragAndDrop(androidx.compose.ui.test.MouseInjectionScope, long start, long end, optional long durationMillis);
+    method @Deprecated @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void longClick(androidx.compose.ui.test.MouseInjectionScope, optional long position);
+    method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void longClick(androidx.compose.ui.test.MouseInjectionScope, optional long position, optional int button);
     method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void rightClick(androidx.compose.ui.test.MouseInjectionScope, optional long position);
     method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void smoothScroll(androidx.compose.ui.test.MouseInjectionScope, float scrollAmount, optional long durationMillis, optional int scrollWheel);
-    method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void tripleClick(androidx.compose.ui.test.MouseInjectionScope, optional long position);
+    method @Deprecated @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void tripleClick(androidx.compose.ui.test.MouseInjectionScope, optional long position);
+    method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void tripleClick(androidx.compose.ui.test.MouseInjectionScope, optional long position, optional int button);
   }
 
   public sealed interface MultiModalInjectionScope extends androidx.compose.ui.test.InjectionScope {
diff --git a/compose/ui/ui-test/api/restricted_current.txt b/compose/ui/ui-test/api/restricted_current.txt
index e482d77..fb5c367 100644
--- a/compose/ui/ui-test/api/restricted_current.txt
+++ b/compose/ui/ui-test/api/restricted_current.txt
@@ -390,13 +390,18 @@
     method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void animateAlong(androidx.compose.ui.test.MouseInjectionScope, kotlin.jvm.functions.Function1<? super java.lang.Long,androidx.compose.ui.geometry.Offset> curve, optional long durationMillis);
     method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void animateBy(androidx.compose.ui.test.MouseInjectionScope, long delta, optional long durationMillis);
     method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void animateTo(androidx.compose.ui.test.MouseInjectionScope, long position, optional long durationMillis);
-    method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void click(androidx.compose.ui.test.MouseInjectionScope, optional long position);
-    method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void doubleClick(androidx.compose.ui.test.MouseInjectionScope, optional long position);
-    method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void dragAndDrop(androidx.compose.ui.test.MouseInjectionScope, long start, long end, optional long durationMillis);
-    method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void longClick(androidx.compose.ui.test.MouseInjectionScope, optional long position);
+    method @Deprecated @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void click(androidx.compose.ui.test.MouseInjectionScope, optional long position);
+    method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void click(androidx.compose.ui.test.MouseInjectionScope, optional long position, optional int button);
+    method @Deprecated @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void doubleClick(androidx.compose.ui.test.MouseInjectionScope, optional long position);
+    method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void doubleClick(androidx.compose.ui.test.MouseInjectionScope, optional long position, optional int button);
+    method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void dragAndDrop(androidx.compose.ui.test.MouseInjectionScope, long start, long end, optional int button, optional long durationMillis);
+    method @Deprecated @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void dragAndDrop(androidx.compose.ui.test.MouseInjectionScope, long start, long end, optional long durationMillis);
+    method @Deprecated @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void longClick(androidx.compose.ui.test.MouseInjectionScope, optional long position);
+    method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void longClick(androidx.compose.ui.test.MouseInjectionScope, optional long position, optional int button);
     method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void rightClick(androidx.compose.ui.test.MouseInjectionScope, optional long position);
     method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void smoothScroll(androidx.compose.ui.test.MouseInjectionScope, float scrollAmount, optional long durationMillis, optional int scrollWheel);
-    method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void tripleClick(androidx.compose.ui.test.MouseInjectionScope, optional long position);
+    method @Deprecated @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void tripleClick(androidx.compose.ui.test.MouseInjectionScope, optional long position);
+    method @SuppressCompatibility @androidx.compose.ui.test.ExperimentalTestApi public static void tripleClick(androidx.compose.ui.test.MouseInjectionScope, optional long position, optional int button);
   }
 
   public sealed interface MultiModalInjectionScope extends androidx.compose.ui.test.InjectionScope {
diff --git a/compose/ui/ui-test/samples/src/main/java/androidx/compose/ui/test/samples/MouseInjectionScopeSamples.kt b/compose/ui/ui-test/samples/src/main/java/androidx/compose/ui/test/samples/MouseInjectionScopeSamples.kt
index 2535abb..f162158 100644
--- a/compose/ui/ui-test/samples/src/main/java/androidx/compose/ui/test/samples/MouseInjectionScopeSamples.kt
+++ b/compose/ui/ui-test/samples/src/main/java/androidx/compose/ui/test/samples/MouseInjectionScopeSamples.kt
@@ -17,31 +17,90 @@
 package androidx.compose.ui.test.samples
 
 import androidx.annotation.Sampled
+import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.test.ExperimentalTestApi
+import androidx.compose.ui.test.ScrollWheel
+import androidx.compose.ui.test.animateAlong
+import androidx.compose.ui.test.animateTo
 import androidx.compose.ui.test.click
 import androidx.compose.ui.test.onNodeWithTag
 import androidx.compose.ui.test.performMouseInput
+import androidx.compose.ui.test.smoothScroll
+import kotlin.math.PI
+import kotlin.math.cos
+import kotlin.math.sin
 
 @OptIn(ExperimentalTestApi::class)
 @Sampled
 fun mouseInputClick() {
     composeTestRule.onNodeWithTag("myComponent")
         .performMouseInput {
+            // Click in the middle of the node
             click(center)
         }
 }
 
 @OptIn(ExperimentalTestApi::class)
 @Sampled
-fun mouseInputScrollWhileDown() {
+fun mouseInputAnimateTo() {
     composeTestRule.onNodeWithTag("myComponent")
         .performMouseInput {
+            // Hover over the node, making an X shape
+            moveTo(topLeft)
+            animateTo(bottomRight)
+            // Note that an actual user wouldn't be able to instantly
+            // move from the bottom right to the top right
+            moveTo(topRight)
+            animateTo(bottomLeft)
+        }
+}
+
+@OptIn(ExperimentalTestApi::class)
+@Sampled
+fun mouseInputAnimateAlong() {
+    composeTestRule.onNodeWithTag("myComponent")
+        .performMouseInput {
+            // Hover over the node, making a full circle with a radius of 100px
+            val r = 100f
+            animateAlong(
+                curve = {
+                    val angle = 2 * PI * it / 1000
+                    center + Offset(r * cos(angle).toFloat(), r * sin(angle).toFloat())
+                },
+                durationMillis = 1000L
+            )
+        }
+}
+
+@OptIn(ExperimentalTestApi::class)
+@Sampled
+fun mouseInputScrollWhileDown() {
+    composeTestRule.onNodeWithTag("verticalScrollable")
+        // Scroll downwards while keeping a button pressed:
+        .performMouseInput {
+            // Presses the primary mouse button
             press()
+            // Scroll the scroll wheel by 6 units
             repeat(6) {
                 advanceEventTime()
-                scroll(-1f)
+                scroll(1f)
             }
+            // And release the mouse button
             advanceEventTime()
             release()
         }
 }
+
+@OptIn(ExperimentalTestApi::class)
+@Sampled
+fun mouseInputSmoothScroll() {
+    composeTestRule.onNodeWithTag("horizontalScrollable")
+        .performMouseInput {
+            // Scroll forwards horizontally, which is rightwards
+            // unless scroll direction is reversed
+            smoothScroll(100f, durationMillis = 500L, ScrollWheel.Horizontal)
+            // The 100f scroll delta is equally divided into smaller scrolls,
+            // such that the time in between two scroll events is more or less
+            // equal to the default time between events, 16ms.
+        }
+}
diff --git a/compose/ui/ui-test/src/androidCommonTest/kotlin/androidx/compose/ui/test/util/Verifications.kt b/compose/ui/ui-test/src/androidCommonTest/kotlin/androidx/compose/ui/test/util/Verifications.kt
index 489ecf0..f0a814a 100644
--- a/compose/ui/ui-test/src/androidCommonTest/kotlin/androidx/compose/ui/test/util/Verifications.kt
+++ b/compose/ui/ui-test/src/androidCommonTest/kotlin/androidx/compose/ui/test/util/Verifications.kt
@@ -223,9 +223,14 @@
  * Verifies that the [Offset] is equal to the given position with some tolerance. The default
  * tolerance is 0.001.
  */
-fun Offset.isAlmostEqualTo(position: Offset, tolerance: Float = 1e-3f) {
-    assertThat(x).isAlmostEqualTo(position.x, tolerance)
-    assertThat(y).isAlmostEqualTo(position.y, tolerance)
+fun Offset.isAlmostEqualTo(position: Offset, tolerance: Float = 1e-3f, message: String? = null) {
+    if (message != null) {
+        assertWithMessage(message).that(x).isAlmostEqualTo(position.x, tolerance)
+        assertWithMessage(message).that(y).isAlmostEqualTo(position.y, tolerance)
+    } else {
+        assertThat(x).isAlmostEqualTo(position.x, tolerance)
+        assertThat(y).isAlmostEqualTo(position.y, tolerance)
+    }
 }
 
 /**
diff --git a/compose/ui/ui-test/src/androidInstrumentedTest/kotlin/androidx/compose/ui/test/injectionscope/mouse/ClickTest.kt b/compose/ui/ui-test/src/androidInstrumentedTest/kotlin/androidx/compose/ui/test/injectionscope/mouse/ClickTest.kt
index 822384e..2881f1e 100644
--- a/compose/ui/ui-test/src/androidInstrumentedTest/kotlin/androidx/compose/ui/test/injectionscope/mouse/ClickTest.kt
+++ b/compose/ui/ui-test/src/androidInstrumentedTest/kotlin/androidx/compose/ui/test/injectionscope/mouse/ClickTest.kt
@@ -16,22 +16,54 @@
 
 package androidx.compose.ui.test.injectionscope.mouse
 
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.background
+import androidx.compose.foundation.gestures.draggable2D
+import androidx.compose.foundation.gestures.rememberDraggable2DState
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.offset
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
 import androidx.compose.testutils.expectError
+import androidx.compose.ui.Modifier
 import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.input.pointer.PointerEventType.Companion.Enter
 import androidx.compose.ui.input.pointer.PointerEventType.Companion.Exit
 import androidx.compose.ui.input.pointer.PointerEventType.Companion.Move
 import androidx.compose.ui.input.pointer.PointerEventType.Companion.Press
 import androidx.compose.ui.input.pointer.PointerEventType.Companion.Release
+import androidx.compose.ui.platform.testTag
 import androidx.compose.ui.test.ExperimentalTestApi
 import androidx.compose.ui.test.InputDispatcher
 import androidx.compose.ui.test.MouseButton
+import androidx.compose.ui.test.click
+import androidx.compose.ui.test.doubleClick
+import androidx.compose.ui.test.dragAndDrop
+import androidx.compose.ui.test.injectionscope.mouse.Common.ClickDuration
+import androidx.compose.ui.test.injectionscope.mouse.Common.DefaultDoubleClickTimeMillis
+import androidx.compose.ui.test.injectionscope.mouse.Common.DefaultLongClickTimeMillis
 import androidx.compose.ui.test.injectionscope.mouse.Common.PrimaryButton
 import androidx.compose.ui.test.injectionscope.mouse.Common.PrimarySecondaryButton
+import androidx.compose.ui.test.injectionscope.mouse.Common.SecondaryButton
 import androidx.compose.ui.test.injectionscope.mouse.Common.runMouseInputInjectionTest
 import androidx.compose.ui.test.injectionscope.mouse.Common.verifyMouseEvent
+import androidx.compose.ui.test.longClick
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.performMouseInput
+import androidx.compose.ui.test.rightClick
+import androidx.compose.ui.test.runComposeUiTest
+import androidx.compose.ui.test.tripleClick
+import androidx.compose.ui.unit.IntOffset
+import androidx.compose.ui.unit.dp
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
+import com.google.common.truth.Truth.assertWithMessage
+import kotlin.math.roundToInt
 import org.junit.Test
 import org.junit.runner.RunWith
 
@@ -45,6 +77,7 @@
         private val positionMove1 = Offset(2f, 2f)
         private val positionMove2 = Offset(3f, 3f)
         private val positionOut = Offset(101f, 101f)
+        private val positionCenter = Offset(50f, 50f)
     }
 
     @Test
@@ -190,4 +223,130 @@
             { verifyMouseEvent(1 * T, Press, true, positionIn, PrimaryButton) },
         )
     )
+
+    @Test
+    fun clickTest() = runMouseInputInjectionTest(
+        mouseInput = {
+            click()
+        },
+        eventVerifiers = arrayOf(
+            // t = 0, because click() presses immediately
+            { verifyMouseEvent(0, Enter, false, positionCenter) },
+            { verifyMouseEvent(0, Press, true, positionCenter, PrimaryButton) },
+            { verifyMouseEvent(ClickDuration, Release, false, positionCenter) },
+        )
+    )
+
+    @Test
+    fun rightClickTest() = runMouseInputInjectionTest(
+        mouseInput = {
+            rightClick()
+        },
+        eventVerifiers = arrayOf(
+            // t = 0, because click() presses immediately
+            { verifyMouseEvent(0, Enter, false, positionCenter) },
+            { verifyMouseEvent(0, Press, true, positionCenter, SecondaryButton) },
+            { verifyMouseEvent(ClickDuration, Release, false, positionCenter) },
+        )
+    )
+
+    @Test
+    fun doubleClickTest() {
+        // Time starts at 0, because doubleClick() presses immediately
+        val press1 = 0L
+        val release1 = press1 + ClickDuration
+        val press2 = release1 + DefaultDoubleClickTimeMillis
+        val release2 = press2 + ClickDuration
+
+        runMouseInputInjectionTest(
+            mouseInput = {
+                doubleClick()
+            },
+            eventVerifiers = arrayOf(
+                { verifyMouseEvent(press1, Enter, false, positionCenter) },
+                { verifyMouseEvent(press1, Press, true, positionCenter, PrimaryButton) },
+                { verifyMouseEvent(release1, Release, false, positionCenter) },
+                { verifyMouseEvent(press2, Press, true, positionCenter, PrimaryButton) },
+                { verifyMouseEvent(release2, Release, false, positionCenter) },
+            )
+        )
+    }
+
+    @Test
+    fun tripleClickTest() {
+        // Time starts at 0, because tripleClick() presses immediately
+        val press1 = 0L
+        val release1 = press1 + ClickDuration
+        val press2 = release1 + DefaultDoubleClickTimeMillis
+        val release2 = press2 + ClickDuration
+        val press3 = release2 + DefaultDoubleClickTimeMillis
+        val release3 = press3 + ClickDuration
+
+        runMouseInputInjectionTest(
+            mouseInput = {
+                tripleClick()
+            },
+            eventVerifiers = arrayOf(
+                { verifyMouseEvent(press1, Enter, false, positionCenter) },
+                { verifyMouseEvent(press1, Press, true, positionCenter, PrimaryButton) },
+                { verifyMouseEvent(release1, Release, false, positionCenter) },
+                { verifyMouseEvent(press2, Press, true, positionCenter, PrimaryButton) },
+                { verifyMouseEvent(release2, Release, false, positionCenter) },
+                { verifyMouseEvent(press3, Press, true, positionCenter, PrimaryButton) },
+                { verifyMouseEvent(release3, Release, false, positionCenter) },
+            )
+        )
+    }
+
+    @Test
+    fun longClickTest() = runMouseInputInjectionTest(
+        mouseInput = {
+            longClick()
+        },
+        eventVerifiers = arrayOf(
+            // t = 0, because longClick() presses immediately
+            { verifyMouseEvent(0L, Enter, false, positionCenter) },
+            { verifyMouseEvent(0L, Press, true, positionCenter, PrimaryButton) },
+            // longClick adds 100ms to the minimum required time, just to be sure
+            { verifyMouseEvent(DefaultLongClickTimeMillis + 100, Release, false, positionCenter) },
+        )
+    )
+
+    // Rather than checking the events sent on, for this more complex mouse gesture we
+    // check if the events actually lead to the expected outcome.
+    @Test
+    fun dragAndDropTest() = runComposeUiTest {
+        val sizeDp = 50.dp
+        val sizePx = with(density) { sizeDp.toPx() }
+        val marginPx = with(density) { 0.5.dp.toPx() }
+
+        var xOffsetPx by mutableStateOf(0f)
+        var yOffsetPx by mutableStateOf(0f)
+
+        setContent {
+            @OptIn(ExperimentalFoundationApi::class)
+            Box(Modifier.padding(16.dp).fillMaxSize()) {
+                Box(
+                    Modifier
+                        .testTag("draggable-box")
+                        .offset { IntOffset(xOffsetPx.roundToInt(), yOffsetPx.roundToInt()) }
+                        .size(sizeDp)
+                        .background(Color.Red)
+                        .draggable2D(
+                            rememberDraggable2DState {
+                                xOffsetPx += it.x
+                                yOffsetPx += it.y
+                            }
+                        )
+                )
+            }
+        }
+
+        onNodeWithTag("draggable-box").performMouseInput {
+            dragAndDrop(center, center + Offset(2f * width, 4f * height))
+        }
+        waitForIdle()
+        assertWithMessage("xOffset").that(xOffsetPx).isWithin(marginPx).of(2 * sizePx)
+        assertWithMessage("yOffset").that(yOffsetPx).isWithin(marginPx).of(4 * sizePx)
+    }
 }
diff --git a/compose/ui/ui-test/src/androidInstrumentedTest/kotlin/androidx/compose/ui/test/injectionscope/mouse/Common.kt b/compose/ui/ui-test/src/androidInstrumentedTest/kotlin/androidx/compose/ui/test/injectionscope/mouse/Common.kt
index 1612be4..fa93172 100644
--- a/compose/ui/ui-test/src/androidInstrumentedTest/kotlin/androidx/compose/ui/test/injectionscope/mouse/Common.kt
+++ b/compose/ui/ui-test/src/androidInstrumentedTest/kotlin/androidx/compose/ui/test/injectionscope/mouse/Common.kt
@@ -16,6 +16,8 @@
 
 package androidx.compose.ui.test.injectionscope.mouse
 
+import androidx.compose.testutils.TestViewConfiguration
+import androidx.compose.testutils.WithViewConfiguration
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.input.pointer.PointerButtons
 import androidx.compose.ui.input.pointer.PointerEventType
@@ -38,6 +40,18 @@
     val PrimarySecondaryButton = PointerButtons(
         MouseButton.Primary.buttonId or MouseButton.Secondary.buttonId
     )
+    val SecondaryButton = PointerButtons(MouseButton.Secondary.buttonId)
+
+    const val ClickDuration = 60L // MouseInjectionScope.SingleClickDelayMillis
+    private const val DoubleClickMin = 40L
+    private const val DoubleClickMax = 200L
+    const val DefaultDoubleClickTimeMillis = (DoubleClickMin + DoubleClickMax) / 2
+    const val DefaultLongClickTimeMillis = 300L
+    private val testViewConfiguration = TestViewConfiguration(
+        doubleTapMinTimeMillis = DoubleClickMin,
+        doubleTapTimeoutMillis = DoubleClickMax,
+        longPressTimeoutMillis = DefaultLongClickTimeMillis
+    )
 
     fun runMouseInputInjectionTest(
         mouseInput: MouseInjectionScope.() -> Unit,
@@ -46,7 +60,9 @@
         mainClock.autoAdvance = false
         val recorder = SinglePointerInputRecorder()
         setContent {
-            ClickableTestBox(recorder)
+            WithViewConfiguration(testViewConfiguration) {
+                ClickableTestBox(recorder)
+            }
         }
         onNodeWithTag(ClickableTestBox.defaultTag).performMouseInput(mouseInput)
         runOnIdle { recorder.verifyEvents(*eventVerifiers) }
diff --git a/compose/ui/ui-test/src/androidInstrumentedTest/kotlin/androidx/compose/ui/test/util/PointerInputs.kt b/compose/ui/ui-test/src/androidInstrumentedTest/kotlin/androidx/compose/ui/test/util/PointerInputs.kt
index ce31fd62..9e47232 100644
--- a/compose/ui/ui-test/src/androidInstrumentedTest/kotlin/androidx/compose/ui/test/util/PointerInputs.kt
+++ b/compose/ui/ui-test/src/androidInstrumentedTest/kotlin/androidx/compose/ui/test/util/PointerInputs.kt
@@ -198,19 +198,20 @@
     expectedButtons: PointerButtons = PointerButtons(0),
     expectedKeyboardModifiers: PointerKeyboardModifiers = PointerKeyboardModifiers(0),
 ) {
+    val s = " of $this"
     if (expectedTimestamp != null) {
-        assertWithMessage("timestamp").that(timestamp).isEqualTo(expectedTimestamp)
+        assertWithMessage("timestamp$s").that(timestamp).isEqualTo(expectedTimestamp)
     }
     if (expectedId != null) {
-        assertWithMessage("pointerId").that(id).isEqualTo(expectedId)
+        assertWithMessage("pointerId$s").that(id).isEqualTo(expectedId)
     }
-    assertWithMessage("isDown").that(down).isEqualTo(expectedDown)
-    assertWithMessage("position").that(position).isEqualTo(expectedPosition)
-    assertWithMessage("pointerType").that(pointerType).isEqualTo(expectedPointerType)
-    assertWithMessage("eventType").that(eventType).isEqualTo(expectedEventType)
-    assertWithMessage("scrollDelta").that(scrollDelta).isEqualTo(expectedScrollDelta)
-    assertWithMessage("buttonsDown").that(buttons).isEqualTo(expectedButtons)
-    assertWithMessage("keyModifiers").that(keyboardModifiers).isEqualTo(expectedKeyboardModifiers)
+    assertWithMessage("isDown$s").that(down).isEqualTo(expectedDown)
+    position.isAlmostEqualTo(expectedPosition, message = "position$s")
+    assertWithMessage("pointerType$s").that(pointerType).isEqualTo(expectedPointerType)
+    assertWithMessage("eventType$s").that(eventType).isEqualTo(expectedEventType)
+    scrollDelta.isAlmostEqualTo(expectedScrollDelta, message = "scrollDelta$s")
+    assertWithMessage("buttonsDown$s").that(buttons).isEqualTo(expectedButtons)
+    assertWithMessage("keyModifiers$s").that(keyboardModifiers).isEqualTo(expectedKeyboardModifiers)
 }
 
 /**
diff --git a/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/MouseInjectionScope.kt b/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/MouseInjectionScope.kt
index 36c5fbc..5261179 100644
--- a/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/MouseInjectionScope.kt
+++ b/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/MouseInjectionScope.kt
@@ -173,12 +173,8 @@
     fun cancel(delayMillis: Long = eventPeriodMillis)
 
     /**
-     * Sends a hover enter event at the given [position], [delayMillis] after the last sent event.
-     *
-     * Note that it is discouraged to manually send a hover enter event followed by a [moveTo]
-     * event. [moveTo] does this for you automatically, making sure the event times of the two
-     * events are in sync. Only use this method for special scenarios where the hover enter event
-     * is not sent as a side effect of another event.
+     * Sends a hover enter event at the given [position], [delayMillis] after the last sent event,
+     * without sending a hover move event.
      *
      * An [IllegalStateException] will be thrown when mouse buttons are down, or if the mouse is
      * already hovering.
@@ -186,6 +182,12 @@
      * The [position] is in the node's local coordinate system, where (0, 0) is the top left
      * corner of the node.
      *
+     * __Note__: enter and exit events are already sent as a side effect of [movement][moveTo]
+     * when necessary. Whether or not this is part of the contract of mouse events is platform
+     * dependent, so it is highly discouraged to manually send enter or exit events.
+     * Only use this method for tests that need to make assertions about a component's state
+     * _in between_ the enter/exit and move event.
+     *
      * @param position The new position of the mouse, in the node's local coordinate system.
      * [currentPosition] by default.
      * @param delayMillis The time between the last sent event and this event.
@@ -194,19 +196,20 @@
     fun enter(position: Offset = currentPosition, delayMillis: Long = eventPeriodMillis)
 
     /**
-     * Sends a hover exit event at the given [position], [delayMillis] after the last sent event.
-     *
-     * Note that it is discouraged to manually send a hover exit event followed by a [moveTo]
-     * that is outside the boundaries of the Compose root or [press]ing a button. These methods
-     * do this for you automatically, making sure the event times of the two events are in sync.
-     * Only use this method for special scenarios where the hover exit event is not sent as a
-     * side effect of another event.
+     * Sends a hover exit event at the given [position], [delayMillis] after the last sent event,
+     * without sending a hover move event.
      *
      * An [IllegalStateException] will be thrown if the mouse was not hovering.
      *
      * The [position] is in the node's local coordinate system, where (0, 0) is the top left
      * corner of the node.
      *
+     * __Note__: enter and exit events are already sent as a side effect of [movement][moveTo]
+     * when necessary. Whether or not this is part of the contract of mouse events is platform
+     * dependent, so it is highly discouraged to manually send enter or exit events.
+     * Only use this method for tests that need to make assertions about a component's state
+     * _in between_ the enter/exit and move event.
+     *
      * @param position The new position of the mouse, in the node's local coordinate system
      * [currentPosition] by default.
      * @param delayMillis The time between the last sent event and this event.
@@ -227,6 +230,9 @@
      * of `64.dp`. However, on any platform, this conversion factor could change in the
      * future to improve the mouse scroll experience.
      *
+     * Example of how scroll could be used:
+     * @sample androidx.compose.ui.test.samples.mouseInputScrollWhileDown
+     *
      * @param delta The amount of scroll
      * @param scrollWheel Which scroll wheel to rotate. Can be either [ScrollWheel.Vertical] (the
      * default) or [ScrollWheel.Horizontal].
@@ -285,23 +291,37 @@
     }
 }
 
+@Deprecated(
+    message = "Replaced by an overload that takes a button parameter",
+    replaceWith = ReplaceWith("click(position)"),
+    level = DeprecationLevel.HIDDEN
+)
+@ExperimentalTestApi
+fun MouseInjectionScope.click(position: Offset = center) = click(position)
+
 /**
- * Click on [position], or on the current mouse position if [position] is
+ * Use [button] to click on [position], or on the current mouse position if [position] is
  * [unspecified][Offset.Unspecified]. The [position] is in the node's local coordinate system,
- * where (0, 0) is the top left corner of the node.
+ * where (0, 0) is the top left corner of the node. The default [button] is the
+ * [primary][MouseButton.Primary] button. There is a small 60ms delay between the press and
+ * release events to have a realistic simulation.
  *
  * @param position The position where to click, in the node's local coordinate system. If
  * omitted, the [center] of the node will be used. If [unspecified][Offset.Unspecified], clicks
  * on the current mouse position.
+ * @param button The button to click with. Uses the [primary][MouseButton.Primary] by default.
  */
 @ExperimentalTestApi
-fun MouseInjectionScope.click(position: Offset = center) {
+fun MouseInjectionScope.click(
+    position: Offset = center,
+    button: MouseButton = MouseButton.Primary
+) {
     if (position.isSpecified) {
         updatePointerTo(position)
     }
-    press(MouseButton.Primary)
+    press(button)
     advanceEventTime(SingleClickDelayMillis)
-    release(MouseButton.Primary)
+    release(button)
 }
 
 /**
@@ -316,70 +336,103 @@
  * on the current mouse position.
  */
 @ExperimentalTestApi
-fun MouseInjectionScope.rightClick(position: Offset = center) {
-    if (position.isSpecified) {
-        updatePointerTo(position)
-    }
-    press(MouseButton.Secondary)
-    advanceEventTime(SingleClickDelayMillis)
-    release(MouseButton.Secondary)
-}
+fun MouseInjectionScope.rightClick(position: Offset = center) =
+    click(position, MouseButton.Secondary)
 
 // The average of min and max is a safe default
 private val ViewConfiguration.defaultDoubleTapDelayMillis: Long
     get() = (doubleTapMinTimeMillis + doubleTapTimeoutMillis) / 2
 
-/**
- * Double-click on [position], or on the current mouse position if [position] is
- * [unspecified][Offset.Unspecified]. The [position] is in the node's local coordinate system,
- * where (0, 0) is the top left corner of the node.
- *
- * @param position The position where to click, in the node's local coordinate system. If
- * omitted, the [center] of the node will be used. If [unspecified][Offset.Unspecified], clicks
- * on the current mouse position.
- */
+@Deprecated(
+    message = "Replaced by an overload that takes a button parameter",
+    replaceWith = ReplaceWith("doubleClick(position)"),
+    level = DeprecationLevel.HIDDEN
+)
 @ExperimentalTestApi
-fun MouseInjectionScope.doubleClick(position: Offset = center) {
-    click(position)
-    advanceEventTime(viewConfiguration.defaultDoubleTapDelayMillis)
-    click(position)
-}
+fun MouseInjectionScope.doubleClick(position: Offset = center) = doubleClick(position)
 
 /**
- * Triple-click on [position], or on the current mouse position if [position] is
+ * Use [button] to double-click on [position], or on the current mouse position if [position] is
  * [unspecified][Offset.Unspecified]. The [position] is in the node's local coordinate system,
- * where (0, 0) is the top left corner of the node.
+ * where (0, 0) is the top left corner of the node. The default [button] is the
+ * [primary][MouseButton.Primary] button.
  *
  * @param position The position where to click, in the node's local coordinate system. If
  * omitted, the [center] of the node will be used. If [unspecified][Offset.Unspecified], clicks
  * on the current mouse position.
+ * @param button The button to click with. Uses the [primary][MouseButton.Primary] by default.
  */
 @ExperimentalTestApi
-fun MouseInjectionScope.tripleClick(position: Offset = center) {
-    click(position)
+fun MouseInjectionScope.doubleClick(
+    position: Offset = center,
+    button: MouseButton = MouseButton.Primary
+) {
+    click(position, button)
     advanceEventTime(viewConfiguration.defaultDoubleTapDelayMillis)
-    click(position)
-    advanceEventTime(viewConfiguration.defaultDoubleTapDelayMillis)
-    click(position)
+    click(position, button)
 }
 
+@Deprecated(
+    message = "Replaced by an overload that takes a button parameter",
+    replaceWith = ReplaceWith("tripleClick(position)"),
+    level = DeprecationLevel.HIDDEN
+)
+@ExperimentalTestApi
+fun MouseInjectionScope.tripleClick(position: Offset = center) = tripleClick(position)
+
 /**
- * Long-click on [position], or on the current mouse position if [position] is
+ * Use [button] to triple-click on [position], or on the current mouse position if [position] is
  * [unspecified][Offset.Unspecified]. The [position] is in the node's local coordinate system,
- * where (0, 0) is the top left corner of the node.
+ * where (0, 0) is the top left corner of the node. The default [button] is the
+ * [primary][MouseButton.Primary] button.
  *
  * @param position The position where to click, in the node's local coordinate system. If
  * omitted, the [center] of the node will be used. If [unspecified][Offset.Unspecified], clicks
  * on the current mouse position.
+ * @param button The button to click with. Uses the [primary][MouseButton.Primary] by default.
  */
 @ExperimentalTestApi
-fun MouseInjectionScope.longClick(position: Offset = center) {
+fun MouseInjectionScope.tripleClick(
+    position: Offset = center,
+    button: MouseButton = MouseButton.Primary
+) {
+    click(position, button)
+    advanceEventTime(viewConfiguration.defaultDoubleTapDelayMillis)
+    click(position, button)
+    advanceEventTime(viewConfiguration.defaultDoubleTapDelayMillis)
+    click(position, button)
+}
+
+@Deprecated(
+    message = "Replaced by an overload that takes a button parameter",
+    replaceWith = ReplaceWith("longClick(position)"),
+    level = DeprecationLevel.HIDDEN
+)
+@ExperimentalTestApi
+fun MouseInjectionScope.longClick(position: Offset = center) = longClick(position)
+
+/**
+ * Use [button] to long-click on [position], or on the current mouse position if [position] is
+ * [unspecified][Offset.Unspecified]. The [position] is in the node's local coordinate system,
+ * where (0, 0) is the top left corner of the node. The default [button] is the
+ * [primary][MouseButton.Primary] button.
+ *
+ * @param position The position where to click, in the node's local coordinate system. If
+ * omitted, the [center] of the node will be used. If [unspecified][Offset.Unspecified], clicks
+ * on the current mouse position.
+ * @param button The button to click with. Uses the [primary][MouseButton.Primary] by default.
+ */
+@ExperimentalTestApi
+fun MouseInjectionScope.longClick(
+    position: Offset = center,
+    button: MouseButton = MouseButton.Primary
+) {
     if (position.isSpecified) {
         updatePointerTo(position)
     }
-    press(MouseButton.Primary)
+    press(button)
     advanceEventTime(viewConfiguration.longPressTimeoutMillis + 100L)
-    release(MouseButton.Primary)
+    release(button)
 }
 
 /**
@@ -389,6 +442,9 @@
  * a different position. The [position] is in the node's local coordinate system, where (0, 0) is
  * the top left corner of the node.
  *
+ * Example of moving the mouse along a line:
+ * @sample androidx.compose.ui.test.samples.mouseInputAnimateTo
+ *
  * @param position The position where to move the mouse to, in the node's local coordinate system
  * @param durationMillis The duration of the gesture. By default 300 milliseconds.
  */
@@ -429,6 +485,9 @@
  * path, `curve(0)`, if it is not already there. The positions defined by the [curve] are in the
  * node's local coordinate system, where (0, 0) is the top left corner of the node.
  *
+ * Example of moving the mouse along a curve:
+ * @sample androidx.compose.ui.test.samples.mouseInputAnimateAlong
+ *
  * @param curve The function that defines the position of the mouse over time for this gesture,
  * in the node's local coordinate system.
  * @param durationMillis The duration of the gesture. By default 300 milliseconds.
@@ -461,29 +520,42 @@
     }
 }
 
+@Deprecated(
+    message = "Replaced by an overload that takes a button parameter",
+    replaceWith = ReplaceWith("dragAndDrop(start, end, durationMillis = durationMillis)"),
+    level = DeprecationLevel.HIDDEN
+)
+@ExperimentalTestApi
+fun MouseInjectionScope.dragAndDrop(
+    start: Offset,
+    end: Offset,
+    durationMillis: Long = DefaultMouseGestureDurationMillis
+) = dragAndDrop(start, end, durationMillis = durationMillis)
+
 /**
- * Drag and drop something from [start] to [end] in [durationMillis] milliseconds. This gesture
- * uses the primary mouse button to drag with, and does not reset any mouse buttons prior to
- * starting the gesture. The mouse position is [updated][MouseInjectionScope.updatePointerTo] to
- * the start position before starting the gesture. The positions defined by the [start] and [end]
- * are in the node's local coordinate system, where (0, 0) is the top left corner of the node.
+ * Use [button] to drag and drop something from [start] to [end] in [durationMillis] milliseconds.
+ * The mouse position is [updated][MouseInjectionScope.updatePointerTo] to the start position
+ * before starting the gesture. The positions defined by the [start] and [end] are in the node's
+ * local coordinate system, where (0, 0) is the top left corner of the node.
  *
  * @param start The position where to press the primary mouse button and initiate the drag, in
  * the node's local coordinate system.
  * @param end The position where to release the primary mouse button and end the drag, in the
  * node's local coordinate system.
+ * @param button The button to drag with. Uses the [primary][MouseButton.Primary] by default.
  * @param durationMillis The duration of the gesture. By default 300 milliseconds.
  */
 @ExperimentalTestApi
 fun MouseInjectionScope.dragAndDrop(
     start: Offset,
     end: Offset,
+    button: MouseButton = MouseButton.Primary,
     durationMillis: Long = DefaultMouseGestureDurationMillis
 ) {
     updatePointerTo(start)
-    press(MouseButton.Primary)
+    press(button)
     animateTo(end, durationMillis)
-    release(MouseButton.Primary)
+    release(button)
 }
 
 /**
@@ -494,6 +566,9 @@
  * bottom of a column, or at the end of a row), negative values correspond to scrolling backward
  * (new content appears at the top of a column, or at the start of a row).
  *
+ * Example of a horizontal smooth scroll:
+ * @sample androidx.compose.ui.test.samples.mouseInputSmoothScroll
+ *
  * @param scrollAmount The total delta to scroll the [scrollWheel] by
  * @param durationMillis The duration of the gesture. By default 300 milliseconds.
  * @param scrollWheel Which scroll wheel will be rotated. By default [ScrollWheel.Vertical].
diff --git a/compose/ui/ui-tooling/build.gradle b/compose/ui/ui-tooling/build.gradle
index cb5c42f..98f9161 100644
--- a/compose/ui/ui-tooling/build.gradle
+++ b/compose/ui/ui-tooling/build.gradle
@@ -138,7 +138,7 @@
     description = "Compose tooling library. This library exposes information to our tools for better IDE support."
     legacyDisableKotlinStrictApiMode = true
     samples(project(":compose:animation:animation:animation-samples"))
-    // samples(project(":compose:animation:animation-core:animation-core-samples"))TODO(b/318840087)
+    // samples(project(":compose:animation:animation-core:animation-core-samples")) TODO(b/318840087)
 }
 
 android {
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/AndroidLayoutDrawTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/AndroidLayoutDrawTest.kt
index ce24620..2ca13db 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/AndroidLayoutDrawTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/AndroidLayoutDrawTest.kt
@@ -391,7 +391,7 @@
                 Executors.newFixedThreadPool(3).asCoroutineDispatcher()
             ),
             ViewLayerContainer(activity),
-            {},
+            { _, _ -> },
             {}).apply {
             val scope = ReusableGraphicsLayerScope()
             scope.cameraDistance = cameraDistance
@@ -431,7 +431,7 @@
                 Executors.newFixedThreadPool(3).asCoroutineDispatcher()
             ),
             ViewLayerContainer(activity),
-            {},
+            { _, _ -> },
             {}
         ).apply {
             val scope = ReusableGraphicsLayerScope()
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 a2ae451..868bf43 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
@@ -48,7 +48,6 @@
 import androidx.test.filters.SdkSuppress
 import com.google.common.truth.Truth.assertThat
 import org.junit.After
-import org.junit.Ignore
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -259,7 +258,9 @@
             .assertPixels(expectedSize) { Color.Red }
     }
 
-    @Ignore("remove annotation when Modifier.graphicsLayer() will use the same layer mechanism")
+    // TODO remove sdk suppress when we start using new layers as Modifier.graphicsLayer() on
+    //  older versions.
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.Q)
     @Test
     fun keepDrawingNestedLayers_graphicsLayerModifier() {
         rule.setContent {
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/pointer/AndroidPointerInputTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/pointer/AndroidPointerInputTest.kt
index b20ed84..e9bd13b 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/pointer/AndroidPointerInputTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/pointer/AndroidPointerInputTest.kt
@@ -92,7 +92,6 @@
 import org.junit.Assert.assertFalse
 import org.junit.Assert.assertTrue
 import org.junit.Before
-import org.junit.Ignore
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -537,13 +536,7 @@
         }
     }
 
-    // Currently ignored because it fails when run via command line.  Runs successfully in Android
-    // Studio.
     @Test
-    // TODO(b/158099918): For some reason, this test fails when run from command line but passes
-    //  when run from Android Studio.  This seems to be caused by b/158099918.  Once that is
-    //  fixed, @Ignore can be removed.
-    @Ignore
     fun dispatchTouchEvent_throughLayersOfAndroidAndCompose_hitsChildWithCorrectCoords() {
 
         // Arrange
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 ae09d76..d1b40df 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
@@ -4167,7 +4167,7 @@
     }
 
     override fun createLayer(
-        drawBlock: (Canvas) -> Unit,
+        drawBlock: (Canvas, GraphicsLayer?) -> Unit,
         invalidateParentLayer: () -> Unit,
         explicitLayer: GraphicsLayer?
     ): OwnedLayer {
@@ -4188,7 +4188,7 @@
             }
 
             override fun drawLayer(canvas: Canvas, parentLayer: GraphicsLayer?) {
-                drawBlock(canvas)
+                drawBlock(canvas, parentLayer)
             }
 
             override fun updateDisplayList() {
@@ -4204,7 +4204,7 @@
             }
 
             override fun reuseLayer(
-                drawBlock: (Canvas) -> Unit,
+                drawBlock: (Canvas, GraphicsLayer?) -> Unit,
                 invalidateParentLayer: () -> Unit
             ) {
             }
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/pointer/PointerInputEventProcessorTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/pointer/PointerInputEventProcessorTest.kt
index 80c407a..5e072bd 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/pointer/PointerInputEventProcessorTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/pointer/PointerInputEventProcessorTest.kt
@@ -3421,7 +3421,7 @@
     }
 
     override fun createLayer(
-        drawBlock: (Canvas) -> Unit,
+        drawBlock: (Canvas, GraphicsLayer?) -> Unit,
         invalidateParentLayer: () -> Unit,
         explicitLayer: GraphicsLayer?
     ): OwnedLayer {
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/pointer/SuspendingPointerInputFilterTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/pointer/SuspendingPointerInputFilterTest.kt
index d015749..84b683c 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/pointer/SuspendingPointerInputFilterTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/pointer/SuspendingPointerInputFilterTest.kt
@@ -25,6 +25,7 @@
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.rememberUpdatedState
 import androidx.compose.runtime.setValue
+import androidx.compose.testutils.assertModifierIsPure
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.node.DelegatingNode
@@ -35,6 +36,7 @@
 import androidx.compose.ui.test.assertHeightIsEqualTo
 import androidx.compose.ui.test.junit4.createComposeRule
 import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.performClick
 import androidx.compose.ui.test.performTouchInput
 import androidx.compose.ui.unit.IntSize
 import androidx.compose.ui.unit.dp
@@ -45,6 +47,7 @@
 import com.google.common.truth.Truth.assertThat
 import java.util.concurrent.CountDownLatch
 import java.util.concurrent.TimeUnit
+import kotlinx.coroutines.CancellationException
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.channels.Channel
 import kotlinx.coroutines.flow.map
@@ -597,6 +600,28 @@
     }
 
     @Test
+    @SmallTest
+    fun testEquality_key() {
+        val block: suspend PointerInputScope.() -> Unit = {}
+
+        assertModifierIsPure { toggleInput ->
+            Modifier.pointerInput(toggleInput, block = block)
+        }
+    }
+
+    @Test
+    @SmallTest
+    fun testEquality_block() {
+        val block1: suspend PointerInputScope.() -> Unit = {}
+        val block2: suspend PointerInputScope.() -> Unit = {}
+
+        assertModifierIsPure { toggleInput ->
+            val block = if (toggleInput) block1 else block2
+            Modifier.pointerInput(Unit, block = block)
+        }
+    }
+
+    @Test
     @MediumTest
     fun testRestartPointerInputWithTouchEvent() {
         val emitter = PointerInputChangeEmitter()
@@ -931,34 +956,145 @@
     }
 
     @Test
-    fun pointerInput_badStartingSinglePointer_composeIgnores() {
-        val events = mutableListOf<PointerEventType>()
-        val tag = "input rect"
+    @MediumTest
+    fun testUpdatingKey1RestartsPointerInput() {
+        val tag = "box"
+        var key1 by mutableStateOf(false)
+        var cancelled = false
+
         rule.setContent {
             Box(
-                Modifier.fillMaxSize()
+                Modifier
                     .testTag(tag)
-                    .pointerInput(Unit) {
-                        awaitPointerEventScope {
-                            while (true) {
-                                val event = awaitPointerEvent()
-                                events += event.type
-                            }
+                    .fillMaxSize()
+                    .pointerInput(key1 = key1) {
+                        try {
+                            suspendCancellableCoroutine<Unit> {}
+                        } catch (e: CancellationException) {
+                            cancelled = true
                         }
                     }
             )
         }
 
-        rule.onNodeWithTag(tag).performTouchInput {
-            // Starts gestures with bad data. Because the bad x/y are part of the
-            // MotionEvent, Compose won't process the entire event or any following events
-            // until the bad data is removed.
-            down(Offset(Float.NaN, Float.NaN)) // Compose ignores
-            moveBy(0, Offset(10f, 10f)) // Compose ignores because first was invalid
-            up() // Compose ignores because first was invalid
+        rule.onNodeWithTag(tag).performClick()
+
+        rule.runOnIdle {
+            assertThat(cancelled).isFalse()
         }
-        assertThat(events).hasSize(0)
-        assertThat(events).containsExactly()
+
+        key1 = true
+
+        rule.runOnIdle {
+            assertThat(cancelled).isTrue()
+        }
+    }
+
+    @Test
+    @MediumTest
+    fun testUpdatingKey2RestartsPointerInput() {
+        val tag = "box"
+        var key2 by mutableStateOf(false)
+        var cancelled = false
+
+        rule.setContent {
+            Box(
+                Modifier
+                    .testTag(tag)
+                    .fillMaxSize()
+                    .pointerInput(key1 = Unit, key2 = key2) {
+                        try {
+                            suspendCancellableCoroutine<Unit> {}
+                        } catch (e: CancellationException) {
+                            cancelled = true
+                        }
+                    }
+            )
+        }
+
+        rule.onNodeWithTag(tag).performClick()
+
+        rule.runOnIdle {
+            assertThat(cancelled).isFalse()
+        }
+
+        key2 = true
+
+        rule.runOnIdle {
+            assertThat(cancelled).isTrue()
+        }
+    }
+
+    @Test
+    @MediumTest
+    fun testUpdatingKeysRestartsPointerInput() {
+        val tag = "box"
+        var keys by mutableStateOf(arrayOf(false))
+        var cancelled = false
+
+        rule.setContent {
+            Box(
+                Modifier
+                    .testTag(tag)
+                    .fillMaxSize()
+                    .pointerInput(keys = keys) {
+                        try {
+                            suspendCancellableCoroutine<Unit> {}
+                        } catch (e: CancellationException) {
+                            cancelled = true
+                        }
+                    }
+            )
+        }
+
+        rule.onNodeWithTag(tag).performClick()
+
+        rule.runOnIdle {
+            assertThat(cancelled).isFalse()
+        }
+
+        keys = arrayOf(true)
+
+        rule.runOnIdle {
+            assertThat(cancelled).isTrue()
+        }
+    }
+
+    @Test
+    @MediumTest
+    fun testUpdatingBlockDoesNotRestartPointerInput() {
+        val tag = "box"
+        var cancelled = false
+        val lambda1: suspend PointerInputScope.() -> Unit = {
+            try {
+                suspendCancellableCoroutine<Unit> {}
+            } catch (e: CancellationException) {
+                cancelled = true
+            }
+        }
+        val lambda2: suspend PointerInputScope.() -> Unit = {}
+        var block by mutableStateOf(lambda1)
+
+        rule.setContent {
+            Box(
+                Modifier
+                    .testTag(tag)
+                    .fillMaxSize()
+                    .pointerInput(key1 = Unit, key2 = Unit, block = block)
+            )
+        }
+
+        rule.onNodeWithTag(tag).performClick()
+
+        rule.runOnIdle {
+            assertThat(cancelled).isFalse()
+        }
+
+        block = lambda2
+
+        rule.runOnIdle {
+            assertThat(cancelled).isFalse()
+        }
     }
 
     // Tests pointerInput with bad pointer data
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/Helpers.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/Helpers.kt
index 316e860..e8557cf 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/Helpers.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/Helpers.kt
@@ -211,7 +211,7 @@
         get() = TODO("Not yet implemented")
 
     override fun createLayer(
-        drawBlock: (Canvas) -> Unit,
+        drawBlock: (canvas: Canvas, parentLayer: GraphicsLayer?) -> Unit,
         invalidateParentLayer: () -> Unit,
         explicitLayer: GraphicsLayer?
     ) = createLayer()
@@ -601,7 +601,7 @@
     }
 
     override fun reuseLayer(
-        drawBlock: (Canvas) -> Unit,
+        drawBlock: (canvas: Canvas, parentLayer: GraphicsLayer?) -> Unit,
         invalidateParentLayer: () -> Unit
     ) {
     }
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/node/NodeChainTester.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/node/NodeChainTester.kt
index 0b4ff31..c2ec417 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/node/NodeChainTester.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/node/NodeChainTester.kt
@@ -484,7 +484,7 @@
         TODO("Not yet implemented")
     }
     override fun createLayer(
-        drawBlock: (Canvas) -> Unit,
+        drawBlock: (Canvas, GraphicsLayer?) -> Unit,
         invalidateParentLayer: () -> Unit,
         explicitLayer: GraphicsLayer?
     ): OwnedLayer {
@@ -495,7 +495,7 @@
             override fun move(position: IntOffset) {}
             override fun resize(size: IntSize) {}
             override fun drawLayer(canvas: Canvas, parentLayer: GraphicsLayer?) {
-                drawBlock(canvas)
+                drawBlock(canvas, parentLayer)
             }
             override fun updateDisplayList() {}
             override fun invalidate() { invalidatedLayers.add(this) }
@@ -505,7 +505,7 @@
             override fun inverseTransform(matrix: Matrix) { matrix.timesAssign(inverseTransform) }
             override fun mapOffset(point: Offset, inverse: Boolean) = point
             override fun reuseLayer(
-                drawBlock: (Canvas) -> Unit,
+                drawBlock: (Canvas, GraphicsLayer?) -> Unit,
                 invalidateParentLayer: () -> Unit
             ) {}
             override fun updateLayerProperties(
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/node/NodeChainTests.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/node/NodeChainTests.kt
index 6d74a3a..99d5b96 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/node/NodeChainTests.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/node/NodeChainTests.kt
@@ -50,8 +50,8 @@
         val a = AttachedStateDebuggerNode()
         val b = AttachedStateDebuggerNode()
         chainTester()
-            .withModifierNodes(a, b)
             .attach()
+            .withModifierNodes(a, b)
             .validateAttached()
 
         check(a.localIsAttached)
@@ -67,8 +67,8 @@
         val c = object : NodeModifierElementNode(AttachedStateDebuggerNode()) {}
 
         chainTester()
-            .withModifiers(a)
             .attach()
+            .withModifiers(a)
             .validateAttached()
             .withModifiers(c, a, b)
             .validateAttached()
@@ -196,8 +196,8 @@
         val a = modifierA()
         val b = modifierB()
         val modifierInfo = chainTester()
-            .withModifiers(a, b)
             .attach()
+            .withModifiers(a, b)
             .chain
             .getModifierInfo()
 
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/scrollcapture/ScrollCaptureDrawTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/scrollcapture/ScrollCaptureDrawTest.kt
index 17d7a57..fcaecc7 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/scrollcapture/ScrollCaptureDrawTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/scrollcapture/ScrollCaptureDrawTest.kt
@@ -34,14 +34,14 @@
 import androidx.compose.ui.test.junit4.createComposeRule
 import androidx.core.graphics.applyCanvas
 import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.MediumTest
+import androidx.test.filters.LargeTest
 import androidx.test.filters.SdkSuppress
 import com.google.common.truth.Truth.assertThat
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 
-@MediumTest
+@LargeTest
 @RunWith(AndroidJUnit4::class)
 @SdkSuppress(minSdkVersion = 31)
 class ScrollCaptureDrawTest {
@@ -186,13 +186,99 @@
         assertThat(scrollState.value).isEqualTo(5)
     }
 
+    @Test
+    fun capture_drawsScrollContents_fromTop_withCaptureHeightFullViewport_reverseScrolling() =
+        captureTester.runTest {
+            val scrollState = ScrollState(0)
+            captureTester.setContent {
+                TestContent(scrollState, reverseScrolling = true)
+            }
+            val target = captureTester.findCaptureTargets().single()
+            val bitmaps = captureTester.captureBitmapsVertically(target, captureHeight = 10)
+            assertThat(bitmaps).hasSize(3)
+            bitmaps.joinVerticallyToBitmap().use { joined ->
+                joined.assertRect(Rect(0, 0, 10, 9), Color.Red)
+                joined.assertRect(Rect(0, 10, 10, 18), Color.Blue)
+                joined.assertRect(Rect(0, 19, 10, 27), Color.Green)
+            }
+        }
+
+    @Test
+    fun capture_drawsScrollContents_fromMiddle_withCaptureHeightFullViewport_reverseScrolling() =
+        captureTester.runTest {
+            val scrollState = ScrollState(0)
+            captureTester.setContent {
+                TestContent(scrollState, reverseScrolling = true)
+            }
+
+            scrollState.scrollTo(scrollState.maxValue / 2)
+
+            val target = captureTester.findCaptureTargets().single()
+            val bitmaps = captureTester.captureBitmapsVertically(target, captureHeight = 10)
+            assertThat(bitmaps).hasSize(3)
+            bitmaps.joinVerticallyToBitmap().use { joined ->
+                joined.assertRect(Rect(0, 0, 10, 9), Color.Red)
+                joined.assertRect(Rect(0, 10, 10, 18), Color.Blue)
+                joined.assertRect(Rect(0, 19, 10, 27), Color.Green)
+            }
+        }
+
+    @Test
+    fun capture_drawsScrollContents_fromBottom_withCaptureHeightFullViewport_reverseScrolling() =
+        captureTester.runTest {
+            val scrollState = ScrollState(0)
+            captureTester.setContent {
+                TestContent(scrollState, reverseScrolling = true)
+            }
+
+            scrollState.scrollTo(scrollState.maxValue)
+
+            val target = captureTester.findCaptureTargets().single()
+            val bitmaps = captureTester.captureBitmapsVertically(target, captureHeight = 10)
+            assertThat(bitmaps).hasSize(3)
+            bitmaps.joinVerticallyToBitmap().use { joined ->
+                joined.assertRect(Rect(0, 0, 10, 9), Color.Red)
+                joined.assertRect(Rect(0, 10, 10, 18), Color.Blue)
+                joined.assertRect(Rect(0, 19, 10, 27), Color.Green)
+            }
+        }
+
+    @Test
+    fun capture_resetsScrollPosition_from0_reverseScrolling() = captureTester.runTest {
+        val scrollState = ScrollState(0)
+        captureTester.setContent {
+            TestContent(scrollState, reverseScrolling = true)
+        }
+        val target = captureTester.findCaptureTargets().single()
+        val bitmaps = captureTester.captureBitmapsVertically(target, captureHeight = 10)
+        bitmaps.forEach { it.recycle() }
+        rule.awaitIdle()
+        assertThat(scrollState.value).isEqualTo(0)
+    }
+
+    @Test
+    fun capture_resetsScrollPosition_fromNonZero_reverseScrolling() = captureTester.runTest {
+        val scrollState = ScrollState(5)
+        captureTester.setContent {
+            TestContent(scrollState, reverseScrolling = true)
+        }
+        val target = captureTester.findCaptureTargets().single()
+        val bitmaps = captureTester.captureBitmapsVertically(target, captureHeight = 10)
+        bitmaps.forEach { it.recycle() }
+        rule.awaitIdle()
+        assertThat(scrollState.value).isEqualTo(5)
+    }
+
     @Composable
-    private fun TestContent(scrollState: ScrollState) {
+    private fun TestContent(
+        scrollState: ScrollState,
+        reverseScrolling: Boolean = false,
+    ) {
         with(LocalDensity.current) {
             Column(
                 Modifier
                     .size(10.toDp())
-                    .verticalScroll(scrollState)
+                    .verticalScroll(scrollState, reverseScrolling = reverseScrolling)
             ) {
                 Box(
                     Modifier
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/scrollcapture/ScrollCaptureTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/scrollcapture/ScrollCaptureTest.kt
index f805517..9232f12 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/scrollcapture/ScrollCaptureTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/scrollcapture/ScrollCaptureTest.kt
@@ -372,6 +372,56 @@
     }
 
     @Test
+    fun callbackOnImageCapture_scrollsBackwardsThenForwards_reverseScrolling() =
+        captureTester.runTest {
+            expectingScrolls(rule) {
+                val size = 10
+                val captureHeight = size / 2
+                captureTester.setContent {
+                    TestVerticalScrollable(
+                        reverseScrolling = true,
+                        size = size,
+                        // Can't be a reference, see https://youtrack.jetbrains.com/issue/KT-49665
+                        onScrollByOffset = { respondToScrollExpectation(it) }
+                    )
+                }
+
+                val target = captureTester.findCaptureTargets().single()
+                captureTester.capture(target, captureHeight) {
+                    // First request is at origin, no scrolling required.
+                    assertThat(performCaptureDiscardingBitmap()).isEqualTo(Rect(0, 0, 10, 5))
+                    assertNoPendingScrollRequests()
+
+                    // Back one half-page, but only respond to part of it.
+                    expectScrollRequest(Offset(0f, 5f), consume = Offset(0f, 4f))
+                    shiftWindowBy(-5)
+                    assertThat(performCaptureDiscardingBitmap()).isEqualTo(Rect(0, -4, 10, 0))
+
+                    // Forward one half-page – already in viewport, no scrolling required.
+                    shiftWindowBy(5)
+                    assertThat(performCaptureDiscardingBitmap()).isEqualTo(Rect(0, 0, 10, 5))
+                    assertNoPendingScrollRequests()
+
+                    // Forward another half-page. This time we need to scroll.
+                    expectScrollRequest(Offset(0f, -4f))
+                    shiftWindowBy(5)
+                    assertThat(performCaptureDiscardingBitmap()).isEqualTo(Rect(0, 5, 10, 10))
+
+                    // Forward another half-page, scroll again so now we're past the original
+                    // viewport.
+                    expectScrollRequest(Offset(0f, -5f))
+                    shiftWindowBy(5)
+                    assertThat(performCaptureDiscardingBitmap()).isEqualTo(Rect(0, 10, 10, 15))
+
+                    // When capture ends expect one last scroll request to reset to original offset.
+                    // Note that this request will be made _after_ this capture{} lambda returns.
+                    expectScrollRequest(Offset(0f, 5f))
+                }
+                assertNoPendingScrollRequests()
+            }
+        }
+
+    @Test
     fun captureSession_setsScrollCaptureInProgress_inSameComposition() = captureTester.runTest {
         var isScrollCaptureInProgressValue = false
         captureTester.setContent {
@@ -429,6 +479,7 @@
         size: Int = 10,
         maxValue: Float = 1f,
         onScrollByOffset: suspend (Offset) -> Offset = { Offset.Zero },
+        reverseScrolling: Boolean = false,
         content: (@Composable () -> Unit)? = null
     ) {
         with(LocalDensity.current) {
@@ -437,6 +488,7 @@
                 ScrollAxisRange(
                     value = { 0f },
                     maxValue = { updatedMaxValue },
+                    reverseScrolling = reverseScrolling,
                 )
             }
             Box(
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/AndroidViewTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/AndroidViewTest.kt
index 3e56cd1..d8bee52 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/AndroidViewTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/AndroidViewTest.kt
@@ -179,9 +179,8 @@
                         .inflate(R.layout.test_multiple_invalidation_layout, null)
                     customView = view.findViewById<InvalidatedTextView>(R.id.custom_draw_view)
                     customView!!.timesToInvalidate = timesToInvalidate
-                    view.viewTreeObserver?.addOnPreDrawListener {
+                    customView!!.onDraw = {
                         ++drawCount
-                        true
                     }
                     view
                 })
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/InvalidatedTextView.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/InvalidatedTextView.kt
index 4b2583a1..08276eb 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/InvalidatedTextView.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/InvalidatedTextView.kt
@@ -31,6 +31,7 @@
 class InvalidatedTextView : TextView {
     var timesDrawn: Int = 0
     var timesToInvalidate: Int = 0
+    var onDraw: () -> Unit = {}
 
     constructor(context: Context?) : super(context)
     constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
@@ -46,5 +47,6 @@
         }
         super.draw(canvas)
         ++timesDrawn
+        onDraw()
     }
 }
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.android.kt
index 5e9e671..4013394 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.android.kt
@@ -175,6 +175,7 @@
 import androidx.compose.ui.platform.coreshims.ViewCompatShims
 import androidx.compose.ui.scrollcapture.ScrollCapture
 import androidx.compose.ui.semantics.EmptySemanticsElement
+import androidx.compose.ui.semantics.EmptySemanticsModifier
 import androidx.compose.ui.semantics.SemanticsOwner
 import androidx.compose.ui.semantics.findClosestParentNode
 import androidx.compose.ui.text.font.Font
@@ -248,7 +249,8 @@
     override var density by mutableStateOf(Density(context), referentialEqualityPolicy())
         private set
 
-    private val semanticsModifier = EmptySemanticsElement
+    private val rootSemanticsNode = EmptySemanticsModifier()
+    private val semanticsModifier = EmptySemanticsElement(rootSemanticsNode)
 
     override val focusOwner: FocusOwner = FocusOwnerImpl(
         onRequestApplyChangesListener = ::registerOnEndApplyChangesListener,
@@ -408,7 +410,7 @@
 
     override val rootForTest: RootForTest = this
 
-    override val semanticsOwner: SemanticsOwner = SemanticsOwner(root)
+    override val semanticsOwner: SemanticsOwner = SemanticsOwner(root, rootSemanticsNode)
     private val composeAccessibilityDelegate =
         AndroidComposeViewAccessibilityDelegateCompat(this)
     internal var contentCaptureManager = AndroidContentCaptureManager(
@@ -1404,12 +1406,18 @@
     }
 
     override fun createLayer(
-        drawBlock: (Canvas) -> Unit,
+        drawBlock: (canvas: Canvas, parentLayer: GraphicsLayer?) -> Unit,
         invalidateParentLayer: () -> Unit,
         explicitLayer: GraphicsLayer?
     ): OwnedLayer {
         if (explicitLayer != null) {
-            return GraphicsLayerOwnerLayer(explicitLayer, this, drawBlock, invalidateParentLayer)
+            return GraphicsLayerOwnerLayer(
+                graphicsLayer = explicitLayer,
+                context = null,
+                ownerView = this,
+                drawBlock = drawBlock,
+                invalidateParentLayer = invalidateParentLayer
+            )
         }
         // First try the layer cache
         val layer = layerCache.pop()
@@ -1423,6 +1431,15 @@
         // the ViewLayer implementation. We'll try even on on P devices, but it will fail
         // until ART allows things on the unsupported list on P.
         if (isHardwareAccelerated && SDK_INT >= M && isRenderNodeCompatible) {
+            if (SDK_INT >= Q) {
+                return GraphicsLayerOwnerLayer(
+                    graphicsLayer = graphicsContext.createGraphicsLayer(),
+                    context = graphicsContext,
+                    ownerView = this,
+                    drawBlock = drawBlock,
+                    invalidateParentLayer = invalidateParentLayer
+                )
+            }
             try {
                 return RenderNodeLayer(
                     this,
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 cecabef..12737fd 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
@@ -16,18 +16,30 @@
 
 package androidx.compose.ui.platform
 
+import android.os.Build
 import androidx.compose.ui.geometry.MutableRect
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.geometry.isUnspecified
 import androidx.compose.ui.graphics.Canvas
+import androidx.compose.ui.graphics.CompositingStrategy as OldCompositingStrategy
+import androidx.compose.ui.graphics.Fields
+import androidx.compose.ui.graphics.GraphicsContext
 import androidx.compose.ui.graphics.Matrix
+import androidx.compose.ui.graphics.Outline
+import androidx.compose.ui.graphics.Paint
 import androidx.compose.ui.graphics.Path
+import androidx.compose.ui.graphics.RectangleShape
 import androidx.compose.ui.graphics.ReusableGraphicsLayerScope
+import androidx.compose.ui.graphics.Shape
+import androidx.compose.ui.graphics.TransformOrigin
 import androidx.compose.ui.graphics.drawscope.CanvasDrawScope
 import androidx.compose.ui.graphics.drawscope.draw
 import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
+import androidx.compose.ui.graphics.layer.CompositingStrategy
 import androidx.compose.ui.graphics.layer.GraphicsLayer
 import androidx.compose.ui.graphics.layer.drawLayer
+import androidx.compose.ui.graphics.layer.setOutline
+import androidx.compose.ui.graphics.nativeCanvas
 import androidx.compose.ui.internal.throwIllegalStateException
 import androidx.compose.ui.layout.GraphicLayerInfo
 import androidx.compose.ui.node.OwnedLayer
@@ -41,18 +53,21 @@
 
 internal class GraphicsLayerOwnerLayer(
     private val graphicsLayer: GraphicsLayer,
+    // when we have a context it means the object is created by us and we need to release it
+    private val context: GraphicsContext?,
     private val ownerView: AndroidComposeView,
-    drawBlock: (Canvas) -> Unit,
+    drawBlock: (canvas: Canvas, parentLayer: GraphicsLayer?) -> Unit,
     invalidateParentLayer: () -> Unit
 ) : OwnedLayer, GraphicLayerInfo {
-    private var drawBlock: ((Canvas) -> Unit)? = drawBlock
+    private var drawBlock: ((canvas: Canvas, parentLayer: GraphicsLayer?) -> Unit)? = drawBlock
     private var invalidateParentLayer: (() -> Unit)? = invalidateParentLayer
 
-    private var size: IntSize = IntSize.Zero
+    private var size: IntSize = IntSize(Int.MAX_VALUE, Int.MAX_VALUE)
     private var isDestroyed = false
     private val matrixCache = Matrix()
+    private var inverseMatrixCache: Matrix? = null
 
-    private var isDirty = true
+    private var isDirty = false
         set(value) {
             if (value != field) {
                 field = value
@@ -63,19 +78,127 @@
     private var density = Density(1f)
     private var layoutDirection = LayoutDirection.Ltr
     private val scope = CanvasDrawScope()
-
-    private var tmpTouchPointPath: Path? = null
-    private var tmpOpPath: Path? = null
+    private var mutatedFields: Int = 0
+    private var transformOrigin: TransformOrigin = TransformOrigin.Center
+    private var shape: Shape = RectangleShape
+    private var tmpPath: Path? = null
+    /**
+     * Optional paint used when the RenderNode is rendered on a software backed
+     * canvas and is somewhat transparent (i.e. alpha less than 1.0f)
+     */
+    private var softwareLayerPaint: Paint? = null
 
     override fun updateLayerProperties(
         scope: ReusableGraphicsLayerScope,
         layoutDirection: LayoutDirection,
         density: Density,
     ) {
-        throwIllegalStateException(
-            "Current apis doesn't allow for both GraphicsLayer and GraphicsLayerScope to be " +
-                "used together"
-        )
+        var maybeChangedFields = scope.mutatedFields or mutatedFields
+        if (this.layoutDirection != layoutDirection || this.density != density) {
+            this.layoutDirection = layoutDirection
+            this.density = density
+            maybeChangedFields = maybeChangedFields or Fields.Shape
+        }
+        if (maybeChangedFields and Fields.TransformOrigin != 0) {
+            this.transformOrigin = scope.transformOrigin
+        }
+        if (maybeChangedFields and Fields.ScaleX != 0) {
+            graphicsLayer.scaleX = scope.scaleX
+        }
+        if (maybeChangedFields and Fields.ScaleY != 0) {
+            graphicsLayer.scaleY = scope.scaleY
+        }
+        if (maybeChangedFields and Fields.Alpha != 0) {
+            graphicsLayer.alpha = scope.alpha
+        }
+        if (maybeChangedFields and Fields.TranslationX != 0) {
+            graphicsLayer.translationX = scope.translationX
+        }
+        if (maybeChangedFields and Fields.TranslationY != 0) {
+            graphicsLayer.translationY = scope.translationY
+        }
+        if (maybeChangedFields and Fields.ShadowElevation != 0) {
+            graphicsLayer.shadowElevation = scope.shadowElevation
+            // TODO We should somehow move it into the android specific GraphicsLayer
+            //  implementation where the code enabling Z is located. It is not yet clear how we
+            //  can trigger the full layer invalidation from there when such changes happen, but
+            //  seems like we have to figure it out. This issue is tracked in b/333862760
+            if (scope.shadowElevation > 0f && !drawnWithEnabledZ) {
+                // we need to redraw with enabling Z
+                invalidateParentLayer?.invoke()
+            }
+        }
+        if (maybeChangedFields and Fields.AmbientShadowColor != 0) {
+            graphicsLayer.ambientShadowColor = scope.ambientShadowColor
+        }
+        if (maybeChangedFields and Fields.SpotShadowColor != 0) {
+            graphicsLayer.spotShadowColor = scope.spotShadowColor
+        }
+        if (maybeChangedFields and Fields.RotationZ != 0) {
+            graphicsLayer.rotationZ = scope.rotationZ
+        }
+        if (maybeChangedFields and Fields.RotationX != 0) {
+            graphicsLayer.rotationX = scope.rotationX
+        }
+        if (maybeChangedFields and Fields.RotationY != 0) {
+            graphicsLayer.rotationY = scope.rotationY
+        }
+        if (maybeChangedFields and Fields.CameraDistance != 0) {
+            graphicsLayer.cameraDistance = scope.cameraDistance
+        }
+        if (maybeChangedFields and Fields.TransformOrigin != 0) {
+            graphicsLayer.pivotOffset = Offset(
+                transformOrigin.pivotFractionX * size.width,
+                transformOrigin.pivotFractionY * size.height
+            )
+        }
+        if (maybeChangedFields and Fields.Shape != 0) {
+            this.shape = scope.shape
+            updateOutline()
+        }
+        if (maybeChangedFields and Fields.Clip != 0) {
+            graphicsLayer.clip = scope.clip
+        }
+        if (maybeChangedFields and Fields.RenderEffect != 0) {
+            graphicsLayer.renderEffect = scope.renderEffect
+        }
+        if (maybeChangedFields and Fields.CompositingStrategy != 0) {
+            graphicsLayer.compositingStrategy = when (scope.compositingStrategy) {
+                OldCompositingStrategy.Auto -> CompositingStrategy.Auto
+                OldCompositingStrategy.Offscreen -> CompositingStrategy.Offscreen
+                OldCompositingStrategy.ModulateAlpha -> CompositingStrategy.ModulateAlpha
+                else -> throw IllegalStateException("Not supported composition strategy")
+            }
+        }
+
+        mutatedFields = scope.mutatedFields
+        if (maybeChangedFields != 0) {
+            triggerRepaint()
+        }
+    }
+
+    // TODO: GraphicsLayer api should be doing it on its own every time any layer property
+    //  has been updated. This issue is tracked in b/329417380.
+    private fun triggerRepaint() {
+        // onDescendantInvalidated is only supported on O+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+            WrapperRenderNodeLayerHelperMethods.onDescendantInvalidated(ownerView)
+        } else {
+            ownerView.invalidate()
+        }
+    }
+
+    private fun updateOutline() {
+        val outline = shape.createOutline(size.toSize(), layoutDirection, density)
+        graphicsLayer.setOutline(outline)
+        if (outline is Outline.Generic && Build.VERSION.SDK_INT < 33) {
+            // before 33 many of the paths are not clipping by rendernode. instead we have to
+            // manually clip on a canvas. it means we have redraw the parent layer when it changes
+            // TODO We should somehow move it into the android specific GraphicsLayer
+            //  implementation where the clipping logic is located.
+            //  This issue is tracked in b/333862760
+            invalidateParentLayer?.invoke()
+        }
     }
 
     override fun isInLayer(position: Offset): Boolean {
@@ -83,8 +206,7 @@
         val y = position.y
 
         if (graphicsLayer.clip) {
-            val outline = graphicsLayer.outline
-            return isInOutline(outline, x, y, tmpTouchPointPath, tmpOpPath)
+            return isInOutline(graphicsLayer.outline, x, y)
         }
 
         return true
@@ -101,18 +223,72 @@
         }
     }
 
+    private var drawnWithEnabledZ = false
+
     override fun drawLayer(canvas: Canvas, parentLayer: GraphicsLayer?) {
-        updateDisplayList()
-        scope.draw(density, layoutDirection, canvas, size.toSize(), parentLayer) {
-            drawLayer(graphicsLayer)
+        val androidCanvas = canvas.nativeCanvas
+        if (androidCanvas.isHardwareAccelerated) {
+            updateDisplayList()
+            drawnWithEnabledZ = graphicsLayer.shadowElevation > 0
+            scope.draw(density, layoutDirection, canvas, size.toSize(), parentLayer) {
+                drawLayer(graphicsLayer)
+            }
+        } else {
+            // TODO ideally there should be some solution for drawing a layer on a software
+            //  accelerated canvas built in right into GraphicsLayer, as this workaround is not
+            //  solving all the use cases. For example, some one can use layers directly via
+            //        drawWithContent {
+            //            layer.record {
+            //                this@drawWithContent.drawContent()
+            //            }
+            //            drawLayer(layer)
+            //        }
+            //  and if someone would try to draw the whole ComposeView on software accelerated
+            //  canvas it will just crash saying RenderNodes can't be drawn into this canvas.
+            //  This issue is tracked in b/333866398
+            val left = graphicsLayer.topLeft.x.toFloat()
+            val top = graphicsLayer.topLeft.y.toFloat()
+            val right = left + size.width
+            val bottom = top + size.height
+            // If there is alpha applied, we must render into an offscreen buffer to
+            // properly blend the contents of this layer against the background content
+            if (graphicsLayer.alpha < 1.0f) {
+                val paint = (softwareLayerPaint ?: Paint().also { softwareLayerPaint = it })
+                    .apply { alpha = graphicsLayer.alpha }
+                androidCanvas.saveLayer(
+                    left,
+                    top,
+                    right,
+                    bottom,
+                    paint.asFrameworkPaint()
+                )
+            } else {
+                canvas.save()
+            }
+            // If we are software rendered we must translate the canvas based on the offset provided
+            // in the move call which operates directly on the RenderNode
+            canvas.translate(left, top)
+            canvas.concat(getMatrix())
+            if (graphicsLayer.clip) {
+                clipManually(canvas)
+            }
+            drawBlock?.invoke(canvas, null)
+            canvas.restore()
         }
     }
 
     override fun updateDisplayList() {
         if (isDirty) {
+            if (graphicsLayer.size != size) {
+                graphicsLayer.pivotOffset = Offset(
+                    transformOrigin.pivotFractionX * size.width,
+                    transformOrigin.pivotFractionY * size.height
+                )
+                updateOutline()
+            }
             graphicsLayer.record(density, layoutDirection, size) {
                 drawIntoCanvas { canvas ->
-                    drawBlock?.let { it(canvas) }
+                    drawBlock?.let { it(canvas, drawContext.graphicsLayer) }
                 }
             }
             isDirty = false
@@ -131,26 +307,46 @@
         invalidateParentLayer = null
         isDestroyed = true
         isDirty = false
+        context?.releaseGraphicsLayer(graphicsLayer)
     }
 
     override fun mapOffset(point: Offset, inverse: Boolean): Offset {
-        return getMatrix(inverse).map(point)
+        return if (inverse) {
+            getInverseMatrix()?.map(point) ?: Offset.Infinite
+        } else {
+            getMatrix().map(point)
+        }
     }
 
     override fun mapBounds(rect: MutableRect, inverse: Boolean) {
-        getMatrix(inverse).map(rect)
+        if (inverse) {
+            val matrix = getInverseMatrix()
+            if (matrix == null) {
+                rect.set(0f, 0f, 0f, 0f)
+            } else {
+                matrix.map(rect)
+            }
+        } else {
+            getMatrix().map(rect)
+        }
     }
 
-    override fun reuseLayer(drawBlock: (Canvas) -> Unit, invalidateParentLayer: () -> Unit) {
+    override fun reuseLayer(
+        drawBlock: (canvas: Canvas, parentLayer: GraphicsLayer?) -> Unit,
+        invalidateParentLayer: () -> Unit
+    ) {
         throwIllegalStateException("reuseLayer is not supported yet")
     }
 
     override fun transform(matrix: Matrix) {
-        matrix.timesAssign(getMatrix(inverse = false))
+        matrix.timesAssign(getMatrix())
     }
 
     override fun inverseTransform(matrix: Matrix) {
-        matrix.timesAssign(getMatrix(inverse = true))
+        val inverse = getInverseMatrix()
+        if (inverse != null) {
+            matrix.timesAssign(inverse)
+        }
     }
 
     override val layerId: Long
@@ -159,14 +355,21 @@
     override val ownerViewId: Long
         get() = graphicsLayer.ownerViewId
 
-    private fun getMatrix(inverse: Boolean = false): Matrix {
+    private fun getMatrix(): Matrix {
         updateMatrix()
-        if (inverse) {
-            matrixCache.invert()
-        }
         return matrixCache
     }
 
+    private fun getInverseMatrix(): Matrix? {
+        val matrix = getMatrix()
+        val inverseMatrix = inverseMatrixCache ?: Matrix().also { inverseMatrixCache = it }
+        return if (matrix.invertTo(inverseMatrix)) {
+            inverseMatrix
+        } else {
+            null
+        }
+    }
+
     private fun updateMatrix() = with(graphicsLayer) {
         val pivot = if (pivotOffset.isUnspecified) size.center.toOffset() else pivotOffset
 
@@ -185,4 +388,27 @@
             translate(x = pivot.x, y = pivot.y)
         }
     }
+
+    /**
+     * Manually clips the content of the RenderNodeLayer in the provided canvas.
+     * This is used only in software rendered use cases
+     */
+    private fun clipManually(canvas: Canvas) {
+        if (graphicsLayer.clip) {
+            when (val outline = graphicsLayer.outline) {
+                is Outline.Rectangle -> {
+                    canvas.clipRect(outline.rect)
+                }
+                is Outline.Rounded -> {
+                    val path = tmpPath ?: Path().also { tmpPath = it }
+                    path.reset()
+                    path.addRoundRect(outline.roundRect)
+                    canvas.clipPath(path)
+                }
+                is Outline.Generic -> {
+                    canvas.clipPath(outline.path)
+                }
+            }
+        }
+    }
 }
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/RenderNodeLayer.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/RenderNodeLayer.android.kt
index 7e258ec..b1c7718 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/RenderNodeLayer.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/RenderNodeLayer.android.kt
@@ -47,10 +47,10 @@
 @RequiresApi(Build.VERSION_CODES.M)
 internal class RenderNodeLayer(
     val ownerView: AndroidComposeView,
-    drawBlock: (Canvas) -> Unit,
+    drawBlock: (canvas: Canvas, parentLayer: GraphicsLayer?) -> Unit,
     invalidateParentLayer: () -> Unit
 ) : OwnedLayer, GraphicLayerInfo {
-    private var drawBlock: ((Canvas) -> Unit)? = drawBlock
+    private var drawBlock: ((canvas: Canvas, parentLayer: GraphicsLayer?) -> Unit)? = drawBlock
     private var invalidateParentLayer: (() -> Unit)? = invalidateParentLayer
 
     /**
@@ -314,7 +314,7 @@
             canvas.translate(left, top)
             canvas.concat(matrixCache.calculateMatrix(renderNode))
             clipRenderNode(canvas)
-            drawBlock?.invoke(canvas)
+            drawBlock?.invoke(canvas, null)
             canvas.restore()
             isDirty = false
         }
@@ -337,8 +337,10 @@
             } else {
                 null
             }
-            drawBlock?.let {
-                renderNode.record(canvasHolder, clipPath, it)
+            drawBlock?.let { drawBlock ->
+                renderNode.record(canvasHolder, clipPath) {
+                    drawBlock(it, null)
+                }
             }
             isDirty = false
         }
@@ -377,7 +379,10 @@
         }
     }
 
-    override fun reuseLayer(drawBlock: (Canvas) -> Unit, invalidateParentLayer: () -> Unit) {
+    override fun reuseLayer(
+        drawBlock: (canvas: Canvas, parentLayer: GraphicsLayer?) -> Unit,
+        invalidateParentLayer: () -> Unit
+    ) {
         isDirty = false
         isDestroyed = false
         drawnWithZ = false
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/ViewLayer.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/ViewLayer.android.kt
index 4ef277e..0ccc913 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/ViewLayer.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/ViewLayer.android.kt
@@ -52,10 +52,10 @@
 internal class ViewLayer(
     val ownerView: AndroidComposeView,
     val container: DrawChildContainer,
-    drawBlock: (Canvas) -> Unit,
+    drawBlock: (canvas: Canvas, parentLayer: GraphicsLayer?) -> Unit,
     invalidateParentLayer: () -> Unit
 ) : View(ownerView.context), OwnedLayer, GraphicLayerInfo {
-    private var drawBlock: ((Canvas) -> Unit)? = drawBlock
+    private var drawBlock: ((canvas: Canvas, parentLayer: GraphicsLayer?) -> Unit)? = drawBlock
     private var invalidateParentLayer: (() -> Unit)? = invalidateParentLayer
 
     private val outlineResolver = Snapshot.withoutReadObservation {
@@ -329,7 +329,7 @@
                 save()
                 outlineResolver.clipToOutline(this)
             }
-            drawBlock?.invoke(this)
+            drawBlock?.invoke(this, null)
             if (didClip) {
                 restore()
             }
@@ -401,7 +401,10 @@
         }
     }
 
-    override fun reuseLayer(drawBlock: (Canvas) -> Unit, invalidateParentLayer: () -> Unit) {
+    override fun reuseLayer(
+        drawBlock: (canvas: Canvas, parentLayer: GraphicsLayer?) -> Unit,
+        invalidateParentLayer: () -> Unit
+    ) {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M || shouldUseDispatchDraw) {
             container.addView(this)
         } else {
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/scrollcapture/ComposeScrollCaptureCallback.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/scrollcapture/ComposeScrollCaptureCallback.android.kt
index ad00863..66ad43f 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/scrollcapture/ComposeScrollCaptureCallback.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/scrollcapture/ComposeScrollCaptureCallback.android.kt
@@ -22,6 +22,7 @@
 import android.graphics.Paint
 import android.graphics.Rect as AndroidRect
 import android.os.CancellationSignal
+import android.util.Log
 import android.view.ScrollCaptureCallback
 import android.view.ScrollCaptureSession
 import androidx.annotation.RequiresApi
@@ -35,6 +36,7 @@
 import androidx.compose.ui.internal.checkPreconditionNotNull
 import androidx.compose.ui.semantics.SemanticsActions.ScrollByOffset
 import androidx.compose.ui.semantics.SemanticsNode
+import androidx.compose.ui.semantics.SemanticsProperties.VerticalScrollAxisRange
 import androidx.compose.ui.unit.IntRect
 import java.util.function.Consumer
 import kotlin.math.roundToInt
@@ -46,6 +48,7 @@
 import kotlinx.coroutines.plus
 
 private const val DEBUG = false
+private const val TAG = "ScrollCapture"
 
 /**
  * Implementation of [ScrollCaptureCallback] that captures Compose scroll containers.
@@ -67,15 +70,26 @@
 
     private val scrollTracker = RelativeScroller(
         viewportSize = viewportBoundsInWindow.height,
-        scrollBy = { amount ->
+        scrollBy = { delta ->
             val scrollByOffset = checkPreconditionNotNull(node.scrollCaptureScrollByAction)
+            val reverseScrolling = node.unmergedConfig[VerticalScrollAxisRange].reverseScrolling
+
+            val actualDelta = if (reverseScrolling) -delta else delta
+            if (DEBUG) Log.d(
+                TAG, "scrolling by delta $actualDelta " +
+                    "(reverseScrolling=$reverseScrolling, requested delta=$delta)"
+            )
+
             // This action may animate, ensure any calls to this RelativeScroll are done with a
             // coroutine context that disables animations.
-            val consumed = scrollByOffset(Offset(0f, amount))
-            consumed.y
+            val consumed = scrollByOffset(Offset(0f, actualDelta))
+            if (reverseScrolling) -consumed.y else consumed.y
         }
     )
 
+    /** Only used when [DEBUG] is true. */
+    private var requestCount = 0
+
     override fun onScrollCaptureSearch(signal: CancellationSignal, onReady: Consumer<AndroidRect>) {
         val bounds = viewportBoundsInWindow
         onReady.accept(bounds.toAndroidRect())
@@ -87,6 +101,7 @@
         onReady: Runnable
     ) {
         scrollTracker.reset()
+        requestCount = 0
         listener.onSessionStarted()
         onReady.run()
     }
@@ -110,6 +125,7 @@
         // Scroll the requested capture area into the viewport so we can draw it.
         val targetMin = captureArea.top
         val targetMax = captureArea.bottom
+        if (DEBUG) Log.d(TAG, "capture request for $targetMin..$targetMax")
         scrollTracker.scrollRangeIntoView(targetMin, targetMax)
 
         // Wait a frame to allow layout to respond to the scroll.
@@ -119,6 +135,7 @@
         // the viewport.
         val viewportClippedMin = scrollTracker.mapOffsetToViewport(targetMin)
         val viewportClippedMax = scrollTracker.mapOffsetToViewport(targetMax)
+        if (DEBUG) Log.d(TAG, "drawing viewport $viewportClippedMin..$viewportClippedMax")
         val viewportClippedRect = captureArea.copy(
             top = viewportClippedMin,
             bottom = viewportClippedMax
@@ -164,6 +181,7 @@
 
         // Translate back to "original" coordinates to report.
         val resultRect = viewportClippedRect.translate(0, scrollTracker.scrollAmount.roundToInt())
+        if (DEBUG) Log.d(TAG, "captured rectangle $resultRect")
         return resultRect
     }
 
@@ -190,6 +208,7 @@
         val circleRadius = 20f
         val circlePaint = Paint().apply {
             color = Color.RED
+            textSize = 48f
         }
         drawCircle(0f, 0f, circleRadius, circlePaint)
         drawCircle(width.toFloat(), 0f, circleRadius, circlePaint)
@@ -200,6 +219,9 @@
             circlePaint
         )
         drawCircle(0f, height.toFloat(), circleRadius, circlePaint)
+
+        drawText(requestCount.toString(), width / 2f, height / 2f, circlePaint)
+        requestCount++
     }
 
     interface ScrollCaptureSessionListener {
@@ -244,6 +266,7 @@
      * viewport.
      */
     suspend fun scrollRangeIntoView(min: Int, max: Int) {
+        if (DEBUG) Log.d(TAG, "scrollRangeIntoView(min=$min, max=$max)")
         require(min <= max) { "Expected min=$min ≤ max=$max" }
         require(max - min <= viewportSize) {
             "Expected range (${max - min}) to be ≤ viewportSize=$viewportSize"
@@ -251,11 +274,13 @@
 
         if (min >= scrollAmount && max <= scrollAmount + viewportSize) {
             // Already visible, no need to scroll.
+            if (DEBUG) Log.d(TAG, "requested range already in view, not scrolling")
             return
         }
 
         // Scroll to the nearest edge.
         val target = if (min < scrollAmount) min else max - viewportSize
+        if (DEBUG) Log.d(TAG, "scrolling to $target")
         scrollTo(target.toFloat())
     }
 
@@ -273,12 +298,17 @@
     /**
      * Try to scroll to [offset] pixels past the original scroll position.
      */
-    suspend fun scrollTo(offset: Float): Float = scrollBy(offset - scrollAmount)
+    suspend fun scrollTo(offset: Float) {
+        scrollBy(offset - scrollAmount)
+    }
 
-    private suspend fun scrollBy(delta: Float): Float {
+    private suspend fun scrollBy(delta: Float) {
         val consumed = scrollBy.invoke(delta)
         scrollAmount += consumed
-        return consumed
+        if (DEBUG) Log.d(
+            TAG,
+            "scrolled $consumed of requested $delta, after scrollAmount=$scrollAmount"
+        )
     }
 }
 
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/scrollcapture/ScrollCapture.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/scrollcapture/ScrollCapture.android.kt
index 2a3afd0..1062dbc 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/scrollcapture/ScrollCapture.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/scrollcapture/ScrollCapture.android.kt
@@ -134,7 +134,7 @@
 ) {
     fromNode.visitDescendants { node ->
         // Invisible/disabled nodes can't be candidates, nor can any of their descendants.
-        if (!node.isVisible || Disabled in node.config) {
+        if (!node.isVisible || Disabled in node.unmergedConfig) {
             return@visitDescendants false
         }
 
@@ -178,7 +178,8 @@
     }
 }
 
-internal val SemanticsNode.scrollCaptureScrollByAction get() = config.getOrNull(ScrollByOffset)
+internal val SemanticsNode.scrollCaptureScrollByAction
+    get() = unmergedConfig.getOrNull(ScrollByOffset)
 
 // TODO(mnuzen): Port this back to the SemanticsUtil file
 @OptIn(ExperimentalComposeUiApi::class)
@@ -188,7 +189,7 @@
 private val SemanticsNode.canScrollVertically: Boolean
     get() {
         val scrollByOffset = scrollCaptureScrollByAction
-        val verticalScrollAxisRange = config.getOrNull(VerticalScrollAxisRange)
+        val verticalScrollAxisRange = unmergedConfig.getOrNull(VerticalScrollAxisRange)
         return scrollByOffset != null &&
             verticalScrollAxisRange != null &&
             verticalScrollAxisRange.maxValue() > 0f
diff --git a/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/node/DelegatingNodeTest.kt b/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/node/DelegatingNodeTest.kt
index 0f54238..30c59065 100644
--- a/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/node/DelegatingNodeTest.kt
+++ b/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/node/DelegatingNodeTest.kt
@@ -792,22 +792,17 @@
 ): NodeChain {
     val owner = MockOwner()
     val root = LayoutNode()
-    val ln = unattachedLayout(*modifiers)
-    LayoutScopeImpl(ln).block()
+    val ln = LayoutNode()
     root.insertAt(0, ln)
     root.attach(owner)
-    root.innerCoordinator.updateLayerBlock({})
-    return ln.nodes
-}
-
-private fun unattachedLayout(vararg modifiers: Modifier.Node): LayoutNode {
-    val ln = LayoutNode()
     var m: Modifier = Modifier
     for (node in modifiers) {
         m = m.then(NodeElement(node))
     }
     ln.nodes.updateFrom(m)
-    return ln
+    LayoutScopeImpl(ln).block()
+    root.innerCoordinator.updateLayerBlock({})
+    return ln.nodes
 }
 
 internal data class NodeElement(val node: Modifier.Node) : ModifierNodeElement<Modifier.Node>() {
@@ -823,9 +818,14 @@
 }
 internal class LayoutScopeImpl(val layout: LayoutNode) : LayoutScope {
     override fun layout(vararg modifiers: Modifier.Node, block: LayoutScope.() -> Unit) {
-        val ln = unattachedLayout(*modifiers)
-        LayoutScopeImpl(ln).block()
+        val ln = LayoutNode()
         layout.insertAt(layout.children.size, ln)
+        var m: Modifier = Modifier
+        for (node in modifiers) {
+            m = m.then(NodeElement(node))
+        }
+        ln.nodes.updateFrom(m)
+        LayoutScopeImpl(ln).block()
     }
 }
 interface LayoutScope {
diff --git a/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/node/LayoutNodeTest.kt b/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/node/LayoutNodeTest.kt
index 14e60cb..bb76634 100644
--- a/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/node/LayoutNodeTest.kt
+++ b/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/node/LayoutNodeTest.kt
@@ -81,6 +81,7 @@
 import com.google.common.truth.Truth.assertThat
 import java.util.concurrent.Executors
 import kotlin.coroutines.CoroutineContext
+import kotlin.test.assertNotSame
 import kotlinx.coroutines.asCoroutineDispatcher
 import org.junit.Assert
 import org.junit.Assert.assertEquals
@@ -695,6 +696,40 @@
         assertEquals(0, node.children.size)
     }
 
+    // Modifiers set before the layout node is attached should not be applied until after attach
+    @Test
+    fun modifierSetBeforeLayoutNodeAttached() {
+        val layoutNode = LayoutNode()
+        val layoutModifier = Modifier.graphicsLayer { }
+
+        layoutNode.modifier = layoutModifier
+        // Changes should not be applied yet
+        assertNotSame(layoutNode.modifier, layoutModifier)
+        assertFalse(layoutNode.outerCoordinator.isAttached)
+        assertFalse(layoutNode.nodes.has(Nodes.Any))
+
+        layoutNode.attach(MockOwner())
+        // Changes should now be applied
+        assertSame(layoutNode.modifier, layoutModifier)
+        assertTrue(layoutNode.outerCoordinator.isAttached)
+        assertTrue(layoutNode.nodes.has(Nodes.Any))
+    }
+
+    // Modifiers set after the layout node is attached should be applied immediately
+    @Test
+    fun modifierSetAfterLayoutNodeAttached() {
+        val layoutNode = LayoutNode()
+        val layoutModifier = Modifier.graphicsLayer { }
+        layoutNode.attach(MockOwner())
+
+        layoutNode.modifier = layoutModifier
+
+        // Changes should be applied
+        assertSame(layoutNode.modifier, layoutModifier)
+        assertTrue(layoutNode.outerCoordinator.isAttached)
+        assertTrue(layoutNode.nodes.has(Nodes.Any))
+    }
+
     // The layout coordinates of a LayoutNode should be attached when
     // the layout node is attached.
     @Test
@@ -716,13 +751,11 @@
     @Test
     fun nodeCoordinatorSameWithReplacementModifier() {
         val layoutNode = LayoutNode()
+        layoutNode.attach(MockOwner())
         val layoutModifier = Modifier.graphicsLayer { }
 
         layoutNode.modifier = layoutModifier
         val oldNodeCoordinator = layoutNode.outerCoordinator
-        assertFalse(oldNodeCoordinator.isAttached)
-
-        layoutNode.attach(MockOwner())
         assertTrue(oldNodeCoordinator.isAttached)
 
         layoutNode.modifier = Modifier.graphicsLayer { }
@@ -767,14 +800,17 @@
             .graphicsLayer { }
 
         layoutNode.modifier = layoutModifier
-        val oldNodeCoordinator = layoutNode.outerCoordinator
-        val oldInnerNodeCoordinator = oldNodeCoordinator.wrapped
+        var oldNodeCoordinator = layoutNode.outerCoordinator
+        var oldInnerNodeCoordinator = oldNodeCoordinator.wrapped
         assertFalse(oldNodeCoordinator.isAttached)
-        assertNotNull(oldInnerNodeCoordinator)
-        assertFalse(oldInnerNodeCoordinator!!.isAttached)
+        assertNull(oldInnerNodeCoordinator)
 
         layoutNode.attach(MockOwner())
+        oldNodeCoordinator = layoutNode.outerCoordinator
+        oldInnerNodeCoordinator = oldNodeCoordinator.wrapped
         assertTrue(oldNodeCoordinator.isAttached)
+        assertNotNull(oldInnerNodeCoordinator)
+        assertTrue(oldInnerNodeCoordinator!!.isAttached)
 
         // only 1 modifier now, so one should be detached and the other can be reused
         layoutNode.modifier = Modifier.graphicsLayer()
@@ -2349,6 +2385,7 @@
         val modifier2 = Modifier.layout(measureLambda2)
 
         val root = LayoutNode()
+        root.attach(MockOwner())
         root.modifier = modifier1.then(modifier2)
 
         assertEquals(
@@ -2644,7 +2681,7 @@
     val invalidatedLayers = mutableListOf<OwnedLayer>()
 
     override fun createLayer(
-        drawBlock: (Canvas) -> Unit,
+        drawBlock: (Canvas, GraphicsLayer?) -> Unit,
         invalidateParentLayer: () -> Unit,
         explicitLayer: GraphicsLayer?
     ): OwnedLayer {
@@ -2673,7 +2710,7 @@
             }
 
             override fun drawLayer(canvas: Canvas, parentLayer: GraphicsLayer?) {
-                drawBlock(canvas)
+                drawBlock(canvas, null)
             }
 
             override fun updateDisplayList() {
@@ -2690,7 +2727,7 @@
             }
 
             override fun reuseLayer(
-                drawBlock: (Canvas) -> Unit,
+                drawBlock: (Canvas, GraphicsLayer?) -> Unit,
                 invalidateParentLayer: () -> Unit
             ) {
             }
diff --git a/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/node/ModifierLocalConsumerEntityTest.kt b/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/node/ModifierLocalConsumerEntityTest.kt
index 1c7c4c2..fe6890b 100644
--- a/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/node/ModifierLocalConsumerEntityTest.kt
+++ b/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/node/ModifierLocalConsumerEntityTest.kt
@@ -388,7 +388,7 @@
             get() = TODO("Not yet implemented")
 
         override fun createLayer(
-            drawBlock: (Canvas) -> Unit,
+            drawBlock: (Canvas, GraphicsLayer?) -> Unit,
             invalidateParentLayer: () -> Unit,
             explicitLayer: GraphicsLayer?
         ) = TODO("Not yet implemented")
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/autofill/Autofill.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/autofill/Autofill.kt
index d1db594..13d2354 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/autofill/Autofill.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/autofill/Autofill.kt
@@ -90,7 +90,7 @@
 
         if (autofillTypes != other.autofillTypes) return false
         if (boundingBox != other.boundingBox) return false
-        if (onFill != other.onFill) return false
+        if (onFill !== other.onFill) return false
 
         return true
     }
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/pointer/SuspendingPointerInputFilter.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/pointer/SuspendingPointerInputFilter.kt
index 66497b3..421f11a 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/pointer/SuspendingPointerInputFilter.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/pointer/SuspendingPointerInputFilter.kt
@@ -330,11 +330,11 @@
     }
 
     override fun create(): SuspendingPointerInputModifierNodeImpl {
-        return SuspendingPointerInputModifierNodeImpl(pointerInputHandler)
+        return SuspendingPointerInputModifierNodeImpl(key1, key2, keys, pointerInputHandler)
     }
 
     override fun update(node: SuspendingPointerInputModifierNodeImpl) {
-        node.pointerInputHandler = pointerInputHandler
+        node.update(key1, key2, keys, pointerInputHandler)
     }
 
     override fun equals(other: Any?): Boolean {
@@ -348,13 +348,14 @@
             if (!keys.contentEquals(other.keys)) return false
         } else if (other.keys != null) return false
 
-        return true
+        return pointerInputHandler === other.pointerInputHandler
     }
 
     override fun hashCode(): Int {
         var result = key1?.hashCode() ?: 0
         result = 31 * result + (key2?.hashCode() ?: 0)
         result = 31 * result + (keys?.contentHashCode() ?: 0)
+        result = 31 * result + pointerInputHandler.hashCode()
         return result
     }
 }
@@ -370,7 +371,7 @@
 fun SuspendingPointerInputModifierNode(
     pointerInputHandler: suspend PointerInputScope.() -> Unit
 ): SuspendingPointerInputModifierNode {
-    return SuspendingPointerInputModifierNodeImpl(pointerInputHandler)
+    return SuspendingPointerInputModifierNodeImpl(null, null, null, pointerInputHandler)
 }
 
 /**
@@ -412,17 +413,55 @@
  * first event is fired (making it more efficient) and is cancelled via resetPointerInputHandler().
  */
 internal class SuspendingPointerInputModifierNodeImpl(
+    private var key1: Any? = null,
+    private var key2: Any? = null,
+    private var keys: Array<out Any?>? = null,
     pointerInputHandler: suspend PointerInputScope.() -> Unit
 ) : Modifier.Node(),
     SuspendingPointerInputModifierNode,
     PointerInputScope,
     Density {
 
-    override var pointerInputHandler = pointerInputHandler
+    internal fun update(
+        key1: Any?,
+        key2: Any?,
+        keys: Array<out Any?>?,
+        pointerInputHandler: suspend PointerInputScope.() -> Unit
+    ) {
+        var needsReset = false
+        if (this.key1 != key1) {
+            needsReset = true
+        }
+        this.key1 = key1
+        if (this.key2 != key2) {
+            needsReset = true
+        }
+        this.key2 = key2
+        if (this.keys != null && keys == null) {
+            needsReset = true
+        }
+        if (this.keys == null && keys != null) {
+            needsReset = true
+        }
+        if (this.keys != null && keys != null && !keys.contentEquals(this.keys)) {
+            needsReset = true
+        }
+        this.keys = keys
+        if (needsReset) {
+            resetPointerInputHandler()
+        }
+        // Avoids calling resetPointerInputHandler when setting this if no keys have changed
+        _pointerInputHandler = pointerInputHandler
+    }
+
+    private var _pointerInputHandler = pointerInputHandler
+
+    override var pointerInputHandler
         set(value) {
             resetPointerInputHandler()
-            field = value
+            _pointerInputHandler = value
         }
+        get() = _pointerInputHandler
 
     override val density: Float
         get() = requireLayoutNode().density.density
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/OnGloballyPositionedModifier.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/OnGloballyPositionedModifier.kt
index d6ee7f8..065c55e 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/OnGloballyPositionedModifier.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/OnGloballyPositionedModifier.kt
@@ -54,7 +54,7 @@
     override fun equals(other: Any?): Boolean {
         if (this === other) return true
         if (other !is OnGloballyPositionedElement) return false
-        return onGloballyPositioned == other.onGloballyPositioned
+        return onGloballyPositioned === other.onGloballyPositioned
     }
 
     override fun hashCode(): Int {
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/OnRemeasuredModifier.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/OnRemeasuredModifier.kt
index 91fe684..a6b2e22 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/OnRemeasuredModifier.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/OnRemeasuredModifier.kt
@@ -59,7 +59,7 @@
         if (this === other) return true
         if (other !is OnSizeChangedModifier) return false
 
-        return onSizeChanged == other.onSizeChanged
+        return onSizeChanged === other.onSizeChanged
     }
 
     override fun hashCode(): Int {
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/modifier/ModifierLocalConsumer.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/modifier/ModifierLocalConsumer.kt
index 6d291ff..e7bb4b1 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/modifier/ModifierLocalConsumer.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/modifier/ModifierLocalConsumer.kt
@@ -67,7 +67,7 @@
     }
 
     override fun equals(other: Any?): Boolean {
-        return other is ModifierLocalConsumerImpl && other.consumer == consumer
+        return other is ModifierLocalConsumerImpl && other.consumer === consumer
     }
 
     override fun hashCode() = consumer.hashCode()
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNode.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNode.kt
index b541297..fc363d0 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNode.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNode.kt
@@ -465,6 +465,10 @@
 
         this.owner = owner
         this.depth = (parent?.depth ?: -1) + 1
+
+        pendingModifier?.let { applyModifier(it) }
+        pendingModifier = null
+
         if (nodes.has(Nodes.Semantics)) {
             invalidateSemantics()
         }
@@ -878,10 +882,15 @@
         }
     }
 
+    private var _modifier: Modifier = Modifier
+    private var pendingModifier: Modifier? = null
+    internal val applyingModifierOnAttach get() = pendingModifier != null
+
     /**
      * The [Modifier] currently applied to this node.
      */
-    override var modifier: Modifier = Modifier
+    override var modifier: Modifier
+        get() = _modifier
         set(value) {
             requirePrecondition(!isVirtual || modifier === Modifier) {
                 "Modifiers are not supported on virtual LayoutNodes"
@@ -889,14 +898,22 @@
             requirePrecondition(!isDeactivated) {
                 "modifier is updated when deactivated"
             }
-            field = value
-            nodes.updateFrom(value)
-            layoutDelegate.updateParentData()
-            if (lookaheadRoot == null && nodes.has(Nodes.ApproachMeasure)) {
-                lookaheadRoot = this
+            if (isAttached) {
+                applyModifier(value)
+            } else {
+                pendingModifier = value
             }
         }
 
+    private fun applyModifier(modifier: Modifier) {
+        _modifier = modifier
+        nodes.updateFrom(modifier)
+        layoutDelegate.updateParentData()
+        if (lookaheadRoot == null && nodes.has(Nodes.ApproachMeasure)) {
+            lookaheadRoot = this
+        }
+    }
+
     private fun resetModifierState() {
         nodes.resetState()
     }
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeChain.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeChain.kt
index 4fbe097..ba32617 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeChain.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeChain.kt
@@ -23,7 +23,6 @@
 import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.areObjectsOfSameType
-import androidx.compose.ui.input.pointer.SuspendPointerInputElement
 import androidx.compose.ui.internal.checkPrecondition
 import androidx.compose.ui.internal.checkPreconditionNotNull
 import androidx.compose.ui.layout.ModifierInfo
@@ -165,15 +164,15 @@
                     before,
                     after,
                     node,
-                    layoutNode.isAttached,
+                    !layoutNode.applyingModifierOnAttach,
                 )
             }
-        } else if (!layoutNode.isAttached && beforeSize == 0) {
+        } else if (layoutNode.applyingModifierOnAttach && beforeSize == 0) {
             // common case where we are initializing the chain and the previous size is zero. In
             // this case we just do all inserts. Since this is so common, we add a fast path here
-            // for this condition. Since the layout node is not attached, the inserted nodes will
-            // not get eagerly attached, which means we can avoid dealing with the coordinator sync
-            // until the end, which keeps this code path much simpler.
+            // for this condition. Since the layout node is currently attaching, the inserted nodes
+            // will not get eagerly attached, which means we can avoid dealing with the coordinator
+            // sync until the end, which keeps this code path much simpler.
             coordinatorSyncNeeded = true
             var node = paddedHead
             while (i < after.size) {
@@ -203,7 +202,7 @@
                 before,
                 after,
                 paddedHead,
-                layoutNode.isAttached,
+                !layoutNode.applyingModifierOnAttach,
             )
         }
         current = after
@@ -223,16 +222,6 @@
         tailToHead {
             if (it.isAttached) it.reset()
         }
-        current?.let { elements ->
-            elements.forEachIndexed { i, element ->
-                // we need to make sure the suspending pointer input modifier node is updated after
-                // being reset so we use the latest lambda, even if the keys provided as input
-                // didn't change.
-                if (element is SuspendPointerInputElement) {
-                    elements[i] = ForceUpdateElement(element)
-                }
-            }
-        }
         runDetachLifecycle()
         markAsDetached()
     }
@@ -814,9 +803,7 @@
 internal fun actionForModifiers(prev: Modifier.Element, next: Modifier.Element): Int {
     return if (prev == next) {
         ActionReuse
-    } else if (areObjectsOfSameType(prev, next) ||
-        (prev is ForceUpdateElement && areObjectsOfSameType(prev.original, next))
-    ) {
+    } else if (areObjectsOfSameType(prev, next)) {
         ActionUpdate
     } else {
         ActionReplace
@@ -853,15 +840,3 @@
     }
     return result
 }
-
-@Suppress("ModifierNodeInspectableProperties")
-private data class ForceUpdateElement(val original: ModifierNodeElement<*>) :
-    ModifierNodeElement<Modifier.Node>() {
-    override fun create(): Modifier.Node {
-        throw IllegalStateException("Shouldn't be called")
-    }
-
-    override fun update(node: Modifier.Node) {
-        throw IllegalStateException("Shouldn't be called")
-    }
-}
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeCoordinator.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeCoordinator.kt
index 64e839f..f797a9c 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeCoordinator.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeCoordinator.kt
@@ -447,10 +447,10 @@
 
     // implementation of draw block passed to the OwnedLayer
     @Suppress("LiftReturnOrAssignment")
-    private val drawBlock: (Canvas) -> Unit = { canvas ->
-        if (layoutNode.isPlaced) {
-            snapshotObserver.observeReads(this, onCommitAffectingLayer) {
-                drawContainedDrawModifiers(canvas, explicitLayer)
+    private val drawBlock: (Canvas, GraphicsLayer?) -> Unit = { canvas, parentLayer ->
+            if (layoutNode.isPlaced) {
+                snapshotObserver.observeReads(this, onCommitAffectingLayer) {
+                    drawContainedDrawModifiers(canvas, parentLayer)
             }
             lastLayerDrawingWasSkipped = false
         } else {
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/OwnedLayer.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/OwnedLayer.kt
index 23fdbd4..f68b387 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/OwnedLayer.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/OwnedLayer.kt
@@ -103,7 +103,10 @@
      * [drawBlock] and [invalidateParentLayer] values. The layer will be reinitialized
      * as new after this call.
      */
-    fun reuseLayer(drawBlock: (Canvas) -> Unit, invalidateParentLayer: () -> Unit)
+    fun reuseLayer(
+        drawBlock: (canvas: Canvas, parentLayer: GraphicsLayer?) -> Unit,
+        invalidateParentLayer: () -> Unit
+    )
 
     /**
      * Calculates the transform from the parent to the local coordinates and multiplies
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/Owner.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/Owner.kt
index dbc9f47..789cefc 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/Owner.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/Owner.kt
@@ -256,7 +256,7 @@
      * Creates an [OwnedLayer] which will be drawing the passed [drawBlock].
      */
     fun createLayer(
-        drawBlock: (Canvas) -> Unit,
+        drawBlock: (canvas: Canvas, parentLayer: GraphicsLayer?) -> Unit,
         invalidateParentLayer: () -> Unit,
         explicitLayer: GraphicsLayer? = null
     ): OwnedLayer
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsModifier.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsModifier.kt
index dd4decb..40bf53c 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsModifier.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsModifier.kt
@@ -46,9 +46,9 @@
     val semanticsConfiguration: SemanticsConfiguration
 }
 
-internal object EmptySemanticsElement :
+internal class EmptySemanticsElement(private val node: EmptySemanticsModifier) :
     ModifierNodeElement<EmptySemanticsModifier>() {
-    override fun create() = EmptySemanticsModifier()
+    override fun create() = node
 
     override fun update(node: EmptySemanticsModifier) {}
 
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsOwner.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsOwner.kt
index ec5a18f..b1e955a 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsOwner.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsOwner.kt
@@ -18,7 +18,6 @@
 
 import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.node.LayoutNode
-import androidx.compose.ui.node.Nodes
 import androidx.compose.ui.util.fastForEach
 
 /**
@@ -26,7 +25,10 @@
  * semantics tree
  */
 @OptIn(ExperimentalComposeUiApi::class)
-class SemanticsOwner internal constructor(private val rootNode: LayoutNode) {
+class SemanticsOwner internal constructor(
+    private val rootNode: LayoutNode,
+    private val outerSemanticsNode: EmptySemanticsModifier
+) {
     /**
      * The root node of the semantics tree.  Does not contain any unmerged data.
      * May contain merged data.
@@ -39,7 +41,7 @@
     val unmergedRootSemanticsNode: SemanticsNode
         get() {
             return SemanticsNode(
-                outerSemanticsNode = rootNode.nodes.head(Nodes.Semantics)!!.node,
+                outerSemanticsNode = outerSemanticsNode,
                 layoutNode = rootNode,
                 mergingEnabled = false,
                 // Forcing an empty SemanticsConfiguration here since the root node will always
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsProperties.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsProperties.kt
index 50dffd3..0d60bb9 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsProperties.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsProperties.kt
@@ -620,7 +620,7 @@
         if (other !is CustomAccessibilityAction) return false
 
         if (label != other.label) return false
-        if (action != other.action) return false
+        if (action !== other.action) return false
 
         return true
     }
diff --git a/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/platform/SkiaLayerTest.kt b/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/platform/SkiaLayerTest.kt
index 5293ba2..082fff8 100644
--- a/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/platform/SkiaLayerTest.kt
+++ b/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/platform/SkiaLayerTest.kt
@@ -374,7 +374,7 @@
     private fun TestSkiaLayer() = SkiaLayer(
         Density(1f, 1f),
         invalidateParentLayer = {},
-        drawBlock = {}
+        drawBlock = { _, _ -> }
     )
 
     private fun SkiaLayer.updateProperties(
diff --git a/compose/ui/ui/src/skikoMain/kotlin/androidx/compose/ui/platform/SkiaBasedOwner.skiko.kt b/compose/ui/ui/src/skikoMain/kotlin/androidx/compose/ui/platform/SkiaBasedOwner.skiko.kt
index bc03008..dda9f9f 100644
--- a/compose/ui/ui/src/skikoMain/kotlin/androidx/compose/ui/platform/SkiaBasedOwner.skiko.kt
+++ b/compose/ui/ui/src/skikoMain/kotlin/androidx/compose/ui/platform/SkiaBasedOwner.skiko.kt
@@ -78,6 +78,7 @@
 import androidx.compose.ui.node.OwnerSnapshotObserver
 import androidx.compose.ui.node.RootForTest
 import androidx.compose.ui.semantics.EmptySemanticsElement
+import androidx.compose.ui.semantics.EmptySemanticsModifier
 import androidx.compose.ui.semantics.SemanticsOwner
 import androidx.compose.ui.text.font.createFontFamilyResolver
 import androidx.compose.ui.text.input.TextInputService
@@ -125,7 +126,8 @@
 
     override val sharedDrawScope = LayoutNodeDrawScope()
 
-    private val semanticsModifier = EmptySemanticsElement
+    private val rootSemanticsNode = EmptySemanticsModifier()
+    private val semanticsModifier = EmptySemanticsElement(rootSemanticsNode)
 
     override val focusOwner: FocusOwner = FocusOwnerImpl(
         onRequestApplyChangesListener = ::registerOnEndApplyChangesListener,
@@ -237,7 +239,7 @@
 
     override val textToolbar = DefaultTextToolbar()
 
-    override val semanticsOwner: SemanticsOwner = SemanticsOwner(root)
+    override val semanticsOwner: SemanticsOwner = SemanticsOwner(root, rootSemanticsNode)
 
     override val dragAndDropManager: DragAndDropManager get() = TODO("Not yet implemented")
 
@@ -376,7 +378,7 @@
     }
 
     override fun createLayer(
-        drawBlock: (Canvas) -> Unit,
+        drawBlock: (Canvas, GraphicsLayer?) -> Unit,
         invalidateParentLayer: () -> Unit,
         explicitLayer: GraphicsLayer?
     ) = SkiaLayer(
diff --git a/compose/ui/ui/src/skikoMain/kotlin/androidx/compose/ui/platform/SkiaLayer.skiko.kt b/compose/ui/ui/src/skikoMain/kotlin/androidx/compose/ui/platform/SkiaLayer.skiko.kt
index 5f8b1e8..41bffb8 100644
--- a/compose/ui/ui/src/skikoMain/kotlin/androidx/compose/ui/platform/SkiaLayer.skiko.kt
+++ b/compose/ui/ui/src/skikoMain/kotlin/androidx/compose/ui/platform/SkiaLayer.skiko.kt
@@ -59,7 +59,7 @@
 internal class SkiaLayer(
     private var density: Density,
     private val invalidateParentLayer: () -> Unit,
-    private val drawBlock: (Canvas) -> Unit,
+    private val drawBlock: (Canvas, GraphicsLayer?) -> Unit,
     private val onDestroy: () -> Unit = {}
 ) : OwnedLayer {
     private var size = IntSize.Zero
@@ -95,7 +95,10 @@
         onDestroy()
     }
 
-    override fun reuseLayer(drawBlock: (Canvas) -> Unit, invalidateParentLayer: () -> Unit) {
+    override fun reuseLayer(
+        drawBlock: (Canvas, GraphicsLayer?) -> Unit,
+        invalidateParentLayer: () -> Unit
+    ) {
         // TODO: in destroy, call recycle, and reconfigure this layer to be ready to use here.
     }
 
@@ -274,7 +277,7 @@
                 skiaCanvas.alphaMultiplier = 1.0f
             }
 
-            drawBlock(canvas)
+            drawBlock(canvas, null)
             canvas.restore()
             if (clip) {
                 canvas.restore()
diff --git a/constraintlayout/constraintlayout-compose/src/androidMain/kotlin/androidx/constraintlayout/compose/ConstraintLayout.kt b/constraintlayout/constraintlayout-compose/src/androidMain/kotlin/androidx/constraintlayout/compose/ConstraintLayout.kt
index 04f1c6d..32ac6ba 100644
--- a/constraintlayout/constraintlayout-compose/src/androidMain/kotlin/androidx/constraintlayout/compose/ConstraintLayout.kt
+++ b/constraintlayout/constraintlayout-compose/src/androidMain/kotlin/androidx/constraintlayout/compose/ConstraintLayout.kt
@@ -957,7 +957,7 @@
         override fun hashCode() = constrainBlock.hashCode()
 
         override fun equals(other: Any?) =
-            constrainBlock == (other as? ConstrainAsModifier)?.constrainBlock
+            constrainBlock === (other as? ConstrainAsModifier)?.constrainBlock
     }
 }
 
@@ -1064,7 +1064,7 @@
     override val layoutId: Any = ref.id
 
     override fun equals(other: Any?) = other is ConstraintLayoutParentData &&
-        ref.id == other.ref.id && constrain == other.constrain
+        ref.id == other.ref.id && constrain === other.constrain
 
     override fun hashCode() = ref.id.hashCode() * 31 + constrain.hashCode()
 }
diff --git a/datastore/datastore-core/src/commonJvmMain/kotlin/androidx/datastore/core/Serializer.kt b/datastore/datastore-core/src/commonJvmMain/kotlin/androidx/datastore/core/Serializer.kt
index b39e56d..5fc0640 100644
--- a/datastore/datastore-core/src/commonJvmMain/kotlin/androidx/datastore/core/Serializer.kt
+++ b/datastore/datastore-core/src/commonJvmMain/kotlin/androidx/datastore/core/Serializer.kt
@@ -44,7 +44,7 @@
      *  Marshal object to a stream. Closing the provided OutputStream is a no-op.
      *
      *  @param t the data to write to output
-     *  @output the OutputStream to serialize data to
+     *  @param output the OutputStream to serialize data to
      */
     public suspend fun writeTo(t: T, output: OutputStream)
 }
diff --git a/development/bench-flame-diff/app/src/main/kotlin/bench/flame/diff/command/Diff.kt b/development/bench-flame-diff/app/src/main/kotlin/bench/flame/diff/command/Diff.kt
index 48ed373..ecf3682 100644
--- a/development/bench-flame-diff/app/src/main/kotlin/bench/flame/diff/command/Diff.kt
+++ b/development/bench-flame-diff/app/src/main/kotlin/bench/flame/diff/command/Diff.kt
@@ -43,11 +43,13 @@
 
         val before: File = when {
             before == null -> promptProvideFile("Provide the 'before' path",
+                excludePattern = ".*\\.json$",
                 defaultSrcDir = Paths.savedTracesDir.toFile())
             else -> checkNotNull(before)
         }
         val after: File = when {
             after == null -> promptProvideFile("Provide the 'after' path",
+                excludePattern = ".*\\.json$",
                 defaultSrcDir = Paths.savedTracesDir.toFile())
             else -> checkNotNull(after)
         }
@@ -73,6 +75,18 @@
         log("Opened '${indexHtml.canonicalPath}' in the browser.", isStdErr = true)
     }
 
+    private fun fetchBenchmarkResultForTrace(traceFile: File): String {
+        val file = traceFile.parentFile.resolve(traceFile.nameWithoutExtension + ".json")
+        if (!file.exists()) {
+            log(
+                "Could not locate benchmark result file for trace: ${traceFile.name} ",
+                isStdErr = true
+            )
+            return ""
+        }
+        return file.readText()
+    }
+
     private fun createDiffHtmlPage(beforeRaw: File, afterRaw: File, diffDir: File): File {
         val beforeRawFolded = diffDir.resolve("before-raw.folded")
         val afterRawFolded = diffDir.resolve("after-raw.folded")
@@ -96,8 +110,20 @@
         createFlameGraph(afterDiffFolded, afterDiffSvg)
         createFlameGraph(beforeDiffFolded, beforeDiffSvg, negate = true)
 
+        // fetch benchmark result data
+        val benchmarkResultBefore = fetchBenchmarkResultForTrace(beforeRaw)
+        val benchmarkResultAfter = fetchBenchmarkResultForTrace(afterRaw)
         createIndexHtml(
-            TraceDiffResult(beforeRawSvg, beforeDiffSvg, afterRawSvg, afterDiffSvg), indexHtml
+            TraceDiffResult(
+                beforeRawSvg,
+                beforeDiffSvg,
+                afterRawSvg,
+                afterDiffSvg,
+                benchmarkResultBefore,
+                benchmarkResultAfter,
+                beforeRaw.name,
+                afterRaw.name
+            ), indexHtml
         )
 
         for (tmpFile in listOf(beforeRawFolded, afterRawFolded, beforeDiffFolded, afterDiffFolded))
@@ -109,7 +135,11 @@
         val beforeRawGraph: File,
         val beforeDiffGraph: File,
         val afterRawGraph: File,
-        val afterDiffGraph: File
+        val afterDiffGraph: File,
+        val beforeBenchmarkResult: String,
+        val afterBenchmarkResult: String,
+        val beforeTraceFileName: String,
+        val afterTraceFileName: String
     )
 
     private fun fileOption(role: String): MutuallyExclusiveOptions<File, File?> {
@@ -191,6 +221,10 @@
             .replace("%before_diff_name%", "diff base vs curr")
             .replace("%after_raw_name%", "show curr")
             .replace("%after_diff_name%", "diff curr vs base")
-        dstFile.bufferedWriter().use { writer -> writer.write(content) }
+            .replace("%benchmark_result_before_raw%", src.beforeBenchmarkResult)
+            .replace("%benchmark_result_after_raw%", src.afterBenchmarkResult)
+            .replace("%before_trace_file_name%", src.beforeTraceFileName)
+            .replace("%after_trace_file_name%", src.afterTraceFileName)
+        dstFile.writeText(content)
     }
 }
diff --git a/development/bench-flame-diff/app/src/main/kotlin/bench/flame/diff/command/List.kt b/development/bench-flame-diff/app/src/main/kotlin/bench/flame/diff/command/List.kt
index ccda04a..cb5d5ba 100644
--- a/development/bench-flame-diff/app/src/main/kotlin/bench/flame/diff/command/List.kt
+++ b/development/bench-flame-diff/app/src/main/kotlin/bench/flame/diff/command/List.kt
@@ -44,13 +44,14 @@
 
     companion object {
         /** Returns a list of saved traces sorted by 'most recently modified first' */
-        internal fun savedTraces(savedTracesDir: File): List<FileWithId> {
-            val files: Array<File> = when {
-                !savedTracesDir.exists() -> emptyArray<File>()
-                else -> savedTracesDir.listFiles() ?: emptyArray<File>()
-            }
-            files.sortWith(compareBy { f: File -> -f.lastModified() })
-            return files.asSequence().withId().toList()
-        }
+        internal fun savedTraces(savedTracesDir: File): List<FileWithId> =
+            savedTracesDir
+                .listFiles()
+                .let { it ?: return emptyList() }
+                .filter { !it.name.lowercase().endsWith(".json") }
+                .sortedBy { -it.lastModified() }
+                .asSequence()
+                .withId()
+                .toList()
     }
 }
diff --git a/development/bench-flame-diff/app/src/main/kotlin/bench/flame/diff/command/Save.kt b/development/bench-flame-diff/app/src/main/kotlin/bench/flame/diff/command/Save.kt
index 70fec93..8b95718 100644
--- a/development/bench-flame-diff/app/src/main/kotlin/bench/flame/diff/command/Save.kt
+++ b/development/bench-flame-diff/app/src/main/kotlin/bench/flame/diff/command/Save.kt
@@ -46,21 +46,40 @@
         .default(Paths.traceFileNamePattern)
 
     override fun run() {
+        // determine the source trace file location
         val src = src // allows for smart casts
-        val srcFile: File = when {
+        val srcTraceFile: File = when {
             src != null && src.isFile -> src
-            else -> promptProvideFile("Provide trace source", pattern, src, Paths.outDir.toFile())
+            else -> promptProvideFile(
+                "Provide trace source", pattern,
+                excludePattern = null, src, Paths.outDir.toFile()
+            )
         }
-        check(srcFile.exists() && srcFile.isFile)
+        check(srcTraceFile.exists() && srcTraceFile.isFile)
 
-        val dstFile: File =
-            Paths.savedTracesDir.resolve(dst ?: promptDestinationName(srcFile.name)).toFile()
-        if (dstFile.exists()) promptOverwriteFile(dstFile).let { overwrite ->
+        // copy the source trace file to the destination
+        val dstTraceFile: File =
+            Paths.savedTracesDir.resolve(dst ?: promptDestinationName(srcTraceFile.name)).toFile()
+        if (dstTraceFile.exists()) promptOverwriteFile(dstTraceFile).let { overwrite ->
             if (!overwrite) return
         }
+        dstTraceFile.parentFile.mkdirs() // ensure destination dir is present
+        srcTraceFile.copyTo(dstTraceFile, overwrite = true)
 
-        dstFile.parentFile.mkdirs() // ensure destination dir is present
-        srcFile.copyTo(dstFile, overwrite = true)
+        // Determine the test result file corresponding to the trace (if present). JSON file will
+        // have the trace name in profileResults section. Trace files are guaranteed unique.
+        val srcTestResultFile = srcTraceFile.parentFile.walkTopDown().filter {
+            it.name.lowercase().endsWith("json") && it.readText().contains(srcTraceFile.name)
+        }.singleOrNull()
+
+        // copy the test result file to the destination
+        srcTestResultFile?.let {
+            val dstTestResultFileName = dstTraceFile.nameWithoutExtension + ".json"
+            val dstTestResultFile = dstTraceFile.parentFile.resolve(dstTestResultFileName)
+            // If we are changing the name of the trace file, we also need to reflect that in JSON.
+            val updatedJsonFile = it.readText().replace(srcTraceFile.name, dstTraceFile.name)
+            dstTestResultFile.writeText(updatedJsonFile)
+        }
     }
 
     private fun promptDestinationName(default: String? = null): String =
diff --git a/development/bench-flame-diff/app/src/main/kotlin/bench/flame/diff/ui/Terminal.kt b/development/bench-flame-diff/app/src/main/kotlin/bench/flame/diff/ui/Terminal.kt
index b78f809..e4bd356 100644
--- a/development/bench-flame-diff/app/src/main/kotlin/bench/flame/diff/ui/Terminal.kt
+++ b/development/bench-flame-diff/app/src/main/kotlin/bench/flame/diff/ui/Terminal.kt
@@ -62,7 +62,8 @@
 
 internal fun CliktCommand.promptProvideFile(
     prompt: String,
-    pattern: String = ".*",
+    includePattern: String = ".*",
+    excludePattern: String? = null,
     srcDir: File? = null,
     defaultSrcDir: File? = null
 ): File {
@@ -80,11 +81,20 @@
     }
 
     check(baseDir.isDirectory)
-    echo("Looking for files in '${baseDir.absolutePath}' matching '$pattern'...")
-    val candidates = baseDir.walkTopDown().filter { it.isFile && it.name.matches(Regex(pattern)) }
-        .sortedBy { -it.lastModified() }.withId().toList()
+    echo("Looking for files in '${baseDir.absolutePath}' matching '$includePattern'...")
+    val candidates = baseDir.walkTopDown()
+        .filter { it.isFile }
+        .filter { it.name.matches(Regex(includePattern)) }
+        .filter { if (excludePattern == null) true else !it.name.matches(Regex(excludePattern)) }
+        .sortedBy { -it.lastModified() }
+        .withId()
+        .toList()
 
-    if (candidates.isEmpty()) exitProcessWithError("No files matching '$pattern' in '$baseDir'")
+    if (candidates.isEmpty()) exitProcessWithError(
+        "No files matching '$includePattern'" +
+                (if (excludePattern == null) "" else " (and excluding $excludePattern)") +
+                " in '$baseDir'"
+    )
     return promptPickFile(candidates, baseDir)
 }
 
diff --git a/development/bench-flame-diff/app/src/main/resources/templates/index.html b/development/bench-flame-diff/app/src/main/resources/templates/index.html
index 90ee7c4..fd2899e 100644
--- a/development/bench-flame-diff/app/src/main/resources/templates/index.html
+++ b/development/bench-flame-diff/app/src/main/resources/templates/index.html
@@ -37,6 +37,7 @@
         <div class="spacer">|</div>
         <button class="button" onclick="window.open('http://go/bench-flame-diff-readme')">help</button>
       </div>
+      <div id="results"></div>
       <div id="%before_raw_name%" class="svg">
         <object type="image/svg+xml" data="%before_raw_file%">Failed to display the file: %before_raw_file%</object>
       </div>
@@ -51,6 +52,15 @@
       </div>
     </div>
 
+    <!-- Note: 'application/json' ensures the content is treated as data (i.e. not executed) -->
+    <script type="application/json" id="result-before-raw">
+      %benchmark_result_before_raw%
+    </script>
+
+    <script type="application/json" id="result-after-raw">
+      %benchmark_result_after_raw%
+    </script>
+
     <script>
       mdc.ripple.MDCRipple.attachTo(document.querySelector(".button"));
 
@@ -60,6 +70,31 @@
         document.getElementById(tabName).style.display = "block";
       }
 
+      function populateBenchmarkResult(stage, traceFileName) {
+        const dataString = document.getElementById(`result-${stage}-raw`).textContent.trim()
+        if (!dataString) return // no benchmark result data
+
+        const benchmark = JSON.parse(dataString).benchmarks.find(b =>
+                b.profilerOutputs &&
+                b.profilerOutputs.some(po => po.filename === traceFileName)
+        ) || undefined;
+        if (!benchmark || !benchmark.metrics) return // no benchmark matching the trace file name
+        const metrics = benchmark.metrics
+
+        let outputString = "";
+        Object.entries(metrics).forEach(([metricName, metricResult], ix) => {
+          const {minimum, maximum, median} = metricResult;
+          const resultString = JSON.stringify({minimum, maximum, median});
+          outputString += `${metricName}: ${resultString} `;
+          if (ix !== metrics.length - 1) outputString += " | "
+        })
+        document.querySelector(`#results`).innerHTML += "<div><span>" +
+                `${stage}: <code>${outputString}</code>` +
+                "</span></div>"
+      }
+
+      populateBenchmarkResult("before", "%before_trace_file_name%")
+      populateBenchmarkResult("after", "%after_trace_file_name%")
       openTab("%after_diff_name%");
     </script>
   </body>
diff --git a/development/build_log_simplifier/messages.ignore b/development/build_log_simplifier/messages.ignore
index e00a5f7..840b4f0 100644
--- a/development/build_log_simplifier/messages.ignore
+++ b/development/build_log_simplifier/messages.ignore
@@ -245,6 +245,8 @@
 WARN: .*\/unzippedJvmSources\/androidx\/cursoradapter\/widget\/ResourceCursorAdapter\.java:UnknownLine Missing @param tag for parameter `c` in DFunction ResourceCursorAdapter
 WARN: .*\/unzippedJvmSources\/androidx\/customview\/poolingcontainer\/PoolingContainer\.kt:[0-9]+ Missing @param tag for parameter `listener` in DFunction addPoolingContainerListener
 WARN: .*\/unzippedJvmSources\/androidx\/customview\/widget\/ViewDragHelper\.java:[0-9]+ Missing @param tag for parameter `pointerId` in DFunction isEdgeTouched
+WARN: \$OUT_DIR/androidx/docs\-public/build/unzippedJvmSources/commonJvmMain/androidx/datastore/core/Serializer\.kt:[0-9]+ Missing @param tag for parameter `output` in DFunction writeTo
+WARN: \$OUT_DIR/androidx/docs\-public/build/unzippedJvmSources/commonMain/androidx/datastore/preferences/core/Preferences\.kt:[0-9]+ Missing @param tag for parameter `value` in DFunction set
 WARN: .*\/unzippedJvmSources\/androidx\/datastore\/rxjava2\/RxDataStoreDelegate\.kt:UnknownLine Missing @param tag for parameter `serializer` in DFunction rxDataStore
 WARN: .*\/unzippedJvmSources\/androidx\/datastore\/rxjava3\/RxDataStoreDelegate\.kt:UnknownLine Missing @param tag for parameter `serializer` in DFunction rxDataStore
 WARN: .*\/unzippedJvmSources\/androidx\/documentfile\/provider\/DocumentFile\.java:[0-9]+ Missing @param tag for parameter `context` in DFunction fromSingleUri
@@ -285,7 +287,6 @@
 WARN: .*\/unzippedJvmSources\/androidx\/paging\/compose\/LazyPagingItems\.kt:[0-9]+ Failed to resolve See PagingSource\.invalidate in DFunction refresh\. Did you mean PagingSource#invalidate\?
 WARN: .*\/unzippedJvmSources\/androidx\/paging\/LoadStateAdapter\.kt:[0-9]+ Missing @param tag for parameter `holder` in DFunction onBindViewHolder
 WARN: .*\/unzippedJvmSources\/androidx\/palette\/graphics\/Palette\.java:[0-9]+ Missing @param tag for parameter `target` in DFunction getColorForTarget
-WARN\: \$OUT_DIR\/androidx\/docs\-tip\-of\-tree\/build\/unzippedMultiplatformSources\/nativeMain\/androidx\/room\/RoomDatabase\.native\.kt\:UnknownLine Link does not resolve for \@throws kotlin\.IllegalArgumentException in DFunction valueOf\. Is it from a package that the containing file does not import\? Are docs inherited by an un\-documented override function\, but the exception class is not in scope in the inheriting class\? The general fix for these is to fully qualify the exception name\, e\.g\. \`\@throws java\.io\.IOException under some conditions\`\.
 WARN: .*\/unzippedJvmSources\/androidx\/recyclerview\/widget\/BatchingListUpdateCallback\.java:[0-9]+ Missing @param tag for parameter `payload` in DFunction onChanged
 WARN: .*\/unzippedJvmSources\/androidx\/recyclerview\/widget\/DefaultItemAnimator\.java:[0-9]+ Missing @param tag for parameter `fromX` in DFunction animateMove
 WARN: .*\/unzippedJvmSources\/androidx\/recyclerview\/widget\/DefaultItemAnimator\.java:[0-9]+ Missing @param tag for parameter `fromY` in DFunction animateMove
@@ -503,12 +504,10 @@
 WARN: .*\/unzippedMultiplatformSources\/jvmMain\/androidx\/datastore\/core\/Serializer\.kt:[0-9]+ Missing @param tag for parameter `output` in DFunction writeTo
 WARN: .*\/unzippedMultiplatformSources\/commonJvmMain\/androidx\/datastore\/core\/Serializer\.kt:[0-9]+ Missing @param tag for parameter `output` in DFunction writeTo
 WARN: .*\/unzippedMultiplatformSources\/nonJvmMain\/androidx\/annotation\/RestrictTo\.nonJvm\.kt:UnknownLine Link does not resolve for @throws kotlin\.IllegalArgumentException in DFunction valueOf\. Is it from a package that the containing file does not import\? Are docs inherited by an un-documented override function, but the exception class is not in scope in the inheriting class\? The general fix for these is to fully qualify the exception name, e\.g\. `@throws java\.io\.IOException under some conditions`\.
+WARN: .*\/unzippedMultiplatformSources\/.*Main\/androidx\/room\/RoomDatabase.*\.kt:UnknownLine Link does not resolve for @throws kotlin\.IllegalArgumentException in DFunction valueOf\. Is it from a package that the containing file does not import\? Are docs inherited by an un-documented override function, but the exception class is not in scope in the inheriting class\? The general fix for these is to fully qualify the exception name, e\.g\. `@throws java\.io\.IOException under some conditions`\.
 WARN: File location could not be determined\. Failed to resolve See <a href="https:\/\/developer\.android\.com\/training\/transitions">Transition API Guide<\/a> in DPackage androidx\.transition
-# Task docs-*:unzipJvmSources
-# paging and wear have multiple libraries depending on the same samples library, which can cause the samples library to be unzipped multiple times
-Encountered duplicate path "androidx/paging/samples/.*
-Encountered duplicate path "androidx/wear/compose/material/samples/.*
-Encountered duplicate path "androidx/wear/watchface/samples/.*
+[0-9]+ cpus, so not storing build metrics.
+64 cpus, so storing build metrics.
 # > Task :compose:ui:ui-tooling:processDebugAndroidTestManifest
 \$SUPPORT/compose/ui/ui\-tooling/src/androidInstrumentedTest/AndroidManifest\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
 # ./gradlew tasks warns as we have warnings present
@@ -608,4 +607,4 @@
 # > Task :room:integration-tests:room-testapp-multiplatform:ksp.*
 i: \[ksp\] loaded provider\(s\): \[androidx\.room\.RoomKspProcessor\$Provider\]
 # buildPrivacySandboxSdkApksForDebug (b/329101823)
-Extracted sandbox SDK APK for.*
+Extracted sandbox SDK APK for.*
\ No newline at end of file
diff --git a/docs-public/build.gradle b/docs-public/build.gradle
index 7a6119e..e1972be 100644
--- a/docs-public/build.gradle
+++ b/docs-public/build.gradle
@@ -15,15 +15,14 @@
 }
 
 dependencies {
-    docs("androidx.activity:activity:1.9.0-rc01")
-    docs("androidx.activity:activity-compose:1.9.0-rc01")
-    samples("androidx.activity:activity-compose-samples:1.9.0-rc01")
-    docs("androidx.activity:activity-ktx:1.9.0-rc01")
+    docs("androidx.activity:activity:1.9.0")
+    docs("androidx.activity:activity-compose:1.9.0")
+    docs("androidx.activity:activity-ktx:1.9.0")
     // ads-identifier is deprecated
     docsWithoutApiSince("androidx.ads:ads-identifier:1.0.0-alpha05")
     docsWithoutApiSince("androidx.ads:ads-identifier-common:1.0.0-alpha05")
     docsWithoutApiSince("androidx.ads:ads-identifier-provider:1.0.0-alpha05")
-    kmpDocs("androidx.annotation:annotation:1.8.0-beta01")
+    kmpDocs("androidx.annotation:annotation:1.8.0-beta02")
     docs("androidx.annotation:annotation-experimental:1.4.1")
     docs("androidx.appcompat:appcompat:1.7.0-alpha03")
     docs("androidx.appcompat:appcompat-resources:1.7.0-alpha03")
@@ -39,94 +38,87 @@
     docs("androidx.asynclayoutinflater:asynclayoutinflater:1.1.0-alpha01")
     docs("androidx.asynclayoutinflater:asynclayoutinflater-appcompat:1.1.0-alpha01")
     docs("androidx.autofill:autofill:1.3.0-alpha01")
-    docs("androidx.benchmark:benchmark-common:1.3.0-alpha02")
-    docs("androidx.benchmark:benchmark-junit4:1.3.0-alpha02")
-    docs("androidx.benchmark:benchmark-macro:1.3.0-alpha02")
-    docs("androidx.benchmark:benchmark-macro-junit4:1.3.0-alpha02")
+    docs("androidx.benchmark:benchmark-common:1.3.0-alpha03")
+    docs("androidx.benchmark:benchmark-junit4:1.3.0-alpha03")
+    docs("androidx.benchmark:benchmark-macro:1.3.0-alpha03")
+    docs("androidx.benchmark:benchmark-macro-junit4:1.3.0-alpha03")
     docs("androidx.biometric:biometric:1.2.0-alpha05")
     docs("androidx.biometric:biometric-ktx:1.2.0-alpha05")
     samples("androidx.biometric:biometric-ktx-samples:1.2.0-alpha05")
     docs("androidx.bluetooth:bluetooth:1.0.0-alpha02")
     docs("androidx.bluetooth:bluetooth-testing:1.0.0-alpha02")
     docs("androidx.browser:browser:1.8.0")
-    docs("androidx.camera:camera-camera2:1.4.0-alpha04")
-    docs("androidx.camera:camera-core:1.4.0-alpha04")
-    docs("androidx.camera:camera-effects:1.4.0-alpha04")
-    docs("androidx.camera:camera-extensions:1.4.0-alpha04")
+    docs("androidx.camera:camera-camera2:1.4.0-alpha05")
+    docs("androidx.camera:camera-core:1.4.0-alpha05")
+    docs("androidx.camera:camera-effects:1.4.0-alpha05")
+    docs("androidx.camera:camera-extensions:1.4.0-alpha05")
     stubs(fileTree(dir: "../camera/camera-extensions-stub", include: ["camera-extensions-stub.jar"]))
     docs("androidx.camera:camera-lifecycle:1.4.0-alpha04")
-    docs("androidx.camera:camera-mlkit-vision:1.4.0-alpha04")
-    docs("androidx.camera:camera-video:1.4.0-alpha04")
-    docs("androidx.camera:camera-view:1.4.0-alpha04")
-    docs("androidx.camera:camera-viewfinder:1.4.0-alpha04")
+    docs("androidx.camera:camera-mlkit-vision:1.4.0-alpha05")
+    docs("androidx.camera:camera-video:1.4.0-alpha05")
+    docs("androidx.camera:camera-view:1.4.0-alpha05")
+    docs("androidx.camera:camera-viewfinder:1.4.0-alpha05")
     docs("androidx.camera:camera-viewfinder-compose:1.4.0-alpha03")
-    docs("androidx.camera:camera-viewfinder-core:1.4.0-alpha04")
-    samples("androidx.camera:camera-viewfinder-core-samples:1.4.0-alpha04")
-    docs("androidx.car.app:app:1.7.0-alpha01")
-    docs("androidx.car.app:app-automotive:1.7.0-alpha01")
-    docs("androidx.car.app:app-projected:1.7.0-alpha01")
-    docs("androidx.car.app:app-testing:1.7.0-alpha01")
+    docs("androidx.camera:camera-viewfinder-core:1.4.0-alpha05")
+    docs("androidx.car.app:app:1.7.0-alpha02")
+    docs("androidx.car.app:app-automotive:1.7.0-alpha02")
+    docs("androidx.car.app:app-projected:1.7.0-alpha02")
+    docs("androidx.car.app:app-testing:1.7.0-alpha02")
     docs("androidx.cardview:cardview:1.0.0")
     kmpDocs("androidx.collection:collection:1.4.0")
     docs("androidx.collection:collection-ktx:1.4.0-rc01")
-    kmpDocs("androidx.compose.animation:animation:1.7.0-alpha06")
-    kmpDocs("androidx.compose.animation:animation-core:1.7.0-alpha06")
-    kmpDocs("androidx.compose.animation:animation-graphics:1.7.0-alpha06")
-    samples("androidx.compose.animation:animation-samples:1.7.0-alpha06")
-    samples("androidx.compose.animation:animation-core-samples:1.7.0-alpha06")
-    samples("androidx.compose.animation:animation-graphics-samples:1.7.0-alpha06")
-    kmpDocs("androidx.compose.foundation:foundation:1.7.0-alpha06")
-    kmpDocs("androidx.compose.foundation:foundation-layout:1.7.0-alpha06")
-    samples("androidx.compose.foundation:foundation-layout-samples:1.7.0-alpha06")
-    samples("androidx.compose.foundation:foundation-samples:1.7.0-alpha06")
-    kmpDocs("androidx.compose.material3.adaptive:adaptive:1.0.0-alpha10")
-    kmpDocs("androidx.compose.material3.adaptive:adaptive-layout:1.0.0-alpha10")
-    docs("androidx.compose.material3.adaptive:adaptive-navigation:1.0.0-alpha10")
-    samples("androidx.compose.material3.adaptive:adaptive-samples:1.0.0-alpha10")
-    kmpDocs("androidx.compose.material3:material3:1.3.0-alpha04")
-    kmpDocs("androidx.compose.material3:material3-adaptive-navigation-suite:1.0.0-alpha05")
+    kmpDocs("androidx.compose.animation:animation:1.7.0-alpha07")
+    kmpDocs("androidx.compose.animation:animation-core:1.7.0-alpha07")
+    kmpDocs("androidx.compose.animation:animation-graphics:1.7.0-alpha07")
+    samples("androidx.compose.animation:animation-samples:1.7.0-alpha07")
+    samples("androidx.compose.animation:animation-core-samples:1.7.0-alpha07")
+    samples("androidx.compose.animation:animation-graphics-samples:1.7.0-alpha07")
+    kmpDocs("androidx.compose.foundation:foundation:1.7.0-alpha07")
+    kmpDocs("androidx.compose.foundation:foundation-layout:1.7.0-alpha07")
+    samples("androidx.compose.foundation:foundation-layout-samples:1.7.0-alpha07")
+    samples("androidx.compose.foundation:foundation-samples:1.7.0-alpha07")
+    kmpDocs("androidx.compose.material3.adaptive:adaptive:1.0.0-alpha11")
+    kmpDocs("androidx.compose.material3.adaptive:adaptive-layout:1.0.0-alpha11")
+    kmpDocs("androidx.compose.material3.adaptive:adaptive-navigation:1.0.0-alpha11")
+    samples("androidx.compose.material3.adaptive:adaptive-samples:1.0.0-alpha11")
+    kmpDocs("androidx.compose.material3:material3:1.3.0-alpha05")
+    kmpDocs("androidx.compose.material3:material3-adaptive-navigation-suite:1.0.0-alpha06")
     samples("androidx.compose.material3:material3-adaptive-navigation-suite-samples:1.3.0-alpha04")
     docs("androidx.compose.material3:material3-common:1.0.0-alpha01")
-    samples("androidx.compose.material3:material3-samples:1.3.0-alpha04")
-    kmpDocs("androidx.compose.material3:material3-window-size-class:1.3.0-alpha04")
+    samples("androidx.compose.material3:material3-common-samples:1.3.0-alpha05")
+    samples("androidx.compose.material3:material3-samples:1.3.0-alpha05")
+    kmpDocs("androidx.compose.material3:material3-window-size-class:1.3.0-alpha05")
     samples("androidx.compose.material3:material3-window-size-class-samples:1.3.0-alpha04")
-    kmpDocs("androidx.compose.material:material:1.7.0-alpha06")
-    kmpDocs("androidx.compose.material:material-icons-core:1.7.0-alpha06")
-    samples("androidx.compose.material:material-icons-core-samples:1.7.0-alpha06")
-    docs("androidx.compose.material:material-navigation:1.7.0-alpha06")
-    samples("androidx.compose.material:material-navigation-samples:1.7.0-alpha06")
-    kmpDocs("androidx.compose.material:material-ripple:1.7.0-alpha06")
-    samples("androidx.compose.material:material-samples:1.7.0-alpha06")
-    kmpDocs("androidx.compose.runtime:runtime:1.7.0-alpha06")
-    docs("androidx.compose.runtime:runtime-livedata:1.7.0-alpha06")
-    samples("androidx.compose.runtime:runtime-livedata-samples:1.7.0-alpha06")
-    docs("androidx.compose.runtime:runtime-rxjava2:1.7.0-alpha06")
-    samples("androidx.compose.runtime:runtime-rxjava2-samples:1.7.0-alpha06")
-    docs("androidx.compose.runtime:runtime-rxjava3:1.7.0-alpha06")
-    samples("androidx.compose.runtime:runtime-rxjava3-samples:1.7.0-alpha06")
-    kmpDocs("androidx.compose.runtime:runtime-saveable:1.7.0-alpha06")
-    samples("androidx.compose.runtime:runtime-saveable-samples:1.7.0-alpha06")
-    samples("androidx.compose.runtime:runtime-samples:1.7.0-alpha06")
+    kmpDocs("androidx.compose.material:material:1.7.0-alpha07")
+    kmpDocs("androidx.compose.material:material-icons-core:1.7.0-alpha07")
+    samples("androidx.compose.material:material-icons-core-samples:1.7.0-alpha07")
+    docs("androidx.compose.material:material-navigation:1.7.0-alpha07")
+    samples("androidx.compose.material:material-navigation-samples:1.7.0-alpha07")
+    kmpDocs("androidx.compose.material:material-ripple:1.7.0-alpha07")
+    kmpDocs("androidx.compose.runtime:runtime:1.7.0-alpha07")
+    docs("androidx.compose.runtime:runtime-livedata:1.7.0-alpha07")
+    docs("androidx.compose.runtime:runtime-rxjava2:1.7.0-alpha07")
+    docs("androidx.compose.runtime:runtime-rxjava3:1.7.0-alpha07")
+    kmpDocs("androidx.compose.runtime:runtime-saveable:1.7.0-alpha07")
     docs("androidx.compose.runtime:runtime-tracing:1.0.0-beta01")
-    kmpDocs("androidx.compose.ui:ui:1.7.0-alpha06")
-    kmpDocs("androidx.compose.ui:ui-geometry:1.7.0-alpha06")
-    kmpDocs("androidx.compose.ui:ui-graphics:1.7.0-alpha06")
-    samples("androidx.compose.ui:ui-graphics-samples:1.7.0-alpha06")
-    kmpDocs("androidx.compose.ui:ui-test:1.7.0-alpha06")
-    kmpDocs("androidx.compose.ui:ui-test-junit4:1.7.0-alpha06")
-    samples("androidx.compose.ui:ui-test-samples:1.7.0-alpha06")
-    kmpDocs("androidx.compose.ui:ui-text:1.7.0-alpha06")
-    docs("androidx.compose.ui:ui-text-google-fonts:1.7.0-alpha06")
-    samples("androidx.compose.ui:ui-text-samples:1.7.0-alpha06")
-    kmpDocs("androidx.compose.ui:ui-tooling:1.7.0-alpha06")
-    kmpDocs("androidx.compose.ui:ui-tooling-data:1.7.0-alpha06")
-    kmpDocs("androidx.compose.ui:ui-tooling-preview:1.7.0-alpha06")
-    kmpDocs("androidx.compose.ui:ui-unit:1.7.0-alpha06")
-    samples("androidx.compose.ui:ui-unit-samples:1.7.0-alpha06")
-    kmpDocs("androidx.compose.ui:ui-util:1.7.0-alpha06")
-    docs("androidx.compose.ui:ui-viewbinding:1.7.0-alpha06")
-    samples("androidx.compose.ui:ui-viewbinding-samples:1.7.0-alpha06")
-    samples("androidx.compose.ui:ui-samples:1.7.0-alpha06")
+    kmpDocs("androidx.compose.ui:ui:1.7.0-alpha07")
+    docs("androidx.compose.ui:ui-android-stubs:1.7.0-alpha07")
+    kmpDocs("androidx.compose.ui:ui-geometry:1.7.0-alpha07")
+    kmpDocs("androidx.compose.ui:ui-graphics:1.7.0-alpha07")
+    samples("androidx.compose.ui:ui-graphics-samples:1.7.0-alpha07")
+    kmpDocs("androidx.compose.ui:ui-test:1.7.0-alpha07")
+    kmpDocs("androidx.compose.ui:ui-test-junit4:1.7.0-alpha07")
+    samples("androidx.compose.ui:ui-test-samples:1.7.0-alpha07")
+    kmpDocs("androidx.compose.ui:ui-text:1.7.0-alpha07")
+    docs("androidx.compose.ui:ui-text-google-fonts:1.7.0-alpha07")
+    samples("androidx.compose.ui:ui-text-samples:1.7.0-alpha07")
+    kmpDocs("androidx.compose.ui:ui-tooling:1.7.0-alpha07")
+    kmpDocs("androidx.compose.ui:ui-tooling-data:1.7.0-alpha07")
+    kmpDocs("androidx.compose.ui:ui-tooling-preview:1.7.0-alpha07")
+    kmpDocs("androidx.compose.ui:ui-unit:1.7.0-alpha07")
+    kmpDocs("androidx.compose.ui:ui-util:1.7.0-alpha07")
+    docs("androidx.compose.ui:ui-viewbinding:1.7.0-alpha07")
+    samples("androidx.compose.ui:ui-samples:1.7.0-alpha07")
     docs("androidx.concurrent:concurrent-futures:1.2.0-alpha03")
     docs("androidx.concurrent:concurrent-futures-ktx:1.2.0-alpha03")
     docs("androidx.constraintlayout:constraintlayout:2.2.0-alpha13")
@@ -146,31 +138,31 @@
     docs("androidx.core:core-performance-play-services:1.0.0")
     samples("androidx.core:core-performance-samples:1.0.0")
     docs("androidx.core:core-performance-testing:1.0.0")
-    docs("androidx.core:core-remoteviews:1.1.0-beta01")
+    docs("androidx.core:core-remoteviews:1.1.0-beta02")
     docs("androidx.core:core-role:1.2.0-alpha01")
-    docs("androidx.core:core-splashscreen:1.1.0-alpha02")
-    docs("androidx.core:core-telecom:1.0.0-alpha02")
+    docs("androidx.core:core-splashscreen:1.2.0-alpha01")
+    docs("androidx.core:core-telecom:1.0.0-alpha03")
     docs("androidx.core:core-testing:1.13.0")
     docs("androidx.core.uwb:uwb:1.0.0-alpha08")
     docs("androidx.core.uwb:uwb-rxjava3:1.0.0-alpha08")
-    docs("androidx.credentials:credentials:1.3.0-alpha02")
-    docs("androidx.credentials:credentials-e2ee:1.0.0-alpha01")
+    docs("androidx.credentials:credentials:1.3.0-alpha03")
+    docs("androidx.credentials:credentials-e2ee:1.0.0-alpha02")
     docs("androidx.credentials:credentials-fido:1.0.0-alpha02")
-    docs("androidx.credentials:credentials-play-services-auth:1.3.0-alpha02")
-    samples("androidx.credentials:credentials-samples:1.3.0-alpha02")
+    docs("androidx.credentials:credentials-play-services-auth:1.3.0-alpha03")
+    samples("androidx.credentials:credentials-samples:1.3.0-alpha03")
     docs("androidx.cursoradapter:cursoradapter:1.0.0")
     docs("androidx.customview:customview:1.2.0-alpha02")
     // TODO(b/294531403): Turn on apiSince for customview-poolingcontainer when it releases as alpha
     docsWithoutApiSince("androidx.customview:customview-poolingcontainer:1.0.0-rc01")
-    kmpDocs("androidx.datastore:datastore:1.1.0-rc01")
-    kmpDocs("androidx.datastore:datastore-core:1.1.0-rc01")
-    kmpDocs("androidx.datastore:datastore-core-okio:1.1.0-rc01")
-    kmpDocs("androidx.datastore:datastore-preferences:1.1.0-rc01")
-    kmpDocs("androidx.datastore:datastore-preferences-core:1.1.0-rc01")
-    docs("androidx.datastore:datastore-preferences-rxjava2:1.1.0-rc01")
-    docs("androidx.datastore:datastore-preferences-rxjava3:1.1.0-rc01")
-    docs("androidx.datastore:datastore-rxjava2:1.1.0-rc01")
-    docs("androidx.datastore:datastore-rxjava3:1.1.0-rc01")
+    docs("androidx.datastore:datastore:1.1.0")
+    docs("androidx.datastore:datastore-core:1.1.0")
+    docs("androidx.datastore:datastore-core-okio:1.1.0")
+    docs("androidx.datastore:datastore-preferences:1.1.0")
+    docs("androidx.datastore:datastore-preferences-core:1.1.0")
+    docs("androidx.datastore:datastore-preferences-rxjava2:1.1.0")
+    docs("androidx.datastore:datastore-preferences-rxjava3:1.1.0")
+    docs("androidx.datastore:datastore-rxjava2:1.1.0")
+    docs("androidx.datastore:datastore-rxjava3:1.1.0")
     docs("androidx.documentfile:documentfile:1.1.0-alpha01")
     docs("androidx.draganddrop:draganddrop:1.0.0")
     docs("androidx.drawerlayout:drawerlayout:1.2.0")
@@ -187,25 +179,22 @@
     docs("androidx.enterprise:enterprise-feedback:1.1.0")
     docs("androidx.enterprise:enterprise-feedback-testing:1.1.0")
     docs("androidx.exifinterface:exifinterface:1.3.6")
-    docs("androidx.fragment:fragment:1.8.0-alpha01")
-    docs("androidx.fragment:fragment-compose:1.8.0-alpha01")
-    samples("androidx.fragment:fragment-compose-samples:1.8.0-alpha01")
-    docs("androidx.fragment:fragment-ktx:1.8.0-alpha01")
-    docs("androidx.fragment:fragment-testing:1.8.0-alpha01")
-    docs("androidx.glance:glance:1.1.0-beta01")
-    docs("androidx.glance:glance-appwidget:1.1.0-beta01")
-    samples("androidx.glance:glance-appwidget-samples:1.1.0-beta01")
+    docs("androidx.fragment:fragment:1.8.0-alpha02")
+    docs("androidx.fragment:fragment-compose:1.8.0-alpha02")
+    docs("androidx.fragment:fragment-ktx:1.8.0-alpha02")
+    docs("androidx.fragment:fragment-testing:1.8.0-alpha02")
+    docs("androidx.glance:glance:1.1.0-beta02")
+    docs("androidx.glance:glance-appwidget:1.1.0-beta02")
     docs("androidx.glance:glance-appwidget-preview:1.0.0-alpha06")
-    docs("androidx.glance:glance-appwidget-testing:1.1.0-beta01")
-    samples("androidx.glance:glance-appwidget-testing-samples:1.1.0-beta01")
-    docs("androidx.glance:glance-material:1.1.0-beta01")
-    docs("androidx.glance:glance-material3:1.1.0-beta01")
+    docs("androidx.glance:glance-appwidget-testing:1.1.0-beta02")
+    docs("androidx.glance:glance-material:1.1.0-beta02")
+    docs("androidx.glance:glance-material3:1.1.0-beta02")
     docs("androidx.glance:glance-preview:1.0.0-alpha06")
     docs("androidx.glance:glance-template:1.0.0-alpha06")
-    docs("androidx.glance:glance-testing:1.1.0-beta01")
+    docs("androidx.glance:glance-testing:1.1.0-beta02")
     docs("androidx.glance:glance-wear-tiles:1.0.0-alpha06")
-    docs("androidx.graphics:graphics-core:1.0.0-beta01")
-    samples("androidx.graphics:graphics-core-samples:1.0.0-beta01")
+    docs("androidx.graphics:graphics-core:1.0.0-rc01")
+    samples("androidx.graphics:graphics-core-samples:1.0.0-rc01")
     docs("androidx.graphics:graphics-path:1.0.0")
     kmpDocs("androidx.graphics:graphics-shapes:1.0.0-alpha05")
     docs("androidx.gridlayout:gridlayout:1.1.0-beta01")
@@ -216,7 +205,6 @@
     docs("androidx.hilt:hilt-common:1.2.0")
     docs("androidx.hilt:hilt-navigation:1.2.0")
     docs("androidx.hilt:hilt-navigation-compose:1.2.0")
-    samples("androidx.hilt:hilt-navigation-compose-samples:1.2.0")
     docs("androidx.hilt:hilt-navigation-fragment:1.2.0")
     docs("androidx.hilt:hilt-work:1.2.0")
     docs("androidx.input:input-motionprediction:1.0.0-beta03")
@@ -227,27 +215,26 @@
     docs("androidx.leanback:leanback-paging:1.1.0-alpha11")
     docs("androidx.leanback:leanback-preference:1.2.0-alpha04")
     docs("androidx.leanback:leanback-tab:1.1.0-beta01")
-    kmpDocs("androidx.lifecycle:lifecycle-common:2.8.0-alpha04")
-    docs("androidx.lifecycle:lifecycle-common-java8:2.8.0-alpha04")
+    kmpDocs("androidx.lifecycle:lifecycle-common:2.8.0-beta01")
+    docs("androidx.lifecycle:lifecycle-common-java8:2.8.0-beta01")
     docs("androidx.lifecycle:lifecycle-extensions:2.2.0")
-    docs("androidx.lifecycle:lifecycle-livedata:2.8.0-alpha04")
-    docs("androidx.lifecycle:lifecycle-livedata-core:2.8.0-alpha04")
-    docs("androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.0-alpha04")
-    docs("androidx.lifecycle:lifecycle-livedata-ktx:2.8.0-alpha04")
-    docs("androidx.lifecycle:lifecycle-process:2.8.0-alpha04")
-    docs("androidx.lifecycle:lifecycle-reactivestreams:2.8.0-alpha04")
-    docs("androidx.lifecycle:lifecycle-reactivestreams-ktx:2.8.0-alpha04")
-    kmpDocs("androidx.lifecycle:lifecycle-runtime:2.8.0-alpha04")
-    docs("androidx.lifecycle:lifecycle-runtime-compose:2.8.0-alpha04")
-    samples("androidx.lifecycle:lifecycle-runtime-compose-samples:2.8.0-alpha04")
-    kmpDocs("androidx.lifecycle:lifecycle-runtime-ktx:2.8.0-alpha04")
-    docs("androidx.lifecycle:lifecycle-runtime-testing:2.8.0-alpha04")
-    docs("androidx.lifecycle:lifecycle-service:2.8.0-alpha04")
-    kmpDocs("androidx.lifecycle:lifecycle-viewmodel:2.8.0-alpha04")
-    docs("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.0-alpha04")
-    samples("androidx.lifecycle:lifecycle-viewmodel-compose-samples:2.8.0-alpha04")
-    docs("androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.0-alpha04")
-    docs("androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.0-alpha04")
+    docs("androidx.lifecycle:lifecycle-livedata:2.8.0-beta01")
+    docs("androidx.lifecycle:lifecycle-livedata-core:2.8.0-beta01")
+    docs("androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.0-beta01")
+    docs("androidx.lifecycle:lifecycle-livedata-ktx:2.8.0-beta01")
+    docs("androidx.lifecycle:lifecycle-process:2.8.0-beta01")
+    docs("androidx.lifecycle:lifecycle-reactivestreams:2.8.0-beta01")
+    docs("androidx.lifecycle:lifecycle-reactivestreams-ktx:2.8.0-beta01")
+    kmpDocs("androidx.lifecycle:lifecycle-runtime:2.8.0-beta01")
+    kmpDocs("androidx.lifecycle:lifecycle-runtime-compose:2.8.0-beta01")
+    kmpDocs("androidx.lifecycle:lifecycle-runtime-ktx:2.8.0-beta01")
+    docs("androidx.lifecycle:lifecycle-runtime-testing:2.8.0-beta01")
+    docs("androidx.lifecycle:lifecycle-service:2.8.0-beta01")
+    kmpDocs("androidx.lifecycle:lifecycle-viewmodel:2.8.0-beta01")
+    kmpDocs("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.0-beta01")
+    samples("androidx.lifecycle:lifecycle-viewmodel-compose-samples:2.8.0-beta01")
+    docs("androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.0-beta01")
+    docs("androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.0-beta01")
     docs("androidx.loader:loader:1.1.0")
     // localbroadcastmanager is deprecated
     docsWithoutApiSince("androidx.localbroadcastmanager:localbroadcastmanager:1.1.0")
@@ -285,31 +272,29 @@
     docs("androidx.mediarouter:mediarouter:1.7.0")
     docs("androidx.mediarouter:mediarouter-testing:1.7.0")
     docs("androidx.metrics:metrics-performance:1.0.0-beta01")
-    docs("androidx.navigation:navigation-common:2.8.0-alpha06")
-    docs("androidx.navigation:navigation-common-ktx:2.8.0-alpha06")
-    docs("androidx.navigation:navigation-compose:2.8.0-alpha06")
-    samples("androidx.navigation:navigation-compose-samples:2.8.0-alpha06")
-    docs("androidx.navigation:navigation-dynamic-features-fragment:2.8.0-alpha06")
-    docs("androidx.navigation:navigation-dynamic-features-runtime:2.8.0-alpha06")
-    docs("androidx.navigation:navigation-fragment:2.8.0-alpha06")
-    docs("androidx.navigation:navigation-fragment-ktx:2.8.0-alpha06")
-    docs("androidx.navigation:navigation-runtime:2.8.0-alpha06")
-    docs("androidx.navigation:navigation-runtime-ktx:2.8.0-alpha06")
-    docs("androidx.navigation:navigation-testing:2.8.0-alpha06")
-    docs("androidx.navigation:navigation-ui:2.8.0-alpha06")
-    docs("androidx.navigation:navigation-ui-ktx:2.8.0-alpha06")
-    kmpDocs("androidx.paging:paging-common:3.3.0-beta01")
-    docs("androidx.paging:paging-common-ktx:3.3.0-beta01")
-    kmpDocs("androidx.paging:paging-compose:3.3.0-beta01")
-    samples("androidx.paging:paging-compose-samples:3.3.0-beta01")
-    docs("androidx.paging:paging-guava:3.3.0-beta01")
-    docs("androidx.paging:paging-runtime:3.3.0-beta01")
-    docs("androidx.paging:paging-runtime-ktx:3.3.0-beta01")
-    docs("androidx.paging:paging-rxjava2:3.3.0-beta01")
-    docs("androidx.paging:paging-rxjava2-ktx:3.3.0-beta01")
-    docs("androidx.paging:paging-rxjava3:3.3.0-beta01")
-    samples("androidx.paging:paging-samples:3.3.0-beta01")
-    kmpDocs("androidx.paging:paging-testing:3.3.0-beta01")
+    docs("androidx.navigation:navigation-common:2.8.0-alpha07")
+    docs("androidx.navigation:navigation-common-ktx:2.8.0-alpha07")
+    docs("androidx.navigation:navigation-compose:2.8.0-alpha07")
+    docs("androidx.navigation:navigation-dynamic-features-fragment:2.8.0-alpha07")
+    docs("androidx.navigation:navigation-dynamic-features-runtime:2.8.0-alpha07")
+    docs("androidx.navigation:navigation-fragment:2.8.0-alpha07")
+    docs("androidx.navigation:navigation-fragment-compose:2.8.0-alpha07")
+    docs("androidx.navigation:navigation-fragment-ktx:2.8.0-alpha07")
+    docs("androidx.navigation:navigation-runtime:2.8.0-alpha07")
+    docs("androidx.navigation:navigation-runtime-ktx:2.8.0-alpha07")
+    docs("androidx.navigation:navigation-testing:2.8.0-alpha07")
+    docs("androidx.navigation:navigation-ui:2.8.0-alpha07")
+    docs("androidx.navigation:navigation-ui-ktx:2.8.0-alpha07")
+    kmpDocs("androidx.paging:paging-common:3.3.0-rc01")
+    docs("androidx.paging:paging-common-ktx:3.3.0-rc01")
+    kmpDocs("androidx.paging:paging-compose:3.3.0-rc01")
+    docs("androidx.paging:paging-guava:3.3.0-rc01")
+    docs("androidx.paging:paging-runtime:3.3.0-rc01")
+    docs("androidx.paging:paging-runtime-ktx:3.3.0-rc01")
+    docs("androidx.paging:paging-rxjava2:3.3.0-rc01")
+    docs("androidx.paging:paging-rxjava2-ktx:3.3.0-rc01")
+    docs("androidx.paging:paging-rxjava3:3.3.0-rc01")
+    kmpDocs("androidx.paging:paging-testing:3.3.0-rc01")
     docs("androidx.palette:palette:1.0.0")
     docs("androidx.palette:palette-ktx:1.0.0")
     docs("androidx.percentlayout:percentlayout:1.0.1")
@@ -319,8 +304,8 @@
     docs("androidx.privacysandbox.activity:activity-client:1.0.0-alpha01")
     docs("androidx.privacysandbox.activity:activity-core:1.0.0-alpha01")
     docs("androidx.privacysandbox.activity:activity-provider:1.0.0-alpha01")
-    docs("androidx.privacysandbox.ads:ads-adservices:1.1.0-beta05")
-    docs("androidx.privacysandbox.ads:ads-adservices-java:1.1.0-beta05")
+    docs("androidx.privacysandbox.ads:ads-adservices:1.1.0-beta06")
+    docs("androidx.privacysandbox.ads:ads-adservices-java:1.1.0-beta06")
     docs("androidx.privacysandbox.sdkruntime:sdkruntime-client:1.0.0-alpha13")
     docs("androidx.privacysandbox.sdkruntime:sdkruntime-core:1.0.0-alpha13")
     docs("androidx.privacysandbox.sdkruntime:sdkruntime-provider:1.0.0-alpha13")
@@ -393,8 +378,8 @@
     // TODO(243405142) clean-up
     docsWithoutApiSince("androidx.tracing:tracing-perfetto-common:1.0.0-alpha16")
     docs("androidx.tracing:tracing-perfetto-handshake:1.0.0")
-    docs("androidx.transition:transition:1.5.0-rc01")
-    docs("androidx.transition:transition-ktx:1.5.0-rc01")
+    docs("androidx.transition:transition:1.5.0-rc02")
+    docs("androidx.transition:transition-ktx:1.5.0-rc02")
     docs("androidx.tv:tv-foundation:1.0.0-alpha10")
     docs("androidx.tv:tv-material:1.0.0-alpha10")
     samples("androidx.tv:tv-samples:1.0.0-alpha10")
@@ -405,16 +390,13 @@
     docs("androidx.versionedparcelable:versionedparcelable:1.2.0")
     docs("androidx.viewpager2:viewpager2:1.1.0-beta02")
     docs("androidx.viewpager:viewpager:1.1.0-alpha01")
-    docs("androidx.wear.compose:compose-foundation:1.4.0-alpha06")
-    samples("androidx.wear.compose:compose-foundation-samples:1.4.0-alpha06")
-    docs("androidx.wear.compose:compose-material:1.4.0-alpha06")
-    docs("androidx.wear.compose:compose-material-core:1.4.0-alpha06")
-    samples("androidx.wear.compose:compose-material-samples:1.4.0-alpha06")
-    docs("androidx.wear.compose:compose-material3:1.0.0-alpha20")
-    samples("androidx.wear.compose:compose-material3-samples:1.4.0-alpha06")
-    docs("androidx.wear.compose:compose-navigation:1.4.0-alpha06")
-    samples("androidx.wear.compose:compose-navigation-samples:1.4.0-alpha06")
-    docs("androidx.wear.compose:compose-ui-tooling:1.4.0-alpha06")
+    docs("androidx.wear.compose:compose-foundation:1.4.0-alpha07")
+    docs("androidx.wear.compose:compose-material:1.4.0-alpha07")
+    docs("androidx.wear.compose:compose-material-core:1.4.0-alpha07")
+    docs("androidx.wear.compose:compose-material3:1.0.0-alpha21")
+    samples("androidx.wear.compose:compose-material3-samples:1.4.0-alpha07")
+    docs("androidx.wear.compose:compose-navigation:1.4.0-alpha07")
+    docs("androidx.wear.compose:compose-ui-tooling:1.4.0-alpha07")
     docs("androidx.wear.protolayout:protolayout:1.2.0-alpha01")
     docs("androidx.wear.protolayout:protolayout-expression:1.2.0-alpha01")
     docs("androidx.wear.protolayout:protolayout-expression-pipeline:1.2.0-alpha01")
@@ -427,22 +409,19 @@
     docs("androidx.wear.tiles:tiles-testing:1.4.0-alpha01")
     docs("androidx.wear.tiles:tiles-tooling:1.4.0-alpha01")
     docs("androidx.wear.tiles:tiles-tooling-preview:1.4.0-alpha01")
-    docs("androidx.wear.watchface:watchface:1.3.0-alpha02")
-    docs("androidx.wear.watchface:watchface-client:1.3.0-alpha02")
-    docs("androidx.wear.watchface:watchface-client-guava:1.3.0-alpha02")
-    docs("androidx.wear.watchface:watchface-complications:1.3.0-alpha02")
-    docs("androidx.wear.watchface:watchface-complications-data:1.3.0-alpha02")
-    docs("androidx.wear.watchface:watchface-complications-data-source:1.3.0-alpha02")
-    docs("androidx.wear.watchface:watchface-complications-data-source-ktx:1.3.0-alpha02")
-    samples("androidx.wear.watchface:watchface-complications-permission-dialogs-sample:1.3.0-alpha02")
-    docs("androidx.wear.watchface:watchface-complications-rendering:1.3.0-alpha02")
-    docs("androidx.wear.watchface:watchface-data:1.3.0-alpha02")
-    docs("androidx.wear.watchface:watchface-editor:1.3.0-alpha02")
-    docs("androidx.wear.watchface:watchface-editor-guava:1.3.0-alpha02")
-    samples("androidx.wear.watchface:watchface-editor-samples:1.3.0-alpha02")
-    docs("androidx.wear.watchface:watchface-guava:1.3.0-alpha02")
-    samples("androidx.wear.watchface:watchface-samples:1.3.0-alpha02")
-    docs("androidx.wear.watchface:watchface-style:1.3.0-alpha02")
+    docs("androidx.wear.watchface:watchface:1.3.0-alpha03")
+    docs("androidx.wear.watchface:watchface-client:1.3.0-alpha03")
+    docs("androidx.wear.watchface:watchface-client-guava:1.3.0-alpha03")
+    docs("androidx.wear.watchface:watchface-complications:1.3.0-alpha03")
+    docs("androidx.wear.watchface:watchface-complications-data:1.3.0-alpha03")
+    docs("androidx.wear.watchface:watchface-complications-data-source:1.3.0-alpha03")
+    docs("androidx.wear.watchface:watchface-complications-data-source-ktx:1.3.0-alpha03")
+    docs("androidx.wear.watchface:watchface-complications-rendering:1.3.0-alpha03")
+    docs("androidx.wear.watchface:watchface-data:1.3.0-alpha03")
+    docs("androidx.wear.watchface:watchface-editor:1.3.0-alpha03")
+    docs("androidx.wear.watchface:watchface-editor-guava:1.3.0-alpha03")
+    docs("androidx.wear.watchface:watchface-guava:1.3.0-alpha03")
+    docs("androidx.wear.watchface:watchface-style:1.3.0-alpha03")
     docs("androidx.wear:wear:1.4.0-alpha01")
     stubs(fileTree(dir: "../wear/wear_stubs/", include: ["com.google.android.wearable-stubs.jar"]))
     docs("androidx.wear:wear-input:1.2.0-alpha02")
@@ -454,7 +433,7 @@
     docs("androidx.wear:wear-remote-interactions:1.1.0-alpha02")
     samples("androidx.wear:wear-remote-interactions-samples:1.1.0-alpha02")
     docs("androidx.wear:wear-tooling-preview:1.0.0")
-    docs("androidx.webkit:webkit:1.11.0-rc01")
+    docs("androidx.webkit:webkit:1.12.0-alpha01")
     docs("androidx.window.extensions.core:core:1.0.0")
     docs("androidx.window:window:1.3.0-beta01")
     stubs(fileTree(dir: "../window/stubs/", include: ["window-sidecar-release-0.1.0-alpha01.aar"]))
@@ -465,16 +444,13 @@
     docs("androidx.window:window-rxjava3:1.3.0-beta01")
     samples("androidx.window:window-samples:1.3.0-beta01")
     docs("androidx.window:window-testing:1.3.0-beta01")
-    docs("androidx.work:work-gcm:2.10.0-alpha01")
-    docs("androidx.work:work-multiprocess:2.10.0-alpha01")
-    docs("androidx.work:work-runtime:2.10.0-alpha01")
-    docs("androidx.work:work-runtime-ktx:2.10.0-alpha01")
-    docs("androidx.work:work-rxjava2:2.10.0-alpha01")
-    docs("androidx.work:work-rxjava3:2.10.0-alpha01")
-    docs("androidx.work:work-testing:2.10.0-alpha01")
-
-    // Force upgrade to jsoup 1.16.2 (b/309773103)
-    stubs("org.jsoup:jsoup:1.16.2")
+    docs("androidx.work:work-gcm:2.10.0-alpha02")
+    docs("androidx.work:work-multiprocess:2.10.0-alpha02")
+    docs("androidx.work:work-runtime:2.10.0-alpha02")
+    docs("androidx.work:work-runtime-ktx:2.10.0-alpha02")
+    docs("androidx.work:work-rxjava2:2.10.0-alpha02")
+    docs("androidx.work:work-rxjava3:2.10.0-alpha02")
+    docs("androidx.work:work-testing:2.10.0-alpha02")
 }
 
 afterEvaluate {
diff --git a/docs-tip-of-tree/build.gradle b/docs-tip-of-tree/build.gradle
index fd5648d..96f3018 100644
--- a/docs-tip-of-tree/build.gradle
+++ b/docs-tip-of-tree/build.gradle
@@ -17,16 +17,17 @@
 }
 
 dependencies {
+    // If there is not at least one samples dependency, DocsImplPlugin breaks. b/332262321
+    samples("androidx.window:window-samples:1.3.0-alpha03")
+
     docsForOptionalProject(":xr:xr")
     docs(project(":activity:activity"))
     docs(project(":activity:activity-compose"))
-    samples(project(":activity:activity-compose:activity-compose-samples"))
     docs(project(":activity:activity-ktx"))
     // ads-identifier is deprecated
     kmpDocs(project(":annotation:annotation"))
     docs(project(":annotation:annotation-experimental"))
     docs(project(":appactions:builtintypes:builtintypes"))
-    samples(project(":appactions:builtintypes:builtintypes:builtintypes-samples"))
     docs(project(":appactions:interaction:interaction-capabilities-communication"))
     docs(project(":appactions:interaction:interaction-capabilities-core"))
     docs(project(":appactions:interaction:interaction-capabilities-productivity"))
@@ -56,7 +57,6 @@
     docs(project(":benchmark:benchmark-macro-junit4"))
     docs(project(":biometric:biometric"))
     docs(project(":biometric:biometric-ktx"))
-    samples(project(":biometric:biometric-ktx-samples"))
     docs(project(":bluetooth:bluetooth"))
     docs(project(":bluetooth:bluetooth-testing"))
     docs(project(":browser:browser"))
@@ -75,75 +75,49 @@
     docs(project(":camera:camera-viewfinder"))
     docs(project(":camera:camera-viewfinder-compose"))
     docs(project(":camera:camera-viewfinder-core"))
-    samples(project(":camera:camera-viewfinder-core:camera-viewfinder-core-samples"))
     docs(project(":car:app:app"))
     docs(project(":car:app:app-automotive"))
     docs(project(":car:app:app-projected"))
     docs(project(":car:app:app-testing"))
-    samples(project(":car:app:app-samples:navigation-common"))
     docs(project(":cardview:cardview"))
     kmpDocs(project(":collection:collection"))
     docs(project(":collection:collection-ktx"))
     kmpDocs(project(":compose:animation:animation"))
     kmpDocs(project(":compose:animation:animation-core"))
     kmpDocs(project(":compose:animation:animation-graphics"))
-    samples(project(":compose:animation:animation-core:animation-core-samples"))
-    samples(project(":compose:animation:animation:animation-samples"))
-    samples(project(":compose:animation:animation-graphics:animation-graphics-samples"))
     kmpDocs(project(":compose:foundation:foundation"))
     kmpDocs(project(":compose:foundation:foundation-layout"))
-    samples(project(":compose:foundation:foundation-layout:foundation-layout-samples"))
-    samples(project(":compose:foundation:foundation:foundation-samples"))
     kmpDocs(project(":compose:material3:adaptive:adaptive"))
     kmpDocs(project(":compose:material3:adaptive:adaptive-layout"))
     kmpDocs(project(":compose:material3:adaptive:adaptive-navigation"))
-    samples(project(":compose:material3:adaptive:adaptive-samples"))
     kmpDocs(project(":compose:material3:material3"))
-    samples(project(":compose:material3:material3:material3-samples"))
     kmpDocs(project(":compose:material3:material3-adaptive-navigation-suite"))
-    samples(project(":compose:material3:material3-adaptive-navigation-suite:material3-adaptive-navigation-suite-samples"))
     kmpDocs(project(":compose:material3:material3-common"))
-    samples(project(":compose:material3:material3-common:material3-common-samples"))
     kmpDocs(project(":compose:material3:material3-window-size-class"))
-    samples(project(":compose:material3:material3-window-size-class:material3-window-size-class-samples"))
     kmpDocs(project(":compose:material:material"))
     kmpDocs(project(":compose:material:material-icons-core"))
-    samples(project(":compose:material:material-icons-core:material-icons-core-samples"))
     kmpDocs(project(":compose:material:material-ripple"))
     docs(project(":compose:material:material-navigation"))
-    samples(project(":compose:material:material-navigation-samples"))
-    samples(project(":compose:material:material:material-samples"))
     kmpDocs(project(":compose:runtime:runtime"))
-    samples(project(":compose:runtime:runtime:runtime-samples"))
     docs(project(":compose:runtime:runtime-livedata"))
-    samples(project(":compose:runtime:runtime-livedata:runtime-livedata-samples"))
     docs(project(":compose:runtime:runtime-rxjava2"))
-    samples(project(":compose:runtime:runtime-rxjava2:runtime-rxjava2-samples"))
     docs(project(":compose:runtime:runtime-rxjava3"))
-    samples(project(":compose:runtime:runtime-rxjava3:runtime-rxjava3-samples"))
     kmpDocs(project(":compose:runtime:runtime-saveable"))
-    samples(project(":compose:runtime:runtime-saveable:runtime-saveable-samples"))
     docs(project(":compose:runtime:runtime-tracing"))
     kmpDocs(project(":compose:ui:ui"))
     docs(project(":compose:ui:ui-android-stubs"))
     kmpDocs(project(":compose:ui:ui-geometry"))
     kmpDocs(project(":compose:ui:ui-graphics"))
-    samples(project(":compose:ui:ui-graphics:ui-graphics-samples"))
     kmpDocs(project(":compose:ui:ui-test"))
-    samples(project(":compose:ui:ui-test:ui-test-samples"))
     kmpDocs(project(":compose:ui:ui-test-junit4"))
     kmpDocs(project(":compose:ui:ui-text"))
-    samples(project(":compose:ui:ui-text:ui-text-samples"))
     docs(project(":compose:ui:ui-text-google-fonts"))
     kmpDocs(project(":compose:ui:ui-tooling"))
     kmpDocs(project(":compose:ui:ui-tooling-data"))
     kmpDocs(project(":compose:ui:ui-tooling-preview"))
     kmpDocs(project(":compose:ui:ui-unit"))
-    samples(project(":compose:ui:ui-unit:ui-unit-samples"))
     kmpDocs(project(":compose:ui:ui-util"))
     docs(project(":compose:ui:ui-viewbinding"))
-    samples(project(":compose:ui:ui-viewbinding:ui-viewbinding-samples"))
-    samples(project(":compose:ui:ui:ui-samples"))
     docs(project(":concurrent:concurrent-futures"))
     docs(project(":concurrent:concurrent-futures-ktx"))
     docs(project(":constraintlayout:constraintlayout"))
@@ -157,14 +131,12 @@
     docs(project(":core:core-appdigest"))
     docs(project(":core:core-google-shortcuts"))
     docs(project(":core:haptics:haptics"))
-    samples(project(":core:haptics:haptics-samples"))
     docs(project(":core:core-i18n"))
     docs(project(":core:core-ktx"))
     docs(project(":core:core-location-altitude"))
     docs(project(":core:core-performance"))
     docs(project(":core:core-performance-play-services"))
     docs(project(":core:core-performance-testing"))
-    samples(project(":core:core-performance:core-performance-samples"))
     docs(project(":core:core-remoteviews"))
     docs(project(":core:core-role"))
     docs(project(":core:core-splashscreen"))
@@ -174,7 +146,6 @@
     docs(project(":core:uwb:uwb-rxjava3"))
     docs(project(":credentials:credentials"))
     docs(project(":credentials:credentials-fido"))
-    samples(project(":credentials:credentials-samples"))
     docs(project(":credentials:credentials-play-services-auth"))
     docs(project(":credentials:credentials-e2ee"))
     docs(project(":cursoradapter:cursoradapter"))
@@ -207,14 +178,11 @@
     docs(project(":exifinterface:exifinterface"))
     docs(project(":fragment:fragment"))
     docs(project(":fragment:fragment-compose"))
-    samples(project(":fragment:fragment-compose:fragment-compose-samples"))
     docs(project(":fragment:fragment-ktx"))
     docs(project(":fragment:fragment-testing"))
     docs(project(":glance:glance"))
     docs(project(":glance:glance-appwidget"))
     docs(project(":glance:glance-appwidget-testing"))
-    samples(project(":glance:glance-appwidget:glance-appwidget-samples"))
-    samples(project(":glance:glance-appwidget-testing:glance-appwidget-testing-samples"))
     docs(project(":glance:glance-appwidget-preview"))
     docs(project(":glance:glance-material"))
     docs(project(":glance:glance-material3"))
@@ -224,18 +192,15 @@
     docs(project(":glance:glance-wear-tiles"))
     docs(project(":graphics:filters:filters"))
     docs(project(":graphics:graphics-core"))
-    samples(project(":graphics:graphics-core:graphics-core-samples"))
     docs(project(":graphics:graphics-path"))
     kmpDocs(project(":graphics:graphics-shapes"))
     docs(project(":gridlayout:gridlayout"))
     docs(project(":health:connect:connect-client"))
-    samples(project(":health:connect:connect-client-samples"))
     docs(project(":health:health-services-client"))
     docs(project(":heifwriter:heifwriter"))
     docs(project(":hilt:hilt-common"))
     docs(project(":hilt:hilt-navigation"))
     docs(project(":hilt:hilt-navigation-compose"))
-    samples(project(":hilt:hilt-navigation-compose-samples"))
     docs(project(":hilt:hilt-navigation-fragment"))
     docs(project(":hilt:hilt-work"))
     docs(project(":input:input-motionprediction"))
@@ -258,13 +223,11 @@
     docs(project(":lifecycle:lifecycle-reactivestreams-ktx"))
     kmpDocs(project(":lifecycle:lifecycle-runtime"))
     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"))
     docs(project(":lifecycle:lifecycle-service"))
     kmpDocs(project(":lifecycle:lifecycle-viewmodel"))
     kmpDocs(project(":lifecycle:lifecycle-viewmodel-compose"))
-    samples(project(":lifecycle:lifecycle-viewmodel-compose:lifecycle-viewmodel-compose-samples"))
     docs(project(":lifecycle:lifecycle-viewmodel-ktx"))
     docs(project(":lifecycle:lifecycle-viewmodel-savedstate"))
     docs(project(":loader:loader"))
@@ -278,7 +241,6 @@
     docs(project(":navigation:navigation-common"))
     docs(project(":navigation:navigation-common-ktx"))
     docs(project(":navigation:navigation-compose"))
-    samples(project(":navigation:navigation-compose:navigation-compose-samples"))
     docs(project(":navigation:navigation-dynamic-features-fragment"))
     docs(project(":navigation:navigation-dynamic-features-runtime"))
     docs(project(":navigation:navigation-fragment"))
@@ -292,14 +254,12 @@
     kmpDocs(project(":paging:paging-common"))
     docs(project(":paging:paging-common-ktx"))
     kmpDocs(project(":paging:paging-compose"))
-    samples(project(":paging:paging-compose:paging-compose-samples"))
     docs(project(":paging:paging-guava"))
     docs(project(":paging:paging-runtime"))
     docs(project(":paging:paging-runtime-ktx"))
     docs(project(":paging:paging-rxjava2"))
     docs(project(":paging:paging-rxjava2-ktx"))
     docs(project(":paging:paging-rxjava3"))
-    samples(project(":paging:paging-samples"))
     kmpDocs(project(":paging:paging-testing"))
     docs(project(":palette:palette"))
     docs(project(":palette:palette-ktx"))
@@ -374,7 +334,6 @@
     docs(project(":transition:transition-ktx"))
     docs(project(":tv:tv-foundation"))
     docs(project(":tv:tv-material"))
-    samples(project(":tv:tv-samples"))
     docs(project(":tvprovider:tvprovider"))
     docs(project(":vectordrawable:vectordrawable"))
     docs(project(":vectordrawable:vectordrawable-animated"))
@@ -383,14 +342,10 @@
     docs(project(":viewpager2:viewpager2"))
     docs(project(":viewpager:viewpager"))
     docs(project(":wear:compose:compose-foundation"))
-    samples(project(":wear:compose:compose-foundation-samples"))
     docs(project(":wear:compose:compose-material"))
     docs(project(":wear:compose:compose-material-core"))
-    samples(project(":wear:compose:compose-material-samples"))
     docs(project(":wear:compose:compose-material3"))
-    samples(project(":wear:compose:compose-material3-samples"))
     docs(project(":wear:compose:compose-navigation"))
-    samples(project(":wear:compose:compose-navigation-samples"))
     docs(project(":wear:compose:compose-ui-tooling"))
     docs(project(":wear:protolayout:protolayout"))
     docs(project(":wear:protolayout:protolayout-expression"))
@@ -411,26 +366,20 @@
     docs(project(":wear:watchface:watchface-complications-data"))
     docs(project(":wear:watchface:watchface-complications-data-source"))
     docs(project(":wear:watchface:watchface-complications-data-source-ktx"))
-    samples(project(":wear:watchface:watchface-complications-permission-dialogs-sample"))
     docs(project(":wear:watchface:watchface-complications-rendering"))
     docs(project(":wear:watchface:watchface-data"))
     docs(project(":wear:watchface:watchface-editor"))
     docs(project(":wear:watchface:watchface-editor-guava"))
-    samples(project(":wear:watchface:watchface-editor-samples"))
     docs(project(":wear:watchface:watchface-guava"))
-    samples(project(":wear:watchface:watchface-samples"))
     docs(project(":wear:watchface:watchface-style"))
     docs(project(":wear:wear"))
     docs(project(":wear:wear-core"))
     stubs(fileTree(dir: "../wear/wear_stubs/", include: ["com.google.android.wearable-stubs.jar"]))
     docs(project(":wear:wear-input"))
-    samples(project(":wear:wear-input-samples"))
     docs(project(":wear:wear-input-testing"))
     docs(project(":wear:wear-ongoing"))
     docs(project(":wear:wear-phone-interactions"))
-    samples(project(":wear:wear-phone-interactions-samples"))
     docs(project(":wear:wear-remote-interactions"))
-    samples(project(":wear:wear-remote-interactions-samples"))
     docs(project(":wear:wear-tooling-preview"))
     docs(project(":webkit:webkit"))
     docs(project(":window:window"))
@@ -441,7 +390,6 @@
     docs(project(":window:window-java"))
     docs(project(":window:window-rxjava2"))
     docs(project(":window:window-rxjava3"))
-    samples(project(":window:window-samples"))
     docs(project(":window:window-testing"))
     docs(project(":work:work-gcm"))
     docs(project(":work:work-multiprocess"))
diff --git a/docs/macrobenchmarking.md b/docs/macrobenchmarking.md
index 612cd7e..7084c39 100644
--- a/docs/macrobenchmarking.md
+++ b/docs/macrobenchmarking.md
@@ -1,4 +1,4 @@
-# Benchmarking in AndroidX
+# MACRObenchmarking in AndroidX
 
 [TOC]
 
@@ -10,7 +10,7 @@
       <td><strong>Benchmark</strong></td>
     </tr>
     <tr>
-        <td>Measure high-level entry points(Activity launch / Scrolling a list)</td>
+        <td>Measure high-level entry points (Activity launch / Scrolling a list)</td>
         <td>Measure individual functions</td>
     </tr>
     <tr>
@@ -22,12 +22,12 @@
         <td>Fast iteration speed (Often less than 10 seconds)</td>
     </tr>
     <tr>
-        <td>Configure compilation with CompilationMode</td>
+        <td>Configure compilation with <a href="https://developer.android.com/reference/androidx/benchmark/macro/CompilationMode">CompilationMode</a></td>
         <td>Always fully AOT (<code>speed</code>) compiled.</td>
     </tr>
     <tr>
         <td>Min API 23</td>
-        <td>Min API 14</td>
+        <td>Min API 19</td>
     </tr>
     <tr>
         <td>Relatively lower stability measurements</td>
@@ -122,7 +122,7 @@
 
 *   [`:compose:integration-tests:macrobenchmark`](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:compose/integration-tests/macrobenchmark/)
 
-Note: Compose macrobenchmarks are generally duplicated with View system
+Note: Compose macrobenchmarks are ideally duplicated with View system
 counterparts, defined in `:benchmark:integration-tests:macrobenchmark-target`.
 This is how we compare performance of the two systems.
 
diff --git a/enterprise/OWNERS b/enterprise/OWNERS
index 8f42a2b..a1bb741 100644
--- a/enterprise/OWNERS
+++ b/enterprise/OWNERS
@@ -1,3 +1,3 @@
 # Bug component: 606793
-alexkershaw@google.com
-scottjonathan@google.com
+sandness@google.com
+sinduran@google.com
diff --git a/glance/glance-appwidget/integration-tests/demos/src/main/AndroidManifest.xml b/glance/glance-appwidget/integration-tests/demos/src/main/AndroidManifest.xml
index 9b09378..56c5b6d 100644
--- a/glance/glance-appwidget/integration-tests/demos/src/main/AndroidManifest.xml
+++ b/glance/glance-appwidget/integration-tests/demos/src/main/AndroidManifest.xml
@@ -17,10 +17,10 @@
     xmlns:tools="http://schemas.android.com/tools">
 
     <application
+        android:name=".DemoApplication"
         android:allowBackup="false"
         android:icon="@mipmap/ic_launcher"
         android:label="@string/demos_label"
-        android:name=".DemoApplication"
         android:supportsRtl="true">
 
         <activity
@@ -38,7 +38,7 @@
             android:name=".SimpleWidgetViewer"
             android:exported="true"
             android:label="@string/demo_widget_viewer"
-            android:theme="@android:style/Theme.Material.Light.NoActionBar" >
+            android:theme="@android:style/Theme.Material.Light.NoActionBar">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
@@ -46,19 +46,24 @@
         </activity>
 
         <activity android:name=".ActionDemoActivity" />
-        <service
-            android:name=".ActionDemoService"
-            tools:ignore="MissingServiceExportedEqualsTrue" />
 
-        <activity android:name=".ListClickDestinationActivity" android:exported="false" />
-        <activity android:name=".ErrorUiAppWidgetConfigurationActivity"
-            android:exported="false"
-            >
+        <activity
+            android:name=".ListClickDestinationActivity"
+            android:exported="false" />
+
+        <activity
+            android:name=".ErrorUiAppWidgetConfigurationActivity"
+            android:exported="false">
             <intent-filter>
                 <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
             </intent-filter>
         </activity>
 
+        <provider
+            android:name="androidx.glance.appwidget.demos.ImageAppWidgetImageContentProvider"
+            android:authorities="androidx.glance.appwidget.demos"
+            android:enabled="true"
+            android:exported="true" />
 
         <receiver
             android:name="androidx.glance.appwidget.demos.ResponsiveAppWidgetReceiver"
@@ -131,9 +136,9 @@
 
         <receiver
             android:name="androidx.glance.appwidget.demos.ErrorUiAppWidgetReceiver"
-            android:label="@string/error_widget_name"
             android:enabled="@bool/glance_appwidget_available"
-            android:exported="false">
+            android:exported="false"
+            android:label="@string/error_widget_name">
             <intent-filter>
                 <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
                 <action android:name="android.intent.action.LOCALE_CHANGED" />
@@ -145,9 +150,9 @@
 
         <receiver
             android:name="androidx.glance.appwidget.demos.FontDemoAppWidgetReceiver"
-            android:label="@string/font_widget_name"
             android:enabled="@bool/glance_appwidget_available"
-            android:exported="false">
+            android:exported="false"
+            android:label="@string/font_widget_name">
             <intent-filter>
                 <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
                 <action android:name="android.intent.action.LOCALE_CHANGED" />
@@ -159,9 +164,9 @@
 
         <receiver
             android:name="androidx.glance.appwidget.demos.TypographyDemoAppWidgetReceiver"
-            android:label="@string/typography_widget_name"
             android:enabled="@bool/glance_appwidget_available"
-            android:exported="false">
+            android:exported="false"
+            android:label="@string/typography_widget_name">
             <intent-filter>
                 <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
             </intent-filter>
@@ -172,9 +177,9 @@
 
         <receiver
             android:name="androidx.glance.appwidget.demos.ScrollableAppWidgetReceiver"
-            android:label="@string/scrollable_widget_name"
             android:enabled="@bool/glance_appwidget_available"
-            android:exported="false">
+            android:exported="false"
+            android:label="@string/scrollable_widget_name">
             <intent-filter>
                 <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
             </intent-filter>
@@ -185,9 +190,9 @@
 
         <receiver
             android:name="androidx.glance.appwidget.demos.ImageAppWidgetReceiver"
-            android:label="@string/image_widget_name"
             android:enabled="@bool/glance_appwidget_available"
-            android:exported="false">
+            android:exported="false"
+            android:label="@string/image_widget_name">
             <intent-filter>
                 <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
             </intent-filter>
@@ -198,9 +203,9 @@
 
         <receiver
             android:name="androidx.glance.appwidget.demos.RippleAppWidgetReceiver"
-            android:label="@string/ripple_widget_name"
             android:enabled="@bool/glance_appwidget_available"
-            android:exported="false">
+            android:exported="false"
+            android:label="@string/ripple_widget_name">
             <intent-filter>
                 <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
             </intent-filter>
@@ -211,9 +216,9 @@
 
         <receiver
             android:name="androidx.glance.appwidget.demos.RemoteViewsWidgetReceiver"
-            android:label="@string/remote_views_widget_name"
             android:enabled="@bool/glance_appwidget_available"
-            android:exported="false">
+            android:exported="false"
+            android:label="@string/remote_views_widget_name">
             <intent-filter>
                 <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
             </intent-filter>
@@ -224,9 +229,9 @@
 
         <receiver
             android:name="androidx.glance.appwidget.demos.VerticalGridAppWidgetReceiver"
-            android:label="@string/grid_widget_name"
             android:enabled="@bool/glance_appwidget_available"
-            android:exported="false">
+            android:exported="false"
+            android:label="@string/grid_widget_name">
             <intent-filter>
                 <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
             </intent-filter>
@@ -237,9 +242,9 @@
 
         <receiver
             android:name="androidx.glance.appwidget.demos.DefaultStateAppWidgetReceiver"
-            android:label="@string/default_state_widget_name"
             android:enabled="@bool/glance_appwidget_available"
-            android:exported="false">
+            android:exported="false"
+            android:label="@string/default_state_widget_name">
             <intent-filter>
                 <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
             </intent-filter>
@@ -250,9 +255,9 @@
 
         <receiver
             android:name="androidx.glance.appwidget.demos.ProgressIndicatorAppWidgetReceiver"
-            android:label="@string/progress_indicator_widget_name"
             android:enabled="@bool/glance_appwidget_available"
-            android:exported="false">
+            android:exported="false"
+            android:label="@string/progress_indicator_widget_name">
             <intent-filter>
                 <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
             </intent-filter>
@@ -263,9 +268,9 @@
 
         <receiver
             android:name="androidx.glance.appwidget.demos.DefaultColorsAppWidgetReceiver"
-            android:label="@string/default_color_widget_name"
             android:enabled="@bool/glance_appwidget_available"
-            android:exported="false">
+            android:exported="false"
+            android:label="@string/default_color_widget_name">
             <intent-filter>
                 <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
             </intent-filter>
@@ -290,9 +295,9 @@
 
         <receiver
             android:name="androidx.glance.appwidget.demos.BackgroundTintWidgetBroadcastReceiver"
-            android:label="@string/tint_widget"
             android:enabled="@bool/glance_appwidget_available"
-            android:exported="false">
+            android:exported="false"
+            android:label="@string/tint_widget">
             <intent-filter>
                 <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
             </intent-filter>
@@ -303,9 +308,9 @@
 
         <receiver
             android:name="androidx.glance.appwidget.demos.TitleBarWidgetBroadcastReceiver"
-            android:label="@string/title_bar_widget"
             android:enabled="@bool/glance_appwidget_available"
-            android:exported="false">
+            android:exported="false"
+            android:label="@string/title_bar_widget">
             <intent-filter>
                 <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
             </intent-filter>
@@ -316,9 +321,9 @@
 
         <receiver
             android:name="androidx.glance.appwidget.demos.ContentDescriptionAppWidgetReceiver"
-            android:label="@string/content_description_widget_name"
             android:enabled="@bool/glance_appwidget_available"
-            android:exported="false">
+            android:exported="false"
+            android:label="@string/content_description_widget_name">
             <intent-filter>
                 <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
             </intent-filter>
@@ -326,5 +331,9 @@
                 android:name="android.appwidget.provider"
                 android:resource="@xml/default_app_widget_info" />
         </receiver>
+
+        <service
+            android:name=".ActionDemoService"
+            android:exported="true" />
     </application>
 </manifest>
diff --git a/glance/glance-appwidget/integration-tests/demos/src/main/java/androidx/glance/appwidget/demos/ImageAppWidget.kt b/glance/glance-appwidget/integration-tests/demos/src/main/java/androidx/glance/appwidget/demos/ImageAppWidget.kt
index bc136c1..a794006 100644
--- a/glance/glance-appwidget/integration-tests/demos/src/main/java/androidx/glance/appwidget/demos/ImageAppWidget.kt
+++ b/glance/glance-appwidget/integration-tests/demos/src/main/java/androidx/glance/appwidget/demos/ImageAppWidget.kt
@@ -16,13 +16,24 @@
 
 package androidx.glance.appwidget.demos
 
+import android.content.ContentProvider
+import android.content.ContentValues
 import android.content.Context
+import android.database.Cursor
+import android.graphics.Bitmap
+import android.graphics.Canvas
+import android.graphics.Paint
+import android.graphics.drawable.Icon
+import android.net.Uri
+import android.os.Build
+import android.os.ParcelFileDescriptor
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.toArgb
 import androidx.compose.ui.unit.dp
 import androidx.glance.Button
 import androidx.glance.ColorFilter
@@ -34,11 +45,17 @@
 import androidx.glance.action.clickable
 import androidx.glance.appwidget.GlanceAppWidget
 import androidx.glance.appwidget.GlanceAppWidgetReceiver
+import androidx.glance.appwidget.ImageProvider
 import androidx.glance.appwidget.SizeMode
+import androidx.glance.appwidget.components.Scaffold
+import androidx.glance.appwidget.demos.ShareableImageUtils.getShareableImageUri
+import androidx.glance.appwidget.demos.ShareableImageUtils.uriImageFile
+import androidx.glance.appwidget.lazy.LazyColumn
 import androidx.glance.appwidget.provideContent
 import androidx.glance.background
 import androidx.glance.color.ColorProvider
 import androidx.glance.layout.Alignment
+import androidx.glance.layout.Box
 import androidx.glance.layout.Column
 import androidx.glance.layout.ContentScale
 import androidx.glance.layout.Row
@@ -48,6 +65,11 @@
 import androidx.glance.layout.padding
 import androidx.glance.layout.size
 import androidx.glance.text.Text
+import java.io.File
+
+class ImageAppWidgetReceiver : GlanceAppWidgetReceiver() {
+    override val glanceAppWidget: GlanceAppWidget = ImageAppWidget()
+}
 
 /**
  * Sample AppWidget that showcase the [ContentScale] options for [Image]
@@ -58,73 +80,324 @@
     override suspend fun provideGlance(
         context: Context,
         id: GlanceId
-    ) = provideContent {
-        var type by remember { mutableStateOf(ContentScale.Fit) }
-        Column(modifier = GlanceModifier.fillMaxSize().padding(8.dp)) {
-            Header()
-            Spacer(GlanceModifier.size(4.dp))
-            Button(
-                text = "Content Scale: ${type.asString()}",
-                modifier = GlanceModifier.fillMaxWidth(),
-                onClick = {
-                    type = when (type) {
-                        ContentScale.Crop -> ContentScale.FillBounds
-                        ContentScale.FillBounds -> ContentScale.Fit
-                        else -> ContentScale.Crop
-                    }
-                }
-            )
-            Spacer(GlanceModifier.size(4.dp))
-            Image(
-                provider = ImageProvider(R.drawable.compose),
-                contentDescription = "Content Scale image sample (value: ${type.asString()})",
-                contentScale = type,
-                modifier = GlanceModifier.fillMaxSize().background(Color.DarkGray)
+    ) {
+        val imageUri: Uri = getShareableImageUri(context)
+
+        provideContent {
+            Scaffold(
+                titleBar = { Header() },
+                content = { BodyContent(imageUri = imageUri) }
             )
         }
     }
-
-    @Composable
-    private fun Header() {
-        val context = LocalContext.current
-        var shouldTintHeaderIcon by remember { mutableStateOf(true) }
-
-        Row(
-            horizontalAlignment = Alignment.CenterHorizontally,
-            verticalAlignment = Alignment.CenterVertically,
-            modifier = GlanceModifier.fillMaxWidth().background(Color.White)
-        ) {
-            // Demonstrates toggling application of color filter on an image
-            Image(
-                provider = ImageProvider(R.drawable.ic_android),
-                contentDescription = null,
-                colorFilter = if (shouldTintHeaderIcon) {
-                    ColorFilter.tint(
-                        ColorProvider(day = Color.Green, night = Color.Blue)
-                    )
-                } else {
-                    null
-                },
-                modifier = GlanceModifier.clickable {
-                    shouldTintHeaderIcon = !shouldTintHeaderIcon
-                }
-            )
-            Text(
-                text = context.getString(R.string.image_widget_name),
-                modifier = GlanceModifier.padding(8.dp),
-            )
-        }
-    }
-
-    private fun ContentScale.asString(): String =
-        when (this) {
-            ContentScale.Fit -> "Fit"
-            ContentScale.FillBounds -> "Fill Bounds"
-            ContentScale.Crop -> "Crop"
-            else -> "Unknown content scale"
-        }
 }
 
-class ImageAppWidgetReceiver : GlanceAppWidgetReceiver() {
-    override val glanceAppWidget: GlanceAppWidget = ImageAppWidget()
+@Composable
+private fun Header() {
+    val context = LocalContext.current
+    var shouldTintHeaderIcon by remember { mutableStateOf(true) }
+
+    Row(
+        horizontalAlignment = Alignment.CenterHorizontally,
+        verticalAlignment = Alignment.CenterVertically,
+        modifier = GlanceModifier.fillMaxWidth().background(Color.White)
+    ) {
+        // Demonstrates toggling application of color filter on an image
+        Image(
+            provider = ImageProvider(R.drawable.ic_android),
+            contentDescription = null,
+            colorFilter = if (shouldTintHeaderIcon) {
+                ColorFilter.tint(
+                    ColorProvider(day = Color.Green, night = Color.Blue)
+                )
+            } else {
+                null
+            },
+            modifier = GlanceModifier.clickable {
+                shouldTintHeaderIcon = !shouldTintHeaderIcon
+            }
+        )
+        Text(
+            text = context.getString(R.string.image_widget_name),
+            modifier = GlanceModifier.padding(8.dp),
+        )
+    }
+}
+
+@Composable
+private fun BodyContent(imageUri: Uri) {
+    var type by remember { mutableStateOf(ContentScale.Fit) }
+    Column(modifier = GlanceModifier.fillMaxSize().padding(8.dp)) {
+        Spacer(GlanceModifier.size(4.dp))
+        Button(
+            text = "Content Scale: ${type.asString()}",
+            modifier = GlanceModifier.fillMaxWidth(),
+            onClick = {
+                type = when (type) {
+                    ContentScale.Crop -> ContentScale.FillBounds
+                    ContentScale.FillBounds -> ContentScale.Fit
+                    else -> ContentScale.Crop
+                }
+            }
+        )
+        Spacer(GlanceModifier.size(4.dp))
+
+        val itemModifier = GlanceModifier.fillMaxWidth().padding(vertical = 4.dp)
+
+        LazyColumn(GlanceModifier.fillMaxSize()) {
+            val textModifier = GlanceModifier.padding(bottom = 8.dp)
+            item {
+                Column {
+                    // An image who's provider uses a resource.
+                    ResourceImage(contentScale = type, modifier = itemModifier)
+                    Text("ImageProvider(resourceId)", textModifier)
+                }
+            }
+            item {
+                Column {
+                    // An image who's provider uses a content uri. This uri will be passed through
+                    // the remote views to the AppWidget's host. The host will query our app via
+                    // content provider to resolve the Uri into a bitmap.
+                    UriImage(uri = imageUri, contentScale = type, modifier = itemModifier)
+                    Text("ImageProvider(uri)", textModifier)
+                }
+            }
+
+            item {
+                Column {
+                    // An image who's provider holds an in-memory bitmap.
+                    BitmapImage(contentScale = type, modifier = itemModifier)
+                    Text("ImageProvider(bitmap)", textModifier)
+                }
+            }
+
+            item {
+                Column {
+                    // An image who's provider uses the Icon api.
+                    IconImage(contentScale = type, modifier = itemModifier)
+                    Text("ImageProvider(icon)", textModifier)
+                }
+            }
+        }
+    }
+}
+
+@Composable
+private fun ResourceImage(contentScale: ContentScale, modifier: GlanceModifier = GlanceModifier) {
+    Image(
+        provider = ImageProvider(R.drawable.compose),
+        contentDescription = "Content Scale image sample (value: ${contentScale.asString()})",
+        contentScale = contentScale,
+        modifier = modifier
+    )
+}
+
+/**
+ * Demonstrates using the Uri image provider in `androidx.glance.appwidget`. This image will be
+ * sent to the RemoteViews as a uri. In the AppWidgetHost, the uri will be resolved by querying
+ * back to this app's [ContentProvider], see [ImageAppWidgetImageContentProvider]. There are several
+ * drawbacks to this approach. Consider them before going this route.
+ * - Images that are within the app's private directories can only be exposed via ContentProvider;
+ *   a direct reference via file:// uri will not work.
+ * - The ContentProvider approach will not work across user/work profiles.
+ * - Any time the image is loaded, the AppWidget's process will be started, consuming battery
+ *   and memory.
+ * - FileProvider cannot be used due to a permissions issue.
+ */
+@Composable
+private fun UriImage(
+    contentScale: ContentScale,
+    modifier: GlanceModifier = GlanceModifier,
+    uri: Uri
+) {
+    Image(
+        provider = ImageProvider(uri),
+        contentDescription = "Content Scale image sample (value: ${contentScale.asString()})",
+        contentScale = contentScale,
+        modifier = modifier
+    )
+}
+
+/**
+ * Bitmaps are passed in memory from the appwidget provider's process to the appwidget host's
+ * process. Be careful to not use too many or too large bitmaps. See [android.widget.RemoteViews]
+ * for more info.
+ */
+@Composable
+private fun BitmapImage(contentScale: ContentScale, modifier: GlanceModifier = GlanceModifier) {
+    fun makeBitmap(): Bitmap {
+        val w = 100f
+        val h = 100f
+        val bmp = Bitmap.createBitmap(w.toInt(), h.toInt(), Bitmap.Config.ARGB_8888)
+        val canvas = Canvas(bmp)
+        val paint = Paint()
+
+        paint.setColor(Color.Black.toArgb()) // transparent
+        canvas.drawRect(0f, 0f, w, h, paint)
+        paint.setColor(Color.White.toArgb()) // Opaque
+        canvas.drawCircle(w / 2f, h / 2f, w / 3f, paint)
+
+        return bmp
+    }
+
+    Image(
+        provider = ImageProvider(makeBitmap()),
+        contentDescription = "An image with an in-memory bitmap provider",
+        contentScale = contentScale,
+        modifier = modifier
+    )
+}
+
+/**
+ * For displaying [Image]s backed by [android.graphics.drawable.Icon]s. Despite the name, an
+ * [Icon] does not need to represent a literal icon.
+ */
+@Composable
+private fun IconImage(contentScale: ContentScale, modifier: GlanceModifier) {
+    if (Build.VERSION.SDK_INT < 23) {
+        Text("The Icon api requires api >= 23")
+        return
+    }
+
+    val bitmap = canvasBitmap(200, circleColor = Color.Red)
+
+    Box {
+        Image(
+            provider = ImageProvider(bitmap),
+            contentDescription = "An image with an in-memory bitmap provider",
+            contentScale = contentScale,
+            modifier = modifier
+        )
+    }
+}
+
+private fun canvasBitmap(outputCanvasSize: Int, circleColor: Color): Bitmap {
+    val bitmap = Bitmap.createBitmap(
+        outputCanvasSize,
+        outputCanvasSize,
+        Bitmap.Config.ARGB_8888
+    )
+    val padding = outputCanvasSize * .05f
+    val canvas = Canvas(bitmap)
+
+    fun drawBlueSquare(canvas: Canvas) {
+        val squareSize = outputCanvasSize * (2f / 3f)
+
+        val x0 = padding
+        val x1 = x0 + squareSize
+        val y0 = (outputCanvasSize - squareSize - padding)
+        val y1 = y0 + squareSize
+        val paint = Paint().apply { setColor(Color.Blue.toArgb()) }
+        canvas.drawRect(x0, y0, x1, y1, paint)
+    }
+
+    fun drawCircle(canvas: Canvas) {
+        val r = outputCanvasSize * (1f / 3f)
+        val cx = outputCanvasSize - r - padding
+        val cy = r + padding
+
+        val paint = Paint().apply { setColor(circleColor.toArgb()) }
+        canvas.drawCircle(cx, cy, r, paint)
+    }
+
+    drawBlueSquare(canvas)
+    drawCircle(canvas)
+
+    return bitmap
+}
+
+private fun ContentScale.asString(): String =
+    when (this) {
+        ContentScale.Fit -> "Fit"
+        ContentScale.FillBounds -> "Fill Bounds"
+        ContentScale.Crop -> "Crop"
+        else -> "Unknown content scale"
+    }
+
+private object ShareableImageUtils {
+    private val fileProviderDirectory = "imageAppWidget"
+    private val fileName = "imageToBeLoadedFromUri.png"
+
+    private fun uri(context: Context, filename: String): Uri {
+        val packageName = context.packageName
+        return Uri.parse("content://$packageName/$filename")
+    }
+
+    val Context.uriImageFile: File
+        get() = File(
+            this.filesDir, "$fileProviderDirectory/$fileName"
+        )
+
+    /**
+     * Create a Uri to share and ensure the file we want to return exists.
+     */
+    fun getShareableImageUri(context: Context): Uri {
+
+        val file: File = context.uriImageFile
+        file.parentFile?.mkdir()
+        val success = if (file.exists()) {
+            true
+        } else {
+            val bitmap = canvasBitmap(300, circleColor = Color.Green)
+            file.outputStream().use { out ->
+                bitmap.compress(Bitmap.CompressFormat.PNG, 100, out)
+            }
+        }
+
+        if (success) {
+            return uri(context, file.name)
+        } else {
+            throw IllegalStateException("Failed to write bitmap")
+        }
+    }
+}
+
+/**
+ * Expose an image file via content:// uri.
+ */
+class ImageAppWidgetImageContentProvider : ContentProvider() {
+    override fun onCreate(): Boolean {
+        return true
+    }
+
+    /**
+     * A simplified version of [openFile] for example only. This version does not validate the
+     * uri and always returns the same file.
+     */
+    override fun openFile(uri: Uri, mode: String): ParcelFileDescriptor? {
+        val context = context ?: return null
+        val file = context.uriImageFile
+        return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY)
+    }
+
+    override fun query(
+        uri: Uri,
+        projection: Array<out String>?,
+        selection: String?,
+        selectionArgs: Array<out String>?,
+        sortOrder: String?
+    ): Cursor? {
+        return null // unused
+    }
+
+    override fun getType(uri: Uri): String? {
+        return "image/png"
+    }
+
+    override fun insert(uri: Uri, values: ContentValues?): Uri? {
+        return null // unused
+    }
+
+    override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?): Int {
+        return 0 // unused
+    }
+
+    override fun update(
+        uri: Uri,
+        values: ContentValues?,
+        selection: String?,
+        selectionArgs: Array<out String>?
+    ): Int {
+        return 0 // unused
+    }
 }
diff --git a/glance/glance-appwidget/src/androidTest/kotlin/androidx/glance/appwidget/GlanceAppWidgetReceiverScreenshotTest.kt b/glance/glance-appwidget/src/androidTest/kotlin/androidx/glance/appwidget/GlanceAppWidgetReceiverScreenshotTest.kt
index eb7c74f9..c14bf11 100644
--- a/glance/glance-appwidget/src/androidTest/kotlin/androidx/glance/appwidget/GlanceAppWidgetReceiverScreenshotTest.kt
+++ b/glance/glance-appwidget/src/androidTest/kotlin/androidx/glance/appwidget/GlanceAppWidgetReceiverScreenshotTest.kt
@@ -24,6 +24,7 @@
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
 import androidx.glance.Button
+import androidx.glance.ButtonColors
 import androidx.glance.ButtonDefaults
 import androidx.glance.GlanceModifier
 import androidx.glance.GlanceTheme
@@ -643,6 +644,76 @@
         mScreenshotRule.checkScreenshot(mHostRule.mHostView, "buttonTests_buttonDefaultColors")
     }
 
+    /**
+     * Button should ignore [androidx.glance.BackgroundModifier]. It does not support background
+     * images, and background color should be set via [androidx.glance.ButtonColors].
+     */
+    @Test
+    fun buttonTests_buttonShouldIgnoreBackgroundModifiers() {
+        @Composable
+        fun Ui() {
+            Column {
+                // the bg image modifier should be stripped.
+                Button(
+                    text = "Button w/incorrect bg modifier: image",
+                    onClick = { },
+                    modifier =
+                    GlanceModifier.background(
+                        imageProvider = ImageProvider(R.drawable.compose),
+                    ),
+                )
+                Spacer(GlanceModifier.size(4.dp))
+
+                // Bg modifiers should be stripped
+                Button(
+                    text = "Button w/incorrect modifiers: Image, Color",
+                    onClick = { },
+                    modifier =
+                    GlanceModifier.background(
+                        Color.Cyan
+                    ).background(
+                        imageProvider = ImageProvider(R.drawable.compose),
+                    ),
+                )
+                Spacer(GlanceModifier.size(4.dp))
+
+                // Bg color modifier should be stripped.
+                Button(
+                    text = "Button w/incorrect bg modifier: color",
+                    onClick = { },
+                    modifier =
+                    GlanceModifier.background(
+                        Color.Cyan
+                    ),
+                )
+                Spacer(GlanceModifier.size(4.dp))
+
+                Button(
+                    text = "Button with no modifier",
+                    onClick = { },
+                )
+                Spacer(GlanceModifier.size(4.dp))
+                Button(
+                    text = "Button with proper color",
+                    colors = ButtonDefaults.buttonColors(
+                        backgroundColor = ColorProvider(Color.Cyan),
+                        contentColor = ColorProvider(Color.Magenta)
+                    ),
+                    onClick = { },
+                )
+            }
+        }
+
+        TestGlanceAppWidget.uiDefinition = {
+            Ui()
+        }
+        mHostRule.startHost()
+        mScreenshotRule.checkScreenshot(
+            mHostRule.mHostView,
+            "buttonTests_buttonIgnoresBgImageModifier"
+        )
+    }
+
     @Test
     fun topbarTests_createBarWithIconTextTwoActions() {
         TestGlanceAppWidget.uiDefinition = {
diff --git a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/NormalizeCompositionTree.kt b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/NormalizeCompositionTree.kt
index 7a1f57e..9d22cd6 100644
--- a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/NormalizeCompositionTree.kt
+++ b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/NormalizeCompositionTree.kt
@@ -198,6 +198,34 @@
     var target = this
     val isButton = target is EmittableButton
 
+    // Button ignores background modifiers.
+    if (isButton && Build.VERSION.SDK_INT > Build.VERSION_CODES.R) {
+        // Buttons cannot have a background image modifier. Remove BackgroundModifier.Image from
+        // the button if it exists.
+        val (maybeBgImageModifier, modifiersMinusBgImage) =
+            target.modifier.extractModifier<BackgroundModifier.Image>()
+        if (maybeBgImageModifier != null) {
+            Log.w(
+                GlanceAppWidgetTag,
+                "Glance Buttons should not have a background image modifier. " +
+                    "Consider an image with a clickable modifier."
+            )
+            target.modifier = modifiersMinusBgImage
+        }
+
+        // Buttons ignore background color modifier. Remove it.
+        val (maybeBgColorModifier, modifiersMinusBgColor) =
+            target.modifier.extractModifier<BackgroundModifier.Image>()
+        if (maybeBgColorModifier != null) {
+            Log.w(
+                GlanceAppWidgetTag,
+                "Glance Buttons should not have a background color modifier. " +
+                    "Consider a tinted image with a clickable modifier"
+            )
+            target.modifier = modifiersMinusBgColor
+        }
+    }
+
     val shouldWrapTargetInABox = target.modifier.any {
         // Background images (i.e. BitMap or drawable resources) are emulated by placing the image
         // before the target in the wrapper box. This allows us to support content scale as well as
@@ -219,6 +247,7 @@
     var rippleImage: EmittableImage? = null
 
     val (bgModifier, targetModifiersMinusBg) = target.modifier.extractModifier<BackgroundModifier>()
+
     if (bgModifier != null) {
         if (isButton) {
             // Emulate rounded corners (fixed radius) using a drawable and apply background colors
diff --git a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/translators/ImageTranslator.kt b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/translators/ImageTranslator.kt
index 2055f35..9ce6d8b 100644
--- a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/translators/ImageTranslator.kt
+++ b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/translators/ImageTranslator.kt
@@ -142,8 +142,11 @@
                 rv.setImageViewColorFilter(viewDef.mainViewId, color)
                 rv.setImageViewImageAlpha(viewDef.mainViewId, android.graphics.Color.alpha(color))
             } else {
-                throw IllegalStateException(
-                    "There is no use case yet to support this colorFilter in S+ versions."
+                val trace = Throwable()
+                Log.e(
+                    GlanceAppWidgetTag,
+                    "There is no use case yet to support this colorFilter in S+ versions.",
+                    trace
                 )
             }
         }
diff --git a/gradle.properties b/gradle.properties
index 241307e..7a42aa7 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -42,7 +42,7 @@
 # Don't warn about needing to update AGP
 android.suppressUnsupportedCompileSdk=UpsideDownCake,VanillaIceCream,33,34
 
-androidx.compileSdkVersion=android-34
+androidx.compileSdk=34
 androidx.targetSdkVersion=34
 androidx.allowCustomCompileSdk=true
 androidx.includeOptionalProjects=false
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 7745cc6..425cf58 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -24,7 +24,7 @@
 atomicFu = "0.17.0"
 autoService = "1.0-rc6"
 autoValue = "1.6.3"
-binaryCompatibilityValidator = "0.14.0"
+binaryCompatibilityValidator = "0.15.0-Beta.2"
 byteBuddy = "1.14.9"
 asm = "9.3"
 cmake = "3.22.1"
diff --git a/graphics/graphics-shapes/api/1.0.0-beta02.txt b/graphics/graphics-shapes/api/1.0.0-beta02.txt
new file mode 100644
index 0000000..f9d62d6f
--- /dev/null
+++ b/graphics/graphics-shapes/api/1.0.0-beta02.txt
@@ -0,0 +1,163 @@
+// Signature format: 4.0
+package androidx.graphics.shapes {
+
+  public final class CornerRounding {
+    ctor public CornerRounding(optional @FloatRange(from=0.0) float radius, optional @FloatRange(from=0.0, to=1.0) float smoothing);
+    method public float getRadius();
+    method public float getSmoothing();
+    property public final float radius;
+    property public final float smoothing;
+    field public static final androidx.graphics.shapes.CornerRounding.Companion Companion;
+    field public static final androidx.graphics.shapes.CornerRounding Unrounded;
+  }
+
+  public static final class CornerRounding.Companion {
+  }
+
+  public class Cubic {
+    method public static final androidx.graphics.shapes.Cubic circularArc(float centerX, float centerY, float x0, float y0, float x1, float y1);
+    method public final operator androidx.graphics.shapes.Cubic div(float x);
+    method public final operator androidx.graphics.shapes.Cubic div(int x);
+    method public final float getAnchor0X();
+    method public final float getAnchor0Y();
+    method public final float getAnchor1X();
+    method public final float getAnchor1Y();
+    method public final float getControl0X();
+    method public final float getControl0Y();
+    method public final float getControl1X();
+    method public final float getControl1Y();
+    method public final operator androidx.graphics.shapes.Cubic plus(androidx.graphics.shapes.Cubic o);
+    method public final androidx.graphics.shapes.Cubic reverse();
+    method public final kotlin.Pair<androidx.graphics.shapes.Cubic,androidx.graphics.shapes.Cubic> split(float t);
+    method public static final androidx.graphics.shapes.Cubic straightLine(float x0, float y0, float x1, float y1);
+    method public final operator androidx.graphics.shapes.Cubic times(float x);
+    method public final operator androidx.graphics.shapes.Cubic times(int x);
+    method public final androidx.graphics.shapes.Cubic transformed(androidx.graphics.shapes.PointTransformer f);
+    property public final float anchor0X;
+    property public final float anchor0Y;
+    property public final float anchor1X;
+    property public final float anchor1Y;
+    property public final float control0X;
+    property public final float control0Y;
+    property public final float control1X;
+    property public final float control1Y;
+    field public static final androidx.graphics.shapes.Cubic.Companion Companion;
+  }
+
+  public static final class Cubic.Companion {
+    method public androidx.graphics.shapes.Cubic circularArc(float centerX, float centerY, float x0, float y0, float x1, float y1);
+    method public androidx.graphics.shapes.Cubic straightLine(float x0, float y0, float x1, float y1);
+  }
+
+  public final class CubicKt {
+    method public static androidx.graphics.shapes.Cubic Cubic(float anchor0X, float anchor0Y, float control0X, float control0Y, float control1X, float control1Y, float anchor1X, float anchor1Y);
+  }
+
+  public final class Morph {
+    ctor public Morph(androidx.graphics.shapes.RoundedPolygon start, androidx.graphics.shapes.RoundedPolygon end);
+    method public java.util.List<androidx.graphics.shapes.Cubic> asCubics(float progress);
+    method public float[] calculateBounds();
+    method public float[] calculateBounds(optional float[] bounds);
+    method public float[] calculateBounds(optional float[] bounds, optional boolean approximate);
+    method public float[] calculateMaxBounds(optional float[] bounds);
+    method public inline void forEachCubic(float progress, optional androidx.graphics.shapes.MutableCubic mutableCubic, kotlin.jvm.functions.Function1<? super androidx.graphics.shapes.MutableCubic,kotlin.Unit> callback);
+    method public inline void forEachCubic(float progress, kotlin.jvm.functions.Function1<? super androidx.graphics.shapes.MutableCubic,kotlin.Unit> callback);
+  }
+
+  public final class MutableCubic extends androidx.graphics.shapes.Cubic {
+    ctor public MutableCubic();
+    method public void interpolate(androidx.graphics.shapes.Cubic c1, androidx.graphics.shapes.Cubic c2, float progress);
+    method public void transform(androidx.graphics.shapes.PointTransformer f);
+  }
+
+  public interface MutablePoint {
+    method public float getX();
+    method public float getY();
+    method public void setX(float);
+    method public void setY(float);
+    property public abstract float x;
+    property public abstract float y;
+  }
+
+  public fun interface PointTransformer {
+    method public long transform(float x, float y);
+  }
+
+  public final class RoundedPolygon {
+    method public float[] calculateBounds();
+    method public float[] calculateBounds(optional float[] bounds);
+    method public float[] calculateBounds(optional float[] bounds, optional boolean approximate);
+    method public float[] calculateMaxBounds(optional float[] bounds);
+    method public float getCenterX();
+    method public float getCenterY();
+    method public java.util.List<androidx.graphics.shapes.Cubic> getCubics();
+    method public androidx.graphics.shapes.RoundedPolygon normalized();
+    method public androidx.graphics.shapes.RoundedPolygon transformed(androidx.graphics.shapes.PointTransformer f);
+    property public final float centerX;
+    property public final float centerY;
+    property public final java.util.List<androidx.graphics.shapes.Cubic> cubics;
+    field public static final androidx.graphics.shapes.RoundedPolygon.Companion Companion;
+  }
+
+  public static final class RoundedPolygon.Companion {
+  }
+
+  public final class RoundedPolygonKt {
+    method public static androidx.graphics.shapes.RoundedPolygon RoundedPolygon(androidx.graphics.shapes.RoundedPolygon source);
+    method public static androidx.graphics.shapes.RoundedPolygon RoundedPolygon(float[] vertices);
+    method public static androidx.graphics.shapes.RoundedPolygon RoundedPolygon(float[] vertices, optional androidx.graphics.shapes.CornerRounding rounding);
+    method public static androidx.graphics.shapes.RoundedPolygon RoundedPolygon(float[] vertices, optional androidx.graphics.shapes.CornerRounding rounding, optional java.util.List<androidx.graphics.shapes.CornerRounding>? perVertexRounding);
+    method public static androidx.graphics.shapes.RoundedPolygon RoundedPolygon(float[] vertices, optional androidx.graphics.shapes.CornerRounding rounding, optional java.util.List<androidx.graphics.shapes.CornerRounding>? perVertexRounding, optional float centerX);
+    method public static androidx.graphics.shapes.RoundedPolygon RoundedPolygon(float[] vertices, optional androidx.graphics.shapes.CornerRounding rounding, optional java.util.List<androidx.graphics.shapes.CornerRounding>? perVertexRounding, optional float centerX, optional float centerY);
+    method public static androidx.graphics.shapes.RoundedPolygon RoundedPolygon(@IntRange(from=3L) int numVertices);
+    method public static androidx.graphics.shapes.RoundedPolygon RoundedPolygon(@IntRange(from=3L) int numVertices, optional float radius);
+    method public static androidx.graphics.shapes.RoundedPolygon RoundedPolygon(@IntRange(from=3L) int numVertices, optional float radius, optional float centerX);
+    method public static androidx.graphics.shapes.RoundedPolygon RoundedPolygon(@IntRange(from=3L) int numVertices, optional float radius, optional float centerX, optional float centerY);
+    method public static androidx.graphics.shapes.RoundedPolygon RoundedPolygon(@IntRange(from=3L) int numVertices, optional float radius, optional float centerX, optional float centerY, optional androidx.graphics.shapes.CornerRounding rounding);
+    method public static androidx.graphics.shapes.RoundedPolygon RoundedPolygon(@IntRange(from=3L) int numVertices, optional float radius, optional float centerX, optional float centerY, optional androidx.graphics.shapes.CornerRounding rounding, optional java.util.List<androidx.graphics.shapes.CornerRounding>? perVertexRounding);
+  }
+
+  public final class ShapesKt {
+    method public static androidx.graphics.shapes.RoundedPolygon circle(androidx.graphics.shapes.RoundedPolygon.Companion);
+    method public static androidx.graphics.shapes.RoundedPolygon circle(androidx.graphics.shapes.RoundedPolygon.Companion, optional @IntRange(from=3L) int numVertices);
+    method public static androidx.graphics.shapes.RoundedPolygon circle(androidx.graphics.shapes.RoundedPolygon.Companion, optional @IntRange(from=3L) int numVertices, optional float radius);
+    method public static androidx.graphics.shapes.RoundedPolygon circle(androidx.graphics.shapes.RoundedPolygon.Companion, optional @IntRange(from=3L) int numVertices, optional float radius, optional float centerX);
+    method public static androidx.graphics.shapes.RoundedPolygon circle(androidx.graphics.shapes.RoundedPolygon.Companion, optional @IntRange(from=3L) int numVertices, optional float radius, optional float centerX, optional float centerY);
+    method public static androidx.graphics.shapes.RoundedPolygon pill(androidx.graphics.shapes.RoundedPolygon.Companion);
+    method public static androidx.graphics.shapes.RoundedPolygon pill(androidx.graphics.shapes.RoundedPolygon.Companion, optional float width);
+    method public static androidx.graphics.shapes.RoundedPolygon pill(androidx.graphics.shapes.RoundedPolygon.Companion, optional float width, optional float height);
+    method public static androidx.graphics.shapes.RoundedPolygon pill(androidx.graphics.shapes.RoundedPolygon.Companion, optional float width, optional float height, optional float smoothing);
+    method public static androidx.graphics.shapes.RoundedPolygon pill(androidx.graphics.shapes.RoundedPolygon.Companion, optional float width, optional float height, optional float smoothing, optional float centerX);
+    method public static androidx.graphics.shapes.RoundedPolygon pill(androidx.graphics.shapes.RoundedPolygon.Companion, optional float width, optional float height, optional float smoothing, optional float centerX, optional float centerY);
+    method public static androidx.graphics.shapes.RoundedPolygon pillStar(androidx.graphics.shapes.RoundedPolygon.Companion);
+    method public static androidx.graphics.shapes.RoundedPolygon pillStar(androidx.graphics.shapes.RoundedPolygon.Companion, optional float width);
+    method public static androidx.graphics.shapes.RoundedPolygon pillStar(androidx.graphics.shapes.RoundedPolygon.Companion, optional float width, optional float height);
+    method public static androidx.graphics.shapes.RoundedPolygon pillStar(androidx.graphics.shapes.RoundedPolygon.Companion, optional float width, optional float height, optional int numVerticesPerRadius);
+    method public static androidx.graphics.shapes.RoundedPolygon pillStar(androidx.graphics.shapes.RoundedPolygon.Companion, optional float width, optional float height, optional int numVerticesPerRadius, optional @FloatRange(from=0.0, fromInclusive=false, to=1.0, toInclusive=false) float innerRadiusRatio);
+    method public static androidx.graphics.shapes.RoundedPolygon pillStar(androidx.graphics.shapes.RoundedPolygon.Companion, optional float width, optional float height, optional int numVerticesPerRadius, optional @FloatRange(from=0.0, fromInclusive=false, to=1.0, toInclusive=false) float innerRadiusRatio, optional androidx.graphics.shapes.CornerRounding rounding);
+    method public static androidx.graphics.shapes.RoundedPolygon pillStar(androidx.graphics.shapes.RoundedPolygon.Companion, optional float width, optional float height, optional int numVerticesPerRadius, optional @FloatRange(from=0.0, fromInclusive=false, to=1.0, toInclusive=false) float innerRadiusRatio, optional androidx.graphics.shapes.CornerRounding rounding, optional androidx.graphics.shapes.CornerRounding? innerRounding);
+    method public static androidx.graphics.shapes.RoundedPolygon pillStar(androidx.graphics.shapes.RoundedPolygon.Companion, optional float width, optional float height, optional int numVerticesPerRadius, optional @FloatRange(from=0.0, fromInclusive=false, to=1.0, toInclusive=false) float innerRadiusRatio, optional androidx.graphics.shapes.CornerRounding rounding, optional androidx.graphics.shapes.CornerRounding? innerRounding, optional java.util.List<androidx.graphics.shapes.CornerRounding>? perVertexRounding);
+    method public static androidx.graphics.shapes.RoundedPolygon pillStar(androidx.graphics.shapes.RoundedPolygon.Companion, optional float width, optional float height, optional int numVerticesPerRadius, optional @FloatRange(from=0.0, fromInclusive=false, to=1.0, toInclusive=false) float innerRadiusRatio, optional androidx.graphics.shapes.CornerRounding rounding, optional androidx.graphics.shapes.CornerRounding? innerRounding, optional java.util.List<androidx.graphics.shapes.CornerRounding>? perVertexRounding, optional @FloatRange(from=0.0, to=1.0) float vertexSpacing);
+    method public static androidx.graphics.shapes.RoundedPolygon pillStar(androidx.graphics.shapes.RoundedPolygon.Companion, optional float width, optional float height, optional int numVerticesPerRadius, optional @FloatRange(from=0.0, fromInclusive=false, to=1.0, toInclusive=false) float innerRadiusRatio, optional androidx.graphics.shapes.CornerRounding rounding, optional androidx.graphics.shapes.CornerRounding? innerRounding, optional java.util.List<androidx.graphics.shapes.CornerRounding>? perVertexRounding, optional @FloatRange(from=0.0, to=1.0) float vertexSpacing, optional @FloatRange(from=0.0, to=1.0) float startLocation);
+    method public static androidx.graphics.shapes.RoundedPolygon pillStar(androidx.graphics.shapes.RoundedPolygon.Companion, optional float width, optional float height, optional int numVerticesPerRadius, optional @FloatRange(from=0.0, fromInclusive=false, to=1.0, toInclusive=false) float innerRadiusRatio, optional androidx.graphics.shapes.CornerRounding rounding, optional androidx.graphics.shapes.CornerRounding? innerRounding, optional java.util.List<androidx.graphics.shapes.CornerRounding>? perVertexRounding, optional @FloatRange(from=0.0, to=1.0) float vertexSpacing, optional @FloatRange(from=0.0, to=1.0) float startLocation, optional float centerX);
+    method public static androidx.graphics.shapes.RoundedPolygon pillStar(androidx.graphics.shapes.RoundedPolygon.Companion, optional float width, optional float height, optional int numVerticesPerRadius, optional @FloatRange(from=0.0, fromInclusive=false, to=1.0, toInclusive=false) float innerRadiusRatio, optional androidx.graphics.shapes.CornerRounding rounding, optional androidx.graphics.shapes.CornerRounding? innerRounding, optional java.util.List<androidx.graphics.shapes.CornerRounding>? perVertexRounding, optional @FloatRange(from=0.0, to=1.0) float vertexSpacing, optional @FloatRange(from=0.0, to=1.0) float startLocation, optional float centerX, optional float centerY);
+    method public static androidx.graphics.shapes.RoundedPolygon rectangle(androidx.graphics.shapes.RoundedPolygon.Companion, optional float width, optional float height, optional androidx.graphics.shapes.CornerRounding rounding, optional java.util.List<androidx.graphics.shapes.CornerRounding>? perVertexRounding, optional float centerX, optional float centerY);
+    method public static androidx.graphics.shapes.RoundedPolygon star(androidx.graphics.shapes.RoundedPolygon.Companion, int numVerticesPerRadius);
+    method public static androidx.graphics.shapes.RoundedPolygon star(androidx.graphics.shapes.RoundedPolygon.Companion, int numVerticesPerRadius, optional float radius);
+    method public static androidx.graphics.shapes.RoundedPolygon star(androidx.graphics.shapes.RoundedPolygon.Companion, int numVerticesPerRadius, optional float radius, optional float innerRadius);
+    method public static androidx.graphics.shapes.RoundedPolygon star(androidx.graphics.shapes.RoundedPolygon.Companion, int numVerticesPerRadius, optional float radius, optional float innerRadius, optional androidx.graphics.shapes.CornerRounding rounding);
+    method public static androidx.graphics.shapes.RoundedPolygon star(androidx.graphics.shapes.RoundedPolygon.Companion, int numVerticesPerRadius, optional float radius, optional float innerRadius, optional androidx.graphics.shapes.CornerRounding rounding, optional androidx.graphics.shapes.CornerRounding? innerRounding);
+    method public static androidx.graphics.shapes.RoundedPolygon star(androidx.graphics.shapes.RoundedPolygon.Companion, int numVerticesPerRadius, optional float radius, optional float innerRadius, optional androidx.graphics.shapes.CornerRounding rounding, optional androidx.graphics.shapes.CornerRounding? innerRounding, optional java.util.List<androidx.graphics.shapes.CornerRounding>? perVertexRounding);
+    method public static androidx.graphics.shapes.RoundedPolygon star(androidx.graphics.shapes.RoundedPolygon.Companion, int numVerticesPerRadius, optional float radius, optional float innerRadius, optional androidx.graphics.shapes.CornerRounding rounding, optional androidx.graphics.shapes.CornerRounding? innerRounding, optional java.util.List<androidx.graphics.shapes.CornerRounding>? perVertexRounding, optional float centerX);
+    method public static androidx.graphics.shapes.RoundedPolygon star(androidx.graphics.shapes.RoundedPolygon.Companion, int numVerticesPerRadius, optional float radius, optional float innerRadius, optional androidx.graphics.shapes.CornerRounding rounding, optional androidx.graphics.shapes.CornerRounding? innerRounding, optional java.util.List<androidx.graphics.shapes.CornerRounding>? perVertexRounding, optional float centerX, optional float centerY);
+  }
+
+  public final class Shapes_androidKt {
+    method public static android.graphics.Path toPath(androidx.graphics.shapes.Morph, float progress, optional android.graphics.Path path);
+    method public static android.graphics.Path toPath(androidx.graphics.shapes.RoundedPolygon);
+    method public static android.graphics.Path toPath(androidx.graphics.shapes.RoundedPolygon, optional android.graphics.Path path);
+    method public static androidx.graphics.shapes.RoundedPolygon transformed(androidx.graphics.shapes.RoundedPolygon, android.graphics.Matrix matrix);
+  }
+
+}
+
diff --git a/graphics/graphics-shapes/api/res-1.0.0-beta02.txt b/graphics/graphics-shapes/api/res-1.0.0-beta02.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/graphics/graphics-shapes/api/res-1.0.0-beta02.txt
diff --git a/graphics/graphics-shapes/api/restricted_1.0.0-beta02.txt b/graphics/graphics-shapes/api/restricted_1.0.0-beta02.txt
new file mode 100644
index 0000000..d691f29
--- /dev/null
+++ b/graphics/graphics-shapes/api/restricted_1.0.0-beta02.txt
@@ -0,0 +1,164 @@
+// Signature format: 4.0
+package androidx.graphics.shapes {
+
+  public final class CornerRounding {
+    ctor public CornerRounding(optional @FloatRange(from=0.0) float radius, optional @FloatRange(from=0.0, to=1.0) float smoothing);
+    method public float getRadius();
+    method public float getSmoothing();
+    property public final float radius;
+    property public final float smoothing;
+    field public static final androidx.graphics.shapes.CornerRounding.Companion Companion;
+    field public static final androidx.graphics.shapes.CornerRounding Unrounded;
+  }
+
+  public static final class CornerRounding.Companion {
+  }
+
+  public class Cubic {
+    method public static final androidx.graphics.shapes.Cubic circularArc(float centerX, float centerY, float x0, float y0, float x1, float y1);
+    method public final operator androidx.graphics.shapes.Cubic div(float x);
+    method public final operator androidx.graphics.shapes.Cubic div(int x);
+    method public final float getAnchor0X();
+    method public final float getAnchor0Y();
+    method public final float getAnchor1X();
+    method public final float getAnchor1Y();
+    method public final float getControl0X();
+    method public final float getControl0Y();
+    method public final float getControl1X();
+    method public final float getControl1Y();
+    method public final operator androidx.graphics.shapes.Cubic plus(androidx.graphics.shapes.Cubic o);
+    method public final androidx.graphics.shapes.Cubic reverse();
+    method public final kotlin.Pair<androidx.graphics.shapes.Cubic,androidx.graphics.shapes.Cubic> split(float t);
+    method public static final androidx.graphics.shapes.Cubic straightLine(float x0, float y0, float x1, float y1);
+    method public final operator androidx.graphics.shapes.Cubic times(float x);
+    method public final operator androidx.graphics.shapes.Cubic times(int x);
+    method public final androidx.graphics.shapes.Cubic transformed(androidx.graphics.shapes.PointTransformer f);
+    property public final float anchor0X;
+    property public final float anchor0Y;
+    property public final float anchor1X;
+    property public final float anchor1Y;
+    property public final float control0X;
+    property public final float control0Y;
+    property public final float control1X;
+    property public final float control1Y;
+    field public static final androidx.graphics.shapes.Cubic.Companion Companion;
+  }
+
+  public static final class Cubic.Companion {
+    method public androidx.graphics.shapes.Cubic circularArc(float centerX, float centerY, float x0, float y0, float x1, float y1);
+    method public androidx.graphics.shapes.Cubic straightLine(float x0, float y0, float x1, float y1);
+  }
+
+  public final class CubicKt {
+    method public static androidx.graphics.shapes.Cubic Cubic(float anchor0X, float anchor0Y, float control0X, float control0Y, float control1X, float control1Y, float anchor1X, float anchor1Y);
+  }
+
+  public final class Morph {
+    ctor public Morph(androidx.graphics.shapes.RoundedPolygon start, androidx.graphics.shapes.RoundedPolygon end);
+    method public java.util.List<androidx.graphics.shapes.Cubic> asCubics(float progress);
+    method public float[] calculateBounds();
+    method public float[] calculateBounds(optional float[] bounds);
+    method public float[] calculateBounds(optional float[] bounds, optional boolean approximate);
+    method public float[] calculateMaxBounds(optional float[] bounds);
+    method public inline void forEachCubic(float progress, optional androidx.graphics.shapes.MutableCubic mutableCubic, kotlin.jvm.functions.Function1<? super androidx.graphics.shapes.MutableCubic,kotlin.Unit> callback);
+    method public inline void forEachCubic(float progress, kotlin.jvm.functions.Function1<? super androidx.graphics.shapes.MutableCubic,kotlin.Unit> callback);
+    property @kotlin.PublishedApi internal final java.util.List<kotlin.Pair<androidx.graphics.shapes.Cubic,androidx.graphics.shapes.Cubic>> morphMatch;
+  }
+
+  public final class MutableCubic extends androidx.graphics.shapes.Cubic {
+    ctor public MutableCubic();
+    method public void interpolate(androidx.graphics.shapes.Cubic c1, androidx.graphics.shapes.Cubic c2, float progress);
+    method public void transform(androidx.graphics.shapes.PointTransformer f);
+  }
+
+  public interface MutablePoint {
+    method public float getX();
+    method public float getY();
+    method public void setX(float);
+    method public void setY(float);
+    property public abstract float x;
+    property public abstract float y;
+  }
+
+  public fun interface PointTransformer {
+    method public long transform(float x, float y);
+  }
+
+  public final class RoundedPolygon {
+    method public float[] calculateBounds();
+    method public float[] calculateBounds(optional float[] bounds);
+    method public float[] calculateBounds(optional float[] bounds, optional boolean approximate);
+    method public float[] calculateMaxBounds(optional float[] bounds);
+    method public float getCenterX();
+    method public float getCenterY();
+    method public java.util.List<androidx.graphics.shapes.Cubic> getCubics();
+    method public androidx.graphics.shapes.RoundedPolygon normalized();
+    method public androidx.graphics.shapes.RoundedPolygon transformed(androidx.graphics.shapes.PointTransformer f);
+    property public final float centerX;
+    property public final float centerY;
+    property public final java.util.List<androidx.graphics.shapes.Cubic> cubics;
+    field public static final androidx.graphics.shapes.RoundedPolygon.Companion Companion;
+  }
+
+  public static final class RoundedPolygon.Companion {
+  }
+
+  public final class RoundedPolygonKt {
+    method public static androidx.graphics.shapes.RoundedPolygon RoundedPolygon(androidx.graphics.shapes.RoundedPolygon source);
+    method public static androidx.graphics.shapes.RoundedPolygon RoundedPolygon(float[] vertices);
+    method public static androidx.graphics.shapes.RoundedPolygon RoundedPolygon(float[] vertices, optional androidx.graphics.shapes.CornerRounding rounding);
+    method public static androidx.graphics.shapes.RoundedPolygon RoundedPolygon(float[] vertices, optional androidx.graphics.shapes.CornerRounding rounding, optional java.util.List<androidx.graphics.shapes.CornerRounding>? perVertexRounding);
+    method public static androidx.graphics.shapes.RoundedPolygon RoundedPolygon(float[] vertices, optional androidx.graphics.shapes.CornerRounding rounding, optional java.util.List<androidx.graphics.shapes.CornerRounding>? perVertexRounding, optional float centerX);
+    method public static androidx.graphics.shapes.RoundedPolygon RoundedPolygon(float[] vertices, optional androidx.graphics.shapes.CornerRounding rounding, optional java.util.List<androidx.graphics.shapes.CornerRounding>? perVertexRounding, optional float centerX, optional float centerY);
+    method public static androidx.graphics.shapes.RoundedPolygon RoundedPolygon(@IntRange(from=3L) int numVertices);
+    method public static androidx.graphics.shapes.RoundedPolygon RoundedPolygon(@IntRange(from=3L) int numVertices, optional float radius);
+    method public static androidx.graphics.shapes.RoundedPolygon RoundedPolygon(@IntRange(from=3L) int numVertices, optional float radius, optional float centerX);
+    method public static androidx.graphics.shapes.RoundedPolygon RoundedPolygon(@IntRange(from=3L) int numVertices, optional float radius, optional float centerX, optional float centerY);
+    method public static androidx.graphics.shapes.RoundedPolygon RoundedPolygon(@IntRange(from=3L) int numVertices, optional float radius, optional float centerX, optional float centerY, optional androidx.graphics.shapes.CornerRounding rounding);
+    method public static androidx.graphics.shapes.RoundedPolygon RoundedPolygon(@IntRange(from=3L) int numVertices, optional float radius, optional float centerX, optional float centerY, optional androidx.graphics.shapes.CornerRounding rounding, optional java.util.List<androidx.graphics.shapes.CornerRounding>? perVertexRounding);
+  }
+
+  public final class ShapesKt {
+    method public static androidx.graphics.shapes.RoundedPolygon circle(androidx.graphics.shapes.RoundedPolygon.Companion);
+    method public static androidx.graphics.shapes.RoundedPolygon circle(androidx.graphics.shapes.RoundedPolygon.Companion, optional @IntRange(from=3L) int numVertices);
+    method public static androidx.graphics.shapes.RoundedPolygon circle(androidx.graphics.shapes.RoundedPolygon.Companion, optional @IntRange(from=3L) int numVertices, optional float radius);
+    method public static androidx.graphics.shapes.RoundedPolygon circle(androidx.graphics.shapes.RoundedPolygon.Companion, optional @IntRange(from=3L) int numVertices, optional float radius, optional float centerX);
+    method public static androidx.graphics.shapes.RoundedPolygon circle(androidx.graphics.shapes.RoundedPolygon.Companion, optional @IntRange(from=3L) int numVertices, optional float radius, optional float centerX, optional float centerY);
+    method public static androidx.graphics.shapes.RoundedPolygon pill(androidx.graphics.shapes.RoundedPolygon.Companion);
+    method public static androidx.graphics.shapes.RoundedPolygon pill(androidx.graphics.shapes.RoundedPolygon.Companion, optional float width);
+    method public static androidx.graphics.shapes.RoundedPolygon pill(androidx.graphics.shapes.RoundedPolygon.Companion, optional float width, optional float height);
+    method public static androidx.graphics.shapes.RoundedPolygon pill(androidx.graphics.shapes.RoundedPolygon.Companion, optional float width, optional float height, optional float smoothing);
+    method public static androidx.graphics.shapes.RoundedPolygon pill(androidx.graphics.shapes.RoundedPolygon.Companion, optional float width, optional float height, optional float smoothing, optional float centerX);
+    method public static androidx.graphics.shapes.RoundedPolygon pill(androidx.graphics.shapes.RoundedPolygon.Companion, optional float width, optional float height, optional float smoothing, optional float centerX, optional float centerY);
+    method public static androidx.graphics.shapes.RoundedPolygon pillStar(androidx.graphics.shapes.RoundedPolygon.Companion);
+    method public static androidx.graphics.shapes.RoundedPolygon pillStar(androidx.graphics.shapes.RoundedPolygon.Companion, optional float width);
+    method public static androidx.graphics.shapes.RoundedPolygon pillStar(androidx.graphics.shapes.RoundedPolygon.Companion, optional float width, optional float height);
+    method public static androidx.graphics.shapes.RoundedPolygon pillStar(androidx.graphics.shapes.RoundedPolygon.Companion, optional float width, optional float height, optional int numVerticesPerRadius);
+    method public static androidx.graphics.shapes.RoundedPolygon pillStar(androidx.graphics.shapes.RoundedPolygon.Companion, optional float width, optional float height, optional int numVerticesPerRadius, optional @FloatRange(from=0.0, fromInclusive=false, to=1.0, toInclusive=false) float innerRadiusRatio);
+    method public static androidx.graphics.shapes.RoundedPolygon pillStar(androidx.graphics.shapes.RoundedPolygon.Companion, optional float width, optional float height, optional int numVerticesPerRadius, optional @FloatRange(from=0.0, fromInclusive=false, to=1.0, toInclusive=false) float innerRadiusRatio, optional androidx.graphics.shapes.CornerRounding rounding);
+    method public static androidx.graphics.shapes.RoundedPolygon pillStar(androidx.graphics.shapes.RoundedPolygon.Companion, optional float width, optional float height, optional int numVerticesPerRadius, optional @FloatRange(from=0.0, fromInclusive=false, to=1.0, toInclusive=false) float innerRadiusRatio, optional androidx.graphics.shapes.CornerRounding rounding, optional androidx.graphics.shapes.CornerRounding? innerRounding);
+    method public static androidx.graphics.shapes.RoundedPolygon pillStar(androidx.graphics.shapes.RoundedPolygon.Companion, optional float width, optional float height, optional int numVerticesPerRadius, optional @FloatRange(from=0.0, fromInclusive=false, to=1.0, toInclusive=false) float innerRadiusRatio, optional androidx.graphics.shapes.CornerRounding rounding, optional androidx.graphics.shapes.CornerRounding? innerRounding, optional java.util.List<androidx.graphics.shapes.CornerRounding>? perVertexRounding);
+    method public static androidx.graphics.shapes.RoundedPolygon pillStar(androidx.graphics.shapes.RoundedPolygon.Companion, optional float width, optional float height, optional int numVerticesPerRadius, optional @FloatRange(from=0.0, fromInclusive=false, to=1.0, toInclusive=false) float innerRadiusRatio, optional androidx.graphics.shapes.CornerRounding rounding, optional androidx.graphics.shapes.CornerRounding? innerRounding, optional java.util.List<androidx.graphics.shapes.CornerRounding>? perVertexRounding, optional @FloatRange(from=0.0, to=1.0) float vertexSpacing);
+    method public static androidx.graphics.shapes.RoundedPolygon pillStar(androidx.graphics.shapes.RoundedPolygon.Companion, optional float width, optional float height, optional int numVerticesPerRadius, optional @FloatRange(from=0.0, fromInclusive=false, to=1.0, toInclusive=false) float innerRadiusRatio, optional androidx.graphics.shapes.CornerRounding rounding, optional androidx.graphics.shapes.CornerRounding? innerRounding, optional java.util.List<androidx.graphics.shapes.CornerRounding>? perVertexRounding, optional @FloatRange(from=0.0, to=1.0) float vertexSpacing, optional @FloatRange(from=0.0, to=1.0) float startLocation);
+    method public static androidx.graphics.shapes.RoundedPolygon pillStar(androidx.graphics.shapes.RoundedPolygon.Companion, optional float width, optional float height, optional int numVerticesPerRadius, optional @FloatRange(from=0.0, fromInclusive=false, to=1.0, toInclusive=false) float innerRadiusRatio, optional androidx.graphics.shapes.CornerRounding rounding, optional androidx.graphics.shapes.CornerRounding? innerRounding, optional java.util.List<androidx.graphics.shapes.CornerRounding>? perVertexRounding, optional @FloatRange(from=0.0, to=1.0) float vertexSpacing, optional @FloatRange(from=0.0, to=1.0) float startLocation, optional float centerX);
+    method public static androidx.graphics.shapes.RoundedPolygon pillStar(androidx.graphics.shapes.RoundedPolygon.Companion, optional float width, optional float height, optional int numVerticesPerRadius, optional @FloatRange(from=0.0, fromInclusive=false, to=1.0, toInclusive=false) float innerRadiusRatio, optional androidx.graphics.shapes.CornerRounding rounding, optional androidx.graphics.shapes.CornerRounding? innerRounding, optional java.util.List<androidx.graphics.shapes.CornerRounding>? perVertexRounding, optional @FloatRange(from=0.0, to=1.0) float vertexSpacing, optional @FloatRange(from=0.0, to=1.0) float startLocation, optional float centerX, optional float centerY);
+    method public static androidx.graphics.shapes.RoundedPolygon rectangle(androidx.graphics.shapes.RoundedPolygon.Companion, optional float width, optional float height, optional androidx.graphics.shapes.CornerRounding rounding, optional java.util.List<androidx.graphics.shapes.CornerRounding>? perVertexRounding, optional float centerX, optional float centerY);
+    method public static androidx.graphics.shapes.RoundedPolygon star(androidx.graphics.shapes.RoundedPolygon.Companion, int numVerticesPerRadius);
+    method public static androidx.graphics.shapes.RoundedPolygon star(androidx.graphics.shapes.RoundedPolygon.Companion, int numVerticesPerRadius, optional float radius);
+    method public static androidx.graphics.shapes.RoundedPolygon star(androidx.graphics.shapes.RoundedPolygon.Companion, int numVerticesPerRadius, optional float radius, optional float innerRadius);
+    method public static androidx.graphics.shapes.RoundedPolygon star(androidx.graphics.shapes.RoundedPolygon.Companion, int numVerticesPerRadius, optional float radius, optional float innerRadius, optional androidx.graphics.shapes.CornerRounding rounding);
+    method public static androidx.graphics.shapes.RoundedPolygon star(androidx.graphics.shapes.RoundedPolygon.Companion, int numVerticesPerRadius, optional float radius, optional float innerRadius, optional androidx.graphics.shapes.CornerRounding rounding, optional androidx.graphics.shapes.CornerRounding? innerRounding);
+    method public static androidx.graphics.shapes.RoundedPolygon star(androidx.graphics.shapes.RoundedPolygon.Companion, int numVerticesPerRadius, optional float radius, optional float innerRadius, optional androidx.graphics.shapes.CornerRounding rounding, optional androidx.graphics.shapes.CornerRounding? innerRounding, optional java.util.List<androidx.graphics.shapes.CornerRounding>? perVertexRounding);
+    method public static androidx.graphics.shapes.RoundedPolygon star(androidx.graphics.shapes.RoundedPolygon.Companion, int numVerticesPerRadius, optional float radius, optional float innerRadius, optional androidx.graphics.shapes.CornerRounding rounding, optional androidx.graphics.shapes.CornerRounding? innerRounding, optional java.util.List<androidx.graphics.shapes.CornerRounding>? perVertexRounding, optional float centerX);
+    method public static androidx.graphics.shapes.RoundedPolygon star(androidx.graphics.shapes.RoundedPolygon.Companion, int numVerticesPerRadius, optional float radius, optional float innerRadius, optional androidx.graphics.shapes.CornerRounding rounding, optional androidx.graphics.shapes.CornerRounding? innerRounding, optional java.util.List<androidx.graphics.shapes.CornerRounding>? perVertexRounding, optional float centerX, optional float centerY);
+  }
+
+  public final class Shapes_androidKt {
+    method public static android.graphics.Path toPath(androidx.graphics.shapes.Morph, float progress, optional android.graphics.Path path);
+    method public static android.graphics.Path toPath(androidx.graphics.shapes.RoundedPolygon);
+    method public static android.graphics.Path toPath(androidx.graphics.shapes.RoundedPolygon, optional android.graphics.Path path);
+    method public static androidx.graphics.shapes.RoundedPolygon transformed(androidx.graphics.shapes.RoundedPolygon, android.graphics.Matrix matrix);
+  }
+
+}
+
diff --git a/graphics/graphics-shapes/build.gradle b/graphics/graphics-shapes/build.gradle
index 3fcc603..c75fad11 100644
--- a/graphics/graphics-shapes/build.gradle
+++ b/graphics/graphics-shapes/build.gradle
@@ -71,7 +71,7 @@
             dependsOn(jvmMain)
             dependencies {
                 implementation("androidx.core:core-ktx:1.10.0")
-                implementation(project(":annotation:annotation-experimental"))
+                implementation("androidx.annotation:annotation-experimental:1.4.0-rc01")
             }
         }
 
diff --git a/health/connect/connect-client/build.gradle b/health/connect/connect-client/build.gradle
index 1dd21ba..9717548 100644
--- a/health/connect/connect-client/build.gradle
+++ b/health/connect/connect-client/build.gradle
@@ -86,7 +86,8 @@
     }
     testOptions.unitTests.includeAndroidResources = true
     namespace "androidx.health.connect.client"
-    compileSdkVersion = "android-34-ext10"
+    compileSdk = 34
+    compileSdkExtension = 10
 }
 
 androidx {
diff --git a/libraryversions.toml b/libraryversions.toml
index 91ec465..93c28a5 100644
--- a/libraryversions.toml
+++ b/libraryversions.toml
@@ -73,7 +73,7 @@
 GRAPHICS_CORE = "1.0.0-rc01"
 GRAPHICS_FILTERS = "1.0.0-alpha01"
 GRAPHICS_PATH = "1.0.0-rc01"
-GRAPHICS_SHAPES = "1.0.0-beta01"
+GRAPHICS_SHAPES = "1.0.0-beta02"
 GRIDLAYOUT = "1.1.0-beta02"
 HEALTH_CONNECT = "1.1.0-alpha08"
 HEALTH_SERVICES_CLIENT = "1.1.0-alpha03"
diff --git a/lifecycle/integration-tests/incrementality/src/test/kotlin/androidx/lifecycle/IncrementalAnnotationProcessingTest.kt b/lifecycle/integration-tests/incrementality/src/test/kotlin/androidx/lifecycle/IncrementalAnnotationProcessingTest.kt
index eafa782..0e028ea 100644
--- a/lifecycle/integration-tests/incrementality/src/test/kotlin/androidx/lifecycle/IncrementalAnnotationProcessingTest.kt
+++ b/lifecycle/integration-tests/incrementality/src/test/kotlin/androidx/lifecycle/IncrementalAnnotationProcessingTest.kt
@@ -237,7 +237,7 @@
 
             android {
                 namespace "androidx.lifecycle.incap"
-                compileSdkVersion ${projectSetup.props.compileSdkVersion}
+                compileSdk ${projectSetup.props.compileSdk}
                 buildToolsVersion "${projectSetup.props.buildToolsVersion}"
 
                 defaultConfig {
diff --git a/lifecycle/lifecycle-common/src/jvmMain/baseline-prof.txt b/lifecycle/lifecycle-common/src/jvmMain/baseline-prof.txt
deleted file mode 100644
index 041b060..0000000
--- a/lifecycle/lifecycle-common/src/jvmMain/baseline-prof.txt
+++ /dev/null
@@ -1,44 +0,0 @@
-# Baseline Profiles for lifecycle-common
-
-HPLandroidx/lifecycle/Lifecycle$Event;->downFrom(Landroidx/lifecycle/Lifecycle$State;)Landroidx/lifecycle/Lifecycle$Event;
-HSPLandroidx/lifecycle/ClassesInfoCache$CallbackInfo;-><init>(Ljava/util/Map;)V
-HSPLandroidx/lifecycle/ClassesInfoCache$CallbackInfo;->invokeCallbacks(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;Ljava/lang/Object;)V
-HSPLandroidx/lifecycle/ClassesInfoCache$CallbackInfo;->invokeMethodsForEvent(Ljava/util/List;Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;Ljava/lang/Object;)V
-HSPLandroidx/lifecycle/ClassesInfoCache$MethodReference;-><init>(ILjava/lang/reflect/Method;)V
-HSPLandroidx/lifecycle/ClassesInfoCache$MethodReference;->hashCode()I
-HSPLandroidx/lifecycle/ClassesInfoCache$MethodReference;->invokeCallback(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;Ljava/lang/Object;)V
-HSPLandroidx/lifecycle/ClassesInfoCache;-><clinit>()V
-HSPLandroidx/lifecycle/ClassesInfoCache;-><init>()V
-HSPLandroidx/lifecycle/ClassesInfoCache;->createInfo(Ljava/lang/Class;[Ljava/lang/reflect/Method;)Landroidx/lifecycle/ClassesInfoCache$CallbackInfo;
-HSPLandroidx/lifecycle/ClassesInfoCache;->getDeclaredMethods(Ljava/lang/Class;)[Ljava/lang/reflect/Method;
-HSPLandroidx/lifecycle/ClassesInfoCache;->getInfo(Ljava/lang/Class;)Landroidx/lifecycle/ClassesInfoCache$CallbackInfo;
-HSPLandroidx/lifecycle/ClassesInfoCache;->hasLifecycleMethods(Ljava/lang/Class;)Z
-HSPLandroidx/lifecycle/ClassesInfoCache;->verifyAndPutHandler(Ljava/util/Map;Landroidx/lifecycle/ClassesInfoCache$MethodReference;Landroidx/lifecycle/Lifecycle$Event;Ljava/lang/Class;)V
-HSPLandroidx/lifecycle/DefaultLifecycleObserver$-CC;->$default$onCreate(Landroidx/lifecycle/DefaultLifecycleObserver;Landroidx/lifecycle/LifecycleOwner;)V
-HSPLandroidx/lifecycle/DefaultLifecycleObserver$-CC;->$default$onResume(Landroidx/lifecycle/DefaultLifecycleObserver;Landroidx/lifecycle/LifecycleOwner;)V
-HSPLandroidx/lifecycle/DefaultLifecycleObserver$-CC;->$default$onStart(Landroidx/lifecycle/DefaultLifecycleObserver;Landroidx/lifecycle/LifecycleOwner;)V
-HSPLandroidx/lifecycle/FullLifecycleObserverAdapter$1;-><clinit>()V
-HSPLandroidx/lifecycle/FullLifecycleObserverAdapter;-><init>(Landroidx/lifecycle/FullLifecycleObserver;Landroidx/lifecycle/LifecycleEventObserver;)V
-HSPLandroidx/lifecycle/FullLifecycleObserverAdapter;->onStateChanged(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V
-HSPLandroidx/lifecycle/Lifecycle$1;-><clinit>()V
-HSPLandroidx/lifecycle/Lifecycle$Event;-><clinit>()V
-HSPLandroidx/lifecycle/Lifecycle$Event;-><init>(Ljava/lang/String;I)V
-HSPLandroidx/lifecycle/Lifecycle$Event;->getTargetState()Landroidx/lifecycle/Lifecycle$State;
-HSPLandroidx/lifecycle/Lifecycle$Event;->upFrom(Landroidx/lifecycle/Lifecycle$State;)Landroidx/lifecycle/Lifecycle$Event;
-HSPLandroidx/lifecycle/Lifecycle$Event;->values()[Landroidx/lifecycle/Lifecycle$Event;
-HSPLandroidx/lifecycle/Lifecycle$State;-><clinit>()V
-HSPLandroidx/lifecycle/Lifecycle$State;-><init>(Ljava/lang/String;I)V
-HSPLandroidx/lifecycle/Lifecycle$State;->isAtLeast(Landroidx/lifecycle/Lifecycle$State;)Z
-HSPLandroidx/lifecycle/Lifecycle$State;->values()[Landroidx/lifecycle/Lifecycle$State;
-HSPLandroidx/lifecycle/Lifecycle;-><init>()V
-HSPLandroidx/lifecycle/Lifecycling;-><clinit>()V
-HSPLandroidx/lifecycle/Lifecycling;->generatedConstructor(Ljava/lang/Class;)Ljava/lang/reflect/Constructor;
-HSPLandroidx/lifecycle/Lifecycling;->getAdapterName(Ljava/lang/String;)Ljava/lang/String;
-HSPLandroidx/lifecycle/Lifecycling;->getObserverConstructorType(Ljava/lang/Class;)I
-HSPLandroidx/lifecycle/Lifecycling;->lifecycleEventObserver(Ljava/lang/Object;)Landroidx/lifecycle/LifecycleEventObserver;
-HSPLandroidx/lifecycle/Lifecycling;->resolveObserverCallbackType(Ljava/lang/Class;)I
-HSPLandroidx/lifecycle/ReflectiveGenericLifecycleObserver;-><init>(Ljava/lang/Object;)V
-HSPLandroidx/lifecycle/ReflectiveGenericLifecycleObserver;->onStateChanged(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V
-PLandroidx/lifecycle/DefaultLifecycleObserver$-CC;->$default$onDestroy(Landroidx/lifecycle/DefaultLifecycleObserver;Landroidx/lifecycle/LifecycleOwner;)V
-PLandroidx/lifecycle/DefaultLifecycleObserver$-CC;->$default$onPause(Landroidx/lifecycle/DefaultLifecycleObserver;Landroidx/lifecycle/LifecycleOwner;)V
-PLandroidx/lifecycle/DefaultLifecycleObserver$-CC;->$default$onStop(Landroidx/lifecycle/DefaultLifecycleObserver;Landroidx/lifecycle/LifecycleOwner;)V
diff --git a/lifecycle/lifecycle-runtime/build.gradle b/lifecycle/lifecycle-runtime/build.gradle
index 323d017..b8503f9 100644
--- a/lifecycle/lifecycle-runtime/build.gradle
+++ b/lifecycle/lifecycle-runtime/build.gradle
@@ -14,6 +14,7 @@
 plugins {
     id("AndroidXPlugin")
     id("com.android.library")
+    id("androidx.baselineprofile")
 }
 androidXMultiplatform {
     android()
@@ -56,6 +57,12 @@
             dependsOn(jvmMain)
         }
 
+        desktopTest {
+            dependencies {
+                implementation(libs.kotlinCoroutinesSwing)
+            }
+        }
+
         androidMain {
             dependsOn(jvmMain)
             dependencies {
diff --git a/lifecycle/lifecycle-runtime/src/androidMain/baseline-prof.txt b/lifecycle/lifecycle-runtime/src/androidMain/baseline-prof.txt
index 47d4f10..e60ad60 100644
--- a/lifecycle/lifecycle-runtime/src/androidMain/baseline-prof.txt
+++ b/lifecycle/lifecycle-runtime/src/androidMain/baseline-prof.txt
@@ -48,3 +48,48 @@
 PLandroidx/lifecycle/ReportFragment;->onDestroy()V
 PLandroidx/lifecycle/ReportFragment;->onPause()V
 PLandroidx/lifecycle/ReportFragment;->onStop()V
+
+# Baseline Profiles for lifecycle-common
+
+HPLandroidx/lifecycle/Lifecycle$Event;->downFrom(Landroidx/lifecycle/Lifecycle$State;)Landroidx/lifecycle/Lifecycle$Event;
+HSPLandroidx/lifecycle/ClassesInfoCache$CallbackInfo;-><init>(Ljava/util/Map;)V
+HSPLandroidx/lifecycle/ClassesInfoCache$CallbackInfo;->invokeCallbacks(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;Ljava/lang/Object;)V
+HSPLandroidx/lifecycle/ClassesInfoCache$CallbackInfo;->invokeMethodsForEvent(Ljava/util/List;Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;Ljava/lang/Object;)V
+HSPLandroidx/lifecycle/ClassesInfoCache$MethodReference;-><init>(ILjava/lang/reflect/Method;)V
+HSPLandroidx/lifecycle/ClassesInfoCache$MethodReference;->hashCode()I
+HSPLandroidx/lifecycle/ClassesInfoCache$MethodReference;->invokeCallback(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;Ljava/lang/Object;)V
+HSPLandroidx/lifecycle/ClassesInfoCache;-><clinit>()V
+HSPLandroidx/lifecycle/ClassesInfoCache;-><init>()V
+HSPLandroidx/lifecycle/ClassesInfoCache;->createInfo(Ljava/lang/Class;[Ljava/lang/reflect/Method;)Landroidx/lifecycle/ClassesInfoCache$CallbackInfo;
+HSPLandroidx/lifecycle/ClassesInfoCache;->getDeclaredMethods(Ljava/lang/Class;)[Ljava/lang/reflect/Method;
+HSPLandroidx/lifecycle/ClassesInfoCache;->getInfo(Ljava/lang/Class;)Landroidx/lifecycle/ClassesInfoCache$CallbackInfo;
+HSPLandroidx/lifecycle/ClassesInfoCache;->hasLifecycleMethods(Ljava/lang/Class;)Z
+HSPLandroidx/lifecycle/ClassesInfoCache;->verifyAndPutHandler(Ljava/util/Map;Landroidx/lifecycle/ClassesInfoCache$MethodReference;Landroidx/lifecycle/Lifecycle$Event;Ljava/lang/Class;)V
+HSPLandroidx/lifecycle/DefaultLifecycleObserver$-CC;->$default$onCreate(Landroidx/lifecycle/DefaultLifecycleObserver;Landroidx/lifecycle/LifecycleOwner;)V
+HSPLandroidx/lifecycle/DefaultLifecycleObserver$-CC;->$default$onResume(Landroidx/lifecycle/DefaultLifecycleObserver;Landroidx/lifecycle/LifecycleOwner;)V
+HSPLandroidx/lifecycle/DefaultLifecycleObserver$-CC;->$default$onStart(Landroidx/lifecycle/DefaultLifecycleObserver;Landroidx/lifecycle/LifecycleOwner;)V
+HSPLandroidx/lifecycle/FullLifecycleObserverAdapter$1;-><clinit>()V
+HSPLandroidx/lifecycle/FullLifecycleObserverAdapter;-><init>(Landroidx/lifecycle/FullLifecycleObserver;Landroidx/lifecycle/LifecycleEventObserver;)V
+HSPLandroidx/lifecycle/FullLifecycleObserverAdapter;->onStateChanged(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V
+HSPLandroidx/lifecycle/Lifecycle$1;-><clinit>()V
+HSPLandroidx/lifecycle/Lifecycle$Event;-><clinit>()V
+HSPLandroidx/lifecycle/Lifecycle$Event;-><init>(Ljava/lang/String;I)V
+HSPLandroidx/lifecycle/Lifecycle$Event;->getTargetState()Landroidx/lifecycle/Lifecycle$State;
+HSPLandroidx/lifecycle/Lifecycle$Event;->upFrom(Landroidx/lifecycle/Lifecycle$State;)Landroidx/lifecycle/Lifecycle$Event;
+HSPLandroidx/lifecycle/Lifecycle$Event;->values()[Landroidx/lifecycle/Lifecycle$Event;
+HSPLandroidx/lifecycle/Lifecycle$State;-><clinit>()V
+HSPLandroidx/lifecycle/Lifecycle$State;-><init>(Ljava/lang/String;I)V
+HSPLandroidx/lifecycle/Lifecycle$State;->isAtLeast(Landroidx/lifecycle/Lifecycle$State;)Z
+HSPLandroidx/lifecycle/Lifecycle$State;->values()[Landroidx/lifecycle/Lifecycle$State;
+HSPLandroidx/lifecycle/Lifecycle;-><init>()V
+HSPLandroidx/lifecycle/Lifecycling;-><clinit>()V
+HSPLandroidx/lifecycle/Lifecycling;->generatedConstructor(Ljava/lang/Class;)Ljava/lang/reflect/Constructor;
+HSPLandroidx/lifecycle/Lifecycling;->getAdapterName(Ljava/lang/String;)Ljava/lang/String;
+HSPLandroidx/lifecycle/Lifecycling;->getObserverConstructorType(Ljava/lang/Class;)I
+HSPLandroidx/lifecycle/Lifecycling;->lifecycleEventObserver(Ljava/lang/Object;)Landroidx/lifecycle/LifecycleEventObserver;
+HSPLandroidx/lifecycle/Lifecycling;->resolveObserverCallbackType(Ljava/lang/Class;)I
+HSPLandroidx/lifecycle/ReflectiveGenericLifecycleObserver;-><init>(Ljava/lang/Object;)V
+HSPLandroidx/lifecycle/ReflectiveGenericLifecycleObserver;->onStateChanged(Landroidx/lifecycle/LifecycleOwner;Landroidx/lifecycle/Lifecycle$Event;)V
+PLandroidx/lifecycle/DefaultLifecycleObserver$-CC;->$default$onDestroy(Landroidx/lifecycle/DefaultLifecycleObserver;Landroidx/lifecycle/LifecycleOwner;)V
+PLandroidx/lifecycle/DefaultLifecycleObserver$-CC;->$default$onPause(Landroidx/lifecycle/DefaultLifecycleObserver;Landroidx/lifecycle/LifecycleOwner;)V
+PLandroidx/lifecycle/DefaultLifecycleObserver$-CC;->$default$onStop(Landroidx/lifecycle/DefaultLifecycleObserver;Landroidx/lifecycle/LifecycleOwner;)V
diff --git a/lifecycle/lifecycle-runtime/src/desktopMain/kotlin/androidx/lifecycle/MainDispatcherChecker.desktop.kt b/lifecycle/lifecycle-runtime/src/desktopMain/kotlin/androidx/lifecycle/MainDispatcherChecker.desktop.kt
index b2088bf..6d4407c 100644
--- a/lifecycle/lifecycle-runtime/src/desktopMain/kotlin/androidx/lifecycle/MainDispatcherChecker.desktop.kt
+++ b/lifecycle/lifecycle-runtime/src/desktopMain/kotlin/androidx/lifecycle/MainDispatcherChecker.desktop.kt
@@ -16,30 +16,45 @@
 package androidx.lifecycle
 
 import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.launch
 import kotlinx.coroutines.runBlocking
 
 internal object MainDispatcherChecker {
-    private val isMainDispatcherAvailable: Boolean
-    private var isMainDispatcherThread = ThreadLocal.withInitial { false }
+    private var isMainDispatcherAvailable: Boolean = true
+    @Volatile
+    private var mainDispatcherThread: Thread? = null
 
-    init {
-        isMainDispatcherAvailable = try {
-            runBlocking {
-                launch(Dispatchers.Main.immediate) {
-                    isMainDispatcherThread.set(true)
-                }
+    private fun updateMainDispatcherThread() {
+        try {
+            runBlocking(Dispatchers.Main.immediate) {
+                mainDispatcherThread = Thread.currentThread()
             }
-            true
         } catch (_: IllegalStateException) {
             // No main dispatchers are present in the classpath
-            false
+            isMainDispatcherAvailable = false
         }
     }
 
-    fun isMainDispatcherThread(): Boolean = if (isMainDispatcherAvailable) {
-        isMainDispatcherThread.get()
-    } else {
-        true
+    fun isMainDispatcherThread(): Boolean {
+        if (!isMainDispatcherAvailable) {
+            // If we know there's no main dispatcher, assume we're on it.
+            return true
+        }
+
+        val currentThread = Thread.currentThread()
+        // If the thread has already been retrieved,
+        // we can just check whether we are currently running on the same thread
+        if (currentThread === mainDispatcherThread) {
+            return true
+        }
+
+        // If the current thread doesn't match the stored main dispatcher thread, is is either:
+        // * The field may not have been initialized yet.
+        // * The Swing Event Dispatch Thread (EDT) may have changed (if applicable).
+        // * We're genuinely not executing on the main thread.
+        // Let's recheck to obtain the most up-to-date dispatcher reference. The recheck can
+        // be time-consuming, but should only occur in less common scenarios.
+        updateMainDispatcherThread()
+
+        return !isMainDispatcherAvailable || currentThread === mainDispatcherThread
     }
 }
diff --git a/lifecycle/lifecycle-runtime/src/desktopTest/kotlin/MainDispatcherCheckerTest.kt b/lifecycle/lifecycle-runtime/src/desktopTest/kotlin/MainDispatcherCheckerTest.kt
new file mode 100644
index 0000000..9ecaacf
--- /dev/null
+++ b/lifecycle/lifecycle-runtime/src/desktopTest/kotlin/MainDispatcherCheckerTest.kt
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+
+import androidx.lifecycle.MainDispatcherChecker
+import java.util.concurrent.ExecutorService
+import java.util.concurrent.Executors
+import kotlin.coroutines.CoroutineContext
+import kotlin.test.Test
+import kotlin.test.assertFalse
+import kotlin.test.assertTrue
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.MainCoroutineDispatcher
+import kotlinx.coroutines.Runnable
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.resetMain
+import kotlinx.coroutines.test.setMain
+
+class MainDispatcherCheckerTest {
+    @Test
+    fun checkMainDispatcher() {
+        runBlocking(Dispatchers.Main) {
+            assertTrue(MainDispatcherChecker.isMainDispatcherThread())
+        }
+        runBlocking(Dispatchers.Main.immediate) {
+            assertTrue(MainDispatcherChecker.isMainDispatcherThread())
+        }
+    }
+
+    @Test
+    fun checkNonMainDispatcher() {
+        runBlocking(Dispatchers.IO) {
+            assertFalse(MainDispatcherChecker.isMainDispatcherThread())
+        }
+    }
+
+    @OptIn(ExperimentalCoroutinesApi::class)
+    @Test
+    fun checkMainDispatcherChanged() {
+        try {
+            Dispatchers.setMain(ThreadChangingMainDispatcher)
+            runBlocking(Dispatchers.Main) {
+                assertTrue(MainDispatcherChecker.isMainDispatcherThread())
+            }
+            ThreadChangingMainDispatcher.changeThread()
+            runBlocking(Dispatchers.Main) {
+                assertTrue(MainDispatcherChecker.isMainDispatcherThread())
+            }
+        } finally {
+            Dispatchers.resetMain()
+        }
+    }
+
+    private object ThreadChangingMainDispatcher : MainCoroutineDispatcher() {
+        private var thread: Thread? = null
+        private var executor = newExecutorService()
+
+        override val immediate: MainCoroutineDispatcher
+            get() = this
+
+        override fun dispatch(context: CoroutineContext, block: Runnable) {
+            // support reentrancy
+            if (Thread.currentThread() == thread) {
+                block.run()
+            } else {
+                executor.submit(block)
+            }
+        }
+
+        fun changeThread() {
+            executor.shutdown()
+            executor = newExecutorService()
+        }
+
+        private fun newExecutorService(): ExecutorService =
+            Executors.newSingleThreadExecutor {
+                thread = Thread(it)
+                thread
+            }
+    }
+}
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 cb1bb1a..10913aa 100644
--- a/lifecycle/lifecycle-viewmodel/src/commonMain/kotlin/androidx/lifecycle/ViewModel.kt
+++ b/lifecycle/lifecycle-viewmodel/src/commonMain/kotlin/androidx/lifecycle/ViewModel.kt
@@ -145,10 +145,7 @@
      * prevent a memory leak, as the subscriptions might hold a reference to the [ViewModel] even
      * after it is no longer needed.
      *
-     * **Clearing Sequence:**
-     * 1. [AutoCloseable.close] resources added **without** a key via [addCloseable].
-     * 2. [AutoCloseable.close] resources added **with** a key via [addCloseable].
-     * 3. Invoke the [onCleared] callback.
+     * For specifics about the clearing sequence, refer to the [clear] method.
      */
     protected open fun onCleared()
 
@@ -159,9 +156,10 @@
      * immediately closed.
      *
      * **Clearing Sequence:**
-     * 1. [AutoCloseable.close] resources added **without** a key via [addCloseable].
-     * 2. [AutoCloseable.close] resources added **with** a key via [addCloseable].
-     * 3. Invoke the [onCleared] callback.
+     * 1. [Close][AutoCloseable.close] resources added **with** a key via [addCloseable].
+     * 2. [Close][AutoCloseable.close] resources added via `constructor`.
+     * 3. [Close][AutoCloseable.close] resources added **without** a key via [addCloseable].
+     * 4. Invoke the [onCleared] callback.
      */
     @MainThread
     internal fun clear()
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 dd79e0c..00efd4b 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
@@ -42,13 +42,10 @@
      * The associated resources will be [AutoCloseable.close] right before the [ViewModel.onCleared]
      * is called. This provides automatic resource cleanup upon [ViewModel] release.
      *
-     * The clearing order is:
-     * 1. [keyToCloseables][AutoCloseable.close]
-     * 2. [closeables][AutoCloseable.close]
-     * 3. [ViewModel.onCleared]
+     * For specifics about the clearing sequence, refer to the [ViewModel.clear] method.
      *
-     * **Note:** Manually [SynchronizedObject] is necessary to prevent issues on Android API 21 and 22.
-     * This avoids potential problems found in older versions of `ConcurrentHashMap`.
+     * **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>
      */
@@ -84,9 +81,10 @@
 
         isCleared = true
         synchronized(lock) {
-            // 1. Closes resources added without a key.
-            // 2. Closes resources added with a key.
-            for (closeable in closeables + keyToCloseables.values) {
+            for (closeable in keyToCloseables.values) {
+                closeWithRuntimeException(closeable)
+            }
+            for (closeable in closeables) {
                 closeWithRuntimeException(closeable)
             }
             // Clear only resources without keys to prevent accidental recreation of resources.
diff --git a/lifecycle/lifecycle-viewmodel/src/commonTest/kotlin/androidx/lifecycle/ViewModelTest.kt b/lifecycle/lifecycle-viewmodel/src/commonTest/kotlin/androidx/lifecycle/ViewModelTest.kt
index 570bf8e..fc82ddb 100644
--- a/lifecycle/lifecycle-viewmodel/src/commonTest/kotlin/androidx/lifecycle/ViewModelTest.kt
+++ b/lifecycle/lifecycle-viewmodel/src/commonTest/kotlin/androidx/lifecycle/ViewModelTest.kt
@@ -154,12 +154,50 @@
     }
     //endregion
 
+    @Test
+    fun clear_closesResources_inCleaningSequenceOrder() {
+        val clearedInOrderCloseables = mutableListOf<AutoCloseable>()
+        val closeableInConstructor1 = CloseableResource { clearedInOrderCloseables += this }
+        val closeableInConstructor2 = CloseableResource { clearedInOrderCloseables += this }
+        val closeableWithoutKey1 = CloseableResource { clearedInOrderCloseables += this }
+        val closeableWithoutKey2 = CloseableResource { clearedInOrderCloseables += this }
+        val closeableWithKey1 = CloseableResource { clearedInOrderCloseables += this }
+        val closeableWithKey2 = CloseableResource { clearedInOrderCloseables += this }
+
+        val viewModel = TestViewModel(closeableInConstructor1, closeableInConstructor2)
+        viewModel.addCloseable(closeableWithoutKey1)
+        viewModel.addCloseable(key = "customKey1", closeableWithKey1)
+        viewModel.addCloseable(closeableWithoutKey2)
+        viewModel.addCloseable(key = "customKey2", closeableWithKey2)
+        viewModel.clear()
+
+        // The clearing order is:
+        val expectedCloseables = listOf(
+            // 1. Resources added **with** a key via `addCloseable`.
+            closeableWithKey1,
+            closeableWithKey2,
+
+            // 2. Resources added **without** a key via `constructor`.
+            closeableInConstructor1,
+            closeableInConstructor2,
+
+            // 3. Resources added **without** a key via `addCloseable`.
+            closeableWithoutKey1,
+            closeableWithoutKey2,
+        )
+        assertThat(clearedInOrderCloseables).isEqualTo(expectedCloseables)
+    }
+
     //region test helpers
     private class TestViewModel(vararg closeables: AutoCloseable) : ViewModel(*closeables)
 
-    private class CloseableResource(var isClosed: Boolean = false) : AutoCloseable {
+    private class CloseableResource(
+        var isClosed: Boolean = false,
+        val onClose: CloseableResource.() -> Unit = {},
+    ) : AutoCloseable {
         override fun close() {
             isClosed = true
+            onClose(this)
         }
     }
     //endregion
diff --git a/navigation/navigation-common/api/current.txt b/navigation/navigation-common/api/current.txt
index 54e9664..fcb454f 100644
--- a/navigation/navigation-common/api/current.txt
+++ b/navigation/navigation-common/api/current.txt
@@ -183,6 +183,7 @@
   }
 
   public final class NavDeepLinkDslBuilderKt {
+    method @SuppressCompatibility @androidx.navigation.ExperimentalSafeArgsApi public static inline <reified T> androidx.navigation.NavDeepLink navDeepLink(optional java.util.Map<kotlin.reflect.KType,androidx.navigation.NavType<?>> typeMap, kotlin.jvm.functions.Function1<? super androidx.navigation.NavDeepLinkDslBuilder,kotlin.Unit> deepLinkBuilder);
     method public static androidx.navigation.NavDeepLink navDeepLink(kotlin.jvm.functions.Function1<? super androidx.navigation.NavDeepLinkDslBuilder,kotlin.Unit> deepLinkBuilder);
   }
 
@@ -454,16 +455,21 @@
     property public boolean isNullableAllowed;
     property public String name;
     field public static final androidx.navigation.NavType<boolean[]?> BoolArrayType;
+    field public static final androidx.navigation.NavType<java.util.List<java.lang.Boolean>?> BoolListType;
     field public static final androidx.navigation.NavType<java.lang.Boolean> BoolType;
     field public static final androidx.navigation.NavType.Companion Companion;
     field public static final androidx.navigation.NavType<float[]?> FloatArrayType;
+    field public static final androidx.navigation.NavType<java.util.List<java.lang.Float>?> FloatListType;
     field public static final androidx.navigation.NavType<java.lang.Float> FloatType;
     field public static final androidx.navigation.NavType<int[]?> IntArrayType;
+    field public static final androidx.navigation.NavType<java.util.List<java.lang.Integer>?> IntListType;
     field public static final androidx.navigation.NavType<java.lang.Integer> IntType;
     field public static final androidx.navigation.NavType<long[]?> LongArrayType;
+    field public static final androidx.navigation.NavType<java.util.List<java.lang.Long>?> LongListType;
     field public static final androidx.navigation.NavType<java.lang.Long> LongType;
     field public static final androidx.navigation.NavType<java.lang.Integer> ReferenceType;
     field public static final androidx.navigation.NavType<java.lang.String[]?> StringArrayType;
+    field public static final androidx.navigation.NavType<java.util.List<java.lang.String>?> StringListType;
     field public static final androidx.navigation.NavType<java.lang.String?> StringType;
   }
 
diff --git a/navigation/navigation-common/api/restricted_current.txt b/navigation/navigation-common/api/restricted_current.txt
index 54e9664..fcb454f 100644
--- a/navigation/navigation-common/api/restricted_current.txt
+++ b/navigation/navigation-common/api/restricted_current.txt
@@ -183,6 +183,7 @@
   }
 
   public final class NavDeepLinkDslBuilderKt {
+    method @SuppressCompatibility @androidx.navigation.ExperimentalSafeArgsApi public static inline <reified T> androidx.navigation.NavDeepLink navDeepLink(optional java.util.Map<kotlin.reflect.KType,androidx.navigation.NavType<?>> typeMap, kotlin.jvm.functions.Function1<? super androidx.navigation.NavDeepLinkDslBuilder,kotlin.Unit> deepLinkBuilder);
     method public static androidx.navigation.NavDeepLink navDeepLink(kotlin.jvm.functions.Function1<? super androidx.navigation.NavDeepLinkDslBuilder,kotlin.Unit> deepLinkBuilder);
   }
 
@@ -454,16 +455,21 @@
     property public boolean isNullableAllowed;
     property public String name;
     field public static final androidx.navigation.NavType<boolean[]?> BoolArrayType;
+    field public static final androidx.navigation.NavType<java.util.List<java.lang.Boolean>?> BoolListType;
     field public static final androidx.navigation.NavType<java.lang.Boolean> BoolType;
     field public static final androidx.navigation.NavType.Companion Companion;
     field public static final androidx.navigation.NavType<float[]?> FloatArrayType;
+    field public static final androidx.navigation.NavType<java.util.List<java.lang.Float>?> FloatListType;
     field public static final androidx.navigation.NavType<java.lang.Float> FloatType;
     field public static final androidx.navigation.NavType<int[]?> IntArrayType;
+    field public static final androidx.navigation.NavType<java.util.List<java.lang.Integer>?> IntListType;
     field public static final androidx.navigation.NavType<java.lang.Integer> IntType;
     field public static final androidx.navigation.NavType<long[]?> LongArrayType;
+    field public static final androidx.navigation.NavType<java.util.List<java.lang.Long>?> LongListType;
     field public static final androidx.navigation.NavType<java.lang.Long> LongType;
     field public static final androidx.navigation.NavType<java.lang.Integer> ReferenceType;
     field public static final androidx.navigation.NavType<java.lang.String[]?> StringArrayType;
+    field public static final androidx.navigation.NavType<java.util.List<java.lang.String>?> StringListType;
     field public static final androidx.navigation.NavType<java.lang.String?> StringType;
   }
 
diff --git a/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavDeepLinkBuilderTest.kt b/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavDeepLinkBuilderTest.kt
index a04bdab..bae7b4e 100644
--- a/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavDeepLinkBuilderTest.kt
+++ b/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavDeepLinkBuilderTest.kt
@@ -16,10 +16,12 @@
 
 package androidx.navigation
 
+import androidx.navigation.NavOptionsTest.TestClass
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.google.common.truth.Truth.assertThat
 import com.google.common.truth.Truth.assertWithMessage
+import kotlinx.serialization.Serializable
 import org.junit.Assert.fail
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -91,4 +93,137 @@
             .that(navDeepLink.action)
             .isNull()
     }
+
+    @OptIn(ExperimentalSafeArgsApi::class)
+    @Test
+    fun buildDeepLinkAllSetKClass() {
+        val expectedUri = "example.com"
+        val expectedAction = "test.action"
+        val expectedMimeType = "test/type"
+        val navDeepLink = navDeepLink<TestClass> {
+            uriPattern = expectedUri
+            action = expectedAction
+            mimeType = expectedMimeType
+        }
+        assertWithMessage("NavDeepLink should have uri pattern set")
+            .that(navDeepLink.uriPattern)
+            .isEqualTo(expectedUri)
+        assertWithMessage("NavDeepLink should have action set")
+            .that(navDeepLink.action)
+            .isEqualTo(expectedAction)
+        assertWithMessage("NavDeepLink should have mimeType set")
+            .that(navDeepLink.mimeType)
+            .isEqualTo(expectedMimeType)
+    }
+
+    @OptIn(ExperimentalSafeArgsApi::class)
+    @Test
+    fun buildDeepLinkAllSetKClassWithPathArgs() {
+        @Serializable
+        class TestClass(val arg: Int, val arg2: String)
+
+        val expectedUri = "example.com"
+        val expectedAction = "test.action"
+        val expectedMimeType = "test/type"
+        val navDeepLink = navDeepLink<TestClass> {
+            uriPattern = expectedUri
+            action = expectedAction
+            mimeType = expectedMimeType
+        }
+        assertWithMessage("NavDeepLink should have uri pattern set")
+            .that(navDeepLink.uriPattern)
+            .isEqualTo("$expectedUri/{arg}/{arg2}")
+        assertWithMessage("NavDeepLink should have action set")
+            .that(navDeepLink.action)
+            .isEqualTo(expectedAction)
+        assertWithMessage("NavDeepLink should have mimeType set")
+            .that(navDeepLink.mimeType)
+            .isEqualTo(expectedMimeType)
+    }
+
+    @OptIn(ExperimentalSafeArgsApi::class)
+    @Test
+    fun buildDeepLinkAllSetKClassWithQueryArgs() {
+        @Serializable
+        class TestClass(val arg: Int, val arg2: String = "default")
+
+        val expectedUri = "example.com"
+        val expectedAction = "test.action"
+        val expectedMimeType = "test/type"
+        val navDeepLink = navDeepLink<TestClass> {
+            uriPattern = expectedUri
+            action = expectedAction
+            mimeType = expectedMimeType
+        }
+        assertWithMessage("NavDeepLink should have uri pattern set")
+            .that(navDeepLink.uriPattern)
+            .isEqualTo("$expectedUri/{arg}?arg2={arg2}")
+        assertWithMessage("NavDeepLink should have action set")
+            .that(navDeepLink.action)
+            .isEqualTo(expectedAction)
+        assertWithMessage("NavDeepLink should have mimeType set")
+            .that(navDeepLink.mimeType)
+            .isEqualTo(expectedMimeType)
+    }
+
+    @OptIn(ExperimentalSafeArgsApi::class)
+    @Test
+    fun buildDeepLinkNoneSetKClass() {
+        var exception: IllegalStateException? = null
+        try {
+            navDeepLink<TestClass> {}
+            fail("NavDeepLink must throw when attempting to build an empty builder.")
+        } catch (e: IllegalStateException) {
+            exception = e
+        }
+        assertThat(exception?.message)
+            .isEqualTo("The NavDeepLink must have an uri, action, and/or mimeType.")
+    }
+
+    @OptIn(ExperimentalSafeArgsApi::class)
+    @Test
+    fun buildDeepLinkNoUriKClass() {
+        var exception: IllegalStateException? = null
+        try {
+            navDeepLink<TestClass> { action = "action" }
+            fail("NavDeepLink must throw when attempting to build an empty builder.")
+        } catch (e: IllegalStateException) {
+            exception = e
+        }
+        assertThat(exception?.message)
+            .isEqualTo("Failed to build NavDeepLink from KClass. Ensure base path is " +
+                "set through uriPattern.")
+    }
+
+    @OptIn(ExperimentalSafeArgsApi::class)
+    @Test
+    fun buildDeepLinkEmptyActionKClass() {
+        var exception: IllegalArgumentException? = null
+        try {
+            navDeepLink<TestClass> { action = "" }
+            fail("NavDeepLink must throw when attempting to build with an empty action.")
+        } catch (e: IllegalArgumentException) {
+            exception = e
+        }
+        assertThat(exception?.message)
+            .isEqualTo("The NavDeepLink cannot have an empty action.")
+    }
+
+    @OptIn(ExperimentalSafeArgsApi::class)
+    @Test
+    fun buildDeepLinkDoubleActionSetNullKClass() {
+        val expectedUri = "www.example.com"
+        val navDeepLink = navDeepLink<TestClass> {
+            uriPattern = expectedUri
+            action = "blah"
+            action = null
+        }
+
+        assertWithMessage("NavDeepLink should have uri pattern set")
+            .that(navDeepLink.uriPattern)
+            .isEqualTo(expectedUri)
+        assertWithMessage("NavDeepLink should have action set")
+            .that(navDeepLink.action)
+            .isNull()
+    }
 }
diff --git a/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavTypeTest.kt b/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavTypeTest.kt
index c92982f..82dd11c 100644
--- a/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavTypeTest.kt
+++ b/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavTypeTest.kt
@@ -38,14 +38,24 @@
     companion object {
         private const val i = 1
         private val ints = intArrayOf(0, 1)
+        private val intList = listOf(0, 1)
+        private val intArrayList = arrayListOf(0, 1)
         private const val l = 1L
         private val longs = longArrayOf(0L, 1L)
+        private val longList = listOf(0L, 1L)
+        private val longArrayList = arrayListOf(0L, 1L)
         private const val fl = 1.5f
         private val floats = floatArrayOf(1f, 2.5f)
+        private val floatList = listOf(1f, 2.5f)
+        private val floatArrayList = arrayListOf(1f, 2.5f)
         private const val b = true
         private val booleans = booleanArrayOf(b, false)
+        private val boolList = listOf(b, false)
+        private val booArrayList = arrayListOf(b, false)
         private const val s = "a_string"
         private val strings = arrayOf("aa", "bb")
+        private val stringList = listOf("aa", "bb")
+        private val stringArrayList = arrayListOf("aa", "bb")
         private val reference = R.id.nav_id_reference
         private val referenceHex = "0x" + R.id.nav_id_reference.toString(16)
         private val parcelable = ActivityInfo()
@@ -71,22 +81,32 @@
             .isEqualTo(NavType.IntType)
         assertThat(NavType.fromArgType("integer[]", null))
             .isEqualTo(NavType.IntArrayType)
+        assertThat(NavType.fromArgType("List<Int>", null))
+            .isEqualTo(NavType.IntListType)
         assertThat(NavType.fromArgType("long", null))
             .isEqualTo(NavType.LongType)
         assertThat(NavType.fromArgType("long[]", null))
             .isEqualTo(NavType.LongArrayType)
+        assertThat(NavType.fromArgType("List<Long>", null))
+            .isEqualTo(NavType.LongListType)
         assertThat(NavType.fromArgType("float", null))
             .isEqualTo(NavType.FloatType)
         assertThat(NavType.fromArgType("float[]", null))
             .isEqualTo(NavType.FloatArrayType)
+        assertThat(NavType.fromArgType("List<Float>", null))
+            .isEqualTo(NavType.FloatListType)
         assertThat(NavType.fromArgType("boolean", null))
             .isEqualTo(NavType.BoolType)
         assertThat(NavType.fromArgType("boolean[]", null))
             .isEqualTo(NavType.BoolArrayType)
+        assertThat(NavType.fromArgType("List<Boolean>", null))
+            .isEqualTo(NavType.BoolListType)
         assertThat(NavType.fromArgType("string", null))
             .isEqualTo(NavType.StringType)
         assertThat(NavType.fromArgType("string[]", null))
             .isEqualTo(NavType.StringArrayType)
+        assertThat(NavType.fromArgType("List<String>", null))
+            .isEqualTo(NavType.StringListType)
         assertThat(NavType.fromArgType("reference", null))
             .isEqualTo(NavType.ReferenceType)
         assertThat(NavType.fromArgType("android.content.pm.ActivityInfo", null))
@@ -169,6 +189,16 @@
             .isEqualTo(ints)
         bundle.clear()
 
+        NavType.IntListType.put(bundle, key, intList)
+        assertThat(NavType.IntListType[bundle, key])
+            .isEqualTo(intList)
+        bundle.clear()
+
+        NavType.IntListType.put(bundle, key, intArrayList)
+        assertThat(NavType.IntListType[bundle, key])
+            .isEqualTo(intArrayList)
+        bundle.clear()
+
         NavType.LongType.put(bundle, key, l)
         assertThat(NavType.LongType[bundle, key])
             .isEqualTo(l)
@@ -179,6 +209,16 @@
             .isEqualTo(longs)
         bundle.clear()
 
+        NavType.LongListType.put(bundle, key, longList)
+        assertThat(NavType.LongListType[bundle, key])
+            .isEqualTo(longList)
+        bundle.clear()
+
+        NavType.LongListType.put(bundle, key, longArrayList)
+        assertThat(NavType.LongListType[bundle, key])
+            .isEqualTo(longArrayList)
+        bundle.clear()
+
         NavType.FloatType.put(bundle, key, fl)
         assertThat(NavType.FloatType[bundle, key])
             .isEqualTo(fl)
@@ -189,6 +229,16 @@
             .isEqualTo(floats)
         bundle.clear()
 
+        NavType.FloatListType.put(bundle, key, floatList)
+        assertThat(NavType.FloatListType[bundle, key])
+            .isEqualTo(floatList)
+        bundle.clear()
+
+        NavType.FloatListType.put(bundle, key, floatArrayList)
+        assertThat(NavType.FloatListType[bundle, key])
+            .isEqualTo(floatArrayList)
+        bundle.clear()
+
         NavType.BoolType.put(bundle, key, b)
         assertThat(NavType.BoolType[bundle, key])
             .isEqualTo(b)
@@ -199,6 +249,16 @@
             .isEqualTo(booleans)
         bundle.clear()
 
+        NavType.BoolListType.put(bundle, key, boolList)
+        assertThat(NavType.BoolListType[bundle, key])
+            .isEqualTo(boolList)
+        bundle.clear()
+
+        NavType.BoolListType.put(bundle, key, booArrayList)
+        assertThat(NavType.BoolListType[bundle, key])
+            .isEqualTo(booArrayList)
+        bundle.clear()
+
         NavType.StringType.put(bundle, key, s)
         assertThat(NavType.StringType[bundle, key])
             .isEqualTo(s)
@@ -209,6 +269,16 @@
             .isEqualTo(strings)
         bundle.clear()
 
+        NavType.StringListType.put(bundle, key, stringList)
+        assertThat(NavType.StringListType[bundle, key])
+            .isEqualTo(stringList)
+        bundle.clear()
+
+        NavType.StringListType.put(bundle, key, stringArrayList)
+        assertThat(NavType.StringListType[bundle, key])
+            .isEqualTo(stringArrayList)
+        bundle.clear()
+
         NavType.ReferenceType.put(bundle, key, reference)
         assertThat(NavType.ReferenceType[bundle, key])
             .isEqualTo(reference)
@@ -302,18 +372,48 @@
         assertThat((NavType.IntArrayType as CollectionNavType).serializeAsValues(
             intArrayOf(0, 1))
         ).containsExactly("0", "1").inOrder()
+        assertThat((NavType.IntListType as CollectionNavType).serializeAsValues(
+            listOf(0, 1))
+        ).containsExactly("0", "1").inOrder()
+        assertThat((NavType.IntListType as CollectionNavType).serializeAsValues(
+            arrayListOf(0, 1))
+        ).containsExactly("0", "1").inOrder()
         assertThat((NavType.BoolArrayType as CollectionNavType).serializeAsValues(
             booleanArrayOf(true, false))
         ).containsExactly("true", "false").inOrder()
+        assertThat((NavType.BoolListType as CollectionNavType).serializeAsValues(
+            listOf(true, false))
+        ).containsExactly("true", "false").inOrder()
+        assertThat((NavType.BoolListType as CollectionNavType).serializeAsValues(
+            arrayListOf(true, false))
+        ).containsExactly("true", "false").inOrder()
         assertThat((NavType.StringArrayType as CollectionNavType).serializeAsValues(
             arrayOf("test", "test2"))
         ).containsExactly("test", "test2").inOrder()
+        assertThat((NavType.StringListType as CollectionNavType).serializeAsValues(
+            listOf("test", "test2"))
+        ).containsExactly("test", "test2").inOrder()
+        assertThat((NavType.StringListType as CollectionNavType).serializeAsValues(
+            arrayListOf("test", "test2"))
+        ).containsExactly("test", "test2").inOrder()
         assertThat((NavType.FloatArrayType as CollectionNavType).serializeAsValues(
             floatArrayOf(1F, 2F))
         ).containsExactly("1.0", "2.0").inOrder()
+        assertThat((NavType.FloatListType as CollectionNavType).serializeAsValues(
+            listOf(1F, 2F))
+        ).containsExactly("1.0", "2.0").inOrder()
+        assertThat((NavType.FloatListType as CollectionNavType).serializeAsValues(
+            arrayListOf(1F, 2F))
+        ).containsExactly("1.0", "2.0").inOrder()
         assertThat((NavType.LongArrayType as CollectionNavType).serializeAsValues(
             longArrayOf(1L, 2L))
         ).containsExactly("1", "2").inOrder()
+        assertThat((NavType.LongListType as CollectionNavType).serializeAsValues(
+            listOf(1L, 2L))
+        ).containsExactly("1", "2").inOrder()
+        assertThat((NavType.LongListType as CollectionNavType).serializeAsValues(
+            arrayListOf(1L, 2L))
+        ).containsExactly("1", "2").inOrder()
     }
 
     @Test
diff --git a/navigation/navigation-common/src/androidTest/java/androidx/navigation/serialization/RouteDecoderTest.kt b/navigation/navigation-common/src/androidTest/java/androidx/navigation/serialization/RouteDecoderTest.kt
index c07082f..6905a17 100644
--- a/navigation/navigation-common/src/androidTest/java/androidx/navigation/serialization/RouteDecoderTest.kt
+++ b/navigation/navigation-common/src/androidTest/java/androidx/navigation/serialization/RouteDecoderTest.kt
@@ -379,6 +379,17 @@
         assertThat(result.custom.arg).isNull()
     }
 
+    @Test
+    fun decodeCollectionNavType() {
+        val arg = listOf(CustomType(1), CustomType(3), CustomType(5))
+        val bundle = bundleOf("list" to arg)
+        val result = decode<TestClassCollectionArg>(
+            bundle,
+            listOf(navArgument("list") { type = collectionNavType })
+        )
+        assertThat(result.list).containsExactlyElementsIn(arg).inOrder()
+    }
+
     private inline fun <reified T : Any> decode(
         bundle: Bundle,
         args: List<NamedNavArgument> = emptyList()
diff --git a/navigation/navigation-common/src/androidTest/java/androidx/navigation/serialization/RouteFilledTest.kt b/navigation/navigation-common/src/androidTest/java/androidx/navigation/serialization/RouteFilledTest.kt
index 7f1ac4a..9bb4d25 100644
--- a/navigation/navigation-common/src/androidTest/java/androidx/navigation/serialization/RouteFilledTest.kt
+++ b/navigation/navigation-common/src/androidTest/java/androidx/navigation/serialization/RouteFilledTest.kt
@@ -17,6 +17,7 @@
 package androidx.navigation.serialization
 
 import android.os.Bundle
+import androidx.navigation.CollectionNavType
 import androidx.navigation.NamedNavArgument
 import androidx.navigation.NavType
 import androidx.navigation.navArgument
@@ -401,6 +402,23 @@
     }
 
     @Test
+    fun routeListArgs() {
+        @Serializable
+        @SerialName(PATH_SERIAL_NAME)
+        class IntList(val list: List<Int>)
+        assertThatRouteFilledFrom(
+            IntList(listOf(1, 2)),
+            listOf(
+                navArgument("list") {
+                    type = NavType.IntListType
+                    nullable = false
+                    unknownDefaultValuePresent = false
+                }
+            )
+        ).isEqualTo("$PATH_SERIAL_NAME?list=1&list=2")
+    }
+
+    @Test
     fun withSecondaryConstructor() {
         @Serializable
         @SerialName(PATH_SERIAL_NAME)
@@ -548,6 +566,67 @@
     }
 
     @Test
+    fun customTypeParam() {
+        @Serializable
+        open class TypeParam
+        @Serializable
+        class CustomType<T : TypeParam>
+        @Serializable
+        @SerialName(PATH_SERIAL_NAME)
+        class TestClass(val custom: CustomType<TypeParam>)
+
+        val navType = object : NavType<CustomType<TypeParam>>(false) {
+            override val name: String
+                get() = "CustomType"
+            override fun put(bundle: Bundle, key: String, value: CustomType<TypeParam>) { }
+            override fun get(bundle: Bundle, key: String): CustomType<TypeParam>? = null
+            override fun parseValue(value: String): CustomType<TypeParam> = CustomType()
+            override fun serializeAsValue(value: CustomType<TypeParam>) = "customValue"
+        }
+        assertThatRouteFilledFrom(
+            TestClass(CustomType()),
+            listOf(navArgument("custom") { type = navType })
+        ).isEqualTo(
+            "$PATH_SERIAL_NAME/customValue"
+        )
+    }
+
+    @Test
+    fun customTypeParamNested() {
+        @Serializable
+        open class TypeParamNested
+        @Serializable
+        open class TypeParam<K : TypeParamNested>
+        @Serializable
+        class CustomType<T : TypeParam<TypeParamNested>>
+        @Serializable
+        @SerialName(PATH_SERIAL_NAME)
+        class TestClass(val custom: CustomType<TypeParam<TypeParamNested>>)
+
+        val navType = object : NavType<CustomType<TypeParam<TypeParamNested>>>(false) {
+            override val name: String
+                get() = "CustomType"
+            override fun put(
+                bundle: Bundle,
+                key: String,
+                value: CustomType<TypeParam<TypeParamNested>>
+            ) { }
+            override fun get(bundle: Bundle, key: String): CustomType<TypeParam<TypeParamNested>>? =
+                null
+            override fun parseValue(value: String): CustomType<TypeParam<TypeParamNested>> =
+                CustomType()
+            override fun serializeAsValue(value: CustomType<TypeParam<TypeParamNested>>) =
+                "customValue"
+        }
+        assertThatRouteFilledFrom(
+            TestClass(CustomType()),
+            listOf(navArgument("custom") { type = navType })
+        ).isEqualTo(
+            "$PATH_SERIAL_NAME/customValue"
+        )
+    }
+
+    @Test
     fun paramWithNoBackingField() {
         @Serializable
         @SerialName(PATH_SERIAL_NAME)
@@ -684,6 +763,16 @@
             PATH_SERIAL_NAME
         )
     }
+
+    @Test
+    fun collectionNavType() {
+        assertThatRouteFilledFrom(
+            TestClassCollectionArg(listOf(CustomType(1), CustomType(3), CustomType(5))),
+            listOf(navArgument("list") { type = collectionNavType })
+        ).isEqualTo(
+            "$PATH_SERIAL_NAME?list=1&list=3&list=5"
+        )
+    }
 }
 
 private fun <T : Any> assertThatRouteFilledFrom(
@@ -748,6 +837,25 @@
         CustomSerializerClass(decoder.decodeLong())
 }
 
+@Serializable
+data class CustomType(val id: Int)
+
+@Serializable
+@SerialName(PATH_SERIAL_NAME)
+class TestClassCollectionArg(val list: List<CustomType>)
+
+val collectionNavType = object : CollectionNavType<List<CustomType>>(false) {
+    override fun put(bundle: Bundle, key: String, value: List<CustomType>) { }
+    override fun serializeAsValues(value: List<CustomType>): List<String> =
+        value.map { it.id.toString() }
+    @Suppress("UNCHECKED_CAST", "DEPRECATION")
+    override fun get(bundle: Bundle, key: String): List<CustomType> {
+        return bundle[key] as List<CustomType>
+    }
+    override fun parseValue(value: String): List<CustomType> = listOf()
+    override fun serializeAsValue(value: List<CustomType>) = "customValue"
+}
+
 private interface TestInterface
 
 internal fun stringArgument(
diff --git a/navigation/navigation-common/src/main/java/androidx/navigation/NavDeepLinkDslBuilder.kt b/navigation/navigation-common/src/main/java/androidx/navigation/NavDeepLinkDslBuilder.kt
index 9472414..475a888 100644
--- a/navigation/navigation-common/src/main/java/androidx/navigation/NavDeepLinkDslBuilder.kt
+++ b/navigation/navigation-common/src/main/java/androidx/navigation/NavDeepLinkDslBuilder.kt
@@ -16,24 +16,79 @@
 
 package androidx.navigation
 
+import androidx.annotation.RestrictTo
+import kotlin.reflect.KClass
+import kotlin.reflect.KType
+
 @DslMarker
 public annotation class NavDeepLinkDsl
 
 /**
  * Construct a new [NavDeepLink]
+ *
+ * @param deepLinkBuilder the builder used to construct the deeplink
  */
 public fun navDeepLink(deepLinkBuilder: NavDeepLinkDslBuilder.() -> Unit): NavDeepLink =
     NavDeepLinkDslBuilder().apply(deepLinkBuilder).build()
 
 /**
+ * Construct a new [NavDeepLink]
+ *
+ * @param T The route from KClass to extract deeplink arguments from
+ * @param typeMap map of destination arguments' kotlin type [KType] to its respective custom
+ * [NavType]. May be empty if [T] does not use custom NavTypes.
+ * @param deepLinkBuilder the builder used to construct the deeplink
+ */
+@ExperimentalSafeArgsApi
+public inline fun <reified T : Any> navDeepLink(
+    typeMap: Map<KType, @JvmSuppressWildcards NavType<*>> = emptyMap(),
+    noinline deepLinkBuilder: NavDeepLinkDslBuilder.() -> Unit
+): NavDeepLink = navDeepLink(T::class, typeMap, deepLinkBuilder)
+
+// public delegation for reified version to call internal build()
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public fun <T : Any> navDeepLink(
+    route: KClass<T>,
+    typeMap: Map<KType, @JvmSuppressWildcards NavType<*>>,
+    deepLinkBuilder: NavDeepLinkDslBuilder.() -> Unit
+): NavDeepLink = NavDeepLinkDslBuilder(route, typeMap).apply(deepLinkBuilder).build()
+
+/**
  * DSL for constructing a new [NavDeepLink]
  */
 @NavDeepLinkDsl
 public class NavDeepLinkDslBuilder {
     private val builder = NavDeepLink.Builder()
 
+    private var route: KClass<*>? = null
+    private var typeMap: Map<KType, NavType<*>> = emptyMap()
+
+    constructor()
+
+    /**
+     * DSl for constructing a new [NavDeepLink] with a route
+     *
+     * Extracts deeplink arguments from [route] and appends it to the base uri path. The base
+     * uri path should be set with [uriPattern].
+     *
+     * @param route The route from KClass to extract deeplink arguments from
+     * @param typeMap map of destination arguments' kotlin type [KType] to its respective custom
+     * [NavType]. May be empty if [route] does not use custom NavTypes.
+     */
+    internal constructor(
+        route: KClass<*>,
+        typeMap: Map<KType, @JvmSuppressWildcards NavType<*>>
+    ) {
+        this.route = route
+        this.typeMap = typeMap
+    }
+
     /**
      * The uri pattern of the deep link
+     *
+     * If used with safe args, this forms the base uri to which arguments are appended. See docs on
+     * the safe args version of [NavDeepLink.Builder.setUriPattern] for the final uriPattern's
+     * generation logic.
      */
     public var uriPattern: String? = null
 
@@ -60,7 +115,15 @@
         check(!(uriPattern == null && action == null && mimeType == null)) {
             ("The NavDeepLink must have an uri, action, and/or mimeType.")
         }
-        uriPattern?.let { setUriPattern(it) }
+        if (route != null) {
+            checkNotNull(uriPattern) {
+                "Failed to build NavDeepLink from KClass. Ensure base path is set " +
+                    "through uriPattern."
+            }
+            setUriPattern(uriPattern!!, route!!, typeMap)
+        } else {
+            uriPattern?.let { setUriPattern(it) }
+        }
         action?.let { setAction(it) }
         mimeType?.let { setMimeType(it) }
     }.build()
diff --git a/navigation/navigation-common/src/main/java/androidx/navigation/NavType.kt b/navigation/navigation-common/src/main/java/androidx/navigation/NavType.kt
index 878d6a4..3f09a49 100644
--- a/navigation/navigation-common/src/main/java/androidx/navigation/NavType.kt
+++ b/navigation/navigation-common/src/main/java/androidx/navigation/NavType.kt
@@ -175,14 +175,19 @@
             when {
                 IntType.name == type -> return IntType
                 IntArrayType.name == type -> return IntArrayType
+                IntListType.name == type -> return IntListType
                 LongType.name == type -> return LongType
                 LongArrayType.name == type -> return LongArrayType
+                LongListType.name == type -> return LongListType
                 BoolType.name == type -> return BoolType
                 BoolArrayType.name == type -> return BoolArrayType
+                BoolListType.name == type -> return BoolListType
                 StringType.name == type -> return StringType
                 StringArrayType.name == type -> return StringArrayType
+                StringListType.name == type -> return StringListType
                 FloatType.name == type -> return FloatType
                 FloatArrayType.name == type -> return FloatArrayType
+                FloatListType.name == type -> return FloatListType
                 ReferenceType.name == type -> return ReferenceType
                 !type.isNullOrEmpty() -> {
                     try {
@@ -411,6 +416,46 @@
         }
 
         /**
+         * NavType for storing list of Ints.
+         *
+         * Null values are supported.
+         * List NavTypes in Navigation XML files are not supported.
+         */
+        @JvmField
+        public val IntListType: NavType<List<Int>?> = object : CollectionNavType<List<Int>?>(
+            true
+        ) {
+            override val name: String
+                get() = "List<Int>"
+
+            override fun put(bundle: Bundle, key: String, value: List<Int>?) {
+                bundle.putIntArray(key, value?.toIntArray())
+            }
+
+            @Suppress("DEPRECATION")
+            override fun get(bundle: Bundle, key: String): List<Int>? {
+                return (bundle[key] as IntArray?)?.toList()
+            }
+
+            override fun parseValue(value: String): List<Int> {
+                return listOf(IntType.parseValue(value))
+            }
+
+            override fun parseValue(value: String, previousValue: List<Int>?): List<Int>? {
+                return previousValue?.plus(IntType.parseValue(value)) ?: parseValue(value)
+            }
+
+            override fun valueEquals(value: List<Int>?, other: List<Int>?): Boolean {
+                val valueArray = value?.toTypedArray()
+                val otherArray = other?.toTypedArray()
+                return valueArray.contentDeepEquals(otherArray)
+            }
+
+            override fun serializeAsValues(value: List<Int>?): List<String> =
+                value?.map { it.toString() } ?: emptyList()
+        }
+
+        /**
          * NavType for storing long values,
          * corresponding with the "long" type in a Navigation XML file.
          *
@@ -490,6 +535,46 @@
         }
 
         /**
+         * NavType for storing list of Longs.
+         *
+         * Null values are supported.
+         * List NavTypes in Navigation XML files are not supported.
+         */
+        @JvmField
+        public val LongListType: NavType<List<Long>?> = object : CollectionNavType<List<Long>?>(
+            true
+        ) {
+            override val name: String
+                get() = "List<Long>"
+
+            override fun put(bundle: Bundle, key: String, value: List<Long>?) {
+                bundle.putLongArray(key, value?.toLongArray())
+            }
+
+            @Suppress("DEPRECATION")
+            override fun get(bundle: Bundle, key: String): List<Long>? {
+                return (bundle[key] as LongArray?)?.toList()
+            }
+
+            override fun parseValue(value: String): List<Long> {
+                return listOf(LongType.parseValue(value))
+            }
+
+            override fun parseValue(value: String, previousValue: List<Long>?): List<Long>? {
+                return previousValue?.plus(LongType.parseValue(value)) ?: parseValue(value)
+            }
+
+            override fun valueEquals(value: List<Long>?, other: List<Long>?): Boolean {
+                val valueArray = value?.toTypedArray()
+                val otherArray = other?.toTypedArray()
+                return valueArray.contentDeepEquals(otherArray)
+            }
+
+            override fun serializeAsValues(value: List<Long>?): List<String> =
+                value?.map { it.toString() } ?: emptyList()
+        }
+
+        /**
          * NavType for storing float values,
          * corresponding with the "float" type in a Navigation XML file.
          *
@@ -556,6 +641,46 @@
         }
 
         /**
+         * NavType for storing list of Floats.
+         *
+         * Null values are supported.
+         * List NavTypes in Navigation XML files are not supported.
+         */
+        @JvmField
+        public val FloatListType: NavType<List<Float>?> = object : CollectionNavType<List<Float>?>(
+            true
+        ) {
+            override val name: String
+                get() = "List<Float>"
+
+            override fun put(bundle: Bundle, key: String, value: List<Float>?) {
+                bundle.putFloatArray(key, value?.toFloatArray())
+            }
+
+            @Suppress("DEPRECATION")
+            override fun get(bundle: Bundle, key: String): List<Float>? {
+                return (bundle[key] as FloatArray?)?.toList()
+            }
+
+            override fun parseValue(value: String): List<Float> {
+                return listOf(FloatType.parseValue(value))
+            }
+
+            override fun parseValue(value: String, previousValue: List<Float>?): List<Float>? {
+                return previousValue?.plus(FloatType.parseValue(value)) ?: parseValue(value)
+            }
+
+            override fun valueEquals(value: List<Float>?, other: List<Float>?): Boolean {
+                val valueArray = value?.toTypedArray()
+                val otherArray = other?.toTypedArray()
+                return valueArray.contentDeepEquals(otherArray)
+            }
+
+            override fun serializeAsValues(value: List<Float>?): List<String> =
+                value?.map { it.toString() } ?: emptyList()
+        }
+
+        /**
          * NavType for storing boolean values,
          * corresponding with the "boolean" type in a Navigation XML file.
          *
@@ -629,6 +754,45 @@
         }
 
         /**
+         * NavType for storing list of Booleans.
+         *
+         * Null values are supported.
+         * List NavTypes in Navigation XML files are not supported.
+         */
+        @JvmField
+        public val BoolListType: NavType<List<Boolean>?> =
+            object : CollectionNavType<List<Boolean>?>(true) {
+            override val name: String
+                get() = "List<Boolean>"
+
+            override fun put(bundle: Bundle, key: String, value: List<Boolean>?) {
+                bundle.putBooleanArray(key, value?.toBooleanArray())
+            }
+
+            @Suppress("DEPRECATION")
+            override fun get(bundle: Bundle, key: String): List<Boolean>? {
+                return (bundle[key] as BooleanArray?)?.toList()
+            }
+
+            override fun parseValue(value: String): List<Boolean> {
+                return listOf(BoolType.parseValue(value))
+            }
+
+            override fun parseValue(value: String, previousValue: List<Boolean>?): List<Boolean>? {
+                return previousValue?.plus(BoolType.parseValue(value)) ?: parseValue(value)
+            }
+
+            override fun valueEquals(value: List<Boolean>?, other: List<Boolean>?): Boolean {
+                val valueArray = value?.toTypedArray()
+                val otherArray = other?.toTypedArray()
+                return valueArray.contentDeepEquals(otherArray)
+            }
+
+            override fun serializeAsValues(value: List<Boolean>?): List<String> =
+                value?.map { it.toString() } ?: emptyList()
+        }
+
+        /**
          * NavType for storing String values,
          * corresponding with the "string" type in a Navigation XML file.
          *
@@ -704,8 +868,50 @@
                 value.contentDeepEquals(other)
 
             override fun serializeAsValues(value: Array<String>?): List<String> =
-                value?.toList() ?: emptyList()
+                value?.map { Uri.encode(it) } ?: emptyList()
         }
+
+        /**
+         * NavType for storing list of Strings.
+         *
+         * Null values are supported.
+         * List NavTypes in Navigation XML files are not supported.
+         */
+        @JvmField
+        public val StringListType: NavType<List<String>?> =
+            object : CollectionNavType<List<String>?>(true) {
+                override val name: String
+                    get() = "List<String>"
+
+                override fun put(bundle: Bundle, key: String, value: List<String>?) {
+                    bundle.putStringArray(key, value?.toTypedArray())
+                }
+
+                @Suppress("UNCHECKED_CAST", "DEPRECATION")
+                override fun get(bundle: Bundle, key: String): List<String>? {
+                    return (bundle[key] as Array<String>?)?.toList()
+                }
+
+                override fun parseValue(value: String): List<String> {
+                    return listOf(value)
+                }
+
+                override fun parseValue(
+                    value: String,
+                    previousValue: List<String>?
+                ): List<String>? {
+                    return previousValue?.plus(value) ?: parseValue(value)
+                }
+
+                override fun valueEquals(value: List<String>?, other: List<String>?): Boolean {
+                    val valueArray = value?.toTypedArray()
+                    val otherArray = other?.toTypedArray()
+                    return valueArray.contentDeepEquals(otherArray)
+                }
+
+                override fun serializeAsValues(value: List<String>?): List<String> =
+                    value?.map { Uri.encode(it) } ?: emptyList()
+            }
     }
 
     /**
diff --git a/navigation/navigation-common/src/main/java/androidx/navigation/serialization/NavTypeConverter.kt b/navigation/navigation-common/src/main/java/androidx/navigation/serialization/NavTypeConverter.kt
index a626a74..7f7b754 100644
--- a/navigation/navigation-common/src/main/java/androidx/navigation/serialization/NavTypeConverter.kt
+++ b/navigation/navigation-common/src/main/java/androidx/navigation/serialization/NavTypeConverter.kt
@@ -23,13 +23,12 @@
 import kotlin.reflect.KType
 import kotlinx.serialization.ExperimentalSerializationApi
 import kotlinx.serialization.descriptors.SerialDescriptor
-
-private interface InternalCommonType
+import kotlinx.serialization.serializer
 
 /**
- * Marker for Native Kotlin Primitives and Collections
+ * Marker for Native Kotlin types with either full or partial built-in NavType support
  */
-private enum class Native : InternalCommonType {
+private enum class InternalType {
     INT,
     BOOL,
     FLOAT,
@@ -40,162 +39,83 @@
     FLOAT_ARRAY,
     LONG_ARRAY,
     ARRAY,
-    ARRAY_LIST,
-    SET,
-    HASHSET,
-    MAP,
-    HASH_MAP,
+    LIST,
     UNKNOWN
 }
 
 /**
- * Marker for custom classes, objects, enums, and other Native Kotlin types that are not
- * included in [Native]
- */
-private data class Custom(val className: String) : InternalCommonType
-
-/**
- * Converts an argument type to a native NavType.
+ * Converts an argument type to a built-in NavType.
  *
- * Native NavTypes includes NavType objects declared within [NavType.Companion], or types that are
- * either java Serializable, Parcelable, or Enum.
+ * Built-in NavTypes include NavType objects declared within [NavType.Companion], such as
+ * [NavType.IntType], [NavType.BoolArrayType] etc.
  *
- * Returns [UNKNOWN] type if the argument does not belong to any of the above.
+ * Returns [UNKNOWN] type if the argument does not have built-in NavType support.
  */
-@Suppress("UNCHECKED_CAST")
-internal fun SerialDescriptor.getNavType(): NavType<Any?> {
+internal fun SerialDescriptor.getNavType(): NavType<*> {
     val type = when (this.toInternalType()) {
-        Native.INT -> NavType.IntType
-        Native.BOOL -> NavType.BoolType
-        Native.FLOAT -> NavType.FloatType
-        Native.LONG -> NavType.LongType
-        Native.STRING -> NavType.StringType
-        Native.INT_ARRAY -> NavType.IntArrayType
-        Native.BOOL_ARRAY -> NavType.BoolArrayType
-        Native.FLOAT_ARRAY -> NavType.FloatArrayType
-        Native.LONG_ARRAY -> NavType.LongArrayType
-        Native.ARRAY -> {
+        InternalType.INT -> NavType.IntType
+        InternalType.BOOL -> NavType.BoolType
+        InternalType.FLOAT -> NavType.FloatType
+        InternalType.LONG -> NavType.LongType
+        InternalType.STRING -> NavType.StringType
+        InternalType.INT_ARRAY -> NavType.IntArrayType
+        InternalType.BOOL_ARRAY -> NavType.BoolArrayType
+        InternalType.FLOAT_ARRAY -> NavType.FloatArrayType
+        InternalType.LONG_ARRAY -> NavType.LongArrayType
+        InternalType.ARRAY -> {
             val typeParameter = getElementDescriptor(0).toInternalType()
-            if (typeParameter == Native.STRING) NavType.StringArrayType else UNKNOWN
+            if (typeParameter == InternalType.STRING) NavType.StringArrayType else UNKNOWN
+        }
+        InternalType.LIST -> {
+            val typeParameter = getElementDescriptor(0).toInternalType()
+            when (typeParameter) {
+                InternalType.INT -> NavType.IntListType
+                InternalType.BOOL -> NavType.BoolListType
+                InternalType.FLOAT -> NavType.FloatListType
+                InternalType.LONG -> NavType.LongListType
+                InternalType.STRING -> NavType.StringListType
+                else -> UNKNOWN
+            }
         }
         else -> UNKNOWN
     }
-    return type as NavType<Any?>
-}
-
-/**
- * Convert KType to an [InternalCommonType].
- *
- * Conversion is based on KType name. The KType could be any of the native Kotlin types that
- * are supported in [Native], or it could be a custom KType (custom class, object or enum).
- */
-private fun KType.toInternalType(): InternalCommonType {
-    // first we need to parse KType name to the right format
-    // extract base class without type parameters
-    val typeParamRegex = Regex(pattern = "^[^<]*", options = setOf(RegexOption.IGNORE_CASE))
-    val trimmedTypeParam = typeParamRegex.find(this.toString())
-    // remove the warning that was appended to KType name due to missing kotlin reflect library
-    val trimEndingRegex = Regex("(\\S+)")
-    val trimmedEnding = trimEndingRegex.find(trimmedTypeParam!!.value)
-    val finalName = trimmedEnding?.value
-        // we assert the nullability directly with isNullable properties so its more reliable
-        ?.replace("?", "")
-        // we also replace the delimiter `$` with `.` for child classes to match the format of
-        // serial names
-        ?.replace("$", ".")
-
-    return when (finalName) {
-        null -> Native.UNKNOWN
-        "int" -> Native.INT
-        "java.lang.Integer" -> Native.INT
-        "boolean" -> Native.BOOL
-        "java.lang.Boolean" -> Native.BOOL
-        "float" -> Native.FLOAT
-        "java.lang.Float" -> Native.FLOAT
-        "long" -> Native.LONG
-        "java.lang.Long" -> Native.LONG
-        "java.lang.String" -> Native.STRING
-        "kotlin.IntArray" -> Native.INT_ARRAY
-        "kotlin.BooleanArray" -> Native.BOOL_ARRAY
-        "kotlin.FloatArray" -> Native.FLOAT_ARRAY
-        "kotlin.LongArray" -> Native.LONG_ARRAY
-        "kotlin.Array" -> Native.ARRAY
-        "java.util.ArrayList" -> Native.ARRAY_LIST
-        // KType List mapped to ArrayList because serialized name does not differentiate them
-        "java.util.List" -> Native.ARRAY_LIST
-        "java.util.Set" -> Native.SET
-        "java.util.HashSet" -> Native.HASHSET
-        "java.util.Map" -> Native.MAP
-        "java.util.HashMap" -> Native.HASH_MAP
-        else -> Custom(finalName)
-    }
+    return type
 }
 
 /**
  * Convert SerialDescriptor to an InternalCommonType.
  *
- * The descriptor's associated argument could be any of the native Kotlin types that
- * are supported in [Native], or it could be a custom type (custom class, object or enum).
+ * The descriptor's associated argument could be any of the native Kotlin types supported
+ * in [InternalType], or it could be an unsupported type (custom class, object or enum).
  */
-private fun SerialDescriptor.toInternalType(): InternalCommonType {
+private fun SerialDescriptor.toInternalType(): InternalType {
     val serialName = serialName.replace("?", "")
     return when {
-        serialName == "kotlin.Int" -> Native.INT
-        serialName == "kotlin.Boolean" -> Native.BOOL
-        serialName == "kotlin.Float" -> Native.FLOAT
-        serialName == "kotlin.Long" -> Native.LONG
-        serialName == "kotlin.String" -> Native.STRING
-        serialName == "kotlin.IntArray" -> Native.INT_ARRAY
-        serialName == "kotlin.BooleanArray" -> Native.BOOL_ARRAY
-        serialName == "kotlin.FloatArray" -> Native.FLOAT_ARRAY
-        serialName == "kotlin.LongArray" -> Native.LONG_ARRAY
-        serialName == "kotlin.Array" -> Native.ARRAY
+        serialName == "kotlin.Int" -> InternalType.INT
+        serialName == "kotlin.Boolean" -> InternalType.BOOL
+        serialName == "kotlin.Float" -> InternalType.FLOAT
+        serialName == "kotlin.Long" -> InternalType.LONG
+        serialName == "kotlin.String" -> InternalType.STRING
+        serialName == "kotlin.IntArray" -> InternalType.INT_ARRAY
+        serialName == "kotlin.BooleanArray" -> InternalType.BOOL_ARRAY
+        serialName == "kotlin.FloatArray" -> InternalType.FLOAT_ARRAY
+        serialName == "kotlin.LongArray" -> InternalType.LONG_ARRAY
+        serialName == "kotlin.Array" -> InternalType.ARRAY
         // serial name for both List and ArrayList
-        serialName.startsWith("kotlin.collections.ArrayList") -> Native.ARRAY_LIST
-        serialName.startsWith("kotlin.collections.LinkedHashSet") -> Native.SET
-        serialName.startsWith("kotlin.collections.HashSet") -> Native.HASHSET
-        serialName.startsWith("kotlin.collections.LinkedHashMap") -> Native.MAP
-        serialName.startsWith("kotlin.collections.HashMap") -> Native.HASH_MAP
-        else -> Custom(serialName)
+        serialName.startsWith("kotlin.collections.ArrayList") -> InternalType.LIST
+        // custom classes or other types without built-in NavTypes
+        else -> InternalType.UNKNOWN
     }
 }
 
 /**
- * Returns true if a serialized argument type matches the given KType.
+ * Match the [SerialDescriptor] of a type to a KType
  *
- * Matching starts by matching the base class of the type and then matching type parameters
- * in their declared order. Nested TypeParameters are matched recursively in the same manner.
- *
- * Limitation: For custom Types, TypeParameters are erased in serialization by default.
- * The type is preserved only if there is a class field of type T, and even then we cannot know
- * that this type is in fact the TypeParameter. Therefore, matching custom types with
- * type parameters only works under two conditions:
- *
- * 1. A class field of that type must be declared for each generic type
- * 2. These class fields must be declared in primary constructor in same order
- *
- * For example, this declaration will work:
- * `class TestClass<T: Any, K: Any>(val arg: T, val arg2: K)`
- * and these variations will not work:
- * `class TestClass<T: Any, K: Any>(val arg: K, val arg2: T)`
- * `class TestClass<T: Any, K: Any>(val other: Int, val arg: K, val arg2: T)`
- *
- * If TypeParameters of custom classes cannot be matched, the custom class will be matched to
- * a KType purely based on the class's fully qualified name and will not be able to differentiate
- * between different TypeParameters. This can lead to indeterminate matching behavior.
+ * Returns true match, false otherwise.
  */
 internal fun SerialDescriptor.matchKType(kType: KType): Boolean {
     if (this.isNullable != kType.isMarkedNullable) return false
-    if (this.toInternalType() != kType.toInternalType()) return false
-    var index = 0
-    // recursive match nested TypeParameters
-    while (index < elementsCount && index < kType.arguments.size) {
-        val descriptor = getElementDescriptor(index)
-        val childKType = kType.arguments.getOrNull(index)?.type ?: return false
-        val result = descriptor.matchKType(childKType)
-        if (!result) return false
-        index++
-    }
+    if (this.hashCode() != serializer(kType).descriptor.hashCode()) return false
     return true
 }
 
diff --git a/navigation/navigation-common/src/main/java/androidx/navigation/serialization/RouteSerializer.kt b/navigation/navigation-common/src/main/java/androidx/navigation/serialization/RouteSerializer.kt
index b18469c..38923ce 100644
--- a/navigation/navigation-common/src/main/java/androidx/navigation/serialization/RouteSerializer.kt
+++ b/navigation/navigation-common/src/main/java/androidx/navigation/serialization/RouteSerializer.kt
@@ -58,7 +58,7 @@
     val map = mutableMapOf<String, NavType<Any?>>()
     for (i in 0 until descriptor.elementsCount) {
         val argName = descriptor.getElementName(i)
-        val type = descriptor.getElementDescriptor(i).computeNavType(typeMap)
+        val type = descriptor.getElementDescriptor(i).computeNavType(argName, typeMap)
         map[argName] = type
     }
     val builder = if (path != null) {
@@ -110,13 +110,7 @@
         navArgument(name) {
             val element = descriptor.getElementDescriptor(index)
             val isNullable = element.isNullable
-            type = element.computeNavType(typeMap)
-            if (type == UNKNOWN) {
-                throw IllegalArgumentException(
-                    "Cannot cast $name of type ${element.serialName} to a NavType. Make sure " +
-                        "to provide custom NavType for this argument."
-                )
-            }
+            type = element.computeNavType(name, typeMap)
             nullable = isNullable
             if (descriptor.isElementOptional(index)) {
                 // Navigation mostly just cares about defaultValuePresent state for
@@ -153,12 +147,27 @@
     }
 }
 
+/**
+ * Computes and return the [NavType] based on the SerialDescriptor of a class type.
+ *
+ * Match priority:
+ * 1. Match with custom NavType provided in [typeMap]
+ * 2. Match to a built-in NavType such as [NavType.IntType], [NavType.BoolArrayType] etc.
+ */
 @Suppress("UNCHECKED_CAST")
 private fun SerialDescriptor.computeNavType(
+    name: String,
     typeMap: Map<KType, NavType<*>>
 ): NavType<Any?> {
     val customType = typeMap.keys
         .find { kType -> matchKType(kType) }
         ?.let { typeMap[it] } as? NavType<Any?>
-    return customType ?: getNavType()
+    val result = customType ?: getNavType()
+    if (result == UNKNOWN) {
+        throw IllegalArgumentException(
+            "Cannot cast $name of type $serialName to a NavType. Make sure " +
+                "to provide custom NavType for this argument."
+        )
+    }
+    return result as NavType<Any?>
 }
diff --git a/navigation/navigation-common/src/test/java/androidx/navigation/serialization/NavArgumentGeneratorTest.kt b/navigation/navigation-common/src/test/java/androidx/navigation/serialization/NavArgumentGeneratorTest.kt
index 391d320..c0c9214 100644
--- a/navigation/navigation-common/src/test/java/androidx/navigation/serialization/NavArgumentGeneratorTest.kt
+++ b/navigation/navigation-common/src/test/java/androidx/navigation/serialization/NavArgumentGeneratorTest.kt
@@ -183,6 +183,45 @@
     }
 
     @Test
+    fun convertToIntList() {
+        @Serializable class TestClass(val arg: List<Int>)
+
+        val converted = serializer<TestClass>().generateNavArguments()
+        val expected = navArgument("arg") {
+            type = NavType.IntListType
+            nullable = false
+        }
+        assertThat(converted).containsExactlyInOrder(expected)
+        assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
+    }
+
+    @Test
+    fun convertArrayListToIntList() {
+        @Serializable class TestClass(val arg: ArrayList<Int>)
+
+        val converted = serializer<TestClass>().generateNavArguments()
+        val expected = navArgument("arg") {
+            type = NavType.IntListType
+            nullable = false
+        }
+        assertThat(converted).containsExactlyInOrder(expected)
+        assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
+    }
+
+    @Test
+    fun convertToIntListNullable() {
+        @Serializable class TestClass(val arg: List<Int>?)
+
+        val converted = serializer<TestClass>().generateNavArguments()
+        val expected = navArgument("arg") {
+            type = NavType.IntListType
+            nullable = true
+        }
+        assertThat(converted).containsExactlyInOrder(expected)
+        assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
+    }
+
+    @Test
     fun convertToLongArray() {
         @Serializable class TestClass(val arg: LongArray)
 
@@ -209,6 +248,45 @@
     }
 
     @Test
+    fun convertToLongList() {
+        @Serializable class TestClass(val arg: List<Long>)
+
+        val converted = serializer<TestClass>().generateNavArguments()
+        val expected = navArgument("arg") {
+            type = NavType.LongListType
+            nullable = false
+        }
+        assertThat(converted).containsExactlyInOrder(expected)
+        assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
+    }
+
+    @Test
+    fun convertArrayListToLongList() {
+        @Serializable class TestClass(val arg: ArrayList<Long>)
+
+        val converted = serializer<TestClass>().generateNavArguments()
+        val expected = navArgument("arg") {
+            type = NavType.LongListType
+            nullable = false
+        }
+        assertThat(converted).containsExactlyInOrder(expected)
+        assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
+    }
+
+    @Test
+    fun convertToLongListNullable() {
+        @Serializable class TestClass(val arg: List<Long>?)
+
+        val converted = serializer<TestClass>().generateNavArguments()
+        val expected = navArgument("arg") {
+            type = NavType.LongListType
+            nullable = true
+        }
+        assertThat(converted).containsExactlyInOrder(expected)
+        assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
+    }
+
+    @Test
     fun convertToFloatArray() {
         @Serializable class TestClass(val arg: FloatArray)
 
@@ -235,6 +313,45 @@
     }
 
     @Test
+    fun convertToFloatList() {
+        @Serializable class TestClass(val arg: List<Float>)
+
+        val converted = serializer<TestClass>().generateNavArguments()
+        val expected = navArgument("arg") {
+            type = NavType.FloatListType
+            nullable = false
+        }
+        assertThat(converted).containsExactlyInOrder(expected)
+        assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
+    }
+
+    @Test
+    fun convertArrayListToFloatList() {
+        @Serializable class TestClass(val arg: ArrayList<Float>)
+
+        val converted = serializer<TestClass>().generateNavArguments()
+        val expected = navArgument("arg") {
+            type = NavType.FloatListType
+            nullable = false
+        }
+        assertThat(converted).containsExactlyInOrder(expected)
+        assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
+    }
+
+    @Test
+    fun convertToFloatListNullable() {
+        @Serializable class TestClass(val arg: List<Float>?)
+
+        val converted = serializer<TestClass>().generateNavArguments()
+        val expected = navArgument("arg") {
+            type = NavType.FloatListType
+            nullable = true
+        }
+        assertThat(converted).containsExactlyInOrder(expected)
+        assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
+    }
+
+    @Test
     fun convertToBoolArray() {
         @Serializable class TestClass(val arg: BooleanArray)
 
@@ -261,6 +378,45 @@
     }
 
     @Test
+    fun convertToBooleanList() {
+        @Serializable class TestClass(val arg: List<Boolean>)
+
+        val converted = serializer<TestClass>().generateNavArguments()
+        val expected = navArgument("arg") {
+            type = NavType.BoolListType
+            nullable = false
+        }
+        assertThat(converted).containsExactlyInOrder(expected)
+        assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
+    }
+
+    @Test
+    fun convertArrayListToBooleanList() {
+        @Serializable class TestClass(val arg: ArrayList<Boolean>)
+
+        val converted = serializer<TestClass>().generateNavArguments()
+        val expected = navArgument("arg") {
+            type = NavType.BoolListType
+            nullable = false
+        }
+        assertThat(converted).containsExactlyInOrder(expected)
+        assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
+    }
+
+    @Test
+    fun convertToBooleanListNullable() {
+        @Serializable class TestClass(val arg: List<Boolean>?)
+
+        val converted = serializer<TestClass>().generateNavArguments()
+        val expected = navArgument("arg") {
+            type = NavType.BoolListType
+            nullable = true
+        }
+        assertThat(converted).containsExactlyInOrder(expected)
+        assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
+    }
+
+    @Test
     fun convertToStringArray() {
         @Serializable class TestClass(val arg: Array<String>)
 
@@ -287,6 +443,45 @@
     }
 
     @Test
+    fun convertToStringList() {
+        @Serializable class TestClass(val arg: List<String>)
+
+        val converted = serializer<TestClass>().generateNavArguments()
+        val expected = navArgument("arg") {
+            type = NavType.StringListType
+            nullable = false
+        }
+        assertThat(converted).containsExactlyInOrder(expected)
+        assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
+    }
+
+    @Test
+    fun convertArrayListToStringList() {
+        @Serializable class TestClass(val arg: ArrayList<String>)
+
+        val converted = serializer<TestClass>().generateNavArguments()
+        val expected = navArgument("arg") {
+            type = NavType.StringListType
+            nullable = false
+        }
+        assertThat(converted).containsExactlyInOrder(expected)
+        assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
+    }
+
+    @Test
+    fun convertToStringListNullable() {
+        @Serializable class TestClass(val arg: List<String>?)
+
+        val converted = serializer<TestClass>().generateNavArguments()
+        val expected = navArgument("arg") {
+            type = NavType.StringListType
+            nullable = true
+        }
+        assertThat(converted).containsExactlyInOrder(expected)
+        assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
+    }
+
+    @Test
     fun convertToParcelable() {
         @Serializable
         class TestParcelable : Parcelable {
@@ -599,14 +794,14 @@
 
     @Test
     fun convertIllegalCustomType() {
-        @Serializable class TestClass(val arg: ArrayList<String>)
+        @Serializable class TestClass(val arg: Set<String>)
 
         val exception = assertFailsWith<IllegalArgumentException> {
             serializer<TestClass>().generateNavArguments()
         }
 
         assertThat(exception.message).isEqualTo(
-         "Cannot cast arg of type kotlin.collections.ArrayList to a NavType. " +
+         "Cannot cast arg of type kotlin.collections.LinkedHashSet to a NavType. " +
              "Make sure to provide custom NavType for this argument."
         )
     }
diff --git a/navigation/navigation-common/src/test/java/androidx/navigation/serialization/NavTypeConverterTest.kt b/navigation/navigation-common/src/test/java/androidx/navigation/serialization/NavTypeConverterTest.kt
index ec47b98..dba8173 100644
--- a/navigation/navigation-common/src/test/java/androidx/navigation/serialization/NavTypeConverterTest.kt
+++ b/navigation/navigation-common/src/test/java/androidx/navigation/serialization/NavTypeConverterTest.kt
@@ -22,8 +22,8 @@
 import com.google.common.truth.Truth.assertThat
 import kotlin.reflect.typeOf
 import kotlin.test.Test
-import kotlin.test.assertFails
 import kotlinx.serialization.Serializable
+import kotlinx.serialization.descriptors.SerialDescriptor
 import kotlinx.serialization.serializer
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
@@ -376,21 +376,21 @@
     }
 
     @Test
-    fun matchWrongTypeParameter() {
+    fun matchWrongTypeParam() {
         val descriptor = serializer<Set<Int>>().descriptor
         val kType = typeOf<Set<Boolean>>()
         assertThat(descriptor.matchKType(kType)).isFalse()
     }
 
     @Test
-    fun matchWrongOrderTypeParameter() {
+    fun matchWrongOrderTypeParam() {
         val descriptor = serializer<Map<String, Int>>().descriptor
         val kType = typeOf<Map<Int, String>>()
         assertThat(descriptor.matchKType(kType)).isFalse()
     }
 
     @Test
-    fun matchNestedTypeParameter() {
+    fun matchNestedTypeParam() {
         val descriptor = serializer<List<List<Int>>>().descriptor
         val kType = typeOf<List<List<Int>>>()
         assertThat(descriptor.matchKType(kType)).isTrue()
@@ -400,7 +400,7 @@
     }
 
     @Test
-    fun matchMultiNestedTypeParameter() {
+    fun matchMultiNestedTypeParam() {
         val descriptor = serializer<Map<List<Int>, Set<Boolean>>>().descriptor
         val kType = typeOf<Map<List<Int>, Set<Boolean>>>()
         assertThat(descriptor.matchKType(kType)).isTrue()
@@ -410,14 +410,14 @@
     }
 
     @Test
-    fun matchThriceNestedTypeParameter() {
+    fun matchThriceNestedTypeParam() {
         val descriptor = serializer<List<Set<List<Boolean>>>>().descriptor
         val kType = typeOf<List<Set<List<Boolean>>>>()
         assertThat(descriptor.matchKType(kType)).isTrue()
     }
 
     @Test
-    fun matchNativeClassWithCustomTypeParameter() {
+    fun matchNativeTypeCustomTypeParam() {
         @Serializable
         class TestClass(val arg: Int, val arg2: String)
 
@@ -427,7 +427,14 @@
     }
 
     @Test
-    fun matchNativeClassWithNestedCustomTypeParameter() {
+    fun matchNativeTypeCustomTypeParamCustomSerializer() {
+        val descriptor = serializer<List<CustomSerializerClass>>().descriptor
+        val kType = typeOf<List<CustomSerializerClass>>()
+        assertThat(descriptor.matchKType(kType)).isTrue()
+    }
+
+    @Test
+    fun matchNativeTypeCustomTypeParamNested() {
         @Serializable
         open class Nested(val arg: Int)
 
@@ -440,7 +447,17 @@
     }
 
     @Test
-    fun matchCustomClass() {
+    fun matchNativeTypeCustomTypeParamNestedCustomSerializer() {
+        @Serializable
+        class TestClass<T : CustomSerializerClass>(val arg: Int)
+
+        val descriptor = serializer<List<TestClass<CustomSerializerClass>>>().descriptor
+        val kType = typeOf<List<TestClass<CustomSerializerClass>>>()
+        assertThat(descriptor.matchKType(kType)).isTrue()
+    }
+
+    @Test
+    fun matchCustomType() {
         @Serializable
         class TestClass(val arg: Int, val arg2: String)
 
@@ -464,45 +481,142 @@
     }
 
     @Test
-    fun matchCustomClassTypeParameterWithSingleArg() {
+    fun matchCustomTypeNativeTypeParam() {
         @Serializable
-        class TestClass<T : Any>(val arg: T)
+        class TestClass<T : SerialDescriptor>
 
-        val descriptor = serializer<TestClass<String>>().descriptor
-        val kType = typeOf<TestClass<String>>()
+        val descriptor = serializer<TestClass<SerialDescriptor>>().descriptor
+        val kType = typeOf<TestClass<SerialDescriptor>>()
         assertThat(descriptor.matchKType(kType)).isTrue()
-
-        val descriptor2 = serializer<TestClass<Int>>().descriptor
-        assertThat(descriptor2.matchKType(kType)).isFalse()
     }
 
     @Test
-    fun matchCustomClassTypeParameterWithMultipleArg() {
+    fun matchCustomTypeArgNativeTypeParam() {
         @Serializable
-        class TestClass<T : Any, K : Any>(val arg: T, val arg2: K, val arg3: Int)
+        class TestClass<T : SerialDescriptor>(val arg: Int)
 
-        val descriptor = serializer<TestClass<String, Int>>().descriptor
-        val kType = typeOf<TestClass<String, Int>>()
+        val descriptor = serializer<TestClass<SerialDescriptor>>().descriptor
+        val kType = typeOf<TestClass<SerialDescriptor>>()
         assertThat(descriptor.matchKType(kType)).isTrue()
-
-        val descriptor2 = serializer<TestClass<Int, String>>().descriptor
-        assertThat(descriptor2.matchKType(kType)).isFalse()
     }
 
     @Test
-    fun matchCustomClassTypeParameterWithNoArgFails() {
+    fun matchCustomTypeCustomArgNativeTypeParam() {
+        @Serializable
+        class MyArg(val name: String)
+
+        @Serializable
+        class TestClass<T : SerialDescriptor>(val arg: MyArg)
+
+        val descriptor = serializer<TestClass<SerialDescriptor>>().descriptor
+        val kType = typeOf<TestClass<SerialDescriptor>>()
+        assertThat(descriptor.matchKType(kType)).isTrue()
+    }
+
+    @Test
+    fun matchCustomTypeMultiArgNativeTypeParam() {
+        @Serializable
+        class MyArg(val name: String)
+
+        @Serializable
+        class TestClass<T : SerialDescriptor>(val arg: Int, val arg2: MyArg)
+
+        val descriptor = serializer<TestClass<SerialDescriptor>>().descriptor
+        val kType = typeOf<TestClass<SerialDescriptor>>()
+        assertThat(descriptor.matchKType(kType)).isTrue()
+    }
+
+    @Test
+    fun matchCustomTypeNativeTypeParamMismatch() {
         @Serializable
         class TestClass<T : Any>
 
         val descriptor = serializer<TestClass<Int>>().descriptor
         val kType = typeOf<TestClass<String>>()
 
-        // type T is erased in serialization so we cannot differentiate between Int/String
         val isMatch = descriptor.matchKType(kType)
-        val result = assertFails {
-            assertThat(isMatch).isFalse()
-        }
-        assertThat(result.message).isEqualTo("expected to be false")
+        assertThat(isMatch).isFalse()
+    }
+
+    @Test
+    fun matchCustomTypeCustomTypeParam() {
+        @Serializable
+        open class Param
+
+        @Serializable
+        class TestClass<T : Param>
+
+        val descriptor = serializer<TestClass<Param>>().descriptor
+        val kType = typeOf<TestClass<Param>>()
+
+        val isMatch = descriptor.matchKType(kType)
+        assertThat(isMatch).isTrue()
+    }
+
+    @Test
+    fun matchCustomTypeCustomTypeParamCustomSerializer() {
+        @Serializable
+        class TestClass<T : CustomSerializerClass>
+
+        val descriptor = serializer<TestClass<CustomSerializerClass>>().descriptor
+        val kType = typeOf<TestClass<CustomSerializerClass>>()
+
+        val isMatch = descriptor.matchKType(kType)
+        assertThat(isMatch).isTrue()
+    }
+
+    @Test
+    fun matchCustomTypeMultiCustomTypeParam() {
+        @Serializable
+        open class ParamTwo
+
+        @Serializable
+        open class Param
+
+        @Serializable
+        class TestClass<T : Param, K : ParamTwo>
+
+        val descriptor = serializer<TestClass<Param, ParamTwo>>().descriptor
+        val kType = typeOf<TestClass<Param, ParamTwo>>()
+
+        val isMatch = descriptor.matchKType(kType)
+        assertThat(isMatch).isTrue()
+    }
+
+    @Test
+    fun matchCustomTypeCustomTypeParamNested() {
+        @Serializable
+        class TestClass<T : Param>
+
+        val descriptor = serializer<TestClass<ParamDerived>>().descriptor
+        val kType = typeOf<TestClass<ParamDerived>>()
+
+        val isMatch = descriptor.matchKType(kType)
+        assertThat(isMatch).isTrue()
+    }
+
+    @Test
+    fun matchCustomTypeMultiCustomTypeParamNested() {
+        @Serializable
+        class TestClass<T : Param, K : Param>
+
+        val descriptor = serializer<TestClass<ParamDerived, ParamDerivedTwo>>().descriptor
+        val kType = typeOf<TestClass<ParamDerived, ParamDerivedTwo>>()
+
+        val isMatch = descriptor.matchKType(kType)
+        assertThat(isMatch).isTrue()
+    }
+
+    @Test
+    fun matchCustomTypeCustomTypeParamNestedMismatch() {
+        @Serializable
+        class TestClass<T : Param>
+
+        val descriptor = serializer<TestClass<ParamDerived>>().descriptor
+        val kType = typeOf<TestClass<ParamDerivedTwo>>()
+
+        val isMatch = descriptor.matchKType(kType)
+        assertThat(isMatch).isFalse()
     }
 
     @Test
@@ -635,6 +749,15 @@
     }
 
     @Serializable
+    class ParamDerivedTwo : Param()
+
+    @Serializable
+    class ParamDerived : Param()
+
+    @Serializable
+    open class Param
+
+    @Serializable
     class TestParcelable(val arg: Int, val arg2: String) : Parcelable {
         override fun describeContents() = 0
         override fun writeToParcel(dest: Parcel, flags: Int) { }
diff --git a/navigation/navigation-common/src/test/java/androidx/navigation/serialization/RoutePatternTest.kt b/navigation/navigation-common/src/test/java/androidx/navigation/serialization/RoutePatternTest.kt
index 92a5b66..dee4366 100644
--- a/navigation/navigation-common/src/test/java/androidx/navigation/serialization/RoutePatternTest.kt
+++ b/navigation/navigation-common/src/test/java/androidx/navigation/serialization/RoutePatternTest.kt
@@ -16,7 +16,12 @@
 
 package androidx.navigation.serialization
 
+import android.os.Bundle
+import androidx.navigation.CollectionNavType
+import androidx.navigation.NavType
 import com.google.common.truth.Truth.assertThat
+import kotlin.reflect.KType
+import kotlin.reflect.typeOf
 import kotlin.test.assertFailsWith
 import kotlinx.serialization.KSerializer
 import kotlinx.serialization.SerialName
@@ -250,7 +255,16 @@
         @SerialName(PATH_SERIAL_NAME)
         class TestClass(val custom: CustomType)
 
-        assertThatRoutePatternFrom(serializer<TestClass>()).isEqualTo(
+        val type = object : NavType<CustomType>(false) {
+            override val name: String
+                get() = "CustomType"
+            override fun put(bundle: Bundle, key: String, value: CustomType) { }
+            override fun get(bundle: Bundle, key: String): CustomType? = null
+            override fun parseValue(value: String): CustomType = CustomType()
+            override fun serializeAsValue(value: CustomType) = "customValue"
+        }
+        val map = mapOf(typeOf<CustomType>() to type)
+        assertThatRoutePatternFrom(serializer<TestClass>(), map).isEqualTo(
             "$PATH_SERIAL_NAME/{custom}"
         )
     }
@@ -267,7 +281,16 @@
         @SerialName(PATH_SERIAL_NAME)
         class TestClass(val custom: CustomType)
 
-        assertThatRoutePatternFrom(serializer<TestClass>()).isEqualTo(
+        val type = object : NavType<CustomType>(false) {
+            override val name: String
+                get() = "CustomType"
+            override fun put(bundle: Bundle, key: String, value: CustomType) { }
+            override fun get(bundle: Bundle, key: String): CustomType? = null
+            override fun parseValue(value: String): CustomType = CustomType(NestedCustomType())
+            override fun serializeAsValue(value: CustomType) = "customValue"
+        }
+        val map = mapOf(typeOf<CustomType>() to type)
+        assertThatRoutePatternFrom(serializer<TestClass>(), map).isEqualTo(
             "$PATH_SERIAL_NAME/{custom}"
         )
     }
@@ -276,19 +299,81 @@
     fun customSerializerParamType() {
         @Serializable
         @SerialName(PATH_SERIAL_NAME)
-        class TestClass(
-            val arg: Int,
-            @Serializable(with = CustomSerializer::class)
-            val arg2: NonSerializedClass
-        )
+        class TestClass(val arg: Int, val arg2: CustomSerializerClass)
 
-        // args will be duplicated
-        assertThatRoutePatternFrom(serializer<TestClass>()).isEqualTo(
+        val type = object : NavType<CustomSerializerClass>(false) {
+            override val name: String
+                get() = "CustomType"
+            override fun put(bundle: Bundle, key: String, value: CustomSerializerClass) { }
+            override fun get(bundle: Bundle, key: String): CustomSerializerClass? = null
+            override fun parseValue(value: String): CustomSerializerClass =
+                CustomSerializerClass(1L)
+            override fun serializeAsValue(value: CustomSerializerClass) = "customValue"
+        }
+        val map = mapOf(typeOf<CustomSerializerClass>() to type)
+        assertThatRoutePatternFrom(serializer<TestClass>(), map).isEqualTo(
             "$PATH_SERIAL_NAME/{arg}/{arg2}"
         )
     }
 
     @Test
+    fun customTypeParam() {
+        @Serializable
+        open class TypeParam
+        @Serializable
+        class CustomType<T : TypeParam>
+        @Serializable
+        @SerialName(PATH_SERIAL_NAME)
+        class TestClass(val custom: CustomType<TypeParam>)
+
+        val type = object : NavType<CustomType<TypeParam>>(false) {
+            override val name: String
+                get() = "CustomType"
+            override fun put(bundle: Bundle, key: String, value: CustomType<TypeParam>) { }
+            override fun get(bundle: Bundle, key: String): CustomType<TypeParam>? = null
+            override fun parseValue(value: String): CustomType<TypeParam> = CustomType()
+            override fun serializeAsValue(value: CustomType<TypeParam>) = "customValue"
+        }
+        val map = mapOf(typeOf<CustomType<TypeParam>>() to type)
+        assertThatRoutePatternFrom(serializer<TestClass>(), map).isEqualTo(
+            "$PATH_SERIAL_NAME/{custom}"
+        )
+    }
+
+    @Test
+    fun customTypeParamNested() {
+        @Serializable
+        open class TypeParamNested
+        @Serializable
+        open class TypeParam<K : TypeParamNested>
+        @Serializable
+        class CustomType<T : TypeParam<TypeParamNested>>
+        @Serializable
+        @SerialName(PATH_SERIAL_NAME)
+        class TestClass(val custom: CustomType<TypeParam<TypeParamNested>>)
+
+        val type = object : NavType<CustomType<TypeParam<TypeParamNested>>>(false) {
+            override val name: String
+                get() = "CustomType"
+            override fun put(
+                bundle: Bundle,
+                key: String,
+                value: CustomType<TypeParam<TypeParamNested>>
+            ) { }
+            override fun get(bundle: Bundle, key: String): CustomType<TypeParam<TypeParamNested>>? =
+                null
+            override fun parseValue(value: String): CustomType<TypeParam<TypeParamNested>> =
+                CustomType()
+            override fun serializeAsValue(value: CustomType<TypeParam<TypeParamNested>>) =
+                "customValue"
+        }
+        val map = mapOf(typeOf<CustomType<TypeParam<TypeParamNested>>>() to type)
+        assertThatRoutePatternFrom(serializer<TestClass>(), map).isEqualTo(
+            "$PATH_SERIAL_NAME/{custom}"
+        )
+    }
+
+    @Test
     fun paramWithNoBackingField() {
         @Serializable
         @SerialName(PATH_SERIAL_NAME)
@@ -326,7 +411,16 @@
             lateinit var arg: CustomType
         }
 
-        assertThatRoutePatternFrom(serializer<TestClass>()).isEqualTo(
+        val type = object : NavType<CustomType>(false) {
+            override val name: String
+                get() = "CustomType"
+            override fun put(bundle: Bundle, key: String, value: CustomType) { }
+            override fun get(bundle: Bundle, key: String): CustomType? = null
+            override fun parseValue(value: String): CustomType = CustomType()
+            override fun serializeAsValue(value: CustomType) = "customValue"
+        }
+        val map = mapOf(typeOf<CustomType>() to type)
+        assertThatRoutePatternFrom(serializer<TestClass>(), map).isEqualTo(
             "$PATH_SERIAL_NAME/{arg}"
         )
     }
@@ -419,10 +513,34 @@
             PATH_SERIAL_NAME
         )
     }
+
+    @Test
+    fun collectionNavType() {
+        @Serializable
+        class CustomType
+
+        @Serializable
+        @SerialName(PATH_SERIAL_NAME)
+        class TestClass(val list: List<CustomType>)
+
+        val type = object : CollectionNavType<List<CustomType>>(false) {
+            override fun put(bundle: Bundle, key: String, value: List<CustomType>) { }
+            override fun serializeAsValues(value: List<CustomType>): List<String> = emptyList()
+            override fun get(bundle: Bundle, key: String): List<CustomType>? = null
+            override fun parseValue(value: String): List<CustomType> = listOf()
+            override fun serializeAsValue(value: List<CustomType>) = "customValue"
+        }
+        val map = mapOf(typeOf<List<CustomType>>() to type)
+        assertThatRoutePatternFrom(serializer<TestClass>(), map).isEqualTo(
+            "$PATH_SERIAL_NAME?list={list}"
+        )
+    }
 }
 
-private fun <T> assertThatRoutePatternFrom(serializer: KSerializer<T>) =
-    serializer.generateRoutePattern()
+private fun <T> assertThatRoutePatternFrom(
+    serializer: KSerializer<T>,
+    map: Map<KType, NavType<*>> = emptyMap()
+) = serializer.generateRoutePattern(map)
 
 private fun String.isEqualTo(other: String) {
     assertThat(this).isEqualTo(other)
@@ -465,16 +583,17 @@
     }
 }
 
-private class NonSerializedClass(val longArg: Long)
+@Serializable(with = CustomSerializer::class)
+internal open class CustomSerializerClass(val longArg: Long)
 
-private class CustomSerializer : KSerializer<NonSerializedClass> {
+internal class CustomSerializer : KSerializer<CustomSerializerClass> {
     override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor(
         "Date", PrimitiveKind.LONG
     )
-    override fun serialize(encoder: Encoder, value: NonSerializedClass) =
+    override fun serialize(encoder: Encoder, value: CustomSerializerClass) =
         encoder.encodeLong(value.longArg)
-    override fun deserialize(decoder: Decoder): NonSerializedClass =
-        NonSerializedClass(decoder.decodeLong())
+    override fun deserialize(decoder: Decoder): CustomSerializerClass =
+        CustomSerializerClass(decoder.decodeLong())
 }
 
 private interface TestInterface
diff --git a/navigation/navigation-fragment-compose/api/current.txt b/navigation/navigation-fragment-compose/api/current.txt
index fc044e2..d598ace 100644
--- a/navigation/navigation-fragment-compose/api/current.txt
+++ b/navigation/navigation-fragment-compose/api/current.txt
@@ -28,5 +28,10 @@
     method public androidx.navigation.fragment.compose.ComposableNavHostFragment create(@NavigationRes int graphResId, optional android.os.Bundle? startDestinationArgs);
   }
 
+  public final class LocalFragmentKt {
+    method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.fragment.app.Fragment> getLocalFragment();
+    property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.fragment.app.Fragment> LocalFragment;
+  }
+
 }
 
diff --git a/navigation/navigation-fragment-compose/api/restricted_current.txt b/navigation/navigation-fragment-compose/api/restricted_current.txt
index fc044e2..d598ace 100644
--- a/navigation/navigation-fragment-compose/api/restricted_current.txt
+++ b/navigation/navigation-fragment-compose/api/restricted_current.txt
@@ -28,5 +28,10 @@
     method public androidx.navigation.fragment.compose.ComposableNavHostFragment create(@NavigationRes int graphResId, optional android.os.Bundle? startDestinationArgs);
   }
 
+  public final class LocalFragmentKt {
+    method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.fragment.app.Fragment> getLocalFragment();
+    property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.fragment.app.Fragment> LocalFragment;
+  }
+
 }
 
diff --git a/navigation/navigation-fragment-compose/src/androidTest/java/androidx/navigation/fragment/compose/ComposableFragmentTest.kt b/navigation/navigation-fragment-compose/src/androidTest/java/androidx/navigation/fragment/compose/ComposableFragmentTest.kt
index 7955fe4..a122a75 100644
--- a/navigation/navigation-fragment-compose/src/androidTest/java/androidx/navigation/fragment/compose/ComposableFragmentTest.kt
+++ b/navigation/navigation-fragment-compose/src/androidTest/java/androidx/navigation/fragment/compose/ComposableFragmentTest.kt
@@ -54,6 +54,25 @@
 
         testRule.onNodeWithText("ComposableFragment").assertIsDisplayed()
     }
+
+    @Test
+    fun showContentWithArgs() {
+        val composableFragment = ComposableFragment(
+            "androidx.navigation.fragment.compose.ComposableFragmentTestKt\$ContentWithArgs"
+        ).apply {
+            requireArguments().putString("test", "argument")
+        }
+        val fragmentManager = testRule.activity.supportFragmentManager
+        testRule.runOnUiThread {
+            fragmentManager.commitNow {
+                add(R.id.fragment_container, composableFragment)
+            }
+        }
+
+        testRule.waitForIdle()
+
+        testRule.onNodeWithText("ComposableFragment: argument").assertIsDisplayed()
+    }
 }
 
 @Suppress("TestFunctionName")
@@ -61,3 +80,11 @@
 fun Content() {
     Text("ComposableFragment")
 }
+
+@Suppress("TestFunctionName")
+@Composable
+fun ContentWithArgs() {
+    val args = LocalFragment.current.requireArguments()
+    val testArgument = args.getString("test")
+    Text("ComposableFragment: $testArgument")
+}
diff --git a/navigation/navigation-fragment-compose/src/main/java/androidx/navigation/fragment/compose/ComposableFragment.kt b/navigation/navigation-fragment-compose/src/main/java/androidx/navigation/fragment/compose/ComposableFragment.kt
index 79a452f..4e616cd 100644
--- a/navigation/navigation-fragment-compose/src/main/java/androidx/navigation/fragment/compose/ComposableFragment.kt
+++ b/navigation/navigation-fragment-compose/src/main/java/androidx/navigation/fragment/compose/ComposableFragment.kt
@@ -20,6 +20,7 @@
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
+import androidx.compose.runtime.CompositionLocalProvider
 import androidx.compose.runtime.currentComposer
 import androidx.compose.runtime.reflect.getDeclaredComposableMethod
 import androidx.compose.ui.platform.ComposeView
@@ -29,7 +30,8 @@
 
 /**
  * This class provides a [Fragment] wrapper around a composable function that is loaded via
- * reflection.
+ * reflection. The composable function has access to this fragment instance via
+ * [LocalFragment].
  *
  * This class is constructed via a factory method: make sure you add
  * `import androidx.navigation.fragment.compose.ComposableFragment.Companion.ComposableFragment`
@@ -56,7 +58,9 @@
         return ComposeView(requireContext()).apply {
             setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
             setContent {
-                composableMethod.invoke(currentComposer, null)
+                CompositionLocalProvider(LocalFragment provides this@ComposableFragment) {
+                    composableMethod.invoke(currentComposer, null)
+                }
             }
         }
     }
diff --git a/navigation/navigation-fragment-compose/src/main/java/androidx/navigation/fragment/compose/LocalFragment.kt b/navigation/navigation-fragment-compose/src/main/java/androidx/navigation/fragment/compose/LocalFragment.kt
new file mode 100644
index 0000000..de9543e
--- /dev/null
+++ b/navigation/navigation-fragment-compose/src/main/java/androidx/navigation/fragment/compose/LocalFragment.kt
@@ -0,0 +1,29 @@
+/*
+ * 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.fragment.compose
+
+import androidx.compose.runtime.staticCompositionLocalOf
+import androidx.fragment.app.Fragment
+
+/**
+ * The CompositionLocal containing the containing [Fragment]. This is sett by default for
+ * composables created within a [ComposableFragment].
+ */
+val LocalFragment = staticCompositionLocalOf<Fragment> {
+    error("CompositionLocal Fragment not present: are you sure your composable is within a " +
+        "navigation-fragment-compose provided ComposableFragment?")
+}
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerRouteTest.kt b/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerRouteTest.kt
index 5ce5551..31d714e 100644
--- a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerRouteTest.kt
+++ b/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerRouteTest.kt
@@ -54,6 +54,7 @@
 import com.google.common.truth.Truth.assertWithMessage
 import java.util.concurrent.CountDownLatch
 import java.util.concurrent.TimeUnit
+import kotlin.reflect.typeOf
 import kotlin.test.assertFailsWith
 import kotlinx.serialization.SerialName
 import kotlinx.serialization.Serializable
@@ -261,7 +262,7 @@
 
         val navController = createNavController()
         navController.graph = navController.createGraph(startDestination = TestClass::class) {
-            test(route = TestClass::class)
+            test<TestClass>()
         }
         assertThat(navController.currentDestination?.route).isEqualTo("test")
         assertThat(navController.currentDestination?.id).isEqualTo(
@@ -278,7 +279,7 @@
 
         val navController = createNavController()
         navController.graph = navController.createGraph(startDestination = TestClass::class) {
-            test(route = TestClass::class)
+            test<TestClass>()
         }
         assertThat(navController.currentDestination?.route).isEqualTo("test/{arg}")
         assertThat(navController.currentDestination?.id).isEqualTo(
@@ -301,7 +302,7 @@
             startDestination = NestedGraph::class
         ) {
             navigation<NestedGraph>(startDestination = TestClass::class) {
-                test(route = TestClass::class)
+                test<TestClass>()
             }
         }
         assertThat(navController.currentDestination?.route).isEqualTo("test")
@@ -319,7 +320,7 @@
 
         val navController = createNavController()
         navController.graph = navController.createGraph(startDestination = TestClass()) {
-            test(route = TestClass::class)
+            test<TestClass>()
         }
         assertThat(navController.currentDestination?.route).isEqualTo("test")
         assertThat(navController.currentDestination?.id).isEqualTo(
@@ -338,7 +339,7 @@
         navController.graph = navController.createGraph(
             startDestination = TestClass(0)
         ) {
-            test(route = TestClass::class)
+            test<TestClass>()
         }
         assertThat(navController.currentDestination?.route).isEqualTo(
             "test/{arg}"
@@ -362,7 +363,7 @@
         navController.graph = navController.createGraph(
             startDestination = TestClass(false)
         ) {
-            test(route = TestClass::class)
+            test<TestClass>()
         }
         assertThat(navController.currentDestination?.route).isEqualTo(
             "test?arg={arg}"
@@ -467,7 +468,7 @@
             startDestination = NestedGraph(0)
         ) {
             navigation<NestedGraph>(startDestination = TestClass(1)) {
-                test(route = TestClass::class)
+                test<TestClass>()
             }
         }
         assertThat(navController.currentDestination?.route).isEqualTo(
@@ -710,7 +711,7 @@
         val navController = createNavController()
         navController.graph = navController.createGraph(startDestination = "start") {
             test("start")
-            test(TestClass::class)
+            test<TestClass>()
         }
         assertThat(navController.currentDestination?.route).isEqualTo("start")
         assertThat(navController.currentBackStack.value.size).isEqualTo(2)
@@ -726,7 +727,7 @@
         val navController = createNavController()
         navController.graph = navController.createGraph(startDestination = "start") {
             test("start")
-            test(TestClassPathArg::class)
+            test<TestClassPathArg>()
         }
         assertThat(navController.currentDestination?.route).isEqualTo("start")
         assertThat(navController.currentBackStack.value.size).isEqualTo(2)
@@ -747,7 +748,7 @@
         val navController = createNavController()
         navController.graph = navController.createGraph(startDestination = "start") {
             test("start")
-            test(TestClass::class)
+            test<TestClass>()
         }
         assertThat(navController.currentDestination?.route).isEqualTo("start")
         assertThat(navController.currentBackStack.value.size).isEqualTo(2)
@@ -771,7 +772,7 @@
         val navController = createNavController()
         navController.graph = navController.createGraph(startDestination = "start") {
             test("start")
-            test(TestClass::class)
+            test<TestClass>()
         }
         assertThat(navController.currentDestination?.route).isEqualTo("start")
         assertThat(navController.currentBackStack.value.size).isEqualTo(2)
@@ -790,6 +791,56 @@
 
     @UiThreadTest
     @Test
+    fun testNavigateWithObjectCollectionNavType() {
+        val navController = createNavController()
+        @Serializable
+        data class CustomType(val id: Int)
+        @Serializable
+        class TestClass(val list: List<CustomType>)
+
+        val collectionNavType = object : CollectionNavType<List<CustomType>>(false) {
+            override fun put(bundle: Bundle, key: String, value: List<CustomType>) {
+                val array = value.map { it.id }.toIntArray()
+                bundle.putIntArray(key, array)
+            }
+            override fun serializeAsValues(value: List<CustomType>) = value.map { it.id.toString() }
+            override fun get(bundle: Bundle, key: String): List<CustomType> {
+                return bundle.getIntArray(key)!!.map { CustomType(it) }
+            }
+            override fun parseValue(value: String) = listOf(CustomType(value.toInt()))
+            override fun parseValue(
+                value: String,
+                previousValue: List<CustomType>
+            ): List<CustomType> {
+                val list = mutableListOf<CustomType>()
+                list.addAll(previousValue)
+                list.add(CustomType(value.toInt()))
+                return list
+            }
+        }
+
+        navController.graph = navController.createGraph(startDestination = "start") {
+            test("start")
+            test<TestClass>(mapOf(typeOf<List<CustomType>>() to collectionNavType))
+        }
+
+        assertThat(navController.currentDestination?.route).isEqualTo("start")
+        assertThat(navController.currentBackStack.value.size).isEqualTo(2)
+
+        val list = listOf(CustomType(1), CustomType(3), CustomType(5))
+        navController.navigate(TestClass(list))
+        assertThat(navController.currentDestination?.route).isEqualTo(
+            "androidx.navigation.NavControllerRouteTest." +
+                "testNavigateWithObjectCollectionNavType.TestClass?list={list}"
+        )
+        assertThat(navController.currentBackStack.value.size).isEqualTo(3)
+        assertThat(
+            navController.currentBackStackEntry!!.toRoute<TestClass>().list
+        ).containsExactlyElementsIn(list).inOrder()
+    }
+
+    @UiThreadTest
+    @Test
     fun testNavigateWithObjectInvalidObject() {
         @Serializable
         class WrongTestClass
@@ -797,7 +848,7 @@
         val navController = createNavController()
         navController.graph = navController.createGraph(startDestination = "start") {
             test("start")
-            test(TestClass::class)
+            test<TestClass>()
         }
         assertThat(navController.currentDestination?.route).isEqualTo("start")
         assertThat(navController.currentBackStack.value.size).isEqualTo(2)
@@ -813,7 +864,7 @@
         val navController = createNavController()
         navController.graph = navController.createGraph(startDestination = "start") {
             test("start")
-            test(TestClass::class)
+            test<TestClass>()
         }
         assertThat(navController.currentDestination?.route).isEqualTo("start")
         assertThat(navController.currentBackStack.value.size).isEqualTo(2)
@@ -831,7 +882,7 @@
         val navController = createNavController()
         navController.graph = navController.createGraph(startDestination = "start") {
             test("start")
-            test(TestClassPathArg::class)
+            test<TestClassPathArg>()
         }
         assertThat(navController.currentDestination?.route).isEqualTo("start")
         assertThat(navController.currentBackStack.value.size).isEqualTo(2)
@@ -862,7 +913,7 @@
         val navController = createNavController()
         navController.graph = navController.createGraph(startDestination = "start") {
             test("start")
-            test(TestClassPathArg::class)
+            test<TestClassPathArg>()
         }
         assertThat(navController.currentDestination?.route).isEqualTo("start")
         assertThat(navController.currentBackStack.value.size).isEqualTo(2)
@@ -1403,7 +1454,7 @@
         val navController = createNavController()
         navController.graph = navController.createGraph(startDestination = "start") {
             test("start")
-            test(TestClass::class)
+            test<TestClass>()
         }
 
         navController.navigate(TEST_CLASS_ROUTE)
@@ -1421,7 +1472,7 @@
         val navController = createNavController()
         navController.graph = navController.createGraph(startDestination = "start") {
             test("start")
-            test(TestClassPathArg::class)
+            test<TestClassPathArg>()
         }
 
         navController.navigate(TEST_CLASS_PATH_ARG_ROUTE.replace("{arg}", "0"))
@@ -1439,7 +1490,7 @@
         val navController = createNavController()
         navController.graph = navController.createGraph(startDestination = "start") {
             test("start")
-            test(TestClass::class)
+            test<TestClass>()
         }
 
         navController.navigate(TEST_CLASS_ROUTE)
@@ -1459,7 +1510,7 @@
             route = TestGraph::class,
             startDestination = TestClass::class
         ) {
-            test(TestClass::class)
+            test<TestClass>()
         }
 
         assertThat(navController.currentBackStack.value.size).isEqualTo(2)
@@ -1479,7 +1530,7 @@
         val navController = createNavController()
         navController.graph = navController.createGraph(startDestination = "start") {
             test("start")
-            test(TestClassPathArg::class)
+            test<TestClassPathArg>()
         }
 
         navController.navigate(TEST_CLASS_PATH_ARG_ROUTE.replace("{arg}", "0"))
@@ -1497,7 +1548,7 @@
         val navController = createNavController()
         navController.graph = navController.createGraph(startDestination = "start") {
             test("start")
-            test(TestClassPathArg::class)
+            test<TestClassPathArg>()
         }
 
         navController.navigate(TEST_CLASS_PATH_ARG_ROUTE.replace("{arg}", "0"))
@@ -1727,7 +1778,7 @@
         val navController = createNavController()
         navController.graph = navController.createGraph(startDestination = "start") {
             test("start")
-            test(TestClass::class)
+            test<TestClass>()
         }
 
         // first nav
@@ -1752,7 +1803,7 @@
             route = TestGraph::class,
             startDestination = TestClass::class
         ) {
-            test(TestClass::class)
+            test<TestClass>()
         }
 
         assertThat(navController.currentBackStack.value.size).isEqualTo(2)
@@ -1773,7 +1824,7 @@
         val navController = createNavController()
         navController.graph = navController.createGraph(startDestination = "start") {
             test("start")
-            test(TestClassPathArg::class)
+            test<TestClassPathArg>()
         }
 
         // first nav
@@ -1796,7 +1847,7 @@
         val navController = createNavController()
         navController.graph = navController.createGraph(startDestination = "start") {
             test("start")
-            test(TestClass::class)
+            test<TestClass>()
         }
 
         // first nav
@@ -1821,7 +1872,7 @@
             route = TestGraph::class,
             startDestination = TestClass::class
         ) {
-            test(TestClass::class)
+            test<TestClass>()
         }
 
         assertThat(navController.currentBackStack.value.size).isEqualTo(2)
@@ -1842,7 +1893,7 @@
         val navController = createNavController()
         navController.graph = navController.createGraph(startDestination = "start") {
             test("start")
-            test(TestClassPathArg::class)
+            test<TestClassPathArg>()
         }
 
         // first nav
@@ -1865,7 +1916,7 @@
         val navController = createNavController()
         navController.graph = navController.createGraph(startDestination = "start") {
             test("start")
-            test(TestClassPathArg::class)
+            test<TestClassPathArg>()
         }
 
         // first nav
@@ -2217,7 +2268,7 @@
         val navController = createNavController()
         navController.graph = navController.createGraph(startDestination = "start") {
             test("start")
-            test(TestClass::class)
+            test<TestClass>()
         }
 
         navController.navigate(TEST_CLASS_ROUTE)
@@ -2236,7 +2287,7 @@
         val navController = createNavController()
         navController.graph = navController.createGraph(startDestination = "start") {
             test("start")
-            test(TestClass::class)
+            test<TestClass>()
         }
 
         navController.navigate(TEST_CLASS_ROUTE)
@@ -2255,7 +2306,7 @@
         val navController = createNavController()
         navController.graph = navController.createGraph(startDestination = "start") {
             test("start")
-            test(TestClassPathArg::class)
+            test<TestClassPathArg>()
         }
 
         navController.navigate(TEST_CLASS_PATH_ARG_ROUTE.replace("{arg}", "0"))
@@ -2274,7 +2325,7 @@
         val navController = createNavController()
         navController.graph = navController.createGraph(startDestination = "start") {
             test("start")
-            test(TestClass::class)
+            test<TestClass>()
         }
 
         navController.navigate(TEST_CLASS_ROUTE)
@@ -2293,7 +2344,7 @@
         val navController = createNavController()
         navController.graph = navController.createGraph(startDestination = "start") {
             test("start")
-            test(TestClass::class)
+            test<TestClass>()
         }
 
         navController.navigate(TEST_CLASS_ROUTE)
@@ -2312,7 +2363,7 @@
         val navController = createNavController()
         navController.graph = navController.createGraph(startDestination = "start") {
             test("start")
-            test(TestClassPathArg::class)
+            test<TestClassPathArg>()
         }
 
         // second nav
@@ -2331,7 +2382,113 @@
 
     @UiThreadTest
     @Test
-    fun testNavigateViaDeepLinkDefaultArgs() {
+    fun testNavigateViaDeepLinkKClass() {
+        val baseUri = "www.example.com"
+        @Serializable
+        class TestClass(val arg: Int)
+
+        val navController = createNavController()
+        navController.graph = navController.createGraph(startDestination = "start") {
+            test("start")
+            test<TestClass> {
+                deepLink(
+                    navDeepLink<TestClass> { uriPattern = baseUri }
+                )
+            }
+        }
+        val navigator = navController.navigatorProvider.getNavigator(TestNavigator::class.java)
+        val deepLink = Uri.parse("http://$baseUri/1")
+
+        navController.navigate(deepLink)
+
+        assertThat(navigator.backStack.size).isEqualTo(2)
+        assertThat(navController.currentBackStackEntry!!.arguments!!.getInt("arg"))
+            .isEqualTo(1)
+    }
+
+    @UiThreadTest
+    @Test
+    fun testNavigateViaDeepLinkKClassDefaultArg() {
+        val baseUri = "www.example.com"
+        @Serializable
+        class TestClass(val arg: Int = 1)
+
+        val navController = createNavController()
+        navController.graph = navController.createGraph(startDestination = "start") {
+            test("start")
+            test<TestClass> {
+                deepLink(
+                    navDeepLink<TestClass> { uriPattern = baseUri }
+                )
+            }
+        }
+        val navigator = navController.navigatorProvider.getNavigator(TestNavigator::class.java)
+        val deepLink = Uri.parse("http://$baseUri")
+
+        navController.navigate(deepLink)
+
+        assertThat(navigator.backStack.size).isEqualTo(2)
+        val dest = navController.currentBackStackEntry?.toRoute<TestClass>()
+        assertThat(dest?.arg).isEqualTo(1)
+    }
+
+    @UiThreadTest
+    @Test
+    fun testNavigateViaDeepLinkKClassDefaultArgOverride() {
+        val baseUri = "www.example.com"
+        @Serializable
+        class TestClass(val arg: Int = 1)
+
+        val navController = createNavController()
+        navController.graph = navController.createGraph(startDestination = "start") {
+            test("start")
+            test<TestClass> {
+                deepLink(
+                    navDeepLink<TestClass> { uriPattern = baseUri }
+                )
+            }
+        }
+        val navigator = navController.navigatorProvider.getNavigator(TestNavigator::class.java)
+        val deepLink = Uri.parse("http://$baseUri?arg=2")
+
+        navController.navigate(deepLink)
+
+        assertThat(navigator.backStack.size).isEqualTo(2)
+        val dest = navController.currentBackStackEntry?.toRoute<TestClass>()
+        assertThat(dest?.arg).isEqualTo(2)
+    }
+
+    @UiThreadTest
+    @Test
+    fun testNavigateViaDeepLinkKClassPopUpTo() {
+        val baseUri = "www.example.com"
+        @Serializable
+        class TestClass(val arg: Int)
+
+        val navController = createNavController()
+        navController.graph = navController.createGraph(startDestination = "start") {
+            test("start")
+            test<TestClass> {
+                deepLink(
+                    navDeepLink<TestClass> { uriPattern = baseUri }
+                )
+            }
+        }
+        val navigator = navController.navigatorProvider.getNavigator(TestNavigator::class.java)
+        val deepLink = Uri.parse("http://$baseUri/1")
+
+        navController.navigate(deepLink, navOptions {
+            popUpTo("start") { inclusive = true }
+        })
+
+        assertThat(navigator.backStack.size).isEqualTo(1)
+        assertThat(navController.currentBackStackEntry!!.arguments!!.getInt("arg"))
+            .isEqualTo(1)
+    }
+
+    @UiThreadTest
+    @Test
+    fun testNavigateViaDeepLinkDefaultArg() {
         val navController = createNavController()
         navController.graph = nav_simple_route_graph
         val navigator = navController.navigatorProvider.getNavigator(TestNavigator::class.java)
@@ -3082,7 +3239,7 @@
     fun testNavigateWithPopKClassInclusive() {
         val navController = createNavController()
         navController.graph = navController.createGraph(startDestination = TestClass::class) {
-            test(TestClass::class)
+            test<TestClass>()
             test("second")
         }
 
@@ -3106,7 +3263,7 @@
     fun testNavigateWithPopKClassNotInclusive() {
         val navController = createNavController()
         navController.graph = navController.createGraph(startDestination = TestClass::class) {
-            test(TestClass::class)
+            test<TestClass>()
             test("second")
             test("third")
         }
@@ -3135,7 +3292,7 @@
     fun testNavigateWithPopObjectInclusive() {
         val navController = createNavController()
         navController.graph = navController.createGraph(startDestination = TestClass::class) {
-            test(TestClass::class)
+            test<TestClass>()
             test("second")
         }
 
@@ -3159,7 +3316,7 @@
     fun testNavigateWithPopObjectNotInclusive() {
         val navController = createNavController()
         navController.graph = navController.createGraph(startDestination = TestClass::class) {
-            test(TestClass::class)
+            test<TestClass>()
             test("second")
             test("third")
         }
@@ -3188,7 +3345,7 @@
     fun testNavigateWithPopObjectArg() {
         val navController = createNavController()
         navController.graph = navController.createGraph(startDestination = TestClassPathArg(0)) {
-            test(TestClassPathArg::class)
+            test<TestClassPathArg>()
             test("second")
         }
 
@@ -3212,7 +3369,7 @@
     fun testNavigateWithPopObjectWrongArg() {
         val navController = createNavController()
         navController.graph = navController.createGraph(startDestination = TestClassPathArg(0)) {
-            test(TestClassPathArg::class)
+            test<TestClassPathArg>()
             test("second")
         }
 
@@ -3233,6 +3390,27 @@
 
     @UiThreadTest
     @Test
+    fun testNavigateWithObjectListArg() {
+        @Serializable
+        class TestClass(val arg: MutableList<Boolean>)
+
+        val navController = createNavController()
+        navController.graph = navController.createGraph(
+            startDestination = TestClass(mutableListOf(true, false, true))
+        ) {
+           test<TestClass>()
+        }
+        assertThat(navController.currentDestination?.route).isEqualTo(
+            "androidx.navigation.NavControllerRouteTest.testNavigateWithObjectListArg" +
+                ".TestClass?arg={arg}"
+        )
+        val route = navController.currentBackStackEntry?.toRoute<TestClass>()
+        assertThat(route?.arg is MutableList).isTrue()
+        assertThat(route?.arg).containsExactly(true, false, true).inOrder()
+    }
+
+    @UiThreadTest
+    @Test
     fun testDeepLinkFromNavGraph() {
         val navController = createNavController()
         navController.graph = nav_simple_route_graph
diff --git a/navigation/navigation-safe-args-gradle-plugin/src/test/kotlin/androidx/navigation/safeargs/gradle/BasePluginTest.kt b/navigation/navigation-safe-args-gradle-plugin/src/test/kotlin/androidx/navigation/safeargs/gradle/BasePluginTest.kt
index 5f0e351..187dc0e 100644
--- a/navigation/navigation-safe-args-gradle-plugin/src/test/kotlin/androidx/navigation/safeargs/gradle/BasePluginTest.kt
+++ b/navigation/navigation-safe-args-gradle-plugin/src/test/kotlin/androidx/navigation/safeargs/gradle/BasePluginTest.kt
@@ -115,7 +115,7 @@
         projectSetup.buildFile.writeText(
             """
             buildscript {
-                ext.compileSdk = ${props.compileSdkVersion}
+                ext.compileSdk = ${props.compileSdk}
                 ext.buildTools = "${props.buildToolsVersion}"
                 ext.minSdk = ${props.minSdkVersion}
                 ext.debugKeystoreFile = "${props.debugKeystore}"
diff --git a/paging/integration-tests/testapp/build.gradle b/paging/integration-tests/testapp/build.gradle
index 8b420e1..f198a5e 100644
--- a/paging/integration-tests/testapp/build.gradle
+++ b/paging/integration-tests/testapp/build.gradle
@@ -67,3 +67,7 @@
 tasks.withType(JavaCompile) {
     options.compilerArgs << "-parameters"
 }
+
+ksp {
+    arg('room.generateKotlin', 'false')
+}
diff --git a/pdf/pdf-viewer/src/main/res/values-be/strings.xml b/pdf/pdf-viewer/src/main/res/values-be/strings.xml
index 11d3a42..192a70e 100644
--- a/pdf/pdf-viewer/src/main/res/values-be/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-be/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"Тып файла"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"Гэты файл абаронены"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"Пароль"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"Няправільны пароль"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"Скасаваць"</string>
+    <string name="button_open" msgid="5445014062438566842">"Адкрыць"</string>
+    <string name="desc_password" msgid="6636473611443746739">"поле ўводу пароля"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"няправільны пароль"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"няправільны пароль"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> з <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"старонка <xliff:g id="PAGE">%1$d</xliff:g> з <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"маштаб <xliff:g id="FIRST">%1$d</xliff:g>%%"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"На старонку <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
     <string name="desc_page" msgid="5684226167093594168">"старонка <xliff:g id="PAGE">%1$d</xliff:g>"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"Выберыце тэкст, каб змясціць свой каментарый"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"Націсніце там, дзе будзеце каментаваць"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"Скасаваць"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"Не ўдаецца паказаць PDF-файл \"<xliff:g id="TITLE">%1$s</xliff:g>\" (няправільны фармат)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"Немагчыма адлюстраваць старонку <xliff:g id="PAGE">%1$d</xliff:g> (памылка файла)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Не ўдаецца загрузіць рэжым анатацый для гэтага элемента."</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Спасылка: вэб-старонка <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"Спасылка: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"Адрас электроннай пошты: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"Тэлефон: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"пачатак вылучэння"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"канец вылучэння"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> з <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-bg/strings.xml b/pdf/pdf-viewer/src/main/res/values-bg/strings.xml
index b1af046..71a21a7 100644
--- a/pdf/pdf-viewer/src/main/res/values-bg/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-bg/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"Файлов тип"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"Този файл е защитен"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"Парола"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"Неправилна парола"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"Отказ"</string>
+    <string name="button_open" msgid="5445014062438566842">"Отваряне"</string>
+    <string name="desc_password" msgid="6636473611443746739">"поле за парола"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"неправилна парола"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"неправилна парола"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"страница <xliff:g id="PAGE">%1$d</xliff:g> от <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"Процент на промяна на мащаба: <xliff:g id="FIRST">%1$d</xliff:g>"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"Към страница <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
     <string name="desc_page" msgid="5684226167093594168">"страница <xliff:g id="PAGE">%1$d</xliff:g>"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"Изберете текст, за да поставите коментара си"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"Докоснете област, която да коментирате"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"Отказ"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"PDF файлът <xliff:g id="TITLE">%1$s</xliff:g> не може да се покаже (форматът е невалиден)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"Страница <xliff:g id="PAGE">%1$d</xliff:g> не може да се покаже (грешка във файла)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Режимът за пояснения не може да се зареди за този елемент."</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Връзка: уеб страница от <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"Връзка: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"Имейл адрес: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"Телефон: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"начало на избраното"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"край на избраното"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g> – <xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-bn/strings.xml b/pdf/pdf-viewer/src/main/res/values-bn/strings.xml
index f4df82a..ec56333 100644
--- a/pdf/pdf-viewer/src/main/res/values-bn/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-bn/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"ফাইলের ধরন"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"এই ফাইল সুরক্ষিত আছে"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"পাসওয়ার্ড"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"পাসওয়ার্ড সঠিক নয়"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"বাতিল করুন"</string>
+    <string name="button_open" msgid="5445014062438566842">"খুলুন"</string>
+    <string name="desc_password" msgid="6636473611443746739">"পাসওয়ার্ড ফিল্ড"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"পাসওয়ার্ড সঠিক নয়"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"পাসওয়ার্ড সঠিক নয়"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"<xliff:g id="TOTAL">%2$d</xliff:g>টির মধ্যে <xliff:g id="PAGE">%1$d</xliff:g> নম্বর পৃষ্ঠা"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"<xliff:g id="FIRST">%1$d</xliff:g> শতাংশ জুম করুন"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"<xliff:g id="PAGE_NUMBER">%1$d</xliff:g> নম্বর পৃষ্ঠায় যান"</string>
     <string name="desc_page" msgid="5684226167093594168">"পৃষ্ঠা <xliff:g id="PAGE">%1$d</xliff:g>"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"আপনার কমেন্ট করতে টেক্সট বেছে নিন"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"কমেন্ট করতে কোনও একটি অংশে ট্যাপ করুন"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"বাতিল করুন"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"পিডিএফ দেখানো যাবে না (<xliff:g id="TITLE">%1$s</xliff:g> ভুল ফর্ম্যাটে আছে)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"<xliff:g id="PAGE">%1$d</xliff:g> পৃষ্ঠা দেখানো যাবে না (ফাইলে সমস্যা)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"এই আইটেমের জন্য অ্যানোটেশন মোড লোড করা যায়নি।"</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"লিঙ্ক: <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>-এ ওয়েবপেজ"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"লিঙ্ক: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"ইমেল: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"ফোন: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"বেছে নেওয়া টেক্সটের শুরু"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"বেছে নেওয়া টেক্সটের শেষ"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-bs/strings.xml b/pdf/pdf-viewer/src/main/res/values-bs/strings.xml
index cc94c57..6f0cfa1 100644
--- a/pdf/pdf-viewer/src/main/res/values-bs/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-bs/strings.xml
@@ -18,29 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"Vrsta fajla"</string>
-    <string name="title_dialog_password" msgid="2018068413709926925">"Datoteka je zaštićena"</string>
-    <string name="label_password_first" msgid="4456258714097111908">"Zaporka"</string>
-    <string name="label_password_incorrect" msgid="8449142641187704667">"Zaporka nije točna"</string>
-    <string name="button_cancel" msgid="5855794576957267334">"Odustani"</string>
+    <string name="title_dialog_password" msgid="2018068413709926925">"Fajl je zaštićen"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"Lozinka"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"Pogrešna lozinka"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"Otkaži"</string>
     <string name="button_open" msgid="5445014062438566842">"Otvori"</string>
-    <string name="desc_password" msgid="6636473611443746739">"polje zaporke"</string>
-    <string name="desc_password_incorrect" msgid="4718823067483963845">"zaporka nije točna"</string>
-    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"zaporka nije točna"</string>
+    <string name="desc_password" msgid="6636473611443746739">"polje za lozinku"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"pogrešna lozinka"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"pogrešna lozinka"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"<xliff:g id="PAGE">%1$d</xliff:g>. stranica od <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"zumiranje <xliff:g id="FIRST">%1$d</xliff:g> posto"</string>
-    <string name="desc_goto_link" msgid="2461368384824849714">"Idite na stranicu <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
+    <string name="desc_goto_link" msgid="2461368384824849714">"Odlazak na <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>. stranicu"</string>
     <string name="desc_page" msgid="5684226167093594168">"<xliff:g id="PAGE">%1$d</xliff:g>. stranica"</string>
-    <string name="message_select_text_to_comment" msgid="5725327644007067522">"Odaberite tekst za postavljanje komentara"</string>
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"Odaberite tekst da unesete komentar"</string>
     <string name="message_tap_to_comment" msgid="7820801719181709999">"Dodirnite područje koje ćete komentirati"</string>
-    <string name="action_cancel" msgid="5494417739210197522">"Odustani"</string>
-    <string name="error_file_format_pdf" msgid="7567006188638831878">"PDF se ne može prikazati (format <xliff:g id="TITLE">%1$s</xliff:g> nije važeći)"</string>
-    <string name="error_on_page" msgid="1592475819957182385">"Stranica <xliff:g id="PAGE">%1$d</xliff:g> ne može se prikazati (pogreška datoteke)"</string>
-    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Način za napomene za tu stavku ne može se učitati."</string>
-    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Veza: web-stranica na domeni <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
-    <string name="desc_web_link" msgid="2776023299237058419">"Veza: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
-    <string name="desc_email_link" msgid="7027325672358507448">"E-adresa: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
-    <string name="desc_phone_link" msgid="4986414958429253135">"Telefonski broj: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"Otkaži"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"Nije moguće prikazati PDF (fajl <xliff:g id="TITLE">%1$s</xliff:g> ima nevažeći format)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"Nije moguće prikazati <xliff:g id="PAGE">%1$d</xliff:g>. stranicu (greška fajla)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Nije moguće učitati način rada za bilješke za ovu stavku."</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Link: web stranica na <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"Link: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"Adresa e-pošte: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"Broj telefona: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"početak odabira"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"kraj odabira"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>.–<xliff:g id="LAST">%2$d</xliff:g>. / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-ca/strings.xml b/pdf/pdf-viewer/src/main/res/values-ca/strings.xml
index 8318f9e..0c26917 100644
--- a/pdf/pdf-viewer/src/main/res/values-ca/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ca/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"Tipus de fitxer"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"Aquest fitxer està protegit"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"Contrasenya"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"Contrasenya incorrecta"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"Cancel·la"</string>
+    <string name="button_open" msgid="5445014062438566842">"Obre"</string>
+    <string name="desc_password" msgid="6636473611443746739">"camp de contrasenya"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"contrasenya incorrecta"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"contrasenya incorrecta"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"pàgina <xliff:g id="PAGE">%1$d</xliff:g> de <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"zoom <xliff:g id="FIRST">%1$d</xliff:g> per cent"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"Ves a la pàgina <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
     <string name="desc_page" msgid="5684226167093594168">"pàgina <xliff:g id="PAGE">%1$d</xliff:g>"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"Selecciona text per escriure un comentari"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"Toca una zona per comentar-la"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"Cancel·la"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"No es pot mostrar el PDF (<xliff:g id="TITLE">%1$s</xliff:g> no és un format vàlid)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"No es pot mostrar la pàgina <xliff:g id="PAGE">%1$d</xliff:g> (error del fitxer)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"No es pot carregar el mode d\'anotació per a aquest element."</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Enllaç: pàgina web a <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"Enllaç: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"Adreça electrònica: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"Telèfon: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"inici de la selecció"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"final de la selecció"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-cs/strings.xml b/pdf/pdf-viewer/src/main/res/values-cs/strings.xml
index 2bb8adc..baf857b 100644
--- a/pdf/pdf-viewer/src/main/res/values-cs/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-cs/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"Typ souboru"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"Tento soubor je chráněn"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"Heslo"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"Nesprávné heslo"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"Zrušit"</string>
+    <string name="button_open" msgid="5445014062438566842">"Otevřít"</string>
+    <string name="desc_password" msgid="6636473611443746739">"pole hesla"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"nesprávné heslo"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"nesprávné heslo"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"stránka <xliff:g id="PAGE">%1$d</xliff:g> z <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"lupa <xliff:g id="FIRST">%1$d</xliff:g> procent"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"Přejít na stránku <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
     <string name="desc_page" msgid="5684226167093594168">"stránka <xliff:g id="PAGE">%1$d</xliff:g>"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"Vyberte text k umístění komentáře"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"Klepněte na oblast k okomentování"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"Zrušit"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"PDF nelze zobrazit (<xliff:g id="TITLE">%1$s</xliff:g> má neplatný formát)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"Stránku <xliff:g id="PAGE">%1$d</xliff:g> nelze zobrazit (chyba souboru)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Pro tuto položku nelze načíst režim poznámek."</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Odkaz: stránka na webu <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"Odkaz: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"E‑mail: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"Telefon: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"začátek výběru"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"konec výběru"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-da/strings.xml b/pdf/pdf-viewer/src/main/res/values-da/strings.xml
index fea00587..d4aa7e3 100644
--- a/pdf/pdf-viewer/src/main/res/values-da/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-da/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"Filtype"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"Denne fil er beskyttet"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"Adgangskode"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"Adgangskoden er forkert"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"Annuller"</string>
+    <string name="button_open" msgid="5445014062438566842">"Åbn"</string>
+    <string name="desc_password" msgid="6636473611443746739">"felt til adgangskode"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"adgangskoden er forkert"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"adgangskoden er forkert"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"side <xliff:g id="PAGE">%1$d</xliff:g> af <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"zoom <xliff:g id="FIRST">%1$d</xliff:g> %%"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"Gå til side <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
     <string name="desc_page" msgid="5684226167093594168">"side <xliff:g id="PAGE">%1$d</xliff:g>"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"Markér tekst for at indsætte din kommentar"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"Tryk på et område, du vil kommentere"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"Annuller"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"PDF kan ikke vises (<xliff:g id="TITLE">%1$s</xliff:g> er i et ugyldigt format)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"Side <xliff:g id="PAGE">%1$d</xliff:g> kan ikke vises (filfejl)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Annoteringstilstanden for dette element kan ikke indlæses."</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Link: webside på <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"Link: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"Mailadresse: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"Telefonnummer: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"start på markering"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"slut på markering"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-de/strings.xml b/pdf/pdf-viewer/src/main/res/values-de/strings.xml
index fcfc0f1..b341d91 100644
--- a/pdf/pdf-viewer/src/main/res/values-de/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-de/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"Dateityp"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"Diese Datei ist geschützt"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"Passwort"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"Falsches Passwort"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"Abbrechen"</string>
+    <string name="button_open" msgid="5445014062438566842">"Öffnen"</string>
+    <string name="desc_password" msgid="6636473611443746739">"Passwortfeld"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"Falsches Passwort"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"Falsches Passwort"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"Seite <xliff:g id="PAGE">%1$d</xliff:g> von <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"Zoom: <xliff:g id="FIRST">%1$d</xliff:g> %%"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"Gehe zu Seite <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
     <string name="desc_page" msgid="5684226167093594168">"Seite <xliff:g id="PAGE">%1$d</xliff:g>"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"Zum Einfügen des Kommentars Text auswählen"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"Auf Bereich tippen, um zu kommentieren"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"Abbrechen"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"Anzeige von PDF nicht möglich („<xliff:g id="TITLE">%1$s</xliff:g>“ hat ungültiges Dateiformat)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"Anzeige von Seite <xliff:g id="PAGE">%1$d</xliff:g> nicht möglich (Dateifehler)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Anmerkungsmodus für dieses Element kann nicht geladen werden."</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Link: Webseite unter <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"Link: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"E-Mail-Adresse: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"Telefonnummer: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"Beginn der Auswahl"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"Ende der Auswahl"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-el/strings.xml b/pdf/pdf-viewer/src/main/res/values-el/strings.xml
index 20a3d0d..14926d4 100644
--- a/pdf/pdf-viewer/src/main/res/values-el/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-el/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"Τύπος αρχείου"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"Αυτό το αρχείο είναι προστατευμένο"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"Κωδικός πρόσβασης"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"Εσφαλμένος κωδικός πρόσβασης"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"Ακύρωση"</string>
+    <string name="button_open" msgid="5445014062438566842">"Άνοιγμα"</string>
+    <string name="desc_password" msgid="6636473611443746739">"πεδίο κωδικού πρόσβασης"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"εσφαλμένος κωδικός πρόσβασης"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"εσφαλμένος κωδικός πρόσβασης"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"σελίδα <xliff:g id="PAGE">%1$d</xliff:g> από <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"εστίαση <xliff:g id="FIRST">%1$d</xliff:g> τοις εκατό"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"Μετάβαση στη σελίδα <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
     <string name="desc_page" msgid="5684226167093594168">"σελίδα <xliff:g id="PAGE">%1$d</xliff:g>"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"Επιλέξτε κείμενο για να τοποθετήσετε σχόλιο"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"Πατήστε μια περιοχή για να σχολιάσετε"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"Ακύρωση"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"Δεν είναι δυνατή η προβολή του PDF (μη έγκυρη μορφή του <xliff:g id="TITLE">%1$s</xliff:g>)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"Δεν είναι δυνατή η προβολή της σελίδας <xliff:g id="PAGE">%1$d</xliff:g> (σφάλμα αρχείου)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Δεν είναι δυνατή η φόρτωση της λειτουργίας σχολιασμού για αυτό το στοιχείο."</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Σύνδεσμος: ιστοσελίδα στη διεύθυνση <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"Σύνδεσμος: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"Διεύθυνση ηλεκτρονικού ταχυδρομείου: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"Τηλέφωνο: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"αρχή επιλογής"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"τέλος επιλογής"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-en-rAU/strings.xml b/pdf/pdf-viewer/src/main/res/values-en-rAU/strings.xml
index abd87b6..dcb8ff3 100644
--- a/pdf/pdf-viewer/src/main/res/values-en-rAU/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-en-rAU/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"File type"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"This file is protected"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"Password"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"Password incorrect"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"Cancel"</string>
+    <string name="button_open" msgid="5445014062438566842">"Open"</string>
+    <string name="desc_password" msgid="6636473611443746739">"password field"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"password incorrect"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"password incorrect"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"page <xliff:g id="PAGE">%1$d</xliff:g> of <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"zoom <xliff:g id="FIRST">%1$d</xliff:g> per cent"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"Go to page <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
     <string name="desc_page" msgid="5684226167093594168">"page <xliff:g id="PAGE">%1$d</xliff:g>"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"Select text to place your comment"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"Tap an area to comment on it"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"Cancel"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"Cannot display PDF (<xliff:g id="TITLE">%1$s</xliff:g> is of invalid format)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"Cannot display page <xliff:g id="PAGE">%1$d</xliff:g> (file error)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Can\'t load annotation mode for this item."</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Link: web page at <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"Link: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"Email: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"Phone: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"selection start"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"selection end"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-en-rGB/strings.xml b/pdf/pdf-viewer/src/main/res/values-en-rGB/strings.xml
index abd87b6..dcb8ff3 100644
--- a/pdf/pdf-viewer/src/main/res/values-en-rGB/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-en-rGB/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"File type"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"This file is protected"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"Password"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"Password incorrect"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"Cancel"</string>
+    <string name="button_open" msgid="5445014062438566842">"Open"</string>
+    <string name="desc_password" msgid="6636473611443746739">"password field"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"password incorrect"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"password incorrect"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"page <xliff:g id="PAGE">%1$d</xliff:g> of <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"zoom <xliff:g id="FIRST">%1$d</xliff:g> per cent"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"Go to page <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
     <string name="desc_page" msgid="5684226167093594168">"page <xliff:g id="PAGE">%1$d</xliff:g>"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"Select text to place your comment"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"Tap an area to comment on it"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"Cancel"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"Cannot display PDF (<xliff:g id="TITLE">%1$s</xliff:g> is of invalid format)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"Cannot display page <xliff:g id="PAGE">%1$d</xliff:g> (file error)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Can\'t load annotation mode for this item."</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Link: web page at <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"Link: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"Email: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"Phone: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"selection start"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"selection end"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-en-rIN/strings.xml b/pdf/pdf-viewer/src/main/res/values-en-rIN/strings.xml
index abd87b6..dcb8ff3 100644
--- a/pdf/pdf-viewer/src/main/res/values-en-rIN/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-en-rIN/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"File type"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"This file is protected"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"Password"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"Password incorrect"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"Cancel"</string>
+    <string name="button_open" msgid="5445014062438566842">"Open"</string>
+    <string name="desc_password" msgid="6636473611443746739">"password field"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"password incorrect"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"password incorrect"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"page <xliff:g id="PAGE">%1$d</xliff:g> of <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"zoom <xliff:g id="FIRST">%1$d</xliff:g> per cent"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"Go to page <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
     <string name="desc_page" msgid="5684226167093594168">"page <xliff:g id="PAGE">%1$d</xliff:g>"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"Select text to place your comment"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"Tap an area to comment on it"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"Cancel"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"Cannot display PDF (<xliff:g id="TITLE">%1$s</xliff:g> is of invalid format)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"Cannot display page <xliff:g id="PAGE">%1$d</xliff:g> (file error)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Can\'t load annotation mode for this item."</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Link: web page at <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"Link: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"Email: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"Phone: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"selection start"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"selection end"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-es-rUS/strings.xml b/pdf/pdf-viewer/src/main/res/values-es-rUS/strings.xml
index 4bca430..0db6b02 100644
--- a/pdf/pdf-viewer/src/main/res/values-es-rUS/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-es-rUS/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"Tipo de archivo"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"Este archivo está protegido"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"Contraseña"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"La contraseña es incorrecta"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"Cancelar"</string>
+    <string name="button_open" msgid="5445014062438566842">"Abrir"</string>
+    <string name="desc_password" msgid="6636473611443746739">"campo de contraseña"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"contraseña incorrecta"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"contraseña incorrecta"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> de <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"página <xliff:g id="PAGE">%1$d</xliff:g> de <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"zoom <xliff:g id="FIRST">%1$d</xliff:g> por ciento"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"Ir a la página <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
     <string name="desc_page" msgid="5684226167093594168">"página <xliff:g id="PAGE">%1$d</xliff:g>"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"Selecciona texto para colocar tu comentario"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"Presiona un área para comentar"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"Cancelar"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"No se puede mostrar el PDF (<xliff:g id="TITLE">%1$s</xliff:g> tiene un formato no válido)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"No se puede mostrar la página <xliff:g id="PAGE">%1$d</xliff:g> (error de archivo)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"No se puede cargar el modo de anotación para este elemento."</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Vínculo: página web en <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"Vínculo: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"Correo electrónico: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"Teléfono: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"inicio de la selección"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"fin de la selección"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g> a <xliff:g id="LAST">%2$d</xliff:g> de <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-es/strings.xml b/pdf/pdf-viewer/src/main/res/values-es/strings.xml
index 4f07b38..a416a41 100644
--- a/pdf/pdf-viewer/src/main/res/values-es/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-es/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"Tipo de archivo"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"Este archivo está protegido"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"Contraseña"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"Contraseña incorrecta"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"Cancelar"</string>
+    <string name="button_open" msgid="5445014062438566842">"Abrir"</string>
+    <string name="desc_password" msgid="6636473611443746739">"campo de contraseña"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"contraseña incorrecta"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"contraseña incorrecta"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"página <xliff:g id="PAGE">%1$d</xliff:g> de <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"zoom <xliff:g id="FIRST">%1$d</xliff:g> por ciento"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"Ir a la página <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
     <string name="desc_page" msgid="5684226167093594168">"página <xliff:g id="PAGE">%1$d</xliff:g>"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"Selecciona el texto para añadir tu comentario"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"Toca una zona para dejar un comentario"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"Cancelar"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"No se puede mostrar el PDF (el formato de <xliff:g id="TITLE">%1$s</xliff:g> no es válido)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"No se puede mostrar la página <xliff:g id="PAGE">%1$d</xliff:g> (error de archivo)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"No se puede cargar el modo de anotación en este elemento."</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Enlace: página web en <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"Enlace: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"Correo: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"Teléfono: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"inicio de la selección"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"final de la selección"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-et/strings.xml b/pdf/pdf-viewer/src/main/res/values-et/strings.xml
index 18e68f0..88b7755 100644
--- a/pdf/pdf-viewer/src/main/res/values-et/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-et/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"Faili tüüp"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"Fail on kaitstud"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"Parool"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"Parool on vale"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"Tühista"</string>
+    <string name="button_open" msgid="5445014062438566842">"Ava"</string>
+    <string name="desc_password" msgid="6636473611443746739">"parooliväli"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"parool on vale"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"parool on vale"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"lk <xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"suum <xliff:g id="FIRST">%1$d</xliff:g> protsenti"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"Mine lehele <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
     <string name="desc_page" msgid="5684226167093594168">"lk <xliff:g id="PAGE">%1$d</xliff:g>"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"Valige tekst, millele kommentaar lisada"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"Puudutage ala, millele kommentaar lisada"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"Tühista"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"PDF-i ei saa kuvada (<xliff:g id="TITLE">%1$s</xliff:g> on vales vormingus)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"Lehekülge <xliff:g id="PAGE">%1$d</xliff:g> ei saa kuvada (viga failis)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Selle üksuse jaoks ei saa märkuste lisamise režiimi laadida."</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Link: veebileht aadressil <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"Link: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"E-posti aadress: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"Telefon: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"valiku algus"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"valiku lõpp"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-eu/strings.xml b/pdf/pdf-viewer/src/main/res/values-eu/strings.xml
index dd0b571..1f0b66d 100644
--- a/pdf/pdf-viewer/src/main/res/values-eu/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-eu/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"Fitxategi mota"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"Fitxategi hau babestuta dago"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"Pasahitza"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"Pasahitza okerra da"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"Utzi"</string>
+    <string name="button_open" msgid="5445014062438566842">"Ireki"</string>
+    <string name="desc_password" msgid="6636473611443746739">"pasahitzaren eremua"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"pasahitza okerra da"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"pasahitza okerra da"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"<xliff:g id="TOTAL">%2$d</xliff:g> orritatik <xliff:g id="PAGE">%1$d</xliff:g>garrena"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"zooma ehuneko <xliff:g id="FIRST">%1$d</xliff:g>"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"Joan <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>. orrira"</string>
     <string name="desc_page" msgid="5684226167093594168">"<xliff:g id="PAGE">%1$d</xliff:g>garren orria"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"Iruzkina egiteko, hautatu testua"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"Sakatu iruzkindu beharreko eremua"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"Utzi"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"Ezin da erakutsi PDFa (<xliff:g id="TITLE">%1$s</xliff:g> fitxategiaren formatuak ez du balio)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"Ezin da erakutsi <xliff:g id="PAGE">%1$d</xliff:g> orria (fitxategi-errorea)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Ezin da kargatu oharpenen modua elementu honetarako."</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Esteka: <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g> domeinuko web-orria"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"Esteka: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"Helbide elektronikoa: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"Telefono-zenbakia: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"hautapenaren hasiera"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"hautapenaren amaiera"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-fi/strings.xml b/pdf/pdf-viewer/src/main/res/values-fi/strings.xml
index 482722b..c1ad329 100644
--- a/pdf/pdf-viewer/src/main/res/values-fi/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-fi/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"Tiedostotyyppi"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"Tämä tiedosto on suojattu"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"Salasana"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"Väärä salasana"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"Peruuta"</string>
+    <string name="button_open" msgid="5445014062438566842">"Avaa"</string>
+    <string name="desc_password" msgid="6636473611443746739">"salasanakenttä"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"väärä salasana"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"väärä salasana"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"sivu <xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"zoomaus <xliff:g id="FIRST">%1$d</xliff:g> prosenttia"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"Siirry sivulle <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
     <string name="desc_page" msgid="5684226167093594168">"sivu <xliff:g id="PAGE">%1$d</xliff:g>"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"Valitse teksti, johon haluat lisätä kommentin"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"Napauta kommentoitavaa aluetta"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"Peruuta"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"PDF:ää ei voi näyttää (<xliff:g id="TITLE">%1$s</xliff:g> on virheellinen muoto)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"Sivua <xliff:g id="PAGE">%1$d</xliff:g> ei voi näyttää (tiedostovirhe)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Kohteen muistiinpanotilaa ei voi ladata."</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Linkki: verkkosivu osoitteessa <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"Linkki: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"Sähköpostiosoite: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"Puhelinnumero: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"valinnan alku"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"valinnan loppu"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-fr-rCA/strings.xml b/pdf/pdf-viewer/src/main/res/values-fr-rCA/strings.xml
index bb4469d..d1cf1e2 100644
--- a/pdf/pdf-viewer/src/main/res/values-fr-rCA/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-fr-rCA/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"Type de fichier"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"Ce fichier est protégé"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"Mot de passe"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"Mot de passe incorrect"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"Annuler"</string>
+    <string name="button_open" msgid="5445014062438566842">"Ouvrir"</string>
+    <string name="desc_password" msgid="6636473611443746739">"champ du mot de passe"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"mot de passe incorrect"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"mot de passe incorrect"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"page <xliff:g id="PAGE">%1$d</xliff:g> sur <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"zoom <xliff:g id="FIRST">%1$d</xliff:g> pour cent"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"Accéder à la page <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
     <string name="desc_page" msgid="5684226167093594168">"page <xliff:g id="PAGE">%1$d</xliff:g>"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"Sélect. du texte pour placer le commentaire"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"Touchez une zone à commenter"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"Annuler"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"Impossible d\'afficher le PDF (format de <xliff:g id="TITLE">%1$s</xliff:g> non valide)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"Impossible d\'afficher la page <xliff:g id="PAGE">%1$d</xliff:g> (erreur de fichier)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Impossible de charger le mode d\'annotation pour cet élément."</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Lien : page Web sur <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"Lien : <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"Adresse de courriel : <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"Numéro de téléphone : <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"début de la sélection"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"fin de la sélection"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-fr/strings.xml b/pdf/pdf-viewer/src/main/res/values-fr/strings.xml
index 37ae617..9ea14c1 100644
--- a/pdf/pdf-viewer/src/main/res/values-fr/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-fr/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"Type de fichier"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"Ce fichier est protégé"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"Mot de passe"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"Mot de passe incorrect"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"Annuler"</string>
+    <string name="button_open" msgid="5445014062438566842">"Ouvrir"</string>
+    <string name="desc_password" msgid="6636473611443746739">"champ de mot de passe"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"mot de passe incorrect"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"mot de passe incorrect"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"page <xliff:g id="PAGE">%1$d</xliff:g> sur <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"zoom : <xliff:g id="FIRST">%1$d</xliff:g> pour cent"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"Accéder à la page <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
     <string name="desc_page" msgid="5684226167093594168">"page <xliff:g id="PAGE">%1$d</xliff:g>"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"Sélectionnez le texte à commenter"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"Appuyez sur la zone à commenter"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"Annuler"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"Impossible d\'afficher le PDF (format non valide pour <xliff:g id="TITLE">%1$s</xliff:g>)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"Impossible d\'afficher la page <xliff:g id="PAGE">%1$d</xliff:g> (erreur de fichier)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Impossible de charger le mode Annotation pour cet élément."</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Lien : page Web du domaine <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"Lien : <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"Adresse e-mail : <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"Téléphone : <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"début de la sélection"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"fin de la sélection"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-gl/strings.xml b/pdf/pdf-viewer/src/main/res/values-gl/strings.xml
index ce8c6b3..4a85719 100644
--- a/pdf/pdf-viewer/src/main/res/values-gl/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-gl/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"Tipo de ficheiro"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"Este ficheiro está protexido"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"Contrasinal"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"Contrasinal incorrecto"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"Cancelar"</string>
+    <string name="button_open" msgid="5445014062438566842">"Abrir"</string>
+    <string name="desc_password" msgid="6636473611443746739">"campo do contrasinal"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"contrasinal incorrecto"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"contrasinal incorrecto"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"páxina <xliff:g id="PAGE">%1$d</xliff:g> de <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"zoom ao <xliff:g id="FIRST">%1$d</xliff:g> por cento"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"Vai á páxina <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
     <string name="desc_page" msgid="5684226167093594168">"páxina <xliff:g id="PAGE">%1$d</xliff:g>"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"Selecciona o texto para engadir un comentario"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"Toca a zona na que engadir un comentario"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"Cancelar"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"Non se puido mostrar o PDF (<xliff:g id="TITLE">%1$s</xliff:g> ten un formato non válido)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"Non se puido mostrar a páxina <xliff:g id="PAGE">%1$d</xliff:g> (hai un erro no ficheiro)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Non se puido cargar o modo de anotación para este elemento."</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Ligazón: páxina web en <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"Ligazón: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"Correo electrónico: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"Teléfono: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"inicio da selección"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"fin da selección"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-hu/strings.xml b/pdf/pdf-viewer/src/main/res/values-hu/strings.xml
index 618d6b0..72c88d9 100644
--- a/pdf/pdf-viewer/src/main/res/values-hu/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-hu/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"Fájltípus"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"A fájl védett"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"Jelszó"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"Helytelen jelszó"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"Mégse"</string>
+    <string name="button_open" msgid="5445014062438566842">"Megnyitás"</string>
+    <string name="desc_password" msgid="6636473611443746739">"jelszómező"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"helytelen jelszó"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"helytelen jelszó"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="TOTAL">%2$d</xliff:g>/<xliff:g id="PAGE">%1$d</xliff:g>."</string>
     <string name="desc_page_single" msgid="8459583146661044094">"<xliff:g id="TOTAL">%2$d</xliff:g>/<xliff:g id="PAGE">%1$d</xliff:g>. oldal"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"<xliff:g id="FIRST">%1$d</xliff:g> százalékos nagyítás"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"Ugrás erre az oldalra: <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
     <string name="desc_page" msgid="5684226167093594168">"<xliff:g id="PAGE">%1$d</xliff:g>. oldal"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"Válassza ki a szöveget a megjegyzéshez"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"Koppintson arra a területre, amelyhez megjegyzést szeretne fűzni"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"Mégse"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"Nem sikerült megjeleníteni a PDF-et (<xliff:g id="TITLE">%1$s</xliff:g> formátuma érvénytelen)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"Nem sikerült megjeleníteni a(z) <xliff:g id="PAGE">%1$d</xliff:g> oldalt (fájlhiba)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Az elemhez nem lehet betölteni kommentár módot."</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Link: weboldal helye: <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"Link: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"E-mail-cím: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"Telefon: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"kijelölés kezdete"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"kijelölés vége"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="TOTAL">%3$d</xliff:g>/<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g>."</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-hy/strings.xml b/pdf/pdf-viewer/src/main/res/values-hy/strings.xml
index 376f583..bcf72be 100644
--- a/pdf/pdf-viewer/src/main/res/values-hy/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-hy/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"Ֆայլի տեսակը"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"Այս ֆայլը պաշտպանված է"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"Գաղտնաբառ"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"Գաղտնաբառը սխալ է"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"Չեղարկել"</string>
+    <string name="button_open" msgid="5445014062438566842">"Բացել"</string>
+    <string name="desc_password" msgid="6636473611443746739">"գաղտնաբառի դաշտ"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"գաղտնաբառը սխալ է"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"գաղտնաբառը սխալ է"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"Էջ <xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"մասշտաբը՝ <xliff:g id="FIRST">%1$d</xliff:g> տոկոս"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"Անցեք <xliff:g id="PAGE_NUMBER">%1$d</xliff:g> էջ"</string>
     <string name="desc_page" msgid="5684226167093594168">"էջ <xliff:g id="PAGE">%1$d</xliff:g>"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"Նշեք տեքստը՝ մեկնաբանություն տեղադրելու համար"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"Հպեք՝ մեկնաբանություն ավելացնելու համար"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"Չեղարկել"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"Հնարավոր չէ ցուցադրել PDF-ը (<xliff:g id="TITLE">%1$s</xliff:g> ֆայլը անվավեր ձևաչափ ունի)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"Հնարավոր չէ ցուցադրել էջ <xliff:g id="PAGE">%1$d</xliff:g>-ը (ֆայլի սխալ)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Չհաջողվեց բեռնել ծանոթագրության ռեժիմն այս տարրի համար։"</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Հղում՝ կայքէջ <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>-ում"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"Հղում՝ <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"Էլ․ հասցե՝ <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"Հեռախոս՝ <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"ընտրվածքի սկիզբ"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"ընտրվածքի վերջ"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-it/strings.xml b/pdf/pdf-viewer/src/main/res/values-it/strings.xml
index a6bc398..fb24fa5 100644
--- a/pdf/pdf-viewer/src/main/res/values-it/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-it/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"Tipo di file"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"Questo file è protetto"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"Password"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"Password errata"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"Annulla"</string>
+    <string name="button_open" msgid="5445014062438566842">"Apri"</string>
+    <string name="desc_password" msgid="6636473611443746739">"campo password"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"password errata"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"password errata"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"pagina <xliff:g id="PAGE">%1$d</xliff:g> di <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"zoom <xliff:g id="FIRST">%1$d</xliff:g>%%"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"Vai alla pagina <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
     <string name="desc_page" msgid="5684226167093594168">"pagina <xliff:g id="PAGE">%1$d</xliff:g>"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"Seleziona il testo da inserire nel commento"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"Tocca un\'area per inserire un commento"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"Annulla"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"Impossibile visualizzare PDF (<xliff:g id="TITLE">%1$s</xliff:g> è in un formato non valido)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"Impossibile visualizzare la pagina <xliff:g id="PAGE">%1$d</xliff:g> (errore del file)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Impossibile caricare la modalità di annotazione per questo elemento."</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Link: pagina web all\'indirizzo <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"Link: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"Email: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"Telefono: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"inizio selezione"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"fine selezione"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-iw/strings.xml b/pdf/pdf-viewer/src/main/res/values-iw/strings.xml
index c7b0d79..411301a 100644
--- a/pdf/pdf-viewer/src/main/res/values-iw/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-iw/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"סוג הקובץ"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"הקובץ הזה מוגן"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"סיסמה"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"הסיסמה שגויה"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"ביטול"</string>
+    <string name="button_open" msgid="5445014062438566842">"פתיחה"</string>
+    <string name="desc_password" msgid="6636473611443746739">"שדה הסיסמה"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"הסיסמה שגויה"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"הסיסמה שגויה"</string>
     <string name="label_page_single" msgid="456123685879261101">"‎<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>‫‎"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"דף <xliff:g id="PAGE">%1$d</xliff:g> מתוך <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"שינוי מרחק התצוגה ב-<xliff:g id="FIRST">%1$d</xliff:g> אחוזים"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"מעבר לדף <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
     <string name="desc_page" msgid="5684226167093594168">"עמוד <xliff:g id="PAGE">%1$d</xliff:g>"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"צריך לבחור את הטקסט לתגובה"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"אפשר להקיש על אזור כדי להגיב עליו"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"ביטול"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"‏אי אפשר להציג קובץ PDF ‏(<xliff:g id="TITLE">%1$s</xliff:g> בפורמט לא תקין)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"לא ניתן להציג את הדף <xliff:g id="PAGE">%1$d</xliff:g> (שגיאת קובץ)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"אי אפשר לטעון את מצב ההערות בפריט הזה."</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"קישור: דף אינטרנט בדומיין <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"קישור: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"אימייל: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"טלפון: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"התחלת הבחירה"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"סיום הבחירה"</string>
     <string name="label_page_range" msgid="8290964180158460076">"‫‎<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>‎"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-ja/strings.xml b/pdf/pdf-viewer/src/main/res/values-ja/strings.xml
index 34f3ae5..13cb183 100644
--- a/pdf/pdf-viewer/src/main/res/values-ja/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ja/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"ファイル形式"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"このファイルは保護されています"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"パスワード"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"パスワードが正しくありません"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"キャンセル"</string>
+    <string name="button_open" msgid="5445014062438566842">"開く"</string>
+    <string name="desc_password" msgid="6636473611443746739">"パスワードを入力する項目です"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"パスワードが正しくありません"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"パスワードが正しくありません"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g> ページ"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"ズーム <xliff:g id="FIRST">%1$d</xliff:g> %%"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"<xliff:g id="PAGE_NUMBER">%1$d</xliff:g> ページに移動します"</string>
     <string name="desc_page" msgid="5684226167093594168">"<xliff:g id="PAGE">%1$d</xliff:g> ページ"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"コメントを配置するテキストを選択してください"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"コメント対象の範囲をタップしてください"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"キャンセル"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"PDF を表示できません(<xliff:g id="TITLE">%1$s</xliff:g> の形式が無効です)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"<xliff:g id="PAGE">%1$d</xliff:g> ページを表示できません(ファイルエラー)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"このアイテムのアノテーション モードを読み込めません。"</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"リンク: ウェブページ(<xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>)"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"リンク: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"メールアドレス: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"電話番号: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"選択範囲の最初"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"選択範囲の最後"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>~<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-ka/strings.xml b/pdf/pdf-viewer/src/main/res/values-ka/strings.xml
index dc8c626..115eceb 100644
--- a/pdf/pdf-viewer/src/main/res/values-ka/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ka/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"ფაილის ტიპი"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"ეს ფაილი დაცულია"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"პაროლი"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"პაროლი არასწორია"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"გაუქმება"</string>
+    <string name="button_open" msgid="5445014062438566842">"გახსნა"</string>
+    <string name="desc_password" msgid="6636473611443746739">"პაროლის ველი"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"პაროლი არასწორია"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"პაროლი არასწორია"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>-დან"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"გვერდი <xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>-დან"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"მასშტაბი <xliff:g id="FIRST">%1$d</xliff:g> პროცენტი"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"<xliff:g id="PAGE_NUMBER">%1$d</xliff:g>-ე გვერდზე გადასვლა"</string>
     <string name="desc_page" msgid="5684226167093594168">"გვერდი <xliff:g id="PAGE">%1$d</xliff:g>"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"კომენტარის განსათავსებლად მონიშნეთ ტექსტი"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"შეეხეთ ველს კომენტარის დასატოვებლად"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"გაუქმება"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"PDF-ის ჩვენება შეუძლებელია (<xliff:g id="TITLE">%1$s</xliff:g> არასწორ ფორმატშია)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"გვერდის ჩვენება შეუძლებელია <xliff:g id="PAGE">%1$d</xliff:g> (ფაილის შეცდომა)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"ამ ერთეულისთვის ანოტაციის რეჟიმის ჩატვირთვა არ არის შესაძლებელი."</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"ბმული: ვებგვერდი <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"ბმული: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"ელფოსტა: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"ტელეფონის ნომერი: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"არჩევანის დასაწყისი"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"არჩევანის დასასრული"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>-დან"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-kk/strings.xml b/pdf/pdf-viewer/src/main/res/values-kk/strings.xml
index 678c988..27917cf 100644
--- a/pdf/pdf-viewer/src/main/res/values-kk/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-kk/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"Файл түрі"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"Бұл файл қорғалған"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"Құпия сөз"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"Құпия сөз қате"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"Бас тарту"</string>
+    <string name="button_open" msgid="5445014062438566842">"Ашу"</string>
+    <string name="desc_password" msgid="6636473611443746739">"құпия сөз өрісі"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"құпия сөз қате"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"құпия сөз қате"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"Бет: <xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"<xliff:g id="FIRST">%1$d</xliff:g> пайызға масштабтау"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"<xliff:g id="PAGE_NUMBER">%1$d</xliff:g>-бетке өтіңіз."</string>
     <string name="desc_page" msgid="5684226167093594168">"<xliff:g id="PAGE">%1$d</xliff:g>-бет"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"Пікір қалдыру үшін мәтін таңдаңыз."</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"Пікір қалдыру үшін аймақты түртіңіз."</string>
+    <string name="action_cancel" msgid="5494417739210197522">"Бас тарту"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"PDF файлын көрсету мүмкін емес (<xliff:g id="TITLE">%1$s</xliff:g> форматы жарамсыз)."</string>
+    <string name="error_on_page" msgid="1592475819957182385">"<xliff:g id="PAGE">%1$d</xliff:g>-бетті көрсету мүмкін емес (файл қатесі)."</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Бұл элемент үшін aннотация режимін жүктеу мүмкін емес."</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Сілтеме: <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g> веб-беті"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"Сілтеме: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"Электрондық мекенжай: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"Телефон: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"таңдалған мәтіннің басы"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"таңдалған мәтіннің соңы"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-kn/strings.xml b/pdf/pdf-viewer/src/main/res/values-kn/strings.xml
index dca93d4..eef4ed4 100644
--- a/pdf/pdf-viewer/src/main/res/values-kn/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-kn/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"ಫೈಲ್ ಪ್ರಕಾರ"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"ಈ ಫೈಲ್ ಅನ್ನು ಸಂರಕ್ಷಿಸಲಾಗಿದೆ"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"ಪಾಸ್‌ವರ್ಡ್"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"ಪಾಸ್‌ವರ್ಡ್ ತಪ್ಪಾಗಿದೆ"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"ರದ್ದುಮಾಡಿ"</string>
+    <string name="button_open" msgid="5445014062438566842">"ತೆರೆಯಿರಿ"</string>
+    <string name="desc_password" msgid="6636473611443746739">"ಪಾಸ್‌ವರ್ಡ್ ಫೀಲ್ಡ್"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"ಪಾಸ್‌ವರ್ಡ್ ತಪ್ಪಾಗಿದೆ"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"ಪಾಸ್‌ವರ್ಡ್ ತಪ್ಪಾಗಿದೆ"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"<xliff:g id="TOTAL">%2$d</xliff:g> ರಲ್ಲಿ <xliff:g id="PAGE">%1$d</xliff:g> ಪುಟ"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"ಶೇಕಡಾ <xliff:g id="FIRST">%1$d</xliff:g> ರಷ್ಟು ಝೂಮ್ ಮಾಡಿ"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"ಪುಟ <xliff:g id="PAGE_NUMBER">%1$d</xliff:g> ಕ್ಕೆ ತೆರಳಿ"</string>
     <string name="desc_page" msgid="5684226167093594168">"ಪುಟ <xliff:g id="PAGE">%1$d</xliff:g>"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"ನಿಮ್ಮ ಕಾಮೆಂಟ್ ಅನ್ನು ಇರಿಸಲು ಪಠ್ಯವನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"ಕಾಮೆಂಟ್ ಮಾಡಲು ಪ್ರದೇಶವನ್ನು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"ರದ್ದುಮಾಡಿ"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"PDF ಅನ್ನು ಪ್ರದರ್ಶಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ (<xliff:g id="TITLE">%1$s</xliff:g> ಅಮಾನ್ಯವಾದ ಫಾರ್ಮ್ಯಾಟ್ ಆಗಿದೆ)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"<xliff:g id="PAGE">%1$d</xliff:g> ಪುಟವನ್ನು ಪ್ರದರ್ಶಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ (ಫೈಲ್ ದೋಷ)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"ಈ ಐಟಂಗೆ ಟಿಪ್ಪಣಿಯನ್ನು ಲೋಡ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ."</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"ಲಿಂಕ್: <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g> ನಲ್ಲಿರುವ ವೆಬ್‌ಪುಟ"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"ಲಿಂಕ್: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"ಇಮೇಲ್: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"ಫೋನ್: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"ಆಯ್ಕೆ ಪ್ರಾರಂಭ"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"ಆಯ್ಕೆ ಮುಕ್ತಾಯ"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-ko/strings.xml b/pdf/pdf-viewer/src/main/res/values-ko/strings.xml
index c473a9f..f183833 100644
--- a/pdf/pdf-viewer/src/main/res/values-ko/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ko/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"파일 형식"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"보호된 파일임"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"비밀번호"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"비밀번호가 잘못됨"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"취소"</string>
+    <string name="button_open" msgid="5445014062438566842">"열기"</string>
+    <string name="desc_password" msgid="6636473611443746739">"비밀번호 입력란"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"비밀번호가 잘못됨"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"비밀번호가 잘못됨"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"<xliff:g id="TOTAL">%2$d</xliff:g>페이지 중 <xliff:g id="PAGE">%1$d</xliff:g>페이지"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"<xliff:g id="FIRST">%1$d</xliff:g>%% 확대/축소"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"<xliff:g id="PAGE_NUMBER">%1$d</xliff:g> 페이지로 이동"</string>
     <string name="desc_page" msgid="5684226167093594168">"<xliff:g id="PAGE">%1$d</xliff:g>페이지"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"댓글을 달려는 텍스트를 선택하세요."</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"댓글을 달려는 영역을 탭하세요."</string>
+    <string name="action_cancel" msgid="5494417739210197522">"취소"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"<xliff:g id="TITLE">%1$s</xliff:g>의 형식이 잘못되어 PDF를 표시할 수 없음"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"파일 오류로 <xliff:g id="PAGE">%1$d</xliff:g> 페이지를 표시할 수 없음"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"이 항목에 대한 주석 모드를 로드할 수 없습니다."</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"링크: <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>의 웹페이지"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"링크: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"이메일: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"전화번호: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"선택 영역 시작"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"선택 영역 끝"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>~<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-lt/strings.xml b/pdf/pdf-viewer/src/main/res/values-lt/strings.xml
index ca512f2..6742411 100644
--- a/pdf/pdf-viewer/src/main/res/values-lt/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-lt/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"Failo tipas"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"Šis failas yra apsaugotas"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"Slaptažodis"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"Slaptažodis netinkamas"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"Atšaukti"</string>
+    <string name="button_open" msgid="5445014062438566842">"Atidaryti"</string>
+    <string name="desc_password" msgid="6636473611443746739">"slaptažodžio laukas"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"slaptažodis netinkamas"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"slaptažodis netinkamas"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> iš <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"<xliff:g id="PAGE">%1$d</xliff:g> psl. iš <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"keisti mastelį <xliff:g id="FIRST">%1$d</xliff:g> proc."</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"Eiti į <xliff:g id="PAGE_NUMBER">%1$d</xliff:g> puslapį"</string>
     <string name="desc_page" msgid="5684226167093594168">"<xliff:g id="PAGE">%1$d</xliff:g> psl."</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"Pasirinkite tekstą, kad pateiktumėte komentarą"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"Palieskite komentuotiną sritį"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"Atšaukti"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"Negalima pateikti PDF („<xliff:g id="TITLE">%1$s</xliff:g>“ netinkamo formato)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"Negalima pateikti <xliff:g id="PAGE">%1$d</xliff:g> puslapio (failo klaida)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Nepavyko įkelti šio elemento komentaro režimo."</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Nuoroda: tinklalapis adresu <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"Nuoroda: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"El. pašto adresas: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"Telefono numeris: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"pasirinkimo pradžia"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"pasirinkimo pabaiga"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g> iš <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-lv/strings.xml b/pdf/pdf-viewer/src/main/res/values-lv/strings.xml
index 6807178..00d9d40 100644
--- a/pdf/pdf-viewer/src/main/res/values-lv/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-lv/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"Faila tips"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"Šis fails ir aizsargāts"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"Parole"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"Parole nav pareiza"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"Atcelt"</string>
+    <string name="button_open" msgid="5445014062438566842">"Atvērt"</string>
+    <string name="desc_password" msgid="6636473611443746739">"paroles lauks"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"parole nav pareiza"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"parole nav pareiza"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"<xliff:g id="PAGE">%1$d</xliff:g>. lapa no <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"tālummaiņa procentos ir <xliff:g id="FIRST">%1$d</xliff:g>"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"Doties uz <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>. lapu"</string>
     <string name="desc_page" msgid="5684226167093594168">"<xliff:g id="PAGE">%1$d</xliff:g>. lapa"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"Atlasiet tekstu, lai pievienotu komentāru"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"Pieskarieties komentējamajam apgabalam"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"Atcelt"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"Nevar parādīt PDF (faila “<xliff:g id="TITLE">%1$s</xliff:g>” formāts nav derīgs)."</string>
+    <string name="error_on_page" msgid="1592475819957182385">"Nevar parādīt <xliff:g id="PAGE">%1$d</xliff:g>. lapu (faila kļūda)."</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Šim vienumam nevar ielādēt anotēšanas režīmu."</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Saite: tīmekļa lapa domēnā <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"Saite: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"E-pasta adrese: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"Tālruņa numurs: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"atlases sākums"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"atlases beigas"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-mk/strings.xml b/pdf/pdf-viewer/src/main/res/values-mk/strings.xml
index 2c8826b..d128f84 100644
--- a/pdf/pdf-viewer/src/main/res/values-mk/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-mk/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"Вид датотека"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"Датотекава е заштитена"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"Лозинка"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"Лозинката е неточна"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"Откажи"</string>
+    <string name="button_open" msgid="5445014062438566842">"Отвори"</string>
+    <string name="desc_password" msgid="6636473611443746739">"поле за лозинка"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"лозинката е неточна"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"лозинката е неточна"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"страница <xliff:g id="PAGE">%1$d</xliff:g> од <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"зумирајте <xliff:g id="FIRST">%1$d</xliff:g> проценти"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"Одете на страницата <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
     <string name="desc_page" msgid="5684226167093594168">"страница <xliff:g id="PAGE">%1$d</xliff:g>"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"Изберете текст за поставување на коментарот"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"Допрете област за која ќе коментирате"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"Откажи"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"Не може да се прикаже PDF (<xliff:g id="TITLE">%1$s</xliff:g> е со неважечки формат)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"Не може да се прикаже страницата <xliff:g id="PAGE">%1$d</xliff:g> (грешка во датотеката)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Не може да се вчита „Режимот за прибелешки“ за ставкава."</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Линк: веб-страница на <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"Линк: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"Е-пошта: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"Телефон: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"почеток на изборот"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"крај на изборот"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g> – <xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-mn/strings.xml b/pdf/pdf-viewer/src/main/res/values-mn/strings.xml
index aacb03b..e746e33 100644
--- a/pdf/pdf-viewer/src/main/res/values-mn/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-mn/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"Файлын төрөл"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"Энэ файл хамгаалагдсан"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"Нууц үг"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"Нууц үг буруу байна"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"Цуцлах"</string>
+    <string name="button_open" msgid="5445014062438566842">"Нээх"</string>
+    <string name="desc_password" msgid="6636473611443746739">"нууц үгний талбар"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"нууц үг буруу байна"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"нууц үг буруу байна"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="TOTAL">%2$d</xliff:g>-н <xliff:g id="PAGE">%1$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"<xliff:g id="TOTAL">%2$d</xliff:g>-н <xliff:g id="PAGE">%1$d</xliff:g>-р хуудас"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"<xliff:g id="FIRST">%1$d</xliff:g> хувь томруулсан"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"<xliff:g id="PAGE_NUMBER">%1$d</xliff:g>-р хуудсанд очих"</string>
     <string name="desc_page" msgid="5684226167093594168">"<xliff:g id="PAGE">%1$d</xliff:g>-р хуудас"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"Сэтгэгдлээ байрлуулахын тулд текст сонгоно уу"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"Сэтгэгдэл бичих хэсэг дээр товшино уу"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"Цуцлах"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"PDF-г үзүүлэх боломжгүй (<xliff:g id="TITLE">%1$s</xliff:g>-н формат буруу байна)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"<xliff:g id="PAGE">%1$d</xliff:g> хуудсыг үзүүлэх боломжгүй (файлын алдаа)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Энэ зүйлд тэмдэглэгээний горимыг ачаалах боломжгүй."</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Холбоос: <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g> дээрх веб хуудас"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"Холбоос: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"Имэйл: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"Утас: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"сонголтын эхлэл"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"сонголтын төгсгөл"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-mr/strings.xml b/pdf/pdf-viewer/src/main/res/values-mr/strings.xml
index 1d11dc7..4da35f6 100644
--- a/pdf/pdf-viewer/src/main/res/values-mr/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-mr/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"फाइल प्रकार"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"ही फाइल संरक्षित आहे"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"पासवर्ड"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"पासवर्ड चुकीचा आहे"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"रद्द करा"</string>
+    <string name="button_open" msgid="5445014062438566842">"उघडा"</string>
+    <string name="desc_password" msgid="6636473611443746739">"पासवर्ड फील्ड"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"पासवर्ड चुकीचा आहे"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"पासवर्ड चुकीचा आहे"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"<xliff:g id="TOTAL">%2$d</xliff:g> पैकी पेज <xliff:g id="PAGE">%1$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"<xliff:g id="FIRST">%1$d</xliff:g> टक्के झूम करा"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"पेज <xliff:g id="PAGE_NUMBER">%1$d</xliff:g> वर जा"</string>
     <string name="desc_page" msgid="5684226167093594168">"पेज <xliff:g id="PAGE">%1$d</xliff:g>"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"तुमच्या टिप्पणी ठेवण्यासाठी मजकूर निवडा"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"टिप्पणी करायच्या क्षेत्रावर टॅप करा"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"रद्द करा"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"PDF दाखवू शकत नाही (<xliff:g id="TITLE">%1$s</xliff:g> चा फॉरमॅट चुकीचा आहे)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"<xliff:g id="PAGE">%1$d</xliff:g> पेज दाखवू शकत नाही (फाइल एरर)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"या आयटमसाठी भाष्य मोड लोड करू शकत नाही."</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"लिंक: <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g> वरील वेबपेज"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"लिंक: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"ईमेल: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"फोन: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"निवडणे सुरू करा"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"निवडणे संपवा"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-my/strings.xml b/pdf/pdf-viewer/src/main/res/values-my/strings.xml
index dbeac1d..085401d 100644
--- a/pdf/pdf-viewer/src/main/res/values-my/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-my/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"ဖိုင်အမျိုးအစား"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"ဤဖိုင်ကို ကာကွယ်ထားသည်"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"စကားဝှက်"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"စကားဝှက် မှားနေသည်"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"မလုပ်တော့"</string>
+    <string name="button_open" msgid="5445014062438566842">"ဖွင့်ရန်"</string>
+    <string name="desc_password" msgid="6636473611443746739">"စကားဝှက်ထည့်ရန် အကွက်"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"စကားဝှက် မှားနေသည်"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"စကားဝှက် မှားနေသည်"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"စာမျက်နှာ <xliff:g id="TOTAL">%2$d</xliff:g> အနက် <xliff:g id="PAGE">%1$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"ဇူးမ် <xliff:g id="FIRST">%1$d</xliff:g> ရာခိုင်နှုန်း"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"စာမျက်နှာ <xliff:g id="PAGE_NUMBER">%1$d</xliff:g> သို့"</string>
     <string name="desc_page" msgid="5684226167093594168">"စာမျက်နှာ <xliff:g id="PAGE">%1$d</xliff:g>"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"သင်၏မှတ်ချက်ထည့်ရန် စာသားကို ရွေးပါ"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"မှတ်ချက်ပေးရန် နေရာကို တို့ပါ"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"မလုပ်တော့"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"PDF ကို ပြ၍မရပါ (<xliff:g id="TITLE">%1$s</xliff:g> သည် မမှန်ကန်သော ဖော်မက်ဖြစ်သည်)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"စာမျက်နှာ <xliff:g id="PAGE">%1$d</xliff:g> ကို ပြ၍မရပါ (ဖိုင်အမှား)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"ဤအကြောင်းအရာအတွက် မှတ်ချက်မုဒ် ဖွင့်၍မရပါ။"</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"လင့်ခ်- <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g> ရှိ ဝဘ်စာမျက်နှာ"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"လင့်ခ်- <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"အီးမေးလ်- <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"ဖုန်း- <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"ရွေးချယ်မှုအစ"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"ရွေးချယ်မှုအဆုံး"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-nb/strings.xml b/pdf/pdf-viewer/src/main/res/values-nb/strings.xml
index 189acf8..c1c2c18 100644
--- a/pdf/pdf-viewer/src/main/res/values-nb/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-nb/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"Filtype"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"Denne filen er beskyttet"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"Passord"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"Passordet er feil"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"Avbryt"</string>
+    <string name="button_open" msgid="5445014062438566842">"Åpne"</string>
+    <string name="desc_password" msgid="6636473611443746739">"passordfelt"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"feil passord"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"feil passord"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"side <xliff:g id="PAGE">%1$d</xliff:g> av <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"zoom <xliff:g id="FIRST">%1$d</xliff:g> prosent"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"Gå til side <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
     <string name="desc_page" msgid="5684226167093594168">"side <xliff:g id="PAGE">%1$d</xliff:g>"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"Merk tekst for å sette inn kommentaren din"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"Trykk på et område du vil kommentere"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"Avbryt"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"Kan ikke vise PDF-filen (<xliff:g id="TITLE">%1$s</xliff:g> har ugyldig format)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"Kan ikke vise side <xliff:g id="PAGE">%1$d</xliff:g> (filfeil)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Kan ikke laste inn annoteringsmodus for dette elementet."</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Link: nettside på <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"Link: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"E-postadresse: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"Telefonnummer: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"starten av utvalget"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"slutten av utvalget"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-nl/strings.xml b/pdf/pdf-viewer/src/main/res/values-nl/strings.xml
index caadce5..cf1802a 100644
--- a/pdf/pdf-viewer/src/main/res/values-nl/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-nl/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"Bestandstype"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"Dit bestand is beveiligd"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"Wachtwoord"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"Wachtwoord is onjuist"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"Annuleren"</string>
+    <string name="button_open" msgid="5445014062438566842">"Openen"</string>
+    <string name="desc_password" msgid="6636473611443746739">"wachtwoordveld"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"wachtwoord is onjuist"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"wachtwoord is onjuist"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"pagina <xliff:g id="PAGE">%1$d</xliff:g> van <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"zoom <xliff:g id="FIRST">%1$d</xliff:g> procent"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"Ga naar pagina <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
     <string name="desc_page" msgid="5684226167093594168">"pagina <xliff:g id="PAGE">%1$d</xliff:g>"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"Selecteer tekst om je reactie te plaatsen"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"Tik op een gedeelte waarop je wilt reageren"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"Annuleren"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"Kan pdf niet weergeven (indeling van <xliff:g id="TITLE">%1$s</xliff:g> is ongeldig)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"Kan pagina <xliff:g id="PAGE">%1$d</xliff:g> niet weergeven (bestandsfout)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Kan de annotatiemodus voor dit item niet laden."</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Link: webpagina op <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"Link: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"E-mail: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"Telefoonnummer: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"begin selectie"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"einde selectie"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-pa/strings.xml b/pdf/pdf-viewer/src/main/res/values-pa/strings.xml
index 7579ef3..284fce6 100644
--- a/pdf/pdf-viewer/src/main/res/values-pa/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-pa/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"ਫ਼ਾਈਲ ਦੀ ਕਿਸਮ"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"ਇਹ ਫ਼ਾਈਲ ਸੁਰੱਖਿਅਤ ਹੈ"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"ਪਾਸਵਰਡ"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"ਪਾਸਵਰਡ ਗਲਤ ਹੈ"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"ਰੱਦ ਕਰੋ"</string>
+    <string name="button_open" msgid="5445014062438566842">"ਖੋਲ੍ਹੋ"</string>
+    <string name="desc_password" msgid="6636473611443746739">"ਪਾਸਵਰਡ ਖੇਤਰ"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"ਪਾਸਵਰਡ ਗਲਤ ਹੈ"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"ਪਾਸਵਰਡ ਗਲਤ ਹੈ"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"<xliff:g id="TOTAL">%2$d</xliff:g> ਵਿੱਚੋਂ <xliff:g id="PAGE">%1$d</xliff:g> ਪੰਨਾ"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"ਜ਼ੂਮ <xliff:g id="FIRST">%1$d</xliff:g> ਫ਼ੀਸਦ"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"<xliff:g id="PAGE_NUMBER">%1$d</xliff:g> ਪੰਨੇ \'ਤੇ ਜਾਓ"</string>
     <string name="desc_page" msgid="5684226167093594168">"ਪੰਨਾ <xliff:g id="PAGE">%1$d</xliff:g>"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"ਆਪਣੀ ਟਿੱਪਣੀ ਕਰਨ ਲਈ ਲਿਖਤ ਨੂੰ ਚੁਣੋ"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"ਟਿੱਪਣੀ ਕਰਨ ਲਈ ਕਿਸੇ ਖੇਤਰ \'ਤੇ ਟੈਪ ਕਰੋ"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"ਰੱਦ ਕਰੋ"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"PDF ਨੂੰ ਦਿਖਾਇਆ ਨਹੀਂ ਜਾ ਸਕਦਾ (<xliff:g id="TITLE">%1$s</xliff:g> ਅਵੈਧ ਫਾਰਮੈਟ ਦਾ ਹੈ)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"<xliff:g id="PAGE">%1$d</xliff:g> ਪੰਨੇ ਨੂੰ ਦਿਖਾਇਆ ਨਹੀਂ ਜਾ ਸਕਦਾ (ਫ਼ਾਈਲ ਗੜਬੜ)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"ਇਸ ਆਈਟਮ ਲਈ ਐਨੋਟੇਸ਼ਨ ਮੋਡ ਨੂੰ ਲੋਡ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ।"</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"ਲਿੰਕ: ਵੈੱਬ-ਪੰਨਾ <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g> \'ਤੇ ਹੈ"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"ਲਿੰਕ: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"ਈਮੇਲ: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"ਫ਼ੋਨ ਨੰਬਰ: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"ਚੁਣੀ ਲਿਖਤ ਦਾ ਸ਼ੁਰੂਆਤੀ ਸਿਰਾ"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"ਚੁਣੀ ਲਿਖਤ ਦਾ ਆਖਰੀ ਸਿਰਾ"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-pt-rBR/strings.xml b/pdf/pdf-viewer/src/main/res/values-pt-rBR/strings.xml
index 42e6c8c..439ec80 100644
--- a/pdf/pdf-viewer/src/main/res/values-pt-rBR/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-pt-rBR/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"Tipo de arquivo"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"Este arquivo está protegido"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"Senha"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"Senha incorreta"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"Cancelar"</string>
+    <string name="button_open" msgid="5445014062438566842">"Abrir"</string>
+    <string name="desc_password" msgid="6636473611443746739">"campo senha"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"senha incorreta"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"senha incorreta"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"página <xliff:g id="PAGE">%1$d</xliff:g> de <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"zoom de <xliff:g id="FIRST">%1$d</xliff:g>%%"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"Ir para a página <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
     <string name="desc_page" msgid="5684226167093594168">"página <xliff:g id="PAGE">%1$d</xliff:g>"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"Selecione o texto para inserir seu comentário"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"Toque em uma área para comentar"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"Cancelar"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"Não é possível mostrar o PDF (<xliff:g id="TITLE">%1$s</xliff:g>: formato inválido)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"Não é possível mostrar a página <xliff:g id="PAGE">%1$d</xliff:g> (erro de arquivo)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Não foi possível carregar o modo de anotação deste item."</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Link: página da Web de <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"Link: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"E-mail: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"Telefone: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"início da seleção"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"fim da seleção"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g> a <xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-pt/strings.xml b/pdf/pdf-viewer/src/main/res/values-pt/strings.xml
index 42e6c8c..439ec80 100644
--- a/pdf/pdf-viewer/src/main/res/values-pt/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-pt/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"Tipo de arquivo"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"Este arquivo está protegido"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"Senha"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"Senha incorreta"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"Cancelar"</string>
+    <string name="button_open" msgid="5445014062438566842">"Abrir"</string>
+    <string name="desc_password" msgid="6636473611443746739">"campo senha"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"senha incorreta"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"senha incorreta"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"página <xliff:g id="PAGE">%1$d</xliff:g> de <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"zoom de <xliff:g id="FIRST">%1$d</xliff:g>%%"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"Ir para a página <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
     <string name="desc_page" msgid="5684226167093594168">"página <xliff:g id="PAGE">%1$d</xliff:g>"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"Selecione o texto para inserir seu comentário"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"Toque em uma área para comentar"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"Cancelar"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"Não é possível mostrar o PDF (<xliff:g id="TITLE">%1$s</xliff:g>: formato inválido)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"Não é possível mostrar a página <xliff:g id="PAGE">%1$d</xliff:g> (erro de arquivo)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Não foi possível carregar o modo de anotação deste item."</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Link: página da Web de <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"Link: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"E-mail: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"Telefone: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"início da seleção"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"fim da seleção"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g> a <xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-ro/strings.xml b/pdf/pdf-viewer/src/main/res/values-ro/strings.xml
index 25f3894..ca17732 100644
--- a/pdf/pdf-viewer/src/main/res/values-ro/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ro/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"Tip de fișier"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"Acest fișier este protejat"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"Parolă"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"Parolă incorectă"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"Anulează"</string>
+    <string name="button_open" msgid="5445014062438566842">"Deschide"</string>
+    <string name="desc_password" msgid="6636473611443746739">"câmpul pentru parolă"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"parolă incorectă"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"parolă incorectă"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"pagina <xliff:g id="PAGE">%1$d</xliff:g> din <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"zoom de <xliff:g id="FIRST">%1$d</xliff:g> %%"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"Accesează pagina <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
     <string name="desc_page" msgid="5684226167093594168">"pagina <xliff:g id="PAGE">%1$d</xliff:g>"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"Selectează textul pentru a comenta"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"Atinge o zonă pentru a comenta"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"Anulează"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"Nu se poate afișa ca PDF (<xliff:g id="TITLE">%1$s</xliff:g> are un format nevalid)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"Nu se poate afișa pagina <xliff:g id="PAGE">%1$d</xliff:g> (eroare de fișier)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Nu se poate încărca modul de adnotare pentru acest element."</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Link: pagina web de la <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"Link: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"E-mail: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"Telefon: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"începutul selecției"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"sfârșitul selecției"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-si/strings.xml b/pdf/pdf-viewer/src/main/res/values-si/strings.xml
index 79a1229..23cd51b 100644
--- a/pdf/pdf-viewer/src/main/res/values-si/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-si/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"ගොනු වර්ගය"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"මෙම ගොනුව ආරක්ෂා කර ඇත"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"මුරපදය"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"මුරපදය වැරදියි"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"අවලංගු කරන්න"</string>
+    <string name="button_open" msgid="5445014062438566842">"විවෘත කරන්න"</string>
+    <string name="desc_password" msgid="6636473611443746739">"මුරපද ක්ෂේත්‍රය"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"මුරපදය වැරදියි"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"මුරපදය වැරදියි"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"<xliff:g id="TOTAL">%2$d</xliff:g> න් <xliff:g id="PAGE">%1$d</xliff:g> වෙනි පිටුව"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"විශාලනය සියයට <xliff:g id="FIRST">%1$d</xliff:g>"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"<xliff:g id="PAGE_NUMBER">%1$d</xliff:g> වෙනි පිටුවට යන්න"</string>
     <string name="desc_page" msgid="5684226167093594168">"පිටුව <xliff:g id="PAGE">%1$d</xliff:g>"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"ඔබේ අදහස තැබීමට පෙළ තෝරන්න"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"අදහස් දැක්වීමට ප්‍රදේශයක් තට්ටු කරන්න"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"අවලංගු කරන්න"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"PDF සංදර්ශනය කළ නොහැක (<xliff:g id="TITLE">%1$s</xliff:g> අවලංගු ආකෘතියකි)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"පිටුව සංදර්ශනය කළ නොහැක <xliff:g id="PAGE">%1$d</xliff:g> (ගොනු දෝෂය)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"මෙම අයිතමය සඳහා අනුසටහන් ප්‍රකාරය පූරණය කළ නොහැක."</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"සබැඳිය: <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g> හි දී වෙබ් පිටුව"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"සබැඳිය: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"ඉ-තැපෑල: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"දුරකථනය: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"තේරීම ආරම්භය"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"තේරීම අවසානය"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-sq/strings.xml b/pdf/pdf-viewer/src/main/res/values-sq/strings.xml
index b478e0c..caebc77 100644
--- a/pdf/pdf-viewer/src/main/res/values-sq/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-sq/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"Lloji i skedarit"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"Ky skedar është i mbrojtur."</string>
+    <string name="label_password_first" msgid="4456258714097111908">"Fjalëkalimi"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"Fjalëkalimi është i pasaktë"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"Anulo"</string>
+    <string name="button_open" msgid="5445014062438566842">"Hap"</string>
+    <string name="desc_password" msgid="6636473611443746739">"fusha e fjalëkalimit"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"fjalëkalimi është i pasaktë"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"fjalëkalimi është i pasaktë"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"faqja <xliff:g id="PAGE">%1$d</xliff:g> nga <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"zmadho me <xliff:g id="FIRST">%1$d</xliff:g> për qind"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"Shko te faqja <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
     <string name="desc_page" msgid="5684226167093594168">"faqja <xliff:g id="PAGE">%1$d</xliff:g>"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"Zgjidh tekstin për të vendosur komentin"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"Trokit te një zonë për të komentuar"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"Anulo"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"Skedari PDF nuk mund të shfaqet (\"<xliff:g id="TITLE">%1$s</xliff:g>\" ka format të pavlefshëm)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"Nuk mund të shfaqet faqja <xliff:g id="PAGE">%1$d</xliff:g> (gabim i skedarit)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Modaliteti i shënimit nuk mund të ngarkohet për këtë artikull."</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Lidhja: faqe uebi te <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"Lidhja: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"Email-i: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"Telefoni: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"fillimi i përzgjedhjes"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"fundi i përzgjedhjes"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-sv/strings.xml b/pdf/pdf-viewer/src/main/res/values-sv/strings.xml
index 925f7d9..99b7d55 100644
--- a/pdf/pdf-viewer/src/main/res/values-sv/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-sv/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"Filtyp"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"Den här filen är skyddad"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"Lösenord"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"Felaktigt lösenord"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"Avbryt"</string>
+    <string name="button_open" msgid="5445014062438566842">"Öppna"</string>
+    <string name="desc_password" msgid="6636473611443746739">"lösenordsfält"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"felaktigt lösenord"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"felaktigt lösenord"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"sida <xliff:g id="PAGE">%1$d</xliff:g> av <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"zooma <xliff:g id="FIRST">%1$d</xliff:g> procent"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"Öppna sidan <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
     <string name="desc_page" msgid="5684226167093594168">"sida <xliff:g id="PAGE">%1$d</xliff:g>"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"Markera text för att kommentera"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"Tryck på ett område för att kommentera"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"Avbryt"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"Det går inte att visa PDF-filen (<xliff:g id="TITLE">%1$s</xliff:g> har ett ogiltigt format)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"Det går inte att visa sidan <xliff:g id="PAGE">%1$d</xliff:g> (filfel)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Det gick inte att läsa in kommentarsläget för det här objektet."</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Länk: webbsida på <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"Länk: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"E-postadress: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"Telefonnummer: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"textmarkeringens början"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"textmarkeringens slut"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-ta/strings.xml b/pdf/pdf-viewer/src/main/res/values-ta/strings.xml
index c2f1606..63788a8 100644
--- a/pdf/pdf-viewer/src/main/res/values-ta/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ta/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"ஃபைல் வகை"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"இந்த ஃபைல் பாதுகாக்கப்பட்டுள்ளது"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"கடவுச்சொல்"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"கடவுச்சொல் தவறானது"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"ரத்துசெய்"</string>
+    <string name="button_open" msgid="5445014062438566842">"திற"</string>
+    <string name="desc_password" msgid="6636473611443746739">"கடவுச்சொல் புலம்"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"கடவுச்சொல் தவறானது"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"கடவுச்சொல் தவறானது"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"பக்கம் <xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"<xliff:g id="FIRST">%1$d</xliff:g> சதவீத அளவை மாற்று"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"பக்கம் <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>க்கு செல்லும்"</string>
     <string name="desc_page" msgid="5684226167093594168">"பக்கம் <xliff:g id="PAGE">%1$d</xliff:g>"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"கருத்து வழங்க வார்த்தையைத் தேர்ந்தெடுக்கவும்"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"கருத்து வழங்குவதற்கான பகுதியைத் தட்டவும்"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"ரத்துசெய்"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"PDFஐக் காட்ட முடியவில்லை (<xliff:g id="TITLE">%1$s</xliff:g> தவறான வடிவத்தில் உள்ளது)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"பக்கம் <xliff:g id="PAGE">%1$d</xliff:g>ஐக் காட்ட முடியவில்லை (ஃபைல் பிழை)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"இதற்கான விரிவுரைப் பயன்முறையை ஏற்ற முடியவில்லை."</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"இணைப்பு: <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g> இல் உள்ள இணையப் பக்கம்"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"இணைப்பு: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"மின்னஞ்சல்: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"ஃபோன் எண்: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"தேர்வுசெய்த வார்த்தையின் தொடக்கம்"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"தேர்வுசெய்த வார்த்தையின் முடிவு"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-tr/strings.xml b/pdf/pdf-viewer/src/main/res/values-tr/strings.xml
index e789a8a..db0c86c7 100644
--- a/pdf/pdf-viewer/src/main/res/values-tr/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-tr/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"Dosya türü"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"Bu dosya korunuyor"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"Şifre"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"Şifre yanlış"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"İptal"</string>
+    <string name="button_open" msgid="5445014062438566842">"Aç"</string>
+    <string name="desc_password" msgid="6636473611443746739">"şifre alanı"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"şifre yanlış"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"şifre yanlış"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"sayfa <xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"yakınlaştırma yüzdesi <xliff:g id="FIRST">%1$d</xliff:g>"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"Şu sayfaya git <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
     <string name="desc_page" msgid="5684226167093594168">"sayfa <xliff:g id="PAGE">%1$d</xliff:g>"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"Yorumunuzu yerleştireceğiniz metni seçin"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"Hakkında yorum yapacağınız alana dokunun"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"İptal"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"PDF görüntülenemiyor (<xliff:g id="TITLE">%1$s</xliff:g> geçersiz biçimde)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"<xliff:g id="PAGE">%1$d</xliff:g>. sayfa görüntülenemiyor (dosya hatası)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Bu öğe için ek açıklama modu yüklenemiyor."</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Bağlantı: <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g> alan adındaki web sayfası"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"Bağlantı: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"E-posta gönder: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"Telefon: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"seçim başlangıcı"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"seçim sonu"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-uk/strings.xml b/pdf/pdf-viewer/src/main/res/values-uk/strings.xml
index de608a9..216d16c 100644
--- a/pdf/pdf-viewer/src/main/res/values-uk/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-uk/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"Тип файлу"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"Цей файл захищено"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"Пароль"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"Неправильний пароль"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"Скасувати"</string>
+    <string name="button_open" msgid="5445014062438566842">"Відкрити"</string>
+    <string name="desc_password" msgid="6636473611443746739">"поле пароля"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"неправильний пароль"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"неправильний пароль"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"сторінка <xliff:g id="PAGE">%1$d</xliff:g> з <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"масштаб <xliff:g id="FIRST">%1$d</xliff:g>%%"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"Перейти на сторінку <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
     <string name="desc_page" msgid="5684226167093594168">"сторінка <xliff:g id="PAGE">%1$d</xliff:g>"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"Виділіть текст, щоб додати коментар"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"Торкніться місця, яке хочете коментувати"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"Скасувати"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"Не вдається відобразити PDF (недійсний формат файлу \"<xliff:g id="TITLE">%1$s</xliff:g>\")"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"Не вдається відобразити сторінку <xliff:g id="PAGE">%1$d</xliff:g> (помилка файлу)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Не вдається завантажити режим анотацій для цього об’єкта."</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Посилання: вебсторінка в домені <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"Посилання: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"Електронна адреса: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"Номер телефону: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"початок виділеного тексту"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"кінець виділеного тексту"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-uz/strings.xml b/pdf/pdf-viewer/src/main/res/values-uz/strings.xml
index 7ac1e17..2a6902f 100644
--- a/pdf/pdf-viewer/src/main/res/values-uz/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-uz/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"Fayl turi"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"Ushbu fayl himoyalangan"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"Parol"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"Parol xato"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"Bekor qilish"</string>
+    <string name="button_open" msgid="5445014062438566842">"Ochish"</string>
+    <string name="desc_password" msgid="6636473611443746739">"parol maydonchasi"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"parol xato"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"parol xato"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"sahifa: <xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"zum: <xliff:g id="FIRST">%1$d</xliff:g> foiz"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"<xliff:g id="PAGE_NUMBER">%1$d</xliff:g>-sahifaga oʻtish"</string>
     <string name="desc_page" msgid="5684226167093594168">"sahifa: <xliff:g id="PAGE">%1$d</xliff:g>"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"Fikr bildirish uchun matnni tanlang."</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"Fikr qoʻshish uchun biror maydonni bosing"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"Bekor qilish"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"PDF fayl koʻrsatilmaydi (<xliff:g id="TITLE">%1$s</xliff:g> yaroqsiz formatda)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"<xliff:g id="PAGE">%1$d</xliff:g>-sahifa koʻrsatilmaydi (fayl xatosi)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Bu obyekt uchun izoh rejimi yuklanmadi."</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Havola: <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g> sahifasi"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"Havola: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"Email: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"Telefon: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"belgilashni boshlash"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"belgilashni yakunlash"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-vi/strings.xml b/pdf/pdf-viewer/src/main/res/values-vi/strings.xml
index 463515d..0f5033a 100644
--- a/pdf/pdf-viewer/src/main/res/values-vi/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-vi/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"Loại tệp"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"Tệp này đang được bảo vệ"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"Mật khẩu"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"Mật khẩu không chính xác"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"Huỷ"</string>
+    <string name="button_open" msgid="5445014062438566842">"Mở"</string>
+    <string name="desc_password" msgid="6636473611443746739">"trường nhập mật khẩu"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"mật khẩu không chính xác"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"mật khẩu không chính xác"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"trang <xliff:g id="PAGE">%1$d</xliff:g> trong số <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"thu phóng <xliff:g id="FIRST">%1$d</xliff:g> phần trăm"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"Chuyển đến trang <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
     <string name="desc_page" msgid="5684226167093594168">"trang <xliff:g id="PAGE">%1$d</xliff:g>"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"Chọn văn bản để đưa ra nhận xét"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"Nhấn vào một khu vực để thêm nhận xét"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"Huỷ"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"Không hiển thị được tệp PDF (<xliff:g id="TITLE">%1$s</xliff:g> có định dạng không hợp lệ)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"Không hiển thị được trang <xliff:g id="PAGE">%1$d</xliff:g> (lỗi tệp)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Không tải được chế độ chú giải cho mục này."</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Đường liên kết: trang trên trang web <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"Đường liên kết: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"Email: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"Số điện thoại: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"đầu văn bản đã chọn"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"cuối văn bản đã chọn"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g> – <xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-zh-rCN/strings.xml b/pdf/pdf-viewer/src/main/res/values-zh-rCN/strings.xml
index 57799bb..3094e5c 100644
--- a/pdf/pdf-viewer/src/main/res/values-zh-rCN/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-zh-rCN/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"文件类型"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"此文件受密码保护"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"密码"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"密码不正确"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"取消"</string>
+    <string name="button_open" msgid="5445014062438566842">"打开"</string>
+    <string name="desc_password" msgid="6636473611443746739">"密码字段"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"密码不正确"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"密码不正确"</string>
     <string name="label_page_single" msgid="456123685879261101">"第 <xliff:g id="PAGE">%1$d</xliff:g> 页,共 <xliff:g id="TOTAL">%2$d</xliff:g> 页"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"第 <xliff:g id="PAGE">%1$d</xliff:g> 页,共 <xliff:g id="TOTAL">%2$d</xliff:g> 页"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"缩放比例为百分之 <xliff:g id="FIRST">%1$d</xliff:g>"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"前往第 <xliff:g id="PAGE_NUMBER">%1$d</xliff:g> 页"</string>
     <string name="desc_page" msgid="5684226167093594168">"第 <xliff:g id="PAGE">%1$d</xliff:g> 页"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"选择要添加评论的文本"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"点按要添加评论的区域"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"取消"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"无法显示 PDF(“<xliff:g id="TITLE">%1$s</xliff:g>”的格式无效)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"无法显示第 <xliff:g id="PAGE">%1$d</xliff:g> 页(文件错误)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"无法为此内容加载注解模式。"</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"链接:位于 <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g> 的网页"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"链接:<xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"电子邮件地址:<xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"电话号码:<xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"所选文本的开头"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"所选文本的结尾"</string>
     <string name="label_page_range" msgid="8290964180158460076">"第 <xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> 页,共 <xliff:g id="TOTAL">%3$d</xliff:g> 页"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-zh-rHK/strings.xml b/pdf/pdf-viewer/src/main/res/values-zh-rHK/strings.xml
index 0711b16..34b36c0 100644
--- a/pdf/pdf-viewer/src/main/res/values-zh-rHK/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-zh-rHK/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"檔案類型"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"此檔案受到保護"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"密碼"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"密碼不正確"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"取消"</string>
+    <string name="button_open" msgid="5445014062438566842">"開啟"</string>
+    <string name="desc_password" msgid="6636473611443746739">"密碼欄位"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"密碼不正確"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"密碼不正確"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"第 <xliff:g id="PAGE">%1$d</xliff:g> 頁,共 <xliff:g id="TOTAL">%2$d</xliff:g> 頁"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"縮放 <xliff:g id="FIRST">%1$d</xliff:g>%%"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"前往第 <xliff:g id="PAGE_NUMBER">%1$d</xliff:g> 頁"</string>
     <string name="desc_page" msgid="5684226167093594168">"第 <xliff:g id="PAGE">%1$d</xliff:g> 頁"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"選取文字以加入留言"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"輕按要加入留言的區域"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"取消"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"無法顯示 PDF (<xliff:g id="TITLE">%1$s</xliff:g> 格式無效)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"無法顯示第 <xliff:g id="PAGE">%1$d</xliff:g> 頁 (檔案錯誤)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"無法為此項目載入註釋模式。"</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"連結:位於 <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g> 的網頁"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"連結:<xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"電郵地址:<xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"電話:<xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"選取開頭"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"選取結尾"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g> - <xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-zh-rTW/strings.xml b/pdf/pdf-viewer/src/main/res/values-zh-rTW/strings.xml
index 1f08710..f836592 100644
--- a/pdf/pdf-viewer/src/main/res/values-zh-rTW/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-zh-rTW/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"檔案類型"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"這個檔案受密碼保護"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"密碼"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"密碼不正確"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"取消"</string>
+    <string name="button_open" msgid="5445014062438566842">"開啟"</string>
+    <string name="desc_password" msgid="6636473611443746739">"密碼欄位"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"密碼不正確"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"密碼不正確"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"第 <xliff:g id="PAGE">%1$d</xliff:g> 頁,共 <xliff:g id="TOTAL">%2$d</xliff:g> 頁"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"縮放 <xliff:g id="FIRST">%1$d</xliff:g>%%"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"前往第 <xliff:g id="PAGE_NUMBER">%1$d</xliff:g> 頁"</string>
     <string name="desc_page" msgid="5684226167093594168">"第 <xliff:g id="PAGE">%1$d</xliff:g> 頁"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"選取要加註的文字"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"輕觸要加註的區域"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"取消"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"無法顯示 PDF (「<xliff:g id="TITLE">%1$s</xliff:g>」的格式無效)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"無法顯示第 <xliff:g id="PAGE">%1$d</xliff:g> 頁 (檔案錯誤)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"無法載入這個項目的註解模式。"</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"連結:位於 <xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g> 的網頁"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"連結:<xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"電子郵件地址:<xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"電話號碼:<xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"選取開頭"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"選取結尾"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g> - <xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-zu/strings.xml b/pdf/pdf-viewer/src/main/res/values-zu/strings.xml
index 11347a3..103f045 100644
--- a/pdf/pdf-viewer/src/main/res/values-zu/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-zu/strings.xml
@@ -18,48 +18,29 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="desc_file_type" msgid="8918077960128045611">"Uhlobo lwefayela"</string>
-    <!-- no translation found for title_dialog_password (2018068413709926925) -->
-    <skip />
-    <!-- no translation found for label_password_first (4456258714097111908) -->
-    <skip />
-    <!-- no translation found for label_password_incorrect (8449142641187704667) -->
-    <skip />
-    <!-- no translation found for button_cancel (5855794576957267334) -->
-    <skip />
-    <!-- no translation found for button_open (5445014062438566842) -->
-    <skip />
-    <!-- no translation found for desc_password (6636473611443746739) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect (4718823067483963845) -->
-    <skip />
-    <!-- no translation found for desc_password_incorrect_message (4849541619951023025) -->
-    <skip />
+    <string name="title_dialog_password" msgid="2018068413709926925">"Leli fayela livikelwe"</string>
+    <string name="label_password_first" msgid="4456258714097111908">"Iphasiwedi"</string>
+    <string name="label_password_incorrect" msgid="8449142641187704667">"Iphasiwedi ayilungile"</string>
+    <string name="button_cancel" msgid="5855794576957267334">"Khansela"</string>
+    <string name="button_open" msgid="5445014062438566842">"Vula"</string>
+    <string name="desc_password" msgid="6636473611443746739">"inkambu yephasiwedi"</string>
+    <string name="desc_password_incorrect" msgid="4718823067483963845">"iphasiwedi ayilungile"</string>
+    <string name="desc_password_incorrect_message" msgid="4849541619951023025">"iphasiwedi ayilungile"</string>
     <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"ikhasi <xliff:g id="PAGE">%1$d</xliff:g> kwangu-<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"sondeza iphesenti elingu-<xliff:g id="FIRST">%1$d</xliff:g>"</string>
-    <!-- no translation found for desc_goto_link (2461368384824849714) -->
-    <skip />
+    <string name="desc_goto_link" msgid="2461368384824849714">"Iya ekhasini <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
     <string name="desc_page" msgid="5684226167093594168">"ikhasi <xliff:g id="PAGE">%1$d</xliff:g>"</string>
-    <!-- no translation found for message_select_text_to_comment (5725327644007067522) -->
-    <skip />
-    <!-- no translation found for message_tap_to_comment (7820801719181709999) -->
-    <skip />
-    <!-- no translation found for action_cancel (5494417739210197522) -->
-    <skip />
-    <!-- no translation found for error_file_format_pdf (7567006188638831878) -->
-    <skip />
-    <!-- no translation found for error_on_page (1592475819957182385) -->
-    <skip />
-    <!-- no translation found for annotation_mode_failed_to_open (1659648756255912463) -->
-    <skip />
-    <!-- no translation found for desc_web_link_shortened_to_domain (3323639528531061592) -->
-    <skip />
-    <!-- no translation found for desc_web_link (2776023299237058419) -->
-    <skip />
-    <!-- no translation found for desc_email_link (7027325672358507448) -->
-    <skip />
-    <!-- no translation found for desc_phone_link (4986414958429253135) -->
-    <skip />
+    <string name="message_select_text_to_comment" msgid="5725327644007067522">"Khetha umbhalo ukuze ubeke amazwana akho"</string>
+    <string name="message_tap_to_comment" msgid="7820801719181709999">"Thepha indawo ukuze ubeke amazwana kuyo"</string>
+    <string name="action_cancel" msgid="5494417739210197522">"Khansela"</string>
+    <string name="error_file_format_pdf" msgid="7567006188638831878">"Ayikwazi ukubonisa i-PDF (i-<xliff:g id="TITLE">%1$s</xliff:g> ingeyefomethi engavumelekile)"</string>
+    <string name="error_on_page" msgid="1592475819957182385">"Ayikwazi ukubonisa ikhasi elingu-<xliff:g id="PAGE">%1$d</xliff:g> (iphutha lefayela)"</string>
+    <string name="annotation_mode_failed_to_open" msgid="1659648756255912463">"Ayikwazi ukulayisha imodi yesichasiselo yale nto."</string>
+    <string name="desc_web_link_shortened_to_domain" msgid="3323639528531061592">"Ilinki: ikhasi lewebhu ku-<xliff:g id="DESTINATION_DOMAIN">%1$s</xliff:g>"</string>
+    <string name="desc_web_link" msgid="2776023299237058419">"Ilinki: <xliff:g id="DESTINATION">%1$s</xliff:g>"</string>
+    <string name="desc_email_link" msgid="7027325672358507448">"I-imeyili: <xliff:g id="EMAIL_ADDRESS">%1$s</xliff:g>"</string>
+    <string name="desc_phone_link" msgid="4986414958429253135">"Ifoni: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"isiqalo sokukhetha"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"isiphetho sokukhetha"</string>
     <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
diff --git a/playground-common/androidx-shared.properties b/playground-common/androidx-shared.properties
index 83e5c69..63f5783 100644
--- a/playground-common/androidx-shared.properties
+++ b/playground-common/androidx-shared.properties
@@ -47,7 +47,7 @@
 # Generate versioned API files
 androidx.writeVersionedApiFiles=true
 
-androidx.compileSdkVersion=android-34
+androidx.compileSdk=34
 androidx.targetSdkVersion=34
 
 # Disable features we do not use
diff --git a/playground-common/playground-plugin/src/main/kotlin/androidx/playground/PlaygroundExtension.kt b/playground-common/playground-plugin/src/main/kotlin/androidx/playground/PlaygroundExtension.kt
index 9c8e31f..51bf914 100644
--- a/playground-common/playground-plugin/src/main/kotlin/androidx/playground/PlaygroundExtension.kt
+++ b/playground-common/playground-plugin/src/main/kotlin/androidx/playground/PlaygroundExtension.kt
@@ -111,6 +111,7 @@
         val propertiesFile = File(supportRoot, "playground-common/playground.properties")
         playgroundProperties.load(propertiesFile.inputStream())
         settings.gradle.beforeProject { project ->
+            project.extensions.extraProperties["supportRootFolder"] = supportRoot
             // load playground properties. These are not kept in the playground projects to prevent
             // AndroidX build from reading them.
             playgroundProperties.forEach {
diff --git a/privacysandbox/ads/ads-adservices-java/build.gradle b/privacysandbox/ads/ads-adservices-java/build.gradle
index 4ecece0..8548818 100644
--- a/privacysandbox/ads/ads-adservices-java/build.gradle
+++ b/privacysandbox/ads/ads-adservices-java/build.gradle
@@ -64,7 +64,8 @@
         multiDexEnabled = true
     }
 
-    compileSdkVersion = "android-34-ext11"
+    compileSdk = 34
+    compileSdkExtension = 11
     namespace "androidx.privacysandbox.ads.adservices.java"
 }
 
diff --git a/privacysandbox/ads/ads-adservices/build.gradle b/privacysandbox/ads/ads-adservices/build.gradle
index 47b3f47..c18440f 100644
--- a/privacysandbox/ads/ads-adservices/build.gradle
+++ b/privacysandbox/ads/ads-adservices/build.gradle
@@ -58,7 +58,8 @@
         multiDexEnabled = true
     }
 
-    compileSdkVersion = "android-34-ext11"
+    compileSdk = 34
+    compileSdkExtension = 11
     namespace "androidx.privacysandbox.ads.adservices"
 }
 
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/build.gradle b/privacysandbox/sdkruntime/sdkruntime-client/build.gradle
index f8c0828..6464bf3 100644
--- a/privacysandbox/sdkruntime/sdkruntime-client/build.gradle
+++ b/privacysandbox/sdkruntime/sdkruntime-client/build.gradle
@@ -145,7 +145,8 @@
     }
 
     namespace "androidx.privacysandbox.sdkruntime.client"
-    compileSdkVersion = "android-34-ext10"
+    compileSdk = 34
+    compileSdkExtension = 10
 }
 
 androidx {
diff --git a/privacysandbox/sdkruntime/sdkruntime-core/build.gradle b/privacysandbox/sdkruntime/sdkruntime-core/build.gradle
index 353e73e..d1cfc2e 100644
--- a/privacysandbox/sdkruntime/sdkruntime-core/build.gradle
+++ b/privacysandbox/sdkruntime/sdkruntime-core/build.gradle
@@ -56,7 +56,8 @@
     }
 
     namespace "androidx.privacysandbox.sdkruntime.core"
-    compileSdkVersion = "android-34-ext10"
+    compileSdk = 34
+    compileSdkExtension = 10
 }
 
 androidx {
diff --git a/privacysandbox/sdkruntime/sdkruntime-provider/build.gradle b/privacysandbox/sdkruntime/sdkruntime-provider/build.gradle
index d83e35f..67a9568 100644
--- a/privacysandbox/sdkruntime/sdkruntime-provider/build.gradle
+++ b/privacysandbox/sdkruntime/sdkruntime-provider/build.gradle
@@ -44,7 +44,8 @@
 
 android {
     namespace "androidx.privacysandbox.sdkruntime.provider"
-    compileSdkVersion = "android-34-ext10"
+    compileSdk = 34
+    compileSdkExtension = 10
 }
 
 androidx {
diff --git a/privacysandbox/tools/tools-apicompiler/build.gradle b/privacysandbox/tools/tools-apicompiler/build.gradle
index f1f5a3b..ec701e3 100644
--- a/privacysandbox/tools/tools-apicompiler/build.gradle
+++ b/privacysandbox/tools/tools-apicompiler/build.gradle
@@ -58,7 +58,7 @@
 
 // Get AIDL compiler path and framework.aidl path and pass to tests for code generation.
 def aidlCompilerPath = "${SdkHelperKt.getSdkPath(project)}/build-tools/$buildToolsVersion/aidl"
-def frameworkAidlPath = "${SdkHelperKt.getSdkPath(project)}/platforms/$compileSdk/framework.aidl"
+def frameworkAidlPath = "${SdkHelperKt.getSdkPath(project)}/platforms/android-$compileSdk/framework.aidl"
 def testGeneratedSourcesPath = "${project.buildDir}/testGeneratedSources"
 tasks.withType(Test).configureEach { test ->
     test.inputs.files(aidlCompilerPath)
diff --git a/privacysandbox/tools/tools-apigenerator/build.gradle b/privacysandbox/tools/tools-apigenerator/build.gradle
index a6ba53c..b419d0b 100644
--- a/privacysandbox/tools/tools-apigenerator/build.gradle
+++ b/privacysandbox/tools/tools-apigenerator/build.gradle
@@ -28,6 +28,7 @@
 plugins {
     id("AndroidXPlugin")
     id("kotlin")
+    id("com.github.johnrengelman.shadow")
 }
 
 androidx.configureAarAsJarForConfiguration("testImplementation")
@@ -35,11 +36,48 @@
 def buildToolsVersion = AndroidXConfig.getDefaultAndroidConfig(project).getBuildToolsVersion()
 def compileSdk = AndroidXConfig.getDefaultAndroidConfig(project).getCompileSdk()
 
+configurations {
+    // Configuration of shadowed / jarjared dependencies
+    shadowed
+    // Shadowed dependencies are compile only
+    compileOnly.extendsFrom(shadowed)
+    // Include shadowed dependencies for test compilation
+    testCompile.extendsFrom(shadowed)
+
+    // Replace the standard jar with the one built by 'shadowJar' in both api and runtime variants
+    apiElements.outgoing.artifacts.clear()
+    apiElements.outgoing.artifact(shadowJar) {
+        builtBy shadowJar
+    }
+    runtimeElements.outgoing.artifacts.clear()
+    runtimeElements.outgoing.artifact(shadowJar) {
+        builtBy shadowJar
+    }
+}
+
+shadowJar {
+    archiveClassifier = ""
+    configurations = [project.configurations.shadowed]
+    relocate("kotlinx.metadata", "androidx.privacysandbox.tools.kotlinx.metadata")
+    mergeServiceFiles() // kotlinx-metadata-jvm has a service descriptor that needs transformation
+    // Exclude Kotlin metadata files from kotlinx-metadata-jvm
+    exclude 'META-INF/kotlinx-metadata-jvm.kotlin_module'
+    exclude 'META-INF/kotlinx-metadata.kotlin_module'
+    exclude 'META-INF/metadata.jvm.kotlin_module'
+    exclude 'META-INF/metadata.kotlin_module'
+}
+
+jar {
+    archiveClassifier = "before-jarjar"
+}
+
 dependencies {
     api(libs.kotlinStdlib)
     implementation(libs.asm)
     implementation(libs.asmCommons)
-    implementation(libs.kotlinMetadataJvm)
+    shadowed(libs.kotlinMetadataJvm) {
+        exclude group: "org.jetbrains.kotlin", module: "kotlin-stdlib"
+    }
     implementation(libs.kotlinPoet)
     implementation project(path: ':privacysandbox:tools:tools')
     implementation project(path: ':privacysandbox:tools:tools-core')
@@ -55,6 +93,7 @@
     testImplementationAarAsJar(project(":privacysandbox:sdkruntime:sdkruntime-client"))
     testImplementationAarAsJar(project(":privacysandbox:sdkruntime:sdkruntime-core"))
     testImplementation(libs.kotlinCoroutinesCore)
+    testImplementation(libs.kotlinMetadataJvm)
     testImplementation(libs.junit)
     testImplementation(libs.truth)
 
@@ -64,7 +103,7 @@
 
 // Get AIDL compiler path and framework.aidl path and pass to tests for code generation.
 def aidlCompilerPath = "${SdkHelperKt.getSdkPath(project)}/build-tools/$buildToolsVersion/aidl"
-def frameworkAidlPath = "${SdkHelperKt.getSdkPath(project)}/platforms/$compileSdk/framework.aidl"
+def frameworkAidlPath = "${SdkHelperKt.getSdkPath(project)}/platforms/android-$compileSdk/framework.aidl"
 def testGeneratedSourcesPath = "${project.buildDir}/testGeneratedSources"
 tasks.withType(Test).configureEach { test ->
     test.inputs.files(aidlCompilerPath)
diff --git a/privacysandbox/tools/tools-core/build.gradle b/privacysandbox/tools/tools-core/build.gradle
index fbc42d4..666c58e 100644
--- a/privacysandbox/tools/tools-core/build.gradle
+++ b/privacysandbox/tools/tools-core/build.gradle
@@ -53,7 +53,7 @@
 
 // Get AIDL compiler path and framework.aidl path and pass to tests for code generation.
 def aidlCompilerPath = "${SdkHelperKt.getSdkPath(project)}/build-tools/$buildToolsVersion/aidl"
-def frameworkAidlPath = "${SdkHelperKt.getSdkPath(project)}/platforms/$compileSdk/framework.aidl"
+def frameworkAidlPath = "${SdkHelperKt.getSdkPath(project)}/platforms/android-$compileSdk/framework.aidl"
 tasks.withType(Test).configureEach { test ->
     test.inputs.files(aidlCompilerPath)
             .withPropertyName("aidl_compiler_path")
diff --git a/room/integration-tests/incremental-annotation-processing/src/test/kotlin/androidx/room/gradle/RoomIncrementalAnnotationProcessingTest.kt b/room/integration-tests/incremental-annotation-processing/src/test/kotlin/androidx/room/gradle/RoomIncrementalAnnotationProcessingTest.kt
index 603cead..ae26317 100644
--- a/room/integration-tests/incremental-annotation-processing/src/test/kotlin/androidx/room/gradle/RoomIncrementalAnnotationProcessingTest.kt
+++ b/room/integration-tests/incremental-annotation-processing/src/test/kotlin/androidx/room/gradle/RoomIncrementalAnnotationProcessingTest.kt
@@ -161,6 +161,7 @@
             ksp {
                 arg('room.incremental', '$withIncrementalRoom')
                 arg('room.schemaLocation', '${projectRoot.resolve(GEN_RES_DIR).canonicalPath}')
+                arg('room.generateKotlin', 'false')
             }
             """.trimIndent()
         } else {
diff --git a/room/integration-tests/multiplatformtestapp/build.gradle b/room/integration-tests/multiplatformtestapp/build.gradle
index 2ec523d..a10ab82 100644
--- a/room/integration-tests/multiplatformtestapp/build.gradle
+++ b/room/integration-tests/multiplatformtestapp/build.gradle
@@ -129,5 +129,4 @@
     schemaDirectory(
             provider { layout.projectDirectory.dir("schemas-ksp").getAsFile().getAbsolutePath() }
     )
-    generateKotlin = true
 }
diff --git a/room/integration-tests/multiplatformtestapp/schemas-ksp/androidx.room.integration.multiplatformtestapp.test.BaseAutoMigrationTest.AutoMigrationDatabase/3.json b/room/integration-tests/multiplatformtestapp/schemas-ksp/androidx.room.integration.multiplatformtestapp.test.BaseAutoMigrationTest.AutoMigrationDatabase/3.json
new file mode 100644
index 0000000..08c9605
--- /dev/null
+++ b/room/integration-tests/multiplatformtestapp/schemas-ksp/androidx.room.integration.multiplatformtestapp.test.BaseAutoMigrationTest.AutoMigrationDatabase/3.json
@@ -0,0 +1,45 @@
+{
+  "formatVersion": 1,
+  "database": {
+    "version": 3,
+    "identityHash": "a6f449a18d75d8cad5ca340d6f7f30e2",
+    "entities": [
+      {
+        "tableName": "AutoMigrationEntity",
+        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`pk` INTEGER NOT NULL, `data` INTEGER NOT NULL DEFAULT 0, `moreData` TEXT NOT NULL DEFAULT '', PRIMARY KEY(`pk`))",
+        "fields": [
+          {
+            "fieldPath": "pk",
+            "columnName": "pk",
+            "affinity": "INTEGER",
+            "notNull": true
+          },
+          {
+            "fieldPath": "data",
+            "columnName": "data",
+            "affinity": "INTEGER",
+            "notNull": true,
+            "defaultValue": "0"
+          },
+          {
+            "fieldPath": "moreData",
+            "columnName": "moreData",
+            "affinity": "TEXT",
+            "notNull": true,
+            "defaultValue": "''"
+          }
+        ],
+        "primaryKey": {
+          "autoGenerate": false,
+          "columnNames": [
+            "pk"
+          ]
+        }
+      }
+    ],
+    "setupQueries": [
+      "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
+      "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'a6f449a18d75d8cad5ca340d6f7f30e2')"
+    ]
+  }
+}
\ No newline at end of file
diff --git a/room/integration-tests/multiplatformtestapp/schemas-ksp/androidx.room.integration.multiplatformtestapp.test.BaseMigrationTest.MigrationDatabase/1.json b/room/integration-tests/multiplatformtestapp/schemas-ksp/androidx.room.integration.multiplatformtestapp.test.BaseMigrationTest.MigrationDatabase/1.json
new file mode 100644
index 0000000..18dd2b7
--- /dev/null
+++ b/room/integration-tests/multiplatformtestapp/schemas-ksp/androidx.room.integration.multiplatformtestapp.test.BaseMigrationTest.MigrationDatabase/1.json
@@ -0,0 +1,31 @@
+{
+  "formatVersion": 1,
+  "database": {
+    "version": 1,
+    "identityHash": "f530cb775d66c33d8b3cb1abaf2efd74",
+    "entities": [
+      {
+        "tableName": "MigrationEntity",
+        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`pk` INTEGER NOT NULL, PRIMARY KEY(`pk`))",
+        "fields": [
+          {
+            "fieldPath": "pk",
+            "columnName": "pk",
+            "affinity": "INTEGER",
+            "notNull": true
+          }
+        ],
+        "primaryKey": {
+          "autoGenerate": false,
+          "columnNames": [
+            "pk"
+          ]
+        }
+      }
+    ],
+    "setupQueries": [
+      "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
+      "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'f530cb775d66c33d8b3cb1abaf2efd74')"
+    ]
+  }
+}
\ No newline at end of file
diff --git a/room/integration-tests/multiplatformtestapp/schemas-ksp/androidx.room.integration.multiplatformtestapp.test.BaseMigrationTest.MigrationDatabase/2.json b/room/integration-tests/multiplatformtestapp/schemas-ksp/androidx.room.integration.multiplatformtestapp.test.BaseMigrationTest.MigrationDatabase/2.json
new file mode 100644
index 0000000..bc57e8c
--- /dev/null
+++ b/room/integration-tests/multiplatformtestapp/schemas-ksp/androidx.room.integration.multiplatformtestapp.test.BaseMigrationTest.MigrationDatabase/2.json
@@ -0,0 +1,36 @@
+{
+  "formatVersion": 1,
+  "database": {
+    "version": 2,
+    "identityHash": "0062aa551ade7dc88d151a9bd43592c0",
+    "entities": [
+      {
+        "tableName": "MigrationEntity",
+        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`pk` INTEGER NOT NULL, `addedInV2` TEXT, PRIMARY KEY(`pk`))",
+        "fields": [
+          {
+            "fieldPath": "pk",
+            "columnName": "pk",
+            "affinity": "INTEGER",
+            "notNull": true
+          },
+          {
+            "fieldPath": "addedInV2",
+            "columnName": "addedInV2",
+            "affinity": "TEXT"
+          }
+        ],
+        "primaryKey": {
+          "autoGenerate": false,
+          "columnNames": [
+            "pk"
+          ]
+        }
+      }
+    ],
+    "setupQueries": [
+      "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
+      "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '0062aa551ade7dc88d151a9bd43592c0')"
+    ]
+  }
+}
\ No newline at end of file
diff --git a/room/integration-tests/multiplatformtestapp/schemas-ksp/androidx.room.integration.multiplatformtestapp.test.BaseMigrationTest.MigrationDatabase/99.json b/room/integration-tests/multiplatformtestapp/schemas-ksp/androidx.room.integration.multiplatformtestapp.test.BaseMigrationTest.MigrationDatabase/99.json
new file mode 100644
index 0000000..26d59cd
--- /dev/null
+++ b/room/integration-tests/multiplatformtestapp/schemas-ksp/androidx.room.integration.multiplatformtestapp.test.BaseMigrationTest.MigrationDatabase/99.json
@@ -0,0 +1,36 @@
+{
+  "formatVersion": 1,
+  "database": {
+    "version": 99,
+    "identityHash": "0062aa551ade7dc88d151a9bd43592c0",
+    "entities": [
+      {
+        "tableName": "MigrationEntity",
+        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`pk` INTEGER NOT NULL, `addedInV2` TEXT, PRIMARY KEY(`pk`))",
+        "fields": [
+          {
+            "fieldPath": "pk",
+            "columnName": "pk",
+            "affinity": "INTEGER",
+            "notNull": true
+          },
+          {
+            "fieldPath": "addedInV2",
+            "columnName": "addedInV2",
+            "affinity": "TEXT"
+          }
+        ],
+        "primaryKey": {
+          "autoGenerate": false,
+          "columnNames": [
+            "pk"
+          ]
+        }
+      }
+    ],
+    "setupQueries": [
+      "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
+      "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '0062aa551ade7dc88d151a9bd43592c0')"
+    ]
+  }
+}
\ No newline at end of file
diff --git a/room/integration-tests/multiplatformtestapp/src/androidInstrumentedTest/kotlin/androidx/room/integration/multiplatformtestapp/test/AutoMigrationTest.kt b/room/integration-tests/multiplatformtestapp/src/androidInstrumentedTest/kotlin/androidx/room/integration/multiplatformtestapp/test/AutoMigrationTest.kt
index a8c82ee..c308918 100644
--- a/room/integration-tests/multiplatformtestapp/src/androidInstrumentedTest/kotlin/androidx/room/integration/multiplatformtestapp/test/AutoMigrationTest.kt
+++ b/room/integration-tests/multiplatformtestapp/src/androidInstrumentedTest/kotlin/androidx/room/integration/multiplatformtestapp/test/AutoMigrationTest.kt
@@ -17,18 +17,14 @@
 package androidx.room.integration.multiplatformtestapp.test
 
 import androidx.kruth.assertThat
-import androidx.kruth.assertThrows
 import androidx.room.Room
-import androidx.room.migration.Migration
+import androidx.room.RoomDatabase
 import androidx.room.testing.MigrationTestHelper
 import androidx.sqlite.SQLiteDriver
-import androidx.sqlite.db.SupportSQLiteDatabase
 import androidx.sqlite.driver.bundled.BundledSQLiteDriver
 import androidx.test.platform.app.InstrumentationRegistry
 import kotlin.test.AfterTest
 import kotlin.test.BeforeTest
-import kotlin.test.Test
-import kotlinx.coroutines.test.runTest
 import org.junit.Rule
 
 class AutoMigrationTest : BaseAutoMigrationTest() {
@@ -41,35 +37,17 @@
         instrumentation = instrumentation,
         driver = driver,
         databaseClass = AutoMigrationDatabase::class,
-        file = file
+        file = file,
+        autoMigrationSpecs = listOf(ProvidedSpecFrom2To3())
     )
 
     override fun getTestHelper() = migrationTestHelper
 
-    override fun getRoomDatabase(): AutoMigrationDatabase {
+    override fun getDatabaseBuilder(): RoomDatabase.Builder<AutoMigrationDatabase> {
         return Room.databaseBuilder<AutoMigrationDatabase>(
             context = instrumentation.targetContext,
             name = file.path
-        ).setDriver(driver).build()
-    }
-
-    @Test
-    fun migrationWithWrongOverride() = runTest {
-        // Create database in V1
-        val connection = migrationTestHelper.createDatabase(1)
-        connection.close()
-
-        // Auto migrate to V2
-        val v2Db = Room.databaseBuilder<AutoMigrationDatabase>(
-            context = instrumentation.targetContext,
-            name = file.path
-        ).setDriver(driver).addMigrations(object : Migration(1, 2) {
-            override fun migrate(db: SupportSQLiteDatabase) {} }
-        ).build()
-        assertThrows<NotImplementedError> {
-            v2Db.dao().insert(AutoMigrationEntity(1, 1))
-        }
-        v2Db.close()
+        ).setDriver(driver)
     }
 
     @BeforeTest
diff --git a/room/integration-tests/multiplatformtestapp/src/androidInstrumentedTest/kotlin/androidx/room/integration/multiplatformtestapp/test/MigrationTest.kt b/room/integration-tests/multiplatformtestapp/src/androidInstrumentedTest/kotlin/androidx/room/integration/multiplatformtestapp/test/MigrationTest.kt
new file mode 100644
index 0000000..63a17f7
--- /dev/null
+++ b/room/integration-tests/multiplatformtestapp/src/androidInstrumentedTest/kotlin/androidx/room/integration/multiplatformtestapp/test/MigrationTest.kt
@@ -0,0 +1,98 @@
+/*
+ * 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.multiplatformtestapp.test
+
+import androidx.kruth.assertThat
+import androidx.kruth.assertThrows
+import androidx.room.Room
+import androidx.room.RoomDatabase
+import androidx.room.migration.Migration
+import androidx.room.testing.MigrationTestHelper
+import androidx.sqlite.SQLiteDriver
+import androidx.sqlite.db.SupportSQLiteDatabase
+import androidx.sqlite.driver.bundled.BundledSQLiteDriver
+import androidx.test.platform.app.InstrumentationRegistry
+import kotlin.test.AfterTest
+import kotlin.test.BeforeTest
+import kotlinx.coroutines.test.runTest
+import org.junit.Rule
+import org.junit.Test
+
+class MigrationTest : BaseMigrationTest() {
+    private val instrumentation = InstrumentationRegistry.getInstrumentation()
+    private val file = instrumentation.targetContext.getDatabasePath("test.db")
+    private val driver: SQLiteDriver = BundledSQLiteDriver()
+
+    @get:Rule
+    val migrationTestHelper = MigrationTestHelper(
+        instrumentation = instrumentation,
+        driver = driver,
+        databaseClass = MigrationDatabase::class,
+        file = file
+    )
+
+    override fun getTestHelper() = migrationTestHelper
+
+    override fun getDatabaseBuilder(): RoomDatabase.Builder<MigrationDatabase> {
+        return Room.databaseBuilder<MigrationDatabase>(
+            context = instrumentation.targetContext,
+            name = file.path
+        ).setDriver(driver)
+    }
+
+    @Test
+    fun migrationWithWrongOverride() = runTest {
+        // Create database in V1
+        val connection = migrationTestHelper.createDatabase(1)
+        connection.close()
+
+        // Create database with a migration overriding the wrong function
+        val v2Db = Room.databaseBuilder<MigrationDatabase>(
+            context = instrumentation.targetContext,
+            name = file.path
+        ).setDriver(driver).addMigrations(
+            object : Migration(1, 2) {
+                override fun migrate(db: SupportSQLiteDatabase) {}
+            }
+        ).build()
+        // Expect failure due to database being configured with driver but migration object is
+        // overriding SupportSQLite* version.
+        assertThrows<NotImplementedError> {
+            v2Db.dao().getSingleItem(1)
+        }.hasMessageThat().isEqualTo(
+            "Migration functionality with a provided SQLiteDriver requires overriding the " +
+                "migrate(SQLiteConnection) function."
+        )
+        v2Db.close()
+    }
+
+    @BeforeTest
+    fun before() {
+        assertThat(file).isNotNull()
+        file.parentFile?.mkdirs()
+        deleteDatabaseFile()
+    }
+
+    @AfterTest
+    fun after() {
+        deleteDatabaseFile()
+    }
+
+    private fun deleteDatabaseFile() {
+        instrumentation.targetContext.deleteDatabase(file.name)
+    }
+}
diff --git a/room/integration-tests/multiplatformtestapp/src/androidInstrumentedTest/kotlin/androidx/room/integration/multiplatformtestapp/test/SimpleQueryTest.kt b/room/integration-tests/multiplatformtestapp/src/androidInstrumentedTest/kotlin/androidx/room/integration/multiplatformtestapp/test/QueryTest.kt
similarity index 96%
rename from room/integration-tests/multiplatformtestapp/src/androidInstrumentedTest/kotlin/androidx/room/integration/multiplatformtestapp/test/SimpleQueryTest.kt
rename to room/integration-tests/multiplatformtestapp/src/androidInstrumentedTest/kotlin/androidx/room/integration/multiplatformtestapp/test/QueryTest.kt
index 300ff8c..765680c 100644
--- a/room/integration-tests/multiplatformtestapp/src/androidInstrumentedTest/kotlin/androidx/room/integration/multiplatformtestapp/test/SimpleQueryTest.kt
+++ b/room/integration-tests/multiplatformtestapp/src/androidInstrumentedTest/kotlin/androidx/room/integration/multiplatformtestapp/test/QueryTest.kt
@@ -21,7 +21,7 @@
 import androidx.test.platform.app.InstrumentationRegistry
 import kotlinx.coroutines.Dispatchers
 
-class SimpleQueryTest : BaseSimpleQueryTest() {
+class QueryTest : BaseQueryTest() {
 
     private val instrumentation = InstrumentationRegistry.getInstrumentation()
 
diff --git a/room/integration-tests/multiplatformtestapp/src/androidInstrumentedTest/kotlin/androidx/room/integration/multiplatformtestapp/test/SimpleQueryTest.kt b/room/integration-tests/multiplatformtestapp/src/androidInstrumentedTest/kotlin/androidx/room/integration/multiplatformtestapp/test/TypeConverterTest.kt
similarity index 78%
copy from room/integration-tests/multiplatformtestapp/src/androidInstrumentedTest/kotlin/androidx/room/integration/multiplatformtestapp/test/SimpleQueryTest.kt
copy to room/integration-tests/multiplatformtestapp/src/androidInstrumentedTest/kotlin/androidx/room/integration/multiplatformtestapp/test/TypeConverterTest.kt
index 300ff8c..d89288c 100644
--- a/room/integration-tests/multiplatformtestapp/src/androidInstrumentedTest/kotlin/androidx/room/integration/multiplatformtestapp/test/SimpleQueryTest.kt
+++ b/room/integration-tests/multiplatformtestapp/src/androidInstrumentedTest/kotlin/androidx/room/integration/multiplatformtestapp/test/TypeConverterTest.kt
@@ -17,19 +17,17 @@
 package androidx.room.integration.multiplatformtestapp.test
 
 import androidx.room.Room
+import androidx.room.RoomDatabase
 import androidx.sqlite.driver.bundled.BundledSQLiteDriver
 import androidx.test.platform.app.InstrumentationRegistry
-import kotlinx.coroutines.Dispatchers
 
-class SimpleQueryTest : BaseSimpleQueryTest() {
+class TypeConverterTest : BaseTypeConverterTest() {
 
     private val instrumentation = InstrumentationRegistry.getInstrumentation()
 
-    override fun getRoomDatabase(): SampleDatabase {
-        return Room.inMemoryDatabaseBuilder<SampleDatabase>(
+    override fun getDatabaseBuilder(): RoomDatabase.Builder<TestDatabase> {
+        return Room.inMemoryDatabaseBuilder<TestDatabase>(
             context = instrumentation.targetContext
         ).setDriver(BundledSQLiteDriver())
-            .setQueryCoroutineContext(Dispatchers.IO)
-            .build()
     }
 }
diff --git a/room/integration-tests/multiplatformtestapp/src/commonTest/kotlin/androidx/room/integration/multiplatformtestapp/test/BaseAutoMigrationTest.kt b/room/integration-tests/multiplatformtestapp/src/commonTest/kotlin/androidx/room/integration/multiplatformtestapp/test/BaseAutoMigrationTest.kt
index a5a991a..221b7d5 100644
--- a/room/integration-tests/multiplatformtestapp/src/commonTest/kotlin/androidx/room/integration/multiplatformtestapp/test/BaseAutoMigrationTest.kt
+++ b/room/integration-tests/multiplatformtestapp/src/commonTest/kotlin/androidx/room/integration/multiplatformtestapp/test/BaseAutoMigrationTest.kt
@@ -25,21 +25,22 @@
 import androidx.room.Entity
 import androidx.room.Insert
 import androidx.room.PrimaryKey
+import androidx.room.ProvidedAutoMigrationSpec
 import androidx.room.Query
 import androidx.room.RoomDatabase
-import androidx.room.Update
+import androidx.room.migration.AutoMigrationSpec
 import androidx.room.testing.MigrationTestHelper
+import androidx.sqlite.SQLiteConnection
+import androidx.sqlite.execSQL
 import androidx.sqlite.use
-import kotlin.test.Ignore
 import kotlin.test.Test
 import kotlinx.coroutines.test.runTest
 
 abstract class BaseAutoMigrationTest {
     abstract fun getTestHelper(): MigrationTestHelper
-    abstract fun getRoomDatabase(): AutoMigrationDatabase
+    abstract fun getDatabaseBuilder(): RoomDatabase.Builder<AutoMigrationDatabase>
 
     @Test
-    @Ignore // TODO (b/331622149) Investigate, there seems to be an issue in native.
     fun migrateFromV1ToLatest() = runTest {
         val migrationTestHelper = getTestHelper()
 
@@ -61,11 +62,14 @@
         connection.close()
 
         // Auto migrate to latest
-        val dbVersion2 = getRoomDatabase()
-        assertThat(dbVersion2.dao().update(AutoMigrationEntity(1, 5))).isEqualTo(1)
-        assertThat(dbVersion2.dao().getSingleItem().pk).isEqualTo(1)
-        assertThat(dbVersion2.dao().getSingleItem().data).isEqualTo(5)
-        dbVersion2.close()
+        val dbVersion3 = getDatabaseBuilder()
+            .addAutoMigrationSpec(ProvidedSpecFrom2To3())
+            .build()
+        val dao = dbVersion3.dao()
+        assertThat(dao.getSingleItem().pk).isEqualTo(1)
+        assertThat(dao.getSingleItem().data).isEqualTo(0)
+        assertThat(dao.getSingleItem().moreData).isEqualTo("5")
+        dbVersion3.close()
     }
 
     @Test
@@ -73,47 +77,41 @@
         val migrationTestHelper = getTestHelper()
 
         // Create database V1
-        val connection = migrationTestHelper.createDatabase(1)
+        val connectionV1 = migrationTestHelper.createDatabase(1)
         // Insert some data, we'll validate it is present after migration
-        connection.prepare("INSERT INTO AutoMigrationEntity (pk) VALUES (?)").use {
+        connectionV1.prepare("INSERT INTO AutoMigrationEntity (pk) VALUES (?)").use {
             it.bindLong(1, 1)
             assertThat(it.step()).isFalse() // SQLITE_DONE
         }
-        connection.close()
+        connectionV1.close()
 
-        // Auto migrate to V2
-        migrationTestHelper.runMigrationsAndValidate(2)
+        // Auto migrate to V2 and validate data is still present
+        val connectionV2 = migrationTestHelper.runMigrationsAndValidate(2)
+        connectionV2.prepare("SELECT count(*) FROM AutoMigrationEntity").use {
+            assertThat(it.step()).isTrue() // SQLITE_ROW
+            assertThat(it.getInt(0)).isEqualTo(1)
+        }
+        connectionV2.close()
     }
 
     @Test
-    fun misuseTestHelperAlreadyCreatedDatabase() {
-        val migrationTestHelper = getTestHelper()
-
-        // Create database V1
-        migrationTestHelper.createDatabase(1).close()
-
-        // When trying to create at V1 again, fail due to database file being already created.
-        assertThrows<IllegalStateException> {
-            migrationTestHelper.createDatabase(1)
-        }.hasMessageThat()
-            .contains("Creation of tables didn't occur while creating a new database.")
-
-        // If trying to create at V2, migration will try to run and fail.
-        assertThrows<IllegalStateException> {
-            migrationTestHelper.createDatabase(2)
-        }.hasMessageThat()
-            .contains("A migration from 1 to 2 was required but not found.")
+    fun missingProvidedAutoMigrationSpec() {
+        assertThrows<IllegalArgumentException> {
+            getDatabaseBuilder().build()
+        }.hasMessageThat().contains(
+            "A required auto migration spec (${ProvidedSpecFrom2To3::class.qualifiedName}) is " +
+                "missing in the database configuration."
+        )
     }
 
     @Test
-    fun misuseTestHelperMissingDatabaseForValidateMigrations() {
-        val migrationTestHelper = getTestHelper()
-
-        // Try to validate migrations, but fail due to no previous database created.
-        assertThrows<IllegalStateException> {
-            migrationTestHelper.runMigrationsAndValidate(2, emptyList())
-        }.hasMessageThat()
-            .contains("Creation of tables should never occur while validating migrations.")
+    fun extraProvidedAutoMigrationSpec() {
+        assertThrows<IllegalArgumentException> {
+            getDatabaseBuilder()
+                .addAutoMigrationSpec(ProvidedSpecFrom2To3())
+                .addAutoMigrationSpec(ExtraProvidedSpec())
+                .build()
+        }.hasMessageThat().contains("Unexpected auto migration specs found.")
     }
 
     @Entity
@@ -121,7 +119,9 @@
         @PrimaryKey
         val pk: Long,
         @ColumnInfo(defaultValue = "0")
-        val data: Long
+        val data: Long,
+        @ColumnInfo(defaultValue = "")
+        val moreData: String
     )
 
     @Dao
@@ -129,20 +129,29 @@
         @Insert
         suspend fun insert(entity: AutoMigrationEntity)
 
-        @Update
-        suspend fun update(entity: AutoMigrationEntity): Int
-
         @Query("SELECT * FROM AutoMigrationEntity")
         suspend fun getSingleItem(): AutoMigrationEntity
     }
 
     @Database(
         entities = [AutoMigrationEntity::class],
-        version = 2,
+        version = 3,
         exportSchema = true,
-        autoMigrations = [AutoMigration(from = 1, to = 2)]
+        autoMigrations = [
+            AutoMigration(from = 1, to = 2),
+            AutoMigration(from = 2, to = 3, spec = ProvidedSpecFrom2To3::class)
+        ]
     )
     abstract class AutoMigrationDatabase : RoomDatabase() {
         abstract fun dao(): AutoMigrationDao
     }
+
+    @ProvidedAutoMigrationSpec
+    open class ProvidedSpecFrom2To3 : AutoMigrationSpec {
+        override fun onPostMigrate(connection: SQLiteConnection) {
+            connection.execSQL("UPDATE AutoMigrationEntity SET moreData = '5'")
+        }
+    }
+
+    class ExtraProvidedSpec : AutoMigrationSpec
 }
diff --git a/room/integration-tests/multiplatformtestapp/src/commonTest/kotlin/androidx/room/integration/multiplatformtestapp/test/BaseBuilderTest.kt b/room/integration-tests/multiplatformtestapp/src/commonTest/kotlin/androidx/room/integration/multiplatformtestapp/test/BaseBuilderTest.kt
index 005e926..dea6886 100644
--- a/room/integration-tests/multiplatformtestapp/src/commonTest/kotlin/androidx/room/integration/multiplatformtestapp/test/BaseBuilderTest.kt
+++ b/room/integration-tests/multiplatformtestapp/src/commonTest/kotlin/androidx/room/integration/multiplatformtestapp/test/BaseBuilderTest.kt
@@ -147,4 +147,19 @@
         }.hasMessageThat()
             .contains("It is required that the coroutine context contain a dispatcher.")
     }
+
+    @Test
+    fun setJournalMode() = runTest {
+        val database = getRoomDatabaseBuilder()
+            .setJournalMode(RoomDatabase.JournalMode.TRUNCATE)
+            .build()
+        val journalMode = database.useReaderConnection { connection ->
+            connection.usePrepared("PRAGMA journal_mode") {
+                it.step()
+                it.getText(0)
+            }
+        }
+        assertThat(journalMode).isEqualTo("truncate")
+        database.close()
+    }
 }
diff --git a/room/integration-tests/multiplatformtestapp/src/commonTest/kotlin/androidx/room/integration/multiplatformtestapp/test/BaseMigrationTest.kt b/room/integration-tests/multiplatformtestapp/src/commonTest/kotlin/androidx/room/integration/multiplatformtestapp/test/BaseMigrationTest.kt
new file mode 100644
index 0000000..8b7b4a2
--- /dev/null
+++ b/room/integration-tests/multiplatformtestapp/src/commonTest/kotlin/androidx/room/integration/multiplatformtestapp/test/BaseMigrationTest.kt
@@ -0,0 +1,250 @@
+/*
+ * 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.multiplatformtestapp.test
+
+import androidx.kruth.assertThat
+import androidx.kruth.assertThrows
+import androidx.room.Dao
+import androidx.room.Database
+import androidx.room.Entity
+import androidx.room.Insert
+import androidx.room.PrimaryKey
+import androidx.room.Query
+import androidx.room.RoomDatabase
+import androidx.room.migration.Migration
+import androidx.room.testing.MigrationTestHelper
+import androidx.sqlite.SQLiteConnection
+import androidx.sqlite.execSQL
+import androidx.sqlite.use
+import kotlin.test.Test
+import kotlin.test.assertNotNull
+import kotlin.test.assertNull
+import kotlinx.coroutines.test.runTest
+
+abstract class BaseMigrationTest {
+    abstract fun getTestHelper(): MigrationTestHelper
+    abstract fun getDatabaseBuilder(): RoomDatabase.Builder<MigrationDatabase>
+
+    @Test
+    fun migrateFromV1ToLatest() = runTest {
+        val migrationTestHelper = getTestHelper()
+
+        // Create database V1
+        val connection = migrationTestHelper.createDatabase(1)
+        // Insert some data, we'll validate it is present after migration
+        connection.prepare("INSERT INTO MigrationEntity (pk) VALUES (?)").use {
+            it.bindLong(1, 1)
+            assertThat(it.step()).isFalse() // SQLITE_DONE
+        }
+        connection.close()
+
+        // Migrate to latest
+        val dbVersion2 = getDatabaseBuilder()
+            .addMigrations(object : Migration(1, 2) {
+                override fun migrate(connection: SQLiteConnection) {
+                    connection.execSQL("ALTER TABLE MigrationEntity ADD COLUMN addedInV2 TEXT")
+                }
+            })
+            .build()
+        val item = dbVersion2.dao().getSingleItem(1)
+        assertNotNull(item)
+        assertThat(item.pk).isEqualTo(1)
+        assertThat(item.addedInV2).isNull()
+        dbVersion2.close()
+    }
+
+    @Test
+    fun migrateFromV1ToV2() = runTest {
+        val migrationTestHelper = getTestHelper()
+
+        // Create database V1
+        val connectionV1 = migrationTestHelper.createDatabase(1)
+        // Insert some data, we'll validate it is present after migration
+        connectionV1.prepare("INSERT INTO MigrationEntity (pk) VALUES (?)").use {
+            it.bindLong(1, 1)
+            assertThat(it.step()).isFalse() // SQLITE_DONE
+        }
+        connectionV1.close()
+
+        val migration = object : Migration(1, 2) {
+            override fun migrate(connection: SQLiteConnection) {
+                connection.execSQL("ALTER TABLE MigrationEntity ADD COLUMN addedInV2 TEXT")
+            }
+        }
+        // Migrate to V2 and validate data is still present
+        val connectionV2 = migrationTestHelper.runMigrationsAndValidate(2, listOf(migration))
+        connectionV2.prepare("SELECT count(*) FROM MigrationEntity").use {
+            assertThat(it.step()).isTrue() // SQLITE_ROW
+            assertThat(it.getInt(0)).isEqualTo(1)
+        }
+        connectionV2.close()
+    }
+
+    @Test
+    fun missingMigration() = runTest {
+        val migrationTestHelper = getTestHelper()
+        // Create database V1
+        val connection = migrationTestHelper.createDatabase(1)
+        connection.close()
+
+        // Create database missing migration
+        val dbVersion2 = getDatabaseBuilder().build()
+        // Fail to migrate
+        assertThrows<IllegalStateException> {
+            dbVersion2.dao().getSingleItem(1)
+        }.hasMessageThat().contains("A migration from 1 to 2 was required but not found.")
+        dbVersion2.close()
+    }
+
+    @Test
+    fun invalidMigration() = runTest {
+        val migrationTestHelper = getTestHelper()
+        // Create database V1
+        val connection = migrationTestHelper.createDatabase(1)
+        connection.close()
+
+        // Create database with a migration that doesn't properly changes the schema
+        val dbVersion2 = getDatabaseBuilder()
+            .addMigrations(object : Migration(1, 2) {
+                override fun migrate(connection: SQLiteConnection) {}
+            })
+            .build()
+        // Fail to migrate
+        assertThrows<IllegalStateException> {
+            dbVersion2.dao().getSingleItem(1)
+        }.hasMessageThat().contains("Migration didn't properly handle: MigrationEntity")
+        dbVersion2.close()
+    }
+
+    @Test
+    fun destructiveMigration() = runTest {
+        val migrationTestHelper = getTestHelper()
+        // Create database V1
+        val connection = migrationTestHelper.createDatabase(1)
+        connection.close()
+
+        // Create database with destructive migrations enabled
+        val dbVersion2 = getDatabaseBuilder()
+            .fallbackToDestructiveMigration(dropAllTables = true)
+            .build()
+        // Migrate via fallback destructive deletion
+        val item = dbVersion2.dao().getSingleItem(1)
+        assertNull(item)
+        dbVersion2.close()
+    }
+
+    @Test
+    fun destructiveMigrationOnDowngrade() = runTest {
+        val migrationTestHelper = getTestHelper()
+        // Create database from a future far away
+        val connection = migrationTestHelper.createDatabase(99)
+        connection.close()
+
+        // Create database with destructive migrations on downgrade enabled
+        val dbVersion2 = getDatabaseBuilder()
+            .fallbackToDestructiveMigrationOnDowngrade(dropAllTables = true)
+            .build()
+        // Migrate via fallback destructive deletion
+        val item = dbVersion2.dao().getSingleItem(1)
+        assertNull(item)
+        dbVersion2.close()
+    }
+
+    @Test
+    fun destructiveMigrationFrom() = runTest {
+        val migrationTestHelper = getTestHelper()
+        // Create database V1
+        val connection = migrationTestHelper.createDatabase(1)
+        connection.close()
+
+        // Create database missing migration
+        val dbVersion2 = getDatabaseBuilder()
+            .fallbackToDestructiveMigrationFrom(dropAllTables = true, 1)
+            .build()
+        // Migrate via fallback destructive deletion
+        val item = dbVersion2.dao().getSingleItem(1)
+        assertNull(item)
+        dbVersion2.close()
+    }
+
+    @Test
+    fun invalidDestructiveMigrationFrom() {
+        // Create database with an invalid combination of destructive migration from
+        assertThrows<IllegalArgumentException> {
+            getDatabaseBuilder()
+                .addMigrations(object : Migration(1, 2) {})
+                .fallbackToDestructiveMigrationFrom(dropAllTables = true, 1)
+                .build()
+        }.hasMessageThat().contains("Inconsistency detected.")
+    }
+
+    @Test
+    fun misuseTestHelperAlreadyCreatedDatabase() {
+        val migrationTestHelper = getTestHelper()
+
+        // Create database V1
+        migrationTestHelper.createDatabase(1).close()
+
+        // When trying to create at V1 again, fail due to database file being already created.
+        assertThrows<IllegalStateException> {
+            migrationTestHelper.createDatabase(1)
+        }.hasMessageThat()
+            .contains("Creation of tables didn't occur while creating a new database.")
+
+        // If trying to create at V2, migration will try to run and fail.
+        assertThrows<IllegalStateException> {
+            migrationTestHelper.createDatabase(2)
+        }.hasMessageThat()
+            .contains("A migration from 1 to 2 was required but not found.")
+    }
+
+    @Test
+    fun misuseTestHelperMissingDatabaseForValidateMigrations() {
+        val migrationTestHelper = getTestHelper()
+
+        // Try to validate migrations, but fail due to no previous database created.
+        assertThrows<IllegalStateException> {
+            migrationTestHelper.runMigrationsAndValidate(2, emptyList())
+        }.hasMessageThat()
+            .contains("Creation of tables should never occur while validating migrations.")
+    }
+
+    @Entity
+    data class MigrationEntity(
+        @PrimaryKey
+        val pk: Long,
+        val addedInV2: String?
+    )
+
+    @Dao
+    interface MigrationDao {
+        @Insert
+        suspend fun insert(entity: MigrationEntity)
+
+        @Query("SELECT * FROM MigrationEntity WHERE pk = :pk")
+        suspend fun getSingleItem(pk: Long): MigrationEntity?
+    }
+
+    @Database(
+        entities = [MigrationEntity::class],
+        version = 2,
+        exportSchema = true,
+    )
+    abstract class MigrationDatabase : RoomDatabase() {
+        abstract fun dao(): MigrationDao
+    }
+}
diff --git a/room/integration-tests/multiplatformtestapp/src/commonTest/kotlin/androidx/room/integration/multiplatformtestapp/test/BaseSimpleQueryTest.kt b/room/integration-tests/multiplatformtestapp/src/commonTest/kotlin/androidx/room/integration/multiplatformtestapp/test/BaseQueryTest.kt
similarity index 99%
rename from room/integration-tests/multiplatformtestapp/src/commonTest/kotlin/androidx/room/integration/multiplatformtestapp/test/BaseSimpleQueryTest.kt
rename to room/integration-tests/multiplatformtestapp/src/commonTest/kotlin/androidx/room/integration/multiplatformtestapp/test/BaseQueryTest.kt
index 836f9c4..43909bf 100644
--- a/room/integration-tests/multiplatformtestapp/src/commonTest/kotlin/androidx/room/integration/multiplatformtestapp/test/BaseSimpleQueryTest.kt
+++ b/room/integration-tests/multiplatformtestapp/src/commonTest/kotlin/androidx/room/integration/multiplatformtestapp/test/BaseQueryTest.kt
@@ -37,7 +37,7 @@
 import kotlinx.coroutines.test.runTest
 import kotlinx.coroutines.yield
 
-abstract class BaseSimpleQueryTest {
+abstract class BaseQueryTest {
 
     private lateinit var db: SampleDatabase
 
diff --git a/room/integration-tests/multiplatformtestapp/src/commonTest/kotlin/androidx/room/integration/multiplatformtestapp/test/BaseTypeConverterTest.kt b/room/integration-tests/multiplatformtestapp/src/commonTest/kotlin/androidx/room/integration/multiplatformtestapp/test/BaseTypeConverterTest.kt
new file mode 100644
index 0000000..93b06c4
--- /dev/null
+++ b/room/integration-tests/multiplatformtestapp/src/commonTest/kotlin/androidx/room/integration/multiplatformtestapp/test/BaseTypeConverterTest.kt
@@ -0,0 +1,95 @@
+/*
+ * 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.multiplatformtestapp.test
+
+import androidx.kruth.assertThat
+import androidx.kruth.assertThrows
+import androidx.room.Dao
+import androidx.room.Database
+import androidx.room.Entity
+import androidx.room.Insert
+import androidx.room.PrimaryKey
+import androidx.room.ProvidedTypeConverter
+import androidx.room.Query
+import androidx.room.RoomDatabase
+import androidx.room.TypeConverter
+import androidx.room.TypeConverters
+import kotlin.test.Test
+import kotlinx.coroutines.test.runTest
+
+abstract class BaseTypeConverterTest {
+    abstract fun getDatabaseBuilder(): RoomDatabase.Builder<TestDatabase>
+
+    @Test
+    fun entityWithConverter() = runTest {
+        val database = getDatabaseBuilder()
+            .addTypeConverter(BarConverter())
+            .build()
+        val entity = TestEntity(1, Foo(1979), Bar("Mujer Boricua"))
+        database.getDao().insertItem(entity)
+        assertThat(database.getDao().getItem(1)).isEqualTo(entity)
+        database.close()
+    }
+
+    @Test
+    fun missingTypeConverter() {
+        assertThrows<IllegalArgumentException> {
+            getDatabaseBuilder().build()
+        }.hasMessageThat().isEqualTo("A required type converter (" +
+            "${BarConverter::class.qualifiedName}) for ${TestDao::class.qualifiedName} is " +
+            "missing in the database configuration.")
+    }
+
+    @Database(entities = [TestEntity::class], version = 1, exportSchema = false)
+    @TypeConverters(FooConverter::class, BarConverter::class)
+    abstract class TestDatabase : RoomDatabase() {
+        abstract fun getDao(): TestDao
+    }
+
+    @Dao
+    interface TestDao {
+        @Insert
+        suspend fun insertItem(item: TestEntity)
+
+        @Query("SELECT * FROM TestEntity WHERE id = :id")
+        suspend fun getItem(id: Long): TestEntity
+    }
+
+    @Entity
+    data class TestEntity(@PrimaryKey val id: Long, val foo: Foo, val bar: Bar)
+
+    data class Foo(val number: Int)
+
+    data class Bar(val text: String)
+
+    object FooConverter {
+        @TypeConverter
+        fun toFoo(number: Int): Foo = Foo(number)
+
+        @TypeConverter
+        fun fromFoo(foo: Foo): Int = foo.number
+    }
+
+    @ProvidedTypeConverter
+    class BarConverter {
+        @TypeConverter
+        fun toBar(text: String): Bar = Bar(text)
+
+        @TypeConverter
+        fun fromBar(bar: Bar): String = bar.text
+    }
+}
diff --git a/room/integration-tests/multiplatformtestapp/src/jvmTest/kotlin/androidx/room/integration/multiplatformtestapp/test/AutoMigrationTest.kt b/room/integration-tests/multiplatformtestapp/src/jvmTest/kotlin/androidx/room/integration/multiplatformtestapp/test/AutoMigrationTest.kt
index 3e36969..2423be8 100644
--- a/room/integration-tests/multiplatformtestapp/src/jvmTest/kotlin/androidx/room/integration/multiplatformtestapp/test/AutoMigrationTest.kt
+++ b/room/integration-tests/multiplatformtestapp/src/jvmTest/kotlin/androidx/room/integration/multiplatformtestapp/test/AutoMigrationTest.kt
@@ -17,6 +17,7 @@
 package androidx.room.integration.multiplatformtestapp.test
 
 import androidx.room.Room
+import androidx.room.RoomDatabase
 import androidx.room.testing.MigrationTestHelper
 import androidx.sqlite.SQLiteDriver
 import androidx.sqlite.driver.bundled.BundledSQLiteDriver
@@ -33,13 +34,14 @@
         schemaDirectoryPath = Path("schemas-ksp"),
         databasePath = tempFilePath,
         driver = driver,
-        databaseClass = AutoMigrationDatabase::class
+        databaseClass = AutoMigrationDatabase::class,
+        autoMigrationSpecs = listOf(ProvidedSpecFrom2To3())
     )
 
     override fun getTestHelper() = migrationTestHelper
 
-    override fun getRoomDatabase(): AutoMigrationDatabase {
+    override fun getDatabaseBuilder(): RoomDatabase.Builder<AutoMigrationDatabase> {
         return Room.databaseBuilder<AutoMigrationDatabase>(tempFilePath.toString())
-            .setDriver(driver).build()
+            .setDriver(driver)
     }
 }
diff --git a/room/integration-tests/multiplatformtestapp/src/jvmTest/kotlin/androidx/room/integration/multiplatformtestapp/test/MigrationTest.kt b/room/integration-tests/multiplatformtestapp/src/jvmTest/kotlin/androidx/room/integration/multiplatformtestapp/test/MigrationTest.kt
new file mode 100644
index 0000000..017fdac
--- /dev/null
+++ b/room/integration-tests/multiplatformtestapp/src/jvmTest/kotlin/androidx/room/integration/multiplatformtestapp/test/MigrationTest.kt
@@ -0,0 +1,46 @@
+/*
+ * 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.multiplatformtestapp.test
+
+import androidx.room.Room
+import androidx.room.RoomDatabase
+import androidx.room.testing.MigrationTestHelper
+import androidx.sqlite.SQLiteDriver
+import androidx.sqlite.driver.bundled.BundledSQLiteDriver
+import kotlin.io.path.Path
+import kotlin.io.path.createTempFile
+import org.junit.Rule
+
+class MigrationTest : BaseMigrationTest() {
+    private val tempFilePath = createTempFile("test.db").also { it.toFile().deleteOnExit() }
+    private val driver: SQLiteDriver = BundledSQLiteDriver()
+
+    @get:Rule
+    val migrationTestHelper = MigrationTestHelper(
+        schemaDirectoryPath = Path("schemas-ksp"),
+        databasePath = tempFilePath,
+        driver = driver,
+        databaseClass = MigrationDatabase::class
+    )
+
+    override fun getTestHelper() = migrationTestHelper
+
+    override fun getDatabaseBuilder(): RoomDatabase.Builder<MigrationDatabase> {
+        return Room.databaseBuilder<MigrationDatabase>(tempFilePath.toString())
+            .setDriver(driver)
+    }
+}
diff --git a/room/integration-tests/multiplatformtestapp/src/jvmTest/kotlin/androidx/room/integration/multiplatformtestapp/test/SimpleQueryTest.kt b/room/integration-tests/multiplatformtestapp/src/jvmTest/kotlin/androidx/room/integration/multiplatformtestapp/test/QueryTest.kt
similarity index 95%
rename from room/integration-tests/multiplatformtestapp/src/jvmTest/kotlin/androidx/room/integration/multiplatformtestapp/test/SimpleQueryTest.kt
rename to room/integration-tests/multiplatformtestapp/src/jvmTest/kotlin/androidx/room/integration/multiplatformtestapp/test/QueryTest.kt
index 6be6358f..fa91c34 100644
--- a/room/integration-tests/multiplatformtestapp/src/jvmTest/kotlin/androidx/room/integration/multiplatformtestapp/test/SimpleQueryTest.kt
+++ b/room/integration-tests/multiplatformtestapp/src/jvmTest/kotlin/androidx/room/integration/multiplatformtestapp/test/QueryTest.kt
@@ -20,7 +20,7 @@
 import androidx.sqlite.driver.bundled.BundledSQLiteDriver
 import kotlinx.coroutines.Dispatchers
 
-class SimpleQueryTest : BaseSimpleQueryTest() {
+class QueryTest : BaseQueryTest() {
 
     override fun getRoomDatabase(): SampleDatabase {
         return Room.inMemoryDatabaseBuilder<SampleDatabase>()
diff --git a/room/integration-tests/multiplatformtestapp/src/jvmTest/kotlin/androidx/room/integration/multiplatformtestapp/test/SimpleQueryTest.kt b/room/integration-tests/multiplatformtestapp/src/jvmTest/kotlin/androidx/room/integration/multiplatformtestapp/test/TypeConverterTest.kt
similarity index 74%
copy from room/integration-tests/multiplatformtestapp/src/jvmTest/kotlin/androidx/room/integration/multiplatformtestapp/test/SimpleQueryTest.kt
copy to room/integration-tests/multiplatformtestapp/src/jvmTest/kotlin/androidx/room/integration/multiplatformtestapp/test/TypeConverterTest.kt
index 6be6358f..35bdee5 100644
--- a/room/integration-tests/multiplatformtestapp/src/jvmTest/kotlin/androidx/room/integration/multiplatformtestapp/test/SimpleQueryTest.kt
+++ b/room/integration-tests/multiplatformtestapp/src/jvmTest/kotlin/androidx/room/integration/multiplatformtestapp/test/TypeConverterTest.kt
@@ -17,15 +17,13 @@
 package androidx.room.integration.multiplatformtestapp.test
 
 import androidx.room.Room
+import androidx.room.RoomDatabase
 import androidx.sqlite.driver.bundled.BundledSQLiteDriver
-import kotlinx.coroutines.Dispatchers
 
-class SimpleQueryTest : BaseSimpleQueryTest() {
+class TypeConverterTest : BaseTypeConverterTest() {
 
-    override fun getRoomDatabase(): SampleDatabase {
-        return Room.inMemoryDatabaseBuilder<SampleDatabase>()
+    override fun getDatabaseBuilder(): RoomDatabase.Builder<TestDatabase> {
+        return Room.inMemoryDatabaseBuilder<TestDatabase>()
             .setDriver(BundledSQLiteDriver())
-            .setQueryCoroutineContext(Dispatchers.IO)
-            .build()
     }
 }
diff --git a/room/integration-tests/multiplatformtestapp/src/nativeTest/kotlin/androidx/room/integration/multiplatformtestapp/test/AutoMigrationTest.kt b/room/integration-tests/multiplatformtestapp/src/nativeTest/kotlin/androidx/room/integration/multiplatformtestapp/test/AutoMigrationTest.kt
index 4300bb2..0d349e8 100644
--- a/room/integration-tests/multiplatformtestapp/src/nativeTest/kotlin/androidx/room/integration/multiplatformtestapp/test/AutoMigrationTest.kt
+++ b/room/integration-tests/multiplatformtestapp/src/nativeTest/kotlin/androidx/room/integration/multiplatformtestapp/test/AutoMigrationTest.kt
@@ -17,6 +17,7 @@
 package androidx.room.integration.multiplatformtestapp.test
 
 import androidx.room.Room
+import androidx.room.RoomDatabase
 import androidx.room.testing.MigrationTestHelper
 import androidx.sqlite.SQLiteDriver
 import androidx.sqlite.driver.bundled.BundledSQLiteDriver
@@ -29,21 +30,22 @@
     private val filename = "/tmp/test-${Random.nextInt()}.db"
     private val driver: SQLiteDriver = BundledSQLiteDriver()
 
+    private val dbFactory = { AutoMigrationDatabase::class.instantiateImpl() }
+
     private val migrationTestHelper = MigrationTestHelper(
         schemaDirectoryPath = getSchemaDirectoryPath(),
         fileName = filename,
         driver = driver,
         databaseClass = AutoMigrationDatabase::class,
-        databaseFactory = { AutoMigrationDatabase::class.instantiateImpl() }
+        databaseFactory = dbFactory,
+        autoMigrationSpecs = listOf(ProvidedSpecFrom2To3())
     )
 
     override fun getTestHelper() = migrationTestHelper
 
-    override fun getRoomDatabase(): AutoMigrationDatabase {
-        return Room.databaseBuilder<AutoMigrationDatabase>(filename) {
-            AutoMigrationDatabase::class.instantiateImpl()
-        }
-            .setDriver(driver).build()
+    override fun getDatabaseBuilder(): RoomDatabase.Builder<AutoMigrationDatabase> {
+        return Room.databaseBuilder<AutoMigrationDatabase>(filename, dbFactory)
+            .setDriver(driver)
     }
 
     @BeforeTest
diff --git a/room/integration-tests/multiplatformtestapp/src/nativeTest/kotlin/androidx/room/integration/multiplatformtestapp/test/MigrationTest.kt b/room/integration-tests/multiplatformtestapp/src/nativeTest/kotlin/androidx/room/integration/multiplatformtestapp/test/MigrationTest.kt
new file mode 100644
index 0000000..bddb56a
--- /dev/null
+++ b/room/integration-tests/multiplatformtestapp/src/nativeTest/kotlin/androidx/room/integration/multiplatformtestapp/test/MigrationTest.kt
@@ -0,0 +1,66 @@
+/*
+ * 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.multiplatformtestapp.test
+
+import androidx.room.Room
+import androidx.room.RoomDatabase
+import androidx.room.testing.MigrationTestHelper
+import androidx.sqlite.SQLiteDriver
+import androidx.sqlite.driver.bundled.BundledSQLiteDriver
+import kotlin.random.Random
+import kotlin.test.AfterTest
+import kotlin.test.BeforeTest
+import platform.posix.remove
+
+class MigrationTest : BaseMigrationTest() {
+    private val filename = "/tmp/test-${Random.nextInt()}.db"
+    private val driver: SQLiteDriver = BundledSQLiteDriver()
+
+    private val dbFactory = { MigrationDatabase::class.instantiateImpl() }
+
+    private val migrationTestHelper = MigrationTestHelper(
+        schemaDirectoryPath = getSchemaDirectoryPath(),
+        fileName = filename,
+        driver = driver,
+        databaseClass = MigrationDatabase::class,
+        databaseFactory = dbFactory
+    )
+
+    override fun getTestHelper() = migrationTestHelper
+
+    override fun getDatabaseBuilder(): RoomDatabase.Builder<MigrationDatabase> {
+        return Room.databaseBuilder<MigrationDatabase>(filename, dbFactory)
+            .setDriver(driver)
+    }
+
+    @BeforeTest
+    fun before() {
+        deleteDatabaseFile()
+    }
+
+    @AfterTest
+    fun after() {
+        migrationTestHelper.finished()
+        deleteDatabaseFile()
+    }
+
+    private fun deleteDatabaseFile() {
+        remove(filename)
+        remove("$filename-wal")
+        remove("$filename-shm")
+    }
+}
diff --git a/room/integration-tests/multiplatformtestapp/src/nativeTest/kotlin/androidx/room/integration/multiplatformtestapp/test/SimpleQueryTest.kt b/room/integration-tests/multiplatformtestapp/src/nativeTest/kotlin/androidx/room/integration/multiplatformtestapp/test/QueryTest.kt
similarity index 86%
rename from room/integration-tests/multiplatformtestapp/src/nativeTest/kotlin/androidx/room/integration/multiplatformtestapp/test/SimpleQueryTest.kt
rename to room/integration-tests/multiplatformtestapp/src/nativeTest/kotlin/androidx/room/integration/multiplatformtestapp/test/QueryTest.kt
index 5a0d3c9..9ad0d65 100644
--- a/room/integration-tests/multiplatformtestapp/src/nativeTest/kotlin/androidx/room/integration/multiplatformtestapp/test/SimpleQueryTest.kt
+++ b/room/integration-tests/multiplatformtestapp/src/nativeTest/kotlin/androidx/room/integration/multiplatformtestapp/test/QueryTest.kt
@@ -21,10 +21,12 @@
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.IO
 
-class SimpleQueryTest : BaseSimpleQueryTest() {
+class QueryTest : BaseQueryTest() {
 
     override fun getRoomDatabase(): SampleDatabase {
-        return Room.inMemoryDatabaseBuilder { SampleDatabase::class.instantiateImpl() }
+        return Room.inMemoryDatabaseBuilder<SampleDatabase> {
+            SampleDatabase::class.instantiateImpl()
+        }
             .setDriver(BundledSQLiteDriver())
             .setQueryCoroutineContext(Dispatchers.IO)
             .build()
diff --git a/room/integration-tests/multiplatformtestapp/src/jvmTest/kotlin/androidx/room/integration/multiplatformtestapp/test/SimpleQueryTest.kt b/room/integration-tests/multiplatformtestapp/src/nativeTest/kotlin/androidx/room/integration/multiplatformtestapp/test/TypeConverterTest.kt
similarity index 74%
copy from room/integration-tests/multiplatformtestapp/src/jvmTest/kotlin/androidx/room/integration/multiplatformtestapp/test/SimpleQueryTest.kt
copy to room/integration-tests/multiplatformtestapp/src/nativeTest/kotlin/androidx/room/integration/multiplatformtestapp/test/TypeConverterTest.kt
index 6be6358f..de89cdd 100644
--- a/room/integration-tests/multiplatformtestapp/src/jvmTest/kotlin/androidx/room/integration/multiplatformtestapp/test/SimpleQueryTest.kt
+++ b/room/integration-tests/multiplatformtestapp/src/nativeTest/kotlin/androidx/room/integration/multiplatformtestapp/test/TypeConverterTest.kt
@@ -17,15 +17,13 @@
 package androidx.room.integration.multiplatformtestapp.test
 
 import androidx.room.Room
+import androidx.room.RoomDatabase
 import androidx.sqlite.driver.bundled.BundledSQLiteDriver
-import kotlinx.coroutines.Dispatchers
 
-class SimpleQueryTest : BaseSimpleQueryTest() {
+class TypeConverterTest : BaseTypeConverterTest() {
 
-    override fun getRoomDatabase(): SampleDatabase {
-        return Room.inMemoryDatabaseBuilder<SampleDatabase>()
+    override fun getDatabaseBuilder(): RoomDatabase.Builder<TestDatabase> {
+        return Room.inMemoryDatabaseBuilder<TestDatabase> { TestDatabase::class.instantiateImpl() }
             .setDriver(BundledSQLiteDriver())
-            .setQueryCoroutineContext(Dispatchers.IO)
-            .build()
     }
 }
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspType.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspType.kt
index 8c0aeb1..18ce9fa 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspType.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspType.kt
@@ -72,8 +72,20 @@
      */
     private val xTypeName: XTypeName by lazy {
         val jvmWildcardType = env.resolveWildcards(typeAlias ?: ksType, scope).let {
-            if (it == ksType) {
-                this
+            if (ksType == it) {
+                if (ksType.arguments != it.arguments) {
+                    // Replacing the type arguments to retain the variances resolved in
+                    // `resolveWildcards`. See https://github.com/google/ksp/issues/1778.
+                    copy(
+                        env = env,
+                        ksType = ksType.replace(it.arguments),
+                        originalKSAnnotations = originalKSAnnotations,
+                        scope = scope,
+                        typeAlias = typeAlias
+                    )
+                } else {
+                    this
+                }
             } else {
                 env.wrap(
                     ksType = it,
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/processor/Context.kt b/room/room-compiler/src/main/kotlin/androidx/room/processor/Context.kt
index 16cce2b..1e6377a 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/processor/Context.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/processor/Context.kt
@@ -31,7 +31,6 @@
 import androidx.room.verifier.DatabaseVerifier
 import androidx.room.vo.BuiltInConverterFlags
 import androidx.room.vo.Warning
-import javax.tools.Diagnostic
 
 class Context private constructor(
     val processingEnv: XProcessingEnv,
@@ -86,17 +85,16 @@
     }
 
     val codeLanguage: CodeLanguage by lazy {
-        if (BooleanProcessorOptions.GENERATE_KOTLIN.getValue(processingEnv)) {
-            if (processingEnv.backend == XProcessingEnv.Backend.KSP) {
+        if (processingEnv.backend == XProcessingEnv.Backend.KSP) {
+            if (BooleanProcessorOptions.GENERATE_KOTLIN.getValue(processingEnv)) {
                 CodeLanguage.KOTLIN
             } else {
-                processingEnv.messager.printMessage(
-                    Diagnostic.Kind.ERROR,
-                    "${BooleanProcessorOptions.GENERATE_KOTLIN.argName} can only be enabled in KSP."
-                )
                 CodeLanguage.JAVA
             }
         } else {
+            if (BooleanProcessorOptions.GENERATE_KOTLIN.getInputValue(processingEnv) == true) {
+                logger.e(ProcessorErrors.INVALID_KOTLIN_CODE_GEN_IN_JAVAC)
+            }
             CodeLanguage.JAVA
         }
     }
@@ -287,7 +285,7 @@
         INCREMENTAL("room.incremental", defaultValue = true),
         EXPAND_PROJECTION("room.expandProjection", defaultValue = false),
         USE_NULL_AWARE_CONVERTER("room.useNullAwareTypeAnalysis", defaultValue = false),
-        GENERATE_KOTLIN("room.generateKotlin", defaultValue = false),
+        GENERATE_KOTLIN("room.generateKotlin", defaultValue = true),
         EXPORT_SCHEMA_RESOURCE("room.exportSchemaResource", defaultValue = false);
 
         /**
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt b/room/room-compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt
index 78e4106..2cdf066 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt
@@ -1158,4 +1158,7 @@
 
     val INVALID_BLOCKING_DAO_FUNCTION_NON_ANDROID = "Only suspend functions are allowed in DAOs" +
         " declared in source sets targeting non-Android platforms."
+
+    val INVALID_KOTLIN_CODE_GEN_IN_JAVAC =
+        "${Context.BooleanProcessorOptions.GENERATE_KOTLIN.argName} can only be enabled in KSP."
 }
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/processor/BaseEntityParserTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/processor/BaseEntityParserTest.kt
index eff1336..e8f12f5 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/processor/BaseEntityParserTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/processor/BaseEntityParserTest.kt
@@ -65,6 +65,7 @@
                 code = ENTITY_PREFIX.format(attributesReplacement, baseClassReplacement) +
                     input + ENTITY_SUFFIX
             ),
+            options = mapOf(Context.BooleanProcessorOptions.GENERATE_KOTLIN.argName to "false"),
             classpath = classpathFiles
         ) { invocation ->
             val entity = invocation.roundEnv
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/processor/DaoProcessorTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/processor/DaoProcessorTest.kt
index 2758547..24b55f7 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/processor/DaoProcessorTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/processor/DaoProcessorTest.kt
@@ -764,6 +764,7 @@
                 ),
                 COMMON.USER
             ),
+            options = mapOf(Context.BooleanProcessorOptions.GENERATE_KOTLIN.argName to "false"),
             classpath = classpathFiles
         ) { invocation: XTestInvocation ->
             val dao = invocation.roundEnv
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/processor/DatabaseProcessorTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/processor/DatabaseProcessorTest.kt
index f74dcbb..63fd4dc 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/processor/DatabaseProcessorTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/processor/DatabaseProcessorTest.kt
@@ -487,6 +487,7 @@
         )
         runProcessorTest(
             sources = listOf(BOOK, BOOK_DAO, DB1, DB2, db1_2),
+            options = mapOf(Context.BooleanProcessorOptions.GENERATE_KOTLIN.argName to "false"),
             createProcessingSteps = { listOf(DatabaseProcessingStep()) }
         ) { result ->
             result.generatedSourceFileWithPath("foo/bar/Db1_Impl.java")
@@ -1465,7 +1466,10 @@
         )
         runProcessorTest(
             sources = listOf(dbSource, USER),
-            options = mapOf("room.schemaLocation" to "schemas/")
+            options = mapOf(
+                "room.schemaLocation" to "schemas/",
+                "room.generateKotlin" to "false"
+            )
         ) { invocation ->
             val dbAnnotationName = "androidx.room.Database"
             val roundElements = mapOf(
@@ -1537,7 +1541,10 @@
                 }
                 """
         )
-        runProcessorTest(sources = listOf(jvmNameInDaoGetter)) { invocation ->
+        runProcessorTest(
+            sources = listOf(jvmNameInDaoGetter),
+            options = mapOf(Context.BooleanProcessorOptions.GENERATE_KOTLIN.argName to "false"),
+        ) { invocation ->
             val element = invocation.processingEnv.requireTypeElement("foo.bar.MyDb")
             DatabaseProcessor(
                 baseContext = invocation.context,
@@ -1614,7 +1621,8 @@
         body: (List<DatabaseView>, XTestInvocation) -> Unit
     ) {
         runProcessorTest(
-            sources = listOf(DB3, BOOK)
+            sources = listOf(DB3, BOOK),
+            options = mapOf(Context.BooleanProcessorOptions.GENERATE_KOTLIN.argName to "false"),
         ) { invocation ->
             val database = invocation.roundEnv
                 .getElementsAnnotatedWith(
@@ -1665,6 +1673,7 @@
         )
         runProcessorTest(
             sources = listOf(BOOK, bookDao) + dbs,
+            options = mapOf(Context.BooleanProcessorOptions.GENERATE_KOTLIN.argName to "false"),
             createProcessingSteps = { listOf(DatabaseProcessingStep()) },
         ) {
             onCompilationResult?.invoke(it)
@@ -1685,7 +1694,8 @@
                 ),
             classpath = classpath,
             options = mapOf(
-                "room.schemaLocation" to schemaFolder.root.absolutePath
+                "room.schemaLocation" to schemaFolder.root.absolutePath,
+                Context.BooleanProcessorOptions.GENERATE_KOTLIN.argName to "false"
             )
         ) { invocation ->
             val entity = invocation.roundEnv
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/processor/DeleteOrUpdateShortcutMethodProcessorTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/processor/DeleteOrUpdateShortcutMethodProcessorTest.kt
index 7f7e12a..80de5d3 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/processor/DeleteOrUpdateShortcutMethodProcessorTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/processor/DeleteOrUpdateShortcutMethodProcessorTest.kt
@@ -795,7 +795,8 @@
             COMMON.GUAVA_ROOM
         )
         runProcessorTest(
-            sources = commonSources + additionalSources + inputSource
+            sources = commonSources + additionalSources + inputSource,
+            options = mapOf(Context.BooleanProcessorOptions.GENERATE_KOTLIN.argName to "false"),
         ) { invocation ->
             val (owner, methods) = invocation.roundEnv
                 .getElementsAnnotatedWith(Dao::class.qualifiedName!!)
@@ -836,7 +837,8 @@
         )
 
         runProcessorTest(
-            sources = commonSources + additionalSources + inputSource
+            sources = commonSources + additionalSources + inputSource,
+            options = mapOf(Context.BooleanProcessorOptions.GENERATE_KOTLIN.argName to "false"),
         ) { invocation ->
             val (owner, methods) = invocation.roundEnv
                 .getElementsAnnotatedWith(Dao::class.qualifiedName!!)
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/processor/InsertOrUpsertShortcutMethodProcessorTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/processor/InsertOrUpsertShortcutMethodProcessorTest.kt
index 45f42288..fa50917 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/processor/InsertOrUpsertShortcutMethodProcessorTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/processor/InsertOrUpsertShortcutMethodProcessorTest.kt
@@ -1122,7 +1122,8 @@
         )
 
         runProcessorTest(
-            sources = commonSources + additionalSources + inputSource
+            sources = commonSources + additionalSources + inputSource,
+            options = mapOf(Context.BooleanProcessorOptions.GENERATE_KOTLIN.argName to "false"),
         ) { invocation ->
             val (owner, methods) = invocation.roundEnv
                 .getElementsAnnotatedWith(Dao::class.qualifiedName!!)
@@ -1162,7 +1163,8 @@
         )
 
         runProcessorTest(
-            sources = commonSources + additionalSources + inputSource
+            sources = commonSources + additionalSources + inputSource,
+            options = mapOf(Context.BooleanProcessorOptions.GENERATE_KOTLIN.argName to "false"),
         ) { invocation ->
             val (owner, methods) = invocation.roundEnv
                 .getElementsAnnotatedWith(Dao::class.qualifiedName!!)
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/processor/QueryMethodProcessorTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/processor/QueryMethodProcessorTest.kt
index 9c40b99..636a827 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/processor/QueryMethodProcessorTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/processor/QueryMethodProcessorTest.kt
@@ -1309,9 +1309,11 @@
             COMMON.NOT_AN_ENTITY, COMMON.ARTIST, COMMON.SONG, COMMON.IMAGE, COMMON.IMAGE_FORMAT,
             COMMON.CONVERTER
         )
+        val allOptions =
+            mapOf(Context.BooleanProcessorOptions.GENERATE_KOTLIN.argName to "false") + options
         runProcessorTest(
             sources = additionalSources + commonSources + inputSource,
-            options = options
+            options = allOptions
         ) { invocation ->
             val (owner, methods) = invocation.roundEnv
                 .getElementsAnnotatedWith(Dao::class.qualifiedName!!)
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/processor/RawQueryMethodProcessorTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/processor/RawQueryMethodProcessorTest.kt
index 805c6ea..c28313e 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/processor/RawQueryMethodProcessorTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/processor/RawQueryMethodProcessorTest.kt
@@ -672,7 +672,8 @@
             COMMON.IMAGE_FORMAT, COMMON.CONVERTER
         )
         runProcessorTest(
-            sources = commonSources + inputSource
+            sources = commonSources + inputSource,
+            options = mapOf(Context.BooleanProcessorOptions.GENERATE_KOTLIN.argName to "false"),
         ) { invocation ->
             val (owner, methods) = invocation.roundEnv
                 .getElementsAnnotatedWith(Dao::class.qualifiedName!!)
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/processor/RemoveUnusedColumnsTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/processor/RemoveUnusedColumnsTest.kt
index 3c39305..439f503 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/processor/RemoveUnusedColumnsTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/processor/RemoveUnusedColumnsTest.kt
@@ -118,7 +118,8 @@
                 listOf(DatabaseProcessingStep())
             },
             options = mapOf(
-                "room.expandProjection" to enableExpandProjection.toString()
+                "room.expandProjection" to enableExpandProjection.toString(),
+                "room.generateKotlin" to "false",
             )
         ) { result ->
             validate(result)
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/solver/BuiltInConverterFlagsTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/solver/BuiltInConverterFlagsTest.kt
index c48870e..177e637 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/solver/BuiltInConverterFlagsTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/solver/BuiltInConverterFlagsTest.kt
@@ -24,6 +24,7 @@
 import androidx.room.compiler.processing.util.Source
 import androidx.room.compiler.processing.util.XTestInvocation
 import androidx.room.compiler.processing.util.runProcessorTest
+import androidx.room.processor.Context
 import androidx.room.processor.ProcessorErrors.CANNOT_FIND_COLUMN_TYPE_ADAPTER
 import androidx.room.processor.ProcessorErrors.CANNOT_FIND_CURSOR_READER
 import org.junit.Test
@@ -177,7 +178,8 @@
             dbAnnotation = dbAnnotation
         )
         runProcessorTest(
-            sources = listOf(source)
+            sources = listOf(source),
+            options = mapOf(Context.BooleanProcessorOptions.GENERATE_KOTLIN.argName to "false"),
         ) { invocation ->
             val subject = invocation.processingEnv.requireTypeElement("MyDatabase")
             DatabaseProcessingStep().process(
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/solver/CustomTypeConverterResolutionTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/solver/CustomTypeConverterResolutionTest.kt
index f4ade0b..c188e08 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/solver/CustomTypeConverterResolutionTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/solver/CustomTypeConverterResolutionTest.kt
@@ -35,6 +35,7 @@
 import androidx.room.ext.CommonTypeNames
 import androidx.room.ext.RoomAnnotationTypeNames
 import androidx.room.ext.RoomTypeNames.ROOM_DB
+import androidx.room.processor.Context
 import androidx.room.processor.ProcessorErrors.CANNOT_BIND_QUERY_PARAMETER_INTO_STMT
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -259,6 +260,7 @@
         runProcessorTest(
             sources = sources + CUSTOM_TYPE_JFO + CUSTOM_TYPE_CONVERTER_JFO +
                 CUSTOM_TYPE_SET_CONVERTER_JFO,
+            options = mapOf(Context.BooleanProcessorOptions.GENERATE_KOTLIN.argName to "false"),
             createProcessingSteps = {
                 listOf(DatabaseProcessingStep())
             },
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/writer/DatabaseWriterTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/writer/DatabaseWriterTest.kt
index 253ff02..ed72d66 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/writer/DatabaseWriterTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/writer/DatabaseWriterTest.kt
@@ -22,6 +22,7 @@
 import androidx.room.compiler.processing.util.CompilationResultSubject
 import androidx.room.compiler.processing.util.Source
 import androidx.room.compiler.processing.util.runProcessorTest
+import androidx.room.processor.Context
 import androidx.testutils.generateAllEnumerations
 import loadTestSource
 import org.junit.Test
@@ -141,6 +142,7 @@
     ) + inputs
     runProcessorTest(
         sources = sources,
+        options = mapOf(Context.BooleanProcessorOptions.GENERATE_KOTLIN.argName to "false"),
         javacProcessors = listOf(RoomProcessor()),
         symbolProcessorProviders = listOf(RoomKspProcessor.Provider()),
         onCompilationResult = onCompilationResult
diff --git a/room/room-gradle-plugin/src/test/java/androidx/room/gradle/RoomAndroidGradlePluginTest.kt b/room/room-gradle-plugin/src/test/java/androidx/room/gradle/RoomAndroidGradlePluginTest.kt
index 02b6c11..cc0132e 100644
--- a/room/room-gradle-plugin/src/test/java/androidx/room/gradle/RoomAndroidGradlePluginTest.kt
+++ b/room/room-gradle-plugin/src/test/java/androidx/room/gradle/RoomAndroidGradlePluginTest.kt
@@ -133,6 +133,7 @@
             |
             |room {
             |${schemaDslLines.joinToString(separator = "\n")}
+            |    generateKotlin = false
             |}
             |
             """.trimMargin()
diff --git a/room/room-paging-guava/src/androidTest/kotlin/androidx/room/paging/guava/LimitOffsetListenableFuturePagingSourceTest.kt b/room/room-paging-guava/src/androidTest/kotlin/androidx/room/paging/guava/LimitOffsetListenableFuturePagingSourceTest.kt
index 0a621a1..af3980f 100644
--- a/room/room-paging-guava/src/androidTest/kotlin/androidx/room/paging/guava/LimitOffsetListenableFuturePagingSourceTest.kt
+++ b/room/room-paging-guava/src/androidTest/kotlin/androidx/room/paging/guava/LimitOffsetListenableFuturePagingSourceTest.kt
@@ -207,7 +207,7 @@
 
     @Test
     fun refresh_consecutively() = setupAndRun { db ->
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val pagingSource = LimitOffsetListenableFuturePagingSourceImpl(db, true)
         val pagingSource2 = LimitOffsetListenableFuturePagingSourceImpl(db, true)
 
@@ -308,7 +308,7 @@
         }
     @Test
     fun refresh_onSuccess() = setupAndRun { db ->
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val pagingSource = LimitOffsetListenableFuturePagingSourceImpl(db, true)
 
         val listenableFuture = pagingSource.refresh(key = 30)
@@ -336,7 +336,7 @@
 
     @Test
     fun append_onSuccess() = setupAndRun { db ->
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val pagingSource = LimitOffsetListenableFuturePagingSourceImpl(db)
         pagingSource.itemCount.set(100) // bypass check for initial load
 
@@ -364,7 +364,7 @@
 
     @Test
     fun prepend_onSuccess() = setupAndRun { db ->
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val pagingSource = LimitOffsetListenableFuturePagingSourceImpl(db)
         pagingSource.itemCount.set(100) // bypass check for initial load
 
@@ -632,7 +632,7 @@
 
     @Test
     fun refresh_AfterCancellation() = setupAndRun { db ->
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val pagingSource = LimitOffsetListenableFuturePagingSourceImpl(db, true)
         pagingSource.itemCount.set(100) // bypass check for initial load
 
@@ -656,7 +656,7 @@
 
     @Test
     fun appendAgain_afterFutureCanceled() = setupAndRun { db ->
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val pagingSource = LimitOffsetListenableFuturePagingSourceImpl(db)
         pagingSource.itemCount.set(100) // bypass check for initial load
 
@@ -680,7 +680,7 @@
 
     @Test
     fun prependAgain_afterFutureCanceled() = setupAndRun { db ->
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val pagingSource = LimitOffsetListenableFuturePagingSourceImpl(db)
         pagingSource.itemCount.set(100) // bypass check for initial load
 
@@ -721,7 +721,7 @@
 
             // run this async separately from queryExecutor
             run {
-                db.dao.addItem(TestItem(101))
+                db.getDao().addItem(TestItem(101))
             }
 
             // tasks in queue [nonInitialLoad, InvalidationTracker(from additem)]
@@ -755,7 +755,7 @@
 
             // run this async separately from queryExecutor
             run {
-                db.dao.addItem(TestItem(101))
+                db.getDao().addItem(TestItem(101))
             }
 
             // tasks in queue [nonInitialLoad, InvalidationTracker(from additem)]
@@ -789,7 +789,7 @@
             }
         }
 
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val listenableFuture = pagingSource.refresh()
 
         val page = listenableFuture.await() as LoadResult.Page
@@ -812,7 +812,7 @@
             }
         }
 
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         pagingSource.itemCount.set(100)
         val listenableFuture = pagingSource.append(key = 50)
 
@@ -836,7 +836,7 @@
             }
         }
 
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         pagingSource.itemCount.set(100)
         val listenableFuture = pagingSource.prepend(key = 50)
 
@@ -875,7 +875,7 @@
             .build()
 
         runTest {
-            db.dao.addAllItems(ITEMS_LIST)
+            db.getDao().addAllItems(ITEMS_LIST)
             queryExecutor.executeAll() // InvalidationTracker from the addAllItems
           test(db, queryExecutor, transactionExecutor)
         }
@@ -1091,7 +1091,7 @@
 
 @Database(entities = [TestItem::class], version = 1, exportSchema = false)
 abstract class LimitOffsetTestDb : RoomDatabase() {
-    abstract val dao: TestItemDao
+    abstract fun getDao(): TestItemDao
 }
 
 @Entity(tableName = "TestItem")
diff --git a/room/room-paging-rxjava2/src/androidTest/kotlin/androidx/room/paging/rxjava2/LimitOffsetRxPagingSourceTest.kt b/room/room-paging-rxjava2/src/androidTest/kotlin/androidx/room/paging/rxjava2/LimitOffsetRxPagingSourceTest.kt
index fca3c49..84cf1d4 100644
--- a/room/room-paging-rxjava2/src/androidTest/kotlin/androidx/room/paging/rxjava2/LimitOffsetRxPagingSourceTest.kt
+++ b/room/room-paging-rxjava2/src/androidTest/kotlin/androidx/room/paging/rxjava2/LimitOffsetRxPagingSourceTest.kt
@@ -87,7 +87,7 @@
 
     @Test
     fun initialLoad() = setupAndRun { db ->
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val pagingSource = LimitOffsetRxPagingSourceImpl(db)
         val single = pagingSource.refresh()
         val result = single.await() as LoadResult.Page
@@ -98,7 +98,7 @@
 
     @Test
     fun simpleAppend() = setupAndRun { db ->
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val pagingSource = LimitOffsetRxPagingSourceImpl(db)
         val single = pagingSource.append(key = 15)
         val result = single.await() as LoadResult.Page
@@ -109,7 +109,7 @@
 
     @Test
     fun simplePrepend() = setupAndRun { db ->
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val pagingSource = LimitOffsetRxPagingSourceImpl(db)
         val single = pagingSource.prepend(key = 20)
         val result = single.await() as LoadResult.Page
@@ -120,7 +120,7 @@
 
     @Test
     fun initialLoad_invalidationTracker_isRegistered() = setupAndRun { db ->
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val pagingSource = LimitOffsetRxPagingSourceImpl(db)
         val single = pagingSource.refresh()
         // run loadSingle to register InvalidationTracker
@@ -131,7 +131,7 @@
 
     @Test
     fun nonInitialLoad_invalidationTracker_isRegistered() = setupAndRun { db ->
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val pagingSource = LimitOffsetRxPagingSourceImpl(db)
         val single = pagingSource.prepend(key = 20)
         // run loadSingle to register InvalidationTracker
@@ -142,7 +142,7 @@
 
     @Test
     fun refresh_singleImmediatelyReturn() = setupAndRun { db ->
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val pagingSource = LimitOffsetRxPagingSourceImpl(db)
         val single = pagingSource.refresh()
 
@@ -163,7 +163,7 @@
 
     @Test
     fun append_singleImmediatelyReturn() = setupAndRun { db ->
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val pagingSource = LimitOffsetRxPagingSourceImpl(db)
         val single = pagingSource.append(key = 10)
 
@@ -184,7 +184,7 @@
 
     @Test
     fun prepend_singleImmediatelyReturn() = setupAndRun { db ->
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val pagingSource = LimitOffsetRxPagingSourceImpl(db)
         val single = pagingSource.prepend(key = 15)
 
@@ -205,7 +205,7 @@
 
     @Test
     fun dbUpdate_invalidatesPagingSource() = setupAndRun { db ->
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val pagingSource = LimitOffsetRxPagingSourceImpl(db)
         val single = pagingSource.append(key = 50)
 
@@ -218,7 +218,7 @@
         assertFalse(pagingSource.invalid)
 
         // this should cause refreshVersionsSync to invalidate pagingSource
-        db.dao.addItem(TestItem(113))
+        db.getDao().addItem(TestItem(113))
         countingTaskExecutorRule.drainTasks(500, TimeUnit.MILLISECONDS)
 
         assertTrue(pagingSource.invalid)
@@ -230,7 +230,7 @@
 
     @Test
     fun append_returnsInvalid() = setupAndRun { db ->
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val pagingSource = LimitOffsetRxPagingSourceImpl(db)
         val single = pagingSource.append(key = 50)
 
@@ -248,7 +248,7 @@
 
     @Test
     fun prepend_returnsInvalid() = setupAndRun { db ->
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val pagingSource = LimitOffsetRxPagingSourceImpl(db)
         val single = pagingSource.prepend(key = 50)
 
@@ -268,7 +268,7 @@
 
     @Test
     fun refresh_consecutively() = setupAndRun { db ->
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val pagingSource = LimitOffsetRxPagingSourceImpl(db)
         val single = pagingSource.refresh()
         val result = single.await() as LoadResult.Page
@@ -286,7 +286,7 @@
 
     @Test
     fun append_consecutively() = setupAndRun { db ->
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val pagingSource = LimitOffsetRxPagingSourceImpl(db)
 
         val single = pagingSource.append(key = 15)
@@ -310,7 +310,7 @@
 
     @Test
     fun prepend_consecutively() = setupAndRun { db ->
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val pagingSource = LimitOffsetRxPagingSourceImpl(db)
 
         val single = pagingSource.prepend(key = 15)
@@ -334,7 +334,7 @@
 
     @Test
     fun refreshAgain_afterDispose() = setupAndRun { db ->
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val pagingSource = LimitOffsetRxPagingSourceImpl(db)
 
         var isDisposed = false
@@ -359,7 +359,7 @@
 
     @Test
     fun appendAgain_afterDispose() = setupAndRun { db ->
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val pagingSource = LimitOffsetRxPagingSourceImpl(db)
 
         var isDisposed = false
@@ -384,7 +384,7 @@
 
     @Test
     fun prependAgain_afterDispose() = setupAndRun { db ->
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val pagingSource = LimitOffsetRxPagingSourceImpl(db)
 
         var isDisposed = false
@@ -416,7 +416,7 @@
         ).setQueryExecutor(queryExecutor)
             .build()
 
-        testDb.dao.addAllItems(ITEMS_LIST)
+        testDb.getDao().addAllItems(ITEMS_LIST)
         queryExecutor.executeAll() // add items first
 
         runTest {
@@ -454,7 +454,7 @@
             LimitOffsetTestDb::class.java
         ).build()
 
-        testDb.dao.addAllItems(ITEMS_LIST)
+        testDb.getDao().addAllItems(ITEMS_LIST)
         val pagingSource = LimitOffsetRxPagingSourceImpl(testDb)
 
         runBlocking {
@@ -490,7 +490,7 @@
             }
         }
 
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val single = pagingSource.refresh()
         val result = single.await() as LoadResult.Page
         assertThat(result.data).containsExactlyElementsIn(
@@ -509,7 +509,7 @@
             }
         }
 
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val single = pagingSource.append(key = 15)
         val result = single.await() as LoadResult.Page
         assertThat(result.data).containsExactlyElementsIn(
@@ -528,7 +528,7 @@
             }
         }
 
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val single = pagingSource.prepend(key = 15)
         val result = single.await() as LoadResult.Page
         assertThat(result.data).containsExactlyElementsIn(
@@ -673,7 +673,7 @@
 
 @Database(entities = [TestItem::class], version = 1, exportSchema = false)
 abstract class LimitOffsetTestDb : RoomDatabase() {
-    abstract val dao: TestItemDao
+    abstract fun getDao(): TestItemDao
 }
 
 @Entity(tableName = "TestItem")
diff --git a/room/room-paging-rxjava3/src/androidTest/kotlin/androidx/room/paging/rxjava3/LimitOffsetRxPagingSourceTest.kt b/room/room-paging-rxjava3/src/androidTest/kotlin/androidx/room/paging/rxjava3/LimitOffsetRxPagingSourceTest.kt
index 1684489..df8ac9b 100644
--- a/room/room-paging-rxjava3/src/androidTest/kotlin/androidx/room/paging/rxjava3/LimitOffsetRxPagingSourceTest.kt
+++ b/room/room-paging-rxjava3/src/androidTest/kotlin/androidx/room/paging/rxjava3/LimitOffsetRxPagingSourceTest.kt
@@ -87,7 +87,7 @@
 
     @Test
     fun initialLoad() = setupAndRun { db ->
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val pagingSource = LimitOffsetRxPagingSourceImpl(db)
         val single = pagingSource.refresh()
         val result = single.await() as LoadResult.Page
@@ -98,7 +98,7 @@
 
     @Test
     fun simpleAppend() = setupAndRun { db ->
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val pagingSource = LimitOffsetRxPagingSourceImpl(db)
         val single = pagingSource.append(key = 15)
         val result = single.await() as LoadResult.Page
@@ -109,7 +109,7 @@
 
     @Test
     fun simplePrepend() = setupAndRun { db ->
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val pagingSource = LimitOffsetRxPagingSourceImpl(db)
         val single = pagingSource.prepend(key = 20)
         val result = single.await() as LoadResult.Page
@@ -120,7 +120,7 @@
 
     @Test
     fun initialLoad_invalidationTracker_isRegistered() = setupAndRun { db ->
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val pagingSource = LimitOffsetRxPagingSourceImpl(db)
         val single = pagingSource.refresh()
         // run loadSingle to register InvalidationTracker
@@ -131,7 +131,7 @@
 
     @Test
     fun nonInitialLoad_invalidationTracker_isRegistered() = setupAndRun { db ->
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val pagingSource = LimitOffsetRxPagingSourceImpl(db)
         val single = pagingSource.prepend(key = 20)
         // run loadSingle to register InvalidationTracker
@@ -142,7 +142,7 @@
 
     @Test
     fun refresh_singleImmediatelyReturn() = setupAndRun { db ->
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val pagingSource = LimitOffsetRxPagingSourceImpl(db)
         val single = pagingSource.refresh()
 
@@ -163,7 +163,7 @@
 
     @Test
     fun append_singleImmediatelyReturn() = setupAndRun { db ->
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val pagingSource = LimitOffsetRxPagingSourceImpl(db)
         val single = pagingSource.append(key = 10)
 
@@ -184,7 +184,7 @@
 
     @Test
     fun prepend_singleImmediatelyReturn() = setupAndRun { db ->
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val pagingSource = LimitOffsetRxPagingSourceImpl(db)
         val single = pagingSource.prepend(key = 15)
 
@@ -205,7 +205,7 @@
 
     @Test
     fun dbUpdate_invalidatesPagingSource() = setupAndRun { db ->
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val pagingSource = LimitOffsetRxPagingSourceImpl(db)
         val single = pagingSource.append(key = 50)
 
@@ -218,7 +218,7 @@
         assertFalse(pagingSource.invalid)
 
         // this should cause refreshVersionsSync to invalidate pagingSource
-        db.dao.addItem(TestItem(113))
+        db.getDao().addItem(TestItem(113))
         countingTaskExecutorRule.drainTasks(500, TimeUnit.MILLISECONDS)
 
         assertTrue(pagingSource.invalid)
@@ -230,7 +230,7 @@
 
     @Test
     fun append_returnsInvalid() = setupAndRun { db ->
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val pagingSource = LimitOffsetRxPagingSourceImpl(db)
         val single = pagingSource.append(key = 50)
 
@@ -248,7 +248,7 @@
 
     @Test
     fun prepend_returnsInvalid() = setupAndRun { db ->
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val pagingSource = LimitOffsetRxPagingSourceImpl(db)
         val single = pagingSource.prepend(key = 50)
 
@@ -268,7 +268,7 @@
 
     @Test
     fun refresh_consecutively() = setupAndRun { db ->
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val pagingSource = LimitOffsetRxPagingSourceImpl(db)
         val single = pagingSource.refresh()
         val result = single.await() as LoadResult.Page
@@ -286,7 +286,7 @@
 
     @Test
     fun append_consecutively() = setupAndRun { db ->
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val pagingSource = LimitOffsetRxPagingSourceImpl(db)
 
         val single = pagingSource.append(key = 15)
@@ -310,7 +310,7 @@
 
     @Test
     fun prepend_consecutively() = setupAndRun { db ->
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val pagingSource = LimitOffsetRxPagingSourceImpl(db)
 
         val single = pagingSource.prepend(key = 15)
@@ -334,7 +334,7 @@
 
     @Test
     fun refreshAgain_afterDispose() = setupAndRun { db ->
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val pagingSource = LimitOffsetRxPagingSourceImpl(db)
 
         var isDisposed = false
@@ -359,7 +359,7 @@
 
     @Test
     fun appendAgain_afterDispose() = setupAndRun { db ->
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val pagingSource = LimitOffsetRxPagingSourceImpl(db)
 
         var isDisposed = false
@@ -384,7 +384,7 @@
 
     @Test
     fun prependAgain_afterDispose() = setupAndRun { db ->
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val pagingSource = LimitOffsetRxPagingSourceImpl(db)
 
         var isDisposed = false
@@ -416,7 +416,7 @@
         ).setQueryExecutor(queryExecutor)
             .build()
 
-        testDb.dao.addAllItems(ITEMS_LIST)
+        testDb.getDao().addAllItems(ITEMS_LIST)
         queryExecutor.executeAll() // add items first
 
         runTest {
@@ -454,7 +454,7 @@
             LimitOffsetTestDb::class.java
         ).build()
 
-        testDb.dao.addAllItems(ITEMS_LIST)
+        testDb.getDao().addAllItems(ITEMS_LIST)
         val pagingSource = LimitOffsetRxPagingSourceImpl(testDb)
 
         runBlocking {
@@ -489,7 +489,7 @@
             }
         }
 
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val single = pagingSource.refresh()
         val result = single.await() as LoadResult.Page
         assertThat(result.data).containsExactlyElementsIn(
@@ -508,7 +508,7 @@
             }
         }
 
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val single = pagingSource.append(key = 15)
         val result = single.await() as LoadResult.Page
         assertThat(result.data).containsExactlyElementsIn(
@@ -527,7 +527,7 @@
             }
         }
 
-        db.dao.addAllItems(ITEMS_LIST)
+        db.getDao().addAllItems(ITEMS_LIST)
         val single = pagingSource.prepend(key = 15)
         val result = single.await() as LoadResult.Page
         assertThat(result.data).containsExactlyElementsIn(
@@ -672,7 +672,7 @@
 
 @Database(entities = [TestItem::class], version = 1, exportSchema = false)
 abstract class LimitOffsetTestDb : RoomDatabase() {
-    abstract val dao: TestItemDao
+    abstract fun getDao(): TestItemDao
 }
 
 @Entity(tableName = "TestItem")
diff --git a/room/room-paging/src/androidTest/kotlin/androidx/room/paging/LimitOffsetPagingSourceTest.kt b/room/room-paging/src/androidTest/kotlin/androidx/room/paging/LimitOffsetPagingSourceTest.kt
index 65518e8..6743669 100644
--- a/room/room-paging/src/androidTest/kotlin/androidx/room/paging/LimitOffsetPagingSourceTest.kt
+++ b/room/room-paging/src/androidTest/kotlin/androidx/room/paging/LimitOffsetPagingSourceTest.kt
@@ -68,7 +68,7 @@
             ApplicationProvider.getApplicationContext(),
             LimitOffsetTestDb::class.java,
         ).build()
-        dao = database.dao
+        dao = database.getDao()
     }
 
     @After
@@ -735,7 +735,7 @@
             it.run()
         }.setQueryExecutor(queryExecutor)
             .build()
-        dao = db.dao
+        dao = db.getDao()
     }
 
     @After
diff --git a/room/room-paging/src/androidTest/kotlin/androidx/room/paging/LimitOffsetTestDb.kt b/room/room-paging/src/androidTest/kotlin/androidx/room/paging/LimitOffsetTestDb.kt
index 8d31c44..6a9c989 100644
--- a/room/room-paging/src/androidTest/kotlin/androidx/room/paging/LimitOffsetTestDb.kt
+++ b/room/room-paging/src/androidTest/kotlin/androidx/room/paging/LimitOffsetTestDb.kt
@@ -21,5 +21,5 @@
 
 @Database(entities = [TestItem::class], version = 1, exportSchema = false)
 abstract class LimitOffsetTestDb : RoomDatabase() {
-    abstract val dao: TestItemDao
+    abstract fun getDao(): TestItemDao
 }
diff --git a/room/room-runtime/build.gradle b/room/room-runtime/build.gradle
index 3b4f210..9b0a135 100644
--- a/room/room-runtime/build.gradle
+++ b/room/room-runtime/build.gradle
@@ -220,10 +220,6 @@
     add("kspAndroidAndroidTest", project(":room:room-compiler"))
 }
 
-ksp {
-    arg("room.generateKotlin", "true")
-}
-
 androidx {
     name = "Room-Runtime"
     type = LibraryType.PUBLISHED_LIBRARY
diff --git a/room/room-runtime/src/androidMain/kotlin/androidx/room/DatabaseConfiguration.android.kt b/room/room-runtime/src/androidMain/kotlin/androidx/room/DatabaseConfiguration.android.kt
index 1307781..70201df 100644
--- a/room/room-runtime/src/androidMain/kotlin/androidx/room/DatabaseConfiguration.android.kt
+++ b/room/room-runtime/src/androidMain/kotlin/androidx/room/DatabaseConfiguration.android.kt
@@ -37,54 +37,39 @@
 @SuppressLint("LambdaLast")
 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
 constructor(
-    /**
-     * The context to use while connecting to the database.
-     */
+    /* The context to use while connecting to the database. */
     @JvmField
     val context: Context,
 
-    /**
-     * The name of the database file or null if it is an in-memory database.
-     */
+    /* The name of the database file or null if it is an in-memory database. */
     @JvmField
     actual val name: String?,
 
-    /**
-     * The factory to use to access the database.
-     */
+    /* The factory to use to access the database. */
     @JvmField
     val sqliteOpenHelperFactory: SupportSQLiteOpenHelper.Factory?,
 
-    /**
-     * Collection of available migrations.
-     */
+    /* Collection of available migrations. */
     @JvmField
     actual val migrationContainer: RoomDatabase.MigrationContainer,
 
+    /* Database callbacks. */
     @JvmField
     actual val callbacks: List<RoomDatabase.Callback>?,
 
-    /**
-     * Whether Room should throw an exception for queries run on the main thread.
-     */
+    /* Whether Room should throw an exception for queries run on the main thread. */
     @JvmField
     val allowMainThreadQueries: Boolean,
 
-    /**
-     * The journal mode for this database.
-     */
+    /* The journal mode for this database. */
     @JvmField
     actual val journalMode: RoomDatabase.JournalMode,
 
-    /**
-     * The Executor used to execute asynchronous queries.
-     */
+    /* The Executor used to execute asynchronous queries. */
     @JvmField
     val queryExecutor: Executor,
 
-    /**
-     * The Executor used to execute asynchronous transactions.
-     */
+    /* The Executor used to execute asynchronous transactions. */
     @JvmField
     val transactionExecutor: Executor,
 
@@ -97,38 +82,49 @@
     @JvmField
     val multiInstanceInvalidationServiceIntent: Intent?,
 
+    /* Whether Room should throw an exception for missing migrations. */
     @JvmField
     actual val requireMigration: Boolean,
 
+    /* Whether Room will fallback to destructive migrations on downgrades only .*/
     @JvmField
     actual val allowDestructiveMigrationOnDowngrade: Boolean,
 
     internal actual val migrationNotRequiredFrom: Set<Int>?,
 
+    /* Asset path of pre-package database or null if not used. */
     @JvmField
     val copyFromAssetPath: String?,
 
+    /* File of pre-package database or null if not used. */
     @JvmField
     val copyFromFile: File?,
 
+    /* Input stream of pre-package database or null if not used. */
     @JvmField
     val copyFromInputStream: Callable<InputStream>?,
 
+    /* Callback when Room uses a pre-packaged database. */
     @JvmField
     val prepackagedDatabaseCallback: RoomDatabase.PrepackagedDatabaseCallback?,
 
+    /* List of provided type converters. */
     @JvmField
     actual val typeConverters: List<Any>,
 
+    /* List of provided auto migration specs. */
     @JvmField
     actual val autoMigrationSpecs: List<AutoMigrationSpec>,
 
+    /* Whether Room will delete all tables or only known tables during destructive migrations. */
     @JvmField
-    val allowDestructiveMigrationForAllTables: Boolean,
+    actual val allowDestructiveMigrationForAllTables: Boolean,
 
+    /* The SQLite Driver for the database. */
     @JvmField
     actual val sqliteDriver: SQLiteDriver?,
 
+    /* The Coroutine context for the database. */
     @JvmField
     actual val queryCoroutineContext: CoroutineContext?,
 ) {
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 e8f7d67..40bbd48 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
@@ -115,16 +115,6 @@
         block: suspend (Transactor) -> R
     ): R = connectionPool.useConnection(isReadOnly, block)
 
-    override fun dropAllTables(connection: SQLiteConnection) {
-        if (configuration.allowDestructiveMigrationForAllTables) {
-            // Drops all tables (excluding special ones)
-            super.dropAllTables(connection)
-        } else {
-            // Drops known tables (Room entity tables)
-            openDelegate.dropAllTables(connection)
-        }
-    }
-
     fun close() {
         connectionPool.close()
     }
diff --git a/room/room-runtime/src/androidMain/kotlin/androidx/room/RoomDatabase.android.kt b/room/room-runtime/src/androidMain/kotlin/androidx/room/RoomDatabase.android.kt
index 0a6b0ea..7421bac 100644
--- a/room/room-runtime/src/androidMain/kotlin/androidx/room/RoomDatabase.android.kt
+++ b/room/room-runtime/src/androidMain/kotlin/androidx/room/RoomDatabase.android.kt
@@ -924,18 +924,14 @@
         private var queryCallback: QueryCallback? = null
         private var queryCallbackExecutor: Executor? = null
         private val typeConverters: MutableList<Any> = mutableListOf()
-        private var autoMigrationSpecs: MutableList<AutoMigrationSpec> = mutableListOf()
-
         private var queryExecutor: Executor? = null
-
         private var transactionExecutor: Executor? = null
+
         private var supportOpenHelperFactory: SupportSQLiteOpenHelper.Factory? = null
         private var allowMainThreadQueries = false
         private var journalMode: JournalMode = JournalMode.AUTOMATIC
         private var multiInstanceInvalidationIntent: Intent? = null
-        private var requireMigration: Boolean = true
-        private var allowDestructiveMigrationOnDowngrade = false
-        private var allowDestructiveMigrationForAllTables = false
+
         private var autoCloseTimeout = -1L
         private var autoCloseTimeUnit: TimeUnit? = null
 
@@ -943,6 +939,11 @@
          * Migrations, mapped by from-to pairs.
          */
         private val migrationContainer: MigrationContainer = MigrationContainer()
+
+        /**
+         * Versions that don't require migrations, configured via
+         * [fallbackToDestructiveMigrationFrom].
+         */
         private var migrationsNotRequiredFrom: MutableSet<Int> = mutableSetOf()
 
         /**
@@ -950,7 +951,14 @@
          * [addMigrations] for later validation that makes those versions don't
          * match any versions passed to [fallbackToDestructiveMigrationFrom].
          */
-        private var migrationStartAndEndVersions: MutableSet<Int>? = null
+        private val migrationStartAndEndVersions = mutableSetOf<Int>()
+
+        private val autoMigrationSpecs: MutableList<AutoMigrationSpec> = mutableListOf()
+
+        private var requireMigration: Boolean = true
+        private var allowDestructiveMigrationOnDowngrade = false
+        private var allowDestructiveMigrationForAllTables = false
+
         private var copyFromAssetPath: String? = null
         private var copyFromFile: File? = null
         private var copyFromInputStream: Callable<InputStream>? = null
@@ -1149,42 +1157,35 @@
         /**
          * Adds a migration to the builder.
          *
-         * Each Migration has a start and end versions and Room runs these migrations to bring the
+         * Each [Migration] has a start and end versions and Room runs these migrations to bring the
          * database to the latest version.
          *
-         * If a migration item is missing between current version and the latest version, Room
-         * will clear the database and recreate so even if you have no changes between 2 versions,
-         * you should still provide a Migration object to the builder.
-         *
          * A migration can handle more than 1 version (e.g. if you have a faster path to choose when
-         * going version 3 to 5 without going to version 4). If Room opens a database at version
-         * 3 and latest version is &gt;= 5, Room will use the migration object that can migrate from
-         * 3 to 5 instead of 3 to 4 and 4 to 5.
+         * going from version 3 to 5 without going to version 4). If Room opens a database at
+         * version 3 and latest version is >= 5, Room will use the migration object that can migrate
+         * from 3 to 5 instead of 3 to 4 and 4 to 5.
          *
-         * @param migrations The migration object that can modify the database and to the necessary
-         * changes.
+         * @param migrations The migration objects that modify the database schema with the
+         * necessary changes for a version change.
          * @return This builder instance.
          */
-        open fun addMigrations(vararg migrations: Migration) = apply {
-            if (migrationStartAndEndVersions == null) {
-                migrationStartAndEndVersions = HashSet()
-            }
+        actual open fun addMigrations(vararg migrations: Migration) = apply {
             for (migration in migrations) {
-                migrationStartAndEndVersions!!.add(migration.startVersion)
-                migrationStartAndEndVersions!!.add(migration.endVersion)
+                migrationStartAndEndVersions.add(migration.startVersion)
+                migrationStartAndEndVersions.add(migration.endVersion)
             }
             migrationContainer.addMigrations(*migrations)
         }
 
         /**
-         * Adds an auto migration spec to the builder.
+         * Adds an auto migration spec instance to the builder.
          *
          * @param autoMigrationSpec The auto migration object that is annotated with
-         * [AutoMigrationSpec] and is declared in an [AutoMigration] annotation.
+         * [ProvidedAutoMigrationSpec] and is declared in an [AutoMigration] annotation.
          * @return This builder instance.
          */
         @Suppress("MissingGetterMatchingBuilder")
-        open fun addAutoMigrationSpec(autoMigrationSpec: AutoMigrationSpec) = apply {
+        actual open fun addAutoMigrationSpec(autoMigrationSpec: AutoMigrationSpec) = apply {
             this.autoMigrationSpecs.add(autoMigrationSpec)
         }
 
@@ -1207,18 +1208,16 @@
         /**
          * Sets the journal mode for this database.
          *
-         * This value is ignored if the builder is initialized with
-         * [Room.inMemoryDatabaseBuilder].
-         *
-         * The journal mode should be consistent across multiple instances of
-         * [RoomDatabase] for a single SQLite database file.
+         * The value is ignored if the builder is for an 'in-memory database'. The journal mode
+         * should be consistent across multiple instances of [RoomDatabase] for a single SQLite
+         * database file.
          *
          * The default value is [JournalMode.AUTOMATIC].
          *
          * @param journalMode The journal mode.
          * @return This builder instance.
          */
-        open fun setJournalMode(journalMode: JournalMode) = apply {
+        actual open fun setJournalMode(journalMode: JournalMode) = apply {
             this.journalMode = journalMode
         }
 
@@ -1357,7 +1356,7 @@
          * @return This builder instance.
          */
         @Deprecated(
-            message = "Replace by overloaded version with parameter to indicate if all tables" +
+            message = "Replace by overloaded version with parameter to indicate if all tables " +
                 "should be dropped or not.",
             replaceWith = ReplaceWith("fallbackToDestructiveMigration(false)")
         )
@@ -1372,13 +1371,10 @@
          * migrate old database schemas to the latest schema version are not found.
          *
          * When the database version on the device does not match the latest schema version, Room
-         * runs necessary [Migration]s on the database.
-         *
-         * If it cannot find the set of [Migration]s that will bring the database to the
-         * current version, it will throw an [IllegalStateException].
-         *
-         * You can call this method to change this behavior to re-create the database tables instead
-         * of crashing.
+         * runs necessary [Migration]s on the database. If it cannot find the set of [Migration]s
+         * that will bring the database to the current version, it will throw an
+         * [IllegalStateException]. You can call this method to change this behavior to re-create
+         * the database tables instead of crashing.
          *
          * If the database was create from an asset or a file then Room will try to use the same
          * file to re-create the database, otherwise this will delete all of the data in the
@@ -1388,11 +1384,12 @@
          * [fallbackToDestructiveMigrationOnDowngrade].
          *
          * @param dropAllTables Set to `true` if all tables should be dropped during destructive
-         * migration including those not managed by Room.
+         * migration including those not managed by Room. Recommended value is `true` as otherwise
+         * Room could leave obsolete data when table names or existence changes between versions.
          * @return This builder instance.
          */
         @Suppress("BuilderSetStyle") // Overload of existing API
-        fun fallbackToDestructiveMigration(dropAllTables: Boolean) = apply {
+        actual fun fallbackToDestructiveMigration(dropAllTables: Boolean) = apply {
             this.requireMigration = false
             this.allowDestructiveMigrationOnDowngrade = true
             this.allowDestructiveMigrationForAllTables = dropAllTables
@@ -1407,7 +1404,7 @@
          * @return This builder instance.
          */
         @Deprecated(
-            message = "Replace by overloaded version with parameter to indicate if all tables" +
+            message = "Replace by overloaded version with parameter to indicate if all tables " +
                 "should be dropped or not.",
             replaceWith = ReplaceWith("fallbackToDestructiveMigrationOnDowngrade(false)")
         )
@@ -1428,7 +1425,7 @@
          * @return This builder instance.
          */
         @Suppress("BuilderSetStyle") // Overload of existing API
-        fun fallbackToDestructiveMigrationOnDowngrade(dropAllTables: Boolean) = apply {
+        actual fun fallbackToDestructiveMigrationOnDowngrade(dropAllTables: Boolean) = apply {
             this.requireMigration = true
             this.allowDestructiveMigrationOnDowngrade = true
             this.allowDestructiveMigrationForAllTables = dropAllTables
@@ -1456,7 +1453,7 @@
          * @return This builder instance.
          */
         @Deprecated(
-            message = "Replace by overloaded version with parameter to indicate if all tables" +
+            message = "Replace by overloaded version with parameter to indicate if all tables " +
                 "should be dropped or not.",
             replaceWith = ReplaceWith("fallbackToDestructiveMigrationFrom(false, startVersions)")
         )
@@ -1470,16 +1467,16 @@
          * Informs Room that it is allowed to destructively recreate database tables from specific
          * starting schema versions.
          *
-         * This functionality is the same as that provided by
-         * [fallbackToDestructiveMigration], except that this method allows the
-         * specification of a set of schema versions for which destructive recreation is allowed.
+         * This functionality is the same [fallbackToDestructiveMigration], except that this method
+         * allows the specification of a set of schema versions for which destructive recreation is
+         * allowed.
          *
          * Using this method is preferable to [fallbackToDestructiveMigration] if you want
          * to allow destructive migrations from some schema versions while still taking advantage
          * of exceptions being thrown due to unintentionally missing migrations.
          *
          * Note: No versions passed to this method may also exist as either starting or ending
-         * versions in the [Migration]s provided to [addMigrations]. If a
+         * versions in the [Migration]s provided via [addMigrations]. If a
          * version passed to this method is found as a starting or ending version in a Migration, an
          * exception will be thrown.
          *
@@ -1489,8 +1486,12 @@
          * migration.
          * @return This builder instance.
          */
-        @Suppress("BuilderSetStyle") // Overload of existing API
-        open fun fallbackToDestructiveMigrationFrom(
+        @Suppress(
+            "BuilderSetStyle", // Overload of existing API
+            "MissingJvmstatic", // No need for @JvmOverloads due to an overload already existing
+        )
+        actual open fun fallbackToDestructiveMigrationFrom(
+            @Suppress("KotlinDefaultParameterOrder") // There is a vararg that must be last
             dropAllTables: Boolean,
             vararg startVersions: Int
         ) = apply {
@@ -1533,13 +1534,13 @@
         }
 
         /**
-         * Adds a type converter instance to this database.
+         * Adds a type converter instance to the builder.
          *
-         * @param typeConverter The converter. It must be an instance of a class annotated with
-         * [ProvidedTypeConverter] otherwise Room will throw an exception.
+         * @param typeConverter The converter instance that is annotated with
+         * [ProvidedTypeConverter].
          * @return This builder instance.
          */
-        open fun addTypeConverter(typeConverter: Any) = apply {
+        actual open fun addTypeConverter(typeConverter: Any) = apply {
             this.typeConverters.add(typeConverter)
         }
 
@@ -1647,17 +1648,8 @@
             } else if (queryExecutor == null) {
                 queryExecutor = transactionExecutor
             }
-            if (migrationStartAndEndVersions != null) {
-                for (version in migrationStartAndEndVersions!!) {
-                    require(!migrationsNotRequiredFrom.contains(version)) {
-                        "Inconsistency detected. A Migration was supplied to " +
-                            "addMigration(Migration... migrations) that has a start " +
-                            "or end version equal to a start version supplied to " +
-                            "fallbackToDestructiveMigrationFrom(int... " +
-                            "startVersions). Start version: $version"
-                    }
-                }
-            }
+
+            validateMigrationsNotRequired(migrationStartAndEndVersions, migrationsNotRequiredFrom)
 
             val initialFactory: SupportSQLiteOpenHelper.Factory? =
                 if (driver == null && supportOpenHelperFactory == null) {
@@ -1733,28 +1725,28 @@
                 }
             }
             val configuration = DatabaseConfiguration(
-                context,
-                name,
-                supportOpenHelperFactory,
-                migrationContainer,
-                callbacks,
-                allowMainThreadQueries,
-                journalMode.resolve(context),
-                requireNotNull(queryExecutor),
-                requireNotNull(transactionExecutor),
-                multiInstanceInvalidationIntent,
-                requireMigration,
-                allowDestructiveMigrationOnDowngrade,
-                migrationsNotRequiredFrom,
-                copyFromAssetPath,
-                copyFromFile,
-                copyFromInputStream,
-                prepackagedDatabaseCallback,
-                typeConverters,
-                autoMigrationSpecs,
-                allowDestructiveMigrationForAllTables,
-                driver,
-                queryCoroutineContext,
+                context = context,
+                name = name,
+                sqliteOpenHelperFactory = supportOpenHelperFactory,
+                migrationContainer = migrationContainer,
+                callbacks = callbacks,
+                allowMainThreadQueries = allowMainThreadQueries,
+                journalMode = journalMode.resolve(context),
+                queryExecutor = requireNotNull(queryExecutor),
+                transactionExecutor = requireNotNull(transactionExecutor),
+                multiInstanceInvalidationServiceIntent = multiInstanceInvalidationIntent,
+                requireMigration = requireMigration,
+                allowDestructiveMigrationOnDowngrade = allowDestructiveMigrationOnDowngrade,
+                migrationNotRequiredFrom = migrationsNotRequiredFrom,
+                copyFromAssetPath = copyFromAssetPath,
+                copyFromFile = copyFromFile,
+                copyFromInputStream = copyFromInputStream,
+                prepackagedDatabaseCallback = prepackagedDatabaseCallback,
+                typeConverters = typeConverters,
+                autoMigrationSpecs = autoMigrationSpecs,
+                allowDestructiveMigrationForAllTables = allowDestructiveMigrationForAllTables,
+                sqliteDriver = driver,
+                queryCoroutineContext = queryCoroutineContext,
             )
             val db = factory?.invoke() ?: findAndInstantiateDatabaseImpl(klass.java)
             db.init(configuration)
diff --git a/room/room-runtime/src/androidMain/kotlin/androidx/room/migration/Migration.android.kt b/room/room-runtime/src/androidMain/kotlin/androidx/room/migration/Migration.android.kt
index 1adc4fe..353ad4b 100644
--- a/room/room-runtime/src/androidMain/kotlin/androidx/room/migration/Migration.android.kt
+++ b/room/room-runtime/src/androidMain/kotlin/androidx/room/migration/Migration.android.kt
@@ -37,7 +37,7 @@
  *
  * @constructor Creates a new migration between [startVersion] and [endVersion] inclusive.
  */
-actual abstract class Migration(
+actual abstract class Migration actual constructor(
     @JvmField
     actual val startVersion: Int,
     @JvmField
diff --git a/room/room-runtime/src/commonMain/kotlin/androidx/room/DatabaseConfiguration.kt b/room/room-runtime/src/commonMain/kotlin/androidx/room/DatabaseConfiguration.kt
index f5a89e9..cfa6ff2 100644
--- a/room/room-runtime/src/commonMain/kotlin/androidx/room/DatabaseConfiguration.kt
+++ b/room/room-runtime/src/commonMain/kotlin/androidx/room/DatabaseConfiguration.kt
@@ -28,13 +28,23 @@
     val name: String?
     /* Collection of available migrations. */
     val migrationContainer: RoomDatabase.MigrationContainer
+    /* Database callbacks. */
     val callbacks: List<RoomDatabase.Callback>?
+    /* The journal mode for this database. */
     val journalMode: RoomDatabase.JournalMode
+    /* Whether Room should throw an exception for missing migrations. */
     val requireMigration: Boolean
+    /* Whether Room will fallback to destructive migrations on downgrades only .*/
     val allowDestructiveMigrationOnDowngrade: Boolean
     internal val migrationNotRequiredFrom: Set<Int>?
+    /* List of provided type converters. */
     val typeConverters: List<Any>
+    /* List of provided auto migration specs. */
     val autoMigrationSpecs: List<AutoMigrationSpec>
+    /* Whether Room will delete all tables or only known tables during destructive migrations. */
+    val allowDestructiveMigrationForAllTables: Boolean
+    /* The SQLite Driver for the database. */
     val sqliteDriver: SQLiteDriver?
+    /* The Coroutine context for the database. */
     val queryCoroutineContext: CoroutineContext?
 }
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 8930927..d1f2a0d 100644
--- a/room/room-runtime/src/commonMain/kotlin/androidx/room/RoomConnectionManager.kt
+++ b/room/room-runtime/src/commonMain/kotlin/androidx/room/RoomConnectionManager.kt
@@ -183,21 +183,27 @@
         }
     }
 
-    protected open fun dropAllTables(connection: SQLiteConnection) {
-        connection.prepare(
-            "SELECT name FROM sqlite_master WHERE type = 'table'"
-        ).use { statement ->
-            buildList {
-                while (statement.step()) {
-                    val name = statement.getText(0)
-                    if (name.startsWith("sqlite_") || name == "android_metadata") {
-                        continue
+    private fun dropAllTables(connection: SQLiteConnection) {
+        if (configuration.allowDestructiveMigrationForAllTables) {
+            // Drops all tables (excluding special ones)
+            connection.prepare(
+                "SELECT name FROM sqlite_master WHERE type = 'table'"
+            ).use { statement ->
+                buildList {
+                    while (statement.step()) {
+                        val name = statement.getText(0)
+                        if (name.startsWith("sqlite_") || name == "android_metadata") {
+                            continue
+                        }
+                        add(name)
                     }
-                    add(name)
                 }
+            }.forEach { table ->
+                connection.execSQL("DROP TABLE IF EXISTS $table")
             }
-        }.forEach { table ->
-            connection.execSQL("DROP TABLE IF EXISTS $table")
+        } else {
+            // Drops known tables (Room entity tables)
+            openDelegate.dropAllTables(connection)
         }
     }
 
diff --git a/room/room-runtime/src/commonMain/kotlin/androidx/room/RoomDatabase.kt b/room/room-runtime/src/commonMain/kotlin/androidx/room/RoomDatabase.kt
index 919cf1a..8e59497 100644
--- a/room/room-runtime/src/commonMain/kotlin/androidx/room/RoomDatabase.kt
+++ b/room/room-runtime/src/commonMain/kotlin/androidx/room/RoomDatabase.kt
@@ -226,6 +226,117 @@
         fun setDriver(driver: SQLiteDriver): Builder<T>
 
         /**
+         * Adds a migration to the builder.
+         *
+         * Each [Migration] has a start and end versions and Room runs these migrations to bring the
+         * database to the latest version.
+         *
+         * A migration can handle more than 1 version (e.g. if you have a faster path to choose when
+         * going from version 3 to 5 without going to version 4). If Room opens a database at
+         * version 3 and latest version is >= 5, Room will use the migration object that can migrate
+         * from 3 to 5 instead of 3 to 4 and 4 to 5.
+         *
+         * @param migrations The migration objects that modify the database schema with the
+         * necessary changes for a version change.
+         * @return This builder instance.
+         */
+        fun addMigrations(vararg migrations: Migration): Builder<T>
+
+        /**
+         * Adds an auto migration spec instance to the builder.
+         *
+         * @param autoMigrationSpec The auto migration object that is annotated with
+         * [ProvidedAutoMigrationSpec] and is declared in an [AutoMigration] annotation.
+         * @return This builder instance.
+         */
+        fun addAutoMigrationSpec(autoMigrationSpec: AutoMigrationSpec): Builder<T>
+
+        /**
+         * Allows Room to destructively recreate database tables if [Migration]s that would
+         * migrate old database schemas to the latest schema version are not found.
+         *
+         * When the database version on the device does not match the latest schema version, Room
+         * runs necessary [Migration]s on the database. If it cannot find the set of [Migration]s
+         * that will bring the database to the current version, it will throw an
+         * [IllegalStateException]. You can call this method to change this behavior to re-create
+         * the database tables instead of crashing.
+         *
+         * To let Room fallback to destructive migration only during a schema downgrade then use
+         * [fallbackToDestructiveMigrationOnDowngrade].
+         *
+         * @param dropAllTables Set to `true` if all tables should be dropped during destructive
+         * migration including those not managed by Room. Recommended value is `true` as otherwise
+         * Room could leave obsolete data when table names or existence changes between versions.
+         * @return This builder instance.
+         */
+        fun fallbackToDestructiveMigration(dropAllTables: Boolean): Builder<T>
+
+        /**
+         * Allows Room to destructively recreate database tables if [Migration]s are not
+         * available when downgrading to old schema versions.
+         *
+         * For details, see [Builder.fallbackToDestructiveMigration].
+         *
+         * @param dropAllTables Set to `true` if all tables should be dropped during destructive
+         * migration including those not managed by Room. Recommended value is `true` as otherwise
+         * Room could leave obsolete data when table names or existence changes between versions.
+         * @return This builder instance.
+         */
+        fun fallbackToDestructiveMigrationOnDowngrade(dropAllTables: Boolean): Builder<T>
+
+        /**
+         * Informs Room that it is allowed to destructively recreate database tables from specific
+         * starting schema versions.
+         *
+         * This functionality is the same [fallbackToDestructiveMigration], except that this method
+         * allows the specification of a set of schema versions for which destructive recreation is
+         * allowed.
+         *
+         * Using this method is preferable to [fallbackToDestructiveMigration] if you want
+         * to allow destructive migrations from some schema versions while still taking advantage
+         * of exceptions being thrown due to unintentionally missing migrations.
+         *
+         * Note: No versions passed to this method may also exist as either starting or ending
+         * versions in the [Migration]s provided via [addMigrations]. If a
+         * version passed to this method is found as a starting or ending version in a Migration, an
+         * exception will be thrown.
+         *
+         * @param dropAllTables Set to `true` if all tables should be dropped during destructive
+         * migration including those not managed by Room. Recommended value is `true` as otherwise
+         * Room could leave obsolete data when table names or existence changes between versions.
+         * @param startVersions The set of schema versions from which Room should use a destructive
+         * migration.
+         * @return This builder instance.
+         */
+        fun fallbackToDestructiveMigrationFrom(
+            dropAllTables: Boolean,
+            vararg startVersions: Int
+        ): Builder<T>
+
+        /**
+         * Adds a type converter instance to the builder.
+         *
+         * @param typeConverter The converter instance that is annotated with
+         * [ProvidedTypeConverter].
+         * @return This builder instance.
+         */
+        fun addTypeConverter(typeConverter: Any): Builder<T>
+
+        /**
+         * Sets the journal mode for this database.
+         *
+         * The value is ignored if the builder is for an 'in-memory database'. The journal mode
+         * should be consistent across multiple instances of [RoomDatabase] for a single SQLite
+         * database file.
+         *
+         * The default value is [JournalMode.WRITE_AHEAD_LOGGING].
+         *
+         * @param journalMode The journal mode.
+         * @return This builder instance.
+         */
+        fun setJournalMode(journalMode: JournalMode): Builder<T>
+
+        /**
          * Sets the [CoroutineContext] that will be used to execute all asynchronous queries and
          * tasks, such as `Flow` emissions and [InvalidationTracker] notifications.
          *
@@ -404,6 +515,25 @@
     useConnection(isReadOnly = false, block)
 }
 
+/**
+ * Validates that no added migration start or end are also marked as fallback to destructive
+ * migration from.
+ */
+internal fun validateMigrationsNotRequired(
+    migrationStartAndEndVersions: Set<Int>,
+    migrationsNotRequiredFrom: Set<Int>
+) {
+    if (migrationStartAndEndVersions.isNotEmpty()) {
+        for (version in migrationStartAndEndVersions) {
+            require(!migrationsNotRequiredFrom.contains(version)) {
+                "Inconsistency detected. A Migration was supplied to addMigration() that has a " +
+                    "start or end version equal to a start version supplied to " +
+                    "fallbackToDestructiveMigrationFrom(). Start version is: $version"
+            }
+        }
+    }
+}
+
 internal fun RoomDatabase.validateAutoMigrations(configuration: DatabaseConfiguration) {
     val autoMigrationSpecs = mutableMapOf<KClass<out AutoMigrationSpec>, AutoMigrationSpec>()
     val requiredAutoMigrationSpecs = getRequiredAutoMigrationSpecClasses()
@@ -426,7 +556,7 @@
         autoMigrationSpecs[spec] = configuration.autoMigrationSpecs[foundIndex]
     }
     for (providedIndex in configuration.autoMigrationSpecs.indices.reversed()) {
-        require(usedSpecs[providedIndex]) {
+        require(providedIndex < usedSpecs.size && usedSpecs[providedIndex]) {
             "Unexpected auto migration specs found. " +
                 "Annotate AutoMigrationSpec implementation with " +
                 "@ProvidedAutoMigrationSpec annotation or remove this spec from the " +
@@ -464,7 +594,7 @@
                 }
             }
             require(foundIndex >= 0) {
-                "A required type converter ($converter) for" +
+                "A required type converter (${converter.qualifiedName}) for" +
                     " ${daoName.qualifiedName} is missing in the database configuration."
             }
             addTypeConverter(converter, configuration.typeConverters[foundIndex])
diff --git a/room/room-runtime/src/commonMain/kotlin/androidx/room/migration/Migration.kt b/room/room-runtime/src/commonMain/kotlin/androidx/room/migration/Migration.kt
index bfad951..865e6b8 100644
--- a/room/room-runtime/src/commonMain/kotlin/androidx/room/migration/Migration.kt
+++ b/room/room-runtime/src/commonMain/kotlin/androidx/room/migration/Migration.kt
@@ -34,7 +34,7 @@
  *
  * @constructor Creates a new migration between [startVersion] and [endVersion] inclusive.
  */
-expect abstract class Migration {
+expect abstract class Migration(startVersion: Int, endVersion: Int) {
     val startVersion: Int
     val endVersion: Int
 
diff --git a/room/room-runtime/src/jvmNativeMain/kotlin/androidx/room/DatabaseConfiguration.jvmNative.kt b/room/room-runtime/src/jvmNativeMain/kotlin/androidx/room/DatabaseConfiguration.jvmNative.kt
index 0d6c83d..a282cee 100644
--- a/room/room-runtime/src/jvmNativeMain/kotlin/androidx/room/DatabaseConfiguration.jvmNative.kt
+++ b/room/room-runtime/src/jvmNativeMain/kotlin/androidx/room/DatabaseConfiguration.jvmNative.kt
@@ -28,13 +28,23 @@
     actual val name: String?,
     /* Collection of available migrations. */
     actual val migrationContainer: RoomDatabase.MigrationContainer,
+    /* Database callbacks. */
     actual val callbacks: List<RoomDatabase.Callback>?,
+    /* The journal mode for this database. */
     actual val journalMode: RoomDatabase.JournalMode,
+    /* Whether Room should throw an exception for missing migrations. */
     actual val requireMigration: Boolean,
+    /* Whether Room will fallback to destructive migrations on downgrades only .*/
     actual val allowDestructiveMigrationOnDowngrade: Boolean,
     internal actual val migrationNotRequiredFrom: Set<Int>?,
+    /* List of provided type converters. */
     actual val typeConverters: List<Any>,
+    /* List of provided auto migration specs. */
     actual val autoMigrationSpecs: List<AutoMigrationSpec>,
+    /* Whether Room will delete all tables or only known tables during destructive migrations. */
+    actual val allowDestructiveMigrationForAllTables: Boolean,
+    /* The SQLite Driver for the database. */
     actual val sqliteDriver: SQLiteDriver?,
+    /* The Coroutine context for the database. */
     actual val queryCoroutineContext: CoroutineContext?,
 )
diff --git a/room/room-runtime/src/jvmNativeMain/kotlin/androidx/room/RoomDatabase.jvmNative.kt b/room/room-runtime/src/jvmNativeMain/kotlin/androidx/room/RoomDatabase.jvmNative.kt
index 2d4277c..89b1adf 100644
--- a/room/room-runtime/src/jvmNativeMain/kotlin/androidx/room/RoomDatabase.jvmNative.kt
+++ b/room/room-runtime/src/jvmNativeMain/kotlin/androidx/room/RoomDatabase.jvmNative.kt
@@ -288,8 +288,34 @@
     ) {
 
         private var driver: SQLiteDriver? = null
-        private var queryCoroutineContext: CoroutineContext? = null
         private val callbacks = mutableListOf<Callback>()
+        private val typeConverters: MutableList<Any> = mutableListOf()
+        private var journalMode: JournalMode = JournalMode.WRITE_AHEAD_LOGGING
+        private var queryCoroutineContext: CoroutineContext? = null
+
+        /**
+         * Migrations, mapped by from-to pairs.
+         */
+        private val migrationContainer: MigrationContainer = MigrationContainer()
+
+        /**
+         * Versions that don't require migrations, configured via
+         * [fallbackToDestructiveMigrationFrom].
+         */
+        private var migrationsNotRequiredFrom: MutableSet<Int> = mutableSetOf()
+
+        /**
+         * Keeps track of [Migration.startVersion]s and [Migration.endVersion]s added in
+         * [addMigrations] for later validation that makes those versions don't
+         * match any versions passed to [fallbackToDestructiveMigrationFrom].
+         */
+        private val migrationStartAndEndVersions = mutableSetOf<Int>()
+
+        private val autoMigrationSpecs: MutableList<AutoMigrationSpec> = mutableListOf()
+
+        private var requireMigration: Boolean = true
+        private var allowDestructiveMigrationOnDowngrade = false
+        private var allowDestructiveMigrationForAllTables = false
 
         /**
          * Sets the [SQLiteDriver] implementation to be used by Room to open database connections.
@@ -304,6 +330,142 @@
         }
 
         /**
+         * Adds a migration to the builder.
+         *
+         * Each [Migration] has a start and end versions and Room runs these migrations to bring the
+         * database to the latest version.
+         *
+         * A migration can handle more than 1 version (e.g. if you have a faster path to choose when
+         * going from version 3 to 5 without going to version 4). If Room opens a database at
+         * version 3 and latest version is >= 5, Room will use the migration object that can migrate
+         * from 3 to 5 instead of 3 to 4 and 4 to 5.
+         *
+         * @param migrations The migration objects that modify the database schema with the
+         * necessary changes for a version change.
+         * @return This builder instance.
+         */
+        actual fun addMigrations(vararg migrations: Migration) = apply {
+            for (migration in migrations) {
+                migrationStartAndEndVersions.add(migration.startVersion)
+                migrationStartAndEndVersions.add(migration.endVersion)
+            }
+            migrationContainer.addMigrations(migrations.toList())
+        }
+
+        /**
+         * Adds an auto migration spec instance to the builder.
+         *
+         * @param autoMigrationSpec The auto migration object that is annotated with
+         * [ProvidedAutoMigrationSpec] and is declared in an [AutoMigration] annotation.
+         * @return This builder instance.
+         */
+        actual fun addAutoMigrationSpec(autoMigrationSpec: AutoMigrationSpec) = apply {
+            this.autoMigrationSpecs.add(autoMigrationSpec)
+        }
+
+        /**
+         * Allows Room to destructively recreate database tables if [Migration]s that would
+         * migrate old database schemas to the latest schema version are not found.
+         *
+         * When the database version on the device does not match the latest schema version, Room
+         * runs necessary [Migration]s on the database. If it cannot find the set of [Migration]s
+         * that will bring the database to the current version, it will throw an
+         * [IllegalStateException]. You can call this method to change this behavior to re-create
+         * the database tables instead of crashing.
+         *
+         * To let Room fallback to destructive migration only during a schema downgrade then use
+         * [fallbackToDestructiveMigrationOnDowngrade].
+         *
+         * @param dropAllTables Set to `true` if all tables should be dropped during destructive
+         * migration including those not managed by Room. Recommended value is `true` as otherwise
+         * Room could leave obsolete data when table names or existence changes between versions.
+         * @return This builder instance.
+         */
+        actual fun fallbackToDestructiveMigration(dropAllTables: Boolean) = apply {
+            this.requireMigration = false
+            this.allowDestructiveMigrationOnDowngrade = true
+            this.allowDestructiveMigrationForAllTables = dropAllTables
+        }
+
+        /**
+         * Allows Room to destructively recreate database tables if [Migration]s are not
+         * available when downgrading to old schema versions.
+         *
+         * For details, see [Builder.fallbackToDestructiveMigration].
+         *
+         * @param dropAllTables Set to `true` if all tables should be dropped during destructive
+         * migration including those not managed by Room. Recommended value is `true` as otherwise
+         * Room could leave obsolete data when table names or existence changes between versions.
+         * @return This builder instance.
+         */
+        actual fun fallbackToDestructiveMigrationOnDowngrade(dropAllTables: Boolean) = apply {
+            this.requireMigration = true
+            this.allowDestructiveMigrationOnDowngrade = true
+            this.allowDestructiveMigrationForAllTables = dropAllTables
+        }
+
+        /**
+         * Informs Room that it is allowed to destructively recreate database tables from specific
+         * starting schema versions.
+         *
+         * This functionality is the same [fallbackToDestructiveMigration], except that this method
+         * allows the specification of a set of schema versions for which destructive recreation is
+         * allowed.
+         *
+         * Using this method is preferable to [fallbackToDestructiveMigration] if you want
+         * to allow destructive migrations from some schema versions while still taking advantage
+         * of exceptions being thrown due to unintentionally missing migrations.
+         *
+         * Note: No versions passed to this method may also exist as either starting or ending
+         * versions in the [Migration]s provided via [addMigrations]. If a
+         * version passed to this method is found as a starting or ending version in a Migration, an
+         * exception will be thrown.
+         *
+         * @param dropAllTables Set to `true` if all tables should be dropped during destructive
+         * migration including those not managed by Room. Recommended value is `true` as otherwise
+         * Room could leave obsolete data when table names or existence changes between versions.
+         * @param startVersions The set of schema versions from which Room should use a destructive
+         * migration.
+         * @return This builder instance.
+         */
+        actual fun fallbackToDestructiveMigrationFrom(
+            dropAllTables: Boolean,
+            vararg startVersions: Int
+        ) = apply {
+            for (startVersion in startVersions) {
+                this.migrationsNotRequiredFrom.add(startVersion)
+            }
+            this.allowDestructiveMigrationForAllTables = dropAllTables
+        }
+
+        /**
+         * Adds a type converter instance to the builder.
+         *
+         * @param typeConverter The converter instance that is annotated with
+         * [ProvidedTypeConverter].
+         * @return This builder instance.
+         */
+        actual fun addTypeConverter(typeConverter: Any) = apply {
+            this.typeConverters.add(typeConverter)
+        }
+
+        /**
+         * Sets the journal mode for this database.
+         *
+         * The value is ignored if the builder is for an 'in-memory database'. The journal mode
+         * should be consistent across multiple instances of [RoomDatabase] for a single SQLite
+         * database file.
+         *
+         * The default value is [JournalMode.WRITE_AHEAD_LOGGING].
+         *
+         * @param journalMode The journal mode.
+         * @return This builder instance.
+         */
+        actual fun setJournalMode(journalMode: JournalMode) = apply {
+            this.journalMode = journalMode
+        }
+
+        /**
          * Sets the [CoroutineContext] that will be used to execute all asynchronous queries and
          * tasks, such as `Flow` emissions and [InvalidationTracker] notifications.
          *
@@ -343,16 +505,20 @@
             requireNotNull(driver) {
                 "Cannot create a RoomDatabase without providing a SQLiteDriver via setDriver()."
             }
+
+            validateMigrationsNotRequired(migrationStartAndEndVersions, migrationsNotRequiredFrom)
+
             val configuration = DatabaseConfiguration(
                 name = name,
-                migrationContainer = MigrationContainer(),
+                migrationContainer = migrationContainer,
                 callbacks = callbacks,
-                journalMode = JournalMode.WRITE_AHEAD_LOGGING,
-                requireMigration = false,
-                allowDestructiveMigrationOnDowngrade = false,
-                migrationNotRequiredFrom = null,
-                typeConverters = emptyList(),
-                autoMigrationSpecs = emptyList(),
+                journalMode = journalMode,
+                requireMigration = requireMigration,
+                allowDestructiveMigrationOnDowngrade = allowDestructiveMigrationOnDowngrade,
+                migrationNotRequiredFrom = migrationsNotRequiredFrom,
+                typeConverters = typeConverters,
+                autoMigrationSpecs = autoMigrationSpecs,
+                allowDestructiveMigrationForAllTables = allowDestructiveMigrationForAllTables,
                 sqliteDriver = driver,
                 queryCoroutineContext = queryCoroutineContext ?: Dispatchers.IO,
             )
diff --git a/room/room-runtime/src/jvmNativeMain/kotlin/androidx/room/migration/Migration.jvmNative.kt b/room/room-runtime/src/jvmNativeMain/kotlin/androidx/room/migration/Migration.jvmNative.kt
index cd3bb8c..a6535fe0 100644
--- a/room/room-runtime/src/jvmNativeMain/kotlin/androidx/room/migration/Migration.jvmNative.kt
+++ b/room/room-runtime/src/jvmNativeMain/kotlin/androidx/room/migration/Migration.jvmNative.kt
@@ -34,7 +34,7 @@
  *
  * @constructor Creates a new migration between [startVersion] and [endVersion] inclusive.
  */
-actual abstract class Migration(
+actual abstract class Migration actual constructor(
     actual val startVersion: Int,
     actual val endVersion: Int
 ) {
diff --git a/room/room-testing/src/jvmMain/kotlin/androidx/room/testing/MigrationTestHelper.jvm.kt b/room/room-testing/src/jvmMain/kotlin/androidx/room/testing/MigrationTestHelper.jvm.kt
index fa527a3..bab0e16 100644
--- a/room/room-testing/src/jvmMain/kotlin/androidx/room/testing/MigrationTestHelper.jvm.kt
+++ b/room/room-testing/src/jvmMain/kotlin/androidx/room/testing/MigrationTestHelper.jvm.kt
@@ -175,6 +175,7 @@
         migrationNotRequiredFrom = null,
         typeConverters = emptyList(),
         autoMigrationSpecs = emptyList(),
+        allowDestructiveMigrationForAllTables = false,
         sqliteDriver = driver,
         queryCoroutineContext = null
     )
diff --git a/room/room-testing/src/nativeMain/kotlin/androidx/room/testing/MigrationTestHelper.native.kt b/room/room-testing/src/nativeMain/kotlin/androidx/room/testing/MigrationTestHelper.native.kt
index c0e69bc..9ab308c 100644
--- a/room/room-testing/src/nativeMain/kotlin/androidx/room/testing/MigrationTestHelper.native.kt
+++ b/room/room-testing/src/nativeMain/kotlin/androidx/room/testing/MigrationTestHelper.native.kt
@@ -173,6 +173,7 @@
         migrationNotRequiredFrom = null,
         typeConverters = emptyList(),
         autoMigrationSpecs = emptyList(),
+        allowDestructiveMigrationForAllTables = false,
         sqliteDriver = driver,
         queryCoroutineContext = null
     )
diff --git a/settings.gradle b/settings.gradle
index d2d31c0..6699834 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -33,6 +33,7 @@
         classpath("androidx.build.gradle.gcpbuildcache:gcpbuildcache:1.0.0-beta07")
     }
 }
+def supportRootFolder = buildscript.sourceFile.getParentFile()
 skikoSetup.defineSkikoInVersionCatalog(settings)
 
 // Abort immediately if we're running in Studio, but not a managed instance of Studio.
@@ -45,7 +46,7 @@
 
 // Makes strong assumptions about the project structure.
 def prebuiltsRoot = new File(
-        buildscript.sourceFile.parentFile.parentFile.parentFile,
+        supportRootFolder.parentFile.parentFile,
         "prebuilts"
 ).absolutePath
 def rootProjectRepositories
@@ -64,6 +65,7 @@
         // on each project
         project.repositories.addAll(rootProjectRepositories)
     }
+    project.ext.supportRootFolder = supportRootFolder
     project.ext.prebuiltsRoot = prebuiltsRoot
     init.chooseBuildDirectory(
             new File("${buildscript.sourceFile.parent}/../.."), rootProject.name, project
diff --git a/testutils/testutils-gradle-plugin/src/main/java/androidx/testutils/gradle/ProjectSetupRule.kt b/testutils/testutils-gradle-plugin/src/main/java/androidx/testutils/gradle/ProjectSetupRule.kt
index 8676631..08ae513 100644
--- a/testutils/testutils-gradle-plugin/src/main/java/androidx/testutils/gradle/ProjectSetupRule.kt
+++ b/testutils/testutils-gradle-plugin/src/main/java/androidx/testutils/gradle/ProjectSetupRule.kt
@@ -74,7 +74,7 @@
     val androidProject: String
         get() = """
             android {
-                compileSdkVersion ${props.compileSdkVersion}
+                compileSdk ${props.compileSdk}
                 buildToolsVersion "${props.buildToolsVersion}"
 
                 defaultConfig {
@@ -210,7 +210,7 @@
 
 // TODO(b/233600239): document the rest of the parameters
 data class ProjectProps(
-    val compileSdkVersion: String,
+    val compileSdk: String,
     val buildToolsVersion: String,
     val minSdkVersion: String,
     val debugKeystore: String,
@@ -260,11 +260,7 @@
                         File(it).canonicalPath
                     }
                 },
-                compileSdkVersion = properties.getProperty("compileSdkVersion").let {
-                    // Add quotes around preview SDK string so that we call
-                    // compileSdkVersion(String) instead of compileSdkVersion(int)
-                    return@let if (it.startsWith("android-")) "\"$it\"" else it
-                },
+                compileSdk = properties.getProperty("compileSdk"),
                 buildToolsVersion = properties.getProperty("buildToolsVersion"),
                 minSdkVersion = properties.getProperty("minSdkVersion"),
                 navigationRuntime = properties.getProperty("navigationRuntime"),
diff --git a/testutils/testutils-navigation/src/main/java/androidx/testutils/TestNavigatorDestinationBuilder.kt b/testutils/testutils-navigation/src/main/java/androidx/testutils/TestNavigatorDestinationBuilder.kt
index d321417..b24ff3b 100644
--- a/testutils/testutils-navigation/src/main/java/androidx/testutils/TestNavigatorDestinationBuilder.kt
+++ b/testutils/testutils-navigation/src/main/java/androidx/testutils/TestNavigatorDestinationBuilder.kt
@@ -23,8 +23,10 @@
 import androidx.navigation.NavDestinationBuilder
 import androidx.navigation.NavDestinationDsl
 import androidx.navigation.NavGraphBuilder
+import androidx.navigation.NavType
 import androidx.navigation.get
 import kotlin.reflect.KClass
+import kotlin.reflect.KType
 
 /**
  * Construct a new [TestNavigator.Destination]
@@ -39,7 +41,9 @@
 /**
  * Construct a new [TestNavigator.Destination]
  */
-inline fun NavGraphBuilder.test(route: KClass<*>) = test(route) {}
+inline fun <reified T : Any> NavGraphBuilder.test(
+    typeMap: Map<KType, NavType<*>> = emptyMap()
+) = test<T>(typeMap) {}
 
 /**
  * Construct a new [TestNavigator.Destination]
@@ -68,21 +72,26 @@
 /**
  * Construct a new [TestNavigator.Destination]
  */
-inline fun NavGraphBuilder.test(
-    route: KClass<*>,
+inline fun <reified T : Any> NavGraphBuilder.test(
+    typeMap: Map<KType, NavType<*>> = emptyMap(),
     builder: TestNavigatorDestinationBuilder.() -> Unit
 ) = destination(
-    TestNavigatorDestinationBuilder(provider[TestNavigator::class], route).apply(builder)
+    TestNavigatorDestinationBuilder(provider[TestNavigator::class], T::class, typeMap)
+        .apply(builder)
 )
 
 /**
  * DSL for constructing a new [TestNavigator.Destination]
  */
 @NavDestinationDsl
+@OptIn(ExperimentalSafeArgsApi::class)
 class TestNavigatorDestinationBuilder : NavDestinationBuilder<TestNavigator.Destination> {
     @Suppress("DEPRECATION")
     constructor(navigator: TestNavigator, @IdRes id: Int = 0) : super(navigator, id)
     constructor(navigator: TestNavigator, route: String) : super(navigator, route)
-    @OptIn(ExperimentalSafeArgsApi::class)
-    constructor(navigator: TestNavigator, route: KClass<*>) : super(navigator, route, emptyMap())
+    constructor(
+        navigator: TestNavigator,
+        route: KClass<*>,
+        typeMap: Map<KType, NavType<*>>
+    ) : super(navigator, route, typeMap)
 }
diff --git a/tv/samples/src/main/java/androidx/tv/samples/CardContainerSamples.kt b/tv/samples/src/main/java/androidx/tv/samples/CardContainerSamples.kt
index bc3333f..feb4f87 100644
--- a/tv/samples/src/main/java/androidx/tv/samples/CardContainerSamples.kt
+++ b/tv/samples/src/main/java/androidx/tv/samples/CardContainerSamples.kt
@@ -29,7 +29,7 @@
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.unit.dp
-import androidx.tv.material3.CardContainerDefaults
+import androidx.tv.material3.Card
 import androidx.tv.material3.ExperimentalTvMaterial3Api
 import androidx.tv.material3.StandardCardContainer
 import androidx.tv.material3.Text
@@ -41,7 +41,7 @@
     StandardCardContainer(
         modifier = Modifier.size(150.dp, 120.dp),
         imageCard = { interactionSource ->
-            CardContainerDefaults.ImageCard(
+            Card(
                 onClick = { },
                 interactionSource = interactionSource
             ) {
@@ -63,7 +63,7 @@
     WideCardContainer(
         modifier = Modifier.size(180.dp, 100.dp),
         imageCard = { interactionSource ->
-            CardContainerDefaults.ImageCard(
+            Card(
                 onClick = { },
                 interactionSource = interactionSource
             ) {
diff --git a/tv/samples/src/main/java/androidx/tv/samples/CardSamples.kt b/tv/samples/src/main/java/androidx/tv/samples/CardSamples.kt
index 6cf206a..014a502 100644
--- a/tv/samples/src/main/java/androidx/tv/samples/CardSamples.kt
+++ b/tv/samples/src/main/java/androidx/tv/samples/CardSamples.kt
@@ -19,20 +19,25 @@
 package androidx.tv.samples
 
 import androidx.annotation.Sampled
+import androidx.compose.foundation.BorderStroke
 import androidx.compose.foundation.background
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.PaddingValues
-import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.aspectRatio
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.runtime.Composable
-import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.unit.dp
+import androidx.tv.material3.Border
 import androidx.tv.material3.Card
+import androidx.tv.material3.CardDefaults
 import androidx.tv.material3.ClassicCard
 import androidx.tv.material3.CompactCard
 import androidx.tv.material3.ExperimentalTvMaterial3Api
@@ -41,17 +46,78 @@
 
 @Sampled
 @Composable
-fun CardSample() {
+fun HorizontalImageAspectRatioCardSample() {
     Card(
-        modifier = Modifier.size(150.dp, 120.dp),
-        onClick = { }
+        onClick = { },
+        modifier = Modifier
+            .width(200.dp)
+            .aspectRatio(CardDefaults.HorizontalImageAspectRatio),
+        border = CardDefaults.border(
+            focusedBorder = Border(
+                border = BorderStroke(width = 3.dp, color = Color.Green),
+                shape = RoundedCornerShape(5),
+            ),
+        ),
+        colors = CardDefaults.colors(
+            containerColor = Color.Red,
+            focusedContainerColor = Color.Yellow
+        ),
+        scale = CardDefaults.scale(
+            focusedScale = 1.05f,
+        )
     ) {
-        Box(Modifier.fillMaxSize()) {
-            Text(
-                text = "Card",
-                modifier = Modifier.align(Alignment.Center)
-            )
-        }
+    }
+}
+
+@Sampled
+@Composable
+fun VerticalImageAspectRatioCardSample() {
+    Card(
+        onClick = { },
+        modifier = Modifier
+            .width(200.dp)
+            .aspectRatio(CardDefaults.VerticalImageAspectRatio),
+        border = CardDefaults.border(
+            focusedBorder = Border(
+                border = BorderStroke(width = 3.dp, color = Color.Green),
+                shape = RoundedCornerShape(5),
+            ),
+        ),
+        colors = CardDefaults.colors(
+            containerColor = Color.Red,
+            focusedContainerColor = Color.Yellow
+        ),
+        scale = CardDefaults.scale(
+            focusedScale = 1.05f,
+        )
+    ) {
+    }
+}
+
+@Sampled
+@Composable
+fun SquareImageAspectRatioCardSample() {
+    Card(
+        onClick = { },
+        modifier = Modifier
+            .width(150.dp)
+            .aspectRatio(CardDefaults.SquareImageAspectRatio),
+        border = CardDefaults.border(
+            focusedBorder = Border(
+                border = BorderStroke(width = 3.dp, color = Color.Green)
+            ),
+        ),
+        shape = CardDefaults.shape(
+            shape = CircleShape,
+        ),
+        colors = CardDefaults.colors(
+            containerColor = Color.Red,
+            focusedContainerColor = Color.Yellow
+        ),
+        scale = CardDefaults.scale(
+            focusedScale = 1.05f,
+        )
+    ) {
     }
 }
 
diff --git a/tv/tv-material/api/current.txt b/tv/tv-material/api/current.txt
index d1d9b94..54f54a8 100644
--- a/tv/tv-material/api/current.txt
+++ b/tv/tv-material/api/current.txt
@@ -86,7 +86,6 @@
   }
 
   public final class CardContainerDefaults {
-    method @androidx.compose.runtime.Composable public void ImageCard(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional androidx.tv.material3.CardShape shape, optional androidx.tv.material3.CardColors colors, optional androidx.tv.material3.CardScale scale, optional androidx.tv.material3.CardBorder border, optional androidx.tv.material3.CardGlow glow, kotlin.jvm.functions.Function0<kotlin.Unit> content);
     method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.CardContainerColors contentColor(optional long contentColor, optional long focusedContentColor, optional long pressedContentColor);
     field public static final androidx.tv.material3.CardContainerDefaults INSTANCE;
   }
@@ -100,11 +99,11 @@
     method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.CardBorder border(optional androidx.tv.material3.Border border, optional androidx.tv.material3.Border focusedBorder, optional androidx.tv.material3.Border pressedBorder);
     method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.CardColors colors(optional long containerColor, optional long contentColor, optional long focusedContainerColor, optional long focusedContentColor, optional long pressedContainerColor, optional long pressedContentColor);
     method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.CardColors compactCardColors(optional long containerColor, optional long contentColor, optional long focusedContainerColor, optional long focusedContentColor, optional long pressedContainerColor, optional long pressedContentColor);
-    method public androidx.compose.ui.graphics.Brush getContainerGradient();
+    method public androidx.compose.ui.graphics.Brush getScrimBrush();
     method public androidx.tv.material3.CardGlow glow(optional androidx.tv.material3.Glow glow, optional androidx.tv.material3.Glow focusedGlow, optional androidx.tv.material3.Glow pressedGlow);
     method public androidx.tv.material3.CardScale scale(optional @FloatRange(from=0.0) float scale, optional @FloatRange(from=0.0) float focusedScale, optional @FloatRange(from=0.0) float pressedScale);
     method public androidx.tv.material3.CardShape shape(optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.ui.graphics.Shape focusedShape, optional androidx.compose.ui.graphics.Shape pressedShape);
-    property public final androidx.compose.ui.graphics.Brush ContainerGradient;
+    property public final androidx.compose.ui.graphics.Brush ScrimBrush;
     field public static final float HorizontalImageAspectRatio = 1.7777778f;
     field public static final androidx.tv.material3.CardDefaults INSTANCE;
     field public static final float SquareImageAspectRatio = 1.0f;
@@ -490,21 +489,16 @@
   public final class ListItemDefaults {
     method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.ListItemBorder border(optional androidx.tv.material3.Border border, optional androidx.tv.material3.Border focusedBorder, optional androidx.tv.material3.Border pressedBorder, optional androidx.tv.material3.Border selectedBorder, optional androidx.tv.material3.Border disabledBorder, optional androidx.tv.material3.Border focusedSelectedBorder, optional androidx.tv.material3.Border focusedDisabledBorder, optional androidx.tv.material3.Border pressedSelectedBorder);
     method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.ListItemColors colors(optional long containerColor, optional long contentColor, optional long focusedContainerColor, optional long focusedContentColor, optional long pressedContainerColor, optional long pressedContentColor, optional long selectedContainerColor, optional long selectedContentColor, optional long disabledContainerColor, optional long disabledContentColor, optional long focusedSelectedContainerColor, optional long focusedSelectedContentColor, optional long pressedSelectedContainerColor, optional long pressedSelectedContentColor);
-    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.Border getFocusedDisabledBorder();
     method public float getIconSize();
     method public float getIconSizeDense();
-    method public androidx.compose.foundation.shape.RoundedCornerShape getListItemShape();
     method public float getTonalElevation();
     method public androidx.tv.material3.ListItemGlow glow(optional androidx.tv.material3.Glow glow, optional androidx.tv.material3.Glow focusedGlow, optional androidx.tv.material3.Glow pressedGlow, optional androidx.tv.material3.Glow selectedGlow, optional androidx.tv.material3.Glow focusedSelectedGlow, optional androidx.tv.material3.Glow pressedSelectedGlow);
     method public androidx.tv.material3.ListItemScale scale(optional @FloatRange(from=0.0) float scale, optional @FloatRange(from=0.0) float focusedScale, optional @FloatRange(from=0.0) float pressedScale, optional @FloatRange(from=0.0) float selectedScale, optional @FloatRange(from=0.0) float disabledScale, optional @FloatRange(from=0.0) float focusedSelectedScale, optional @FloatRange(from=0.0) float focusedDisabledScale, optional @FloatRange(from=0.0) float pressedSelectedScale);
     method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.ListItemShape shape(optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.ui.graphics.Shape focusedShape, optional androidx.compose.ui.graphics.Shape pressedShape, optional androidx.compose.ui.graphics.Shape selectedShape, optional androidx.compose.ui.graphics.Shape disabledShape, optional androidx.compose.ui.graphics.Shape focusedSelectedShape, optional androidx.compose.ui.graphics.Shape focusedDisabledShape, optional androidx.compose.ui.graphics.Shape pressedSelectedShape);
-    property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final androidx.tv.material3.Border FocusedDisabledBorder;
     property public final float IconSize;
     property public final float IconSizeDense;
-    property public final androidx.compose.foundation.shape.RoundedCornerShape ListItemShape;
     property public final float TonalElevation;
     field public static final androidx.tv.material3.ListItemDefaults INSTANCE;
-    field public static final float SelectedContainerColorOpacity = 0.4f;
   }
 
   @androidx.compose.runtime.Immutable public final class ListItemGlow {
@@ -755,16 +749,6 @@
     property public abstract boolean hasFocus;
   }
 
-  @androidx.compose.runtime.Immutable public final class NonInteractiveSurfaceColors {
-  }
-
-  public final class NonInteractiveSurfaceDefaults {
-    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.NonInteractiveSurfaceColors colors(optional long containerColor, optional long contentColor);
-    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.compose.ui.graphics.Shape getShape();
-    property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final androidx.compose.ui.graphics.Shape shape;
-    field public static final androidx.tv.material3.NonInteractiveSurfaceDefaults INSTANCE;
-  }
-
   public final class OutlinedButtonDefaults {
     method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.ButtonBorder border(optional androidx.tv.material3.Border border, optional androidx.tv.material3.Border focusedBorder, optional androidx.tv.material3.Border pressedBorder, optional androidx.tv.material3.Border disabledBorder, optional androidx.tv.material3.Border focusedDisabledBorder);
     method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.ButtonColors colors(optional long containerColor, optional long contentColor, optional long focusedContainerColor, optional long focusedContentColor, optional long pressedContainerColor, optional long pressedContentColor, optional long disabledContainerColor, optional long disabledContentColor);
@@ -923,8 +907,18 @@
     field public static final androidx.tv.material3.SuggestionChipDefaults INSTANCE;
   }
 
+  @androidx.compose.runtime.Immutable public final class SurfaceColors {
+  }
+
+  public final class SurfaceDefaults {
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.SurfaceColors colors(optional long containerColor, optional long contentColor);
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.compose.ui.graphics.Shape getShape();
+    property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final androidx.compose.ui.graphics.Shape shape;
+    field public static final androidx.tv.material3.SurfaceDefaults INSTANCE;
+  }
+
   public final class SurfaceKt {
-    method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable public static void Surface(optional androidx.compose.ui.Modifier modifier, optional float tonalElevation, optional androidx.compose.ui.graphics.Shape shape, optional androidx.tv.material3.NonInteractiveSurfaceColors colors, optional androidx.tv.material3.Border border, optional androidx.tv.material3.Glow glow, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable public static void Surface(optional androidx.compose.ui.Modifier modifier, optional float tonalElevation, optional androidx.compose.ui.graphics.Shape shape, optional androidx.tv.material3.SurfaceColors colors, optional androidx.tv.material3.Border border, optional androidx.tv.material3.Glow glow, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
     method @androidx.compose.runtime.Composable public static void Surface(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional float tonalElevation, optional androidx.tv.material3.SelectableSurfaceShape shape, optional androidx.tv.material3.SelectableSurfaceColors colors, optional androidx.tv.material3.SelectableSurfaceScale scale, optional androidx.tv.material3.SelectableSurfaceBorder border, optional androidx.tv.material3.SelectableSurfaceGlow glow, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
     method @androidx.compose.runtime.Composable public static void Surface(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional boolean enabled, optional float tonalElevation, optional androidx.tv.material3.ClickableSurfaceShape shape, optional androidx.tv.material3.ClickableSurfaceColors colors, optional androidx.tv.material3.ClickableSurfaceScale scale, optional androidx.tv.material3.ClickableSurfaceBorder border, optional androidx.tv.material3.ClickableSurfaceGlow glow, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
   }
diff --git a/tv/tv-material/api/restricted_current.txt b/tv/tv-material/api/restricted_current.txt
index d1d9b94..54f54a8 100644
--- a/tv/tv-material/api/restricted_current.txt
+++ b/tv/tv-material/api/restricted_current.txt
@@ -86,7 +86,6 @@
   }
 
   public final class CardContainerDefaults {
-    method @androidx.compose.runtime.Composable public void ImageCard(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional androidx.tv.material3.CardShape shape, optional androidx.tv.material3.CardColors colors, optional androidx.tv.material3.CardScale scale, optional androidx.tv.material3.CardBorder border, optional androidx.tv.material3.CardGlow glow, kotlin.jvm.functions.Function0<kotlin.Unit> content);
     method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.CardContainerColors contentColor(optional long contentColor, optional long focusedContentColor, optional long pressedContentColor);
     field public static final androidx.tv.material3.CardContainerDefaults INSTANCE;
   }
@@ -100,11 +99,11 @@
     method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.CardBorder border(optional androidx.tv.material3.Border border, optional androidx.tv.material3.Border focusedBorder, optional androidx.tv.material3.Border pressedBorder);
     method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.CardColors colors(optional long containerColor, optional long contentColor, optional long focusedContainerColor, optional long focusedContentColor, optional long pressedContainerColor, optional long pressedContentColor);
     method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.CardColors compactCardColors(optional long containerColor, optional long contentColor, optional long focusedContainerColor, optional long focusedContentColor, optional long pressedContainerColor, optional long pressedContentColor);
-    method public androidx.compose.ui.graphics.Brush getContainerGradient();
+    method public androidx.compose.ui.graphics.Brush getScrimBrush();
     method public androidx.tv.material3.CardGlow glow(optional androidx.tv.material3.Glow glow, optional androidx.tv.material3.Glow focusedGlow, optional androidx.tv.material3.Glow pressedGlow);
     method public androidx.tv.material3.CardScale scale(optional @FloatRange(from=0.0) float scale, optional @FloatRange(from=0.0) float focusedScale, optional @FloatRange(from=0.0) float pressedScale);
     method public androidx.tv.material3.CardShape shape(optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.ui.graphics.Shape focusedShape, optional androidx.compose.ui.graphics.Shape pressedShape);
-    property public final androidx.compose.ui.graphics.Brush ContainerGradient;
+    property public final androidx.compose.ui.graphics.Brush ScrimBrush;
     field public static final float HorizontalImageAspectRatio = 1.7777778f;
     field public static final androidx.tv.material3.CardDefaults INSTANCE;
     field public static final float SquareImageAspectRatio = 1.0f;
@@ -490,21 +489,16 @@
   public final class ListItemDefaults {
     method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.ListItemBorder border(optional androidx.tv.material3.Border border, optional androidx.tv.material3.Border focusedBorder, optional androidx.tv.material3.Border pressedBorder, optional androidx.tv.material3.Border selectedBorder, optional androidx.tv.material3.Border disabledBorder, optional androidx.tv.material3.Border focusedSelectedBorder, optional androidx.tv.material3.Border focusedDisabledBorder, optional androidx.tv.material3.Border pressedSelectedBorder);
     method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.ListItemColors colors(optional long containerColor, optional long contentColor, optional long focusedContainerColor, optional long focusedContentColor, optional long pressedContainerColor, optional long pressedContentColor, optional long selectedContainerColor, optional long selectedContentColor, optional long disabledContainerColor, optional long disabledContentColor, optional long focusedSelectedContainerColor, optional long focusedSelectedContentColor, optional long pressedSelectedContainerColor, optional long pressedSelectedContentColor);
-    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.Border getFocusedDisabledBorder();
     method public float getIconSize();
     method public float getIconSizeDense();
-    method public androidx.compose.foundation.shape.RoundedCornerShape getListItemShape();
     method public float getTonalElevation();
     method public androidx.tv.material3.ListItemGlow glow(optional androidx.tv.material3.Glow glow, optional androidx.tv.material3.Glow focusedGlow, optional androidx.tv.material3.Glow pressedGlow, optional androidx.tv.material3.Glow selectedGlow, optional androidx.tv.material3.Glow focusedSelectedGlow, optional androidx.tv.material3.Glow pressedSelectedGlow);
     method public androidx.tv.material3.ListItemScale scale(optional @FloatRange(from=0.0) float scale, optional @FloatRange(from=0.0) float focusedScale, optional @FloatRange(from=0.0) float pressedScale, optional @FloatRange(from=0.0) float selectedScale, optional @FloatRange(from=0.0) float disabledScale, optional @FloatRange(from=0.0) float focusedSelectedScale, optional @FloatRange(from=0.0) float focusedDisabledScale, optional @FloatRange(from=0.0) float pressedSelectedScale);
     method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.ListItemShape shape(optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.ui.graphics.Shape focusedShape, optional androidx.compose.ui.graphics.Shape pressedShape, optional androidx.compose.ui.graphics.Shape selectedShape, optional androidx.compose.ui.graphics.Shape disabledShape, optional androidx.compose.ui.graphics.Shape focusedSelectedShape, optional androidx.compose.ui.graphics.Shape focusedDisabledShape, optional androidx.compose.ui.graphics.Shape pressedSelectedShape);
-    property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final androidx.tv.material3.Border FocusedDisabledBorder;
     property public final float IconSize;
     property public final float IconSizeDense;
-    property public final androidx.compose.foundation.shape.RoundedCornerShape ListItemShape;
     property public final float TonalElevation;
     field public static final androidx.tv.material3.ListItemDefaults INSTANCE;
-    field public static final float SelectedContainerColorOpacity = 0.4f;
   }
 
   @androidx.compose.runtime.Immutable public final class ListItemGlow {
@@ -755,16 +749,6 @@
     property public abstract boolean hasFocus;
   }
 
-  @androidx.compose.runtime.Immutable public final class NonInteractiveSurfaceColors {
-  }
-
-  public final class NonInteractiveSurfaceDefaults {
-    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.NonInteractiveSurfaceColors colors(optional long containerColor, optional long contentColor);
-    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.compose.ui.graphics.Shape getShape();
-    property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final androidx.compose.ui.graphics.Shape shape;
-    field public static final androidx.tv.material3.NonInteractiveSurfaceDefaults INSTANCE;
-  }
-
   public final class OutlinedButtonDefaults {
     method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.ButtonBorder border(optional androidx.tv.material3.Border border, optional androidx.tv.material3.Border focusedBorder, optional androidx.tv.material3.Border pressedBorder, optional androidx.tv.material3.Border disabledBorder, optional androidx.tv.material3.Border focusedDisabledBorder);
     method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.ButtonColors colors(optional long containerColor, optional long contentColor, optional long focusedContainerColor, optional long focusedContentColor, optional long pressedContainerColor, optional long pressedContentColor, optional long disabledContainerColor, optional long disabledContentColor);
@@ -923,8 +907,18 @@
     field public static final androidx.tv.material3.SuggestionChipDefaults INSTANCE;
   }
 
+  @androidx.compose.runtime.Immutable public final class SurfaceColors {
+  }
+
+  public final class SurfaceDefaults {
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.SurfaceColors colors(optional long containerColor, optional long contentColor);
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.compose.ui.graphics.Shape getShape();
+    property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final androidx.compose.ui.graphics.Shape shape;
+    field public static final androidx.tv.material3.SurfaceDefaults INSTANCE;
+  }
+
   public final class SurfaceKt {
-    method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable public static void Surface(optional androidx.compose.ui.Modifier modifier, optional float tonalElevation, optional androidx.compose.ui.graphics.Shape shape, optional androidx.tv.material3.NonInteractiveSurfaceColors colors, optional androidx.tv.material3.Border border, optional androidx.tv.material3.Glow glow, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable public static void Surface(optional androidx.compose.ui.Modifier modifier, optional float tonalElevation, optional androidx.compose.ui.graphics.Shape shape, optional androidx.tv.material3.SurfaceColors colors, optional androidx.tv.material3.Border border, optional androidx.tv.material3.Glow glow, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
     method @androidx.compose.runtime.Composable public static void Surface(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional float tonalElevation, optional androidx.tv.material3.SelectableSurfaceShape shape, optional androidx.tv.material3.SelectableSurfaceColors colors, optional androidx.tv.material3.SelectableSurfaceScale scale, optional androidx.tv.material3.SelectableSurfaceBorder border, optional androidx.tv.material3.SelectableSurfaceGlow glow, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
     method @androidx.compose.runtime.Composable public static void Surface(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional boolean enabled, optional float tonalElevation, optional androidx.tv.material3.ClickableSurfaceShape shape, optional androidx.tv.material3.ClickableSurfaceColors colors, optional androidx.tv.material3.ClickableSurfaceScale scale, optional androidx.tv.material3.ClickableSurfaceBorder border, optional androidx.tv.material3.ClickableSurfaceGlow glow, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
   }
diff --git a/tv/tv-material/src/androidTest/java/androidx/tv/material3/CardContainerScreenshotTest.kt b/tv/tv-material/src/androidTest/java/androidx/tv/material3/CardContainerScreenshotTest.kt
index 81eefa5..2c5473c 100644
--- a/tv/tv-material/src/androidTest/java/androidx/tv/material3/CardContainerScreenshotTest.kt
+++ b/tv/tv-material/src/androidTest/java/androidx/tv/material3/CardContainerScreenshotTest.kt
@@ -72,7 +72,7 @@
                     StandardCardContainer(
                         modifier = standardCardContainerSizeModifier,
                         imageCard = { interactionSource ->
-                            CardContainerDefaults.ImageCard(
+                            Card(
                                 onClick = { },
                                 interactionSource = interactionSource
                             ) {
@@ -103,7 +103,7 @@
                     StandardCardContainer(
                         modifier = standardCardContainerSizeModifier,
                         imageCard = { interactionSource ->
-                            CardContainerDefaults.ImageCard(
+                            Card(
                                 onClick = { },
                                 interactionSource = interactionSource
                             ) {
@@ -135,7 +135,7 @@
                 StandardCardContainer(
                     modifier = standardCardContainerSizeModifier,
                     imageCard = { interactionSource ->
-                        CardContainerDefaults.ImageCard(
+                        Card(
                             onClick = { },
                             interactionSource = interactionSource
                         ) {
@@ -170,7 +170,7 @@
                     WideCardContainer(
                         modifier = wideCardContainerSizeModifier,
                         imageCard = { interactionSource ->
-                            CardContainerDefaults.ImageCard(
+                            Card(
                                 onClick = { },
                                 interactionSource = interactionSource
                             ) {
@@ -201,7 +201,7 @@
                     WideCardContainer(
                         modifier = wideCardContainerSizeModifier,
                         imageCard = { interactionSource ->
-                            CardContainerDefaults.ImageCard(
+                            Card(
                                 onClick = { },
                                 interactionSource = interactionSource
                             ) {
@@ -233,7 +233,7 @@
                 WideCardContainer(
                     modifier = wideCardContainerSizeModifier,
                     imageCard = { interactionSource ->
-                        CardContainerDefaults.ImageCard(
+                        Card(
                             onClick = { },
                             interactionSource = interactionSource
                         ) {
diff --git a/tv/tv-material/src/androidTest/java/androidx/tv/material3/CardContainerTest.kt b/tv/tv-material/src/androidTest/java/androidx/tv/material3/CardContainerTest.kt
index 791bc65..218639e 100644
--- a/tv/tv-material/src/androidTest/java/androidx/tv/material3/CardContainerTest.kt
+++ b/tv/tv-material/src/androidTest/java/androidx/tv/material3/CardContainerTest.kt
@@ -66,7 +66,7 @@
                     .semantics(mergeDescendants = true) {}
                     .testTag(StandardCardContainerTag),
                 imageCard = { interactionSource ->
-                    CardContainerDefaults.ImageCard(
+                    Card(
                         onClick = { count.value += 1 },
                         interactionSource = interactionSource
                     ) { SampleImage() }
@@ -97,7 +97,7 @@
                     .semantics(mergeDescendants = true) {}
                     .testTag(StandardCardContainerTag),
                 imageCard = { interactionSource ->
-                    CardContainerDefaults.ImageCard(
+                    Card(
                         onClick = { count.value += 1 },
                         interactionSource = interactionSource
                     ) { SampleImage() }
@@ -129,7 +129,7 @@
                     .semantics(mergeDescendants = true) {}
                     .testTag(WideCardContainerTag),
                 imageCard = { interactionSource ->
-                    CardContainerDefaults.ImageCard(
+                    Card(
                         onClick = { count.value += 1 },
                         interactionSource = interactionSource
                     ) { SampleImage() }
@@ -160,7 +160,7 @@
                     .semantics(mergeDescendants = true) {}
                     .testTag(WideCardContainerTag),
                 imageCard = { interactionSource ->
-                    CardContainerDefaults.ImageCard(
+                    Card(
                         onClick = { count.value += 1 },
                         interactionSource = interactionSource
                     ) { SampleImage() }
diff --git a/tv/tv-material/src/androidTest/java/androidx/tv/material3/NonInteractiveSurfaceScreenshotTest.kt b/tv/tv-material/src/androidTest/java/androidx/tv/material3/NonInteractiveSurfaceScreenshotTest.kt
index 439bb98..88cf3d9 100644
--- a/tv/tv-material/src/androidTest/java/androidx/tv/material3/NonInteractiveSurfaceScreenshotTest.kt
+++ b/tv/tv-material/src/androidTest/java/androidx/tv/material3/NonInteractiveSurfaceScreenshotTest.kt
@@ -60,7 +60,7 @@
             .align(Alignment.Center)
     }
 
-    private val wrapperTestTag = "NonInteractiveSurfaceWrapper"
+    private val wrapperTestTag = "SurfaceWrapper"
 
     @Test
     fun nonInteractiveSurface_noCustomizations() {
@@ -98,7 +98,7 @@
             Box(containerModifier.testTag(wrapperTestTag)) {
                 Surface(
                     surfaceModifier(),
-                    colors = NonInteractiveSurfaceDefaults.colors(containerColor = Color.Green)
+                    colors = SurfaceDefaults.colors(containerColor = Color.Green)
                 ) {}
             }
         }
@@ -111,7 +111,7 @@
             Box(containerModifier.testTag(wrapperTestTag)) {
                 Surface(
                     surfaceModifier(),
-                    colors = NonInteractiveSurfaceDefaults.colors(contentColor = Color.Red)
+                    colors = SurfaceDefaults.colors(contentColor = Color.Red)
                 ) {}
             }
         }
diff --git a/tv/tv-material/src/androidTest/java/androidx/tv/material3/TabRowScreenshotTest.kt b/tv/tv-material/src/androidTest/java/androidx/tv/material3/TabRowScreenshotTest.kt
index 093e9b7..9e5999e 100644
--- a/tv/tv-material/src/androidTest/java/androidx/tv/material3/TabRowScreenshotTest.kt
+++ b/tv/tv-material/src/androidTest/java/androidx/tv/material3/TabRowScreenshotTest.kt
@@ -70,7 +70,7 @@
 
             Surface(
                 modifier = wrapperModifier,
-                colors = NonInteractiveSurfaceDefaults.colors(
+                colors = SurfaceDefaults.colors(
                     containerColor = Color.Transparent
                 ),
                 shape = RectangleShape
@@ -108,7 +108,7 @@
 
             Surface(
                 modifier = wrapperModifier.focusRequester(focusRequester),
-                colors = NonInteractiveSurfaceDefaults.colors(
+                colors = SurfaceDefaults.colors(
                     containerColor = Color.Transparent
                 ),
                 shape = RectangleShape
@@ -152,7 +152,7 @@
 
             Surface(
                 modifier = wrapperModifier.focusRequester(focusRequester),
-                colors = NonInteractiveSurfaceDefaults.colors(
+                colors = SurfaceDefaults.colors(
                     containerColor = Color.Transparent
                 ),
                 shape = RectangleShape
@@ -195,7 +195,7 @@
 
             Surface(
                 modifier = wrapperModifier,
-                colors = NonInteractiveSurfaceDefaults.colors(
+                colors = SurfaceDefaults.colors(
                     containerColor = Color.Transparent
                 ),
                 shape = RectangleShape
@@ -239,7 +239,7 @@
 
             Surface(
                 modifier = wrapperModifier.focusRequester(focusRequester),
-                colors = NonInteractiveSurfaceDefaults.colors(
+                colors = SurfaceDefaults.colors(
                     containerColor = Color.Transparent
                 ),
                 shape = RectangleShape
@@ -289,7 +289,7 @@
 
             Surface(
                 modifier = wrapperModifier.focusRequester(focusRequester),
-                colors = NonInteractiveSurfaceDefaults.colors(
+                colors = SurfaceDefaults.colors(
                     containerColor = Color.Transparent
                 ),
                 shape = RectangleShape
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/Card.kt b/tv/tv-material/src/main/java/androidx/tv/material3/Card.kt
index 7f9b9b3..f08da19 100644
--- a/tv/tv-material/src/main/java/androidx/tv/material3/Card.kt
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/Card.kt
@@ -45,7 +45,11 @@
  *
  * This Card handles click events, calling its [onClick] lambda.
  *
- * @sample androidx.tv.samples.CardSample
+ * Checkout <a href="https://developer.android.com/design/ui/tv/guides/components/cards#usage">TV Guidelines for Aspect ratios</a> for cards
+ *
+ * @sample androidx.tv.samples.HorizontalImageAspectRatioCardSample
+ * @sample androidx.tv.samples.VerticalImageAspectRatioCardSample
+ * @sample androidx.tv.samples.SquareImageAspectRatioCardSample
  *
  * @param onClick called when this card is clicked.
  * @param modifier the [Modifier] to be applied to this card.
@@ -212,7 +216,7 @@
  * @param glow [CardGlow] defines a shadow to be shown behind the card for different interaction
  * states. See [CardDefaults.glow].
  * @param scrimBrush [Brush] defines a brush/gradient to be used to draw the scrim over the image
- * in the background. See [CardDefaults.ContainerGradient].
+ * in the background. See [CardDefaults.ScrimBrush].
  * @param interactionSource an optional hoisted [MutableInteractionSource] for observing and
  * emitting [Interaction]s for this card. You can use this to change the card's appearance
  * or preview the card in different states. Note that if `null` is provided, interactions will
@@ -232,7 +236,7 @@
     scale: CardScale = CardDefaults.scale(),
     border: CardBorder = CardDefaults.border(),
     glow: CardGlow = CardDefaults.glow(),
-    scrimBrush: Brush = CardDefaults.ContainerGradient,
+    scrimBrush: Brush = CardDefaults.ScrimBrush,
     interactionSource: MutableInteractionSource? = null
 ) {
     Card(
@@ -407,7 +411,7 @@
      * Gradient used in cards to give more emphasis to the textual content that is generally
      * displayed above an image.
      */
-    val ContainerGradient = Brush.verticalGradient(
+    val ScrimBrush = Brush.verticalGradient(
         listOf(
             Color(red = 28, green = 27, blue = 31, alpha = 0),
             Color(red = 28, green = 27, blue = 31, alpha = 204)
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/CardContainer.kt b/tv/tv-material/src/main/java/androidx/tv/material3/CardContainer.kt
index d896f89..6185285 100644
--- a/tv/tv-material/src/main/java/androidx/tv/material3/CardContainer.kt
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/CardContainer.kt
@@ -46,9 +46,7 @@
  *
  * @sample androidx.tv.samples.StandardCardContainerSample
  *
- * @param imageCard defines the [Composable] to be used for the image card. See
- * [CardContainerDefaults.ImageCard] to create an image card. The `interactionSource` param provided
- * in the lambda function should be forwarded and used with the image card composable.
+ * @param imageCard defines the [Composable] to be used for the image card.
  * @param title defines the [Composable] title placed below the image card in the CardContainer.
  * @param modifier the [Modifier] to be applied to this CardContainer.
  * @param subtitle defines the [Composable] supporting text placed below the title in CardContainer.
@@ -111,9 +109,7 @@
  *
  * @sample androidx.tv.samples.WideCardContainerSample
  *
- * @param imageCard defines the [Composable] to be used for the image card. See
- * [CardContainerDefaults.ImageCard] to create an image card. The `interactionSource` param provided
- * in the lambda function should to be forwarded and used with the image card composable.
+ * @param imageCard defines the [Composable] to be used for the image card.
  * @param title defines the [Composable] title placed below the image card in the CardContainer.
  * @param modifier the [Modifier] to be applied to this CardContainer.
  * @param subtitle defines the [Composable] supporting text placed below the title in CardContainer.
@@ -191,58 +187,6 @@
         focusedContentColor = focusedContentColor,
         pressedContentColor = pressedContentColor
     )
-
-    /**
-     * [ImageCard] is basically a [Card] composable with an image as the content. It is recommended
-     * to be used with the different CardContainer(s).
-     *
-     * This Card handles click events, calling its [onClick] lambda.
-     *
-     * @param onClick called when this card is clicked.
-     * @param interactionSource a hoisted [MutableInteractionSource] for observing and
-     * emitting [Interaction]s for this card. When using with the CardContainer(s), it is recommended
-     * to pass in the interaction state obtained from the parent lambda.
-     * @param modifier the [Modifier] to be applied to this card.
-     * @param onLongClick called when this card is long clicked (long-pressed).
-     * @param shape [CardShape] defines the shape of this card's container in different interaction
-     * states. See [CardDefaults.shape].
-     * @param colors [CardColors] defines the background & content colors used in this card for
-     * different interaction states. See [CardDefaults.colors].
-     * @param scale [CardScale] defines size of the card relative to its original size for different
-     * interaction states. See [CardDefaults.scale].
-     * @param border [CardBorder] defines a border around the card for different interaction states.
-     * See [CardDefaults.border].
-     * @param glow [CardGlow] defines a shadow to be shown behind the card for different interaction
-     * states. See [CardDefaults.glow].
-     * @param content defines the image content [Composable] to be displayed inside the Card.
-     */
-    @Composable
-    fun ImageCard(
-        onClick: () -> Unit,
-        interactionSource: MutableInteractionSource,
-        modifier: Modifier = Modifier,
-        onLongClick: (() -> Unit)? = null,
-        shape: CardShape = CardDefaults.shape(),
-        colors: CardColors = CardDefaults.colors(),
-        scale: CardScale = CardDefaults.scale(),
-        border: CardBorder = CardDefaults.border(),
-        glow: CardGlow = CardDefaults.glow(),
-        content: @Composable () -> Unit
-    ) {
-        Card(
-            onClick = onClick,
-            onLongClick = onLongClick,
-            modifier = modifier,
-            shape = shape,
-            colors = colors,
-            scale = scale,
-            border = border,
-            glow = glow,
-            interactionSource = interactionSource
-        ) {
-            content()
-        }
-    }
 }
 
 /**
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/ListItemDefaults.kt b/tv/tv-material/src/main/java/androidx/tv/material3/ListItemDefaults.kt
index 1ea5747..f80a652 100644
--- a/tv/tv-material/src/main/java/androidx/tv/material3/ListItemDefaults.kt
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/ListItemDefaults.kt
@@ -50,12 +50,12 @@
     /**
      * The default shape for a [ListItem].
      */
-    val ListItemShape = RoundedCornerShape(8.dp)
+    private val ListItemShape = RoundedCornerShape(8.dp)
 
     /**
      * The default border applied to [ListItem] in focused disabled state.
      */
-    val FocusedDisabledBorder
+    private val FocusedDisabledBorder
         @ReadOnlyComposable
         @Composable get() = Border(
             border = BorderStroke(
@@ -67,7 +67,7 @@
     /**
      * The default opacity for the [ListItem] container color in selected state.
      */
-    const val SelectedContainerColorOpacity = 0.4f
+    private const val SelectedContainerColorOpacity = 0.4f
 
     /**
      * The default content padding [PaddingValues] used by [ListItem]
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/Surface.kt b/tv/tv-material/src/main/java/androidx/tv/material3/Surface.kt
index 4665acf..92792c2 100644
--- a/tv/tv-material/src/main/java/androidx/tv/material3/Surface.kt
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/Surface.kt
@@ -66,7 +66,7 @@
  * in a darker color in light theme and lighter color in dark theme.
  * @param shape Defines the surface's shape.
  * @param colors Defines the background & content color to be used in this Surface.
- * See [NonInteractiveSurfaceDefaults.colors].
+ * See [SurfaceDefaults.colors].
  * @param border Defines a border around the Surface.
  * @param glow Diffused shadow to be shown behind the Surface. Note that glow is disabled for API
  * levels below 28 as it is not supported by the underlying OS
@@ -77,10 +77,10 @@
 fun Surface(
     modifier: Modifier = Modifier,
     tonalElevation: Dp = 0.dp,
-    shape: Shape = NonInteractiveSurfaceDefaults.shape,
-    colors: NonInteractiveSurfaceColors = NonInteractiveSurfaceDefaults.colors(),
-    border: Border = NonInteractiveSurfaceDefaults.border,
-    glow: Glow = NonInteractiveSurfaceDefaults.glow,
+    shape: Shape = SurfaceDefaults.shape,
+    colors: SurfaceColors = SurfaceDefaults.colors(),
+    border: Border = SurfaceDefaults.border,
+    glow: Glow = SurfaceDefaults.glow,
     content: @Composable (BoxScope.() -> Unit)
 ) {
     SurfaceImpl(
@@ -210,7 +210,7 @@
  *
  * To manually retrieve the content color inside a surface, use [LocalContentColor].
  *
- * @param selected whether or not this Surface is toggled on or off
+ * @param selected whether or not this Surface is selected
  * @param onClick callback to be invoked when the selectable Surface is clicked.
  * @param modifier [Modifier] to be applied to the layout corresponding to the surface
  * @param onLongClick callback to be called when the selectable surface is long clicked
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/SurfaceDefaults.kt b/tv/tv-material/src/main/java/androidx/tv/material3/SurfaceDefaults.kt
index 3d32a1c..eeab748 100644
--- a/tv/tv-material/src/main/java/androidx/tv/material3/SurfaceDefaults.kt
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/SurfaceDefaults.kt
@@ -29,14 +29,14 @@
 /**
  * Contains the default values used by a non-interactive [Surface]
  */
-object NonInteractiveSurfaceDefaults {
+object SurfaceDefaults {
     /**
      * Represents the default shape used by a non-interactive [Surface]
      */
     val shape: Shape @ReadOnlyComposable @Composable get() = RectangleShape
 
     /**
-     * Creates a [NonInteractiveSurfaceColors] that represents the default container & content
+     * Creates a [SurfaceColors] that represents the default container & content
      * colors used by a non-interactive [Surface].
      *
      * @param containerColor the container color of this Surface
@@ -47,7 +47,7 @@
     fun colors(
         containerColor: Color = MaterialTheme.colorScheme.surface,
         contentColor: Color = contentColorFor(containerColor)
-    ) = NonInteractiveSurfaceColors(
+    ) = SurfaceColors(
         containerColor = containerColor,
         contentColor = contentColor
     )
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/SurfaceStyles.kt b/tv/tv-material/src/main/java/androidx/tv/material3/SurfaceStyles.kt
index bf922e6..026f4b4 100644
--- a/tv/tv-material/src/main/java/androidx/tv/material3/SurfaceStyles.kt
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/SurfaceStyles.kt
@@ -597,7 +597,7 @@
  * Defines the container & content color [Color] for a non interactive surface.
  */
 @Immutable
-class NonInteractiveSurfaceColors internal constructor(
+class SurfaceColors internal constructor(
     internal val containerColor: Color,
     internal val contentColor: Color
 ) {
@@ -605,7 +605,7 @@
         if (this === other) return true
         if (other == null || this::class != other::class) return false
 
-        other as NonInteractiveSurfaceColors
+        other as SurfaceColors
 
         if (containerColor != other.containerColor) return false
         if (contentColor != other.contentColor) return false
@@ -620,7 +620,7 @@
     }
 
     override fun toString(): String {
-        return "NonInteractiveSurfaceColors(containerColor=$containerColor, " +
+        return "SurfaceColors(containerColor=$containerColor, " +
             "contentColor=$contentColor)"
     }
 }
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/TabRow.kt b/tv/tv-material/src/main/java/androidx/tv/material3/TabRow.kt
index 2b19522..82481b31 100644
--- a/tv/tv-material/src/main/java/androidx/tv/material3/TabRow.kt
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/TabRow.kt
@@ -114,7 +114,7 @@
             .horizontalScroll(scrollState)
             .onFocusChanged { doesTabRowHaveFocus = it.hasFocus }
             .selectableGroup(),
-        colors = NonInteractiveSurfaceDefaults.colors(
+        colors = SurfaceDefaults.colors(
             containerColor = containerColor,
             contentColor = contentColor
         ),
diff --git a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/lazy/ScalingLazyColumnMeasure.kt b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/lazy/ScalingLazyColumnMeasure.kt
index 7584d68..29de39c 100644
--- a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/lazy/ScalingLazyColumnMeasure.kt
+++ b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/lazy/ScalingLazyColumnMeasure.kt
@@ -236,7 +236,7 @@
         if (minTransitionArea != other.minTransitionArea) return false
         if (maxTransitionArea != other.maxTransitionArea) return false
         if (scaleInterpolator != other.scaleInterpolator) return false
-        if (viewportVerticalOffsetResolver != other.viewportVerticalOffsetResolver) return false
+        if (viewportVerticalOffsetResolver !== other.viewportVerticalOffsetResolver) return false
 
         return true
     }
diff --git a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ScalingLazyColumnMeasure.kt b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ScalingLazyColumnMeasure.kt
index b3abd6e..bf11025 100644
--- a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ScalingLazyColumnMeasure.kt
+++ b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ScalingLazyColumnMeasure.kt
@@ -240,7 +240,7 @@
         if (minTransitionArea != other.minTransitionArea) return false
         if (maxTransitionArea != other.maxTransitionArea) return false
         if (scaleInterpolator != other.scaleInterpolator) return false
-        if (viewportVerticalOffsetResolver != other.viewportVerticalOffsetResolver) return false
+        if (viewportVerticalOffsetResolver !== other.viewportVerticalOffsetResolver) return false
 
         return true
     }
diff --git a/wear/compose/compose-material3/build.gradle b/wear/compose/compose-material3/build.gradle
index 955646f..d18ada1 100644
--- a/wear/compose/compose-material3/build.gradle
+++ b/wear/compose/compose-material3/build.gradle
@@ -85,7 +85,7 @@
             "developers to write Jetpack Compose applications for Wearable devices that " +
             "implement Wear Material 3 Design UX guidelines and specifications. It builds upon " +
             "the Jetpack Compose libraries."
-    samples(project(":wear:compose:compose-material-samples"))
+    samples(project(":wear:compose:compose-material3-samples"))
 }
 
 tasks.withType(KotlinCompile).configureEach {
diff --git a/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/Fingerprint.java b/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/Fingerprint.java
index 004bea8..d92eaa5 100644
--- a/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/Fingerprint.java
+++ b/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/Fingerprint.java
@@ -41,7 +41,6 @@
 @RestrictTo(Scope.LIBRARY_GROUP)
 public final class Fingerprint {
     private static final int DEFAULT_VALUE = 0;
-    private static final int DISCARDED_VALUE = -1;
     private final int selfTypeValue;
     private int selfPropsValue;
     private int childNodesValue;
@@ -65,12 +64,9 @@
 
     /**
      * Get the aggregate numeric fingerprint, representing the message itself as well as all its
-     * child nodes. Returns -1 if the fingerprint is discarded.
+     * child nodes.
      */
     public int aggregateValueAsInt() {
-        if (selfPropsValue == DISCARDED_VALUE) {
-            return DISCARDED_VALUE;
-        }
         int aggregateValue = selfTypeValue;
         aggregateValue = (31 * aggregateValue) + selfPropsValue;
         aggregateValue = (31 * aggregateValue) + childNodesValue;
@@ -84,72 +80,29 @@
 
     /**
      * Get the numeric fingerprint for the message's properties only, excluding its type and child
-     * nodes. Returns -1 if the fingerprint is discarded.
+     * nodes.
      */
     public int selfPropsValue() {
         return selfPropsValue;
     }
 
-    /**
-     * Get the numeric fingerprint for the child nodes. Returns -1 if the fingerprint for children
-     * is discarded.
-     *
-     * <p>Note: If {@link #childNodes()} is empty, the children should be considered fully discarded
-     * at this level. Otherwise, at least one of the children is discarded (self discard) and the
-     * fingerprint of each children should be checked individually.
-     */
+    /** Get the numeric fingerprint for the child nodes. */
     public int childNodesValue() {
         return childNodesValue;
     }
 
-    /**
-     * Get the child nodes. Returns empty list if the node has no children, or if the child
-     * fingerprints are discarded.
-     */
+    /** Get the child nodes. Returns empty list if the node has no children. */
     public @NonNull List<Fingerprint> childNodes() {
         return childNodes == null ? Collections.emptyList() : childNodes;
     }
 
     /** Add a child node to this fingerprint. */
     public void addChildNode(@NonNull Fingerprint childNode) {
-        // Even if the children are not discarded directly through discardValued(true), if one of
-        // them is individually discarded, we need to propagate that so that the differ knows it
-        // has to go down one more level. That's why childNodesValue == DISCARDED_VALUE doesn't
-        // necessarily mean all of the children are discarded. childNodes is used to
-        // differentiate these two cases.
-        if (selfPropsValue == DISCARDED_VALUE
-                && childNodesValue == DISCARDED_VALUE
-                && childNodes == null) {
-            return;
-        }
         if (childNodes == null) {
             childNodes = new ArrayList<>();
         }
         childNodes.add(childNode);
-        if (childNode.selfPropsValue == DISCARDED_VALUE) {
-            childNodesValue = DISCARDED_VALUE;
-        } else if (childNodesValue != DISCARDED_VALUE) {
-            childNodesValue = (31 * childNodesValue) + childNode.aggregateValueAsInt();
-        }
-    }
-
-    /**
-     * Discard values of this fingerprint.
-     *
-     * @param includeChildren if True, discards children values of this fingerprints too.
-     */
-    public void discardValues(boolean includeChildren) {
-        if (selfPropsValue == DISCARDED_VALUE
-                && childNodesValue == DISCARDED_VALUE
-                && !includeChildren) {
-            throw new IllegalStateException(
-                    "Container is in discarded state. Children can't be reinstated.");
-        }
-        selfPropsValue = DISCARDED_VALUE;
-        if (includeChildren) {
-            childNodesValue = DISCARDED_VALUE;
-            childNodes = null;
-        }
+        childNodesValue = (31 * childNodesValue) + childNode.aggregateValueAsInt();
     }
 
     /** Record a property value being updated. */
diff --git a/wear/protolayout/protolayout-expression/src/test/java/androidx/wear/protolayout/expression/FingerprintTest.java b/wear/protolayout/protolayout-expression/src/test/java/androidx/wear/protolayout/expression/FingerprintTest.java
index ad075ef..2f99ad8 100644
--- a/wear/protolayout/protolayout-expression/src/test/java/androidx/wear/protolayout/expression/FingerprintTest.java
+++ b/wear/protolayout/protolayout-expression/src/test/java/androidx/wear/protolayout/expression/FingerprintTest.java
@@ -44,34 +44,6 @@
     }
 
     @Test
-    public void discard_clearsSelfFingerprint() {
-        Fingerprint parentFingerPrint = new Fingerprint(SELF_TYPE_VALUE);
-        Fingerprint childFingerPrint = new Fingerprint(SELF_TYPE_VALUE);
-        childFingerPrint.recordPropertyUpdate(FIELD_1, VALUE_HASH1);
-        parentFingerPrint.addChildNode(childFingerPrint);
-
-        parentFingerPrint.discardValues(/* includeChildren= */ false);
-
-        assertThat(parentFingerPrint.selfPropsValue()).isEqualTo(DISCARDED_VALUE);
-        assertThat(parentFingerPrint.childNodes()).containsExactly(childFingerPrint);
-        assertThat(parentFingerPrint.childNodesValue()).isNotEqualTo(DISCARDED_VALUE);
-    }
-
-    @Test
-    public void discard_includeChildren_clearsSelfAndChildrenFingerprint() {
-        Fingerprint parentFingerPrint = new Fingerprint(SELF_TYPE_VALUE);
-        Fingerprint childFingerPrint = new Fingerprint(SELF_TYPE_VALUE);
-        childFingerPrint.recordPropertyUpdate(FIELD_1, VALUE_HASH1);
-        parentFingerPrint.addChildNode(childFingerPrint);
-
-        parentFingerPrint.discardValues(/* includeChildren= */ true);
-
-        assertThat(parentFingerPrint.selfPropsValue()).isEqualTo(DISCARDED_VALUE);
-        assertThat(parentFingerPrint.childNodes()).isEmpty();
-        assertThat(parentFingerPrint.childNodesValue()).isEqualTo(DISCARDED_VALUE);
-    }
-
-    @Test
     public void toProto_fromProto() {
         Fingerprint parentFingerPrint = new Fingerprint(SELF_TYPE_VALUE);
         Fingerprint childFingerPrint = new Fingerprint(SELF_TYPE_VALUE);
diff --git a/wear/protolayout/protolayout-material-core/src/main/java/androidx/wear/protolayout/materialcore/Chip.java b/wear/protolayout/protolayout-material-core/src/main/java/androidx/wear/protolayout/materialcore/Chip.java
index 97cb0f0..0dafa26 100644
--- a/wear/protolayout/protolayout-material-core/src/main/java/androidx/wear/protolayout/materialcore/Chip.java
+++ b/wear/protolayout/protolayout-material-core/src/main/java/androidx/wear/protolayout/materialcore/Chip.java
@@ -307,7 +307,11 @@
                                                     new Corner.Builder()
                                                             .setRadius(radiusOf(mHeight))
                                                             .build())
-                                            .build());
+                                            .build())
+                            .setSemantics(
+                                    new Semantics.Builder()
+                                        .setContentDescription(getCorrectContentDescription())
+                                        .build());
 
             Box.Builder visible =
                     new Box.Builder()
@@ -327,14 +331,9 @@
                             .setWidth(resolveMinTappableWidth())
                             .setHeight(dp(resolveMinTappableHeight()))
                             .setModifiers(
-                                    new Modifiers.Builder()
-                                            .setMetadata(getCorrectMetadataTag())
-                                            .setSemantics(
-                                                    new Semantics.Builder()
-                                                            .setContentDescription(
-                                                                    getCorrectContentDescription())
-                                                            .build())
-                                            .build())
+                                new Modifiers.Builder()
+                                    .setMetadata(getCorrectMetadataTag())
+                                    .build())
                             .addContent(visible.build())
                             .build();
 
@@ -463,7 +462,8 @@
     /** Returns content description of this Chip. */
     @Nullable
     public StringProp getContentDescription() {
-        Semantics semantics = checkNotNull(mImpl.getModifiers()).getSemantics();
+        // Semantics are applied to the visible view.
+        Semantics semantics = checkNotNull(mElement.getModifiers()).getSemantics();
         if (semantics == null) {
             return null;
         }
diff --git a/wear/protolayout/protolayout-material/api/current.txt b/wear/protolayout/protolayout-material/api/current.txt
index fda934c..02d6896 100644
--- a/wear/protolayout/protolayout-material/api/current.txt
+++ b/wear/protolayout/protolayout-material/api/current.txt
@@ -189,6 +189,7 @@
     ctor public Text.Builder(android.content.Context, String);
     method public androidx.wear.protolayout.material.Text build();
     method public androidx.wear.protolayout.material.Text.Builder setColor(androidx.wear.protolayout.ColorBuilders.ColorProp);
+    method public androidx.wear.protolayout.material.Text.Builder setIsScalable(boolean);
     method public androidx.wear.protolayout.material.Text.Builder setItalic(boolean);
     method public androidx.wear.protolayout.material.Text.Builder setMaxLines(@IntRange(from=1) int);
     method public androidx.wear.protolayout.material.Text.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.Modifiers);
diff --git a/wear/protolayout/protolayout-material/api/restricted_current.txt b/wear/protolayout/protolayout-material/api/restricted_current.txt
index fda934c..02d6896 100644
--- a/wear/protolayout/protolayout-material/api/restricted_current.txt
+++ b/wear/protolayout/protolayout-material/api/restricted_current.txt
@@ -189,6 +189,7 @@
     ctor public Text.Builder(android.content.Context, String);
     method public androidx.wear.protolayout.material.Text build();
     method public androidx.wear.protolayout.material.Text.Builder setColor(androidx.wear.protolayout.ColorBuilders.ColorProp);
+    method public androidx.wear.protolayout.material.Text.Builder setIsScalable(boolean);
     method public androidx.wear.protolayout.material.Text.Builder setItalic(boolean);
     method public androidx.wear.protolayout.material.Text.Builder setMaxLines(@IntRange(from=1) int);
     method public androidx.wear.protolayout.material.Text.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.Modifiers);
diff --git a/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/Chip.java b/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/Chip.java
index e256216..26f4d3f 100644
--- a/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/Chip.java
+++ b/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/Chip.java
@@ -368,7 +368,7 @@
             }
         }
 
-        @SuppressWarnings("deprecation") // ELLIPSIZE_END as existing API
+        @SuppressWarnings("deprecation") // TEXT_OVERFLOW_ELLIPSIZE_END as existing API
         private void setCorrectContent() {
             if (mImageResourceId != null) {
                 Image icon =
diff --git a/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/Text.java b/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/Text.java
index f50c11f..1dd0856 100644
--- a/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/Text.java
+++ b/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/Text.java
@@ -151,7 +151,9 @@
         // Text size is always set in SP, however, by setting this field, we do calculation to
         // interpret it like DP. When getting the text font's size in getters, there is no way to
         // know whether that size was scaled or not.
-        Builder setIsScalable(boolean isScalable) {
+        @NonNull
+        @SuppressWarnings("MissingGetterMatchingBuilder")
+        public Builder setIsScalable(boolean isScalable) {
             this.mIsScalable = isScalable;
             return this;
         }
diff --git a/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/Typography.java b/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/Typography.java
index a297558..9e1613e 100644
--- a/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/Typography.java
+++ b/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/Typography.java
@@ -185,7 +185,7 @@
 
     @NonNull
     @SuppressLint("ResourceType")
-    @SuppressWarnings("deprecation")
+    @SuppressWarnings("deprecation") // scaledDensity, b/335215227
     // This is a helper function to make the font not scalable. It should interpret in value as DP
     // and convert it to SP which is needed to be passed in as a font size. However, we will pass an
     // SP object to it, because the default style is defined in it, but for the case when the font
diff --git a/wear/protolayout/protolayout-proto/src/main/proto/layout.proto b/wear/protolayout/protolayout-proto/src/main/proto/layout.proto
index 32eec63..e55a6199d 100644
--- a/wear/protolayout/protolayout-proto/src/main/proto/layout.proto
+++ b/wear/protolayout/protolayout-proto/src/main/proto/layout.proto
@@ -136,6 +136,32 @@
   // body text, which can be selected using this field. If not specified,
   // defaults to "body".
   FontVariantProp variant = 7;
+
+  // The collection of font variation settings to be applied.
+  //
+  // Supported settings depend on the font used and renderer version. Renderers supporting 1.4 will
+  // have custom weight always available. If this is used with the variable fonts on those
+  // renderers, width setting will be always available too.
+  FontVariation variation_settings = 8;
+}
+
+// The collection of font variation settings.
+//
+// Supported settings depend on the font used and renderer version. Renderers supporting 1.4 will
+// have custom weight always available. If this is used with the variable fonts on those renderers,
+// width setting will be always available too.
+message FontVariation {
+  // A single point of customization in a variation, with axis name and a value for it.
+  repeated Setting settings = 1;
+}
+
+// A single point of customization in a variation, with axis name and a value for it.
+message Setting {
+  // The axis name for this setting. This represents a 4 ASCII characters tag.
+  fixed32 axis_name = 1;
+
+  // The value for this setting.
+  float variation_value = 2;
 }
 
 // How text that will not fit inside the bounds of a Text element will be
diff --git a/wear/protolayout/protolayout/api/current.txt b/wear/protolayout/protolayout/api/current.txt
index 24afe14..e950512 100644
--- a/wear/protolayout/protolayout/api/current.txt
+++ b/wear/protolayout/protolayout/api/current.txt
@@ -1153,8 +1153,8 @@
   }
 
   @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=400) public static final class ModifiersBuilders.Transformation {
-    method public androidx.wear.protolayout.DimensionBuilders.PivotDimension? getPivotX();
-    method public androidx.wear.protolayout.DimensionBuilders.PivotDimension? getPivotY();
+    method public androidx.wear.protolayout.DimensionBuilders.PivotDimension getPivotX();
+    method public androidx.wear.protolayout.DimensionBuilders.PivotDimension getPivotY();
     method public androidx.wear.protolayout.DimensionBuilders.DegreesProp getRotation();
     method public androidx.wear.protolayout.TypeBuilders.FloatProp getScaleX();
     method public androidx.wear.protolayout.TypeBuilders.FloatProp getScaleY();
diff --git a/wear/protolayout/protolayout/api/restricted_current.txt b/wear/protolayout/protolayout/api/restricted_current.txt
index 24afe14..e950512 100644
--- a/wear/protolayout/protolayout/api/restricted_current.txt
+++ b/wear/protolayout/protolayout/api/restricted_current.txt
@@ -1153,8 +1153,8 @@
   }
 
   @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=400) public static final class ModifiersBuilders.Transformation {
-    method public androidx.wear.protolayout.DimensionBuilders.PivotDimension? getPivotX();
-    method public androidx.wear.protolayout.DimensionBuilders.PivotDimension? getPivotY();
+    method public androidx.wear.protolayout.DimensionBuilders.PivotDimension getPivotX();
+    method public androidx.wear.protolayout.DimensionBuilders.PivotDimension getPivotY();
     method public androidx.wear.protolayout.DimensionBuilders.DegreesProp getRotation();
     method public androidx.wear.protolayout.TypeBuilders.FloatProp getScaleX();
     method public androidx.wear.protolayout.TypeBuilders.FloatProp getScaleY();
diff --git a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ModifiersBuilders.java b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ModifiersBuilders.java
index a6bb9fe..c3f280c 100644
--- a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ModifiersBuilders.java
+++ b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ModifiersBuilders.java
@@ -1399,28 +1399,30 @@
         }
 
         /**
-         * Sets the x offset of the point around which the element is rotated and scaled.
-         * Dynamic value is supported.
+         * Gets the horizontal location of the point around which the element is rotated and scaled.
+         * With type {@link DpProp}, it is the offset from the element center; otherwise with type
+         * {@link BoundingBoxRatio}, it is the location proportional to the bounding box width.
          */
-        @Nullable
+        @NonNull
         public PivotDimension getPivotX() {
             if (mImpl.hasPivotX()) {
                 return DimensionBuilders.pivotDimensionFromProto(mImpl.getPivotX());
             } else {
-                return null;
+                return new DpProp.Builder(0f).build();
             }
         }
 
         /**
-         * Gets the y offset of the point around which the element is rotated and scaled.
-         * Dynamic value is supported.
+         * Gets the vertical location of the point around which the element is rotated and scaled.
+         * With type {@link DpProp}, it is the offset from the element center; otherwise with type
+         * {@link BoundingBoxRatio}, it is the location proportional to the bounding box height.
          */
-        @Nullable
+        @NonNull
         public PivotDimension getPivotY() {
             if (mImpl.hasPivotY()) {
                 return DimensionBuilders.pivotDimensionFromProto(mImpl.getPivotY());
             } else {
-                return null;
+                return new DpProp.Builder(0f).build();
             }
         }
 
@@ -1548,8 +1550,10 @@
             }
 
             /**
-             * Sets the x offset of the point around which the element is rotated and scaled.
-             * Dynamic value is supported. If not set, defaults to the element center.
+             * Sets the horizontal location of the point around which the element is rotated and
+             * scaled. With type {@link DpProp}, it is the offset from the element center; otherwise
+             * with type {@link BoundingBoxRatio}, it is the location proportional to the bounding
+             * box width. Dynamic value is supported. If not set, defaults to the element center.
              */
             @RequiresSchemaVersion(major = 1, minor = 400)
             @NonNull
@@ -1561,8 +1565,10 @@
             }
 
             /**
-             * Sets the y offset of the point around which the element is rotated and scaled.
-             * Dynamic value is supported. If not set, defaults to the element center.
+             * Sets the vertical location of the point around which the element is rotated and
+             * scaled. With type {@link DpProp}, it is the offset from the element center; otherwise
+             * with type {@link BoundingBoxRatio}, it is the location proportional to the bounding
+             * box height. Dynamic value is supported. If not set, defaults to the element center.
              */
             @RequiresSchemaVersion(major = 1, minor = 400)
             @NonNull
diff --git a/window/window-core/api/1.3.0-beta02.txt b/window/window-core/api/1.3.0-beta02.txt
index 5f75b34..aa7ee82 100644
--- a/window/window-core/api/1.3.0-beta02.txt
+++ b/window/window-core/api/1.3.0-beta02.txt
@@ -19,15 +19,10 @@
   }
 
   public final class WindowSizeClass {
-    ctor public WindowSizeClass(int widthDp, int heightDp);
     method public static androidx.window.core.layout.WindowSizeClass compute(float dpWidth, float dpHeight);
     method @SuppressCompatibility @androidx.window.core.ExperimentalWindowCoreApi public static androidx.window.core.layout.WindowSizeClass compute(int widthPx, int heightPx, float density);
-    method public int getHeightDp();
-    method public int getWidthDp();
     method public androidx.window.core.layout.WindowHeightSizeClass getWindowHeightSizeClass();
     method public androidx.window.core.layout.WindowWidthSizeClass getWindowWidthSizeClass();
-    property public final int heightDp;
-    property public final int widthDp;
     property public final androidx.window.core.layout.WindowHeightSizeClass windowHeightSizeClass;
     property public final androidx.window.core.layout.WindowWidthSizeClass windowWidthSizeClass;
     field public static final androidx.window.core.layout.WindowSizeClass.Companion Companion;
@@ -38,16 +33,6 @@
     method @SuppressCompatibility @androidx.window.core.ExperimentalWindowCoreApi public androidx.window.core.layout.WindowSizeClass compute(int widthPx, int heightPx, float density);
   }
 
-  public final class WindowSizeClassScoreCalculator {
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowCoreApi public static int scoreWithinAreaBounds(androidx.window.core.layout.WindowSizeClass, int windowWidthDp, int windowHeightDp);
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowCoreApi public static int scoreWithinHeightDp(androidx.window.core.layout.WindowSizeClass, int heightDp);
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowCoreApi public static int scoreWithinWidthDp(androidx.window.core.layout.WindowSizeClass, int widthDp);
-  }
-
-  public final class WindowSizeClassSelectors {
-    method public static androidx.window.core.layout.WindowSizeClass? widestOrEqualWidthDp(java.util.Set<androidx.window.core.layout.WindowSizeClass>, int windowWidthDp, int windowHeightDp);
-  }
-
   public final class WindowWidthSizeClass {
     field public static final androidx.window.core.layout.WindowWidthSizeClass COMPACT;
     field public static final androidx.window.core.layout.WindowWidthSizeClass.Companion Companion;
diff --git a/window/window-core/api/current.ignore b/window/window-core/api/current.ignore
new file mode 100644
index 0000000..6f2176b
--- /dev/null
+++ b/window/window-core/api/current.ignore
@@ -0,0 +1,13 @@
+// Baseline format: 1.0
+RemovedClass: androidx.window.core.layout.WindowSizeClassScoreCalculator:
+    Removed class androidx.window.core.layout.WindowSizeClassScoreCalculator
+RemovedClass: androidx.window.core.layout.WindowSizeClassSelectors:
+    Removed class androidx.window.core.layout.WindowSizeClassSelectors
+
+
+RemovedMethod: androidx.window.core.layout.WindowSizeClass#WindowSizeClass(int, int):
+    Removed constructor androidx.window.core.layout.WindowSizeClass(int,int)
+RemovedMethod: androidx.window.core.layout.WindowSizeClass#getHeightDp():
+    Removed method androidx.window.core.layout.WindowSizeClass.getHeightDp()
+RemovedMethod: androidx.window.core.layout.WindowSizeClass#getWidthDp():
+    Removed method androidx.window.core.layout.WindowSizeClass.getWidthDp()
diff --git a/window/window-core/api/current.txt b/window/window-core/api/current.txt
index 5f75b34..aa7ee82 100644
--- a/window/window-core/api/current.txt
+++ b/window/window-core/api/current.txt
@@ -19,15 +19,10 @@
   }
 
   public final class WindowSizeClass {
-    ctor public WindowSizeClass(int widthDp, int heightDp);
     method public static androidx.window.core.layout.WindowSizeClass compute(float dpWidth, float dpHeight);
     method @SuppressCompatibility @androidx.window.core.ExperimentalWindowCoreApi public static androidx.window.core.layout.WindowSizeClass compute(int widthPx, int heightPx, float density);
-    method public int getHeightDp();
-    method public int getWidthDp();
     method public androidx.window.core.layout.WindowHeightSizeClass getWindowHeightSizeClass();
     method public androidx.window.core.layout.WindowWidthSizeClass getWindowWidthSizeClass();
-    property public final int heightDp;
-    property public final int widthDp;
     property public final androidx.window.core.layout.WindowHeightSizeClass windowHeightSizeClass;
     property public final androidx.window.core.layout.WindowWidthSizeClass windowWidthSizeClass;
     field public static final androidx.window.core.layout.WindowSizeClass.Companion Companion;
@@ -38,16 +33,6 @@
     method @SuppressCompatibility @androidx.window.core.ExperimentalWindowCoreApi public androidx.window.core.layout.WindowSizeClass compute(int widthPx, int heightPx, float density);
   }
 
-  public final class WindowSizeClassScoreCalculator {
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowCoreApi public static int scoreWithinAreaBounds(androidx.window.core.layout.WindowSizeClass, int windowWidthDp, int windowHeightDp);
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowCoreApi public static int scoreWithinHeightDp(androidx.window.core.layout.WindowSizeClass, int heightDp);
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowCoreApi public static int scoreWithinWidthDp(androidx.window.core.layout.WindowSizeClass, int widthDp);
-  }
-
-  public final class WindowSizeClassSelectors {
-    method public static androidx.window.core.layout.WindowSizeClass? widestOrEqualWidthDp(java.util.Set<androidx.window.core.layout.WindowSizeClass>, int windowWidthDp, int windowHeightDp);
-  }
-
   public final class WindowWidthSizeClass {
     field public static final androidx.window.core.layout.WindowWidthSizeClass COMPACT;
     field public static final androidx.window.core.layout.WindowWidthSizeClass.Companion Companion;
diff --git a/window/window-core/api/restricted_1.3.0-beta02.txt b/window/window-core/api/restricted_1.3.0-beta02.txt
index 5f75b34..aa7ee82 100644
--- a/window/window-core/api/restricted_1.3.0-beta02.txt
+++ b/window/window-core/api/restricted_1.3.0-beta02.txt
@@ -19,15 +19,10 @@
   }
 
   public final class WindowSizeClass {
-    ctor public WindowSizeClass(int widthDp, int heightDp);
     method public static androidx.window.core.layout.WindowSizeClass compute(float dpWidth, float dpHeight);
     method @SuppressCompatibility @androidx.window.core.ExperimentalWindowCoreApi public static androidx.window.core.layout.WindowSizeClass compute(int widthPx, int heightPx, float density);
-    method public int getHeightDp();
-    method public int getWidthDp();
     method public androidx.window.core.layout.WindowHeightSizeClass getWindowHeightSizeClass();
     method public androidx.window.core.layout.WindowWidthSizeClass getWindowWidthSizeClass();
-    property public final int heightDp;
-    property public final int widthDp;
     property public final androidx.window.core.layout.WindowHeightSizeClass windowHeightSizeClass;
     property public final androidx.window.core.layout.WindowWidthSizeClass windowWidthSizeClass;
     field public static final androidx.window.core.layout.WindowSizeClass.Companion Companion;
@@ -38,16 +33,6 @@
     method @SuppressCompatibility @androidx.window.core.ExperimentalWindowCoreApi public androidx.window.core.layout.WindowSizeClass compute(int widthPx, int heightPx, float density);
   }
 
-  public final class WindowSizeClassScoreCalculator {
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowCoreApi public static int scoreWithinAreaBounds(androidx.window.core.layout.WindowSizeClass, int windowWidthDp, int windowHeightDp);
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowCoreApi public static int scoreWithinHeightDp(androidx.window.core.layout.WindowSizeClass, int heightDp);
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowCoreApi public static int scoreWithinWidthDp(androidx.window.core.layout.WindowSizeClass, int widthDp);
-  }
-
-  public final class WindowSizeClassSelectors {
-    method public static androidx.window.core.layout.WindowSizeClass? widestOrEqualWidthDp(java.util.Set<androidx.window.core.layout.WindowSizeClass>, int windowWidthDp, int windowHeightDp);
-  }
-
   public final class WindowWidthSizeClass {
     field public static final androidx.window.core.layout.WindowWidthSizeClass COMPACT;
     field public static final androidx.window.core.layout.WindowWidthSizeClass.Companion Companion;
diff --git a/window/window-core/api/restricted_current.ignore b/window/window-core/api/restricted_current.ignore
new file mode 100644
index 0000000..6f2176b
--- /dev/null
+++ b/window/window-core/api/restricted_current.ignore
@@ -0,0 +1,13 @@
+// Baseline format: 1.0
+RemovedClass: androidx.window.core.layout.WindowSizeClassScoreCalculator:
+    Removed class androidx.window.core.layout.WindowSizeClassScoreCalculator
+RemovedClass: androidx.window.core.layout.WindowSizeClassSelectors:
+    Removed class androidx.window.core.layout.WindowSizeClassSelectors
+
+
+RemovedMethod: androidx.window.core.layout.WindowSizeClass#WindowSizeClass(int, int):
+    Removed constructor androidx.window.core.layout.WindowSizeClass(int,int)
+RemovedMethod: androidx.window.core.layout.WindowSizeClass#getHeightDp():
+    Removed method androidx.window.core.layout.WindowSizeClass.getHeightDp()
+RemovedMethod: androidx.window.core.layout.WindowSizeClass#getWidthDp():
+    Removed method androidx.window.core.layout.WindowSizeClass.getWidthDp()
diff --git a/window/window-core/api/restricted_current.txt b/window/window-core/api/restricted_current.txt
index 5f75b34..aa7ee82 100644
--- a/window/window-core/api/restricted_current.txt
+++ b/window/window-core/api/restricted_current.txt
@@ -19,15 +19,10 @@
   }
 
   public final class WindowSizeClass {
-    ctor public WindowSizeClass(int widthDp, int heightDp);
     method public static androidx.window.core.layout.WindowSizeClass compute(float dpWidth, float dpHeight);
     method @SuppressCompatibility @androidx.window.core.ExperimentalWindowCoreApi public static androidx.window.core.layout.WindowSizeClass compute(int widthPx, int heightPx, float density);
-    method public int getHeightDp();
-    method public int getWidthDp();
     method public androidx.window.core.layout.WindowHeightSizeClass getWindowHeightSizeClass();
     method public androidx.window.core.layout.WindowWidthSizeClass getWindowWidthSizeClass();
-    property public final int heightDp;
-    property public final int widthDp;
     property public final androidx.window.core.layout.WindowHeightSizeClass windowHeightSizeClass;
     property public final androidx.window.core.layout.WindowWidthSizeClass windowWidthSizeClass;
     field public static final androidx.window.core.layout.WindowSizeClass.Companion Companion;
@@ -38,16 +33,6 @@
     method @SuppressCompatibility @androidx.window.core.ExperimentalWindowCoreApi public androidx.window.core.layout.WindowSizeClass compute(int widthPx, int heightPx, float density);
   }
 
-  public final class WindowSizeClassScoreCalculator {
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowCoreApi public static int scoreWithinAreaBounds(androidx.window.core.layout.WindowSizeClass, int windowWidthDp, int windowHeightDp);
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowCoreApi public static int scoreWithinHeightDp(androidx.window.core.layout.WindowSizeClass, int heightDp);
-    method @SuppressCompatibility @androidx.window.core.ExperimentalWindowCoreApi public static int scoreWithinWidthDp(androidx.window.core.layout.WindowSizeClass, int widthDp);
-  }
-
-  public final class WindowSizeClassSelectors {
-    method public static androidx.window.core.layout.WindowSizeClass? widestOrEqualWidthDp(java.util.Set<androidx.window.core.layout.WindowSizeClass>, int windowWidthDp, int windowHeightDp);
-  }
-
   public final class WindowWidthSizeClass {
     field public static final androidx.window.core.layout.WindowWidthSizeClass COMPACT;
     field public static final androidx.window.core.layout.WindowWidthSizeClass.Companion Companion;
diff --git a/window/window-core/src/commonMain/kotlin/androidx/window/core/layout/WindowSizeClass.kt b/window/window-core/src/commonMain/kotlin/androidx/window/core/layout/WindowSizeClass.kt
index aa43d8a..8d61d8a1 100644
--- a/window/window-core/src/commonMain/kotlin/androidx/window/core/layout/WindowSizeClass.kt
+++ b/window/window-core/src/commonMain/kotlin/androidx/window/core/layout/WindowSizeClass.kt
@@ -48,36 +48,19 @@
  * In these cases developers may wish to specify their own custom break points and match using
  * a `when` statement.
  *
- * @constructor the primary constructor taking the bounds of the size class.
- * @property widthDp the width in DP for the size class.
- * @property heightDp the height in DP for the size class.
- *
- * @throws IllegalArgumentException if [widthDp] or [heightDp] is negative.
- *
  * @see WindowWidthSizeClass
  * @see WindowHeightSizeClass
  */
-class WindowSizeClass(
-    val widthDp: Int,
-    val heightDp: Int
-) {
-
-    init {
-        require(widthDp >= 0) { "Must have non-negative widthDp: $widthDp." }
-        require(heightDp >= 0) { "Must have non-negative heightDp: $heightDp." }
-    }
-
+class WindowSizeClass private constructor(
     /**
-     * Returns the [WindowWidthSizeClass] that corresponds to the [widthDp].
+     * Returns the [WindowWidthSizeClass] that corresponds to the widthDp of the window.
      */
-    val windowWidthSizeClass: WindowWidthSizeClass
-        get() = WindowWidthSizeClass.compute(widthDp.toFloat())
-
+    val windowWidthSizeClass: WindowWidthSizeClass,
     /**
-     * Returns the [WindowHeightSizeClass] that corresponds to the [heightDp].
+     * Returns the [WindowHeightSizeClass] that corresponds to the heightDp of the window.
      */
     val windowHeightSizeClass: WindowHeightSizeClass
-        get() = WindowHeightSizeClass.compute(heightDp.toFloat())
+) {
 
     override fun equals(other: Any?): Boolean {
         if (this === other) return true
@@ -85,21 +68,22 @@
 
         other as WindowSizeClass
 
-        if (widthDp != other.widthDp) return false
-        if (heightDp != other.heightDp) return false
+        if (windowWidthSizeClass != other.windowWidthSizeClass) return false
+        if (windowHeightSizeClass != other.windowHeightSizeClass) return false
 
         return true
     }
 
     override fun hashCode(): Int {
-        var result = widthDp.hashCode()
-        result = 31 * result + heightDp.hashCode()
+        var result = windowWidthSizeClass.hashCode()
+        result = 31 * result + windowHeightSizeClass.hashCode()
         return result
     }
 
     override fun toString(): String {
-        return "SizeClass { widthDp: $widthDp," +
-            " heightDp: $heightDp }"
+        return "WindowSizeClass {" +
+            "windowWidthSizeClass=$windowWidthSizeClass, " +
+            "windowHeightSizeClass=$windowHeightSizeClass }"
     }
 
     companion object {
@@ -109,23 +93,15 @@
          * @param dpWidth width of a window in DP.
          * @param dpHeight height of a window in DP.
          * @return [WindowSizeClass] that is recommended for the given dimensions.
-         * @see [widestOrEqualWidthDp] for selecting from a custom set of [WindowSizeClass].
          * @throws IllegalArgumentException if [dpWidth] or [dpHeight] is
          * negative.
          */
         @JvmStatic
         fun compute(dpWidth: Float, dpHeight: Float): WindowSizeClass {
-            val widthDp = when {
-                dpWidth < 600 -> 0
-                dpWidth < 840 -> 600
-                else -> 840
-            }
-            val heightDp = when {
-                dpHeight < 480 -> 0
-                dpHeight < 900 -> 480
-                else -> 900
-            }
-            return WindowSizeClass(widthDp, heightDp)
+            return WindowSizeClass(
+                WindowWidthSizeClass.compute(dpWidth),
+                WindowHeightSizeClass.compute(dpHeight)
+            )
         }
 
         /**
diff --git a/window/window-core/src/commonMain/kotlin/androidx/window/core/layout/WindowSizeClassScoreCalculator.kt b/window/window-core/src/commonMain/kotlin/androidx/window/core/layout/WindowSizeClassScoreCalculator.kt
deleted file mode 100644
index e105f90..0000000
--- a/window/window-core/src/commonMain/kotlin/androidx/window/core/layout/WindowSizeClassScoreCalculator.kt
+++ /dev/null
@@ -1,72 +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.
- */
-@file:JvmName("WindowSizeClassScoreCalculator")
-package androidx.window.core.layout
-
-import androidx.window.core.ExperimentalWindowCoreApi
-
-/**
- * A scoring function to calculate how close the width of a [WindowSizeClass] is to [widthDp]
- * without exceeding it.
- *
- * @param widthDp the width bound to try to match.
- * @return an integer from -1 to [Integer.MAX_VALUE] where a larger value indicates a better match.
- */
-@ExperimentalWindowCoreApi
-fun WindowSizeClass.scoreWithinWidthDp(widthDp: Int): Int {
-    return if (this.widthDp <= widthDp) {
-        Integer.MAX_VALUE / (1 + widthDp - this.widthDp)
-    } else {
-        -1
-    }
-}
-
-/**
- * A scoring function to calculate how close the height of a [WindowSizeClass] is to [heightDp]
- * without exceeding it.
- *
- * @param heightDp the height bound to try to match.
- * @return an integer from -1 to [Integer.MAX_VALUE] where a larger value indicates a better match.
- */
-@ExperimentalWindowCoreApi
-fun WindowSizeClass.scoreWithinHeightDp(heightDp: Int): Int {
-    return if (this.heightDp <= heightDp) {
-        Integer.MAX_VALUE / (1 + heightDp - this.heightDp)
-    } else {
-        -1
-    }
-}
-
-/**
- * A scoring function to calculate how close the area of a [WindowSizeClass] is to the area of a
- * window without exceeding it.
- *
- * @param windowWidthDp the width of a window constraint.
- * @param windowHeightDp the height of a window constraint.
- *
- * @return an integer from -1 to [Integer.MAX_VALUE] where a larger value indicates a better match.
- */
-@ExperimentalWindowCoreApi
-fun WindowSizeClass.scoreWithinAreaBounds(
-    windowWidthDp: Int,
-    windowHeightDp: Int
-): Int {
-    if (windowWidthDp < this.widthDp || windowHeightDp < this.heightDp) {
-        return -1
-    }
-    val areaDifference = windowWidthDp * windowHeightDp - this.widthDp * this.heightDp
-    return Integer.MAX_VALUE / (1 + areaDifference)
-}
diff --git a/window/window-core/src/commonMain/kotlin/androidx/window/core/layout/WindowSizeClassSelectors.kt b/window/window-core/src/commonMain/kotlin/androidx/window/core/layout/WindowSizeClassSelectors.kt
deleted file mode 100644
index 529b376..0000000
--- a/window/window-core/src/commonMain/kotlin/androidx/window/core/layout/WindowSizeClassSelectors.kt
+++ /dev/null
@@ -1,62 +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.
- */
-@file:JvmName("WindowSizeClassSelectors")
-package androidx.window.core.layout
-
-/**
- * Calculates which [WindowSizeClass] has the closest matching [windowWidthDp] within the given
- * value. If there are multiple matches then the tallest [WindowSizeClass] is selected within the
- * given value.
- *
- * @param windowWidthDp the width of the current window in DP to choose a [WindowSizeClass].
- * @param windowHeightDp the height of the current window in DP to chose a [WindowSizeClass].
- * @return a [WindowSizeClass] that has [WindowSizeClass.widthDp] less than or equal to the
- * [windowWidthDp] and is the closest to [windowWidthDp] if possible `null` otherwise.
- */
-fun Set<WindowSizeClass>.widestOrEqualWidthDp(
-    windowWidthDp: Int,
-    windowHeightDp: Int
-): WindowSizeClass? {
-    require(0 <= windowHeightDp) {
-        "Window height must be non-negative but got windowHeightDp: $windowHeightDp"
-    }
-    require(0 <= windowWidthDp) {
-        "Window width must be non-negative but got windowHeightDp: $windowWidthDp"
-    }
-    var maxValue: WindowSizeClass? = null
-    forEach { sizeClass ->
-        if (sizeClass.widthDp > windowWidthDp) {
-            return@forEach
-        }
-        if (sizeClass.heightDp > windowHeightDp) {
-            return@forEach
-        }
-
-        val localMax = maxValue
-        if (localMax == null) {
-            maxValue = sizeClass
-            return@forEach
-        }
-        if (localMax.widthDp > sizeClass.widthDp) {
-            return@forEach
-        }
-        if (localMax.widthDp == sizeClass.widthDp && sizeClass.heightDp < localMax.heightDp) {
-            return@forEach
-        }
-        maxValue = sizeClass
-    }
-    return maxValue
-}
diff --git a/window/window-core/src/commonTest/kotlin/androidx/window/core/layout/WindowSizeClassScoreCalculatorTest.kt b/window/window-core/src/commonTest/kotlin/androidx/window/core/layout/WindowSizeClassScoreCalculatorTest.kt
deleted file mode 100644
index 1587ff6..0000000
--- a/window/window-core/src/commonTest/kotlin/androidx/window/core/layout/WindowSizeClassScoreCalculatorTest.kt
+++ /dev/null
@@ -1,117 +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.window.core.layout
-
-import androidx.window.core.ExperimentalWindowCoreApi
-import kotlin.test.Test
-import kotlin.test.assertEquals
-import kotlin.test.assertTrue
-
-@OptIn(ExperimentalWindowCoreApi::class)
-class WindowSizeClassScoreCalculatorTest {
-
-    private val widthDp = 100
-    private val heightDp = 200
-
-    @Test
-    fun scoreWindowSizeClassWithinWidthDp_exact_match_has_max_value() {
-        val sizeClass = WindowSizeClass(widthDp, heightDp)
-
-        val actual = sizeClass.scoreWithinWidthDp(widthDp)
-
-        assertEquals(Integer.MAX_VALUE, actual)
-    }
-
-    @Test
-    fun scoreWindowSizeClassWithinWidthDp_too_wide_has_negative_value() {
-        val sizeClass = WindowSizeClass(widthDp, heightDp)
-
-        val actual = sizeClass.scoreWithinWidthDp(widthDp / 2)
-
-        assertEquals(-1, actual)
-    }
-
-    @Test
-    fun scoreWindowSizeClassWithinWidthDp_closer_match_has_larger_value() {
-        val narrowSizeClass = WindowSizeClass(widthDp - 10, heightDp)
-        val wideSizeClass = WindowSizeClass(widthDp - 5, heightDp)
-
-        val narrowScore = narrowSizeClass.scoreWithinWidthDp(widthDp)
-        val widerScore = wideSizeClass.scoreWithinWidthDp(widthDp)
-
-        assertTrue(narrowScore < widerScore)
-    }
-
-    @Test
-    fun scoreWindowSizeClassWithinHeightDp_exact_match_has_max_value() {
-        val sizeClass = WindowSizeClass(widthDp, heightDp)
-
-        val actual = sizeClass.scoreWithinHeightDp(heightDp)
-
-        assertEquals(Integer.MAX_VALUE, actual)
-    }
-
-    @Test
-    fun scoreWindowSizeClassWithinHeightDp_too_tall_has_negative_value() {
-        val sizeClass = WindowSizeClass(widthDp, heightDp)
-
-        val actual = sizeClass.scoreWithinHeightDp(heightDp / 2)
-
-        assertEquals(-1, actual)
-    }
-
-    @Test
-    fun scoreWindowSizeClassWithinHeightDp_closer_match_has_larger_value() {
-        val shortSizeClass = WindowSizeClass(widthDp, heightDp - 10)
-        val tallSizeClass = WindowSizeClass(widthDp, heightDp - 5)
-
-        val narrowScore = shortSizeClass.scoreWithinHeightDp(heightDp)
-        val widerScore = tallSizeClass.scoreWithinHeightDp(heightDp)
-
-        assertTrue(narrowScore < widerScore)
-    }
-
-    @Test
-    fun scoreWindowSizeClassAreaWithinBounds_exact_match_has_max_value() {
-        val sizeClass = WindowSizeClass(widthDp, heightDp)
-
-        val actual = sizeClass.scoreWithinAreaBounds(widthDp, heightDp)
-
-        assertEquals(Integer.MAX_VALUE, actual)
-    }
-
-    @Test
-    fun scoreWindowSizeClassAreaWithinBounds_too_large_has_negative_value() {
-        val sizeClass = WindowSizeClass(widthDp, heightDp)
-
-        val actual = sizeClass.scoreWithinAreaBounds(widthDp - 1, heightDp)
-
-        assertEquals(-1, actual)
-    }
-
-    @Test
-    fun scoreWindowSizeClassAreaWithinBounds_closer_match_has_larger_value() {
-        val smallSizeClass = WindowSizeClass(widthDp - 10, heightDp - 10)
-        val largeSizeClass = WindowSizeClass(widthDp - 5, heightDp - 5)
-
-        val smallScore = smallSizeClass.scoreWithinAreaBounds(widthDp, heightDp)
-        val largeScore = largeSizeClass.scoreWithinAreaBounds(widthDp, heightDp)
-
-        assertTrue(smallScore < largeScore, "Expected smallScore < large score," +
-            " but was false. smallScore: $smallScore, largeScore: $largeScore")
-    }
-}
diff --git a/window/window-core/src/commonTest/kotlin/androidx/window/core/layout/WindowSizeClassSelectorsTest.kt b/window/window-core/src/commonTest/kotlin/androidx/window/core/layout/WindowSizeClassSelectorsTest.kt
deleted file mode 100644
index 2640117..0000000
--- a/window/window-core/src/commonTest/kotlin/androidx/window/core/layout/WindowSizeClassSelectorsTest.kt
+++ /dev/null
@@ -1,108 +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.window.core.layout
-
-import kotlin.test.Test
-import kotlin.test.assertEquals
-import kotlin.test.assertFailsWith
-import kotlin.test.assertNull
-
-class WindowSizeClassSelectorsTest {
-
-    private val widthDp = 100
-    private val heightDp = 200
-
-    @Test
-    fun widestOrEqualWidthDp_return_null_if_no_width_match() {
-        val sizeClass = WindowSizeClass(widthDp, heightDp)
-
-        val actual = setOf(sizeClass).widestOrEqualWidthDp(0, heightDp)
-
-        assertNull(actual)
-    }
-
-    @Test
-    fun widestOrEqualWidthDp_return_widest_match() {
-        val smallSizeClass = WindowSizeClass(widthDp / 2, heightDp)
-        val mediumSizeClass = WindowSizeClass(widthDp, heightDp)
-        val largeSizeClass = WindowSizeClass(widthDp * 2, heightDp)
-
-        val actual = setOf(smallSizeClass, mediumSizeClass, largeSizeClass)
-            .widestOrEqualWidthDp(widthDp + 1, heightDp)
-
-        assertEquals(mediumSizeClass, actual)
-    }
-
-    @Test
-    fun widestOrEqualWidthDp_return_exact_match() {
-        val smallSizeClass = WindowSizeClass(widthDp / 2, heightDp)
-        val mediumSizeClass = WindowSizeClass(widthDp, heightDp)
-        val largeSizeClass = WindowSizeClass(widthDp * 2, heightDp)
-
-        val actual = setOf(smallSizeClass, mediumSizeClass, largeSizeClass)
-            .widestOrEqualWidthDp(widthDp, heightDp)
-
-        assertEquals(mediumSizeClass, actual)
-    }
-
-    @Test
-    fun widestOrEqualWidthDp_multiple_matches_return_width() {
-        val smallSizeClass = WindowSizeClass(widthDp, heightDp / 2)
-        val mediumSizeClass = WindowSizeClass(widthDp, heightDp)
-        val largeSizeClass = WindowSizeClass(widthDp, heightDp * 2)
-
-        val actual = setOf(smallSizeClass, mediumSizeClass, largeSizeClass)
-            .widestOrEqualWidthDp(widthDp, heightDp * 3)
-
-        assertEquals(largeSizeClass, actual)
-    }
-
-    @Test
-    fun widestOrEqualWidth_throws_on_negative_height() {
-        assertFailsWith(IllegalArgumentException::class) {
-            val sizeClass = WindowSizeClass(widthDp, heightDp)
-
-            setOf(sizeClass).widestOrEqualWidthDp(0, -1)
-        }
-    }
-
-    @Test
-    fun widestOrEqualWidth_throws_on_negative_width() {
-        assertFailsWith(IllegalArgumentException::class) {
-            val sizeClass = WindowSizeClass(widthDp, heightDp)
-
-            setOf(sizeClass).widestOrEqualWidthDp(-1, 0)
-        }
-    }
-
-    @Test
-    fun widestOrEqualWidthDp_return_null_if_no_height_match() {
-        val sizeClass = WindowSizeClass(widthDp, heightDp)
-
-        val actual = setOf(sizeClass).widestOrEqualWidthDp(widthDp, heightDp - 1)
-
-        assertNull(actual)
-    }
-
-    @Test
-    fun widestOrEqualWidthDp_return_value_if_has_exact_height_match() {
-        val sizeClass = WindowSizeClass(widthDp, heightDp)
-
-        val actual = setOf(sizeClass).widestOrEqualWidthDp(widthDp, heightDp)
-
-        assertEquals(sizeClass, actual)
-    }
-}
diff --git a/window/window-core/src/commonTest/kotlin/androidx/window/core/layout/WindowSizeClassTest.kt b/window/window-core/src/commonTest/kotlin/androidx/window/core/layout/WindowSizeClassTest.kt
index d026bfd..bc89fda 100644
--- a/window/window-core/src/commonTest/kotlin/androidx/window/core/layout/WindowSizeClassTest.kt
+++ b/window/window-core/src/commonTest/kotlin/androidx/window/core/layout/WindowSizeClassTest.kt
@@ -34,8 +34,8 @@
             WindowWidthSizeClass.EXPANDED
         )
 
-        val actual = listOf(100, 700, 900).map { width ->
-            WindowSizeClass(widthDp = width, heightDp = 100)
+        val actual = listOf(100f, 700f, 900f).map { width ->
+            WindowSizeClass.compute(width, 100f)
         }.map { sizeClass ->
             sizeClass.windowWidthSizeClass
         }
@@ -45,7 +45,7 @@
 
     @Test
     fun testWindowSizeClass_computeRounds() {
-        val expected = WindowSizeClass(0, 0)
+        val expected = WindowSizeClass.compute(0f, 0f)
 
         val actual = WindowSizeClass.compute(300f, 300f)
 
@@ -70,8 +70,8 @@
             WindowHeightSizeClass.EXPANDED
         )
 
-        val actual = listOf(100, 500, 900).map { height ->
-            WindowSizeClass(widthDp = 100, heightDp = height)
+        val actual = listOf(100f, 500f, 900f).map { height ->
+            WindowSizeClass.compute(100f, height)
         }.map { sizeClass ->
             sizeClass.windowHeightSizeClass
         }
@@ -81,15 +81,14 @@
 
     @Test
     fun testEqualsImpliesHashCode() {
-        val first = WindowSizeClass(widthDp = 100, heightDp = 500)
-        val second = WindowSizeClass(widthDp = 100, heightDp = 500)
+        val first = WindowSizeClass.compute(100f, 500f)
+        val second = WindowSizeClass.compute(100f, 500f)
 
         assertEquals(first, second)
         assertEquals(first.hashCode(), second.hashCode())
     }
 
     @Test
-    @Suppress("DEPRECATION")
     fun truncated_float_does_not_throw() {
         val sizeClass = WindowSizeClass.compute(0.5f, 0.5f)
 
@@ -102,7 +101,7 @@
 
     @Test
     fun zero_size_class_does_not_throw() {
-        val sizeClass = WindowSizeClass(0, 0)
+        val sizeClass = WindowSizeClass.compute(0f, 0f)
 
         val widthSizeClass = sizeClass.windowWidthSizeClass
         val heightSizeClass = sizeClass.windowHeightSizeClass
@@ -114,14 +113,14 @@
     @Test
     fun negative_width_throws() {
         assertFailsWith(IllegalArgumentException::class) {
-            WindowSizeClass(-1, 0)
+            WindowSizeClass.compute(-1f, 0f)
         }
     }
 
     @Test
     fun negative_height_throws() {
         assertFailsWith(IllegalArgumentException::class) {
-            WindowSizeClass(0, -1)
+            WindowSizeClass.compute(0f, -1f)
         }
     }
 }
diff --git a/window/window/build.gradle b/window/window/build.gradle
index 4df8a41..0f9e2d0 100644
--- a/window/window/build.gradle
+++ b/window/window/build.gradle
@@ -101,4 +101,5 @@
     // Suppressing deprecation warnings, since there is a need to maintain compatibility with old
     // Sidecar interface.
     failOnDeprecationWarnings = false
+    samples(project(":window:window-samples"))
 }