Merge "Use the underlying language, instead of sourcePsi" into androidx-main
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 733504c..2af4575 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -1,22 +1,22 @@
 # Global owners:
 # Unless a later match takes precedence, global owners will be # requested for
 # review when someone opens a pull request.
-*          @dlam @yigit
+*                  @dlam @yigit
 
 # Owners for each library group:
-/activity*          @jbw0033 @ianhanniballake
-/appcompat/*        @alanv
-/biometric/*        @jbolinger
-/collection/*       @dlam
-/compose/compiler/* @jimgoog @lelandrichardson
-/compose/runtime/*  @jimgoog @lelandrichardson
-/core/*             @alanv
-/datastore/*        @rohitsat13 @yigit
-/fragment/*         @jbw0033 @ianhanniballake
-/lifecycle/*        @jbw0033 @ianhanniballake
-/navigation/*       @jbw0033 @ianhanniballake @claraf3
-/paging/*           @claraf3 @ianhanniballake
-/room/*             @droid-wan-kenobi @danysantiago @svasilinets
-/work/*             @svasilinets @tikurahul
-
+/activity/         @jbw0033 @ianhanniballake
+/annotation/       @jbw0033 @ianhanniballake
+/appcompat/        @alanv
+/biometric/        @jbolinger
+/collection/       @dlam
+/compose/compiler/ @jimgoog @lelandrichardson
+/compose/runtime/  @jimgoog @lelandrichardson
+/core/             @alanv
+/datastore/        @rohitsat13 @yigit
+/fragment/         @jbw0033 @ianhanniballake
+/lifecycle/        @jbw0033 @ianhanniballake
+/navigation/       @jbw0033 @ianhanniballake @claraf3
+/paging/           @claraf3 @ianhanniballake
+/room/             @droid-wan-kenobi @danysantiago @svasilinets
+/work/             @svasilinets @tikurahul
 
diff --git a/benchmark/baseline-profile-gradle-plugin/lint-baseline.xml b/benchmark/baseline-profile-gradle-plugin/lint-baseline.xml
index 5c2583a..6db0d62 100644
--- a/benchmark/baseline-profile-gradle-plugin/lint-baseline.xml
+++ b/benchmark/baseline-profile-gradle-plugin/lint-baseline.xml
@@ -1,8 +1,8 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.4.0-alpha09" type="baseline" client="gradle" dependencies="false" name="AGP (8.4.0-alpha09)" variant="all" version="8.4.0-alpha09">
+<issues format="6" by="lint 8.4.0-alpha12" type="baseline" client="gradle" dependencies="false" name="AGP (8.4.0-alpha12)" variant="all" version="8.4.0-alpha12">
 
     <issue
-        id="InternalGradleApiUsage"
+        id="InternalAgpApiUsage"
         message="Avoid using internal Android Gradle Plugin APIs"
         errorLine1="import com.android.build.gradle.internal.api.DefaultAndroidSourceDirectorySet"
         errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
@@ -11,7 +11,7 @@
     </issue>
 
     <issue
-        id="InternalGradleApiUsage"
+        id="InternalAgpApiUsage"
         message="Avoid using internal Android Gradle Plugin APIs"
         errorLine1="import com.android.build.gradle.internal.api.DefaultAndroidSourceFile"
         errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
@@ -20,7 +20,7 @@
     </issue>
 
     <issue
-        id="InternalGradleApiUsage"
+        id="InternalAgpApiUsage"
         message="Avoid using internal Android Gradle Plugin APIs"
         errorLine1="import com.android.build.gradle.internal.tasks.BuildAnalyzer"
         errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
@@ -29,7 +29,7 @@
     </issue>
 
     <issue
-        id="InternalGradleApiUsage"
+        id="InternalAgpApiUsage"
         message="Avoid using internal Android Gradle Plugin APIs"
         errorLine1="import com.android.build.gradle.internal.tasks.BuildAnalyzer"
         errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
@@ -38,7 +38,7 @@
     </issue>
 
     <issue
-        id="InternalGradleApiUsage"
+        id="InternalAgpApiUsage"
         message="Avoid using internal Android Gradle Plugin APIs"
         errorLine1="import com.android.build.gradle.internal.tasks.BuildAnalyzer"
         errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
@@ -47,7 +47,7 @@
     </issue>
 
     <issue
-        id="InternalGradleApiUsage"
+        id="InternalAgpApiUsage"
         message="Avoid using internal Android Gradle Plugin APIs"
         errorLine1="import com.android.build.gradle.internal.tasks.BuildAnalyzer"
         errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
diff --git a/benchmark/benchmark-macro/api/current.txt b/benchmark/benchmark-macro/api/current.txt
index b9b8d3b..674fd92 100644
--- a/benchmark/benchmark-macro/api/current.txt
+++ b/benchmark/benchmark-macro/api/current.txt
@@ -228,6 +228,9 @@
 
   public static final class PerfettoTraceProcessor.Session {
     method public kotlin.sequences.Sequence<androidx.benchmark.perfetto.Row> query(@org.intellij.lang.annotations.Language("sql") String query);
+    method public String queryMetricsJson(java.util.List<java.lang.String> metrics);
+    method public byte[] queryMetricsProtoBinary(java.util.List<java.lang.String> metrics);
+    method public String queryMetricsProtoText(java.util.List<java.lang.String> metrics);
     method public byte[] rawQuery(@org.intellij.lang.annotations.Language("sql") String query);
   }
 
diff --git a/benchmark/benchmark-macro/api/restricted_current.txt b/benchmark/benchmark-macro/api/restricted_current.txt
index f98e021..52309ce 100644
--- a/benchmark/benchmark-macro/api/restricted_current.txt
+++ b/benchmark/benchmark-macro/api/restricted_current.txt
@@ -250,6 +250,9 @@
 
   public static final class PerfettoTraceProcessor.Session {
     method public kotlin.sequences.Sequence<androidx.benchmark.perfetto.Row> query(@org.intellij.lang.annotations.Language("sql") String query);
+    method public String queryMetricsJson(java.util.List<java.lang.String> metrics);
+    method public byte[] queryMetricsProtoBinary(java.util.List<java.lang.String> metrics);
+    method public String queryMetricsProtoText(java.util.List<java.lang.String> metrics);
     method public byte[] rawQuery(@org.intellij.lang.annotations.Language("sql") String query);
   }
 
diff --git a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/perfetto/PerfettoTraceProcessorTest.kt b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/perfetto/PerfettoTraceProcessorTest.kt
index 021fc1c..5ed23ba 100644
--- a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/perfetto/PerfettoTraceProcessorTest.kt
+++ b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/perfetto/PerfettoTraceProcessorTest.kt
@@ -38,6 +38,7 @@
 import org.junit.Assume.assumeTrue
 import org.junit.Test
 import org.junit.runner.RunWith
+import perfetto.protos.TraceMetrics
 
 @MediumTest
 @RunWith(AndroidJUnit4::class)
@@ -249,6 +250,40 @@
     }
 
     @Test
+    fun queryMetricsJson() {
+        assumeTrue(isAbiSupported())
+        val traceFile = createTempFileFromAsset("api31_startup_cold", ".perfetto-trace")
+        PerfettoTraceProcessor.runSingleSessionServer(traceFile.absolutePath) {
+            val metrics = queryMetricsJson(listOf("android_startup"))
+            assertTrue(metrics.contains("\"android_startup\": {"))
+            assertTrue(metrics.contains("\"startup_type\": \"cold\","))
+        }
+    }
+
+    @Test
+    fun queryMetricsProtoBinary() {
+        assumeTrue(isAbiSupported())
+        val traceFile = createTempFileFromAsset("api31_startup_cold", ".perfetto-trace")
+        PerfettoTraceProcessor.runSingleSessionServer(traceFile.absolutePath) {
+            val metrics =
+                TraceMetrics.ADAPTER.decode(queryMetricsProtoBinary(listOf("android_startup")))
+            val startup = metrics.android_startup!!
+            assertEquals(startup.startup.single().startup_type, "cold")
+        }
+    }
+
+    @Test
+    fun queryMetricsProtoText() {
+        assumeTrue(isAbiSupported())
+        val traceFile = createTempFileFromAsset("api31_startup_cold", ".perfetto-trace")
+        PerfettoTraceProcessor.runSingleSessionServer(traceFile.absolutePath) {
+            val metrics = queryMetricsProtoText(listOf("android_startup"))
+            assertTrue(metrics.contains("android_startup {"))
+            assertTrue(metrics.contains("startup_type: \"cold\""))
+        }
+    }
+
+    @Test
     fun validatePerfettoTraceProcessorBinariesExist() {
         val context = InstrumentationRegistry.getInstrumentation().targetContext
         val suffixes = listOf("aarch64")
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/server/PerfettoHttpServer.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/server/PerfettoHttpServer.kt
index 1fa38b8..6960117 100644
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/server/PerfettoHttpServer.kt
+++ b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/server/PerfettoHttpServer.kt
@@ -210,11 +210,16 @@
     /**
      * Computes the given metrics on a previously parsed trace.
      */
-    fun computeMetric(metrics: List<String>): ComputeMetricResult =
+    fun computeMetric(
+        metrics: List<String>,
+        resultFormat: ComputeMetricArgs.ResultFormat
+    ): ComputeMetricResult =
         httpRequest(
             method = METHOD_POST,
             url = PATH_COMPUTE_METRIC,
-            encodeBlock = { ComputeMetricArgs.ADAPTER.encode(it, ComputeMetricArgs(metrics)) },
+            encodeBlock = {
+                ComputeMetricArgs.ADAPTER.encode(it, ComputeMetricArgs(metrics, resultFormat))
+            },
             decodeBlock = { ComputeMetricResult.ADAPTER.decode(it) }
         )
 
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/perfetto/PerfettoTraceProcessor.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/perfetto/PerfettoTraceProcessor.kt
index af808e9..1960762 100644
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/perfetto/PerfettoTraceProcessor.kt
+++ b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/perfetto/PerfettoTraceProcessor.kt
@@ -29,6 +29,8 @@
 import kotlin.time.Duration
 import kotlin.time.Duration.Companion.seconds
 import org.intellij.lang.annotations.Language
+import perfetto.protos.ComputeMetricArgs
+import perfetto.protos.ComputeMetricResult
 import perfetto.protos.QueryResult
 import perfetto.protos.TraceMetrics
 
@@ -196,22 +198,87 @@
          */
         @RestrictTo(LIBRARY_GROUP) // avoids exposing Proto API
         fun getTraceMetrics(metric: String): TraceMetrics {
-            inMemoryTrace("PerfettoTraceProcessor#getTraceMetrics $metric") {
-                require(!metric.contains(" ")) {
-                    "Metric must not contain spaces: $metric"
-                }
+            val computeResult = queryAndVerifyMetricResult(
+                listOf(metric),
+                ComputeMetricArgs.ResultFormat.BINARY_PROTOBUF
+            )
+            return TraceMetrics.ADAPTER.decode(computeResult.metrics!!)
+        }
+
+        /**
+         * Computes the given metrics, returning the results as a binary proto.
+         *
+         * The proto format definition for decoding this binary format can be found
+         * [here](https://cs.android.com/android/platform/superproject/main/+/main:external/perfetto/protos/perfetto/metrics/).
+         *
+         * See [perfetto metric docs](https://perfetto.dev/docs/quickstart/trace-analysis#trace-based-metrics)
+         * for an overview on trace based metrics.
+         */
+        fun queryMetricsProtoBinary(metrics: List<String>): ByteArray {
+            val computeResult = queryAndVerifyMetricResult(
+                metrics,
+                ComputeMetricArgs.ResultFormat.BINARY_PROTOBUF
+            )
+            return computeResult.metrics!!.toByteArray()
+        }
+
+        /**
+         * Computes the given metrics, returning the results as JSON text.
+         *
+         * The proto format definition for these metrics can be found
+         * [here](https://cs.android.com/android/platform/superproject/main/+/main:external/perfetto/protos/perfetto/metrics/).
+         *
+         * See [perfetto metric docs](https://perfetto.dev/docs/quickstart/trace-analysis#trace-based-metrics)
+         * for an overview on trace based metrics.
+         */
+        fun queryMetricsJson(metrics: List<String>): String {
+            val computeResult = queryAndVerifyMetricResult(
+                metrics,
+                ComputeMetricArgs.ResultFormat.JSON
+            )
+            check(computeResult.metrics_as_json != null)
+            return computeResult.metrics_as_json
+        }
+
+        /**
+         * Computes the given metrics, returning the result as proto text.
+         *
+         * The proto format definition for these metrics can be found
+         * [here](https://cs.android.com/android/platform/superproject/main/+/main:external/perfetto/protos/perfetto/metrics/).
+         *
+         * See [perfetto metric docs](https://perfetto.dev/docs/quickstart/trace-analysis#trace-based-metrics)
+         * for an overview on trace based metrics.
+         */
+        fun queryMetricsProtoText(metrics: List<String>): String {
+            val computeResult = queryAndVerifyMetricResult(
+                metrics,
+                ComputeMetricArgs.ResultFormat.TEXTPROTO
+            )
+            check(computeResult.metrics_as_prototext != null)
+            return computeResult.metrics_as_prototext
+        }
+
+        private fun queryAndVerifyMetricResult(
+            metrics: List<String>,
+            format: ComputeMetricArgs.ResultFormat
+        ): ComputeMetricResult {
+            val nameString = metrics.joinToString()
+            require(metrics.none { it.contains(" ") }) {
+                "Metrics must not constain spaces, metrics: $nameString"
+            }
+
+            inMemoryTrace("PerfettoTraceProcessor#getTraceMetrics $nameString") {
                 require(traceProcessor.perfettoHttpServer.isRunning()) {
                     "Perfetto trace_shell_process is not running."
                 }
 
                 // Compute metrics
-                val computeResult = traceProcessor.perfettoHttpServer.computeMetric(listOf(metric))
+                val computeResult = traceProcessor.perfettoHttpServer.computeMetric(metrics, format)
                 if (computeResult.error != null) {
                     throw IllegalStateException(computeResult.error)
                 }
 
-                // Decode and return trace metrics
-                return TraceMetrics.ADAPTER.decode(computeResult.metrics!!)
+                return computeResult
             }
         }
 
diff --git a/buildSrc-tests/lint-baseline.xml b/buildSrc-tests/lint-baseline.xml
index 82349a5..935864f4 100644
--- a/buildSrc-tests/lint-baseline.xml
+++ b/buildSrc-tests/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.4.0-alpha09" type="baseline" client="gradle" dependencies="false" name="AGP (8.4.0-alpha09)" variant="all" version="8.4.0-alpha09">
+<issues format="6" by="lint 8.4.0-alpha12" type="baseline" client="gradle" dependencies="false" name="AGP (8.4.0-alpha12)" variant="all" version="8.4.0-alpha12">
 
     <issue
         id="EagerGradleConfiguration"
@@ -184,15 +184,6 @@
     <issue
         id="EagerGradleConfiguration"
         message="Avoid using eager method get"
-        errorLine1="                        .get() as ProcessLibraryManifest"
-        errorLine2="                         ~~~">
-        <location
-            file="${:buildSrc-tests*main*MAIN*sourceProvider*0*javaDir*4}/androidx/build/checkapi/ApiTasks.kt"/>
-    </issue>
-
-    <issue
-        id="EagerGradleConfiguration"
-        message="Avoid using eager method get"
         errorLine1="        val jvmJarTask = jvmJarTaskProvider.get()"
         errorLine2="                                            ~~~">
         <location
@@ -353,6 +344,60 @@
     </issue>
 
     <issue
+        id="InternalAgpApiUsage"
+        message="Avoid using internal Android Gradle Plugin APIs"
+        errorLine1="import com.android.build.gradle.internal.lint.AndroidLintAnalysisTask"
+        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="${:buildSrc-tests*main*MAIN*sourceProvider*0*javaDir*4}/androidx/build/LintConfiguration.kt"/>
+    </issue>
+
+    <issue
+        id="InternalAgpApiUsage"
+        message="Avoid using internal Android Gradle Plugin APIs"
+        errorLine1="import com.android.build.gradle.internal.lint.LintModelWriterTask"
+        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="${:buildSrc-tests*main*MAIN*sourceProvider*0*javaDir*4}/androidx/build/LintConfiguration.kt"/>
+    </issue>
+
+    <issue
+        id="InternalAgpApiUsage"
+        message="Avoid using internal Android Gradle Plugin APIs"
+        errorLine1="import com.android.build.gradle.internal.lint.VariantInputs"
+        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="${:buildSrc-tests*main*MAIN*sourceProvider*0*javaDir*4}/androidx/build/LintConfiguration.kt"/>
+    </issue>
+
+    <issue
+        id="InternalAgpApiUsage"
+        message="Avoid using internal Android Gradle Plugin APIs"
+        errorLine1="import com.android.build.gradle.internal.attributes.VariantAttr"
+        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="${:buildSrc-tests*main*MAIN*sourceProvider*0*javaDir*4}/androidx/build/testConfiguration/TestSuiteConfiguration.kt"/>
+    </issue>
+
+    <issue
+        id="InternalAgpApiUsage"
+        message="Avoid using internal Android Gradle Plugin APIs"
+        errorLine1="import com.android.build.gradle.internal.publishing.AndroidArtifacts"
+        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="${:buildSrc-tests*main*MAIN*sourceProvider*0*javaDir*4}/androidx/build/testConfiguration/TestSuiteConfiguration.kt"/>
+    </issue>
+
+    <issue
+        id="InternalAgpApiUsage"
+        message="Avoid using internal Android Gradle Plugin APIs"
+        errorLine1="import com.android.build.gradle.internal.publishing.AndroidArtifacts.ArtifactType"
+        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="${:buildSrc-tests*main*MAIN*sourceProvider*0*javaDir*4}/androidx/build/testConfiguration/TestSuiteConfiguration.kt"/>
+    </issue>
+
+    <issue
         id="InternalGradleApiUsage"
         message="Avoid using internal Gradle APIs"
         errorLine1="import org.gradle.api.internal.artifacts.dependencies.DefaultExternalModuleDependency"
@@ -435,33 +480,6 @@
 
     <issue
         id="InternalGradleApiUsage"
-        message="Avoid using internal Android Gradle Plugin APIs"
-        errorLine1="import com.android.build.gradle.internal.lint.AndroidLintAnalysisTask"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="${:buildSrc-tests*main*MAIN*sourceProvider*0*javaDir*4}/androidx/build/LintConfiguration.kt"/>
-    </issue>
-
-    <issue
-        id="InternalGradleApiUsage"
-        message="Avoid using internal Android Gradle Plugin APIs"
-        errorLine1="import com.android.build.gradle.internal.lint.LintModelWriterTask"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="${:buildSrc-tests*main*MAIN*sourceProvider*0*javaDir*4}/androidx/build/LintConfiguration.kt"/>
-    </issue>
-
-    <issue
-        id="InternalGradleApiUsage"
-        message="Avoid using internal Android Gradle Plugin APIs"
-        errorLine1="import com.android.build.gradle.internal.lint.VariantInputs"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="${:buildSrc-tests*main*MAIN*sourceProvider*0*javaDir*4}/androidx/build/LintConfiguration.kt"/>
-    </issue>
-
-    <issue
-        id="InternalGradleApiUsage"
         message="Avoid using internal Gradle APIs"
         errorLine1="import org.gradle.api.internal.component.SoftwareComponentInternal"
         errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
@@ -516,33 +534,6 @@
 
     <issue
         id="InternalGradleApiUsage"
-        message="Avoid using internal Android Gradle Plugin APIs"
-        errorLine1="import com.android.build.gradle.internal.attributes.VariantAttr"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="${:buildSrc-tests*main*MAIN*sourceProvider*0*javaDir*4}/androidx/build/testConfiguration/TestSuiteConfiguration.kt"/>
-    </issue>
-
-    <issue
-        id="InternalGradleApiUsage"
-        message="Avoid using internal Android Gradle Plugin APIs"
-        errorLine1="import com.android.build.gradle.internal.publishing.AndroidArtifacts"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="${:buildSrc-tests*main*MAIN*sourceProvider*0*javaDir*4}/androidx/build/testConfiguration/TestSuiteConfiguration.kt"/>
-    </issue>
-
-    <issue
-        id="InternalGradleApiUsage"
-        message="Avoid using internal Android Gradle Plugin APIs"
-        errorLine1="import com.android.build.gradle.internal.publishing.AndroidArtifacts.ArtifactType"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="${:buildSrc-tests*main*MAIN*sourceProvider*0*javaDir*4}/androidx/build/testConfiguration/TestSuiteConfiguration.kt"/>
-    </issue>
-
-    <issue
-        id="InternalGradleApiUsage"
         message="Avoid using internal Gradle APIs"
         errorLine1="import org.gradle.internal.logging.slf4j.OutputEventListenerBackedLogger"
         errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt
index 7c788c4..983c914 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt
@@ -977,7 +977,7 @@
         defaultConfig.targetSdk = project.defaultAndroidConfig.targetSdk
         defaultConfig.testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
 
-        testOptions.animationsDisabled = true
+        testOptions.animationsDisabled = !project.isMacrobenchmark()
         testOptions.unitTests.isReturnDefaultValues = true
         testOptions.unitTests.all { task ->
             task.configureForRobolectric()
@@ -1491,6 +1491,10 @@
     return this.plugins.hasPlugin(BenchmarkPlugin::class.java)
 }
 
+fun Project.isMacrobenchmark(): Boolean {
+    return this.path.endsWith("macrobenchmark")
+}
+
 /**
  * Returns a string that is a valid filename and loosely based on the project name The value
  * returned for each project will be distinct
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/VerifyDependencyVersionsTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/VerifyDependencyVersionsTask.kt
index 8e05eea..6a357b2 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/VerifyDependencyVersionsTask.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/VerifyDependencyVersionsTask.kt
@@ -146,7 +146,7 @@
             task.androidXDependencySet.set(
                 project.provider {
                     val dependencies = mutableSetOf<AndroidXDependency>()
-                    project.configurations.filter(::shouldVerifyConfiguration).forEach {
+                    project.configurations.filter(project::shouldVerifyConfiguration).forEach {
                         configuration ->
                         configuration.allDependencies.filter(::shouldVerifyDependency).forEach {
                             dependency ->
@@ -165,11 +165,12 @@
             )
             task.cacheEvenIfNoOutputs()
         }
+
     addToBuildOnServer(taskProvider)
     return taskProvider
 }
 
-private fun shouldVerifyConfiguration(configuration: Configuration): Boolean {
+private fun Project.shouldVerifyConfiguration(configuration: Configuration): Boolean {
     // Only verify configurations that are exported to POM. In an ideal world, this would be an
     // inclusion derived from the mappings used by the Maven Publish Plugin; however, since we
     // don't have direct access to those, this should remain an exclusion list.
@@ -217,11 +218,15 @@
     if (name.endsWith("DependenciesMetadata")) return false
 
     // don't verify test configurations of KMP projects
-    if (name.contains("JvmTest")) return false
-    if (name.contains("commonTest")) return false
-    if (name.contains("nativeTest")) return false
     if (name.contains("TestCompilation")) return false
     if (name.contains("TestCompile")) return false
+    if (name.contains("commonTest", ignoreCase = true)) return false
+    if (name.contains("nativeTest", ignoreCase = true)) return false
+    if (multiplatformExtension?.targets
+            ?.any { name.contains("${it.name}Test", ignoreCase = true) } == true
+    ) {
+        return false
+    }
 
     return true
 }
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/testConfiguration/GenerateTestConfigurationTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/testConfiguration/GenerateTestConfigurationTask.kt
index 8fe822f..c890c2a 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/testConfiguration/GenerateTestConfigurationTask.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/testConfiguration/GenerateTestConfigurationTask.kt
@@ -93,10 +93,10 @@
 
     @get:Internal abstract val testLoader: Property<BuiltArtifactsLoader>
 
-    @get:Input abstract val testProjectPath: Property<String>
-
     @get:Input abstract val minSdk: Property<Int>
 
+    @get:Input abstract val macrobenchmark: Property<Boolean>
+
     @get:Input abstract val hasBenchmarkPlugin: Property<Boolean>
 
     @get:Input abstract val testRunner: Property<String>
@@ -192,7 +192,7 @@
                 // they run with dryRunMode to check crashes don't happen, without measurement
                 configBuilder.tag("androidx_unit_tests")
             }
-        } else if (testProjectPath.get().endsWith("macrobenchmark")) {
+        } else if (macrobenchmark.get()) {
             // macro benchmarks do not have a dryRunMode, so we don't run them in presubmit
             configBuilder.isMacrobenchmark(true)
             configBuilder.tag("macrobenchmarks")
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/testConfiguration/TestSuiteConfiguration.kt b/buildSrc/private/src/main/kotlin/androidx/build/testConfiguration/TestSuiteConfiguration.kt
index 9d04ef0..898da44 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/testConfiguration/TestSuiteConfiguration.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/testConfiguration/TestSuiteConfiguration.kt
@@ -25,6 +25,7 @@
 import androidx.build.getPrivacySandboxFilesDirectory
 import androidx.build.getSupportRootFolder
 import androidx.build.hasBenchmarkPlugin
+import androidx.build.isMacrobenchmark
 import androidx.build.isPresubmitBuild
 import androidx.build.multiplatformExtension
 import com.android.build.api.artifact.Artifacts
@@ -124,10 +125,9 @@
             task.presubmit.set(isPresubmitBuild())
             task.instrumentationArgs.putAll(instrumentationRunnerArgs)
             task.minSdk.set(minSdk)
-            val hasBenchmarkPlugin = hasBenchmarkPlugin()
-            task.hasBenchmarkPlugin.set(hasBenchmarkPlugin)
+            task.hasBenchmarkPlugin.set(hasBenchmarkPlugin())
+            task.macrobenchmark.set(isMacrobenchmark())
             task.testRunner.set(testRunner)
-            task.testProjectPath.set(path)
             // Skip task if getTestSourceSetsForAndroid is empty, even if
             //  androidXExtension.deviceTests.enabled is set to true
             task.androidTestSourceCodeCollection.from(getTestSourceSetsForAndroid())
diff --git a/camera/camera-camera2-pipe-integration/OWNERS b/camera/camera-camera2-pipe-integration/OWNERS
index c445688..6df0fb2 100644
--- a/camera/camera-camera2-pipe-integration/OWNERS
+++ b/camera/camera-camera2-pipe-integration/OWNERS
@@ -2,3 +2,8 @@
 codelogic@google.com
 sushilnath@google.com
 lnishan@google.com
+fungja@google.com
+scottnien@google.com
+trevormcguire@google.com
+kailianc@google.com
+wenhungteng@google.com
\ No newline at end of file
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/SessionProcessorManager.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/SessionProcessorManager.kt
index db8129e..861f79f 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/SessionProcessorManager.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/SessionProcessorManager.kt
@@ -195,8 +195,9 @@
         val processorSessionConfig = synchronized(lock) {
             if (isClosed()) return@launch configure(null)
             try {
-                DeferrableSurfaces.incrementAll(deferrableSurfaces)
-                postviewDeferrableSurface?.incrementUseCount()
+                val surfacesToIncrement = ArrayList(deferrableSurfaces)
+                postviewDeferrableSurface?.let { surfacesToIncrement.add(it) }
+                DeferrableSurfaces.incrementAll(surfacesToIncrement)
             } catch (exception: DeferrableSurface.SurfaceClosedException) {
                 sessionConfigAdapter.reportSurfaceInvalid(exception.deferrableSurface)
                 return@launch configure(null)
diff --git a/camera/camera-camera2-pipe-testing/OWNERS b/camera/camera-camera2-pipe-testing/OWNERS
index c445688..9a1b187 100644
--- a/camera/camera-camera2-pipe-testing/OWNERS
+++ b/camera/camera-camera2-pipe-testing/OWNERS
@@ -2,3 +2,5 @@
 codelogic@google.com
 sushilnath@google.com
 lnishan@google.com
+fungja@google.com
+trevormcguire@google.com
\ No newline at end of file
diff --git a/camera/camera-camera2-pipe/OWNERS b/camera/camera-camera2-pipe/OWNERS
index c445688..9a1b187 100644
--- a/camera/camera-camera2-pipe/OWNERS
+++ b/camera/camera-camera2-pipe/OWNERS
@@ -2,3 +2,5 @@
 codelogic@google.com
 sushilnath@google.com
 lnishan@google.com
+fungja@google.com
+trevormcguire@google.com
\ No newline at end of file
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/ProcessingCaptureSession.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/ProcessingCaptureSession.java
index 1e8e2fc..ee7006c 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/ProcessingCaptureSession.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/ProcessingCaptureSession.java
@@ -212,10 +212,12 @@
 
                             mProcessorState = ProcessorState.SESSION_INITIALIZED;
                             try {
-                                DeferrableSurfaces.incrementAll(mOutputSurfaces);
+                                List<DeferrableSurface> surfacesToIncrement =
+                                        new ArrayList<>(mOutputSurfaces);
                                 if (postviewDeferrableSurface != null) {
-                                    postviewDeferrableSurface.incrementUseCount();
+                                    surfacesToIncrement.add(postviewDeferrableSurface);
                                 }
+                                DeferrableSurfaces.incrementAll(surfacesToIncrement);
                             } catch (DeferrableSurface.SurfaceClosedException e) {
                                 return Futures.immediateFailedFuture(e);
                             }
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/imagecapture/CaptureNode.java b/camera/camera-core/src/main/java/androidx/camera/core/imagecapture/CaptureNode.java
index 1046b45..6c3cf5d 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/imagecapture/CaptureNode.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/imagecapture/CaptureNode.java
@@ -323,10 +323,16 @@
         // prematurely before it can be used by camera2.
         inputEdge.getSurface().getTerminationFuture().addListener(() -> {
             imageReader.safeClose();
-            if (imageReaderForPostview != null) {
-                imageReaderForPostview.safeClose();
-            }
         }, mainThreadExecutor());
+
+        if (inputEdge.getPostviewSurface() != null) {
+            inputEdge.getPostviewSurface().close();
+            inputEdge.getPostviewSurface().getTerminationFuture().addListener(() -> {
+                if (imageReaderForPostview != null) {
+                    imageReaderForPostview.safeClose();
+                }
+            }, mainThreadExecutor());
+        }
     }
 
     @VisibleForTesting
diff --git a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/util/ExtensionsTestUtil.java b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/util/ExtensionsTestUtil.java
index 24baeae..f9f6649 100644
--- a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/util/ExtensionsTestUtil.java
+++ b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/util/ExtensionsTestUtil.java
@@ -247,7 +247,14 @@
                 || Build.MODEL.equalsIgnoreCase("G8342")))
                 || Build.MODEL.contains("Cuttlefish")
                 || Build.MODEL.equalsIgnoreCase("Pixel XL")
-                || Build.MODEL.equalsIgnoreCase("Pixel");
+                || Build.MODEL.equalsIgnoreCase("Pixel")
+                // Skip all devices that have ExtraCropping Quirk
+                || Build.MODEL.equalsIgnoreCase("SM-T580")
+                || Build.MODEL.equalsIgnoreCase("SM-J710MN")
+                || Build.MODEL.equalsIgnoreCase("SM-A320FL")
+                || Build.MODEL.equalsIgnoreCase("SM-G570M")
+                || Build.MODEL.equalsIgnoreCase("SM-G610F")
+                || Build.MODEL.equalsIgnoreCase("SM-G610M");
     }
 
     /**
diff --git a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java
index bde753e..801976c 100644
--- a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java
+++ b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java
@@ -54,6 +54,7 @@
     private static final int DEFAULT_STAGE_ID = 0;
     private static final int SESSION_STAGE_ID = 101;
     private static final int EFFECT = CaptureRequest.CONTROL_EFFECT_MODE_SOLARIZE;
+    private AutoImageCaptureExtenderCaptureProcessorImpl mCaptureProcessor = null;
 
     public AutoImageCaptureExtenderImpl() {
     }
@@ -93,7 +94,8 @@
     @Override
     public CaptureProcessorImpl getCaptureProcessor() {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
-            return new AutoImageCaptureExtenderCaptureProcessorImpl();
+            mCaptureProcessor = new AutoImageCaptureExtenderCaptureProcessorImpl();
+            return mCaptureProcessor;
         } else {
             return new NoOpCaptureProcessorImpl();
         }
@@ -108,7 +110,9 @@
 
     @Override
     public void onDeInit() {
-
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && mCaptureProcessor != null) {
+            mCaptureProcessor.release();
+        }
     }
 
     @Nullable
@@ -256,6 +260,7 @@
                         }
                     }
                 }
+                outputImage.setTimestamp(image.getTimestamp());
                 mImageWriter.queueInputImage(outputImage);
             }
 
@@ -294,6 +299,12 @@
                 @NonNull ProcessResultImpl resultCallback, @Nullable Executor executor) {
             throw new UnsupportedOperationException("Postview is not supported");
         }
+
+        public void release() {
+            if (mImageWriter != null) {
+                mImageWriter.close();
+            }
+        }
     }
 
     @NonNull
diff --git a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java
index 8e391ea..4647a5b 100644
--- a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java
+++ b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java
@@ -60,6 +60,7 @@
     private static final int EFFECT = CaptureRequest.CONTROL_EFFECT_MODE_NEGATIVE;
 
     private CameraCharacteristics mCameraCharacteristics;
+    private BeautyImageCaptureExtenderCaptureProcessorImpl mCaptureProcessor;
 
     public BeautyImageCaptureExtenderImpl() {
     }
@@ -100,7 +101,8 @@
     @Override
     public CaptureProcessorImpl getCaptureProcessor() {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
-            return new BeautyImageCaptureExtenderCaptureProcessorImpl();
+            mCaptureProcessor = new BeautyImageCaptureExtenderCaptureProcessorImpl();
+            return mCaptureProcessor;
         } else {
             return new NoOpCaptureProcessorImpl();
         }
@@ -115,7 +117,9 @@
 
     @Override
     public void onDeInit() {
-
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && mCaptureProcessor != null) {
+            mCaptureProcessor.release();
+        }
     }
 
     @Nullable
@@ -277,6 +281,7 @@
                         }
                     }
                 }
+                outputImage.setTimestamp(image.getTimestamp());
                 mImageWriter.queueInputImage(outputImage);
             }
 
@@ -315,6 +320,12 @@
                 @NonNull ProcessResultImpl resultCallback, @Nullable Executor executor) {
             throw new UnsupportedOperationException("Postview is not supported");
         }
+
+        public void release() {
+            if (mImageWriter != null) {
+                mImageWriter.close();
+            }
+        }
     }
 
     @NonNull
diff --git a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java
index a2f565c..9afae48 100644
--- a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java
+++ b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java
@@ -56,7 +56,7 @@
     private static final int DEFAULT_STAGE_ID = 0;
     private static final int SESSION_STAGE_ID = 101;
     private static final int EFFECT = CaptureRequest.CONTROL_EFFECT_MODE_SEPIA;
-
+    private BokehImageCaptureExtenderCaptureProcessorImpl mCaptureProcessor;
     public BokehImageCaptureExtenderImpl() {
     }
 
@@ -95,7 +95,8 @@
     @Override
     public CaptureProcessorImpl getCaptureProcessor() {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
-            return new BokehImageCaptureExtenderCaptureProcessorImpl();
+            mCaptureProcessor = new BokehImageCaptureExtenderCaptureProcessorImpl();
+            return mCaptureProcessor;
         } else {
             return new NoOpCaptureProcessorImpl();
         }
@@ -110,7 +111,9 @@
 
     @Override
     public void onDeInit() {
-
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && mCaptureProcessor != null) {
+            mCaptureProcessor.release();
+        }
     }
 
     @Nullable
@@ -257,6 +260,7 @@
                         }
                     }
                 }
+                outputImage.setTimestamp(image.getTimestamp());
                 mImageWriter.queueInputImage(outputImage);
             }
 
@@ -295,6 +299,12 @@
                 @NonNull ProcessResultImpl resultCallback, @Nullable Executor executor) {
             throw new UnsupportedOperationException("Postview is not supported");
         }
+
+        public void release() {
+            if (mImageWriter != null) {
+                mImageWriter.close();
+            }
+        }
     }
 
     @NonNull
diff --git a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java
index 677f4de..20f9124 100644
--- a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java
+++ b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java
@@ -257,6 +257,7 @@
             // Do processing here
             // The sample here simply returns the normal image result
             Image normalImage = imageDataPairs.get(NORMAL_STAGE_ID).first;
+            outputImage.setTimestamp(imageDataPairs.get(UNDER_STAGE_ID).first.getTimestamp());
             if (outputImage.getWidth() != normalImage.getWidth()
                     || outputImage.getHeight() != normalImage.getHeight()) {
                 throw new IllegalStateException(String.format("input image "
diff --git a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java
index 561e6c5..8d9940a 100644
--- a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java
+++ b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java
@@ -271,7 +271,7 @@
             List<Pair<Image, TotalCaptureResult>> imageDataPairs = new ArrayList<>(
                     results.values());
             Image outputImage = mImageWriter.dequeueInputImage();
-
+            outputImage.setTimestamp(imageDataPairs.get(0).first.getTimestamp());
             // Do processing here
             // The sample here simply returns the normal image result
             int stageId = DEFAULT_STAGE_ID;
@@ -300,7 +300,6 @@
                         outYBuffer.put(outIndex, inYBuffer.get(inIndex));
                     }
                 }
-
                 if (resultCallback != null) {
                     executorForCallback.execute(
                             () -> resultCallback.onCaptureProcessProgressed(50));
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/VersionChecker.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/VersionChecker.kt
index a0cf17b..cdcea5f 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/VersionChecker.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/VersionChecker.kt
@@ -146,7 +146,7 @@
          * The maven version string of this compiler. This string should be updated before/after every
          * release.
          */
-        const val compilerVersion: String = "1.5.10"
+        const val compilerVersion: String = "1.5.11"
         private val minimumRuntimeVersion: String
             get() = runtimeVersionToMavenVersionTable[minimumRuntimeVersionInt] ?: "unknown"
     }
diff --git a/compose/material/material-ripple/build.gradle b/compose/material/material-ripple/build.gradle
index e06e787..ee16cb3 100644
--- a/compose/material/material-ripple/build.gradle
+++ b/compose/material/material-ripple/build.gradle
@@ -69,7 +69,6 @@
         androidMain {
             dependsOn(jvmMain)
             dependencies {
-                implementation(project(":compose:ui:ui-graphics"))
             }
         }
 
diff --git a/compose/material/material-ripple/src/androidMain/kotlin/androidx/compose/material/ripple/RippleContainer.android.kt b/compose/material/material-ripple/src/androidMain/kotlin/androidx/compose/material/ripple/RippleContainer.android.kt
index 7bd6362..30c28cb 100644
--- a/compose/material/material-ripple/src/androidMain/kotlin/androidx/compose/material/ripple/RippleContainer.android.kt
+++ b/compose/material/material-ripple/src/androidMain/kotlin/androidx/compose/material/ripple/RippleContainer.android.kt
@@ -18,7 +18,7 @@
 
 import android.content.Context
 import android.view.ViewGroup
-import androidx.compose.ui.graphics.R
+import androidx.compose.ui.R
 
 internal interface RippleHostKey {
     /**
diff --git a/compose/material3/material3/api/current.txt b/compose/material3/material3/api/current.txt
index 7c294bb..8c9f22d 100644
--- a/compose/material3/material3/api/current.txt
+++ b/compose/material3/material3/api/current.txt
@@ -1137,9 +1137,7 @@
   }
 
   public final class OutlinedTextFieldKt {
-    method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void OutlinedTextField(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
     method @androidx.compose.runtime.Composable public static void OutlinedTextField(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
-    method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void OutlinedTextField(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
     method @androidx.compose.runtime.Composable public static void OutlinedTextField(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
   }
 
@@ -1850,12 +1848,6 @@
   @androidx.compose.runtime.Immutable public final class TextFieldDefaults {
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void ContainerBox(boolean enabled, boolean isError, androidx.compose.foundation.interaction.InteractionSource interactionSource, androidx.compose.material3.TextFieldColors colors, optional androidx.compose.ui.graphics.Shape shape);
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void DecorationBox(String value, kotlin.jvm.functions.Function0<kotlin.Unit> innerTextField, boolean enabled, boolean singleLine, androidx.compose.ui.text.input.VisualTransformation visualTransformation, androidx.compose.foundation.interaction.InteractionSource interactionSource, optional boolean isError, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function0<kotlin.Unit> container);
-    method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void FilledContainerBox(boolean enabled, boolean isError, androidx.compose.foundation.interaction.InteractionSource interactionSource, androidx.compose.material3.TextFieldColors colors, optional androidx.compose.ui.graphics.Shape shape);
-    method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void OutlinedBorderContainerBox(boolean enabled, boolean isError, androidx.compose.foundation.interaction.InteractionSource interactionSource, androidx.compose.material3.TextFieldColors colors, optional androidx.compose.ui.graphics.Shape shape, optional float focusedBorderThickness, optional float unfocusedBorderThickness);
-    method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void OutlinedTextFieldDecorationBox(String value, kotlin.jvm.functions.Function0<kotlin.Unit> innerTextField, boolean enabled, boolean singleLine, androidx.compose.ui.text.input.VisualTransformation visualTransformation, androidx.compose.foundation.interaction.InteractionSource interactionSource, optional boolean isError, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional androidx.compose.material3.TextFieldColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function0<kotlin.Unit> container);
-    method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void OutlinedTextFieldDecorationBox(String value, kotlin.jvm.functions.Function0<kotlin.Unit> innerTextField, boolean enabled, boolean singleLine, androidx.compose.ui.text.input.VisualTransformation visualTransformation, androidx.compose.foundation.interaction.InteractionSource interactionSource, optional boolean isError, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional androidx.compose.material3.TextFieldColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function0<kotlin.Unit> container);
-    method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void TextFieldDecorationBox(String value, kotlin.jvm.functions.Function0<kotlin.Unit> innerTextField, boolean enabled, boolean singleLine, androidx.compose.ui.text.input.VisualTransformation visualTransformation, androidx.compose.foundation.interaction.InteractionSource interactionSource, optional boolean isError, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function0<kotlin.Unit> container);
-    method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void TextFieldDecorationBox(String value, kotlin.jvm.functions.Function0<kotlin.Unit> innerTextField, boolean enabled, boolean singleLine, androidx.compose.ui.text.input.VisualTransformation visualTransformation, androidx.compose.foundation.interaction.InteractionSource interactionSource, optional boolean isError, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function0<kotlin.Unit> container);
     method @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors colors();
     method @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors colors(optional long focusedTextColor, optional long unfocusedTextColor, optional long disabledTextColor, optional long errorTextColor, optional long focusedContainerColor, optional long unfocusedContainerColor, optional long disabledContainerColor, optional long errorContainerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors? selectionColors, optional long focusedIndicatorColor, optional long unfocusedIndicatorColor, optional long disabledIndicatorColor, optional long errorIndicatorColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long focusedPlaceholderColor, optional long unfocusedPlaceholderColor, optional long disabledPlaceholderColor, optional long errorPlaceholderColor, optional long focusedSupportingTextColor, optional long unfocusedSupportingTextColor, optional long disabledSupportingTextColor, optional long errorSupportingTextColor, optional long focusedPrefixColor, optional long unfocusedPrefixColor, optional long disabledPrefixColor, optional long errorPrefixColor, optional long focusedSuffixColor, optional long unfocusedSuffixColor, optional long disabledSuffixColor, optional long errorSuffixColor);
     method public androidx.compose.foundation.layout.PaddingValues contentPaddingWithLabel(optional float start, optional float end, optional float top, optional float bottom);
@@ -1870,11 +1862,7 @@
     method @Deprecated public float getUnfocusedBorderThickness();
     method public float getUnfocusedIndicatorThickness();
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public androidx.compose.ui.Modifier indicatorLine(androidx.compose.ui.Modifier, boolean enabled, boolean isError, androidx.compose.foundation.interaction.InteractionSource interactionSource, androidx.compose.material3.TextFieldColors colors, optional float focusedIndicatorLineThickness, optional float unfocusedIndicatorLineThickness);
-    method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors outlinedTextFieldColors(optional long textColor, optional long disabledTextColor, optional long containerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedBorderColor, optional long unfocusedBorderColor, optional long disabledBorderColor, optional long errorBorderColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long placeholderColor, optional long disabledPlaceholderColor, optional long focusedSupportingTextColor, optional long unfocusedSupportingTextColor, optional long disabledSupportingTextColor, optional long errorSupportingTextColor, optional long focusedPrefixColor, optional long unfocusedPrefixColor, optional long disabledPrefixColor, optional long errorPrefixColor, optional long focusedSuffixColor, optional long unfocusedSuffixColor, optional long disabledSuffixColor, optional long errorSuffixColor);
-    method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors outlinedTextFieldColors(optional long focusedTextColor, optional long unfocusedTextColor, optional long disabledTextColor, optional long errorTextColor, optional long containerColor, optional long errorContainerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedBorderColor, optional long unfocusedBorderColor, optional long disabledBorderColor, optional long errorBorderColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long focusedPlaceholderColor, optional long unfocusedPlaceholderColor, optional long disabledPlaceholderColor, optional long errorPlaceholderColor, optional long focusedSupportingTextColor, optional long unfocusedSupportingTextColor, optional long disabledSupportingTextColor, optional long errorSupportingTextColor, optional long focusedPrefixColor, optional long unfocusedPrefixColor, optional long disabledPrefixColor, optional long errorPrefixColor, optional long focusedSuffixColor, optional long unfocusedSuffixColor, optional long disabledSuffixColor, optional long errorSuffixColor);
     method @Deprecated public androidx.compose.foundation.layout.PaddingValues outlinedTextFieldPadding(optional float start, optional float top, optional float end, optional float bottom);
-    method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors textFieldColors(optional long textColor, optional long disabledTextColor, optional long containerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedIndicatorColor, optional long unfocusedIndicatorColor, optional long disabledIndicatorColor, optional long errorIndicatorColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long placeholderColor, optional long disabledPlaceholderColor, optional long focusedSupportingTextColor, optional long unfocusedSupportingTextColor, optional long disabledSupportingTextColor, optional long errorSupportingTextColor, optional long focusedPrefixColor, optional long unfocusedPrefixColor, optional long disabledPrefixColor, optional long errorPrefixColor, optional long focusedSuffixColor, optional long unfocusedSuffixColor, optional long disabledSuffixColor, optional long errorSuffixColor);
-    method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors textFieldColors(optional long focusedTextColor, optional long unfocusedTextColor, optional long disabledTextColor, optional long errorTextColor, optional long containerColor, optional long errorContainerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedIndicatorColor, optional long unfocusedIndicatorColor, optional long disabledIndicatorColor, optional long errorIndicatorColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long focusedPlaceholderColor, optional long unfocusedPlaceholderColor, optional long disabledPlaceholderColor, optional long errorPlaceholderColor, optional long focusedSupportingTextColor, optional long unfocusedSupportingTextColor, optional long disabledSupportingTextColor, optional long errorSupportingTextColor, optional long focusedPrefixColor, optional long unfocusedPrefixColor, optional long disabledPrefixColor, optional long errorPrefixColor, optional long focusedSuffixColor, optional long unfocusedSuffixColor, optional long disabledSuffixColor, optional long errorSuffixColor);
     method @Deprecated public androidx.compose.foundation.layout.PaddingValues textFieldWithLabelPadding(optional float start, optional float end, optional float top, optional float bottom);
     method @Deprecated public androidx.compose.foundation.layout.PaddingValues textFieldWithoutLabelPadding(optional float start, optional float top, optional float end, optional float bottom);
     property @Deprecated public final float FocusedBorderThickness;
@@ -1890,9 +1878,7 @@
   }
 
   public final class TextFieldKt {
-    method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void TextField(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
     method @androidx.compose.runtime.Composable public static void TextField(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
-    method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void TextField(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
     method @androidx.compose.runtime.Composable public static void TextField(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
   }
 
diff --git a/compose/material3/material3/api/restricted_current.txt b/compose/material3/material3/api/restricted_current.txt
index 7c294bb..8c9f22d 100644
--- a/compose/material3/material3/api/restricted_current.txt
+++ b/compose/material3/material3/api/restricted_current.txt
@@ -1137,9 +1137,7 @@
   }
 
   public final class OutlinedTextFieldKt {
-    method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void OutlinedTextField(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
     method @androidx.compose.runtime.Composable public static void OutlinedTextField(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
-    method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void OutlinedTextField(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
     method @androidx.compose.runtime.Composable public static void OutlinedTextField(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
   }
 
@@ -1850,12 +1848,6 @@
   @androidx.compose.runtime.Immutable public final class TextFieldDefaults {
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void ContainerBox(boolean enabled, boolean isError, androidx.compose.foundation.interaction.InteractionSource interactionSource, androidx.compose.material3.TextFieldColors colors, optional androidx.compose.ui.graphics.Shape shape);
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void DecorationBox(String value, kotlin.jvm.functions.Function0<kotlin.Unit> innerTextField, boolean enabled, boolean singleLine, androidx.compose.ui.text.input.VisualTransformation visualTransformation, androidx.compose.foundation.interaction.InteractionSource interactionSource, optional boolean isError, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function0<kotlin.Unit> container);
-    method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void FilledContainerBox(boolean enabled, boolean isError, androidx.compose.foundation.interaction.InteractionSource interactionSource, androidx.compose.material3.TextFieldColors colors, optional androidx.compose.ui.graphics.Shape shape);
-    method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void OutlinedBorderContainerBox(boolean enabled, boolean isError, androidx.compose.foundation.interaction.InteractionSource interactionSource, androidx.compose.material3.TextFieldColors colors, optional androidx.compose.ui.graphics.Shape shape, optional float focusedBorderThickness, optional float unfocusedBorderThickness);
-    method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void OutlinedTextFieldDecorationBox(String value, kotlin.jvm.functions.Function0<kotlin.Unit> innerTextField, boolean enabled, boolean singleLine, androidx.compose.ui.text.input.VisualTransformation visualTransformation, androidx.compose.foundation.interaction.InteractionSource interactionSource, optional boolean isError, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional androidx.compose.material3.TextFieldColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function0<kotlin.Unit> container);
-    method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void OutlinedTextFieldDecorationBox(String value, kotlin.jvm.functions.Function0<kotlin.Unit> innerTextField, boolean enabled, boolean singleLine, androidx.compose.ui.text.input.VisualTransformation visualTransformation, androidx.compose.foundation.interaction.InteractionSource interactionSource, optional boolean isError, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional androidx.compose.material3.TextFieldColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function0<kotlin.Unit> container);
-    method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void TextFieldDecorationBox(String value, kotlin.jvm.functions.Function0<kotlin.Unit> innerTextField, boolean enabled, boolean singleLine, androidx.compose.ui.text.input.VisualTransformation visualTransformation, androidx.compose.foundation.interaction.InteractionSource interactionSource, optional boolean isError, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function0<kotlin.Unit> container);
-    method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void TextFieldDecorationBox(String value, kotlin.jvm.functions.Function0<kotlin.Unit> innerTextField, boolean enabled, boolean singleLine, androidx.compose.ui.text.input.VisualTransformation visualTransformation, androidx.compose.foundation.interaction.InteractionSource interactionSource, optional boolean isError, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function0<kotlin.Unit> container);
     method @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors colors();
     method @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors colors(optional long focusedTextColor, optional long unfocusedTextColor, optional long disabledTextColor, optional long errorTextColor, optional long focusedContainerColor, optional long unfocusedContainerColor, optional long disabledContainerColor, optional long errorContainerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors? selectionColors, optional long focusedIndicatorColor, optional long unfocusedIndicatorColor, optional long disabledIndicatorColor, optional long errorIndicatorColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long focusedPlaceholderColor, optional long unfocusedPlaceholderColor, optional long disabledPlaceholderColor, optional long errorPlaceholderColor, optional long focusedSupportingTextColor, optional long unfocusedSupportingTextColor, optional long disabledSupportingTextColor, optional long errorSupportingTextColor, optional long focusedPrefixColor, optional long unfocusedPrefixColor, optional long disabledPrefixColor, optional long errorPrefixColor, optional long focusedSuffixColor, optional long unfocusedSuffixColor, optional long disabledSuffixColor, optional long errorSuffixColor);
     method public androidx.compose.foundation.layout.PaddingValues contentPaddingWithLabel(optional float start, optional float end, optional float top, optional float bottom);
@@ -1870,11 +1862,7 @@
     method @Deprecated public float getUnfocusedBorderThickness();
     method public float getUnfocusedIndicatorThickness();
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public androidx.compose.ui.Modifier indicatorLine(androidx.compose.ui.Modifier, boolean enabled, boolean isError, androidx.compose.foundation.interaction.InteractionSource interactionSource, androidx.compose.material3.TextFieldColors colors, optional float focusedIndicatorLineThickness, optional float unfocusedIndicatorLineThickness);
-    method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors outlinedTextFieldColors(optional long textColor, optional long disabledTextColor, optional long containerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedBorderColor, optional long unfocusedBorderColor, optional long disabledBorderColor, optional long errorBorderColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long placeholderColor, optional long disabledPlaceholderColor, optional long focusedSupportingTextColor, optional long unfocusedSupportingTextColor, optional long disabledSupportingTextColor, optional long errorSupportingTextColor, optional long focusedPrefixColor, optional long unfocusedPrefixColor, optional long disabledPrefixColor, optional long errorPrefixColor, optional long focusedSuffixColor, optional long unfocusedSuffixColor, optional long disabledSuffixColor, optional long errorSuffixColor);
-    method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors outlinedTextFieldColors(optional long focusedTextColor, optional long unfocusedTextColor, optional long disabledTextColor, optional long errorTextColor, optional long containerColor, optional long errorContainerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedBorderColor, optional long unfocusedBorderColor, optional long disabledBorderColor, optional long errorBorderColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long focusedPlaceholderColor, optional long unfocusedPlaceholderColor, optional long disabledPlaceholderColor, optional long errorPlaceholderColor, optional long focusedSupportingTextColor, optional long unfocusedSupportingTextColor, optional long disabledSupportingTextColor, optional long errorSupportingTextColor, optional long focusedPrefixColor, optional long unfocusedPrefixColor, optional long disabledPrefixColor, optional long errorPrefixColor, optional long focusedSuffixColor, optional long unfocusedSuffixColor, optional long disabledSuffixColor, optional long errorSuffixColor);
     method @Deprecated public androidx.compose.foundation.layout.PaddingValues outlinedTextFieldPadding(optional float start, optional float top, optional float end, optional float bottom);
-    method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors textFieldColors(optional long textColor, optional long disabledTextColor, optional long containerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedIndicatorColor, optional long unfocusedIndicatorColor, optional long disabledIndicatorColor, optional long errorIndicatorColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long placeholderColor, optional long disabledPlaceholderColor, optional long focusedSupportingTextColor, optional long unfocusedSupportingTextColor, optional long disabledSupportingTextColor, optional long errorSupportingTextColor, optional long focusedPrefixColor, optional long unfocusedPrefixColor, optional long disabledPrefixColor, optional long errorPrefixColor, optional long focusedSuffixColor, optional long unfocusedSuffixColor, optional long disabledSuffixColor, optional long errorSuffixColor);
-    method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors textFieldColors(optional long focusedTextColor, optional long unfocusedTextColor, optional long disabledTextColor, optional long errorTextColor, optional long containerColor, optional long errorContainerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedIndicatorColor, optional long unfocusedIndicatorColor, optional long disabledIndicatorColor, optional long errorIndicatorColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long focusedPlaceholderColor, optional long unfocusedPlaceholderColor, optional long disabledPlaceholderColor, optional long errorPlaceholderColor, optional long focusedSupportingTextColor, optional long unfocusedSupportingTextColor, optional long disabledSupportingTextColor, optional long errorSupportingTextColor, optional long focusedPrefixColor, optional long unfocusedPrefixColor, optional long disabledPrefixColor, optional long errorPrefixColor, optional long focusedSuffixColor, optional long unfocusedSuffixColor, optional long disabledSuffixColor, optional long errorSuffixColor);
     method @Deprecated public androidx.compose.foundation.layout.PaddingValues textFieldWithLabelPadding(optional float start, optional float end, optional float top, optional float bottom);
     method @Deprecated public androidx.compose.foundation.layout.PaddingValues textFieldWithoutLabelPadding(optional float start, optional float top, optional float end, optional float bottom);
     property @Deprecated public final float FocusedBorderThickness;
@@ -1890,9 +1878,7 @@
   }
 
   public final class TextFieldKt {
-    method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void TextField(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
     method @androidx.compose.runtime.Composable public static void TextField(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
-    method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void TextField(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
     method @androidx.compose.runtime.Composable public static void TextField(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
   }
 
diff --git a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/carousel/CarouselTest.kt b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/carousel/CarouselTest.kt
index 83811d5..aec6469 100644
--- a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/carousel/CarouselTest.kt
+++ b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/carousel/CarouselTest.kt
@@ -130,6 +130,30 @@
         }
     }
 
+    @Test
+    fun carousel_calculateOutOfBoundsPageCount() {
+        val xSmallSize = 5f
+        val smallSize = 100f
+        val mediumSize = 200f
+        val largeSize = 400f
+        val keylineList = keylineListOf(carouselMainAxisSize = 1000f, CarouselAlignment.Start) {
+            add(xSmallSize, isAnchor = true)
+            add(largeSize)
+            add(mediumSize)
+            add(mediumSize)
+            add(smallSize)
+            add(smallSize)
+            add(xSmallSize, isAnchor = true)
+        }
+        val strategy = Strategy { keylineList }.apply(1000f)
+        val outOfBoundsNum = calculateOutOfBounds(strategy)
+        // With this strategy, we expect 3 loaded items
+        val loadedItems = 3
+
+        assertThat(outOfBoundsNum).isEqualTo(
+            (keylineList.filter { !it.isAnchor }.size - loadedItems) + 1)
+    }
+
     @Composable
     internal fun Item(index: Int) {
         Box(
@@ -147,7 +171,9 @@
     private fun createCarousel(
         initialItem: Int = 0,
         itemCount: () -> Int = { DefaultItemCount },
-        modifier: Modifier = Modifier.width(412.dp).height(221.dp),
+        modifier: Modifier = Modifier
+            .width(412.dp)
+            .height(221.dp),
         orientation: Orientation = Orientation.Horizontal,
         content: @Composable CarouselScope.(item: Int) -> Unit = { Item(index = it) }
     ) {
@@ -178,7 +204,9 @@
     private fun createUncontainedCarousel(
         initialItem: Int = 0,
         itemCount: () -> Int = { DefaultItemCount },
-        modifier: Modifier = Modifier.width(412.dp).height(221.dp),
+        modifier: Modifier = Modifier
+            .width(412.dp)
+            .height(221.dp),
         content: @Composable CarouselScope.(item: Int) -> Unit = { Item(index = it) }
     ) {
         rule.setMaterialContent(lightColorScheme()) {
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/OutlinedTextField.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/OutlinedTextField.kt
index fe9240c..6c210fe 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/OutlinedTextField.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/OutlinedTextField.kt
@@ -400,112 +400,6 @@
     }
 }
 
-@Deprecated("Use overload with prefix and suffix parameters", level = DeprecationLevel.HIDDEN)
-@ExperimentalMaterial3Api
-@Composable
-fun OutlinedTextField(
-    value: String,
-    onValueChange: (String) -> Unit,
-    modifier: Modifier = Modifier,
-    enabled: Boolean = true,
-    readOnly: Boolean = false,
-    textStyle: TextStyle = LocalTextStyle.current,
-    label: @Composable (() -> Unit)? = null,
-    placeholder: @Composable (() -> Unit)? = null,
-    leadingIcon: @Composable (() -> Unit)? = null,
-    trailingIcon: @Composable (() -> Unit)? = null,
-    supportingText: @Composable (() -> Unit)? = null,
-    isError: Boolean = false,
-    visualTransformation: VisualTransformation = VisualTransformation.None,
-    keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
-    keyboardActions: KeyboardActions = KeyboardActions.Default,
-    singleLine: Boolean = false,
-    maxLines: Int = if (singleLine) 1 else Int.MAX_VALUE,
-    minLines: Int = 1,
-    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
-    shape: Shape = OutlinedTextFieldDefaults.shape,
-    colors: TextFieldColors = OutlinedTextFieldDefaults.colors()
-) {
-    OutlinedTextField(
-        value = value,
-        onValueChange = onValueChange,
-        modifier = modifier,
-        enabled = enabled,
-        readOnly = readOnly,
-        textStyle = textStyle,
-        label = label,
-        placeholder = placeholder,
-        leadingIcon = leadingIcon,
-        trailingIcon = trailingIcon,
-        prefix = null,
-        suffix = null,
-        supportingText = supportingText,
-        isError = isError,
-        visualTransformation = visualTransformation,
-        keyboardOptions = keyboardOptions,
-        keyboardActions = keyboardActions,
-        singleLine = singleLine,
-        maxLines = maxLines,
-        minLines = minLines,
-        interactionSource = interactionSource,
-        shape = shape,
-        colors = colors,
-    )
-}
-
-@Deprecated("Use overload with prefix and suffix parameters", level = DeprecationLevel.HIDDEN)
-@ExperimentalMaterial3Api
-@Composable
-fun OutlinedTextField(
-    value: TextFieldValue,
-    onValueChange: (TextFieldValue) -> Unit,
-    modifier: Modifier = Modifier,
-    enabled: Boolean = true,
-    readOnly: Boolean = false,
-    textStyle: TextStyle = LocalTextStyle.current,
-    label: @Composable (() -> Unit)? = null,
-    placeholder: @Composable (() -> Unit)? = null,
-    leadingIcon: @Composable (() -> Unit)? = null,
-    trailingIcon: @Composable (() -> Unit)? = null,
-    supportingText: @Composable (() -> Unit)? = null,
-    isError: Boolean = false,
-    visualTransformation: VisualTransformation = VisualTransformation.None,
-    keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
-    keyboardActions: KeyboardActions = KeyboardActions.Default,
-    singleLine: Boolean = false,
-    maxLines: Int = if (singleLine) 1 else Int.MAX_VALUE,
-    minLines: Int = 1,
-    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
-    shape: Shape = OutlinedTextFieldDefaults.shape,
-    colors: TextFieldColors = OutlinedTextFieldDefaults.colors()
-) {
-    OutlinedTextField(
-        value = value,
-        onValueChange = onValueChange,
-        modifier = modifier,
-        enabled = enabled,
-        readOnly = readOnly,
-        textStyle = textStyle,
-        label = label,
-        placeholder = placeholder,
-        leadingIcon = leadingIcon,
-        trailingIcon = trailingIcon,
-        prefix = null,
-        suffix = null,
-        supportingText = supportingText,
-        isError = isError,
-        visualTransformation = visualTransformation,
-        keyboardOptions = keyboardOptions,
-        keyboardActions = keyboardActions,
-        singleLine = singleLine,
-        maxLines = maxLines,
-        minLines = minLines,
-        interactionSource = interactionSource,
-        shape = shape,
-        colors = colors,
-    )
-}
-
 /**
  * Layout of the leading and trailing icons and the text field, label and placeholder in
  * [OutlinedTextField].
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextField.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextField.kt
index 9cbcf10..6f8d337 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextField.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextField.kt
@@ -398,112 +398,6 @@
     }
 }
 
-@Deprecated("Use overload with prefix and suffix parameters", level = DeprecationLevel.HIDDEN)
-@ExperimentalMaterial3Api
-@Composable
-fun TextField(
-    value: String,
-    onValueChange: (String) -> Unit,
-    modifier: Modifier = Modifier,
-    enabled: Boolean = true,
-    readOnly: Boolean = false,
-    textStyle: TextStyle = LocalTextStyle.current,
-    label: @Composable (() -> Unit)? = null,
-    placeholder: @Composable (() -> Unit)? = null,
-    leadingIcon: @Composable (() -> Unit)? = null,
-    trailingIcon: @Composable (() -> Unit)? = null,
-    supportingText: @Composable (() -> Unit)? = null,
-    isError: Boolean = false,
-    visualTransformation: VisualTransformation = VisualTransformation.None,
-    keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
-    keyboardActions: KeyboardActions = KeyboardActions.Default,
-    singleLine: Boolean = false,
-    maxLines: Int = if (singleLine) 1 else Int.MAX_VALUE,
-    minLines: Int = 1,
-    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
-    shape: Shape = TextFieldDefaults.shape,
-    colors: TextFieldColors = TextFieldDefaults.colors()
-) {
-    TextField(
-        value = value,
-        onValueChange = onValueChange,
-        modifier = modifier,
-        enabled = enabled,
-        readOnly = readOnly,
-        textStyle = textStyle,
-        label = label,
-        placeholder = placeholder,
-        leadingIcon = leadingIcon,
-        trailingIcon = trailingIcon,
-        prefix = null,
-        suffix = null,
-        supportingText = supportingText,
-        isError = isError,
-        visualTransformation = visualTransformation,
-        keyboardOptions = keyboardOptions,
-        keyboardActions = keyboardActions,
-        singleLine = singleLine,
-        maxLines = maxLines,
-        minLines = minLines,
-        interactionSource = interactionSource,
-        shape = shape,
-        colors = colors,
-    )
-}
-
-@Deprecated("Use overload with prefix and suffix parameters", level = DeprecationLevel.HIDDEN)
-@ExperimentalMaterial3Api
-@Composable
-fun TextField(
-    value: TextFieldValue,
-    onValueChange: (TextFieldValue) -> Unit,
-    modifier: Modifier = Modifier,
-    enabled: Boolean = true,
-    readOnly: Boolean = false,
-    textStyle: TextStyle = LocalTextStyle.current,
-    label: @Composable (() -> Unit)? = null,
-    placeholder: @Composable (() -> Unit)? = null,
-    leadingIcon: @Composable (() -> Unit)? = null,
-    trailingIcon: @Composable (() -> Unit)? = null,
-    supportingText: @Composable (() -> Unit)? = null,
-    isError: Boolean = false,
-    visualTransformation: VisualTransformation = VisualTransformation.None,
-    keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
-    keyboardActions: KeyboardActions = KeyboardActions.Default,
-    singleLine: Boolean = false,
-    maxLines: Int = if (singleLine) 1 else Int.MAX_VALUE,
-    minLines: Int = 1,
-    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
-    shape: Shape = TextFieldDefaults.shape,
-    colors: TextFieldColors = TextFieldDefaults.colors()
-) {
-    TextField(
-        value = value,
-        onValueChange = onValueChange,
-        modifier = modifier,
-        enabled = enabled,
-        readOnly = readOnly,
-        textStyle = textStyle,
-        label = label,
-        placeholder = placeholder,
-        leadingIcon = leadingIcon,
-        trailingIcon = trailingIcon,
-        prefix = null,
-        suffix = null,
-        supportingText = supportingText,
-        isError = isError,
-        visualTransformation = visualTransformation,
-        keyboardOptions = keyboardOptions,
-        keyboardActions = keyboardActions,
-        singleLine = singleLine,
-        maxLines = maxLines,
-        minLines = minLines,
-        interactionSource = interactionSource,
-        shape = shape,
-        colors = colors,
-    )
-}
-
 /**
  * Composable responsible for measuring and laying out leading and trailing icons, label,
  * placeholder and the input field.
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextFieldDefaults.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextFieldDefaults.kt
index 735c5b6..ba49cea 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextFieldDefaults.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextFieldDefaults.kt
@@ -557,67 +557,6 @@
     val FocusedBorderThickness = FocusedIndicatorThickness
 
     @Deprecated(
-        message = "Renamed to `TextFieldDefaults.ContainerBox`",
-        replaceWith = ReplaceWith("TextFieldDefaults.ContainerBox(\n" +
-            "        enabled = enabled,\n" +
-            "        isError = isError,\n" +
-            "        interactionSource = interactionSource,\n" +
-            "        colors = colors,\n" +
-            "        shape = shape,\n" +
-            "    )"),
-        level = DeprecationLevel.WARNING
-    )
-    @ExperimentalMaterial3Api
-    @Composable
-    fun FilledContainerBox(
-        enabled: Boolean,
-        isError: Boolean,
-        interactionSource: InteractionSource,
-        colors: TextFieldColors,
-        shape: Shape = TextFieldDefaults.shape,
-    ) = ContainerBox(
-        enabled = enabled,
-        isError = isError,
-        interactionSource = interactionSource,
-        colors = colors,
-        shape = shape,
-    )
-
-    @Deprecated(
-        message = "Renamed to `OutlinedTextFieldDefaults.ContainerBox`",
-        replaceWith = ReplaceWith("OutlinedTextFieldDefaults.ContainerBox(\n" +
-            "        enabled = enabled,\n" +
-            "        isError = isError,\n" +
-            "        interactionSource = interactionSource,\n" +
-            "        colors = colors,\n" +
-            "        shape = shape,\n" +
-            "        focusedBorderThickness = focusedBorderThickness,\n" +
-            "        unfocusedBorderThickness = unfocusedBorderThickness,\n" +
-            "    )",
-            "androidx.compose.material.OutlinedTextFieldDefaults"),
-        level = DeprecationLevel.WARNING
-    )
-    @ExperimentalMaterial3Api
-    @Composable
-    fun OutlinedBorderContainerBox(
-        enabled: Boolean,
-        isError: Boolean,
-        interactionSource: InteractionSource,
-        colors: TextFieldColors,
-        shape: Shape = OutlinedTextFieldTokens.ContainerShape.value,
-        focusedBorderThickness: Dp = OutlinedTextFieldDefaults.FocusedBorderThickness,
-        unfocusedBorderThickness: Dp = OutlinedTextFieldDefaults.UnfocusedBorderThickness
-    ) = OutlinedTextFieldDefaults.ContainerBox(
-        enabled = enabled,
-        isError = isError,
-        interactionSource = interactionSource,
-        colors = colors,
-        shape = shape,
-        focusedBorderThickness = focusedBorderThickness,
-        unfocusedBorderThickness = unfocusedBorderThickness,
-    )
-
-    @Deprecated(
         message = "Renamed to `TextFieldDefaults.contentPaddingWithLabel`",
         replaceWith = ReplaceWith("TextFieldDefaults.contentPaddingWithLabel(\n" +
             "        start = start,\n" +
@@ -683,727 +622,6 @@
         end = end,
         bottom = bottom,
     )
-
-    @Deprecated(
-        message = "Renamed to `TextFieldDefaults.colors` with additional parameters to control" +
-            "container color based on state.",
-        replaceWith = ReplaceWith("TextFieldDefaults.colors(\n" +
-            "        focusedTextColor = focusedTextColor,\n" +
-            "        unfocusedTextColor = unfocusedTextColor,\n" +
-            "        disabledTextColor = disabledTextColor,\n" +
-            "        errorTextColor = errorTextColor,\n" +
-            "        focusedContainerColor = containerColor,\n" +
-            "        unfocusedContainerColor = containerColor,\n" +
-            "        disabledContainerColor = containerColor,\n" +
-            "        errorContainerColor = errorContainerColor,\n" +
-            "        cursorColor = cursorColor,\n" +
-            "        errorCursorColor = errorCursorColor,\n" +
-            "        selectionColors = selectionColors,\n" +
-            "        focusedIndicatorColor = focusedIndicatorColor,\n" +
-            "        unfocusedIndicatorColor = unfocusedIndicatorColor,\n" +
-            "        disabledIndicatorColor = disabledIndicatorColor,\n" +
-            "        errorIndicatorColor = errorIndicatorColor,\n" +
-            "        focusedLeadingIconColor = focusedLeadingIconColor,\n" +
-            "        unfocusedLeadingIconColor = unfocusedLeadingIconColor,\n" +
-            "        disabledLeadingIconColor = disabledLeadingIconColor,\n" +
-            "        errorLeadingIconColor = errorLeadingIconColor,\n" +
-            "        focusedTrailingIconColor = focusedTrailingIconColor,\n" +
-            "        unfocusedTrailingIconColor = unfocusedTrailingIconColor,\n" +
-            "        disabledTrailingIconColor = disabledTrailingIconColor,\n" +
-            "        errorTrailingIconColor = errorTrailingIconColor,\n" +
-            "        focusedLabelColor = focusedLabelColor,\n" +
-            "        unfocusedLabelColor = unfocusedLabelColor,\n" +
-            "        disabledLabelColor = disabledLabelColor,\n" +
-            "        errorLabelColor = errorLabelColor,\n" +
-            "        focusedPlaceholderColor = focusedPlaceholderColor,\n" +
-            "        unfocusedPlaceholderColor = unfocusedPlaceholderColor,\n" +
-            "        disabledPlaceholderColor = disabledPlaceholderColor,\n" +
-            "        errorPlaceholderColor = errorPlaceholderColor,\n" +
-            "        focusedSupportingTextColor = focusedSupportingTextColor,\n" +
-            "        unfocusedSupportingTextColor = unfocusedSupportingTextColor,\n" +
-            "        disabledSupportingTextColor = disabledSupportingTextColor,\n" +
-            "        errorSupportingTextColor = errorSupportingTextColor,\n" +
-            "        focusedPrefixColor = focusedPrefixColor,\n" +
-            "        unfocusedPrefixColor = unfocusedPrefixColor,\n" +
-            "        disabledPrefixColor = disabledPrefixColor,\n" +
-            "        errorPrefixColor = errorPrefixColor,\n" +
-            "        focusedSuffixColor = focusedSuffixColor,\n" +
-            "        unfocusedSuffixColor = unfocusedSuffixColor,\n" +
-            "        disabledSuffixColor = disabledSuffixColor,\n" +
-            "        errorSuffixColor = errorSuffixColor,\n" +
-            "    )"),
-        level = DeprecationLevel.WARNING,
-    )
-    @ExperimentalMaterial3Api
-    @Composable
-    fun textFieldColors(
-        focusedTextColor: Color = FilledTextFieldTokens.FocusInputColor.value,
-        unfocusedTextColor: Color = FilledTextFieldTokens.InputColor.value,
-        disabledTextColor: Color = FilledTextFieldTokens.DisabledInputColor.value
-            .copy(alpha = FilledTextFieldTokens.DisabledInputOpacity),
-        errorTextColor: Color = FilledTextFieldTokens.ErrorInputColor.value,
-        containerColor: Color = FilledTextFieldTokens.ContainerColor.value,
-        errorContainerColor: Color = FilledTextFieldTokens.ContainerColor.value,
-        cursorColor: Color = FilledTextFieldTokens.CaretColor.value,
-        errorCursorColor: Color = FilledTextFieldTokens.ErrorFocusCaretColor.value,
-        selectionColors: TextSelectionColors = LocalTextSelectionColors.current,
-        focusedIndicatorColor: Color = FilledTextFieldTokens.FocusActiveIndicatorColor.value,
-        unfocusedIndicatorColor: Color = FilledTextFieldTokens.ActiveIndicatorColor.value,
-        disabledIndicatorColor: Color = FilledTextFieldTokens.DisabledActiveIndicatorColor.value
-            .copy(alpha = FilledTextFieldTokens.DisabledActiveIndicatorOpacity),
-        errorIndicatorColor: Color = FilledTextFieldTokens.ErrorActiveIndicatorColor.value,
-        focusedLeadingIconColor: Color = FilledTextFieldTokens.FocusLeadingIconColor.value,
-        unfocusedLeadingIconColor: Color = FilledTextFieldTokens.LeadingIconColor.value,
-        disabledLeadingIconColor: Color = FilledTextFieldTokens.DisabledLeadingIconColor.value
-            .copy(alpha = FilledTextFieldTokens.DisabledLeadingIconOpacity),
-        errorLeadingIconColor: Color = FilledTextFieldTokens.ErrorLeadingIconColor.value,
-        focusedTrailingIconColor: Color = FilledTextFieldTokens.FocusTrailingIconColor.value,
-        unfocusedTrailingIconColor: Color = FilledTextFieldTokens.TrailingIconColor.value,
-        disabledTrailingIconColor: Color = FilledTextFieldTokens.DisabledTrailingIconColor.value
-            .copy(alpha = FilledTextFieldTokens.DisabledTrailingIconOpacity),
-        errorTrailingIconColor: Color = FilledTextFieldTokens.ErrorTrailingIconColor.value,
-        focusedLabelColor: Color = FilledTextFieldTokens.FocusLabelColor.value,
-        unfocusedLabelColor: Color = FilledTextFieldTokens.LabelColor.value,
-        disabledLabelColor: Color = FilledTextFieldTokens.DisabledLabelColor.value
-            .copy(alpha = FilledTextFieldTokens.DisabledLabelOpacity),
-        errorLabelColor: Color = FilledTextFieldTokens.ErrorLabelColor.value,
-        focusedPlaceholderColor: Color = FilledTextFieldTokens.InputPlaceholderColor.value,
-        unfocusedPlaceholderColor: Color = FilledTextFieldTokens.InputPlaceholderColor.value,
-        disabledPlaceholderColor: Color = FilledTextFieldTokens.DisabledInputColor.value
-            .copy(alpha = FilledTextFieldTokens.DisabledInputOpacity),
-        errorPlaceholderColor: Color = FilledTextFieldTokens.InputPlaceholderColor.value,
-        focusedSupportingTextColor: Color = FilledTextFieldTokens.FocusSupportingColor.value,
-        unfocusedSupportingTextColor: Color = FilledTextFieldTokens.SupportingColor.value,
-        disabledSupportingTextColor: Color = FilledTextFieldTokens.DisabledSupportingColor.value
-            .copy(alpha = FilledTextFieldTokens.DisabledSupportingOpacity),
-        errorSupportingTextColor: Color = FilledTextFieldTokens.ErrorSupportingColor.value,
-        focusedPrefixColor: Color = FilledTextFieldTokens.InputPrefixColor.value,
-        unfocusedPrefixColor: Color = FilledTextFieldTokens.InputPrefixColor.value,
-        disabledPrefixColor: Color = FilledTextFieldTokens.InputPrefixColor.value
-            .copy(alpha = FilledTextFieldTokens.DisabledInputOpacity),
-        errorPrefixColor: Color = FilledTextFieldTokens.InputPrefixColor.value,
-        focusedSuffixColor: Color = FilledTextFieldTokens.InputSuffixColor.value,
-        unfocusedSuffixColor: Color = FilledTextFieldTokens.InputSuffixColor.value,
-        disabledSuffixColor: Color = FilledTextFieldTokens.InputSuffixColor.value
-            .copy(alpha = FilledTextFieldTokens.DisabledInputOpacity),
-        errorSuffixColor: Color = FilledTextFieldTokens.InputSuffixColor.value,
-    ): TextFieldColors = colors(
-        focusedTextColor = focusedTextColor,
-        unfocusedTextColor = unfocusedTextColor,
-        disabledTextColor = disabledTextColor,
-        errorTextColor = errorTextColor,
-        focusedContainerColor = containerColor,
-        unfocusedContainerColor = containerColor,
-        disabledContainerColor = containerColor,
-        errorContainerColor = errorContainerColor,
-        cursorColor = cursorColor,
-        errorCursorColor = errorCursorColor,
-        selectionColors = selectionColors,
-        focusedIndicatorColor = focusedIndicatorColor,
-        unfocusedIndicatorColor = unfocusedIndicatorColor,
-        disabledIndicatorColor = disabledIndicatorColor,
-        errorIndicatorColor = errorIndicatorColor,
-        focusedLeadingIconColor = focusedLeadingIconColor,
-        unfocusedLeadingIconColor = unfocusedLeadingIconColor,
-        disabledLeadingIconColor = disabledLeadingIconColor,
-        errorLeadingIconColor = errorLeadingIconColor,
-        focusedTrailingIconColor = focusedTrailingIconColor,
-        unfocusedTrailingIconColor = unfocusedTrailingIconColor,
-        disabledTrailingIconColor = disabledTrailingIconColor,
-        errorTrailingIconColor = errorTrailingIconColor,
-        focusedLabelColor = focusedLabelColor,
-        unfocusedLabelColor = unfocusedLabelColor,
-        disabledLabelColor = disabledLabelColor,
-        errorLabelColor = errorLabelColor,
-        focusedPlaceholderColor = focusedPlaceholderColor,
-        unfocusedPlaceholderColor = unfocusedPlaceholderColor,
-        disabledPlaceholderColor = disabledPlaceholderColor,
-        errorPlaceholderColor = errorPlaceholderColor,
-        focusedSupportingTextColor = focusedSupportingTextColor,
-        unfocusedSupportingTextColor = unfocusedSupportingTextColor,
-        disabledSupportingTextColor = disabledSupportingTextColor,
-        errorSupportingTextColor = errorSupportingTextColor,
-        focusedPrefixColor = focusedPrefixColor,
-        unfocusedPrefixColor = unfocusedPrefixColor,
-        disabledPrefixColor = disabledPrefixColor,
-        errorPrefixColor = errorPrefixColor,
-        focusedSuffixColor = focusedSuffixColor,
-        unfocusedSuffixColor = unfocusedSuffixColor,
-        disabledSuffixColor = disabledSuffixColor,
-        errorSuffixColor = errorSuffixColor,
-    )
-
-    @Deprecated(
-        message = "Renamed to `OutlinedTextFieldDefaults.colors` with additional parameters to" +
-            "control container color based on state.",
-        replaceWith = ReplaceWith("OutlinedTextFieldDefaults.colors(\n" +
-            "        focusedTextColor = focusedTextColor,\n" +
-            "        unfocusedTextColor = unfocusedTextColor,\n" +
-            "        disabledTextColor = disabledTextColor,\n" +
-            "        errorTextColor = errorTextColor,\n" +
-            "        focusedContainerColor = containerColor,\n" +
-            "        unfocusedContainerColor = containerColor,\n" +
-            "        disabledContainerColor = containerColor,\n" +
-            "        errorContainerColor = errorContainerColor,\n" +
-            "        cursorColor = cursorColor,\n" +
-            "        errorCursorColor = errorCursorColor,\n" +
-            "        selectionColors = selectionColors,\n" +
-            "        focusedBorderColor = focusedBorderColor,\n" +
-            "        unfocusedBorderColor = unfocusedBorderColor,\n" +
-            "        disabledBorderColor = disabledBorderColor,\n" +
-            "        errorBorderColor = errorBorderColor,\n" +
-            "        focusedLeadingIconColor = focusedLeadingIconColor,\n" +
-            "        unfocusedLeadingIconColor = unfocusedLeadingIconColor,\n" +
-            "        disabledLeadingIconColor = disabledLeadingIconColor,\n" +
-            "        errorLeadingIconColor = errorLeadingIconColor,\n" +
-            "        focusedTrailingIconColor = focusedTrailingIconColor,\n" +
-            "        unfocusedTrailingIconColor = unfocusedTrailingIconColor,\n" +
-            "        disabledTrailingIconColor = disabledTrailingIconColor,\n" +
-            "        errorTrailingIconColor = errorTrailingIconColor,\n" +
-            "        focusedLabelColor = focusedLabelColor,\n" +
-            "        unfocusedLabelColor = unfocusedLabelColor,\n" +
-            "        disabledLabelColor = disabledLabelColor,\n" +
-            "        errorLabelColor = errorLabelColor,\n" +
-            "        focusedPlaceholderColor = focusedPlaceholderColor,\n" +
-            "        unfocusedPlaceholderColor = unfocusedPlaceholderColor,\n" +
-            "        disabledPlaceholderColor = disabledPlaceholderColor,\n" +
-            "        errorPlaceholderColor = errorPlaceholderColor,\n" +
-            "        focusedSupportingTextColor = focusedSupportingTextColor,\n" +
-            "        unfocusedSupportingTextColor = unfocusedSupportingTextColor,\n" +
-            "        disabledSupportingTextColor = disabledSupportingTextColor,\n" +
-            "        errorSupportingTextColor = errorSupportingTextColor,\n" +
-            "        focusedPrefixColor = focusedPrefixColor,\n" +
-            "        unfocusedPrefixColor = unfocusedPrefixColor,\n" +
-            "        disabledPrefixColor = disabledPrefixColor,\n" +
-            "        errorPrefixColor = errorPrefixColor,\n" +
-            "        focusedSuffixColor = focusedSuffixColor,\n" +
-            "        unfocusedSuffixColor = unfocusedSuffixColor,\n" +
-            "        disabledSuffixColor = disabledSuffixColor,\n" +
-            "        errorSuffixColor = errorSuffixColor,\n" +
-            "    )",
-            "androidx.compose.material.OutlinedTextFieldDefaults"),
-        level = DeprecationLevel.WARNING,
-    )
-    @ExperimentalMaterial3Api
-    @Composable
-    fun outlinedTextFieldColors(
-        focusedTextColor: Color = OutlinedTextFieldTokens.FocusInputColor.value,
-        unfocusedTextColor: Color = OutlinedTextFieldTokens.InputColor.value,
-        disabledTextColor: Color = OutlinedTextFieldTokens.DisabledInputColor.value
-            .copy(alpha = OutlinedTextFieldTokens.DisabledInputOpacity),
-        errorTextColor: Color = OutlinedTextFieldTokens.ErrorInputColor.value,
-        containerColor: Color = Color.Transparent,
-        errorContainerColor: Color = Color.Transparent,
-        cursorColor: Color = OutlinedTextFieldTokens.CaretColor.value,
-        errorCursorColor: Color = OutlinedTextFieldTokens.ErrorFocusCaretColor.value,
-        selectionColors: TextSelectionColors = LocalTextSelectionColors.current,
-        focusedBorderColor: Color = OutlinedTextFieldTokens.FocusOutlineColor.value,
-        unfocusedBorderColor: Color = OutlinedTextFieldTokens.OutlineColor.value,
-        disabledBorderColor: Color = OutlinedTextFieldTokens.DisabledOutlineColor.value
-            .copy(alpha = OutlinedTextFieldTokens.DisabledOutlineOpacity),
-        errorBorderColor: Color = OutlinedTextFieldTokens.ErrorOutlineColor.value,
-        focusedLeadingIconColor: Color = OutlinedTextFieldTokens.FocusLeadingIconColor.value,
-        unfocusedLeadingIconColor: Color = OutlinedTextFieldTokens.LeadingIconColor.value,
-        disabledLeadingIconColor: Color = OutlinedTextFieldTokens.DisabledLeadingIconColor.value
-            .copy(alpha = OutlinedTextFieldTokens.DisabledLeadingIconOpacity),
-        errorLeadingIconColor: Color = OutlinedTextFieldTokens.ErrorLeadingIconColor.value,
-        focusedTrailingIconColor: Color = OutlinedTextFieldTokens.FocusTrailingIconColor.value,
-        unfocusedTrailingIconColor: Color = OutlinedTextFieldTokens.TrailingIconColor.value,
-        disabledTrailingIconColor: Color = OutlinedTextFieldTokens.DisabledTrailingIconColor
-            .value.copy(alpha = OutlinedTextFieldTokens.DisabledTrailingIconOpacity),
-        errorTrailingIconColor: Color = OutlinedTextFieldTokens.ErrorTrailingIconColor.value,
-        focusedLabelColor: Color = OutlinedTextFieldTokens.FocusLabelColor.value,
-        unfocusedLabelColor: Color = OutlinedTextFieldTokens.LabelColor.value,
-        disabledLabelColor: Color = OutlinedTextFieldTokens.DisabledLabelColor.value
-            .copy(alpha = OutlinedTextFieldTokens.DisabledLabelOpacity),
-        errorLabelColor: Color = OutlinedTextFieldTokens.ErrorLabelColor.value,
-        focusedPlaceholderColor: Color = OutlinedTextFieldTokens.InputPlaceholderColor.value,
-        unfocusedPlaceholderColor: Color = OutlinedTextFieldTokens.InputPlaceholderColor.value,
-        disabledPlaceholderColor: Color = OutlinedTextFieldTokens.DisabledInputColor.value
-            .copy(alpha = OutlinedTextFieldTokens.DisabledInputOpacity),
-        errorPlaceholderColor: Color = OutlinedTextFieldTokens.InputPlaceholderColor.value,
-        focusedSupportingTextColor: Color = OutlinedTextFieldTokens.FocusSupportingColor.value,
-        unfocusedSupportingTextColor: Color = OutlinedTextFieldTokens.SupportingColor.value,
-        disabledSupportingTextColor: Color = OutlinedTextFieldTokens.DisabledSupportingColor
-            .value.copy(alpha = OutlinedTextFieldTokens.DisabledSupportingOpacity),
-        errorSupportingTextColor: Color = OutlinedTextFieldTokens.ErrorSupportingColor.value,
-        focusedPrefixColor: Color = OutlinedTextFieldTokens.InputPrefixColor.value,
-        unfocusedPrefixColor: Color = OutlinedTextFieldTokens.InputPrefixColor.value,
-        disabledPrefixColor: Color = OutlinedTextFieldTokens.InputPrefixColor.value
-            .copy(alpha = OutlinedTextFieldTokens.DisabledInputOpacity),
-        errorPrefixColor: Color = OutlinedTextFieldTokens.InputPrefixColor.value,
-        focusedSuffixColor: Color = OutlinedTextFieldTokens.InputSuffixColor.value,
-        unfocusedSuffixColor: Color = OutlinedTextFieldTokens.InputSuffixColor.value,
-        disabledSuffixColor: Color = OutlinedTextFieldTokens.InputSuffixColor.value
-            .copy(alpha = OutlinedTextFieldTokens.DisabledInputOpacity),
-        errorSuffixColor: Color = OutlinedTextFieldTokens.InputSuffixColor.value,
-    ): TextFieldColors = OutlinedTextFieldDefaults.colors(
-        focusedTextColor = focusedTextColor,
-        unfocusedTextColor = unfocusedTextColor,
-        disabledTextColor = disabledTextColor,
-        errorTextColor = errorTextColor,
-        focusedContainerColor = containerColor,
-        unfocusedContainerColor = containerColor,
-        disabledContainerColor = containerColor,
-        errorContainerColor = errorContainerColor,
-        cursorColor = cursorColor,
-        errorCursorColor = errorCursorColor,
-        selectionColors = selectionColors,
-        focusedBorderColor = focusedBorderColor,
-        unfocusedBorderColor = unfocusedBorderColor,
-        disabledBorderColor = disabledBorderColor,
-        errorBorderColor = errorBorderColor,
-        focusedLeadingIconColor = focusedLeadingIconColor,
-        unfocusedLeadingIconColor = unfocusedLeadingIconColor,
-        disabledLeadingIconColor = disabledLeadingIconColor,
-        errorLeadingIconColor = errorLeadingIconColor,
-        focusedTrailingIconColor = focusedTrailingIconColor,
-        unfocusedTrailingIconColor = unfocusedTrailingIconColor,
-        disabledTrailingIconColor = disabledTrailingIconColor,
-        errorTrailingIconColor = errorTrailingIconColor,
-        focusedLabelColor = focusedLabelColor,
-        unfocusedLabelColor = unfocusedLabelColor,
-        disabledLabelColor = disabledLabelColor,
-        errorLabelColor = errorLabelColor,
-        focusedPlaceholderColor = focusedPlaceholderColor,
-        unfocusedPlaceholderColor = unfocusedPlaceholderColor,
-        disabledPlaceholderColor = disabledPlaceholderColor,
-        errorPlaceholderColor = errorPlaceholderColor,
-        focusedSupportingTextColor = focusedSupportingTextColor,
-        unfocusedSupportingTextColor = unfocusedSupportingTextColor,
-        disabledSupportingTextColor = disabledSupportingTextColor,
-        errorSupportingTextColor = errorSupportingTextColor,
-        focusedPrefixColor = focusedPrefixColor,
-        unfocusedPrefixColor = unfocusedPrefixColor,
-        disabledPrefixColor = disabledPrefixColor,
-        errorPrefixColor = errorPrefixColor,
-        focusedSuffixColor = focusedSuffixColor,
-        unfocusedSuffixColor = unfocusedSuffixColor,
-        disabledSuffixColor = disabledSuffixColor,
-        errorSuffixColor = errorSuffixColor,
-    )
-
-    @Deprecated(
-        message = "Renamed to `TextFieldDefaults.DecorationBox`",
-        replaceWith = ReplaceWith("TextFieldDefaults.DecorationBox(\n" +
-            "        value = value,\n" +
-            "        innerTextField = innerTextField,\n" +
-            "        enabled = enabled,\n" +
-            "        singleLine = singleLine,\n" +
-            "        visualTransformation = visualTransformation,\n" +
-            "        interactionSource = interactionSource,\n" +
-            "        isError = isError,\n" +
-            "        label = label,\n" +
-            "        placeholder = placeholder,\n" +
-            "        leadingIcon = leadingIcon,\n" +
-            "        trailingIcon = trailingIcon,\n" +
-            "        prefix = prefix,\n" +
-            "        suffix = suffix,\n" +
-            "        supportingText = supportingText,\n" +
-            "        shape = shape,\n" +
-            "        colors = colors,\n" +
-            "        contentPadding = contentPadding,\n" +
-            "        container = container,\n" +
-            "    )"),
-        level = DeprecationLevel.WARNING
-    )
-    @Composable
-    @ExperimentalMaterial3Api
-    fun TextFieldDecorationBox(
-        value: String,
-        innerTextField: @Composable () -> Unit,
-        enabled: Boolean,
-        singleLine: Boolean,
-        visualTransformation: VisualTransformation,
-        interactionSource: InteractionSource,
-        isError: Boolean = false,
-        label: @Composable (() -> Unit)? = null,
-        placeholder: @Composable (() -> Unit)? = null,
-        leadingIcon: @Composable (() -> Unit)? = null,
-        trailingIcon: @Composable (() -> Unit)? = null,
-        prefix: @Composable (() -> Unit)? = null,
-        suffix: @Composable (() -> Unit)? = null,
-        supportingText: @Composable (() -> Unit)? = null,
-        shape: Shape = TextFieldDefaults.shape,
-        colors: TextFieldColors = colors(),
-        contentPadding: PaddingValues =
-            if (label == null) {
-                contentPaddingWithoutLabel()
-            } else {
-                contentPaddingWithLabel()
-            },
-        container: @Composable () -> Unit = {
-            ContainerBox(enabled, isError, interactionSource, colors, shape)
-        }
-    ) = DecorationBox(
-        value = value,
-        innerTextField = innerTextField,
-        enabled = enabled,
-        singleLine = singleLine,
-        visualTransformation = visualTransformation,
-        interactionSource = interactionSource,
-        isError = isError,
-        label = label,
-        placeholder = placeholder,
-        leadingIcon = leadingIcon,
-        trailingIcon = trailingIcon,
-        prefix = prefix,
-        suffix = suffix,
-        supportingText = supportingText,
-        shape = shape,
-        colors = colors,
-        contentPadding = contentPadding,
-        container = container,
-    )
-
-    @Deprecated(
-        message = "Renamed to `OutlinedTextFieldDefaults.DecorationBox`",
-        replaceWith = ReplaceWith("OutlinedTextFieldDefaults.DecorationBox(\n" +
-            "        value = value,\n" +
-            "        innerTextField = innerTextField,\n" +
-            "        enabled = enabled,\n" +
-            "        singleLine = singleLine,\n" +
-            "        visualTransformation = visualTransformation,\n" +
-            "        interactionSource = interactionSource,\n" +
-            "        isError = isError,\n" +
-            "        label = label,\n" +
-            "        placeholder = placeholder,\n" +
-            "        leadingIcon = leadingIcon,\n" +
-            "        trailingIcon = trailingIcon,\n" +
-            "        prefix = prefix,\n" +
-            "        suffix = suffix,\n" +
-            "        supportingText = supportingText,\n" +
-            "        colors = colors,\n" +
-            "        contentPadding = contentPadding,\n" +
-            "        container = container,\n" +
-            "    )",
-            "androidx.compose.material.OutlinedTextFieldDefaults"),
-        level = DeprecationLevel.WARNING
-    )
-    @Composable
-    @ExperimentalMaterial3Api
-    fun OutlinedTextFieldDecorationBox(
-        value: String,
-        innerTextField: @Composable () -> Unit,
-        enabled: Boolean,
-        singleLine: Boolean,
-        visualTransformation: VisualTransformation,
-        interactionSource: InteractionSource,
-        isError: Boolean = false,
-        label: @Composable (() -> Unit)? = null,
-        placeholder: @Composable (() -> Unit)? = null,
-        leadingIcon: @Composable (() -> Unit)? = null,
-        trailingIcon: @Composable (() -> Unit)? = null,
-        prefix: @Composable (() -> Unit)? = null,
-        suffix: @Composable (() -> Unit)? = null,
-        supportingText: @Composable (() -> Unit)? = null,
-        colors: TextFieldColors = OutlinedTextFieldDefaults.colors(),
-        contentPadding: PaddingValues = OutlinedTextFieldDefaults.contentPadding(),
-        container: @Composable () -> Unit = {
-            OutlinedTextFieldDefaults.ContainerBox(enabled, isError, interactionSource, colors)
-        }
-    ) = OutlinedTextFieldDefaults.DecorationBox(
-        value = value,
-        innerTextField = innerTextField,
-        enabled = enabled,
-        singleLine = singleLine,
-        visualTransformation = visualTransformation,
-        interactionSource = interactionSource,
-        isError = isError,
-        label = label,
-        placeholder = placeholder,
-        leadingIcon = leadingIcon,
-        trailingIcon = trailingIcon,
-        prefix = prefix,
-        suffix = suffix,
-        supportingText = supportingText,
-        colors = colors,
-        contentPadding = contentPadding,
-        container = container,
-    )
-
-    @Deprecated("Maintained for binary compatibility", level = DeprecationLevel.HIDDEN)
-    @ExperimentalMaterial3Api
-    @Composable
-    fun textFieldColors(
-        textColor: Color = FilledTextFieldTokens.InputColor.value,
-        disabledTextColor: Color = FilledTextFieldTokens.DisabledInputColor.value
-            .copy(alpha = FilledTextFieldTokens.DisabledInputOpacity),
-        containerColor: Color = FilledTextFieldTokens.ContainerColor.value,
-        cursorColor: Color = FilledTextFieldTokens.CaretColor.value,
-        errorCursorColor: Color = FilledTextFieldTokens.ErrorFocusCaretColor.value,
-        selectionColors: TextSelectionColors = LocalTextSelectionColors.current,
-        focusedIndicatorColor: Color = FilledTextFieldTokens.FocusActiveIndicatorColor.value,
-        unfocusedIndicatorColor: Color = FilledTextFieldTokens.ActiveIndicatorColor.value,
-        disabledIndicatorColor: Color = FilledTextFieldTokens.DisabledActiveIndicatorColor.value
-            .copy(alpha = FilledTextFieldTokens.DisabledActiveIndicatorOpacity),
-        errorIndicatorColor: Color = FilledTextFieldTokens.ErrorActiveIndicatorColor.value,
-        focusedLeadingIconColor: Color = FilledTextFieldTokens.FocusLeadingIconColor.value,
-        unfocusedLeadingIconColor: Color = FilledTextFieldTokens.LeadingIconColor.value,
-        disabledLeadingIconColor: Color = FilledTextFieldTokens.DisabledLeadingIconColor.value
-            .copy(alpha = FilledTextFieldTokens.DisabledLeadingIconOpacity),
-        errorLeadingIconColor: Color = FilledTextFieldTokens.ErrorLeadingIconColor.value,
-        focusedTrailingIconColor: Color = FilledTextFieldTokens.FocusTrailingIconColor.value,
-        unfocusedTrailingIconColor: Color = FilledTextFieldTokens.TrailingIconColor.value,
-        disabledTrailingIconColor: Color = FilledTextFieldTokens.DisabledTrailingIconColor.value
-            .copy(alpha = FilledTextFieldTokens.DisabledTrailingIconOpacity),
-        errorTrailingIconColor: Color = FilledTextFieldTokens.ErrorTrailingIconColor.value,
-        focusedLabelColor: Color = FilledTextFieldTokens.FocusLabelColor.value,
-        unfocusedLabelColor: Color = FilledTextFieldTokens.LabelColor.value,
-        disabledLabelColor: Color = FilledTextFieldTokens.DisabledLabelColor.value
-            .copy(alpha = FilledTextFieldTokens.DisabledLabelOpacity),
-        errorLabelColor: Color = FilledTextFieldTokens.ErrorLabelColor.value,
-        placeholderColor: Color = FilledTextFieldTokens.InputPlaceholderColor.value,
-        disabledPlaceholderColor: Color = FilledTextFieldTokens.DisabledInputColor.value
-            .copy(alpha = FilledTextFieldTokens.DisabledInputOpacity),
-        focusedSupportingTextColor: Color = FilledTextFieldTokens.FocusSupportingColor.value,
-        unfocusedSupportingTextColor: Color = FilledTextFieldTokens.SupportingColor.value,
-        disabledSupportingTextColor: Color = FilledTextFieldTokens.DisabledSupportingColor.value
-            .copy(alpha = FilledTextFieldTokens.DisabledSupportingOpacity),
-        errorSupportingTextColor: Color = FilledTextFieldTokens.ErrorSupportingColor.value,
-        focusedPrefixColor: Color = FilledTextFieldTokens.InputPrefixColor.value,
-        unfocusedPrefixColor: Color = FilledTextFieldTokens.InputPrefixColor.value,
-        disabledPrefixColor: Color = FilledTextFieldTokens.InputPrefixColor.value
-            .copy(alpha = FilledTextFieldTokens.DisabledInputOpacity),
-        errorPrefixColor: Color = FilledTextFieldTokens.InputPrefixColor.value,
-        focusedSuffixColor: Color = FilledTextFieldTokens.InputSuffixColor.value,
-        unfocusedSuffixColor: Color = FilledTextFieldTokens.InputSuffixColor.value,
-        disabledSuffixColor: Color = FilledTextFieldTokens.InputSuffixColor.value
-            .copy(alpha = FilledTextFieldTokens.DisabledInputOpacity),
-        errorSuffixColor: Color = FilledTextFieldTokens.InputSuffixColor.value,
-    ): TextFieldColors = colors(
-        focusedTextColor = textColor,
-        unfocusedTextColor = textColor,
-        disabledTextColor = disabledTextColor,
-        errorTextColor = textColor,
-        focusedContainerColor = containerColor,
-        unfocusedContainerColor = containerColor,
-        disabledContainerColor = containerColor,
-        errorContainerColor = containerColor,
-        cursorColor = cursorColor,
-        errorCursorColor = errorCursorColor,
-        selectionColors = selectionColors,
-        focusedIndicatorColor = focusedIndicatorColor,
-        unfocusedIndicatorColor = unfocusedIndicatorColor,
-        disabledIndicatorColor = disabledIndicatorColor,
-        errorIndicatorColor = errorIndicatorColor,
-        focusedLeadingIconColor = focusedLeadingIconColor,
-        unfocusedLeadingIconColor = unfocusedLeadingIconColor,
-        disabledLeadingIconColor = disabledLeadingIconColor,
-        errorLeadingIconColor = errorLeadingIconColor,
-        focusedTrailingIconColor = focusedTrailingIconColor,
-        unfocusedTrailingIconColor = unfocusedTrailingIconColor,
-        disabledTrailingIconColor = disabledTrailingIconColor,
-        errorTrailingIconColor = errorTrailingIconColor,
-        focusedLabelColor = focusedLabelColor,
-        unfocusedLabelColor = unfocusedLabelColor,
-        disabledLabelColor = disabledLabelColor,
-        errorLabelColor = errorLabelColor,
-        focusedPlaceholderColor = placeholderColor,
-        unfocusedPlaceholderColor = placeholderColor,
-        disabledPlaceholderColor = disabledPlaceholderColor,
-        errorPlaceholderColor = placeholderColor,
-        focusedSupportingTextColor = focusedSupportingTextColor,
-        unfocusedSupportingTextColor = unfocusedSupportingTextColor,
-        disabledSupportingTextColor = disabledSupportingTextColor,
-        errorSupportingTextColor = errorSupportingTextColor,
-        focusedPrefixColor = focusedPrefixColor,
-        unfocusedPrefixColor = unfocusedPrefixColor,
-        disabledPrefixColor = disabledPrefixColor,
-        errorPrefixColor = errorPrefixColor,
-        focusedSuffixColor = focusedSuffixColor,
-        unfocusedSuffixColor = unfocusedSuffixColor,
-        disabledSuffixColor = disabledSuffixColor,
-        errorSuffixColor = errorSuffixColor,
-    )
-
-    @Deprecated("Maintained for binary compatibility", level = DeprecationLevel.HIDDEN)
-    @ExperimentalMaterial3Api
-    @Composable
-    fun outlinedTextFieldColors(
-        textColor: Color = OutlinedTextFieldTokens.InputColor.value,
-        disabledTextColor: Color = OutlinedTextFieldTokens.DisabledInputColor.value
-            .copy(alpha = OutlinedTextFieldTokens.DisabledInputOpacity),
-        containerColor: Color = Color.Transparent,
-        cursorColor: Color = OutlinedTextFieldTokens.CaretColor.value,
-        errorCursorColor: Color = OutlinedTextFieldTokens.ErrorFocusCaretColor.value,
-        selectionColors: TextSelectionColors = LocalTextSelectionColors.current,
-        focusedBorderColor: Color = OutlinedTextFieldTokens.FocusOutlineColor.value,
-        unfocusedBorderColor: Color = OutlinedTextFieldTokens.OutlineColor.value,
-        disabledBorderColor: Color = OutlinedTextFieldTokens.DisabledOutlineColor.value
-            .copy(alpha = OutlinedTextFieldTokens.DisabledOutlineOpacity),
-        errorBorderColor: Color = OutlinedTextFieldTokens.ErrorOutlineColor.value,
-        focusedLeadingIconColor: Color = OutlinedTextFieldTokens.FocusLeadingIconColor.value,
-        unfocusedLeadingIconColor: Color = OutlinedTextFieldTokens.LeadingIconColor.value,
-        disabledLeadingIconColor: Color = OutlinedTextFieldTokens.DisabledLeadingIconColor.value
-            .copy(alpha = OutlinedTextFieldTokens.DisabledLeadingIconOpacity),
-        errorLeadingIconColor: Color = OutlinedTextFieldTokens.ErrorLeadingIconColor.value,
-        focusedTrailingIconColor: Color = OutlinedTextFieldTokens.FocusTrailingIconColor.value,
-        unfocusedTrailingIconColor: Color = OutlinedTextFieldTokens.TrailingIconColor.value,
-        disabledTrailingIconColor: Color = OutlinedTextFieldTokens.DisabledTrailingIconColor
-            .value.copy(alpha = OutlinedTextFieldTokens.DisabledTrailingIconOpacity),
-        errorTrailingIconColor: Color = OutlinedTextFieldTokens.ErrorTrailingIconColor.value,
-        focusedLabelColor: Color = OutlinedTextFieldTokens.FocusLabelColor.value,
-        unfocusedLabelColor: Color = OutlinedTextFieldTokens.LabelColor.value,
-        disabledLabelColor: Color = OutlinedTextFieldTokens.DisabledLabelColor.value
-            .copy(alpha = OutlinedTextFieldTokens.DisabledLabelOpacity),
-        errorLabelColor: Color = OutlinedTextFieldTokens.ErrorLabelColor.value,
-        placeholderColor: Color = OutlinedTextFieldTokens.InputPlaceholderColor.value,
-        disabledPlaceholderColor: Color = OutlinedTextFieldTokens.DisabledInputColor.value
-            .copy(alpha = OutlinedTextFieldTokens.DisabledInputOpacity),
-        focusedSupportingTextColor: Color = OutlinedTextFieldTokens.FocusSupportingColor.value,
-        unfocusedSupportingTextColor: Color = OutlinedTextFieldTokens.SupportingColor.value,
-        disabledSupportingTextColor: Color = OutlinedTextFieldTokens.DisabledSupportingColor
-            .value.copy(alpha = OutlinedTextFieldTokens.DisabledSupportingOpacity),
-        errorSupportingTextColor: Color = OutlinedTextFieldTokens.ErrorSupportingColor.value,
-        focusedPrefixColor: Color = OutlinedTextFieldTokens.InputPrefixColor.value,
-        unfocusedPrefixColor: Color = OutlinedTextFieldTokens.InputPrefixColor.value,
-        disabledPrefixColor: Color = OutlinedTextFieldTokens.InputPrefixColor.value
-            .copy(alpha = OutlinedTextFieldTokens.DisabledInputOpacity),
-        errorPrefixColor: Color = OutlinedTextFieldTokens.InputPrefixColor.value,
-        focusedSuffixColor: Color = OutlinedTextFieldTokens.InputSuffixColor.value,
-        unfocusedSuffixColor: Color = OutlinedTextFieldTokens.InputSuffixColor.value,
-        disabledSuffixColor: Color = OutlinedTextFieldTokens.InputSuffixColor.value
-            .copy(alpha = OutlinedTextFieldTokens.DisabledInputOpacity),
-        errorSuffixColor: Color = OutlinedTextFieldTokens.InputSuffixColor.value,
-    ): TextFieldColors = OutlinedTextFieldDefaults.colors(
-        focusedTextColor = textColor,
-        unfocusedTextColor = textColor,
-        disabledTextColor = disabledTextColor,
-        errorTextColor = textColor,
-        focusedContainerColor = containerColor,
-        unfocusedContainerColor = containerColor,
-        disabledContainerColor = containerColor,
-        errorContainerColor = containerColor,
-        cursorColor = cursorColor,
-        errorCursorColor = errorCursorColor,
-        selectionColors = selectionColors,
-        focusedBorderColor = focusedBorderColor,
-        unfocusedBorderColor = unfocusedBorderColor,
-        disabledBorderColor = disabledBorderColor,
-        errorBorderColor = errorBorderColor,
-        focusedLeadingIconColor = focusedLeadingIconColor,
-        unfocusedLeadingIconColor = unfocusedLeadingIconColor,
-        disabledLeadingIconColor = disabledLeadingIconColor,
-        errorLeadingIconColor = errorLeadingIconColor,
-        focusedTrailingIconColor = focusedTrailingIconColor,
-        unfocusedTrailingIconColor = unfocusedTrailingIconColor,
-        disabledTrailingIconColor = disabledTrailingIconColor,
-        errorTrailingIconColor = errorTrailingIconColor,
-        focusedLabelColor = focusedLabelColor,
-        unfocusedLabelColor = unfocusedLabelColor,
-        disabledLabelColor = disabledLabelColor,
-        errorLabelColor = errorLabelColor,
-        focusedPlaceholderColor = placeholderColor,
-        unfocusedPlaceholderColor = placeholderColor,
-        disabledPlaceholderColor = disabledPlaceholderColor,
-        errorPlaceholderColor = placeholderColor,
-        focusedSupportingTextColor = focusedSupportingTextColor,
-        unfocusedSupportingTextColor = unfocusedSupportingTextColor,
-        disabledSupportingTextColor = disabledSupportingTextColor,
-        errorSupportingTextColor = errorSupportingTextColor,
-        focusedPrefixColor = focusedPrefixColor,
-        unfocusedPrefixColor = unfocusedPrefixColor,
-        disabledPrefixColor = disabledPrefixColor,
-        errorPrefixColor = errorPrefixColor,
-        focusedSuffixColor = focusedSuffixColor,
-        unfocusedSuffixColor = unfocusedSuffixColor,
-        disabledSuffixColor = disabledSuffixColor,
-        errorSuffixColor = errorSuffixColor,
-    )
-
-    @Deprecated("Use overload with prefix and suffix parameters", level = DeprecationLevel.HIDDEN)
-    @Composable
-    @ExperimentalMaterial3Api
-    fun TextFieldDecorationBox(
-        value: String,
-        innerTextField: @Composable () -> Unit,
-        enabled: Boolean,
-        singleLine: Boolean,
-        visualTransformation: VisualTransformation,
-        interactionSource: InteractionSource,
-        isError: Boolean = false,
-        label: @Composable (() -> Unit)? = null,
-        placeholder: @Composable (() -> Unit)? = null,
-        leadingIcon: @Composable (() -> Unit)? = null,
-        trailingIcon: @Composable (() -> Unit)? = null,
-        supportingText: @Composable (() -> Unit)? = null,
-        shape: Shape = TextFieldDefaults.shape,
-        colors: TextFieldColors = colors(),
-        contentPadding: PaddingValues =
-            if (label == null) {
-                contentPaddingWithoutLabel()
-            } else {
-                contentPaddingWithLabel()
-            },
-        container: @Composable () -> Unit = {
-            ContainerBox(enabled, isError, interactionSource, colors, shape)
-        }
-    ) {
-        DecorationBox(
-            value = value,
-            innerTextField = innerTextField,
-            enabled = enabled,
-            singleLine = singleLine,
-            visualTransformation = visualTransformation,
-            interactionSource = interactionSource,
-            isError = isError,
-            label = label,
-            placeholder = placeholder,
-            leadingIcon = leadingIcon,
-            trailingIcon = trailingIcon,
-            prefix = null,
-            suffix = null,
-            supportingText = supportingText,
-            shape = shape,
-            colors = colors,
-            contentPadding = contentPadding,
-            container = container,
-        )
-    }
-
-    @Deprecated("Use overload with prefix and suffix parameters", level = DeprecationLevel.HIDDEN)
-    @Composable
-    @ExperimentalMaterial3Api
-    fun OutlinedTextFieldDecorationBox(
-        value: String,
-        innerTextField: @Composable () -> Unit,
-        enabled: Boolean,
-        singleLine: Boolean,
-        visualTransformation: VisualTransformation,
-        interactionSource: InteractionSource,
-        isError: Boolean = false,
-        label: @Composable (() -> Unit)? = null,
-        placeholder: @Composable (() -> Unit)? = null,
-        leadingIcon: @Composable (() -> Unit)? = null,
-        trailingIcon: @Composable (() -> Unit)? = null,
-        supportingText: @Composable (() -> Unit)? = null,
-        colors: TextFieldColors = OutlinedTextFieldDefaults.colors(),
-        contentPadding: PaddingValues = OutlinedTextFieldDefaults.contentPadding(),
-        container: @Composable () -> Unit = {
-            OutlinedTextFieldDefaults.ContainerBox(enabled, isError, interactionSource, colors)
-        }
-    ) {
-        OutlinedTextFieldDefaults.DecorationBox(
-            value = value,
-            innerTextField = innerTextField,
-            enabled = enabled,
-            singleLine = singleLine,
-            visualTransformation = visualTransformation,
-            interactionSource = interactionSource,
-            isError = isError,
-            label = label,
-            placeholder = placeholder,
-            leadingIcon = leadingIcon,
-            trailingIcon = trailingIcon,
-            prefix = null,
-            suffix = null,
-            supportingText = supportingText,
-            colors = colors,
-            contentPadding = contentPadding,
-            container = container
-        )
-    }
 }
 
 /**
@@ -1694,8 +912,9 @@
                 focusedSupportingTextColor =
                 fromToken(OutlinedTextFieldTokens.FocusSupportingColor),
                 unfocusedSupportingTextColor = fromToken(OutlinedTextFieldTokens.SupportingColor),
-                disabledSupportingTextColor = OutlinedTextFieldTokens.DisabledSupportingColor
-                    .value.copy(alpha = OutlinedTextFieldTokens.DisabledSupportingOpacity),
+                disabledSupportingTextColor =
+                fromToken(OutlinedTextFieldTokens.DisabledSupportingColor)
+                    .copy(alpha = OutlinedTextFieldTokens.DisabledSupportingOpacity),
                 errorSupportingTextColor = fromToken(OutlinedTextFieldTokens.ErrorSupportingColor),
                 focusedPrefixColor = fromToken(OutlinedTextFieldTokens.InputPrefixColor),
                 unfocusedPrefixColor = fromToken(OutlinedTextFieldTokens.InputPrefixColor),
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/carousel/Carousel.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/carousel/Carousel.kt
index b34fc8f..c5e6c51 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/carousel/Carousel.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/carousel/Carousel.kt
@@ -45,6 +45,9 @@
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.LayoutDirection
 import androidx.compose.ui.unit.dp
+import androidx.compose.ui.util.fastFilter
+import androidx.compose.ui.util.fastForEach
+import kotlin.math.ceil
 import kotlin.math.roundToInt
 
 /**
@@ -188,8 +191,9 @@
     val isRtl = LocalLayoutDirection.current == LayoutDirection.Rtl
     val pageSize = remember(keylineList) { CarouselPageSize(keylineList) }
 
-    // TODO: Update beyond bounds numbers according to Strategy
-    val outOfBoundsPageCount = 2
+    val outOfBoundsPageCount = remember(pageSize.strategy.itemMainAxisSize) {
+        calculateOutOfBounds(pageSize.strategy)
+    }
     val carouselScope = CarouselScopeImpl
 
     val snapPositionMap = remember(pageSize.strategy.itemMainAxisSize) {
@@ -247,6 +251,23 @@
     }
 }
 
+internal fun calculateOutOfBounds(strategy: Strategy): Int {
+    if (!strategy.isValid()) {
+        return PagerDefaults.OutOfBoundsPageCount
+    }
+    var totalKeylineSpace = 0f
+    var totalNonAnchorKeylines = 0
+    strategy.defaultKeylines.fastFilter { !it.isAnchor }.fastForEach {
+        totalKeylineSpace += it.size
+        totalNonAnchorKeylines += 1
+    }
+    val itemsLoaded = ceil(totalKeylineSpace / strategy.itemMainAxisSize).toInt()
+    val itemsToLoad = totalNonAnchorKeylines - itemsLoaded
+
+    // We must also load the next item when scrolling
+    return itemsToLoad + 1
+}
+
 /**
  * A [PageSize] implementation that maintains a strategy that is kept up-to-date with the
  * latest available space of the container.
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/BroadcastFrameClock.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/BroadcastFrameClock.kt
index 1718d92..df5f37a 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/BroadcastFrameClock.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/BroadcastFrameClock.kt
@@ -48,10 +48,14 @@
     private var awaiters = mutableListOf<FrameAwaiter<*>>()
     private var spareList = mutableListOf<FrameAwaiter<*>>()
 
+    // Uses AtomicInt to avoid adding AtomicBoolean to the Expect/Actual requirements of the
+    // runtime.
+    private val hasAwaitersUnlocked = AtomicInt(0)
+
     /**
      * `true` if there are any callers of [withFrameNanos] awaiting to run for a pending frame.
      */
-    val hasAwaiters: Boolean get() = synchronized(lock) { awaiters.isNotEmpty() }
+    val hasAwaiters: Boolean get() = hasAwaitersUnlocked.get() != 0
 
     /**
      * Send a frame for time [timeNanos] to all current callers of [withFrameNanos].
@@ -66,6 +70,7 @@
             val toResume = awaiters
             awaiters = spareList
             spareList = toResume
+            hasAwaitersUnlocked.set(0)
 
             for (i in 0 until toResume.size) {
                 toResume[i].resume(timeNanos)
@@ -87,12 +92,14 @@
             awaiter = FrameAwaiter(onFrame, co)
             val hadAwaiters = awaiters.isNotEmpty()
             awaiters.add(awaiter)
+            if (!hadAwaiters) hasAwaitersUnlocked.set(1)
             !hadAwaiters
         }
 
         co.invokeOnCancellation {
             synchronized(lock) {
                 awaiters.remove(awaiter)
+                if (awaiters.isEmpty()) hasAwaitersUnlocked.set(0)
             }
         }
 
@@ -116,6 +123,7 @@
                 awaiter.continuation.resumeWithException(cause)
             }
             awaiters.clear()
+            hasAwaitersUnlocked.set(0)
         }
     }
 
diff --git a/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/RecomposerTests.kt b/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/RecomposerTests.kt
index 50fa39f..50e2f5d5 100644
--- a/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/RecomposerTests.kt
+++ b/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/RecomposerTests.kt
@@ -28,11 +28,13 @@
 import kotlin.test.assertNotNull
 import kotlin.test.assertTrue
 import kotlinx.coroutines.CoroutineName
+import kotlinx.coroutines.DelicateCoroutinesApi
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.Job
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.flow.first
 import kotlinx.coroutines.launch
+import kotlinx.coroutines.newSingleThreadContext
 import kotlinx.coroutines.test.StandardTestDispatcher
 import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.UnconfinedTestDispatcher
@@ -437,6 +439,40 @@
         assertEquals<List<Set<Any>>>(listOf(setOf(countFromEffect)), applications)
     }
 
+    @OptIn(DelicateCoroutinesApi::class)
+    @Test // b/329011032
+    fun validatePotentialDeadlock() = compositionTest {
+        var state by mutableIntStateOf(0)
+        compose {
+            repeat(1000) {
+                Text("This is some text: $state")
+            }
+            LaunchedEffect(Unit) {
+                newSingleThreadContext("other thread").use {
+                    while (true) {
+                        withContext(it) {
+                            state++
+                            Snapshot.registerGlobalWriteObserver { }.dispose()
+                        }
+                    }
+                }
+            }
+            LaunchedEffect(Unit) {
+                while (true) {
+                    withFrameNanos {
+                        state++
+                        Snapshot.sendApplyNotifications()
+                    }
+                }
+            }
+        }
+
+        repeat(10) {
+            state++
+            advance(ignorePendingWork = true)
+        }
+    }
+
     @Test
     fun pausingTheFrameClockStopShouldBlockWithFrameNanos() {
         val dispatcher = StandardTestDispatcher()
diff --git a/compose/ui/ui-graphics/api/res-current.txt b/compose/ui/ui-graphics/api/res-current.txt
index e69de29..4553236 100644
--- a/compose/ui/ui-graphics/api/res-current.txt
+++ b/compose/ui/ui-graphics/api/res-current.txt
@@ -0,0 +1 @@
+id hide_graphics_layer_in_inspector_tag
diff --git a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/view/ViewLayerContainer.android.kt b/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/view/ViewLayerContainer.android.kt
index 23185dd..3aed02d 100644
--- a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/view/ViewLayerContainer.android.kt
+++ b/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/view/ViewLayerContainer.android.kt
@@ -52,7 +52,7 @@
         clipToPadding = false
 
         // Hide this view and its children in tools:
-        setTag(R.id.hide_in_inspector_tag, true)
+        setTag(R.id.hide_graphics_layer_in_inspector_tag, true)
     }
 
     override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
diff --git a/compose/ui/ui-graphics/src/androidMain/res/values/ids.xml b/compose/ui/ui-graphics/src/androidMain/res/values/ids.xml
index 989568a..453cbdb 100644
--- a/compose/ui/ui-graphics/src/androidMain/res/values/ids.xml
+++ b/compose/ui/ui-graphics/src/androidMain/res/values/ids.xml
@@ -16,5 +16,5 @@
   -->
 
 <resources>
-    <item name="hide_in_inspector_tag" type="id" />
+    <item name="hide_graphics_layer_in_inspector_tag" type="id" />
 </resources>
diff --git a/compose/ui/ui-graphics/src/androidMain/res/values/public.xml b/compose/ui/ui-graphics/src/androidMain/res/values/public.xml
new file mode 100644
index 0000000..1a24359
--- /dev/null
+++ b/compose/ui/ui-graphics/src/androidMain/res/values/public.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  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.
+  -->
+
+<resources>
+    <public name="hide_graphics_layer_in_inspector_tag" type="id"/>
+</resources>
diff --git a/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/compose/AndroidComposeViewWrapper.kt b/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/compose/AndroidComposeViewWrapper.kt
index 0140b6d..a1a2615 100644
--- a/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/compose/AndroidComposeViewWrapper.kt
+++ b/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/compose/AndroidComposeViewWrapper.kt
@@ -21,7 +21,7 @@
 import android.view.ViewGroup
 import androidx.collection.LongList
 import androidx.collection.mutableLongListOf
-import androidx.compose.ui.graphics.R
+import androidx.compose.ui.R
 import androidx.compose.ui.inspection.framework.ancestors
 import androidx.compose.ui.inspection.framework.getChildren
 import androidx.compose.ui.inspection.framework.isAndroidComposeView
@@ -113,10 +113,14 @@
     private fun createViewsToSkip(viewGroup: ViewGroup): LongList {
         val result = mutableLongListOf()
         viewGroup.getChildren().forEach { view ->
-            if (view.getTag(R.id.hide_in_inspector_tag) != null) {
+            if (view.hasHideFromInspectionTag()) {
                 result.add(view.uniqueDrawingId)
             }
         }
         return result
     }
+
+    private fun View.hasHideFromInspectionTag(): Boolean =
+        getTag(R.id.hide_in_inspector_tag) != null ||
+            getTag(androidx.compose.ui.graphics.R.id.hide_graphics_layer_in_inspector_tag) != null
 }
diff --git a/compose/ui/ui-tooling/build.gradle b/compose/ui/ui-tooling/build.gradle
index 67395d6..e0e50d7 100644
--- a/compose/ui/ui-tooling/build.gradle
+++ b/compose/ui/ui-tooling/build.gradle
@@ -71,7 +71,7 @@
                 api("androidx.annotation:annotation:1.1.0")
                 implementation(project(":compose:animation:animation"))
                 implementation("androidx.savedstate:savedstate-ktx:1.2.1")
-                implementation(project(":compose:material:material"))
+                implementation("androidx.compose.material:material:1.0.0")
                 implementation("androidx.activity:activity-compose:1.7.0")
                 implementation("androidx.lifecycle:lifecycle-common:2.6.1")
 
diff --git a/compose/ui/ui/api/res-current.txt b/compose/ui/ui/api/res-current.txt
index e69de29..ba71b41 100644
--- a/compose/ui/ui/api/res-current.txt
+++ b/compose/ui/ui/api/res-current.txt
@@ -0,0 +1 @@
+id hide_in_inspector_tag
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/contentcapture/ContentCaptureTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/contentcapture/ContentCaptureTest.kt
index 629ff4e..10940f9 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/contentcapture/ContentCaptureTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/contentcapture/ContentCaptureTest.kt
@@ -63,9 +63,11 @@
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyInt
 import org.mockito.kotlin.any
 import org.mockito.kotlin.argumentCaptor
 import org.mockito.kotlin.clearInvocations
+import org.mockito.kotlin.isNull
 import org.mockito.kotlin.mock
 import org.mockito.kotlin.times
 import org.mockito.kotlin.verify
@@ -140,7 +142,10 @@
                     Box(
                         Modifier
                             .size(10.dp)
-                            .semantics { text = AnnotatedString("foo") }
+                            .semantics {
+                                text = AnnotatedString("foo")
+                                testTag = "testTagFoo"
+                            }
                     )
                     Box(
                         Modifier
@@ -167,6 +172,10 @@
                 assertThat(firstValue).isEqualTo("foo")
                 assertThat(secondValue).isEqualTo("bar")
             }
+            with(argumentCaptor<String>()) {
+                verify(viewStructureCompat, times(1)).setId(anyInt(), isNull(), isNull(), capture())
+                assertThat(firstValue).isEqualTo("testTagFoo")
+            }
             verify(contentCaptureSessionCompat, times(0)).notifyViewsDisappeared(any())
             with(argumentCaptor<List<ViewStructure>>()) {
                 verify(contentCaptureSessionCompat, times(1)).notifyViewsAppeared(capture())
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/contentcapture/AndroidContentCaptureManager.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/contentcapture/AndroidContentCaptureManager.android.kt
index 9ff7b8a..23e60dd 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/contentcapture/AndroidContentCaptureManager.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/contentcapture/AndroidContentCaptureManager.android.kt
@@ -386,6 +386,10 @@
             "android.view.contentcapture.EventTimestamp",
             currentSemanticsNodesSnapshotTimestampMillis)
 
+        configuration.getOrNull(SemanticsProperties.TestTag)?.let {
+            // Treat test tag as resourceId
+            structure.setId(id, null, null, it)
+        }
         configuration.getOrNull(SemanticsProperties.Text)?.let {
             structure.setClassName("android.widget.TextView")
             structure.setText(it.fastJoinToString("\n"))
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/ViewLayerContainer.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/ViewLayerContainer.android.kt
index 118695c..6716cc4 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/ViewLayerContainer.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/ViewLayerContainer.android.kt
@@ -19,8 +19,8 @@
 import android.content.Context
 import android.view.View
 import android.view.ViewGroup
+import androidx.compose.ui.R
 import androidx.compose.ui.graphics.Canvas
-import androidx.compose.ui.graphics.R
 import androidx.compose.ui.graphics.nativeCanvas
 
 /**
diff --git a/compose/ui/ui/src/androidMain/res/values/ids.xml b/compose/ui/ui/src/androidMain/res/values/ids.xml
index 140ecaf..721b41d 100644
--- a/compose/ui/ui/src/androidMain/res/values/ids.xml
+++ b/compose/ui/ui/src/androidMain/res/values/ids.xml
@@ -52,5 +52,6 @@
     <item name="inspection_slot_table_set" type="id" />
     <item name="androidx_compose_ui_view_composition_context" type="id" />
     <item name="compose_view_saveable_id_tag" type="id" />
+    <item name="hide_in_inspector_tag" type="id" />
     <item name="consume_window_insets_tag" type="id" />
 </resources>
diff --git a/compose/ui/ui/src/androidMain/res/values/public.xml b/compose/ui/ui/src/androidMain/res/values/public.xml
index 4d54254..969bb58 100644
--- a/compose/ui/ui/src/androidMain/res/values/public.xml
+++ b/compose/ui/ui/src/androidMain/res/values/public.xml
@@ -15,4 +15,5 @@
   -->
 
 <resources>
+    <public name="hide_in_inspector_tag" type="id" />
 </resources>
diff --git a/compose/ui/ui/src/main/java/androidx/compose/ui/platform/coreshims/ViewStructureCompat.java b/compose/ui/ui/src/main/java/androidx/compose/ui/platform/coreshims/ViewStructureCompat.java
index 1dd6bdb..1052324 100644
--- a/compose/ui/ui/src/main/java/androidx/compose/ui/platform/coreshims/ViewStructureCompat.java
+++ b/compose/ui/ui/src/main/java/androidx/compose/ui/platform/coreshims/ViewStructureCompat.java
@@ -75,6 +75,27 @@
     }
 
     /**
+     * Set the identifier for this view.
+     *
+     * @param id The view's identifier, as per {@link android.view.View#getId View.getId()}.
+     * @param packageName The package name of the view's identifier, or null if there is none.
+     * @param typeName The type name of the view's identifier, or null if there is none.
+     * @param entryName The entry name of the view's identifier, or null if there is none.
+     *
+     * Compatibility behavior:
+     * <ul>
+     * <li>SDK 23 and above, this method matches platform behavior.
+     * <li>SDK 22 and below, this method does nothing.
+     * </ul>
+     */
+    public void setId(int id, @Nullable String packageName, @Nullable String typeName,
+            @Nullable String entryName) {
+        if (SDK_INT >= 23) {
+            Api23Impl.setId((ViewStructure) mWrappedObj, id, packageName, typeName, entryName);
+        }
+    }
+
+    /**
      * Set the text that is associated with this view.  There is no selection
      * associated with the text.  The text may have style spans to supply additional
      * display and semantic information.
@@ -194,6 +215,11 @@
             // This class is not instantiable.
         }
 
+        static void setId(ViewStructure viewStructure, int id, String packageName, String typeName,
+                String entryName) {
+            viewStructure.setId(id, packageName, typeName, entryName);
+        }
+
         @DoNotInline
         static void setDimens(ViewStructure viewStructure, int left, int top, int scrollX,
                 int scrollY, int width, int height) {
diff --git a/constraintlayout/constraintlayout-compose/integration-tests/macrobenchmark/build.gradle b/constraintlayout/constraintlayout-compose/integration-tests/macrobenchmark/build.gradle
index 488e08f..2f9c076 100644
--- a/constraintlayout/constraintlayout-compose/integration-tests/macrobenchmark/build.gradle
+++ b/constraintlayout/constraintlayout-compose/integration-tests/macrobenchmark/build.gradle
@@ -26,8 +26,6 @@
     }
     namespace "androidx.constraintlayout.compose.integration.macrobenchmark"
 
-    // We need animations to work for MotionLayout
-    testOptions.animationsDisabled  false
     targetProjectPath = ":constraintlayout:constraintlayout-compose:integration-tests:macrobenchmark-target"
     experimentalProperties["android.experimental.self-instrumenting"] = true
 }
diff --git a/datastore/datastore-core/src/androidMain/kotlin/androidx/datastore/core/MultiProcessCoordinator.android.kt b/datastore/datastore-core/src/androidMain/kotlin/androidx/datastore/core/MultiProcessCoordinator.android.kt
index 30f06ef..3d3edff 100644
--- a/datastore/datastore-core/src/androidMain/kotlin/androidx/datastore/core/MultiProcessCoordinator.android.kt
+++ b/datastore/datastore-core/src/androidMain/kotlin/androidx/datastore/core/MultiProcessCoordinator.android.kt
@@ -26,7 +26,6 @@
 import kotlin.contracts.ExperimentalContracts
 import kotlin.coroutines.CoroutineContext
 import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.drop
 import kotlinx.coroutines.sync.Mutex
 import kotlinx.coroutines.sync.withLock
 import kotlinx.coroutines.withContext
@@ -37,9 +36,6 @@
 ) : InterProcessCoordinator {
     // TODO(b/269375542): the flow should `flowOn` the provided [context]
     override val updateNotifications: Flow<Unit> = MulticastFileObserver.observe(file)
-        // MulticastFileObserver dispatches 1 value upon connecting to the FileSystem, which
-        // is useful for its tests but not necessary here.
-        .drop(1)
 
     // run block with the exclusive lock
     override suspend fun <T> lock(block: suspend () -> T): T {
diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml
index 2883a4d..a85faf4 100644
--- a/gradle/verification-metadata.xml
+++ b/gradle/verification-metadata.xml
@@ -20,9 +20,9 @@
          <trust group="com.google.mlkit" reason="b/223907608"/>
          <trust group="com.google.testing.platform" reason="b/215430394"/>
          <trust group="gradle" name="gradle"/>
-         <trust file=".*[.]asc" regex="true"/>
          <trust file=".*-javadoc[.]jar" regex="true"/>
          <trust file=".*-sources[.]jar" regex="true"/>
+         <trust file=".*[.]asc" regex="true"/>
          <trust group="^androidx(?!\.compose.compiler\b)\..*" regex="true" reason="not signed yet"/>
          <trust group="^com[.]android($|([.].*))" regex="true" reason="b/215430394"/>
       </trusted-artifacts>
@@ -784,6 +784,14 @@
             <pgp value="720746177725A89207A7075BFD5DEA07FCB690A8"/>
          </artifact>
       </component>
+      <component group="org.jetbrains.kotlin" name="kotlin-gradle-plugin" version="1.9.23">
+         <artifact name="kotlin-gradle-plugin-1.9.23-gradle82.jar">
+            <ignored-keys>
+               <ignored-key id="6F538074CCEBF35F28AF9B066A0975F8B1127B83" reason="Temporary diagnostic for b/321949384"/>
+            </ignored-keys>
+            <sha256 value="9cc4a2206fa5f1adbb4e416f267dc22d8207905b8a1e138c02cb3fac24c67e14" origin="Generated by Gradle" reason="Temporary diagnostic for b/321949384"/>
+         </artifact>
+      </component>
       <component group="org.jetbrains.kotlin" name="kotlin-reflect" version="1.3.71">
          <artifact name="kotlin-reflect-1.3.71.pom">
             <sha256 value="4df94aaeee8d900be431386e31ef44e82a66e57c3ae30866aec2875aff01fe70" origin="Generated by Gradle"/>
diff --git a/graphics/graphics-path/build.gradle b/graphics/graphics-path/build.gradle
index 091c671..753e958 100644
--- a/graphics/graphics-path/build.gradle
+++ b/graphics/graphics-path/build.gradle
@@ -67,6 +67,7 @@
                     "-fomit-frame-pointer",
                     "-ffunction-sections",
                     "-fdata-sections",
+                    "-fstack-protector",
                     "-Wl,--gc-sections",
                     "-Wl,-Bsymbolic-functions",
                     "-nostdlib++"
diff --git a/health/health-services-client/src/test/java/androidx/health/services/client/impl/ServiceBackedPassiveMonitoringClientTest.kt b/health/health-services-client/src/test/java/androidx/health/services/client/impl/ServiceBackedPassiveMonitoringClientTest.kt
index 2c6a3bc..31c8df8 100644
--- a/health/health-services-client/src/test/java/androidx/health/services/client/impl/ServiceBackedPassiveMonitoringClientTest.kt
+++ b/health/health-services-client/src/test/java/androidx/health/services/client/impl/ServiceBackedPassiveMonitoringClientTest.kt
@@ -208,7 +208,7 @@
         assertThat(fakeService.registeredCallbacks).hasSize(2)
         // Stub is not reused.
         assertThat(fakeService.registeredCallbacks[0]).isNotSameInstanceAs(
-            fakeService.registeredCallbacks[1]);
+            fakeService.registeredCallbacks[1])
     }
 
     @Test
diff --git a/libraryversions.toml b/libraryversions.toml
index ba5de7f..560faf2 100644
--- a/libraryversions.toml
+++ b/libraryversions.toml
@@ -23,7 +23,7 @@
 CAR_APP = "1.7.0-alpha01"
 COLLECTION = "1.5.0-alpha01"
 COMPOSE = "1.7.0-alpha05"
-COMPOSE_COMPILER = "1.5.10"  # Update when preparing for a release
+COMPOSE_COMPILER = "1.5.11"  # Update when preparing for a release
 COMPOSE_MATERIAL3 = "1.3.0-alpha03"
 COMPOSE_MATERIAL3_ADAPTIVE = "1.0.0-alpha09"
 COMPOSE_MATERIAL3_ADAPTIVE_NAVIGATION_SUITE = "1.0.0-alpha05"
diff --git a/lint/lint-gradle/src/main/java/androidx/lint/gradle/GradleIssueRegistry.kt b/lint/lint-gradle/src/main/java/androidx/lint/gradle/GradleIssueRegistry.kt
index e0a9e70..b638571 100644
--- a/lint/lint-gradle/src/main/java/androidx/lint/gradle/GradleIssueRegistry.kt
+++ b/lint/lint-gradle/src/main/java/androidx/lint/gradle/GradleIssueRegistry.kt
@@ -28,7 +28,8 @@
 
     override val issues = listOf(
         EagerConfigurationDetector.ISSUE,
-        InternalApiUsageDetector.ISSUE,
+        InternalApiUsageDetector.INTERNAL_GRADLE_ISSUE,
+        InternalApiUsageDetector.INTERNAL_AGP_ISSUE,
         WithPluginClasspathUsageDetector.ISSUE,
     )
 
diff --git a/lint/lint-gradle/src/main/java/androidx/lint/gradle/InternalApiUsageDetector.kt b/lint/lint-gradle/src/main/java/androidx/lint/gradle/InternalApiUsageDetector.kt
index 5e1b881..5b1d9cf 100644
--- a/lint/lint-gradle/src/main/java/androidx/lint/gradle/InternalApiUsageDetector.kt
+++ b/lint/lint-gradle/src/main/java/androidx/lint/gradle/InternalApiUsageDetector.kt
@@ -49,9 +49,14 @@
 
                 if (resolved is PsiClass) {
                     if (resolved.isInternalGradleApi()) {
-                        reportIncidentForNode(node, "Avoid using internal Gradle APIs")
+                        reportIncidentForNode(
+                            INTERNAL_GRADLE_ISSUE,
+                            node,
+                            "Avoid using internal Gradle APIs"
+                        )
                     } else if (resolved.isInternalAgpApi()) {
                         reportIncidentForNode(
+                            INTERNAL_AGP_ISSUE,
                             node,
                             "Avoid using internal Android Gradle Plugin APIs"
                         )
@@ -60,9 +65,9 @@
             }
         }
 
-        private fun reportIncidentForNode(node: UElement, message: String) {
+        private fun reportIncidentForNode(issue: Issue, node: UElement, message: String) {
             val incident = Incident(context)
-                .issue(ISSUE)
+                .issue(issue)
                 .location(context.getLocation(node))
                 .message(message)
                 .scope(node)
@@ -81,7 +86,7 @@
     }
 
     companion object {
-        val ISSUE = Issue.create(
+        val INTERNAL_GRADLE_ISSUE = Issue.create(
             "InternalGradleApiUsage",
             "Avoid using internal Gradle APIs",
             """
@@ -95,5 +100,19 @@
                 Scope.JAVA_FILE_SCOPE
             )
         )
+        val INTERNAL_AGP_ISSUE = Issue.create(
+            "InternalAgpApiUsage",
+            "Avoid using internal Android Gradle Plugin APIs",
+            """
+                Using internal APIs results in fragile plugin behavior as these types have no binary
+                compatibility guarantees. It is best to create a feature request to open up these
+                APIs if you find them useful.
+            """,
+            Category.CORRECTNESS, 5, Severity.ERROR,
+            Implementation(
+                InternalApiUsageDetector::class.java,
+                Scope.JAVA_FILE_SCOPE
+            )
+        )
     }
 }
diff --git a/lint/lint-gradle/src/test/java/androidx/lint/gradle/InternalApiUsageDetectorTest.kt b/lint/lint-gradle/src/test/java/androidx/lint/gradle/InternalApiUsageDetectorTest.kt
index 23a8918..8f3a2e5 100644
--- a/lint/lint-gradle/src/test/java/androidx/lint/gradle/InternalApiUsageDetectorTest.kt
+++ b/lint/lint-gradle/src/test/java/androidx/lint/gradle/InternalApiUsageDetectorTest.kt
@@ -24,7 +24,10 @@
 @RunWith(JUnit4::class)
 class InternalApiUsageDetectorTest : GradleLintDetectorTest(
     detector = InternalApiUsageDetector(),
-    issues = listOf(InternalApiUsageDetector.ISSUE)
+    issues = listOf(
+        InternalApiUsageDetector.INTERNAL_GRADLE_ISSUE,
+        InternalApiUsageDetector.INTERNAL_AGP_ISSUE,
+    )
 ) {
     @Test
     fun `Test usage of internal Gradle API`() {
@@ -90,7 +93,7 @@
             .run()
             .expect(
                 """
-                src/test.kt:1: Error: Avoid using internal Android Gradle Plugin APIs [InternalGradleApiUsage]
+                src/test.kt:1: Error: Avoid using internal Android Gradle Plugin APIs [InternalAgpApiUsage]
                 import com.android.build.gradle.internal.lint.VariantInputs
                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                 1 errors, 0 warnings
diff --git a/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavGraphBuilderTest.kt b/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavGraphBuilderTest.kt
index 4ea7527..47f7464 100644
--- a/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavGraphBuilderTest.kt
+++ b/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavGraphBuilderTest.kt
@@ -135,6 +135,27 @@
             .isTrue()
     }
 
+    @Test
+    fun navigationAddDestinationWithArgsKClassBuilder() {
+        @Serializable
+        class TestClass(val arg: Int)
+
+        val serializer = serializer<TestClass>()
+        val route = serializer.generateRoutePattern()
+        val graph = provider.navigation(
+            startDestination = route
+        ) {
+            val builder = NavDestinationBuilder(provider[NoOpNavigator::class], TestClass::class)
+            addDestination(builder.build())
+        }
+        assertWithMessage("Destination route should be added to the graph")
+            .that(route in graph)
+            .isTrue()
+        assertWithMessage("Destination id should be added to the graph")
+            .that(serializer.hashCode() in graph)
+            .isTrue()
+    }
+
     @Suppress("DEPRECATION")
     @Test(expected = IllegalStateException::class)
     fun navigationMissingStartDestination() {
diff --git a/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavGraphTest.kt b/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavGraphTest.kt
index 937c4c8..fafd8c0 100644
--- a/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavGraphTest.kt
+++ b/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavGraphTest.kt
@@ -18,7 +18,12 @@
 
 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 kotlin.test.assertFailsWith
+import kotlinx.serialization.SerialName
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.serializer
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mockito.mock
@@ -130,6 +135,36 @@
         val graph = NavGraph(navGraphNavigator)
         graph[DESTINATION_ID]
     }
+
+    @Test
+    fun graphSetStartDestinationRoute() {
+        @Serializable
+        @SerialName("route")
+        class TestClass(val arg: Int)
+
+        val graph = NavGraph(navGraphNavigator).apply {
+            setStartDestination(15)
+            addDestination(NavDestinationBuilder(navGraphNavigator, TestClass::class).build())
+        }
+        assertThat(graph.startDestinationId).isEqualTo(15)
+
+        graph.setStartDestination(TestClass::class)
+        assertThat(graph.startDestinationRoute).isEqualTo("route/{arg}")
+        assertThat(graph.startDestinationId).isEqualTo(serializer<TestClass>().hashCode())
+    }
+
+    @Test
+    fun graphSetStartDestinationRouteMissingStartDestination() {
+        @Serializable
+        class TestClass
+
+        val graph = NavGraph(navGraphNavigator)
+
+        // start destination not added via KClass, cannot match
+        assertFailsWith<IllegalStateException> {
+            graph.setStartDestination(TestClass::class)
+        }
+    }
 }
 
 private const val DESTINATION_ID = 1
diff --git a/navigation/navigation-common/src/main/java/androidx/navigation/NavGraph.kt b/navigation/navigation-common/src/main/java/androidx/navigation/NavGraph.kt
index 1e1020e..b241168 100644
--- a/navigation/navigation-common/src/main/java/androidx/navigation/NavGraph.kt
+++ b/navigation/navigation-common/src/main/java/androidx/navigation/NavGraph.kt
@@ -26,6 +26,9 @@
 import androidx.core.content.res.use
 import androidx.navigation.common.R
 import java.lang.StringBuilder
+import kotlin.reflect.KClass
+import kotlinx.serialization.InternalSerializationApi
+import kotlinx.serialization.serializer
 
 /**
  * NavGraph is a collection of [NavDestination] nodes fetchable by ID.
@@ -189,11 +192,10 @@
 
     @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
     public fun findNode(route: String, searchParents: Boolean): NavDestination? {
-        // first try matching with routePattern
-        val id = createRoute(route).hashCode()
-        val destination = nodes[id] ?: nodes.valueIterator().asSequence().firstOrNull {
+        val destination = nodes.valueIterator().asSequence().firstOrNull {
+            // first try matching with routePattern
             // if not found with routePattern, try matching with route args
-            it.matchDeepLink(route) != null
+            it.route.equals(route) || it.matchDeepLink(route) != null
         }
 
         // Search the parent for the NavDestination if it is not a child of this navigation graph
@@ -330,6 +332,31 @@
     }
 
     /**
+     * Sets the starting destination for this NavGraph.
+     *
+     * This will override any previously set [startDestinationId]
+     *
+     * @param startDestRoute The route of the destination as a [KClass] to be shown when navigating
+     * to this NavGraph.
+     */
+    @OptIn(InternalSerializationApi::class)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    public fun setStartDestination(startDestRoute: KClass<*>) {
+        val serializer = startDestRoute.serializer()
+        val id = serializer.hashCode()
+        val startDest = findNode(id)
+        checkNotNull(startDest) {
+            "Cannot find startDestination $startDestRoute from NavGraph. Ensure the starting " +
+                "NavDestination was added via KClass."
+        }
+        // when dest id is based on serializer, we expect the dest route to have been generated
+        // and set
+        startDestinationRoute = startDest.route!!
+        // bypass startDestinationId setter so we don't set route back to null
+        this.startDestId = id
+    }
+
+    /**
      * The route for the starting destination for this NavGraph. When navigating to the
      * NavGraph, the destination represented by this route is the one the user will initially see.
      */
diff --git a/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/migration/AutoMigrationTest.kt b/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/migration/AutoMigrationTest.kt
index 936ba40..0d1f8bf 100644
--- a/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/migration/AutoMigrationTest.kt
+++ b/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/migration/AutoMigrationTest.kt
@@ -21,6 +21,7 @@
 import androidx.sqlite.SQLiteException
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
+import androidx.test.filters.SdkSuppress
 import androidx.test.platform.app.InstrumentationRegistry
 import org.junit.Rule
 import org.junit.Test
@@ -31,6 +32,7 @@
  */
 @RunWith(AndroidJUnit4::class)
 @LargeTest
+@SdkSuppress(minSdkVersion = 22) // b/329236938
 class AutoMigrationTest {
     @JvmField
     @Rule
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/BaseSimpleQueryTest.kt
index d39179d..39da8d5 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/BaseSimpleQueryTest.kt
@@ -21,6 +21,7 @@
 import kotlin.test.AfterTest
 import kotlin.test.BeforeTest
 import kotlin.test.Test
+import kotlinx.coroutines.flow.produceIn
 import kotlinx.coroutines.test.runTest
 
 abstract class BaseSimpleQueryTest {
@@ -93,6 +94,27 @@
     }
 
     @Test
+    fun queryFlow() = runTest {
+        val dao = getRoomDatabase().dao()
+        dao.insertItem(1)
+
+        val channel = dao.getItemListFlow().produceIn(this)
+
+        assertThat(channel.receive()).containsExactly(SampleEntity(1))
+
+        dao.insertItem(2)
+        dao.insertItem(3)
+
+        assertThat(channel.receive()).containsExactly(
+            SampleEntity(1),
+            SampleEntity(2),
+            SampleEntity(3),
+        )
+
+        channel.cancel()
+    }
+
+    @Test
     fun insertAndDelete() = runTest {
         val sampleEntity = SampleEntity(1, 1)
         val dao = getRoomDatabase().dao()
diff --git a/room/integration-tests/multiplatformtestapp/src/commonTest/kotlin/androidx/room/integration/multiplatformtestapp/test/SampleDatabase.kt b/room/integration-tests/multiplatformtestapp/src/commonTest/kotlin/androidx/room/integration/multiplatformtestapp/test/SampleDatabase.kt
index 01bceef..1deccba 100644
--- a/room/integration-tests/multiplatformtestapp/src/commonTest/kotlin/androidx/room/integration/multiplatformtestapp/test/SampleDatabase.kt
+++ b/room/integration-tests/multiplatformtestapp/src/commonTest/kotlin/androidx/room/integration/multiplatformtestapp/test/SampleDatabase.kt
@@ -30,13 +30,14 @@
 import androidx.room.Transaction
 import androidx.room.Update
 import androidx.room.Upsert
+import kotlinx.coroutines.flow.Flow
 
 @Entity
 data class SampleEntity(
     @PrimaryKey
     val pk: Long,
     @ColumnInfo(defaultValue = "0")
-    val data: Long
+    val data: Long = 0
 )
 
 @Entity
@@ -78,6 +79,9 @@
     @Query("SELECT * FROM SampleEntity")
     suspend fun getItemList(): List<SampleEntity>
 
+    @Query("SELECT * FROM SampleEntity")
+    fun getItemListFlow(): Flow<List<SampleEntity>>
+
     @Transaction
     suspend fun deleteList(pks: List<Long>, withError: Boolean = false) {
         require(!withError)
diff --git a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/migration/AutoMigrationTest.java b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/migration/AutoMigrationTest.java
index 0996752..081c285 100644
--- a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/migration/AutoMigrationTest.java
+++ b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/migration/AutoMigrationTest.java
@@ -29,6 +29,7 @@
 import androidx.sqlite.db.SupportSQLiteDatabase;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.LargeTest;
+import androidx.test.filters.SdkSuppress;
 import androidx.test.platform.app.InstrumentationRegistry;
 
 import org.junit.Rule;
@@ -42,6 +43,7 @@
  */
 @RunWith(AndroidJUnit4.class)
 @LargeTest
+@SdkSuppress(minSdkVersion = 22) // b/329236938
 public class AutoMigrationTest {
     private static final String TEST_DB = "auto-migration-test";
     @Rule
diff --git a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/migration/MigrationTest.java b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/migration/MigrationTest.java
index 0be35ef..b8b3378 100644
--- a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/migration/MigrationTest.java
+++ b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/migration/MigrationTest.java
@@ -1006,7 +1006,7 @@
                 Context testContext = InstrumentationRegistry.getInstrumentation().getContext();
                 InputStream input = testContext.getAssets().open(MigrationDb.class.getCanonicalName()
                         + "/" + MigrationDb.LATEST_VERSION + ".json");
-                SchemaBundle schemaBundle = SchemaBundle.deserialize(input);
+                SchemaBundle schemaBundle = SchemaBundle.Companion.deserialize(input);
                 for (String query : schemaBundle.getDatabase().buildCreateQueries()) {
                     db.execSQL(query);
                 }
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/ext/xpoet_ext.kt b/room/room-compiler/src/main/kotlin/androidx/room/ext/xpoet_ext.kt
index 9578966..7b40165 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/ext/xpoet_ext.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/ext/xpoet_ext.kt
@@ -87,6 +87,7 @@
         XClassName.get(ROOM_PACKAGE, "RoomOpenDelegate", "ValidationResult")
     val STATEMENT_UTIL = XClassName.get("$ROOM_PACKAGE.util", "SQLiteStatementUtil")
     val CONNECTION_UTIL = XClassName.get("$ROOM_PACKAGE.util", "SQLiteConnectionUtil")
+    val FLOW_UTIL = XClassName.get("$ROOM_PACKAGE.coroutines", "FlowUtil")
 }
 
 object RoomAnnotationTypeNames {
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/processor/DatabaseProcessor.kt b/room/room-compiler/src/main/kotlin/androidx/room/processor/DatabaseProcessor.kt
index 641a5c0..3fdef4e 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/processor/DatabaseProcessor.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/processor/DatabaseProcessor.kt
@@ -28,7 +28,6 @@
 import androidx.room.migration.bundle.SchemaBundle
 import androidx.room.processor.ProcessorErrors.AUTO_MIGRATION_FOUND_BUT_EXPORT_SCHEMA_OFF
 import androidx.room.processor.ProcessorErrors.AUTO_MIGRATION_SCHEMA_IN_FOLDER_NULL
-import androidx.room.processor.ProcessorErrors.autoMigrationSchemaIsEmpty
 import androidx.room.processor.ProcessorErrors.invalidAutoMigrationSchema
 import androidx.room.util.SchemaFileResolver
 import androidx.room.verifier.DatabaseVerificationErrors
@@ -42,6 +41,7 @@
 import androidx.room.vo.Warning
 import androidx.room.vo.columnNames
 import androidx.room.vo.findFieldByColumnName
+import java.io.FileNotFoundException
 import java.io.IOException
 import java.nio.file.Path
 import java.util.Locale
@@ -230,24 +230,25 @@
             schemaStream.use {
                 SchemaBundle.deserialize(schemaStream)
             }
+        } catch (ex: FileNotFoundException) {
+            context.logger.e(
+                element,
+                ProcessorErrors.autoMigrationSchemasNotFound(
+                    version,
+                    schemaFolderPath.toString()
+                ),
+            )
+            null
         } catch (th: Throwable) {
-            if (th is SchemaBundle.EmptySchemaException) {
-                context.logger.e(
-                    element,
-                    autoMigrationSchemaIsEmpty(
-                        version,
-                        schemaFolderPath.toString()
-                    ),
+            // For debugging support include exception message in a WARN message.
+            context.logger.w("Unable to read schema file: ${th.message ?: ""}")
+            context.logger.e(
+                element,
+                invalidAutoMigrationSchema(
+                    version,
+                    schemaFolderPath.toString()
                 )
-            } else {
-                context.logger.e(
-                    element,
-                    invalidAutoMigrationSchema(
-                        version,
-                        schemaFolderPath.toString()
-                    )
-                )
-            }
+            )
             null
         }
         return bundle?.database
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 a293e29..99e1ccf 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
@@ -926,11 +926,6 @@
             "out folder: $schemaOutFolderPath. Cannot generate auto migrations."
     }
 
-    fun autoMigrationSchemaIsEmpty(schemaVersion: Int, schemaOutFolderPath: String): String {
-        return "Found empty schema file '$schemaVersion.json' required for migration was not " +
-            "found at the schema out folder: $schemaOutFolderPath. Cannot generate auto migrations."
-    }
-
     fun invalidAutoMigrationSchema(schemaVersion: Int, schemaOutFolderPath: String): String {
         return "Found invalid schema file '$schemaVersion.json' at the schema out " +
             "folder: $schemaOutFolderPath.\nIf you've modified the file, you might've broken the " +
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/CoroutineFlowResultBinder.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/CoroutineFlowResultBinder.kt
index fc5e066..2a7ff10 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/CoroutineFlowResultBinder.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/CoroutineFlowResultBinder.kt
@@ -16,17 +16,24 @@
 
 package androidx.room.solver.query.result
 
+import androidx.room.compiler.codegen.CodeLanguage
 import androidx.room.compiler.codegen.XCodeBlock
+import androidx.room.compiler.codegen.XCodeBlock.Builder.Companion.addLocalVal
+import androidx.room.compiler.codegen.XMemberName.Companion.packageMember
 import androidx.room.compiler.codegen.XPropertySpec
+import androidx.room.compiler.codegen.XTypeName
 import androidx.room.compiler.processing.XType
 import androidx.room.ext.ArrayLiteral
 import androidx.room.ext.CallableTypeSpecBuilder
 import androidx.room.ext.CommonTypeNames
+import androidx.room.ext.Function1TypeSpec
 import androidx.room.ext.RoomCoroutinesTypeNames.COROUTINES_ROOM
+import androidx.room.ext.RoomTypeNames
+import androidx.room.ext.SQLiteDriverTypeNames
 import androidx.room.solver.CodeGenScope
 
 /**
- * Binds the result of a of a Kotlin Coroutine Flow<T>
+ * Binds the result of a Kotlin Coroutine Flow<T>
  */
 class CoroutineFlowResultBinder(
     val typeArg: XType,
@@ -76,4 +83,124 @@
             )
         }
     }
+
+    override fun isMigratedToDriver() = adapter?.isMigratedToDriver() == true
+
+    override fun convertAndReturn(
+        sqlQueryVar: String,
+        dbProperty: XPropertySpec,
+        bindStatement: CodeGenScope.(String) -> Unit,
+        returnTypeName: XTypeName,
+        inTransaction: Boolean,
+        scope: CodeGenScope
+    ) {
+        val arrayOfTableNamesLiteral = ArrayLiteral(
+            scope.language,
+            CommonTypeNames.STRING,
+            *tableNames.toTypedArray()
+        )
+        when (scope.language) {
+            CodeLanguage.JAVA -> convertAndReturnJava(
+                sqlQueryVar,
+                dbProperty,
+                bindStatement,
+                inTransaction,
+                arrayOfTableNamesLiteral,
+                scope
+            )
+
+            CodeLanguage.KOTLIN -> convertAndReturnKotlin(
+                sqlQueryVar,
+                dbProperty,
+                bindStatement,
+                inTransaction,
+                arrayOfTableNamesLiteral,
+                scope
+            )
+        }
+    }
+
+    private fun convertAndReturnJava(
+        sqlQueryVar: String,
+        dbProperty: XPropertySpec,
+        bindStatement: CodeGenScope.(String) -> Unit,
+        inTransaction: Boolean,
+        arrayOfTableNamesLiteral: XCodeBlock,
+        scope: CodeGenScope
+    ) {
+        val connectionVar = scope.getTmpVar("_connection")
+        val statementVar = scope.getTmpVar("_stmt")
+        scope.builder.addStatement(
+            "return %M(%N, %L, %L, %L)",
+            RoomTypeNames.FLOW_UTIL.packageMember("createFlow"),
+            dbProperty,
+            inTransaction,
+            arrayOfTableNamesLiteral,
+            // TODO(b/322387497): Generate lambda syntax if possible
+            Function1TypeSpec(
+                language = scope.language,
+                parameterTypeName = SQLiteDriverTypeNames.CONNECTION,
+                parameterName = connectionVar,
+                returnTypeName = typeArg.asTypeName()
+            ) {
+                val functionScope = scope.fork()
+                val outVar = functionScope.getTmpVar("_result")
+                val functionCode = functionScope.builder.apply {
+                    addLocalVal(
+                        statementVar,
+                        SQLiteDriverTypeNames.STATEMENT,
+                        "%L.prepare(%L)",
+                        connectionVar,
+                        sqlQueryVar
+                    )
+                    beginControlFlow("try")
+                    bindStatement(functionScope, statementVar)
+                    adapter?.convert(outVar, statementVar, functionScope)
+                    addStatement("return %L", outVar)
+                    nextControlFlow("finally")
+                    addStatement("%L.close()", statementVar)
+                    endControlFlow()
+                }.build()
+                this.addCode(functionCode)
+            }
+        )
+    }
+
+    private fun convertAndReturnKotlin(
+        sqlQueryVar: String,
+        dbProperty: XPropertySpec,
+        bindStatement: CodeGenScope.(String) -> Unit,
+        inTransaction: Boolean,
+        arrayOfTableNamesLiteral: XCodeBlock,
+        scope: CodeGenScope
+    ) {
+        val connectionVar = scope.getTmpVar("_connection")
+        val statementVar = scope.getTmpVar("_stmt")
+        scope.builder.apply {
+            beginControlFlow(
+                "return %M(%N, %L, %L) { %L ->",
+                RoomTypeNames.FLOW_UTIL.packageMember("createFlow"),
+                dbProperty,
+                inTransaction,
+                arrayOfTableNamesLiteral,
+                connectionVar
+            )
+            addLocalVal(
+                statementVar,
+                SQLiteDriverTypeNames.STATEMENT,
+                "%L.prepare(%L)",
+                connectionVar,
+                sqlQueryVar
+            )
+            beginControlFlow("try")
+            bindStatement(scope, statementVar)
+            val outVar = scope.getTmpVar("_result")
+            adapter?.convert(outVar, statementVar, scope)
+            addStatement("%L", outVar)
+            nextControlFlow("finally")
+            addStatement("%L.close()", statementVar)
+            endControlFlow()
+            endControlFlow()
+        }
+    }
 }
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/util/SchemaDiffer.kt b/room/room-compiler/src/main/kotlin/androidx/room/util/SchemaDiffer.kt
index 9d59d4d..80944a1 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/util/SchemaDiffer.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/util/SchemaDiffer.kt
@@ -16,6 +16,7 @@
 
 package androidx.room.util
 
+import androidx.room.migration.bundle.BaseEntityBundle
 import androidx.room.migration.bundle.DatabaseBundle
 import androidx.room.migration.bundle.DatabaseViewBundle
 import androidx.room.migration.bundle.EntityBundle
@@ -80,7 +81,7 @@
     private val potentiallyDeletedTables = mutableSetOf<String>()
     // Maps FTS tables in the to version to the name of their content tables in the from version
     // for easy lookup.
-    private val contentTableToFtsEntities = mutableMapOf<String, MutableList<EntityBundle>>()
+    private val contentTableToFtsEntities = mutableMapOf<String, MutableList<BaseEntityBundle>>()
 
     private val addedTables = mutableSetOf<AutoMigration.AddedTable>()
     // Any table that has been renamed, but also does not contain any complex changes.
@@ -196,8 +197,8 @@
      * null object will be returned.
      */
     private fun detectTableLevelChanges(
-        fromTable: EntityBundle
-    ): EntityBundle? {
+        fromTable: BaseEntityBundle
+    ): BaseEntityBundle? {
         // Check if the table was renamed. If so, check for other complex changes that could
         // be found on the table level. Save the end result to the complex changed tables map.
         val renamedTable = isTableRenamed(fromTable.tableName)
@@ -283,8 +284,8 @@
      * value if the column was deleted.
      */
     private fun detectColumnLevelChanges(
-        fromTable: EntityBundle,
-        toTable: EntityBundle,
+        fromTable: BaseEntityBundle,
+        toTable: BaseEntityBundle,
         fromColumn: FieldBundle,
     ): String? {
         // Check if this column was renamed. If so, no need to check further, we can mark this
@@ -368,39 +369,37 @@
      * @return A ComplexChangedTable object, null if complex schema change has not been found
      */
     private fun tableContainsComplexChanges(
-        fromTable: EntityBundle,
-        toTable: EntityBundle
+        fromTable: BaseEntityBundle,
+        toTable: BaseEntityBundle
     ): Boolean {
-        // If we have an FTS table, check if options have changed
-        if (fromTable is FtsEntityBundle &&
-            toTable is FtsEntityBundle &&
-            !fromTable.ftsOptions.isSchemaEqual(toTable.ftsOptions)
-        ) {
-            return true
-        }
-        // Check if the to table or the from table is an FTS table while the other is not.
-        if (fromTable is FtsEntityBundle && toTable !is FtsEntityBundle ||
-            toTable is FtsEntityBundle && fromTable !is FtsEntityBundle
-        ) {
-            return true
-        }
-
-        if (!isForeignKeyBundlesListEqual(fromTable.foreignKeys, toTable.foreignKeys)) {
-            return true
-        }
-        if (!isIndexBundlesListEqual(fromTable.indices, toTable.indices)) {
-            return true
-        }
-
         if (!fromTable.primaryKey.isSchemaEqual(toTable.primaryKey)) {
             return true
         }
-        // Check if any foreign keys are referencing a renamed table.
-        return fromTable.foreignKeys.any { foreignKey ->
-            renameTableEntries.any {
-                it.originalTableName == foreignKey.table
+
+        // If both are FTS tables, only check if options have changed
+        if (fromTable is FtsEntityBundle && toTable is FtsEntityBundle) {
+            return !fromTable.ftsOptions.isSchemaEqual(toTable.ftsOptions)
+        }
+
+        // If both are normal tables, check foreign keys and indices
+        if (fromTable is EntityBundle && toTable is EntityBundle) {
+            if (!isForeignKeyBundlesListEqual(fromTable.foreignKeys, toTable.foreignKeys)) {
+                return true
+            }
+            if (!isIndexBundlesListEqual(fromTable.indices, toTable.indices)) {
+                return true
+            }
+            // Check if any foreign keys are referencing a renamed table.
+            return fromTable.foreignKeys.any { foreignKey ->
+                renameTableEntries.any {
+                    it.originalTableName == foreignKey.table
+                }
             }
         }
+
+        // If we reach this check then from and to tables are not of the same type, a change of
+        // table type is complex
+        return true
     }
 
     /**
@@ -525,7 +524,7 @@
      * database that have been already processed
      */
     private fun processAddedTableAndColumns(
-        toTable: EntityBundle,
+        toTable: BaseEntityBundle,
         processedTablesAndColumnsInNewVersion: MutableMap<String, List<String>>
     ) {
         // Old table bundle will be found even if table is renamed.
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/vo/AutoMigration.kt b/room/room-compiler/src/main/kotlin/androidx/room/vo/AutoMigration.kt
index 35248a6..7900a4e 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/vo/AutoMigration.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/vo/AutoMigration.kt
@@ -18,7 +18,7 @@
 
 import androidx.room.compiler.codegen.XClassName
 import androidx.room.compiler.processing.XTypeElement
-import androidx.room.migration.bundle.EntityBundle
+import androidx.room.migration.bundle.BaseEntityBundle
 import androidx.room.migration.bundle.FieldBundle
 import androidx.room.util.SchemaDiffResult
 
@@ -65,7 +65,7 @@
     /**
      * Stores the table that was added to a database in a newer version.
      */
-    data class AddedTable(val entityBundle: EntityBundle)
+    data class AddedTable(val entityBundle: BaseEntityBundle)
 
     /**
      * Stores the table that contains a change in the primary key, foreign key(s) or index(es)
@@ -82,8 +82,8 @@
     data class ComplexChangedTable(
         val tableName: String,
         val tableNameWithNewPrefix: String,
-        val oldVersionEntityBundle: EntityBundle,
-        val newVersionEntityBundle: EntityBundle,
+        val oldVersionEntityBundle: BaseEntityBundle,
+        val newVersionEntityBundle: BaseEntityBundle,
         val renamedColumnsMap: MutableMap<String, String>
     )
 
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/vo/Database.kt b/room/room-compiler/src/main/kotlin/androidx/room/vo/Database.kt
index 04dec4a..78d0d1c 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/vo/Database.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/vo/Database.kt
@@ -21,6 +21,7 @@
 import androidx.room.compiler.processing.XType
 import androidx.room.compiler.processing.XTypeElement
 import androidx.room.migration.bundle.DatabaseBundle
+import androidx.room.migration.bundle.SCHEMA_LATEST_FORMAT_VERSION
 import androidx.room.migration.bundle.SchemaBundle
 import androidx.room.util.SchemaFileResolver
 import java.io.IOException
@@ -107,7 +108,7 @@
     // Writes schema file to output path, using the input path to check if the schema has changed
     // otherwise it is not written.
     fun exportSchema(inputPath: Path, outputPath: Path) {
-        val schemaBundle = SchemaBundle(SchemaBundle.LATEST_FORMAT, bundle)
+        val schemaBundle = SchemaBundle(SCHEMA_LATEST_FORMAT_VERSION, bundle)
         val inputStream = try {
             SchemaFileResolver.RESOLVER.readPath(inputPath)
         } catch (e: IOException) {
@@ -136,7 +137,7 @@
     // existing schema equality, otherwise use the version of `exportSchema` that takes input and
     // output paths.
     fun exportSchemaOnly(outputStream: OutputStream) {
-        val schemaBundle = SchemaBundle(SchemaBundle.LATEST_FORMAT, bundle)
+        val schemaBundle = SchemaBundle(SCHEMA_LATEST_FORMAT_VERSION, bundle)
         SchemaBundle.serialize(schemaBundle, outputStream)
     }
 }
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/vo/Entity.kt b/room/room-compiler/src/main/kotlin/androidx/room/vo/Entity.kt
index 6f4b932..4fbc12f 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/vo/Entity.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/vo/Entity.kt
@@ -18,6 +18,7 @@
 
 import androidx.room.compiler.processing.XType
 import androidx.room.compiler.processing.XTypeElement
+import androidx.room.migration.bundle.BaseEntityBundle
 import androidx.room.migration.bundle.EntityBundle
 import androidx.room.migration.bundle.TABLE_NAME_PLACEHOLDER
 
@@ -87,7 +88,7 @@
         }
     }
 
-    open fun toBundle(): EntityBundle = EntityBundle(
+    open fun toBundle(): BaseEntityBundle = EntityBundle(
         tableName,
         createTableQuery(TABLE_NAME_PLACEHOLDER),
         fields.map { it.toBundle() },
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/vo/FtsEntity.kt b/room/room-compiler/src/main/kotlin/androidx/room/vo/FtsEntity.kt
index 5a8a9a9..3f8255f 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/vo/FtsEntity.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/vo/FtsEntity.kt
@@ -133,6 +133,8 @@
         createTableQuery(TABLE_NAME_PLACEHOLDER),
         nonHiddenFields.map { it.toBundle() },
         primaryKey.toBundle(),
+        emptyList(),
+        emptyList(),
         ftsVersion.name,
         ftsOptions.toBundle(),
         contentSyncTriggerCreateQueries
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/writer/AutoMigrationWriter.kt b/room/room-compiler/src/main/kotlin/androidx/room/writer/AutoMigrationWriter.kt
index 0e4a495..ab93879 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/writer/AutoMigrationWriter.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/writer/AutoMigrationWriter.kt
@@ -29,6 +29,7 @@
 import androidx.room.ext.RoomTypeNames
 import androidx.room.ext.SQLiteDriverMemberNames
 import androidx.room.ext.SQLiteDriverTypeNames.CONNECTION
+import androidx.room.migration.bundle.BaseEntityBundle
 import androidx.room.migration.bundle.EntityBundle
 import androidx.room.migration.bundle.FtsEntityBundle
 import androidx.room.vo.AutoMigration
@@ -201,12 +202,14 @@
                     tableNameWithNewPrefix,
                     migrateBuilder
                 )
-                addStatementsToRecreateIndexes(newEntityBundle, migrateBuilder)
-                if (newEntityBundle.foreignKeys.isNotEmpty()) {
-                    addStatementsToCheckForeignKeyConstraint(
-                        newEntityBundle.tableName,
-                        migrateBuilder
-                    )
+                if (newEntityBundle is EntityBundle) {
+                    addStatementsToRecreateIndexes(newEntityBundle, migrateBuilder)
+                    if (newEntityBundle.foreignKeys.isNotEmpty()) {
+                        addStatementsToCheckForeignKeyConstraint(
+                            newEntityBundle.tableName,
+                            migrateBuilder
+                        )
+                    }
                 }
             }
         }
@@ -214,8 +217,8 @@
 
     private fun addStatementsToMigrateFtsTable(
         migrateBuilder: XFunSpec.Builder,
-        oldTable: EntityBundle,
-        newTable: EntityBundle,
+        oldTable: BaseEntityBundle,
+        newTable: BaseEntityBundle,
         renamedColumnsMap: MutableMap<String, String>
     ) {
         addDatabaseExecuteSqlStatement(migrateBuilder, "DROP TABLE `${oldTable.tableName}`")
@@ -274,7 +277,7 @@
      * @param migrateBuilder Builder for the migrate() function to be generated
      */
     private fun addStatementsToCreateNewTable(
-        newTable: EntityBundle,
+        newTable: BaseEntityBundle,
         migrateBuilder: XFunSpec.Builder
     ) {
         addDatabaseExecuteSqlStatement(
@@ -296,8 +299,8 @@
     private fun addStatementsToContentTransfer(
         oldTableName: String,
         tableNameWithNewPrefix: String,
-        oldEntityBundle: EntityBundle,
-        newEntityBundle: EntityBundle,
+        oldEntityBundle: BaseEntityBundle,
+        newEntityBundle: BaseEntityBundle,
         renamedColumnsMap: MutableMap<String, String>,
         migrateBuilder: XFunSpec.Builder
     ) {
@@ -463,7 +466,9 @@
                 migrateBuilder,
                 addedTable.entityBundle.createTable()
             )
-            addStatementsToRecreateIndexes(addedTable.entityBundle, migrateBuilder)
+            if (addedTable.entityBundle is EntityBundle) {
+                addStatementsToRecreateIndexes(addedTable.entityBundle, migrateBuilder)
+            }
         }
     }
 
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 d8fde6c..1f0d37d 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
@@ -1372,7 +1372,7 @@
             invocation.assertCompilationResult {
                 hasErrorCount(1)
                 hasErrorContaining(
-                    ProcessorErrors.autoMigrationSchemaIsEmpty(
+                    ProcessorErrors.invalidAutoMigrationSchema(
                         1,
                         schemaFolder.root.absolutePath + File.separator + "foo.bar.MyDb"
                     )
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/coroutines.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/coroutines.kt
index 0abb567..64bc0a4 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/coroutines.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/coroutines.kt
@@ -1,16 +1,11 @@
-import android.database.Cursor
-import androidx.room.CoroutinesRoom
 import androidx.room.RoomDatabase
-import androidx.room.RoomSQLiteQuery
-import androidx.room.RoomSQLiteQuery.Companion.acquire
+import androidx.room.coroutines.createFlow
 import androidx.room.util.appendPlaceholders
 import androidx.room.util.getColumnIndexOrThrow
 import androidx.room.util.getLastInsertedRowId
 import androidx.room.util.getTotalChangedRows
 import androidx.room.util.performSuspending
-import androidx.room.util.query
 import androidx.sqlite.SQLiteStatement
-import java.util.concurrent.Callable
 import javax.`annotation`.processing.Generated
 import kotlin.Int
 import kotlin.Long
@@ -40,43 +35,35 @@
     appendPlaceholders(_stringBuilder, _inputSize)
     _stringBuilder.append(")")
     val _sql: String = _stringBuilder.toString()
-    val _argCount: Int = 0 + _inputSize
-    val _statement: RoomSQLiteQuery = acquire(_sql, _argCount)
-    var _argIndex: Int = 1
-    for (_item: String? in arg) {
-      if (_item == null) {
-        _statement.bindNull(_argIndex)
-      } else {
-        _statement.bindString(_argIndex, _item)
-      }
-      _argIndex++
-    }
-    return CoroutinesRoom.createFlow(__db, false, arrayOf("MyEntity"), object : Callable<MyEntity> {
-      public override fun call(): MyEntity {
-        val _cursor: Cursor = query(__db, _statement, false, null)
-        try {
-          val _cursorIndexOfPk: Int = getColumnIndexOrThrow(_cursor, "pk")
-          val _cursorIndexOfOther: Int = getColumnIndexOrThrow(_cursor, "other")
-          val _result: MyEntity
-          if (_cursor.moveToFirst()) {
-            val _tmpPk: Int
-            _tmpPk = _cursor.getInt(_cursorIndexOfPk)
-            val _tmpOther: String
-            _tmpOther = _cursor.getString(_cursorIndexOfOther)
-            _result = MyEntity(_tmpPk,_tmpOther)
+    return createFlow(__db, false, arrayOf("MyEntity")) { _connection ->
+      val _stmt: SQLiteStatement = _connection.prepare(_sql)
+      try {
+        var _argIndex: Int = 1
+        for (_item: String? in arg) {
+          if (_item == null) {
+            _stmt.bindNull(_argIndex)
           } else {
-            error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
+            _stmt.bindText(_argIndex, _item)
           }
-          return _result
-        } finally {
-          _cursor.close()
+          _argIndex++
         }
+        val _cursorIndexOfPk: Int = getColumnIndexOrThrow(_stmt, "pk")
+        val _cursorIndexOfOther: Int = getColumnIndexOrThrow(_stmt, "other")
+        val _result: MyEntity
+        if (_stmt.step()) {
+          val _tmpPk: Int
+          _tmpPk = _stmt.getLong(_cursorIndexOfPk).toInt()
+          val _tmpOther: String
+          _tmpOther = _stmt.getText(_cursorIndexOfOther)
+          _result = MyEntity(_tmpPk,_tmpOther)
+        } else {
+          error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
+        }
+        _result
+      } finally {
+        _stmt.close()
       }
-
-      protected fun finalize() {
-        _statement.release()
-      }
-    })
+    }
   }
 
   public override fun getFlowNullable(vararg arg: String?): Flow<MyEntity?> {
@@ -86,44 +73,35 @@
     appendPlaceholders(_stringBuilder, _inputSize)
     _stringBuilder.append(")")
     val _sql: String = _stringBuilder.toString()
-    val _argCount: Int = 0 + _inputSize
-    val _statement: RoomSQLiteQuery = acquire(_sql, _argCount)
-    var _argIndex: Int = 1
-    for (_item: String? in arg) {
-      if (_item == null) {
-        _statement.bindNull(_argIndex)
-      } else {
-        _statement.bindString(_argIndex, _item)
-      }
-      _argIndex++
-    }
-    return CoroutinesRoom.createFlow(__db, false, arrayOf("MyEntity"), object : Callable<MyEntity?>
-        {
-      public override fun call(): MyEntity? {
-        val _cursor: Cursor = query(__db, _statement, false, null)
-        try {
-          val _cursorIndexOfPk: Int = getColumnIndexOrThrow(_cursor, "pk")
-          val _cursorIndexOfOther: Int = getColumnIndexOrThrow(_cursor, "other")
-          val _result: MyEntity?
-          if (_cursor.moveToFirst()) {
-            val _tmpPk: Int
-            _tmpPk = _cursor.getInt(_cursorIndexOfPk)
-            val _tmpOther: String
-            _tmpOther = _cursor.getString(_cursorIndexOfOther)
-            _result = MyEntity(_tmpPk,_tmpOther)
+    return createFlow(__db, false, arrayOf("MyEntity")) { _connection ->
+      val _stmt: SQLiteStatement = _connection.prepare(_sql)
+      try {
+        var _argIndex: Int = 1
+        for (_item: String? in arg) {
+          if (_item == null) {
+            _stmt.bindNull(_argIndex)
           } else {
-            _result = null
+            _stmt.bindText(_argIndex, _item)
           }
-          return _result
-        } finally {
-          _cursor.close()
+          _argIndex++
         }
+        val _cursorIndexOfPk: Int = getColumnIndexOrThrow(_stmt, "pk")
+        val _cursorIndexOfOther: Int = getColumnIndexOrThrow(_stmt, "other")
+        val _result: MyEntity?
+        if (_stmt.step()) {
+          val _tmpPk: Int
+          _tmpPk = _stmt.getLong(_cursorIndexOfPk).toInt()
+          val _tmpOther: String
+          _tmpOther = _stmt.getText(_cursorIndexOfOther)
+          _result = MyEntity(_tmpPk,_tmpOther)
+        } else {
+          _result = null
+        }
+        _result
+      } finally {
+        _stmt.close()
       }
-
-      protected fun finalize() {
-        _statement.release()
-      }
-    })
+    }
   }
 
   public override suspend fun getSuspendList(vararg arg: String?): List<MyEntity> {
diff --git a/room/room-migration/api/restricted_current.ignore b/room/room-migration/api/restricted_current.ignore
new file mode 100644
index 0000000..9820ce0
--- /dev/null
+++ b/room/room-migration/api/restricted_current.ignore
@@ -0,0 +1,3 @@
+// Baseline format: 1.0
+RemovedPackage: androidx.room.migration.bundle:
+    Removed package androidx.room.migration.bundle
diff --git a/room/room-migration/api/restricted_current.txt b/room/room-migration/api/restricted_current.txt
index 07459f9..e6f50d0 100644
--- a/room/room-migration/api/restricted_current.txt
+++ b/room/room-migration/api/restricted_current.txt
@@ -1,198 +1 @@
 // Signature format: 4.0
-package androidx.room.migration.bundle {
-
-  @RestrictTo({androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX}) public final class BundleUtil {
-    method public static String replaceTableName(String contents, String tableName);
-    method public static String replaceViewName(String contents, String viewName);
-    field public static final String TABLE_NAME_PLACEHOLDER = "${TABLE_NAME}";
-    field public static final String VIEW_NAME_PLACEHOLDER = "${VIEW_NAME}";
-  }
-
-  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class DatabaseBundle implements androidx.room.migration.bundle.SchemaEquality<androidx.room.migration.bundle.DatabaseBundle> {
-    ctor @Deprecated public DatabaseBundle();
-    ctor public DatabaseBundle(int version, String identityHash, java.util.List<? extends androidx.room.migration.bundle.EntityBundle> entities, java.util.List<? extends androidx.room.migration.bundle.DatabaseViewBundle> views, java.util.List<java.lang.String> setupQueries);
-    method public java.util.List<java.lang.String> buildCreateQueries();
-    method public java.util.List<androidx.room.migration.bundle.EntityBundle> getEntities();
-    method public java.util.Map<java.lang.String,androidx.room.migration.bundle.EntityBundle> getEntitiesByTableName();
-    method public String getIdentityHash();
-    method public int getVersion();
-    method public java.util.List<androidx.room.migration.bundle.DatabaseViewBundle> getViews();
-    method public final java.util.Map<java.lang.String,androidx.room.migration.bundle.DatabaseViewBundle> getViewsByName();
-    method public boolean isSchemaEqual(androidx.room.migration.bundle.DatabaseBundle other);
-    property public java.util.List<androidx.room.migration.bundle.EntityBundle> entities;
-    property public java.util.Map<java.lang.String,androidx.room.migration.bundle.EntityBundle> entitiesByTableName;
-    property public String identityHash;
-    property public int version;
-    property public java.util.List<androidx.room.migration.bundle.DatabaseViewBundle> views;
-    property public final java.util.Map<java.lang.String,androidx.room.migration.bundle.DatabaseViewBundle> viewsByName;
-  }
-
-  public static final class DatabaseBundle.FtsEntityCreateComparator implements java.util.Comparator<androidx.room.migration.bundle.EntityBundle> {
-    ctor public DatabaseBundle.FtsEntityCreateComparator();
-    method public int compare(androidx.room.migration.bundle.EntityBundle firstEntity, androidx.room.migration.bundle.EntityBundle secondEntity);
-  }
-
-  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class DatabaseViewBundle implements androidx.room.migration.bundle.SchemaEquality<androidx.room.migration.bundle.DatabaseViewBundle> {
-    ctor public DatabaseViewBundle(@com.google.gson.annotations.SerializedName("viewName") String viewName, @com.google.gson.annotations.SerializedName("createSql") String createSql);
-    method public String createView();
-    method public String getCreateSql();
-    method public String getViewName();
-    method public boolean isSchemaEqual(androidx.room.migration.bundle.DatabaseViewBundle other);
-    property public String createSql;
-    property public String viewName;
-  }
-
-  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class EntityBundle implements androidx.room.migration.bundle.SchemaEquality<androidx.room.migration.bundle.EntityBundle> {
-    ctor public EntityBundle(@com.google.gson.annotations.SerializedName("tableName") String tableName, @com.google.gson.annotations.SerializedName("createSql") String createSql, @com.google.gson.annotations.SerializedName("fields") java.util.List<? extends androidx.room.migration.bundle.FieldBundle> fields, @com.google.gson.annotations.SerializedName("primaryKey") androidx.room.migration.bundle.PrimaryKeyBundle primaryKey, @com.google.gson.annotations.SerializedName("indices") java.util.List<? extends androidx.room.migration.bundle.IndexBundle> indices, @com.google.gson.annotations.SerializedName("foreignKeys") java.util.List<? extends androidx.room.migration.bundle.ForeignKeyBundle> foreignKeys);
-    method public java.util.Collection<java.lang.String> buildCreateQueries();
-    method public String createNewTable();
-    method public String createTable();
-    method public String getCreateSql();
-    method public java.util.List<androidx.room.migration.bundle.FieldBundle> getFields();
-    method public java.util.Map<java.lang.String,androidx.room.migration.bundle.FieldBundle> getFieldsByColumnName();
-    method public java.util.List<androidx.room.migration.bundle.ForeignKeyBundle> getForeignKeys();
-    method public java.util.List<androidx.room.migration.bundle.IndexBundle> getIndices();
-    method public String getNewTableName();
-    method public androidx.room.migration.bundle.PrimaryKeyBundle getPrimaryKey();
-    method public String getTableName();
-    method public boolean isSchemaEqual(androidx.room.migration.bundle.EntityBundle other);
-    method public String renameToOriginal();
-    property public String createSql;
-    property public java.util.List<androidx.room.migration.bundle.FieldBundle> fields;
-    property public java.util.Map<java.lang.String,androidx.room.migration.bundle.FieldBundle> fieldsByColumnName;
-    property public java.util.List<androidx.room.migration.bundle.ForeignKeyBundle> foreignKeys;
-    property public java.util.List<androidx.room.migration.bundle.IndexBundle> indices;
-    property public String newTableName;
-    property public androidx.room.migration.bundle.PrimaryKeyBundle primaryKey;
-    property public String tableName;
-    field public static final androidx.room.migration.bundle.EntityBundle.Companion Companion;
-    field public static final String NEW_TABLE_PREFIX = "_new_";
-  }
-
-  public static final class EntityBundle.Companion {
-  }
-
-  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class FieldBundle implements androidx.room.migration.bundle.SchemaEquality<androidx.room.migration.bundle.FieldBundle> {
-    ctor @Deprecated public FieldBundle(String fieldPath, String columnName, String affinity, boolean nonNull);
-    ctor public FieldBundle(@com.google.gson.annotations.SerializedName("fieldPath") String fieldPath, @com.google.gson.annotations.SerializedName("columnName") String columnName, @com.google.gson.annotations.SerializedName("affinity") String affinity, @com.google.gson.annotations.SerializedName("notNull") boolean isNonNull, @com.google.gson.annotations.SerializedName("defaultValue") String? defaultValue);
-    method public String getAffinity();
-    method public String getColumnName();
-    method public String? getDefaultValue();
-    method public String getFieldPath();
-    method public boolean isNonNull();
-    method public boolean isSchemaEqual(androidx.room.migration.bundle.FieldBundle other);
-    property public String affinity;
-    property public String columnName;
-    property public String? defaultValue;
-    property public String fieldPath;
-    property public boolean isNonNull;
-  }
-
-  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class ForeignKeyBundle implements androidx.room.migration.bundle.SchemaEquality<androidx.room.migration.bundle.ForeignKeyBundle> {
-    ctor public ForeignKeyBundle(String table, String onDelete, String onUpdate, java.util.List<java.lang.String> columns, java.util.List<java.lang.String> referencedColumns);
-    method public java.util.List<java.lang.String> getColumns();
-    method public String getOnDelete();
-    method public String getOnUpdate();
-    method public java.util.List<java.lang.String> getReferencedColumns();
-    method public String getTable();
-    method public boolean isSchemaEqual(androidx.room.migration.bundle.ForeignKeyBundle other);
-    property public java.util.List<java.lang.String> columns;
-    property public String onDelete;
-    property public String onUpdate;
-    property public java.util.List<java.lang.String> referencedColumns;
-    property public String table;
-  }
-
-  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class FtsEntityBundle extends androidx.room.migration.bundle.EntityBundle {
-    ctor public FtsEntityBundle(String tableName, String createSql, java.util.List<? extends androidx.room.migration.bundle.FieldBundle> fields, androidx.room.migration.bundle.PrimaryKeyBundle primaryKey, String ftsVersion, androidx.room.migration.bundle.FtsOptionsBundle ftsOptions, @com.google.gson.annotations.SerializedName("contentSyncTriggers") java.util.List<java.lang.String> contentSyncSqlTriggers);
-    method public java.util.List<java.lang.String> getContentSyncSqlTriggers();
-    method public androidx.room.migration.bundle.FtsOptionsBundle getFtsOptions();
-    method public String getFtsVersion();
-    method public java.util.List<java.lang.String> getShadowTableNames();
-    property public java.util.List<java.lang.String> contentSyncSqlTriggers;
-    property public androidx.room.migration.bundle.FtsOptionsBundle ftsOptions;
-    property public String ftsVersion;
-    property public java.util.List<java.lang.String> shadowTableNames;
-  }
-
-  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class FtsOptionsBundle implements androidx.room.migration.bundle.SchemaEquality<androidx.room.migration.bundle.FtsOptionsBundle> {
-    ctor public FtsOptionsBundle(@com.google.gson.annotations.SerializedName("tokenizer") String tokenizer, @com.google.gson.annotations.SerializedName("tokenizerArgs") java.util.List<java.lang.String> tokenizerArgs, @com.google.gson.annotations.SerializedName("contentTable") String contentTable, @com.google.gson.annotations.SerializedName("languageIdColumnName") String languageIdColumnName, @com.google.gson.annotations.SerializedName("matchInfo") String matchInfo, @com.google.gson.annotations.SerializedName("notIndexedColumns") java.util.List<java.lang.String> notIndexedColumns, @com.google.gson.annotations.SerializedName("prefixSizes") java.util.List<java.lang.Integer> prefixSizes, @com.google.gson.annotations.SerializedName("preferredOrder") String preferredOrder);
-    method public String getContentTable();
-    method public String getLanguageIdColumnName();
-    method public String getMatchInfo();
-    method public java.util.List<java.lang.String> getNotIndexedColumns();
-    method public String getPreferredOrder();
-    method public java.util.List<java.lang.Integer> getPrefixSizes();
-    method public java.util.List<java.lang.String> getTokenizerArgs();
-    method public boolean isSchemaEqual(androidx.room.migration.bundle.FtsOptionsBundle other);
-    property public String contentTable;
-    property public String languageIdColumnName;
-    property public String matchInfo;
-    property public java.util.List<java.lang.String> notIndexedColumns;
-    property public String preferredOrder;
-    property public java.util.List<java.lang.Integer> prefixSizes;
-    property public java.util.List<java.lang.String> tokenizerArgs;
-  }
-
-  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class IndexBundle implements androidx.room.migration.bundle.SchemaEquality<androidx.room.migration.bundle.IndexBundle> {
-    ctor @Deprecated public IndexBundle(String name, boolean unique, java.util.List<java.lang.String> columnNames, String createSql);
-    ctor public IndexBundle(@com.google.gson.annotations.SerializedName("name") String name, @com.google.gson.annotations.SerializedName("unique") boolean isUnique, @com.google.gson.annotations.SerializedName("columnNames") java.util.List<java.lang.String>? columnNames, @com.google.gson.annotations.SerializedName("orders") java.util.List<java.lang.String>? orders, @com.google.gson.annotations.SerializedName("createSql") String createSql);
-    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public String create(String tableName);
-    method public java.util.List<java.lang.String>? getColumnNames();
-    method public String getCreateSql();
-    method public String getCreateSql(String tableName);
-    method public String getName();
-    method public java.util.List<java.lang.String>? getOrders();
-    method public boolean isSchemaEqual(androidx.room.migration.bundle.IndexBundle other);
-    method public boolean isUnique();
-    property public java.util.List<java.lang.String>? columnNames;
-    property public String createSql;
-    property public boolean isUnique;
-    property public String name;
-    property public java.util.List<java.lang.String>? orders;
-    field public static final androidx.room.migration.bundle.IndexBundle.Companion Companion;
-    field public static final String DEFAULT_PREFIX = "index_";
-  }
-
-  public static final class IndexBundle.Companion {
-  }
-
-  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class PrimaryKeyBundle implements androidx.room.migration.bundle.SchemaEquality<androidx.room.migration.bundle.PrimaryKeyBundle> {
-    ctor public PrimaryKeyBundle(@com.google.gson.annotations.SerializedName("autoGenerate") boolean isAutoGenerate, @com.google.gson.annotations.SerializedName("columnNames") java.util.List<java.lang.String> columnNames);
-    method public java.util.List<java.lang.String> getColumnNames();
-    method public boolean isAutoGenerate();
-    method public boolean isSchemaEqual(androidx.room.migration.bundle.PrimaryKeyBundle other);
-    property public java.util.List<java.lang.String> columnNames;
-    property public boolean isAutoGenerate;
-  }
-
-  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class SchemaBundle implements androidx.room.migration.bundle.SchemaEquality<androidx.room.migration.bundle.SchemaBundle> {
-    ctor public SchemaBundle(@com.google.gson.annotations.SerializedName("formatVersion") int formatVersion, @com.google.gson.annotations.SerializedName("database") androidx.room.migration.bundle.DatabaseBundle database);
-    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @kotlin.jvm.Throws(exceptionClasses=UnsupportedEncodingException::class) public static final androidx.room.migration.bundle.SchemaBundle deserialize(java.io.InputStream fis) throws java.io.UnsupportedEncodingException;
-    method public androidx.room.migration.bundle.DatabaseBundle getDatabase();
-    method public int getFormatVersion();
-    method public boolean isSchemaEqual(androidx.room.migration.bundle.SchemaBundle other);
-    method @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @kotlin.jvm.Throws(exceptionClasses=IOException::class) public static final void serialize(androidx.room.migration.bundle.SchemaBundle bundle, java.io.File file) throws java.io.IOException;
-    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @kotlin.jvm.Throws(exceptionClasses=IOException::class) public static final void serialize(androidx.room.migration.bundle.SchemaBundle bundle, java.io.OutputStream outputStream) throws java.io.IOException;
-    property public androidx.room.migration.bundle.DatabaseBundle database;
-    property public int formatVersion;
-    field public static final androidx.room.migration.bundle.SchemaBundle.Companion Companion;
-    field public static final int LATEST_FORMAT = 1; // 0x1
-  }
-
-  public static final class SchemaBundle.Companion {
-    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @kotlin.jvm.Throws(exceptionClasses=UnsupportedEncodingException::class) public androidx.room.migration.bundle.SchemaBundle deserialize(java.io.InputStream fis) throws java.io.UnsupportedEncodingException;
-    method @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @kotlin.jvm.Throws(exceptionClasses=IOException::class) public void serialize(androidx.room.migration.bundle.SchemaBundle bundle, java.io.File file) throws java.io.IOException;
-    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @kotlin.jvm.Throws(exceptionClasses=IOException::class) public void serialize(androidx.room.migration.bundle.SchemaBundle bundle, java.io.OutputStream outputStream) throws java.io.IOException;
-  }
-
-  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static final class SchemaBundle.EmptySchemaException extends java.lang.IllegalStateException {
-    ctor public SchemaBundle.EmptySchemaException();
-  }
-
-  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public interface SchemaEquality<T> {
-    method public boolean isSchemaEqual(T other);
-  }
-
-}
-
diff --git a/room/room-migration/build.gradle b/room/room-migration/build.gradle
index 0e7974f..c51ca24 100644
--- a/room/room-migration/build.gradle
+++ b/room/room-migration/build.gradle
@@ -24,9 +24,11 @@
 
 import androidx.build.PlatformIdentifier
 import androidx.build.Publish
+import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
 
 plugins {
     id("AndroidXPlugin")
+    alias(libs.plugins.kotlinSerialization)
 }
 
 androidXMultiplatform {
@@ -44,6 +46,7 @@
             dependencies {
                 api(libs.kotlinStdlib)
                 implementation(project(":room:room-common"))
+                implementation(libs.kotlinSerializationJson)
             }
         }
         commonTest {
@@ -54,17 +57,21 @@
         }
         jvmMain {
             dependsOn(commonMain)
-            dependencies {
-                implementation(libs.gson)
-            }
         }
         jvmTest {
             dependsOn(commonTest)
             dependencies {
-                implementation(libs.guava)
                 implementation(libs.kotlinTestJunit)
-                implementation(libs.intellijAnnotations)
-                implementation(libs.mockitoCore4)
+            }
+        }
+        nativeMain {
+            dependsOn(commonMain)
+        }
+        targets.all { target ->
+            if (target.platformType == KotlinPlatformType.native) {
+                target.compilations["main"].defaultSourceSet {
+                    dependsOn(nativeMain)
+                }
             }
         }
     }
@@ -75,5 +82,6 @@
     publish = Publish.SNAPSHOT_AND_RELEASE
     inceptionYear = "2017"
     description = "Android Room Migration"
+    legacyDisableKotlinStrictApiMode = true
     metalavaK2UastEnabled = true
 }
diff --git a/room/room-migration/src/commonMain/kotlin/androidx/room/migration/bundle/BaseEntityBundle.kt b/room/room-migration/src/commonMain/kotlin/androidx/room/migration/bundle/BaseEntityBundle.kt
new file mode 100644
index 0000000..2e95f76
--- /dev/null
+++ b/room/room-migration/src/commonMain/kotlin/androidx/room/migration/bundle/BaseEntityBundle.kt
@@ -0,0 +1,80 @@
+/*
+ * 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.migration.bundle
+
+import androidx.annotation.RestrictTo
+import kotlinx.serialization.SerialName
+import kotlinx.serialization.Serializable
+
+/**
+ * Base class that holds common schema information about an entity.
+ */
+@Serializable
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+sealed class BaseEntityBundle {
+    @SerialName("tableName")
+    abstract val tableName: String
+    @SerialName("createSql")
+    abstract val createSql: String
+    @SerialName("fields")
+    abstract val fields: List<FieldBundle>
+    @SerialName("primaryKey")
+    abstract val primaryKey: PrimaryKeyBundle
+    @SerialName("indices")
+    abstract val indices: List<IndexBundle>
+    @SerialName("foreignKeys")
+    abstract val foreignKeys: List<ForeignKeyBundle>
+
+    companion object {
+        const val NEW_TABLE_PREFIX: String = "_new_"
+    }
+
+    val newTableName: String
+        get() {
+            return NEW_TABLE_PREFIX + tableName
+        }
+
+    val fieldsByColumnName: Map<String, FieldBundle> by lazy {
+        fields.associateBy { it.columnName }
+    }
+
+    /**
+     * CREATE TABLE SQL query that uses the actual table name.
+     */
+    fun createTable(): String {
+        return replaceTableName(createSql, tableName)
+    }
+
+    /**
+     * CREATE TABLE SQL query that uses the table name with "new" prefix.
+     */
+    fun createNewTable(): String {
+        return replaceTableName(createSql, newTableName)
+    }
+
+    /**
+     * Renames the table with [newTableName] to [tableName].
+     */
+    fun renameToOriginal(): String {
+        return "ALTER TABLE $newTableName RENAME TO $tableName"
+    }
+
+    /**
+     * Creates the list of SQL queries that are necessary to create this entity.
+     */
+    abstract fun buildCreateQueries(): List<String>
+}
diff --git a/room/room-migration/src/jvmMain/kotlin/androidx/room/migration/bundle/BundleUtil.jvm.kt b/room/room-migration/src/commonMain/kotlin/androidx/room/migration/bundle/BundleUtil.kt
similarity index 73%
rename from room/room-migration/src/jvmMain/kotlin/androidx/room/migration/bundle/BundleUtil.jvm.kt
rename to room/room-migration/src/commonMain/kotlin/androidx/room/migration/bundle/BundleUtil.kt
index 35aeb14..caaaf5d 100644
--- a/room/room-migration/src/jvmMain/kotlin/androidx/room/migration/bundle/BundleUtil.jvm.kt
+++ b/room/room-migration/src/commonMain/kotlin/androidx/room/migration/bundle/BundleUtil.kt
@@ -14,26 +14,27 @@
  * limitations under the License.
  */
 @file:JvmName("BundleUtil")
-@file:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@file:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
 
 package androidx.room.migration.bundle
 
 import androidx.annotation.RestrictTo
+import kotlin.jvm.JvmName
 
 /**
  * Placeholder for table names in queries.
  */
-public const val TABLE_NAME_PLACEHOLDER: String = "\${TABLE_NAME}"
+const val TABLE_NAME_PLACEHOLDER: String = "\${TABLE_NAME}"
 
 /**
  * Placeholder for view names in queries.
  */
-public const val VIEW_NAME_PLACEHOLDER: String = "\${VIEW_NAME}"
+const val VIEW_NAME_PLACEHOLDER: String = "\${VIEW_NAME}"
 
-public fun replaceTableName(contents: String, tableName: String): String {
+fun replaceTableName(contents: String, tableName: String): String {
     return contents.replace(TABLE_NAME_PLACEHOLDER, tableName)
 }
 
-public fun replaceViewName(contents: String, viewName: String): String {
+fun replaceViewName(contents: String, viewName: String): String {
     return contents.replace(VIEW_NAME_PLACEHOLDER, viewName)
 }
diff --git a/room/room-migration/src/commonMain/kotlin/androidx/room/migration/bundle/DatabaseBundle.kt b/room/room-migration/src/commonMain/kotlin/androidx/room/migration/bundle/DatabaseBundle.kt
new file mode 100644
index 0000000..13d27a20
--- /dev/null
+++ b/room/room-migration/src/commonMain/kotlin/androidx/room/migration/bundle/DatabaseBundle.kt
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2017 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.migration.bundle
+
+import androidx.annotation.RestrictTo
+import androidx.room.migration.bundle.SchemaEqualityUtil.checkSchemaEquality
+import androidx.room.migration.bundle.SchemaEqualityUtil.filterValuesInstance
+import kotlinx.serialization.SerialName
+import kotlinx.serialization.Serializable
+
+/**
+ * Data class that holds the schema information for a [androidx.room.Database].
+ */
+@Serializable
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+class DatabaseBundle(
+    @SerialName("version")
+    val version: Int,
+    @SerialName("identityHash")
+    val identityHash: String,
+    @SerialName("entities")
+    val entities: List<BaseEntityBundle>,
+    @SerialName("views")
+    val views: List<DatabaseViewBundle> = emptyList(),
+    @SerialName("setupQueries")
+    private val setupQueries: List<String>,
+) : SchemaEquality<DatabaseBundle> {
+
+    val entitiesByTableName: Map<String, BaseEntityBundle> by lazy {
+        entities.associateBy { it.tableName }
+    }
+
+    val viewsByName: Map<String, DatabaseViewBundle> by lazy {
+        views.associateBy { it.viewName }
+    }
+
+    /**
+     * Builds the list of SQL queries to build this database from scratch.
+     */
+    fun buildCreateQueries(): List<String> {
+        return buildList {
+            entities.sortedWith(FtsEntityCreateComparator()).forEach { entityBundle ->
+                addAll(entityBundle.buildCreateQueries())
+            }
+            views.forEach { viewBundle ->
+                add(viewBundle.createView())
+            }
+            addAll(setupQueries)
+        }
+    }
+
+    override fun isSchemaEqual(other: DatabaseBundle): Boolean {
+        return checkSchemaEquality(
+            entitiesByTableName.filterValuesInstance<String, EntityBundle>(),
+            other.entitiesByTableName.filterValuesInstance<String, EntityBundle>()
+        ) && checkSchemaEquality(
+            entitiesByTableName.filterValuesInstance<String, FtsEntityBundle>(),
+            other.entitiesByTableName.filterValuesInstance<String, FtsEntityBundle>()
+        ) && checkSchemaEquality(viewsByName, other.viewsByName)
+    }
+
+    // Comparator to sort FTS entities after their declared external content entity so that the
+    // content entity table gets created first.
+    private class FtsEntityCreateComparator : Comparator<BaseEntityBundle> {
+        override fun compare(a: BaseEntityBundle, b: BaseEntityBundle): Int {
+            if (a is FtsEntityBundle) {
+                val contentTable = a.ftsOptions.contentTable
+                if (contentTable == b.tableName) {
+                    return 1
+                }
+            } else if (b is FtsEntityBundle) {
+                val contentTable = b.ftsOptions.contentTable
+                if (contentTable == a.tableName) {
+                    return -1
+                }
+            }
+            return 0
+        }
+    }
+}
diff --git a/room/room-migration/src/jvmMain/kotlin/androidx/room/migration/bundle/DatabaseViewBundle.jvm.kt b/room/room-migration/src/commonMain/kotlin/androidx/room/migration/bundle/DatabaseViewBundle.kt
similarity index 65%
rename from room/room-migration/src/jvmMain/kotlin/androidx/room/migration/bundle/DatabaseViewBundle.jvm.kt
rename to room/room-migration/src/commonMain/kotlin/androidx/room/migration/bundle/DatabaseViewBundle.kt
index dad3cce..0f2344a 100644
--- a/room/room-migration/src/jvmMain/kotlin/androidx/room/migration/bundle/DatabaseViewBundle.jvm.kt
+++ b/room/room-migration/src/commonMain/kotlin/androidx/room/migration/bundle/DatabaseViewBundle.kt
@@ -17,28 +17,25 @@
 package androidx.room.migration.bundle
 
 import androidx.annotation.RestrictTo
-import com.google.gson.annotations.SerializedName
+import kotlinx.serialization.SerialName
+import kotlinx.serialization.Serializable
 
 /**
  * Data class that holds the schema information about a [androidx.room.DatabaseView].
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
-public open class DatabaseViewBundle(
-    @SerializedName("viewName")
-    public open val viewName: String,
-    @SerializedName("createSql")
-    public open val createSql: String
+@Serializable
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+class DatabaseViewBundle(
+    @SerialName("viewName")
+    val viewName: String,
+    @SerialName("createSql")
+    val createSql: String
 ) : SchemaEquality<DatabaseViewBundle> {
 
-    // Used by GSON
-    @Deprecated("Marked deprecated to avoid usage in the codebase")
-    @SuppressWarnings("unused")
-    private constructor() : this("", "")
-
     /**
-     * @return Create view SQL query that uses the actual view name.
+     * CREATE VIEW SQL query that uses the actual view name.
      */
-    public open fun createView(): String {
+    fun createView(): String {
         return replaceViewName(createSql, viewName)
     }
 
diff --git a/room/room-migration/src/commonMain/kotlin/androidx/room/migration/bundle/EntityBundle.kt b/room/room-migration/src/commonMain/kotlin/androidx/room/migration/bundle/EntityBundle.kt
new file mode 100644
index 0000000..63921bc
--- /dev/null
+++ b/room/room-migration/src/commonMain/kotlin/androidx/room/migration/bundle/EntityBundle.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2017 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.migration.bundle
+
+import androidx.annotation.RestrictTo
+import androidx.room.migration.bundle.SchemaEqualityUtil.checkSchemaEquality
+import kotlinx.serialization.SerialName
+import kotlinx.serialization.Serializable
+
+/**
+ * Data class that holds the schema information about an [androidx.room.Entity].
+ *
+ */
+@Serializable
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+open class EntityBundle(
+    @SerialName("tableName")
+    override val tableName: String,
+    @SerialName("createSql")
+    override val createSql: String,
+    @SerialName("fields")
+    override val fields: List<FieldBundle>,
+    @SerialName("primaryKey")
+    override val primaryKey: PrimaryKeyBundle,
+    @SerialName("indices")
+    override val indices: List<IndexBundle> = emptyList(),
+    @SerialName("foreignKeys")
+    override val foreignKeys: List<ForeignKeyBundle> = emptyList()
+) : BaseEntityBundle(), SchemaEquality<EntityBundle> {
+
+    /**
+     * Creates the list of SQL queries that are necessary to create this entity.
+     */
+    override fun buildCreateQueries(): List<String> {
+        return buildList {
+            add(createTable())
+            this@EntityBundle.indices.forEach { indexBundle ->
+                add(indexBundle.create(tableName))
+            }
+        }
+    }
+
+    override fun isSchemaEqual(other: EntityBundle): Boolean {
+        if (tableName != other.tableName) {
+            return false
+        }
+        return checkSchemaEquality(fieldsByColumnName, other.fieldsByColumnName) &&
+            checkSchemaEquality(primaryKey, other.primaryKey) &&
+            checkSchemaEquality(indices, other.indices) &&
+            checkSchemaEquality(foreignKeys, other.foreignKeys)
+    }
+}
diff --git a/room/room-migration/src/commonMain/kotlin/androidx/room/migration/bundle/FieldBundle.kt b/room/room-migration/src/commonMain/kotlin/androidx/room/migration/bundle/FieldBundle.kt
new file mode 100644
index 0000000..a902d66
--- /dev/null
+++ b/room/room-migration/src/commonMain/kotlin/androidx/room/migration/bundle/FieldBundle.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2017 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.migration.bundle
+
+import androidx.annotation.RestrictTo
+import kotlinx.serialization.SerialName
+import kotlinx.serialization.Serializable
+
+/**
+ * Data class that holds the schema information for an [androidx.room.Entity] field.
+ */
+@Serializable
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+class FieldBundle(
+    @SerialName("fieldPath")
+    val fieldPath: String,
+    @SerialName("columnName")
+    val columnName: String,
+    @SerialName("affinity")
+    val affinity: String,
+    @SerialName("notNull")
+    val isNonNull: Boolean,
+    @SerialName("defaultValue")
+    val defaultValue: String? = null,
+) : SchemaEquality<FieldBundle> {
+
+    override fun isSchemaEqual(other: FieldBundle): Boolean {
+        if (isNonNull != other.isNonNull) return false
+        if (columnName != other.columnName) {
+            return false
+        }
+        if (defaultValue?.let { it != other.defaultValue } ?: (other.defaultValue != null)) {
+            return false
+        }
+        return affinity == other.affinity
+    }
+}
diff --git a/room/room-migration/src/commonMain/kotlin/androidx/room/migration/bundle/ForeignKeyBundle.kt b/room/room-migration/src/commonMain/kotlin/androidx/room/migration/bundle/ForeignKeyBundle.kt
new file mode 100644
index 0000000..745c855
--- /dev/null
+++ b/room/room-migration/src/commonMain/kotlin/androidx/room/migration/bundle/ForeignKeyBundle.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2017 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.migration.bundle
+
+import androidx.annotation.RestrictTo
+import kotlinx.serialization.SerialName
+import kotlinx.serialization.Serializable
+
+/**
+ * Data class that holds the information about a foreign key reference, i.e.
+ * [androidx.room.ForeignKey].
+ */
+@Serializable
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+class ForeignKeyBundle(
+    @SerialName("table")
+    val table: String,
+    @SerialName("onDelete")
+    val onDelete: String,
+    @SerialName("onUpdate")
+    val onUpdate: String,
+    @SerialName("columns")
+    val columns: List<String>,
+    @SerialName("referencedColumns")
+    val referencedColumns: List<String>
+) : SchemaEquality<ForeignKeyBundle> {
+
+    override fun isSchemaEqual(other: ForeignKeyBundle): Boolean {
+        if (table != other.table) return false
+        if (onDelete != other.onDelete) return false
+        if (onUpdate != other.onUpdate) return false
+        // order matters
+        return (columns == other.columns && referencedColumns == other.referencedColumns)
+    }
+}
diff --git a/room/room-migration/src/commonMain/kotlin/androidx/room/migration/bundle/FtsEntityBundle.kt b/room/room-migration/src/commonMain/kotlin/androidx/room/migration/bundle/FtsEntityBundle.kt
new file mode 100644
index 0000000..e8a03ea
--- /dev/null
+++ b/room/room-migration/src/commonMain/kotlin/androidx/room/migration/bundle/FtsEntityBundle.kt
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2018 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.migration.bundle
+
+import androidx.annotation.RestrictTo
+import androidx.room.migration.bundle.SchemaEqualityUtil.checkSchemaEquality
+import kotlinx.serialization.SerialName
+import kotlinx.serialization.Serializable
+
+/**
+ * Data class that holds the schema information about an [androidx.room.Fts3] or
+ * [androidx.room.Fts4] entity.
+ */
+@Serializable
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+class FtsEntityBundle(
+    @SerialName("tableName")
+    override val tableName: String,
+    @SerialName("createSql")
+    override val createSql: String,
+    @SerialName("fields")
+    override val fields: List<FieldBundle>,
+    @SerialName("primaryKey")
+    override val primaryKey: PrimaryKeyBundle,
+    @SerialName("indices")
+    override val indices: List<IndexBundle> = emptyList(),
+    @SerialName("foreignKeys")
+    override val foreignKeys: List<ForeignKeyBundle> = emptyList(),
+    @SerialName("ftsVersion")
+    val ftsVersion: String,
+    @SerialName("ftsOptions")
+    val ftsOptions: FtsOptionsBundle,
+    @SerialName("contentSyncTriggers")
+    val contentSyncSqlTriggers: List<String>
+) : BaseEntityBundle(), SchemaEquality<FtsEntityBundle> {
+
+    /**
+     * Creates the list of SQL queries that are necessary to create this entity.
+     */
+    override fun buildCreateQueries(): List<String> {
+        return buildList {
+            add(createTable())
+            addAll(contentSyncSqlTriggers)
+        }
+    }
+
+    override fun isSchemaEqual(other: FtsEntityBundle): Boolean {
+        if (tableName != other.tableName) {
+            return false
+        }
+        return checkSchemaEquality(fieldsByColumnName, other.fieldsByColumnName) &&
+            checkSchemaEquality(primaryKey, other.primaryKey) &&
+            checkSchemaEquality(indices, other.indices) &&
+            checkSchemaEquality(foreignKeys, other.foreignKeys) &&
+            ftsVersion == other.ftsVersion &&
+            checkSchemaEquality(ftsOptions, other.ftsOptions)
+    }
+
+    /**
+     * Gets the list of shadow table names corresponding to the FTS virtual table.
+     */
+    val shadowTableNames: List<String> by lazy {
+        val currentTable = this@FtsEntityBundle.tableName
+        buildList {
+            SHADOW_TABLE_NAME_SUFFIXES.forEach { suffix ->
+                add(currentTable + suffix)
+            }
+        }
+    }
+
+    companion object {
+        private val SHADOW_TABLE_NAME_SUFFIXES =
+            listOf(
+                "_content",
+                "_segdir",
+                "_segments",
+                "_stat",
+                "_docsize"
+            )
+    }
+}
diff --git a/room/room-migration/src/commonMain/kotlin/androidx/room/migration/bundle/FtsOptionsBundle.kt b/room/room-migration/src/commonMain/kotlin/androidx/room/migration/bundle/FtsOptionsBundle.kt
new file mode 100644
index 0000000..32a68f8
--- /dev/null
+++ b/room/room-migration/src/commonMain/kotlin/androidx/room/migration/bundle/FtsOptionsBundle.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2018 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.migration.bundle
+
+import androidx.annotation.RestrictTo
+import kotlinx.serialization.SerialName
+import kotlinx.serialization.Serializable
+
+/**
+ * Data class that holds [androidx.room.FtsOptions] information.
+ */
+@Serializable
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+class FtsOptionsBundle(
+    @SerialName("tokenizer")
+    private val tokenizer: String,
+    @SerialName("tokenizerArgs")
+    val tokenizerArgs: List<String>,
+    @SerialName("contentTable")
+    val contentTable: String,
+    @SerialName("languageIdColumnName")
+    val languageIdColumnName: String,
+    @SerialName("matchInfo")
+    val matchInfo: String,
+    @SerialName("notIndexedColumns")
+    val notIndexedColumns: List<String>,
+    @SerialName("prefixSizes")
+    val prefixSizes: List<Int>,
+    @SerialName("preferredOrder")
+    val preferredOrder: String
+) : SchemaEquality<FtsOptionsBundle> {
+
+    override fun isSchemaEqual(other: FtsOptionsBundle): Boolean {
+        return tokenizer == other.tokenizer &&
+            tokenizerArgs == other.tokenizerArgs &&
+            contentTable == other.contentTable &&
+            languageIdColumnName == other.languageIdColumnName &&
+            matchInfo == other.matchInfo &&
+            notIndexedColumns == other.notIndexedColumns &&
+            prefixSizes == other.prefixSizes &&
+            preferredOrder == other.preferredOrder
+    }
+}
diff --git a/room/room-migration/src/commonMain/kotlin/androidx/room/migration/bundle/IndexBundle.kt b/room/room-migration/src/commonMain/kotlin/androidx/room/migration/bundle/IndexBundle.kt
new file mode 100644
index 0000000..8b1f75e
--- /dev/null
+++ b/room/room-migration/src/commonMain/kotlin/androidx/room/migration/bundle/IndexBundle.kt
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2017 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.migration.bundle
+
+import androidx.annotation.RestrictTo
+import androidx.room.Index
+import kotlinx.serialization.SerialName
+import kotlinx.serialization.Serializable
+
+/**
+ * Data class that holds the schema information about a table [androidx.room.Index]
+ */
+@Serializable
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+class IndexBundle(
+    @SerialName("name")
+    val name: String,
+    @SerialName("unique")
+    val isUnique: Boolean,
+    @SerialName("columnNames")
+    val columnNames: List<String>? = null,
+    @SerialName("orders")
+    val orders: List<String>? = null,
+    @SerialName("createSql")
+    val createSql: String
+
+) : SchemaEquality<IndexBundle> {
+    companion object {
+        // should match Index.kt
+        const val DEFAULT_PREFIX: String = "index_"
+    }
+
+    fun create(tableName: String): String {
+        return replaceTableName(createSql, tableName)
+    }
+
+    /**
+     * Gets the CREATE INDEX SQL query that uses the given table name.
+     */
+    fun getCreateSql(tableName: String): String {
+        return replaceTableName(createSql, tableName)
+    }
+
+    override fun isSchemaEqual(other: IndexBundle): Boolean {
+        if (isUnique != other.isUnique) return false
+        if (name.startsWith(DEFAULT_PREFIX)) {
+            if (!other.name.startsWith(DEFAULT_PREFIX)) {
+                return false
+            }
+        } else if (other.name.startsWith(DEFAULT_PREFIX)) {
+            return false
+        } else if (name != other.name) {
+            return false
+        }
+
+        // order matters
+        if (columnNames?.let { columnNames != other.columnNames } ?: (other.columnNames != null)) {
+            return false
+        }
+
+        // order matters and null orders is considered equal to all ASC orders, to be backward
+        // compatible with schemas where orders are not present in the schema file
+        val columnsSize = columnNames?.size ?: 0
+        val orders = if (orders.isNullOrEmpty()) {
+            List(columnsSize) { Index.Order.ASC.name }
+        } else {
+            orders
+        }
+        val otherOrders =
+            if (other.orders.isNullOrEmpty()) {
+                List(columnsSize) { Index.Order.ASC.name }
+            } else {
+                other.orders
+            }
+
+        if (orders != otherOrders) return false
+        return true
+    }
+}
diff --git a/room/room-migration/src/commonMain/kotlin/androidx/room/migration/bundle/Placeholder.kt b/room/room-migration/src/commonMain/kotlin/androidx/room/migration/bundle/Placeholder.kt
deleted file mode 100644
index cc75983..0000000
--- a/room/room-migration/src/commonMain/kotlin/androidx/room/migration/bundle/Placeholder.kt
+++ /dev/null
@@ -1,19 +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.room.migration.bundle
-// empty file to trigger klib creation
-// see: https://youtrack.jetbrains.com/issue/KT-52344
diff --git a/room/room-migration/src/jvmMain/kotlin/androidx/room/migration/bundle/PrimaryKeyBundle.jvm.kt b/room/room-migration/src/commonMain/kotlin/androidx/room/migration/bundle/PrimaryKeyBundle.kt
similarity index 67%
rename from room/room-migration/src/jvmMain/kotlin/androidx/room/migration/bundle/PrimaryKeyBundle.jvm.kt
rename to room/room-migration/src/commonMain/kotlin/androidx/room/migration/bundle/PrimaryKeyBundle.kt
index 8902985..5f7ae0e 100644
--- a/room/room-migration/src/jvmMain/kotlin/androidx/room/migration/bundle/PrimaryKeyBundle.jvm.kt
+++ b/room/room-migration/src/commonMain/kotlin/androidx/room/migration/bundle/PrimaryKeyBundle.kt
@@ -17,22 +17,20 @@
 package androidx.room.migration.bundle
 
 import androidx.annotation.RestrictTo
-import com.google.gson.annotations.SerializedName
+import kotlinx.serialization.SerialName
+import kotlinx.serialization.Serializable
 
 /**
  * Data class that holds the schema information about a [androidx.room.PrimaryKey].
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
-public open class PrimaryKeyBundle(
-    @SerializedName("autoGenerate")
-    public open val isAutoGenerate: Boolean,
-    @SerializedName("columnNames")
-    public open val columnNames: List<String>
+@Serializable
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+class PrimaryKeyBundle(
+    @SerialName("autoGenerate")
+    val isAutoGenerate: Boolean,
+    @SerialName("columnNames")
+    val columnNames: List<String>
 ) : SchemaEquality<PrimaryKeyBundle> {
-    // Used by GSON
-    @Deprecated("Marked deprecated to avoid usage in the codebase")
-    @SuppressWarnings("unused")
-    private constructor() : this(false, emptyList())
 
     override fun isSchemaEqual(other: PrimaryKeyBundle): Boolean {
         return columnNames == other.columnNames && isAutoGenerate == other.isAutoGenerate
diff --git a/room/room-migration/src/commonMain/kotlin/androidx/room/migration/bundle/SchemaBundle.kt b/room/room-migration/src/commonMain/kotlin/androidx/room/migration/bundle/SchemaBundle.kt
new file mode 100644
index 0000000..050eaa2
--- /dev/null
+++ b/room/room-migration/src/commonMain/kotlin/androidx/room/migration/bundle/SchemaBundle.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.
+ */
+
+@file:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+
+package androidx.room.migration.bundle
+
+import androidx.annotation.RestrictTo
+import kotlinx.serialization.DeserializationStrategy
+import kotlinx.serialization.json.ClassDiscriminatorMode
+import kotlinx.serialization.json.Json
+import kotlinx.serialization.json.JsonContentPolymorphicSerializer
+import kotlinx.serialization.json.JsonElement
+import kotlinx.serialization.json.jsonObject
+import kotlinx.serialization.modules.SerializersModule
+
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+expect class SchemaBundle(
+    formatVersion: Int,
+    database: DatabaseBundle
+) : SchemaEquality<SchemaBundle> {
+
+    val formatVersion: Int
+    val database: DatabaseBundle
+
+    override fun isSchemaEqual(other: SchemaBundle): Boolean
+}
+
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+const val SCHEMA_LATEST_FORMAT_VERSION = 1
+
+internal val json = Json {
+    // The schema files are meant to be human readable and are checked-in into repositories.
+    prettyPrint = true
+    // Don't output class discriminator as that would encode library class names into JSON file
+    // making implementation details harder to refactor. When reading, we use a content inspector
+    // that will perform polymorphic deserialization.
+    classDiscriminatorMode = ClassDiscriminatorMode.NONE
+    serializersModule = SerializersModule {
+        polymorphicDefaultDeserializer(BaseEntityBundle::class) { EntitySerializer }
+    }
+}
+
+private object EntitySerializer : JsonContentPolymorphicSerializer<BaseEntityBundle>(
+    baseClass = BaseEntityBundle::class
+) {
+    override fun selectDeserializer(
+        element: JsonElement
+    ): DeserializationStrategy<BaseEntityBundle> = when {
+        "ftsVersion" in element.jsonObject -> FtsEntityBundle.serializer()
+        else -> EntityBundle.serializer()
+    }
+}
diff --git a/room/room-migration/src/jvmMain/kotlin/androidx/room/migration/bundle/SchemaEquality.jvm.kt b/room/room-migration/src/commonMain/kotlin/androidx/room/migration/bundle/SchemaEquality.kt
similarity index 85%
rename from room/room-migration/src/jvmMain/kotlin/androidx/room/migration/bundle/SchemaEquality.jvm.kt
rename to room/room-migration/src/commonMain/kotlin/androidx/room/migration/bundle/SchemaEquality.kt
index 702dca7..2901924 100644
--- a/room/room-migration/src/jvmMain/kotlin/androidx/room/migration/bundle/SchemaEquality.jvm.kt
+++ b/room/room-migration/src/commonMain/kotlin/androidx/room/migration/bundle/SchemaEquality.kt
@@ -21,9 +21,8 @@
 /**
  * A loose equals check which checks schema equality instead of 100% equality (e.g. order of
  * columns in an entity does not have to match)
- *
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
-public interface SchemaEquality<T> {
-    public fun isSchemaEqual(other: T): Boolean
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+interface SchemaEquality<T> {
+    fun isSchemaEqual(other: T): Boolean
 }
diff --git a/room/room-migration/src/jvmMain/kotlin/androidx/room/migration/bundle/SchemaEqualityUtil.jvm.kt b/room/room-migration/src/commonMain/kotlin/androidx/room/migration/bundle/SchemaEqualityUtil.kt
similarity index 80%
rename from room/room-migration/src/jvmMain/kotlin/androidx/room/migration/bundle/SchemaEqualityUtil.jvm.kt
rename to room/room-migration/src/commonMain/kotlin/androidx/room/migration/bundle/SchemaEqualityUtil.kt
index ef98f44..28bb731 100644
--- a/room/room-migration/src/jvmMain/kotlin/androidx/room/migration/bundle/SchemaEqualityUtil.jvm.kt
+++ b/room/room-migration/src/commonMain/kotlin/androidx/room/migration/bundle/SchemaEqualityUtil.kt
@@ -16,14 +16,11 @@
 
 package androidx.room.migration.bundle
 
-import androidx.annotation.RestrictTo
-
 /**
  * Utility class to run schema equality on collections.
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY)
-public object SchemaEqualityUtil {
-    public fun <T, K : SchemaEquality<K>> checkSchemaEquality(
+internal object SchemaEqualityUtil {
+    fun <T, K : SchemaEquality<K>> checkSchemaEquality(
         map1: Map<T, K>?,
         map2: Map<T, K>?
     ): Boolean {
@@ -37,7 +34,7 @@
         }
     }
 
-    public fun <K : SchemaEquality<K>> checkSchemaEquality(
+    fun <K : SchemaEquality<K>> checkSchemaEquality(
         list1: List<K>?,
         list2: List<K>?
     ): Boolean {
@@ -53,8 +50,7 @@
         }
     }
 
-    @SuppressWarnings("SimplifiableIfStatement")
-    public fun <K : SchemaEquality<K>> checkSchemaEquality(
+    fun <K : SchemaEquality<K>> checkSchemaEquality(
         item1: K?,
         item2: K?
     ): Boolean {
@@ -64,4 +60,8 @@
             else -> item1.isSchemaEqual(item2)
         }
     }
+
+    inline fun <K, reified R> Map<K, *>.filterValuesInstance(): Map<K, R> = buildMap {
+        this@filterValuesInstance.forEach { (key, value) -> if (value is R) put(key, value) }
+    }
 }
diff --git a/room/room-migration/src/commonTest/kotlin/androidx/room/migration/bundle/DatabaseBundleTest.kt b/room/room-migration/src/commonTest/kotlin/androidx/room/migration/bundle/DatabaseBundleTest.kt
new file mode 100644
index 0000000..d869647
--- /dev/null
+++ b/room/room-migration/src/commonTest/kotlin/androidx/room/migration/bundle/DatabaseBundleTest.kt
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2018 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.migration.bundle
+
+import androidx.kruth.assertThat
+import kotlin.test.Test
+
+class DatabaseBundleTest {
+
+    @Test
+    fun buildCreateQueries_noFts() {
+        val entity1 = EntityBundle(
+            tableName = "e1", createSql = "sq1",
+            fields = listOf(createFieldBundle("foo1"), createFieldBundle("bar")),
+            primaryKey = PrimaryKeyBundle(false, listOf("foo1")),
+            indices = emptyList(),
+            foreignKeys = emptyList()
+        )
+        val entity2 = EntityBundle(
+            tableName = "e2", createSql = "sq2",
+            fields = listOf(createFieldBundle("foo2"), createFieldBundle("bar")),
+            primaryKey = PrimaryKeyBundle(false, listOf("foo2")),
+            indices = emptyList(),
+            foreignKeys = emptyList()
+        )
+        val bundle = DatabaseBundle(
+            version = 1, identityHash = "hash",
+            entities = listOf(entity1, entity2), views = emptyList(),
+            setupQueries = emptyList()
+        )
+
+        assertThat(bundle.buildCreateQueries()).containsExactly("sq1", "sq2")
+    }
+
+    @Test
+    fun buildCreateQueries_withFts() {
+        val entity1 = EntityBundle(
+            tableName = "e1", createSql = "sq1",
+            fields = listOf(createFieldBundle("foo1"), createFieldBundle("bar")),
+            primaryKey = PrimaryKeyBundle(false, listOf("foo1")),
+            indices = emptyList(),
+            foreignKeys = emptyList()
+        )
+        val entity2 = FtsEntityBundle(
+            tableName = "e2", createSql = "sq2",
+            fields = listOf(createFieldBundle("foo2"), createFieldBundle("bar")),
+            primaryKey = PrimaryKeyBundle(false, listOf("foo2")),
+            ftsVersion = "FTS4",
+            ftsOptions = createFtsOptionsBundle(""),
+            contentSyncSqlTriggers = emptyList()
+        )
+        val entity3 = EntityBundle(
+            tableName = "e3", createSql = "sq3",
+            fields = listOf(createFieldBundle("foo3"), createFieldBundle("bar")),
+            primaryKey = PrimaryKeyBundle(false, listOf("foo3")),
+            indices = emptyList(),
+            foreignKeys = emptyList()
+        )
+        val bundle = DatabaseBundle(
+            version = 1, identityHash = "hash",
+            entities = listOf(entity1, entity2, entity3), views = emptyList(),
+            setupQueries = emptyList()
+        )
+
+        assertThat(bundle.buildCreateQueries()).containsExactly("sq1", "sq2", "sq3")
+    }
+
+    @Test
+    fun buildCreateQueries_withExternalContentFts() {
+        val entity1 = EntityBundle(
+            tableName = "e1", createSql = "sq1",
+            fields = listOf(createFieldBundle("foo1"), createFieldBundle("bar")),
+            primaryKey = PrimaryKeyBundle(false, listOf("foo1")),
+            indices = emptyList(),
+            foreignKeys = emptyList()
+        )
+        val entity2 = FtsEntityBundle(
+            tableName = "e2", createSql = "sq2",
+            fields = listOf(createFieldBundle("foo2"), createFieldBundle("bar")),
+            primaryKey = PrimaryKeyBundle(false, listOf("foo2")),
+            ftsVersion = "FTS4",
+            ftsOptions = createFtsOptionsBundle("e3"),
+            contentSyncSqlTriggers = listOf("e2_trig")
+        )
+        val entity3 = EntityBundle(
+            tableName = "e3", createSql = "sq3",
+            fields = listOf(createFieldBundle("foo3"), createFieldBundle("bar")),
+            primaryKey = PrimaryKeyBundle(false, listOf("foo3")),
+            indices = emptyList(),
+            foreignKeys = emptyList()
+        )
+        val bundle = DatabaseBundle(
+            version = 1,
+            identityHash = "hash",
+            entities = listOf(entity1, entity2, entity3),
+            views = emptyList(),
+            setupQueries = emptyList()
+        )
+
+        assertThat(bundle.buildCreateQueries()).containsExactly("sq1", "sq3", "sq2", "e2_trig")
+    }
+
+    @Test
+    fun schemaEquality_missingView_notEqual() {
+        val entity = EntityBundle(
+            tableName = "e", createSql = "sq",
+            fields = listOf(createFieldBundle("foo"), createFieldBundle("bar")),
+            primaryKey = PrimaryKeyBundle(false, listOf("foo")),
+            indices = emptyList(),
+            foreignKeys = emptyList()
+        )
+        val view = DatabaseViewBundle(viewName = "bar", createSql = "sq")
+        val bundle1 = DatabaseBundle(
+            version = 1, identityHash = "hash",
+            entities = listOf(entity), views = emptyList(),
+            setupQueries = emptyList()
+        )
+        val bundle2 = DatabaseBundle(
+            version = 1, identityHash = "hash",
+            entities = listOf(entity), views = listOf(view),
+            setupQueries = emptyList()
+        )
+        assertThat(bundle1.isSchemaEqual(bundle2)).isFalse()
+    }
+
+    private fun createFieldBundle(name: String): FieldBundle {
+        return FieldBundle(
+            fieldPath = "foo",
+            columnName = name,
+            affinity = "text",
+            isNonNull = false,
+            defaultValue = null
+        )
+    }
+
+    private fun createFtsOptionsBundle(contentTableName: String): FtsOptionsBundle {
+        return FtsOptionsBundle(
+            tokenizer = "",
+            tokenizerArgs = emptyList(),
+            contentTable = contentTableName,
+            languageIdColumnName = "",
+            matchInfo = "",
+            notIndexedColumns = emptyList(),
+            prefixSizes = emptyList(),
+            preferredOrder = ""
+        )
+    }
+}
diff --git a/room/room-migration/src/jvmTest/kotlin/androidx/room/migration/bundle/DatabaseViewBundleTest.kt b/room/room-migration/src/commonTest/kotlin/androidx/room/migration/bundle/DatabaseViewBundleTest.kt
similarity index 61%
rename from room/room-migration/src/jvmTest/kotlin/androidx/room/migration/bundle/DatabaseViewBundleTest.kt
rename to room/room-migration/src/commonTest/kotlin/androidx/room/migration/bundle/DatabaseViewBundleTest.kt
index 75fb554..224e54e 100644
--- a/room/room-migration/src/jvmTest/kotlin/androidx/room/migration/bundle/DatabaseViewBundleTest.kt
+++ b/room/room-migration/src/commonTest/kotlin/androidx/room/migration/bundle/DatabaseViewBundleTest.kt
@@ -16,20 +16,16 @@
 
 package androidx.room.migration.bundle
 
-import org.hamcrest.CoreMatchers.`is`
-import org.hamcrest.MatcherAssert.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
+import androidx.kruth.assertThat
+import kotlin.test.Test
 
-@RunWith(JUnit4::class)
 class DatabaseViewBundleTest {
     @Test
     fun basic() {
-        val bundle = DatabaseViewBundle("abc", "def")
-        val other = DatabaseViewBundle("abc", "def")
-        assertThat(bundle.isSchemaEqual(other), `is`(true))
-        assertThat(bundle.viewName, `is`("abc"))
-        assertThat(bundle.createSql, `is`("def"))
+        val bundle = DatabaseViewBundle(viewName = "abc", createSql = "def")
+        val other = DatabaseViewBundle(viewName = "abc", createSql = "def")
+        assertThat(bundle.isSchemaEqual(other)).isTrue()
+        assertThat(bundle.viewName).isEqualTo("abc")
+        assertThat(bundle.createSql).isEqualTo("def")
     }
 }
diff --git a/room/room-migration/src/commonTest/kotlin/androidx/room/migration/bundle/EntityBundleTest.kt b/room/room-migration/src/commonTest/kotlin/androidx/room/migration/bundle/EntityBundleTest.kt
new file mode 100644
index 0000000..2b1ef7c
--- /dev/null
+++ b/room/room-migration/src/commonTest/kotlin/androidx/room/migration/bundle/EntityBundleTest.kt
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2017 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.migration.bundle
+
+import androidx.kruth.assertThat
+import kotlin.test.Test
+
+class EntityBundleTest {
+    @Test
+    fun schemaEquality_same_equal() {
+        val bundle = EntityBundle(
+            tableName = "foo", createSql = "sq",
+            fields = listOf(createFieldBundle("foo"), createFieldBundle("bar")),
+            primaryKey = PrimaryKeyBundle(false, listOf("foo")),
+            indices = listOf(createIndexBundle("foo")),
+            foreignKeys = listOf(createForeignKeyBundle("bar", "foo"))
+        )
+
+        val other = EntityBundle(
+            tableName = "foo", createSql = "sq",
+            fields = listOf(createFieldBundle("foo"), createFieldBundle("bar")),
+            primaryKey = PrimaryKeyBundle(false, listOf("foo")),
+            indices = listOf(createIndexBundle("foo")),
+            foreignKeys = listOf(createForeignKeyBundle("bar", "foo"))
+        )
+
+        assertThat(bundle.isSchemaEqual(other)).isTrue()
+    }
+
+    @Test
+    fun schemaEquality_reorderedFields_equal() {
+        val bundle = EntityBundle(
+            tableName = "foo", createSql = "sq",
+            fields = listOf(createFieldBundle("foo"), createFieldBundle("bar")),
+            primaryKey = PrimaryKeyBundle(false, listOf("foo")),
+            indices = emptyList(),
+            foreignKeys = emptyList()
+        )
+
+        val other = EntityBundle(
+            tableName = "foo", createSql = "sq",
+            fields = listOf(createFieldBundle("bar"), createFieldBundle("foo")),
+            primaryKey = PrimaryKeyBundle(false, listOf("foo")),
+            indices = emptyList(),
+            foreignKeys = emptyList()
+        )
+
+        assertThat(bundle.isSchemaEqual(other)).isTrue()
+    }
+
+    @Test
+    fun schemaEquality_diffFields_notEqual() {
+        val bundle = EntityBundle(
+            tableName = "foo", createSql = "sq",
+            fields = listOf(createFieldBundle("foo"), createFieldBundle("bar")),
+            primaryKey = PrimaryKeyBundle(false, listOf("foo")),
+            indices = emptyList(),
+            foreignKeys = emptyList()
+        )
+
+        val other = EntityBundle(
+            tableName = "foo", createSql = "sq",
+            fields = listOf(createFieldBundle("foo2"), createFieldBundle("bar")),
+            primaryKey = PrimaryKeyBundle(false, listOf("foo")),
+            indices = emptyList(),
+            foreignKeys = emptyList()
+        )
+
+        assertThat(bundle.isSchemaEqual(other)).isFalse()
+    }
+
+    @Test
+    fun schemaEquality_reorderedForeignKeys_equal() {
+        val bundle = EntityBundle(
+            tableName = "foo", createSql = "sq",
+            fields = emptyList(),
+            primaryKey = PrimaryKeyBundle(false, listOf("foo")),
+            indices = emptyList(),
+            foreignKeys = listOf(
+                createForeignKeyBundle("x", "y"),
+                createForeignKeyBundle("bar", "foo")
+            )
+        )
+
+        val other = EntityBundle(
+            tableName = "foo", createSql = "sq",
+            fields = emptyList(),
+            primaryKey = PrimaryKeyBundle(false, listOf("foo")),
+            indices = emptyList(),
+            foreignKeys = listOf(
+                createForeignKeyBundle("bar", "foo"),
+                createForeignKeyBundle("x", "y")
+            )
+        )
+
+        assertThat(bundle.isSchemaEqual(other)).isTrue()
+    }
+
+    @Test
+    fun schemaEquality_diffForeignKeys_notEqual() {
+        val bundle = EntityBundle(
+            tableName = "foo", createSql = "sq",
+            fields = emptyList(),
+            primaryKey = PrimaryKeyBundle(false, listOf("foo")),
+            indices = emptyList(),
+            foreignKeys = listOf(createForeignKeyBundle("bar", "foo"))
+        )
+
+        val other = EntityBundle(
+            tableName = "foo", createSql = "sq",
+            fields = emptyList(),
+            primaryKey = PrimaryKeyBundle(false, listOf("foo")),
+            indices = emptyList(),
+            foreignKeys = listOf(createForeignKeyBundle("bar2", "foo"))
+        )
+
+        assertThat(bundle.isSchemaEqual(other)).isFalse()
+    }
+
+    @Test
+    fun schemaEquality_reorderedIndices_equal() {
+        val bundle = EntityBundle(
+            tableName = "foo", createSql = "sq",
+            fields = emptyList(),
+            primaryKey = PrimaryKeyBundle(false, listOf("foo")),
+            indices = listOf(createIndexBundle("foo"), createIndexBundle("baz")),
+            foreignKeys = emptyList()
+        )
+
+        val other = EntityBundle(
+            tableName = "foo", createSql = "sq",
+            fields = emptyList(),
+            primaryKey = PrimaryKeyBundle(false, listOf("foo")),
+            indices = listOf(createIndexBundle("baz"), createIndexBundle("foo")),
+            foreignKeys = emptyList()
+        )
+
+        assertThat(bundle.isSchemaEqual(other)).isTrue()
+    }
+
+    @Test
+    fun schemaEquality_diffIndices_notEqual() {
+        val bundle = EntityBundle(
+            tableName = "foo", createSql = "sq",
+            fields = emptyList(),
+            primaryKey = PrimaryKeyBundle(false, listOf("foo")),
+            indices = listOf(createIndexBundle("foo")),
+            foreignKeys = emptyList()
+        )
+
+        val other = EntityBundle(
+            tableName = "foo", createSql = "sq",
+            fields = emptyList(),
+            primaryKey = PrimaryKeyBundle(false, listOf("foo")),
+            indices = listOf(createIndexBundle("foo2")),
+            foreignKeys = emptyList()
+        )
+
+        assertThat(bundle.isSchemaEqual(other)).isFalse()
+    }
+
+    private fun createFieldBundle(name: String): FieldBundle {
+        return FieldBundle(
+            fieldPath = "foo",
+            columnName = name,
+            affinity = "text",
+            isNonNull = false,
+            defaultValue = null
+        )
+    }
+
+    private fun createIndexBundle(colName: String): IndexBundle {
+        return IndexBundle(
+            name = "ind_$colName", isUnique = false,
+            columnNames = listOf(colName), orders = emptyList(), createSql = "create"
+        )
+    }
+
+    private fun createForeignKeyBundle(targetTable: String, column: String): ForeignKeyBundle {
+        return ForeignKeyBundle(
+            table = targetTable, onDelete = "CASCADE", onUpdate = "CASCADE",
+            columns = listOf(column), referencedColumns = listOf(column)
+        )
+    }
+}
diff --git a/room/room-migration/src/commonTest/kotlin/androidx/room/migration/bundle/FieldBundleTest.kt b/room/room-migration/src/commonTest/kotlin/androidx/room/migration/bundle/FieldBundleTest.kt
new file mode 100644
index 0000000..a3b9918
--- /dev/null
+++ b/room/room-migration/src/commonTest/kotlin/androidx/room/migration/bundle/FieldBundleTest.kt
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2017 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.migration.bundle
+
+import androidx.kruth.assertThat
+import kotlin.test.Test
+
+class FieldBundleTest {
+    @Test
+    fun schemaEquality_same_equal() {
+        val bundle = FieldBundle(
+            fieldPath = "foo",
+            columnName = "foo",
+            affinity = "text",
+            isNonNull = false,
+            defaultValue = null
+        )
+        val copy = FieldBundle(
+            fieldPath = "foo",
+            columnName = "foo",
+            affinity = "text",
+            isNonNull = false,
+            defaultValue = null
+        )
+        assertThat(bundle.isSchemaEqual(copy)).isTrue()
+    }
+
+    @Test
+    fun schemaEquality_diffNonNull_notEqual() {
+        val bundle = FieldBundle(
+            fieldPath = "foo",
+            columnName = "foo",
+            affinity = "text",
+            isNonNull = false,
+            defaultValue = null
+        )
+        val copy = FieldBundle(
+            fieldPath = "foo",
+            columnName = "foo",
+            affinity = "text",
+            isNonNull = true,
+            defaultValue = null
+        )
+        assertThat(bundle.isSchemaEqual(copy)).isFalse()
+    }
+
+    @Test
+    fun schemaEquality_diffColumnName_notEqual() {
+        val bundle = FieldBundle(
+            fieldPath = "foo",
+            columnName = "foo",
+            affinity = "text",
+            isNonNull = false,
+            defaultValue = null
+        )
+        val copy = FieldBundle(
+            fieldPath = "foo",
+            columnName = "foo2",
+            affinity = "text",
+            isNonNull = true,
+            defaultValue = null
+        )
+        assertThat(bundle.isSchemaEqual(copy)).isFalse()
+    }
+
+    @Test
+    fun schemaEquality_diffAffinity_notEqual() {
+        val bundle = FieldBundle(
+            fieldPath = "foo",
+            columnName = "foo",
+            affinity = "text",
+            isNonNull = false,
+            defaultValue = null
+        )
+        val copy = FieldBundle(
+            fieldPath = "foo",
+            columnName = "foo2",
+            affinity = "int",
+            isNonNull = false,
+            defaultValue = null
+        )
+        assertThat(bundle.isSchemaEqual(copy)).isFalse()
+    }
+
+    @Test
+    fun schemaEquality_diffPath_equal() {
+        val bundle = FieldBundle(
+            fieldPath = "foo",
+            columnName = "foo",
+            affinity = "text",
+            isNonNull = false,
+            defaultValue = null
+        )
+        val copy = FieldBundle(
+            fieldPath = "foo>bar",
+            columnName = "foo",
+            affinity = "text",
+            isNonNull = false,
+            defaultValue = null
+        )
+        assertThat(bundle.isSchemaEqual(copy)).isTrue()
+    }
+
+    @Test
+    fun schemeEquality_diffDefaultValue_notEqual() {
+        val bundle = FieldBundle(
+            fieldPath = "foo",
+            columnName = "foo",
+            affinity = "text",
+            isNonNull = true,
+            defaultValue = null
+        )
+        val copy = FieldBundle(
+            fieldPath = "foo",
+            columnName = "foo",
+            affinity = "text",
+            isNonNull = true,
+            defaultValue = "bar"
+        )
+        assertThat(bundle.isSchemaEqual(copy)).isFalse()
+    }
+}
diff --git a/room/room-migration/src/commonTest/kotlin/androidx/room/migration/bundle/ForeignKeyBundleTest.kt b/room/room-migration/src/commonTest/kotlin/androidx/room/migration/bundle/ForeignKeyBundleTest.kt
new file mode 100644
index 0000000..0263e0c
--- /dev/null
+++ b/room/room-migration/src/commonTest/kotlin/androidx/room/migration/bundle/ForeignKeyBundleTest.kt
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2017 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.migration.bundle
+
+import androidx.kruth.assertThat
+import kotlin.test.Test
+
+class ForeignKeyBundleTest {
+    @Test
+    fun schemaEquality_same_equal() {
+        val bundle = ForeignKeyBundle(
+            table = "table", onDelete = "onDelete",
+            onUpdate = "onUpdate", columns = listOf("col1", "col2"),
+            referencedColumns = listOf("target1", "target2")
+        )
+        val other = ForeignKeyBundle(
+            table = "table", onDelete = "onDelete",
+            onUpdate = "onUpdate", columns = listOf("col1", "col2"),
+            referencedColumns = listOf("target1", "target2")
+        )
+
+        assertThat(bundle.isSchemaEqual(other)).isTrue()
+    }
+
+    @Test
+    fun schemaEquality_diffTable_notEqual() {
+        val bundle = ForeignKeyBundle(
+            table = "table", onDelete = "onDelete",
+            onUpdate = "onUpdate", columns = listOf("col1", "col2"),
+            referencedColumns = listOf("target1", "target2")
+        )
+        val other = ForeignKeyBundle(
+            table = "table2", onDelete = "onDelete",
+            onUpdate = "onUpdate", columns = listOf("col1", "col2"),
+            referencedColumns = listOf("target1", "target2")
+        )
+        assertThat(bundle.isSchemaEqual(other)).isFalse()
+    }
+
+    @Test
+    fun schemaEquality_diffOnDelete_notEqual() {
+        val bundle = ForeignKeyBundle(
+            table = "table", onDelete = "onDelete2",
+            onUpdate = "onUpdate", columns = listOf("col1", "col2"),
+            referencedColumns = listOf("target1", "target2")
+        )
+        val other = ForeignKeyBundle(
+            table = "table", onDelete = "onDelete",
+            onUpdate = "onUpdate", columns = listOf("col1", "col2"),
+            referencedColumns = listOf("target1", "target2")
+        )
+        assertThat(bundle.isSchemaEqual(other)).isFalse()
+    }
+
+    @Test
+    fun schemaEquality_diffOnUpdate_notEqual() {
+        val bundle = ForeignKeyBundle(
+            table = "table", onDelete = "onDelete",
+            onUpdate = "onUpdate", columns = listOf("col1", "col2"),
+            referencedColumns = listOf("target1", "target2")
+        )
+        val other = ForeignKeyBundle(
+            table = "table", onDelete = "onDelete",
+            onUpdate = "onUpdate2", columns = listOf("col1", "col2"),
+            referencedColumns = listOf("target1", "target2")
+        )
+        assertThat(bundle.isSchemaEqual(other)).isFalse()
+    }
+
+    @Test
+    fun schemaEquality_diffSrcOrder_notEqual() {
+        val bundle = ForeignKeyBundle(
+            table = "table", onDelete = "onDelete",
+            onUpdate = "onUpdate", columns = listOf("col2", "col1"),
+            referencedColumns = listOf("target1", "target2")
+        )
+        val other = ForeignKeyBundle(
+            table = "table", onDelete = "onDelete",
+            onUpdate = "onUpdate", columns = listOf("col1", "col2"),
+            referencedColumns = listOf("target1", "target2")
+        )
+        assertThat(bundle.isSchemaEqual(other)).isFalse()
+    }
+
+    @Test
+    fun schemaEquality_diffTargetOrder_notEqual() {
+        val bundle = ForeignKeyBundle(
+            table = "table", onDelete = "onDelete",
+            onUpdate = "onUpdate", columns = listOf("col1", "col2"),
+            referencedColumns = listOf("target1", "target2")
+        )
+        val other = ForeignKeyBundle(
+            table = "table", onDelete = "onDelete",
+            onUpdate = "onUpdate", columns = listOf("col1", "col2"),
+            referencedColumns = listOf("target2", "target1")
+        )
+        assertThat(bundle.isSchemaEqual(other)).isFalse()
+    }
+}
diff --git a/room/room-migration/src/commonTest/kotlin/androidx/room/migration/bundle/IndexBundleTest.kt b/room/room-migration/src/commonTest/kotlin/androidx/room/migration/bundle/IndexBundleTest.kt
new file mode 100644
index 0000000..be09d5b
--- /dev/null
+++ b/room/room-migration/src/commonTest/kotlin/androidx/room/migration/bundle/IndexBundleTest.kt
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2017 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.migration.bundle
+
+import androidx.kruth.assertThat
+import kotlin.test.Test
+
+class IndexBundleTest {
+    @Test
+    fun schemaEquality_same_equal() {
+        val bundle = IndexBundle(
+            name = "index1", isUnique = false,
+            columnNames = listOf("col1", "col2"), orders = listOf("ASC", "ASC"), createSql = "sql"
+        )
+        val other = IndexBundle(
+            name = "index1", isUnique = false,
+            columnNames = listOf("col1", "col2"), orders = listOf("ASC", "ASC"), createSql = "sql"
+        )
+        assertThat(bundle.isSchemaEqual(other)).isTrue()
+    }
+
+    @Test
+    fun schemaEquality_diffName_notEqual() {
+        val bundle = IndexBundle(
+            name = "index1", isUnique = false,
+            columnNames = listOf("col1", "col2"), orders = listOf("ASC", "ASC"), createSql = "sql"
+        )
+        val other = IndexBundle(
+            name = "index3", isUnique = false,
+            columnNames = listOf("col1", "col2"), orders = listOf("ASC", "ASC"), createSql = "sql"
+        )
+        assertThat(bundle.isSchemaEqual(other)).isFalse()
+    }
+
+    @Test
+    fun schemaEquality_diffGenericName_equal() {
+        val bundle = IndexBundle(
+            name = IndexBundle.DEFAULT_PREFIX + "x", isUnique = false,
+            columnNames = listOf("col1", "col2"), orders = listOf("ASC", "ASC"), createSql = "sql"
+        )
+        val other = IndexBundle(
+            name = IndexBundle.DEFAULT_PREFIX + "y", isUnique = false,
+            columnNames = listOf("col1", "col2"), orders = listOf("ASC", "ASC"), createSql = "sql"
+        )
+        assertThat(bundle.isSchemaEqual(other)).isTrue()
+    }
+
+    @Test
+    fun schemaEquality_diffUnique_notEqual() {
+        val bundle = IndexBundle(
+            name = "index1", isUnique = false,
+            columnNames = listOf("col1", "col2"), orders = listOf("ASC", "ASC"), createSql = "sql"
+        )
+        val other = IndexBundle(
+            name = "index1", isUnique = true,
+            columnNames = listOf("col1", "col2"), orders = listOf("ASC", "ASC"), createSql = "sql"
+        )
+        assertThat(bundle.isSchemaEqual(other)).isFalse()
+    }
+
+    @Test
+    fun schemaEquality_diffColumns_notEqual() {
+        val bundle = IndexBundle(
+            name = "index1", isUnique = false,
+            columnNames = listOf("col1", "col2"), orders = listOf("ASC", "ASC"), createSql = "sql"
+        )
+        val other = IndexBundle(
+            name = "index1", isUnique = false,
+            columnNames = listOf("col2", "col1"), orders = listOf("ASC", "ASC"), createSql = "sql"
+        )
+        assertThat(bundle.isSchemaEqual(other)).isFalse()
+    }
+
+    @Test
+    fun schemaEquality_diffSql_equal() {
+        val bundle = IndexBundle(
+            name = "index1", isUnique = false,
+            columnNames = listOf("col1", "col2"), orders = listOf("ASC", "ASC"), createSql = "sql"
+        )
+        val other = IndexBundle(
+            name = "index1", isUnique = false,
+            columnNames = listOf("col1", "col2"), orders = listOf("ASC", "ASC"), createSql = "sql22"
+        )
+        assertThat(bundle.isSchemaEqual(other)).isTrue()
+    }
+
+    @Test
+    fun schemaEquality_diffSort_notEqual() {
+        val bundle = IndexBundle(
+            "index1", false,
+            listOf("col1", "col2"), listOf("ASC", "DESC"), "sql"
+        )
+        val other = IndexBundle(
+            "index1", false,
+            listOf("col1", "col2"), listOf("DESC", "ASC"), "sql"
+        )
+        assertThat(bundle.isSchemaEqual(other)).isFalse()
+    }
+
+    @Test
+    fun schemaEquality_sortNullVsAllAsc_isEqual() {
+        val bundle = IndexBundle(
+            name = "index1", isUnique = false,
+            columnNames = listOf("col1", "col2"), orders = listOf("ASC", "ASC"), createSql = "sql"
+        )
+        val other = IndexBundle(
+            name = "index1", isUnique = false,
+            columnNames = listOf("col1", "col2"), orders = null, createSql = "sql"
+        )
+        assertThat(bundle.isSchemaEqual(other)).isTrue()
+    }
+
+    @Test
+    fun schemaEquality_sortEmptyVsAllAsc_isEqual() {
+        val bundle = IndexBundle(
+            name = "index1", isUnique = false,
+            columnNames = listOf("col1", "col2"), orders = listOf("ASC", "ASC"), createSql = "sql"
+        )
+        val other = IndexBundle(
+            name = "index1", isUnique = false,
+            columnNames = listOf("col1", "col2"), orders = emptyList(), createSql = "sql"
+        )
+        assertThat(bundle.isSchemaEqual(other)).isTrue()
+    }
+}
diff --git a/room/room-migration/src/commonTest/kotlin/androidx/room/migration/bundle/PrimaryKeyBundleTest.kt b/room/room-migration/src/commonTest/kotlin/androidx/room/migration/bundle/PrimaryKeyBundleTest.kt
new file mode 100644
index 0000000..accd6f1
--- /dev/null
+++ b/room/room-migration/src/commonTest/kotlin/androidx/room/migration/bundle/PrimaryKeyBundleTest.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2017 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.migration.bundle
+
+import androidx.kruth.assertThat
+import kotlin.test.Test
+
+class PrimaryKeyBundleTest {
+    @Test
+    fun schemaEquality_same_equal() {
+        val bundle = PrimaryKeyBundle(
+            isAutoGenerate = true,
+            columnNames = listOf("foo", "bar")
+        )
+        val other = PrimaryKeyBundle(
+            isAutoGenerate = true,
+            columnNames = listOf("foo", "bar")
+        )
+        assertThat(bundle.isSchemaEqual(other)).isTrue()
+    }
+
+    @Test
+    fun schemaEquality_diffAutoGen_notEqual() {
+        val bundle = PrimaryKeyBundle(
+            isAutoGenerate = true,
+            columnNames = listOf("foo", "bar")
+        )
+        val other = PrimaryKeyBundle(
+            isAutoGenerate = false,
+            columnNames = listOf("foo", "bar")
+        )
+        assertThat(bundle.isSchemaEqual(other)).isFalse()
+    }
+
+    @Test
+    fun schemaEquality_diffColumns_notEqual() {
+        val bundle = PrimaryKeyBundle(
+            isAutoGenerate = true,
+            columnNames = listOf("foo", "baz")
+        )
+        val other = PrimaryKeyBundle(
+            isAutoGenerate = true,
+            columnNames = listOf("foo", "bar")
+        )
+        assertThat(bundle.isSchemaEqual(other)).isFalse()
+    }
+
+    @Test
+    fun schemaEquality_diffColumnOrder_notEqual() {
+        val bundle = PrimaryKeyBundle(
+            isAutoGenerate = true,
+            columnNames = listOf("foo", "bar")
+        )
+        val other = PrimaryKeyBundle(
+            isAutoGenerate = true,
+            columnNames = listOf("bar", "foo")
+        )
+        assertThat(bundle.isSchemaEqual(other)).isFalse()
+    }
+}
diff --git a/room/room-migration/src/jvmMain/kotlin/androidx/room/migration/bundle/DatabaseBundle.jvm.kt b/room/room-migration/src/jvmMain/kotlin/androidx/room/migration/bundle/DatabaseBundle.jvm.kt
deleted file mode 100644
index 3c620b1..0000000
--- a/room/room-migration/src/jvmMain/kotlin/androidx/room/migration/bundle/DatabaseBundle.jvm.kt
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2017 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.migration.bundle
-
-import androidx.annotation.RestrictTo
-import androidx.room.migration.bundle.SchemaEqualityUtil.checkSchemaEquality
-import com.google.gson.annotations.SerializedName
-
-/**
- * Data class that holds the schema information for a [androidx.room.Database].
- *
- * @property version Version
- * @property identityHash Identity hash
- * @property entities List of entities
- * @property views List of views
- */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
-public open class DatabaseBundle(
-    @field:SerializedName("version")
-    public open val version: Int,
-    @field:SerializedName("identityHash")
-    public open val identityHash: String,
-    @field:SerializedName("entities")
-    public open val entities: List<EntityBundle>,
-    @field:SerializedName("views")
-    public open val views: List<DatabaseViewBundle>,
-    @field:SerializedName("setupQueries")
-    private val setupQueries: List<String>,
-) : SchemaEquality<DatabaseBundle> {
-
-    // Used by GSON
-    @Deprecated("Marked deprecated to avoid usage in the codebase")
-    @SuppressWarnings("unused")
-    public constructor() : this(0, "", emptyList(), emptyList(), emptyList())
-
-    @delegate:Transient
-    public open val entitiesByTableName: Map<String, EntityBundle> by lazy {
-        entities.associateBy { it.tableName }
-    }
-
-    @delegate:Transient
-    public val viewsByName: Map<String, DatabaseViewBundle> by lazy {
-        views.associateBy { it.viewName }
-    }
-
-    /**
-     * @return List of SQL queries to build this database from scratch.
-     */
-    public open fun buildCreateQueries(): List<String> {
-        return buildList {
-            entities.sortedWith(FtsEntityCreateComparator()).forEach { entityBundle ->
-                addAll(entityBundle.buildCreateQueries())
-            }
-            views.forEach { viewBundle ->
-                add(viewBundle.createView())
-            }
-            addAll(setupQueries)
-        }
-    }
-
-    @Override
-    override fun isSchemaEqual(other: DatabaseBundle): Boolean {
-        return checkSchemaEquality(entitiesByTableName, other.entitiesByTableName) &&
-            checkSchemaEquality(viewsByName, other.viewsByName)
-    }
-
-    // Comparator to sort FTS entities after their declared external content entity so that the
-    // content entity table gets created first.
-    public class FtsEntityCreateComparator : Comparator<EntityBundle> {
-        override fun compare(firstEntity: EntityBundle, secondEntity: EntityBundle): Int {
-            if (firstEntity is FtsEntityBundle) {
-                val contentTable = firstEntity.ftsOptions.contentTable
-                if (contentTable == secondEntity.tableName) {
-                    return 1
-                }
-            } else if (secondEntity is FtsEntityBundle) {
-                val contentTable = secondEntity.ftsOptions.contentTable
-                if (contentTable == firstEntity.tableName) {
-                    return -1
-                }
-            }
-            return 0
-        }
-    }
-}
diff --git a/room/room-migration/src/jvmMain/kotlin/androidx/room/migration/bundle/EntityBundle.jvm.kt b/room/room-migration/src/jvmMain/kotlin/androidx/room/migration/bundle/EntityBundle.jvm.kt
deleted file mode 100644
index 958c918..0000000
--- a/room/room-migration/src/jvmMain/kotlin/androidx/room/migration/bundle/EntityBundle.jvm.kt
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2017 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.migration.bundle
-
-import androidx.annotation.RestrictTo
-import androidx.room.migration.bundle.SchemaEqualityUtil.checkSchemaEquality
-import com.google.gson.annotations.SerializedName
-
-/**
- * Data class that holds the schema information about an [androidx.room.Entity].
- *
- * @property tableName The table name.
- * @property createSql Create query with the table name placeholder.
- * @property fields The list of fields.
- * @property primaryKey The primary key.
- * @property indices The list of indices
- * @property foreignKeys The list of foreign keys
- *
- */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
-public open class EntityBundle(
-    @SerializedName("tableName")
-    public open val tableName: String,
-    @SerializedName("createSql")
-    public open val createSql: String,
-    @SerializedName("fields")
-    public open val fields: List<FieldBundle>,
-    @SerializedName("primaryKey")
-    public open val primaryKey: PrimaryKeyBundle,
-    @SerializedName("indices")
-    public open val indices: List<IndexBundle>,
-    @SerializedName("foreignKeys")
-    public open val foreignKeys: List<ForeignKeyBundle>
-) : SchemaEquality<EntityBundle> {
-
-    // Used by GSON
-    @Deprecated("Marked deprecated to avoid usage in the codebase")
-    @SuppressWarnings("unused")
-    private constructor() : this(
-        "",
-        "",
-        emptyList(),
-        PrimaryKeyBundle(false, emptyList()),
-        emptyList(),
-        emptyList()
-    )
-
-    public companion object {
-        public const val NEW_TABLE_PREFIX: String = "_new_"
-    }
-
-    public open val newTableName: String
-        get() {
-            return NEW_TABLE_PREFIX + tableName
-        }
-
-    @delegate:Transient
-    public open val fieldsByColumnName: Map<String, FieldBundle> by lazy {
-        fields.associateBy { it.columnName }
-    }
-
-    /**
-     * @return Create table SQL query that uses the actual table name.
-     */
-    public open fun createTable(): String {
-        return replaceTableName(createSql, tableName)
-    }
-
-    /**
-     * @return Create table SQL query that uses the table name with "new" prefix.
-     */
-    public open fun createNewTable(): String {
-        return replaceTableName(createSql, newTableName)
-    }
-
-    /**
-     * @return Renames the table with [newTableName] to [tableName].
-     */
-    public open fun renameToOriginal(): String {
-        return "ALTER TABLE $newTableName RENAME TO $tableName"
-    }
-
-    /**
-     * @return Creates the list of SQL queries that are necessary to create this entity.
-     */
-    public open fun buildCreateQueries(): Collection<String> {
-        return buildList {
-            add(createTable())
-            this@EntityBundle.indices.forEach { indexBundle ->
-                add(indexBundle.create(tableName))
-            }
-        }
-    }
-
-    override fun isSchemaEqual(other: EntityBundle): Boolean {
-        if (tableName != other.tableName) {
-            return false
-        }
-        return checkSchemaEquality(
-            fieldsByColumnName,
-            other.fieldsByColumnName
-        ) &&
-            checkSchemaEquality(primaryKey, other.primaryKey) &&
-            checkSchemaEquality(indices, other.indices) &&
-            checkSchemaEquality(foreignKeys, other.foreignKeys)
-    }
-}
diff --git a/room/room-migration/src/jvmMain/kotlin/androidx/room/migration/bundle/FieldBundle.jvm.kt b/room/room-migration/src/jvmMain/kotlin/androidx/room/migration/bundle/FieldBundle.jvm.kt
deleted file mode 100644
index 758b8e39..0000000
--- a/room/room-migration/src/jvmMain/kotlin/androidx/room/migration/bundle/FieldBundle.jvm.kt
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2017 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.migration.bundle
-
-import androidx.annotation.RestrictTo
-import com.google.gson.annotations.SerializedName
-
-/**
- * Data class that holds the schema information for an [androidx.room.Entity] field.
- */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
-public open class FieldBundle(
-    @SerializedName("fieldPath")
-    public open val fieldPath: String,
-    @SerializedName("columnName")
-    public open val columnName: String,
-    @SerializedName("affinity")
-    public open val affinity: String,
-    @SerializedName("notNull")
-    public open val isNonNull: Boolean,
-    @SerializedName("defaultValue")
-    public open val defaultValue: String?,
-) : SchemaEquality<FieldBundle> {
-
-    @Deprecated("Use [FieldBundle(String, String, String, boolean, String)")
-    public constructor(fieldPath: String, columnName: String, affinity: String, nonNull: Boolean) :
-        this(fieldPath, columnName, affinity, nonNull, null)
-
-    // Used by GSON
-    @Deprecated("Marked deprecated to avoid usage in the codebase")
-    @SuppressWarnings("unused")
-    private constructor() : this("", "", "", false, null)
-
-    override fun isSchemaEqual(other: FieldBundle): Boolean {
-        if (isNonNull != other.isNonNull) return false
-        if (columnName != other.columnName) {
-            return false
-        }
-        if (defaultValue?.let { it != other.defaultValue } ?: (other.defaultValue != null)) {
-            return false
-        }
-        return affinity == other.affinity
-    }
-}
diff --git a/room/room-migration/src/jvmMain/kotlin/androidx/room/migration/bundle/ForeignKeyBundle.jvm.kt b/room/room-migration/src/jvmMain/kotlin/androidx/room/migration/bundle/ForeignKeyBundle.jvm.kt
deleted file mode 100644
index 3e8c079..0000000
--- a/room/room-migration/src/jvmMain/kotlin/androidx/room/migration/bundle/ForeignKeyBundle.jvm.kt
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2017 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.migration.bundle
-
-import androidx.annotation.RestrictTo
-import com.google.gson.annotations.SerializedName
-
-/**
- * Data class that holds the information about a foreign key reference, i.e.
- * [androidx.room.ForeignKey].
- *
- * @property table             The target table
- * @property onDelete          OnDelete action
- * @property onUpdate          OnUpdate action
- * @property columns           The list of columns in the current table
- * @property referencedColumns The list of columns in the referenced table
- */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
-public open class ForeignKeyBundle(
-    @field:SerializedName("table")
-    public open val table: String,
-    @field:SerializedName("onDelete")
-    public open val onDelete: String,
-    @field:SerializedName("onUpdate")
-    public open val onUpdate: String,
-    @field:SerializedName("columns")
-    public open val columns: List<String>,
-    @field:SerializedName("referencedColumns")
-    public open val referencedColumns: List<String>
-) : SchemaEquality<ForeignKeyBundle> {
-
-    // Used by GSON
-    @Deprecated("Marked deprecated to avoid usage in the codebase")
-    @SuppressWarnings("unused")
-    private constructor() : this("", "", "", emptyList(), emptyList())
-
-    override fun isSchemaEqual(other: ForeignKeyBundle): Boolean {
-        if (table != other.table) return false
-        if (onDelete != other.onDelete) return false
-        if (onUpdate != other.onUpdate) return false
-        // order matters
-        return (columns == other.columns && referencedColumns == other.referencedColumns)
-    }
-}
diff --git a/room/room-migration/src/jvmMain/kotlin/androidx/room/migration/bundle/FtsEntityBundle.jvm.kt b/room/room-migration/src/jvmMain/kotlin/androidx/room/migration/bundle/FtsEntityBundle.jvm.kt
deleted file mode 100644
index 266f776..0000000
--- a/room/room-migration/src/jvmMain/kotlin/androidx/room/migration/bundle/FtsEntityBundle.jvm.kt
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright 2018 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.migration.bundle
-
-import androidx.annotation.RestrictTo
-import androidx.room.migration.bundle.SchemaEqualityUtil.checkSchemaEquality
-import com.google.gson.annotations.SerializedName
-
-/**
- * Data class that holds the schema information about an [androidx.room.Fts3] or
- * [androidx.room.Fts4] entity.
- */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
-public open class FtsEntityBundle(
-    tableName: String,
-    createSql: String,
-    fields: List<FieldBundle>,
-    primaryKey: PrimaryKeyBundle,
-    @field:SerializedName("ftsVersion")
-    public open val ftsVersion: String,
-    @field:SerializedName("ftsOptions")
-    public open val ftsOptions: FtsOptionsBundle,
-    @SerializedName("contentSyncTriggers")
-    public open val contentSyncSqlTriggers: List<String>
-) : EntityBundle(
-    tableName,
-    createSql,
-    fields,
-    primaryKey,
-    emptyList(),
-    emptyList()
-) {
-    // Used by GSON
-    @Deprecated("Marked deprecated to avoid usage in the codebase")
-    @SuppressWarnings("unused")
-    private constructor() : this(
-        "",
-        "",
-        emptyList(),
-        PrimaryKeyBundle(false, emptyList()),
-        "",
-        FtsOptionsBundle("", emptyList(), "", "", "", emptyList(), emptyList(), ""),
-        emptyList()
-    )
-
-    @Transient
-    private val SHADOW_TABLE_NAME_SUFFIXES = listOf(
-        "_content",
-        "_segdir",
-        "_segments",
-        "_stat",
-        "_docsize"
-    )
-
-    /**
-     * @return Creates the list of SQL queries that are necessary to create this entity.
-     */
-   override fun buildCreateQueries(): Collection<String> {
-        return buildList {
-            add(createTable())
-            addAll(contentSyncSqlTriggers)
-        }
-    }
-
-    override fun isSchemaEqual(other: EntityBundle): Boolean {
-        val isSuperSchemaEqual = super.isSchemaEqual(other)
-        return if (other is FtsEntityBundle) {
-            isSuperSchemaEqual && ftsVersion == other.ftsVersion &&
-                checkSchemaEquality(ftsOptions, other.ftsOptions)
-        } else {
-            isSuperSchemaEqual
-        }
-    }
-
-    /**
-     * Gets the list of shadow table names corresponding to the FTS virtual table.
-     * @return the list of names.
-     */
-    @delegate:Transient
-    public open val shadowTableNames: List<String> by lazy {
-        val currentTable = this@FtsEntityBundle.tableName
-        buildList {
-            SHADOW_TABLE_NAME_SUFFIXES.forEach { suffix ->
-                add(currentTable + suffix)
-            }
-        }
-    }
-}
diff --git a/room/room-migration/src/jvmMain/kotlin/androidx/room/migration/bundle/FtsOptionsBundle.jvm.kt b/room/room-migration/src/jvmMain/kotlin/androidx/room/migration/bundle/FtsOptionsBundle.jvm.kt
deleted file mode 100644
index e73c374..0000000
--- a/room/room-migration/src/jvmMain/kotlin/androidx/room/migration/bundle/FtsOptionsBundle.jvm.kt
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright 2018 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.migration.bundle
-
-import androidx.annotation.RestrictTo
-import com.google.gson.annotations.SerializedName
-
-/**
- * Data class that holds [androidx.room.FtsOptions] information.
- */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
-public open class FtsOptionsBundle(
-    @SerializedName("tokenizer")
-    private val tokenizer: String,
-    @SerializedName("tokenizerArgs")
-    public open val tokenizerArgs: List<String>,
-    @SerializedName("contentTable")
-    public open val contentTable: String,
-    @SerializedName("languageIdColumnName")
-    public open val languageIdColumnName: String,
-    @SerializedName("matchInfo")
-    public open val matchInfo: String,
-    @SerializedName("notIndexedColumns")
-    public open val notIndexedColumns: List<String>,
-    @SerializedName("prefixSizes")
-    public open val prefixSizes: List<Int>,
-    @SerializedName("preferredOrder")
-    public open val preferredOrder: String
-) : SchemaEquality<FtsOptionsBundle> {
-
-    // Used by GSON
-    @Deprecated("Marked deprecated to avoid usage in the codebase")
-    @SuppressWarnings("unused")
-    private constructor() : this("", emptyList(), "", "", "", emptyList(), emptyList(), "")
-
-    override fun isSchemaEqual(other: FtsOptionsBundle): Boolean {
-        return tokenizer == other.tokenizer &&
-            tokenizerArgs == other.tokenizerArgs &&
-            contentTable == other.contentTable &&
-            languageIdColumnName == other.languageIdColumnName &&
-            matchInfo == other.matchInfo &&
-            notIndexedColumns == other.notIndexedColumns &&
-            prefixSizes == other.prefixSizes &&
-            preferredOrder == other.preferredOrder
-    }
-}
diff --git a/room/room-migration/src/jvmMain/kotlin/androidx/room/migration/bundle/IndexBundle.jvm.kt b/room/room-migration/src/jvmMain/kotlin/androidx/room/migration/bundle/IndexBundle.jvm.kt
deleted file mode 100644
index b21f9a5..0000000
--- a/room/room-migration/src/jvmMain/kotlin/androidx/room/migration/bundle/IndexBundle.jvm.kt
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2017 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.migration.bundle
-
-import androidx.annotation.RestrictTo
-import androidx.room.Index
-import com.google.gson.annotations.SerializedName
-
-/**
- * Data class that holds the schema information about a table [androidx.room.Index]
- */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
-public open class IndexBundle(
-    @SerializedName("name")
-    public open val name: String,
-    @SerializedName("unique")
-    public open val isUnique: Boolean,
-    @SerializedName("columnNames")
-    public open val columnNames: List<String>?,
-    @SerializedName("orders")
-    public open val orders: List<String>?,
-    @SerializedName("createSql")
-    public open val createSql: String
-
-) : SchemaEquality<IndexBundle> {
-    public companion object {
-        // should match Index.kt
-        public const val DEFAULT_PREFIX: String = "index_"
-    }
-
-    /**
-     * @deprecated Use {@link #IndexBundle(String, boolean, List, List, String)}
-     */
-    @Deprecated("Use {@link #IndexBundle(String, boolean, List, List, String)}")
-    public constructor(
-        name: String,
-        unique: Boolean,
-        columnNames: List<String>,
-        createSql: String
-    ) : this(name, unique, columnNames, null, createSql)
-
-    // Used by GSON
-    @Deprecated("Marked deprecated to avoid usage in the codebase")
-    @SuppressWarnings("unused")
-    private constructor() : this("", false, emptyList(), emptyList(), "")
-
-    /**
-     */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
-    public open fun create(tableName: String): String {
-        return replaceTableName(createSql, tableName)
-    }
-
-    /**
-     * @param tableName The table name.
-     * @return Create index SQL query that uses the given table name.
-     */
-    public open fun getCreateSql(tableName: String): String {
-        return replaceTableName(createSql, tableName)
-    }
-
-    override fun isSchemaEqual(other: IndexBundle): Boolean {
-        if (isUnique != other.isUnique) return false
-        if (name.startsWith(DEFAULT_PREFIX)) {
-            if (!other.name.startsWith(DEFAULT_PREFIX)) {
-                return false
-            }
-        } else if (other.name.startsWith(DEFAULT_PREFIX)) {
-            return false
-        } else if (!name.equals(other.name)) {
-            return false
-        }
-
-        // order matters
-        if (columnNames?.let { columnNames != other.columnNames } ?: (other.columnNames != null)) {
-            return false
-        }
-
-        // order matters and null orders is considered equal to all ASC orders, to be backward
-        // compatible with schemas where orders are not present in the schema file
-        val columnsSize = columnNames?.size ?: 0
-        val orders = if (orders.isNullOrEmpty()) {
-            List(columnsSize) { Index.Order.ASC.name }
-        } else {
-            orders
-        }
-        val otherOrders =
-            if (other.orders.isNullOrEmpty()) {
-                List(columnsSize) { Index.Order.ASC.name }
-            } else {
-                other.orders
-            }
-
-        if (orders != otherOrders) return false
-        return true
-    }
-}
diff --git a/room/room-migration/src/jvmMain/kotlin/androidx/room/migration/bundle/SchemaBundle.jvm.kt b/room/room-migration/src/jvmMain/kotlin/androidx/room/migration/bundle/SchemaBundle.jvm.kt
index 5c0e92f..7a46bf5 100644
--- a/room/room-migration/src/jvmMain/kotlin/androidx/room/migration/bundle/SchemaBundle.jvm.kt
+++ b/room/room-migration/src/jvmMain/kotlin/androidx/room/migration/bundle/SchemaBundle.jvm.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * 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.
@@ -17,129 +17,42 @@
 package androidx.room.migration.bundle
 
 import androidx.annotation.RestrictTo
-import com.google.gson.Gson
-import com.google.gson.GsonBuilder
-import com.google.gson.JsonElement
-import com.google.gson.JsonObject
-import com.google.gson.TypeAdapter
-import com.google.gson.TypeAdapterFactory
-import com.google.gson.annotations.SerializedName
-import com.google.gson.reflect.TypeToken
-import com.google.gson.stream.JsonReader
-import com.google.gson.stream.JsonWriter
-import java.io.File
-import java.io.FileOutputStream
-import java.io.IOException
 import java.io.InputStream
-import java.io.InputStreamReader
 import java.io.OutputStream
-import java.io.OutputStreamWriter
-import java.io.UnsupportedEncodingException
+import kotlinx.serialization.ExperimentalSerializationApi
+import kotlinx.serialization.SerialName
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.json.decodeFromStream
+import kotlinx.serialization.json.encodeToStream
 
 /**
  * Data class that holds the information about a database schema export.
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
-public open class SchemaBundle(
-    @SerializedName("formatVersion")
-    public open val formatVersion: Int,
-    @SerializedName("database")
-    public open val database: DatabaseBundle
+@Serializable
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+actual class SchemaBundle actual constructor(
+    @SerialName("formatVersion")
+    actual val formatVersion: Int,
+    @SerialName("database")
+    actual val database: DatabaseBundle
 ) : SchemaEquality<SchemaBundle> {
-    public companion object {
-        private const val CHARSET = "UTF-8"
-        public const val LATEST_FORMAT: Int = 1
-        private val GSON: Gson = GsonBuilder()
-            .setPrettyPrinting()
-            .disableHtmlEscaping()
-            .registerTypeAdapterFactory(
-                EntityTypeAdapterFactory()
-            )
-            .create()
 
-        @Throws(UnsupportedEncodingException::class)
-        @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
-        @JvmStatic
-        public fun deserialize(fis: InputStream): SchemaBundle {
-            InputStreamReader(fis, CHARSET).use { inputStream ->
-                return GSON.fromJson(inputStream, SchemaBundle::class.javaObjectType)
-                    ?: throw EmptySchemaException()
-            }
+    actual override fun isSchemaEqual(other: SchemaBundle): Boolean {
+        return formatVersion == other.formatVersion &&
+            SchemaEqualityUtil.checkSchemaEquality(database, other.database)
+    }
+
+    companion object {
+        @OptIn(ExperimentalSerializationApi::class) // For decodeFromStream() with InputStream
+        fun deserialize(fis: InputStream): SchemaBundle = fis.use {
+            json.decodeFromStream(it)
         }
 
-        @Throws(IOException::class)
-        @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
-        @JvmStatic
-        @Deprecated("Prefer overload version that has OutputStream as parameter.")
-        public fun serialize(bundle: SchemaBundle, file: File) {
-            serialize(bundle, FileOutputStream(file, false))
-        }
-
-        @Throws(IOException::class)
-        @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
-        @JvmStatic
-        public fun serialize(bundle: SchemaBundle, outputStream: OutputStream) {
-            OutputStreamWriter(outputStream, CHARSET).use { outputStreamWriter ->
-                GSON.toJson(bundle, outputStreamWriter)
+        @OptIn(ExperimentalSerializationApi::class) // For encodeToStream() with OutputStream
+        fun serialize(bundle: SchemaBundle, outputStream: OutputStream) {
+            outputStream.use {
+                json.encodeToStream(bundle, it)
             }
         }
     }
-
-    override fun isSchemaEqual(other: SchemaBundle): Boolean {
-        return SchemaEqualityUtil.checkSchemaEquality(database, other.database) &&
-            formatVersion == other.formatVersion
-    }
-
-    private open class EntityTypeAdapterFactory : TypeAdapterFactory {
-        @Suppress("UNCHECKED_CAST")
-        override fun <T> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? {
-            if (!EntityBundle::class.java.isAssignableFrom(type.rawType)) {
-                return null
-            }
-            val jsonElementAdapter = gson.getAdapter(
-                JsonElement::class.java
-            )
-            val entityBundleAdapter = gson.getDelegateAdapter(
-                this,
-                TypeToken.get(EntityBundle::class.java)
-            )
-            val ftsEntityBundleAdapter = gson.getDelegateAdapter(
-                this,
-                TypeToken.get(FtsEntityBundle::class.java)
-            )
-            return EntityTypeAdapter(
-                jsonElementAdapter, entityBundleAdapter, ftsEntityBundleAdapter
-            ) as TypeAdapter<T>
-        }
-
-        private class EntityTypeAdapter(
-            val jsonElementAdapter: TypeAdapter<JsonElement>,
-            val entityBundleAdapter: TypeAdapter<EntityBundle>,
-            val ftsEntityBundleAdapter: TypeAdapter<FtsEntityBundle>
-        ) : TypeAdapter<EntityBundle>() {
-            @Throws(IOException::class)
-            override fun write(out: JsonWriter?, value: EntityBundle?) {
-                if (value is FtsEntityBundle) {
-                    ftsEntityBundleAdapter.write(out, value)
-                } else {
-                    entityBundleAdapter.write(out, value)
-                }
-            }
-
-            override fun read(input: JsonReader?): EntityBundle {
-                val jsonObject: JsonObject = jsonElementAdapter.read(input).asJsonObject
-                return if (jsonObject.has("ftsVersion")) {
-                    ftsEntityBundleAdapter.fromJsonTree(jsonObject)
-                } else {
-                    entityBundleAdapter.fromJsonTree(jsonObject)
-                }
-            }
-        }
-    }
-
-    /**
-     * A exception indicating a schema file being read was empty.
-     */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
-    public class EmptySchemaException : IllegalStateException("Empty schema file")
 }
diff --git a/room/room-migration/src/jvmTest/kotlin/androidx/room/migration/bundle/DatabaseBundleTest.kt b/room/room-migration/src/jvmTest/kotlin/androidx/room/migration/bundle/DatabaseBundleTest.kt
deleted file mode 100644
index 7726687..0000000
--- a/room/room-migration/src/jvmTest/kotlin/androidx/room/migration/bundle/DatabaseBundleTest.kt
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright 2018 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.migration.bundle
-
-import org.hamcrest.CoreMatchers.`is`
-import org.hamcrest.MatcherAssert.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-
-@RunWith(JUnit4::class)
-class DatabaseBundleTest {
-
-    @Test
-    fun buildCreateQueries_noFts() {
-        val entity1 = EntityBundle("e1", "sq1",
-                listOf(createFieldBundle("foo1"), createFieldBundle("bar")),
-                PrimaryKeyBundle(false, listOf("foo1")),
-                emptyList(),
-                emptyList())
-        val entity2 = EntityBundle("e2", "sq2",
-            listOf(createFieldBundle("foo2"), createFieldBundle("bar")),
-                PrimaryKeyBundle(false, listOf("foo2")),
-                emptyList(),
-                emptyList())
-        val bundle = DatabaseBundle(1, "hash",
-            listOf(entity1, entity2), emptyList(),
-                emptyList())
-
-        assertThat(bundle.buildCreateQueries(), `is`(listOf("sq1", "sq2")))
-    }
-
-    @Test
-    fun buildCreateQueries_withFts() {
-        val entity1 = EntityBundle("e1", "sq1",
-            listOf(createFieldBundle("foo1"), createFieldBundle("bar")),
-                PrimaryKeyBundle(false, listOf("foo1")),
-                emptyList(),
-                emptyList())
-        val entity2 = FtsEntityBundle("e2", "sq2",
-            listOf(createFieldBundle("foo2"), createFieldBundle("bar")),
-                PrimaryKeyBundle(false, listOf("foo2")),
-                "FTS4",
-                createFtsOptionsBundle(""),
-                emptyList())
-        val entity3 = EntityBundle("e3", "sq3",
-            listOf(createFieldBundle("foo3"), createFieldBundle("bar")),
-                PrimaryKeyBundle(false, listOf("foo3")),
-                emptyList(),
-                emptyList())
-        val bundle = DatabaseBundle(1, "hash",
-            listOf(entity1, entity2, entity3), emptyList(),
-                emptyList())
-
-        assertThat(bundle.buildCreateQueries(), `is`(listOf("sq1", "sq2", "sq3")))
-    }
-
-    @Test
-    fun buildCreateQueries_withExternalContentFts() {
-        val entity1 = EntityBundle("e1", "sq1",
-            listOf(createFieldBundle("foo1"), createFieldBundle("bar")),
-                PrimaryKeyBundle(false, listOf("foo1")),
-                emptyList(),
-                emptyList())
-        val entity2 = FtsEntityBundle("e2", "sq2",
-            listOf(createFieldBundle("foo2"), createFieldBundle("bar")),
-                PrimaryKeyBundle(false, listOf("foo2")),
-                "FTS4",
-                createFtsOptionsBundle("e3"),
-            listOf("e2_trig"))
-        val entity3 = EntityBundle("e3", "sq3",
-        listOf(createFieldBundle("foo3"), createFieldBundle("bar")),
-                PrimaryKeyBundle(false, listOf("foo3")),
-                emptyList(),
-                emptyList())
-        val bundle = DatabaseBundle(
-            1,
-            "hash",
-            listOf(entity1, entity2, entity3),
-            emptyList(),
-            emptyList()
-        )
-
-        assertThat(bundle.buildCreateQueries(), `is`(listOf("sq1", "sq3", "sq2", "e2_trig")))
-    }
-
-    @Test
-    fun schemaEquality_missingView_notEqual() {
-        val entity = EntityBundle("e", "sq",
-            listOf(createFieldBundle("foo"), createFieldBundle("bar")),
-            PrimaryKeyBundle(false, listOf("foo")),
-            emptyList(),
-            emptyList())
-        val view = DatabaseViewBundle("bar", "sq")
-        val bundle1 = DatabaseBundle(1, "hash",
-            listOf(entity), emptyList(),
-            emptyList())
-        val bundle2 = DatabaseBundle(1, "hash",
-            listOf(entity), listOf(view),
-            emptyList())
-        assertThat(bundle1.isSchemaEqual(bundle2), `is`(false))
-    }
-
-    private fun createFieldBundle(name: String): FieldBundle {
-        return FieldBundle("foo", name, "text", false, null)
-    }
-
-    private fun createFtsOptionsBundle(contentTableName: String): FtsOptionsBundle {
-        return FtsOptionsBundle("", emptyList(), contentTableName,
-                "", "", emptyList(), emptyList(), "")
-    }
-}
diff --git a/room/room-migration/src/jvmTest/kotlin/androidx/room/migration/bundle/EntityBundleTest.kt b/room/room-migration/src/jvmTest/kotlin/androidx/room/migration/bundle/EntityBundleTest.kt
deleted file mode 100644
index 53e2b1e..0000000
--- a/room/room-migration/src/jvmTest/kotlin/androidx/room/migration/bundle/EntityBundleTest.kt
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright 2017 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.migration.bundle
-
-import org.hamcrest.CoreMatchers.`is`
-import org.hamcrest.MatcherAssert.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-
-@SuppressWarnings("ArraysAsListWithZeroOrOneArgument")
-@RunWith(JUnit4::class)
-class EntityBundleTest {
-    @Test
-    fun schemaEquality_same_equal() {
-        val bundle = EntityBundle("foo", "sq",
-                listOf(createFieldBundle("foo"), createFieldBundle("bar")),
-            PrimaryKeyBundle(false, listOf("foo")),
-        listOf(createIndexBundle("foo")),
-        listOf(createForeignKeyBundle("bar", "foo")))
-
-        val other = EntityBundle("foo", "sq",
-            listOf(createFieldBundle("foo"), createFieldBundle("bar")),
-            PrimaryKeyBundle(false, listOf("foo")),
-        listOf(createIndexBundle("foo")),
-        listOf(createForeignKeyBundle("bar", "foo")))
-
-        assertThat(bundle.isSchemaEqual(other), `is`(true))
-    }
-
-    @Test
-    fun schemaEquality_reorderedFields_equal() {
-        val bundle = EntityBundle("foo", "sq",
-            listOf(createFieldBundle("foo"), createFieldBundle("bar")),
-            PrimaryKeyBundle(false, listOf("foo")),
-                emptyList(),
-                emptyList())
-
-        val other = EntityBundle("foo", "sq",
-            listOf(createFieldBundle("bar"), createFieldBundle("foo")),
-            PrimaryKeyBundle(false, listOf("foo")),
-                emptyList(),
-                emptyList())
-
-        assertThat(bundle.isSchemaEqual(other), `is`(true))
-    }
-
-    @Test
-    fun schemaEquality_diffFields_notEqual() {
-        val bundle = EntityBundle("foo", "sq",
-            listOf(createFieldBundle("foo"), createFieldBundle("bar")),
-                PrimaryKeyBundle(false, listOf("foo")),
-                emptyList(),
-                emptyList())
-
-        val other = EntityBundle("foo", "sq",
-            listOf(createFieldBundle("foo2"), createFieldBundle("bar")),
-            PrimaryKeyBundle(false, listOf("foo")),
-                emptyList(),
-                emptyList())
-
-        assertThat(bundle.isSchemaEqual(other), `is`(false))
-    }
-
-    @Test
-    fun schemaEquality_reorderedForeignKeys_equal() {
-        val bundle = EntityBundle("foo", "sq",
-                emptyList(),
-                PrimaryKeyBundle(false, listOf("foo")),
-                emptyList(),
-            listOf(createForeignKeyBundle("x", "y"),
-                        createForeignKeyBundle("bar", "foo")))
-
-        val other = EntityBundle("foo", "sq",
-                emptyList(),
-                PrimaryKeyBundle(false, listOf("foo")),
-                emptyList(),
-            listOf(createForeignKeyBundle("bar", "foo"),
-                        createForeignKeyBundle("x", "y")))
-        assertThat(bundle.isSchemaEqual(other), `is`(true))
-    }
-
-    @Test
-    fun schemaEquality_diffForeignKeys_notEqual() {
-        val bundle = EntityBundle("foo", "sq",
-                emptyList(),
-                PrimaryKeyBundle(false, listOf("foo")),
-                emptyList(),
-            listOf(createForeignKeyBundle("bar", "foo")))
-
-        val other = EntityBundle("foo", "sq",
-                emptyList(),
-            PrimaryKeyBundle(false, listOf("foo")),
-                emptyList(),
-            listOf(createForeignKeyBundle("bar2", "foo")))
-
-        assertThat(bundle.isSchemaEqual(other), `is`(false))
-    }
-
-    @Test
-    fun schemaEquality_reorderedIndices_equal() {
-        val bundle = EntityBundle("foo", "sq",
-                emptyList(),
-                PrimaryKeyBundle(false, listOf("foo")),
-            listOf(createIndexBundle("foo"), createIndexBundle("baz")),
-                emptyList())
-
-        val other = EntityBundle("foo", "sq",
-                emptyList(),
-                PrimaryKeyBundle(false, listOf("foo")),
-            listOf(createIndexBundle("baz"), createIndexBundle("foo")),
-                emptyList())
-
-        assertThat(bundle.isSchemaEqual(other), `is`(true))
-    }
-
-    @Test
-    fun schemaEquality_diffIndices_notEqual() {
-        val bundle = EntityBundle("foo", "sq",
-                emptyList(),
-                PrimaryKeyBundle(false, listOf("foo")),
-            listOf(createIndexBundle("foo")),
-                emptyList())
-
-        val other = EntityBundle("foo", "sq",
-                emptyList(),
-                PrimaryKeyBundle(false, listOf("foo")),
-            listOf(createIndexBundle("foo2")),
-                emptyList())
-
-        assertThat(bundle.isSchemaEqual(other), `is`(false))
-    }
-
-    private fun createFieldBundle(name: String): FieldBundle {
-        return FieldBundle("foo", name, "text", false, null)
-    }
-
-    private fun createIndexBundle(colName: String): IndexBundle {
-        return IndexBundle(
-            "ind_$colName", false,
-            listOf(colName), emptyList(), "create")
-    }
-
-    private fun createForeignKeyBundle(targetTable: String, column: String): ForeignKeyBundle {
-        return ForeignKeyBundle(targetTable, "CASCADE", "CASCADE",
-            listOf(column), listOf(column))
-    }
-}
diff --git a/room/room-migration/src/jvmTest/kotlin/androidx/room/migration/bundle/FieldBundleTest.kt b/room/room-migration/src/jvmTest/kotlin/androidx/room/migration/bundle/FieldBundleTest.kt
deleted file mode 100644
index 0dccf46..0000000
--- a/room/room-migration/src/jvmTest/kotlin/androidx/room/migration/bundle/FieldBundleTest.kt
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright 2017 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.migration.bundle
-
-import org.hamcrest.CoreMatchers.`is`
-import org.hamcrest.MatcherAssert.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-
-@RunWith(JUnit4::class)
-class FieldBundleTest {
-    @Test
-    fun schemaEquality_same_equal() {
-        val bundle = FieldBundle("foo", "foo", "text", false, null)
-        val copy = FieldBundle("foo", "foo", "text", false, null)
-        assertThat(bundle.isSchemaEqual(copy), `is`(true))
-    }
-
-    @Test
-    fun schemaEquality_diffNonNull_notEqual() {
-        val bundle = FieldBundle("foo", "foo", "text", false, null)
-        val copy = FieldBundle("foo", "foo", "text", true, null)
-        assertThat(bundle.isSchemaEqual(copy), `is`(false))
-    }
-
-    @Test
-    fun schemaEquality_diffColumnName_notEqual() {
-        val bundle = FieldBundle("foo", "foo", "text", false, null)
-        val copy = FieldBundle("foo", "foo2", "text", true, null)
-        assertThat(bundle.isSchemaEqual(copy), `is`(false))
-    }
-
-    @Test
-    fun schemaEquality_diffAffinity_notEqual() {
-        val bundle = FieldBundle("foo", "foo", "text", false, null)
-        val copy = FieldBundle("foo", "foo2", "int", false, null)
-        assertThat(bundle.isSchemaEqual(copy), `is`(false))
-    }
-
-    @Test
-    fun schemaEquality_diffPath_equal() {
-        val bundle = FieldBundle("foo", "foo", "text", false, null)
-        val copy = FieldBundle("foo>bar", "foo", "text", false, null)
-        assertThat(bundle.isSchemaEqual(copy), `is`(true))
-    }
-
-    @Test
-    fun schemeEquality_diffDefaultValue_notEqual() {
-        val bundle = FieldBundle("foo", "foo", "text", true, null)
-        val copy = FieldBundle("foo", "foo", "text", true, "bar")
-        assertThat(bundle.isSchemaEqual(copy), `is`(false))
-    }
-}
diff --git a/room/room-migration/src/jvmTest/kotlin/androidx/room/migration/bundle/ForeignKeyBundleTest.kt b/room/room-migration/src/jvmTest/kotlin/androidx/room/migration/bundle/ForeignKeyBundleTest.kt
deleted file mode 100644
index fd9e8e1..0000000
--- a/room/room-migration/src/jvmTest/kotlin/androidx/room/migration/bundle/ForeignKeyBundleTest.kt
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright 2017 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.migration.bundle
-
-import org.hamcrest.CoreMatchers.`is`
-import org.hamcrest.MatcherAssert.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-
-@RunWith(JUnit4::class)
-class ForeignKeyBundleTest {
-    @Test
-    fun schemaEquality_same_equal() {
-        val bundle = ForeignKeyBundle("table", "onDelete",
-                "onUpdate", listOf("col1", "col2"),
-                listOf("target1", "target2")
-        )
-        val other = ForeignKeyBundle("table", "onDelete",
-                "onUpdate", listOf("col1", "col2"),
-            listOf("target1", "target2"))
-        assertThat(bundle.isSchemaEqual(other), `is`(true))
-    }
-
-    @Test
-    fun schemaEquality_diffTable_notEqual() {
-        val bundle = ForeignKeyBundle("table", "onDelete",
-                "onUpdate", listOf("col1", "col2"),
-            listOf("target1", "target2"))
-        val other = ForeignKeyBundle("table2", "onDelete",
-                "onUpdate", listOf("col1", "col2"),
-            listOf("target1", "target2"))
-        assertThat(bundle.isSchemaEqual(other), `is`(false))
-    }
-
-    @Test
-    fun schemaEquality_diffOnDelete_notEqual() {
-        val bundle = ForeignKeyBundle("table", "onDelete2",
-                "onUpdate", listOf("col1", "col2"),
-            listOf("target1", "target2"))
-        val other = ForeignKeyBundle("table", "onDelete",
-                "onUpdate", listOf("col1", "col2"),
-            listOf("target1", "target2"))
-        assertThat(bundle.isSchemaEqual(other), `is`(false))
-    }
-
-    @Test
-    fun schemaEquality_diffOnUpdate_notEqual() {
-        val bundle = ForeignKeyBundle("table", "onDelete",
-                "onUpdate", listOf("col1", "col2"),
-            listOf("target1", "target2"))
-        val other = ForeignKeyBundle("table", "onDelete",
-                "onUpdate2", listOf("col1", "col2"),
-            listOf("target1", "target2"))
-        assertThat(bundle.isSchemaEqual(other), `is`(false))
-    }
-
-    @Test
-    fun schemaEquality_diffSrcOrder_notEqual() {
-        val bundle = ForeignKeyBundle("table", "onDelete",
-                "onUpdate", listOf("col2", "col1"),
-            listOf("target1", "target2"))
-        val other = ForeignKeyBundle("table", "onDelete",
-                "onUpdate", listOf("col1", "col2"),
-            listOf("target1", "target2"))
-        assertThat(bundle.isSchemaEqual(other), `is`(false))
-    }
-
-    @Test
-    fun schemaEquality_diffTargetOrder_notEqual() {
-        val bundle = ForeignKeyBundle("table", "onDelete",
-                "onUpdate", listOf("col1", "col2"),
-            listOf("target1", "target2"))
-        val other = ForeignKeyBundle("table", "onDelete",
-                "onUpdate", listOf("col1", "col2"),
-            listOf("target2", "target1"))
-        assertThat(bundle.isSchemaEqual(other), `is`(false))
-    }
-}
diff --git a/room/room-migration/src/jvmTest/kotlin/androidx/room/migration/bundle/IndexBundleTest.kt b/room/room-migration/src/jvmTest/kotlin/androidx/room/migration/bundle/IndexBundleTest.kt
deleted file mode 100644
index a6451ce..0000000
--- a/room/room-migration/src/jvmTest/kotlin/androidx/room/migration/bundle/IndexBundleTest.kt
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright 2017 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.migration.bundle
-
-import org.hamcrest.CoreMatchers.`is`
-import org.hamcrest.MatcherAssert.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-
-@RunWith(JUnit4::class)
-class IndexBundleTest {
-    @Test
-    fun schemaEquality_same_equal() {
-        val bundle = IndexBundle("index1", false,
-            listOf("col1", "col2"), listOf("ASC", "ASC"), "sql")
-        val other = IndexBundle("index1", false,
-            listOf("col1", "col2"), listOf("ASC", "ASC"), "sql")
-        assertThat(bundle.isSchemaEqual(other), `is`(true))
-    }
-
-    @Test
-    fun schemaEquality_diffName_notEqual() {
-        val bundle = IndexBundle("index1", false,
-            listOf("col1", "col2"), listOf("ASC", "ASC"), "sql")
-        val other = IndexBundle("index3", false,
-            listOf("col1", "col2"), listOf("ASC", "ASC"), "sql")
-        assertThat(bundle.isSchemaEqual(other), `is`(false))
-    }
-
-    @Test
-    fun schemaEquality_diffGenericName_equal() {
-        val bundle = IndexBundle(IndexBundle.DEFAULT_PREFIX + "x", false,
-            listOf("col1", "col2"), listOf("ASC", "ASC"), "sql")
-        val other = IndexBundle(IndexBundle.DEFAULT_PREFIX + "y", false,
-            listOf("col1", "col2"), listOf("ASC", "ASC"), "sql")
-        assertThat(bundle.isSchemaEqual(other), `is`(true))
-    }
-
-    @Test
-    fun schemaEquality_diffUnique_notEqual() {
-        val bundle = IndexBundle("index1", false,
-            listOf("col1", "col2"), listOf("ASC", "ASC"), "sql")
-        val other = IndexBundle("index1", true,
-            listOf("col1", "col2"), listOf("ASC", "ASC"), "sql")
-        assertThat(bundle.isSchemaEqual(other), `is`(false))
-    }
-
-    @Test
-    fun schemaEquality_diffColumns_notEqual() {
-        val bundle = IndexBundle("index1", false,
-            listOf("col1", "col2"), listOf("ASC", "ASC"), "sql")
-        val other = IndexBundle("index1", false,
-            listOf("col2", "col1"), listOf("ASC", "ASC"), "sql")
-        assertThat(bundle.isSchemaEqual(other), `is`(false))
-    }
-
-    @Test
-    fun schemaEquality_diffSql_equal() {
-        val bundle = IndexBundle("index1", false,
-            listOf("col1", "col2"), listOf("ASC", "ASC"), "sql")
-        val other = IndexBundle("index1", false,
-            listOf("col1", "col2"), listOf("ASC", "ASC"), "sql22")
-        assertThat(bundle.isSchemaEqual(other), `is`(true))
-    }
-
-    @Test
-    fun schemaEquality_diffSort_notEqual() {
-        val bundle = IndexBundle("index1", false,
-            listOf("col1", "col2"), listOf("ASC", "DESC"), "sql")
-        val other = IndexBundle("index1", false,
-            listOf("col1", "col2"), listOf("DESC", "ASC"), "sql")
-        assertThat(bundle.isSchemaEqual(other), `is`(false))
-    }
-
-    @Test
-    fun schemaEquality_sortNullVsAllAsc_isEqual() {
-        val bundle = IndexBundle("index1", false,
-            listOf("col1", "col2"), listOf("ASC", "ASC"), "sql")
-        val other = IndexBundle("index1", false,
-            listOf("col1", "col2"), null, "sql")
-        assertThat(bundle.isSchemaEqual(other), `is`(true))
-    }
-
-    @Test
-    fun schemaEquality_sortEmptyVsAllAsc_isEqual() {
-        val bundle = IndexBundle("index1", false,
-            listOf("col1", "col2"), listOf("ASC", "ASC"), "sql")
-        val other = IndexBundle("index1", false,
-            listOf("col1", "col2"), emptyList(), "sql")
-        assertThat(bundle.isSchemaEqual(other), `is`(true))
-    }
-}
diff --git a/room/room-migration/src/jvmTest/kotlin/androidx/room/migration/bundle/PrimaryKeyBundleTest.kt b/room/room-migration/src/jvmTest/kotlin/androidx/room/migration/bundle/PrimaryKeyBundleTest.kt
deleted file mode 100644
index 8b43988..0000000
--- a/room/room-migration/src/jvmTest/kotlin/androidx/room/migration/bundle/PrimaryKeyBundleTest.kt
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2017 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.migration.bundle
-
-import org.hamcrest.CoreMatchers.`is`
-import org.hamcrest.MatcherAssert.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-
-@RunWith(JUnit4::class)
-class PrimaryKeyBundleTest {
-    @Test
-    fun schemaEquality_same_equal() {
-        val bundle = PrimaryKeyBundle(true,
-                listOf("foo", "bar")
-        )
-        val other = PrimaryKeyBundle(true,
-            listOf("foo", "bar"))
-        assertThat(bundle.isSchemaEqual(other), `is`(true))
-    }
-
-    @Test
-    fun schemaEquality_diffAutoGen_notEqual() {
-        val bundle = PrimaryKeyBundle(true,
-            listOf("foo", "bar"))
-        val other = PrimaryKeyBundle(false,
-            listOf("foo", "bar"))
-        assertThat(bundle.isSchemaEqual(other), `is`(false))
-    }
-
-    @Test
-    fun schemaEquality_diffColumns_notEqual() {
-        val bundle = PrimaryKeyBundle(true,
-            listOf("foo", "baz"))
-        val other = PrimaryKeyBundle(true,
-            listOf("foo", "bar"))
-        assertThat(bundle.isSchemaEqual(other), `is`(false))
-    }
-
-   @Test
-   fun schemaEquality_diffColumnOrder_notEqual() {
-        val bundle = PrimaryKeyBundle(true,
-            listOf("foo", "bar"))
-        val other = PrimaryKeyBundle(true,
-            listOf("bar", "foo"))
-        assertThat(bundle.isSchemaEqual(other), `is`(false))
-    }
-}
diff --git a/room/room-migration/src/jvmTest/kotlin/androidx/room/migration/bundle/SerializationTest.kt b/room/room-migration/src/jvmTest/kotlin/androidx/room/migration/bundle/SerializationTest.kt
new file mode 100644
index 0000000..7bd26e0
--- /dev/null
+++ b/room/room-migration/src/jvmTest/kotlin/androidx/room/migration/bundle/SerializationTest.kt
@@ -0,0 +1,47 @@
+/*
+ * 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.migration.bundle
+
+import androidx.kruth.assertThrows
+import java.io.ByteArrayInputStream
+import java.io.FileInputStream
+import java.io.FileNotFoundException
+import kotlin.test.Test
+import kotlinx.serialization.SerializationException
+
+class SerializationTest {
+
+    @Test
+    fun emptyStream() {
+        // GSON had a specific exception for an empty file, but with Kotlin serialization it is
+        // as any other serialization exception. We have a test for this since we expect the
+        // exception to properly report an error in the annotation processor.
+        assertThrows<SerializationException> {
+            SchemaBundle.deserialize(ByteArrayInputStream(byteArrayOf()))
+        }
+    }
+
+    @Test
+    fun fileNotFound() {
+        // This is mostly validating File streams throwing FileNotFoundException, but we expect
+        // such exception when the schema file does not exist to properly report an error
+        // in the annotation processor.
+        assertThrows<FileNotFoundException> {
+            FileInputStream("/fake/file/path").use { SchemaBundle.deserialize(it) }
+        }
+    }
+}
diff --git a/room/room-migration/src/nativeMain/kotlin/androidx/room/migration/bundle/SchemaBundle.native.kt b/room/room-migration/src/nativeMain/kotlin/androidx/room/migration/bundle/SchemaBundle.native.kt
new file mode 100644
index 0000000..41b8b2e
--- /dev/null
+++ b/room/room-migration/src/nativeMain/kotlin/androidx/room/migration/bundle/SchemaBundle.native.kt
@@ -0,0 +1,36 @@
+/*
+ * 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.migration.bundle
+
+import androidx.annotation.RestrictTo
+import kotlinx.serialization.SerialName
+import kotlinx.serialization.Serializable
+
+@Serializable
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+actual class SchemaBundle actual constructor(
+    @SerialName("formatVersion")
+    actual val formatVersion: Int,
+    @SerialName("database")
+    actual val database: DatabaseBundle
+) : SchemaEquality<SchemaBundle> {
+
+    actual override fun isSchemaEqual(other: SchemaBundle): Boolean {
+        return formatVersion == other.formatVersion &&
+            SchemaEqualityUtil.checkSchemaEquality(database, other.database)
+    }
+}
diff --git a/room/room-runtime/api/restricted_current.txt b/room/room-runtime/api/restricted_current.txt
index dfc296a..c946c21 100644
--- a/room/room-runtime/api/restricted_current.txt
+++ b/room/room-runtime/api/restricted_current.txt
@@ -2,14 +2,14 @@
 package androidx.room {
 
   @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final class CoroutinesRoom {
-    method public static <R> kotlinx.coroutines.flow.Flow<R> createFlow(androidx.room.RoomDatabase db, boolean inTransaction, String[] tableNames, java.util.concurrent.Callable<R> callable);
+    method @Deprecated public static <R> kotlinx.coroutines.flow.Flow<R> createFlow(androidx.room.RoomDatabase db, boolean inTransaction, String[] tableNames, java.util.concurrent.Callable<R> callable);
     method @Deprecated public static suspend <R> Object? execute(androidx.room.RoomDatabase db, boolean inTransaction, android.os.CancellationSignal? cancellationSignal, java.util.concurrent.Callable<R> callable, kotlin.coroutines.Continuation<? super R>);
     method @Deprecated public static suspend <R> Object? execute(androidx.room.RoomDatabase db, boolean inTransaction, java.util.concurrent.Callable<R> callable, kotlin.coroutines.Continuation<? super R>);
     field public static final androidx.room.CoroutinesRoom.Companion Companion;
   }
 
   public static final class CoroutinesRoom.Companion {
-    method public <R> kotlinx.coroutines.flow.Flow<R> createFlow(androidx.room.RoomDatabase db, boolean inTransaction, String[] tableNames, java.util.concurrent.Callable<R> callable);
+    method @Deprecated public <R> kotlinx.coroutines.flow.Flow<R> createFlow(androidx.room.RoomDatabase db, boolean inTransaction, String[] tableNames, java.util.concurrent.Callable<R> callable);
     method @Deprecated public suspend <R> Object? execute(androidx.room.RoomDatabase db, boolean inTransaction, android.os.CancellationSignal? cancellationSignal, java.util.concurrent.Callable<R> callable, kotlin.coroutines.Continuation<? super R>);
     method @Deprecated public suspend <R> Object? execute(androidx.room.RoomDatabase db, boolean inTransaction, java.util.concurrent.Callable<R> callable, kotlin.coroutines.Continuation<? super R>);
   }
@@ -392,6 +392,14 @@
 
 }
 
+package androidx.room.coroutines {
+
+  public final class FlowUtil {
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static <R> kotlinx.coroutines.flow.Flow<R> createFlow(androidx.room.RoomDatabase db, boolean inTransaction, String[] tableNames, kotlin.jvm.functions.Function1<? super androidx.sqlite.SQLiteConnection,? extends R> block);
+  }
+
+}
+
 package androidx.room.migration {
 
   public interface AutoMigrationSpec {
diff --git a/room/room-runtime/build.gradle b/room/room-runtime/build.gradle
index 2de218e..b2fa665 100644
--- a/room/room-runtime/build.gradle
+++ b/room/room-runtime/build.gradle
@@ -22,12 +22,12 @@
  * modifying its settings.
  */
 
+
 import androidx.build.LibraryType
 import androidx.build.PlatformIdentifier
 import androidx.build.Publish
-import androidx.build.SdkHelperKt
 import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
-import org.jetbrains.kotlin.konan.target.KonanTarget
+import org.jetbrains.kotlin.konan.target.Family
 
 plugins {
     id("AndroidXPlugin")
@@ -198,14 +198,11 @@
                 test.defaultSourceSet {
                     dependsOn(nativeTest)
                 }
-                if (target.konanTarget == KonanTarget.LINUX_X64.INSTANCE) {
+                if (target.konanTarget.family == Family.LINUX) {
                     // For tests in Linux host, statically include androidx's compiled SQLite
                     // via a generated C interop definition
                     createCinteropFromArchiveConfiguration(test, configurations["sqliteSharedArchive"])
-                } else if (
-                        target.konanTarget == KonanTarget.MACOS_X64.INSTANCE ||
-                                target.konanTarget == KonanTarget.MACOS_ARM64.INSTANCE
-                ) {
+                } else if (target.konanTarget.family == Family.OSX) {
                     // For tests in Mac host, link to shared SQLite library included in MacOS
                     test.kotlinOptions.freeCompilerArgs += [
                             "-linker-options", "-lsqlite3"
diff --git a/room/room-runtime/src/androidMain/kotlin/androidx/room/CoroutinesRoom.android.kt b/room/room-runtime/src/androidMain/kotlin/androidx/room/CoroutinesRoom.android.kt
index 84ff12e..dfd95da 100644
--- a/room/room-runtime/src/androidMain/kotlin/androidx/room/CoroutinesRoom.android.kt
+++ b/room/room-runtime/src/androidMain/kotlin/androidx/room/CoroutinesRoom.android.kt
@@ -18,16 +18,12 @@
 
 import android.os.CancellationSignal
 import androidx.annotation.RestrictTo
+import androidx.room.coroutines.createFlow as createFlowCommon
 import androidx.room.util.getCoroutineContext
 import java.util.concurrent.Callable
 import kotlin.coroutines.resume
 import kotlin.coroutines.resumeWithException
-import kotlinx.coroutines.Job
-import kotlinx.coroutines.channels.Channel
-import kotlinx.coroutines.coroutineScope
 import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.emitAll
-import kotlinx.coroutines.flow.flow
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.suspendCancellableCoroutine
 import kotlinx.coroutines.withContext
@@ -88,41 +84,13 @@
         }
 
         @JvmStatic
+        @Deprecated("No longer called by generated implementation")
         public fun <R> createFlow(
             db: RoomDatabase,
             inTransaction: Boolean,
             tableNames: Array<String>,
             callable: Callable<R>
-        ): Flow<@JvmSuppressWildcards R> = flow {
-            coroutineScope {
-                // Observer channel receives signals from the invalidation tracker to emit queries.
-                val observerChannel = Channel<Unit>(Channel.CONFLATED)
-                val observer = object : InvalidationTracker.Observer(tableNames) {
-                    override fun onInvalidated(tables: Set<String>) {
-                        observerChannel.trySend(Unit)
-                    }
-                }
-                observerChannel.trySend(Unit) // Initial signal to perform first query.
-                // Use the database context minus the Job since the collector already has one and
-                // the child coroutine should be tied to it.
-                val queryContext = db.getCoroutineContext(inTransaction).minusKey(Job)
-                val resultChannel = Channel<R>()
-                launch(queryContext) {
-                    db.invalidationTracker.addObserver(observer)
-                    try {
-                        // Iterate until cancelled, transforming observer signals to query results
-                        // to be emitted to the flow.
-                        for (signal in observerChannel) {
-                            val result = callable.call()
-                            resultChannel.send(result)
-                        }
-                    } finally {
-                        db.invalidationTracker.removeObserver(observer)
-                    }
-                }
-
-                emitAll(resultChannel)
-            }
-        }
+        ): Flow<@JvmSuppressWildcards R> =
+            createFlowCommon(db, inTransaction, tableNames) { callable.call() }
     }
 }
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 6b3c7ae..91413b4 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
@@ -198,7 +198,7 @@
     private class SupportConnectionPool(
         val supportDriver: SupportSQLiteDriver
     ) : ConnectionPool {
-        private val supportConnection by lazy(LazyThreadSafetyMode.NONE) {
+        private val supportConnection by lazy(LazyThreadSafetyMode.PUBLICATION) {
             SupportPooledConnection(supportDriver.open())
         }
 
diff --git a/room/room-runtime/src/commonMain/kotlin/androidx/room/coroutines/FlowBuilder.kt b/room/room-runtime/src/commonMain/kotlin/androidx/room/coroutines/FlowBuilder.kt
new file mode 100644
index 0000000..658fcde
--- /dev/null
+++ b/room/room-runtime/src/commonMain/kotlin/androidx/room/coroutines/FlowBuilder.kt
@@ -0,0 +1,73 @@
+/*
+ * 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("FlowUtil")
+
+package androidx.room.coroutines
+
+import androidx.annotation.RestrictTo
+import androidx.room.InvalidationTracker
+import androidx.room.RoomDatabase
+import androidx.room.util.getCoroutineContext
+import androidx.room.util.internalPerform
+import androidx.sqlite.SQLiteConnection
+import kotlin.jvm.JvmName
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.channels.Channel
+import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.emitAll
+import kotlinx.coroutines.flow.flow
+import kotlinx.coroutines.launch
+
+// TODO(b/329315924): Migrate to Flow based machinery.
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+fun <R> createFlow(
+    db: RoomDatabase,
+    inTransaction: Boolean,
+    tableNames: Array<String>,
+    block: (SQLiteConnection) -> R
+): Flow<R> = flow {
+    coroutineScope {
+        // Observer channel receives signals from the invalidation tracker to emit queries.
+        val observerChannel = Channel<Unit>(Channel.CONFLATED)
+        val observer = object : InvalidationTracker.Observer(tableNames) {
+            override fun onInvalidated(tables: Set<String>) {
+                observerChannel.trySend(Unit)
+            }
+        }
+        observerChannel.trySend(Unit) // Initial signal to perform first query.
+        val resultChannel = Channel<R>()
+        launch(db.getCoroutineContext(inTransaction).minusKey(Job)) {
+            db.invalidationTracker.subscribe(observer)
+            try {
+                // Iterate until cancelled, transforming observer signals to query results
+                // to be emitted to the flow.
+                for (signal in observerChannel) {
+                    val result = db.internalPerform(true, inTransaction) { connection ->
+                        val rawConnection = (connection as RawConnectionAccessor).rawConnection
+                        block.invoke(rawConnection)
+                    }
+                    resultChannel.send(result)
+                }
+            } finally {
+                db.invalidationTracker.unsubscribe(observer)
+            }
+        }
+
+        emitAll(resultChannel)
+    }
+}
diff --git a/room/room-testing/src/androidMain/kotlin/androidx/room/testing/BundleUtil.android.kt b/room/room-testing/src/androidMain/kotlin/androidx/room/testing/BundleUtil.android.kt
index 96ef65a..9bde741 100644
--- a/room/room-testing/src/androidMain/kotlin/androidx/room/testing/BundleUtil.android.kt
+++ b/room/room-testing/src/androidMain/kotlin/androidx/room/testing/BundleUtil.android.kt
@@ -20,6 +20,7 @@
 package androidx.room.testing
 
 import androidx.annotation.RestrictTo
+import androidx.room.migration.bundle.BaseEntityBundle
 import androidx.room.migration.bundle.DatabaseViewBundle
 import androidx.room.migration.bundle.EntityBundle
 import androidx.room.migration.bundle.FieldBundle
@@ -62,8 +63,8 @@
         TableInfo.Index(
             name = bundle.name,
             unique = bundle.isUnique,
-            columns = bundle.columnNames!!,
-            orders = bundle.orders!!
+            columns = bundle.columnNames ?: emptyList(),
+            orders = bundle.orders ?: emptyList()
         )
     }.toSet()
     return result
@@ -85,7 +86,7 @@
     return result
 }
 
-private fun EntityBundle.toColumnNamesSet(): Set<String> {
+private fun BaseEntityBundle.toColumnNamesSet(): Set<String> {
     return this.fields.map { field -> field.columnName }.toSet()
 }
 
diff --git a/room/room-testing/src/androidMain/kotlin/androidx/room/testing/MigrationTestHelper.android.kt b/room/room-testing/src/androidMain/kotlin/androidx/room/testing/MigrationTestHelper.android.kt
index c571f9b..0d34fda 100644
--- a/room/room-testing/src/androidMain/kotlin/androidx/room/testing/MigrationTestHelper.android.kt
+++ b/room/room-testing/src/androidMain/kotlin/androidx/room/testing/MigrationTestHelper.android.kt
@@ -26,6 +26,7 @@
 import androidx.room.migration.AutoMigrationSpec
 import androidx.room.migration.Migration
 import androidx.room.migration.bundle.DatabaseBundle
+import androidx.room.migration.bundle.EntityBundle
 import androidx.room.migration.bundle.FtsEntityBundle
 import androidx.room.migration.bundle.SchemaBundle
 import androidx.room.migration.bundle.SchemaBundle.Companion.deserialize
@@ -474,13 +475,14 @@
         ): androidx.room.RoomOpenHelper.ValidationResult {
             val tables = mDatabaseBundle.entitiesByTableName
             tables.values.forEach { entity ->
-                if (entity is FtsEntityBundle) {
-                    val expected = entity.toFtsTableInfo()
-                    val found = FtsTableInfo.read(db, entity.tableName)
-                    if (expected != found) {
-                        return androidx.room.RoomOpenHelper.ValidationResult(
-                            false,
-                            """ ${expected.name.trimEnd()}
+                when (entity) {
+                    is EntityBundle -> {
+                        val expected = entity.toTableInfo()
+                        val found = TableInfo.read(db, entity.tableName)
+                        if (expected != found) {
+                            return androidx.room.RoomOpenHelper.ValidationResult(
+                                false,
+                                """ ${expected.name.trimEnd()}
                                 |
                                 |Expected:
                                 |
@@ -490,15 +492,16 @@
                                 |
                                 |$found
                             """.trimMargin()
-                        )
+                            )
+                        }
                     }
-                } else {
-                    val expected = entity.toTableInfo()
-                    val found = TableInfo.read(db, entity.tableName)
-                    if (expected != found) {
-                        return androidx.room.RoomOpenHelper.ValidationResult(
-                            false,
-                            """ ${expected.name.trimEnd()}
+                    is FtsEntityBundle -> {
+                        val expected = entity.toFtsTableInfo()
+                        val found = FtsTableInfo.read(db, entity.tableName)
+                        if (expected != found) {
+                            return androidx.room.RoomOpenHelper.ValidationResult(
+                                false,
+                                """ ${expected.name.trimEnd()}
                                 |
                                 |Expected:
                                 |
@@ -508,7 +511,8 @@
                                 |
                                 |$found
                             """.trimMargin()
-                        )
+                            )
+                        }
                     }
                 }
             }
diff --git a/sqlite/sqlite-framework/build.gradle b/sqlite/sqlite-framework/build.gradle
index 9f4c995..48334b2 100644
--- a/sqlite/sqlite-framework/build.gradle
+++ b/sqlite/sqlite-framework/build.gradle
@@ -21,10 +21,11 @@
  * Please use that script when creating a new project, rather than copying an existing project and
  * modifying its settings.
  */
+
 import androidx.build.PlatformIdentifier
 import androidx.build.Publish
 import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
-import org.jetbrains.kotlin.konan.target.KonanTarget
+import org.jetbrains.kotlin.konan.target.Family
 
 plugins {
     id("AndroidXPlugin")
@@ -119,14 +120,11 @@
                 test.defaultSourceSet {
                     dependsOn(nativeTest)
                 }
-                if (target.konanTarget == KonanTarget.LINUX_X64.INSTANCE) {
+                if (target.konanTarget.family == Family.LINUX) {
                     // For tests in Linux host, statically include androidx's compiled SQLite
                     // via a generated C interop definition
                     createCinteropFromArchiveConfiguration(test, configurations["sqliteSharedArchive"])
-                } else if (
-                    target.konanTarget == KonanTarget.MACOS_X64.INSTANCE ||
-                        target.konanTarget == KonanTarget.MACOS_ARM64.INSTANCE
-                ) {
+                } else if (target.konanTarget.family == Family.OSX) {
                     // For tests in Mac host, link to shared SQLite library included in MacOS
                     test.kotlinOptions.freeCompilerArgs += [
                         "-linker-options", "-lsqlite3"
diff --git a/stableaidl/stableaidl-gradle-plugin/build.gradle b/stableaidl/stableaidl-gradle-plugin/build.gradle
index efce547..13fded7 100644
--- a/stableaidl/stableaidl-gradle-plugin/build.gradle
+++ b/stableaidl/stableaidl-gradle-plugin/build.gradle
@@ -31,11 +31,18 @@
 
 apply from: "../../buildSrc/kotlin-dsl-dependency.gradle"
 
+configurations {
+    // Config for plugin classpath to be used during tests
+    testPlugin {
+        canBeConsumed = false
+        canBeResolved = true
+    }
+}
+
 dependencies {
     implementation(findGradleKotlinDsl())
     implementation(gradleApi())
     implementation(libs.androidGradlePluginApi)
-    implementation(libs.androidGradlePluginz) // Needed for BaseExtension, see b/268237729.
     implementation(libs.androidToolsCommon)
     implementation(libs.androidToolsRepository)
     implementation(libs.androidToolsSdkCommon)
@@ -44,6 +51,9 @@
     implementation(libs.guava)
     implementation(libs.kotlinStdlib)
 
+    testPlugin(libs.androidGradlePluginz)
+
+    testImplementation(libs.androidGradlePluginz)
     testImplementation(gradleTestKit())
     testImplementation(project(":internal-testutils-gradle-plugin"))
     testImplementation(libs.androidToolsAnalyticsProtos)
@@ -53,6 +63,10 @@
     testImplementation(libs.truth)
 }
 
+tasks.withType(PluginUnderTestMetadata.class).named("pluginUnderTestMetadata").configure {
+    it.pluginClasspath.from(configurations.testPlugin)
+}
+
 gradlePlugin {
     plugins {
         stableAidl {
diff --git a/stableaidl/stableaidl-gradle-plugin/lint-baseline.xml b/stableaidl/stableaidl-gradle-plugin/lint-baseline.xml
index 6ce5472..24cc85a 100644
--- a/stableaidl/stableaidl-gradle-plugin/lint-baseline.xml
+++ b/stableaidl/stableaidl-gradle-plugin/lint-baseline.xml
@@ -1,14 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.4.0-alpha09" type="baseline" client="gradle" dependencies="false" name="AGP (8.4.0-alpha09)" variant="all" version="8.4.0-alpha09">
-
-    <issue
-        id="InternalGradleApiUsage"
-        message="Avoid using internal Android Gradle Plugin APIs"
-        errorLine1="import com.android.build.gradle.internal.LoggerWrapper"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/stableaidl/internal/process/GradleProcessExecutor.kt"/>
-    </issue>
+<issues format="6" by="lint 8.4.0-alpha12" type="baseline" client="gradle" dependencies="false" name="AGP (8.4.0-alpha12)" variant="all" version="8.4.0-alpha12">
 
     <issue
         id="InternalGradleApiUsage"
diff --git a/stableaidl/stableaidl-gradle-plugin/src/main/java/androidx/stableaidl/StableAidlExtensionImpl.kt b/stableaidl/stableaidl-gradle-plugin/src/main/java/androidx/stableaidl/StableAidlExtensionImpl.kt
index fa45f3c..ed441f7 100644
--- a/stableaidl/stableaidl-gradle-plugin/src/main/java/androidx/stableaidl/StableAidlExtensionImpl.kt
+++ b/stableaidl/stableaidl-gradle-plugin/src/main/java/androidx/stableaidl/StableAidlExtensionImpl.kt
@@ -21,7 +21,6 @@
 import androidx.stableaidl.tasks.StableAidlCheckApi
 import androidx.stableaidl.tasks.UpdateStableAidlApiTask
 import com.android.build.api.variant.SourceDirectories
-import com.android.build.gradle.internal.tasks.factory.dependsOn
 import java.io.File
 import org.gradle.api.Task
 import org.gradle.api.tasks.TaskProvider
@@ -67,4 +66,14 @@
 
     internal val importSourceDirs = mutableListOf<SourceDirectories.Flat>()
     internal val allTasks = mutableMapOf<String, Set<TaskProvider<*>>>()
+
+    internal fun <T : Task> TaskProvider<out T>.dependsOn(
+        vararg tasks: TaskProvider<out Task>
+    ): TaskProvider<out T> {
+        if (tasks.isEmpty().not()) {
+            configure { it.dependsOn(*tasks) }
+        }
+
+        return this
+    }
 }
diff --git a/stableaidl/stableaidl-gradle-plugin/src/main/java/androidx/stableaidl/StableAidlPlugin.kt b/stableaidl/stableaidl-gradle-plugin/src/main/java/androidx/stableaidl/StableAidlPlugin.kt
index 754d5e4..6ea7e33 100644
--- a/stableaidl/stableaidl-gradle-plugin/src/main/java/androidx/stableaidl/StableAidlPlugin.kt
+++ b/stableaidl/stableaidl-gradle-plugin/src/main/java/androidx/stableaidl/StableAidlPlugin.kt
@@ -21,7 +21,6 @@
 import com.android.build.api.variant.AndroidComponentsExtension
 import com.android.build.api.variant.DslExtension
 import com.android.build.api.variant.Variant
-import com.android.build.gradle.BaseExtension
 import com.android.utils.usLocaleCapitalize
 import org.gradle.api.GradleException
 import org.gradle.api.Plugin
@@ -196,23 +195,9 @@
  */
 internal const val SOURCE_TYPE_STABLE_AIDL_IMPORTS = "stableAidlImports"
 
-internal fun SdkComponents.aidl(baseExtension: BaseExtension): Provider<RegularFile> =
-    sdkDirectory.map {
-        it.dir("build-tools").dir(baseExtension.buildToolsVersion).file(
-            if (java.lang.System.getProperty("os.name").startsWith("Windows")) {
-                "aidl.exe"
-            } else {
-                "aidl"
-            }
-        )
-    }
-
-internal fun SdkComponents.aidlFramework(baseExtension: BaseExtension): Provider<RegularFile> =
-    sdkDirectory.map {
-        it.dir("platforms")
-            .dir(baseExtension.compileSdkVersion!!)
-            .file("framework.aidl")
-    }
+internal fun SdkComponents.aidl(): Provider<RegularFile> =
+    @Suppress("UnstableApiUsage")
+    aidl.flatMap { it.executable }
 
 /**
  * Returns the AIDL import directories for the given variant of the project.
diff --git a/stableaidl/stableaidl-gradle-plugin/src/main/java/androidx/stableaidl/internal/process/GradleProcessExecutor.kt b/stableaidl/stableaidl-gradle-plugin/src/main/java/androidx/stableaidl/internal/process/GradleProcessExecutor.kt
index 76e13bd..d789156 100644
--- a/stableaidl/stableaidl-gradle-plugin/src/main/java/androidx/stableaidl/internal/process/GradleProcessExecutor.kt
+++ b/stableaidl/stableaidl-gradle-plugin/src/main/java/androidx/stableaidl/internal/process/GradleProcessExecutor.kt
@@ -15,7 +15,7 @@
  */
 package androidx.stableaidl.internal.process
 
-import com.android.build.gradle.internal.LoggerWrapper
+import androidx.stableaidl.internal.LoggerWrapper
 import com.android.ide.common.process.ProcessException
 import com.android.ide.common.process.ProcessExecutor
 import com.android.ide.common.process.ProcessInfo
diff --git a/tv/integration-tests/playground/src/main/java/androidx/tv/integration/playground/ImmersiveList.kt b/tv/integration-tests/playground/src/main/java/androidx/tv/integration/playground/ImmersiveList.kt
index 94240b6..da94fd9 100644
--- a/tv/integration-tests/playground/src/main/java/androidx/tv/integration/playground/ImmersiveList.kt
+++ b/tv/integration-tests/playground/src/main/java/androidx/tv/integration/playground/ImmersiveList.kt
@@ -24,7 +24,12 @@
 import androidx.compose.foundation.lazy.LazyRow
 import androidx.compose.foundation.lazy.itemsIndexed
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.focus.FocusRequester
+import androidx.compose.ui.focus.focusRequester
+import androidx.compose.ui.focus.focusRestorer
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.semantics.CollectionItemInfo
 import androidx.compose.ui.semantics.collectionItemInfo
@@ -43,7 +48,7 @@
     }
 }
 
-@OptIn(ExperimentalTvMaterial3Api::class)
+@OptIn(ExperimentalTvMaterial3Api::class, ExperimentalComposeUiApi::class)
 @Composable
 private fun SampleImmersiveList() {
     val immersiveListHeight = 300.dp
@@ -68,13 +73,13 @@
             )
         }
     ) {
-        val focusRestorerModifiers = createCustomInitialFocusRestorerModifiers()
+        val focusRequester = remember { FocusRequester() }
 
         LazyRow(
             horizontalArrangement = Arrangement.spacedBy(cardSpacing),
             modifier = Modifier
                 .lazyListSemantics(1, backgrounds.count())
-                .then(focusRestorerModifiers.parentModifier)
+                .focusRestorer { focusRequester }
         ) {
             itemsIndexed(backgrounds) { index, backgroundColor ->
                 Card(
@@ -83,7 +88,7 @@
                             collectionItemInfo = CollectionItemInfo(0, 1, index, 1)
                         }
                         .immersiveListItem(index)
-                        .ifElse(index == 0, focusRestorerModifiers.childModifier),
+                        .ifElse(index == 0, Modifier.focusRequester(focusRequester)),
                     backgroundColor = backgroundColor
                 )
             }
diff --git a/tv/integration-tests/playground/src/main/java/androidx/tv/integration/playground/LazyRowsAndColumns.kt b/tv/integration-tests/playground/src/main/java/androidx/tv/integration/playground/LazyRowsAndColumns.kt
index 20134a5..ed832f8 100644
--- a/tv/integration-tests/playground/src/main/java/androidx/tv/integration/playground/LazyRowsAndColumns.kt
+++ b/tv/integration-tests/playground/src/main/java/androidx/tv/integration/playground/LazyRowsAndColumns.kt
@@ -22,7 +22,11 @@
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.setValue
+import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.focus.FocusRequester
+import androidx.compose.ui.focus.focusRequester
+import androidx.compose.ui.focus.focusRestorer
 import androidx.compose.ui.focus.onFocusChanged
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.semantics.CollectionInfo
@@ -56,22 +60,23 @@
     }
 }
 
+@OptIn(ExperimentalComposeUiApi::class)
 @Composable
 fun SampleLazyRow(modifier: Modifier = Modifier) {
     val colors = listOf(Color.Red, Color.Magenta, Color.Green, Color.Yellow, Color.Blue, Color.Cyan)
     val backgroundColors = List(columnsCount) { colors.random() }
-    val focusRestorerModifiers = createCustomInitialFocusRestorerModifiers()
+    val focusRequester = remember { FocusRequester() }
 
     TvLazyRow(
         modifier = modifier
             .lazyListSemantics(1, columnsCount)
-            .then(focusRestorerModifiers.parentModifier),
+            .focusRestorer { focusRequester },
         horizontalArrangement = Arrangement.spacedBy(10.dp)
     ) {
         itemsIndexed(backgroundColors) { index, item ->
             Card(
                 modifier = Modifier
-                    .ifElse(index == 0, focusRestorerModifiers.childModifier)
+                    .ifElse(index == 0, Modifier.focusRequester(focusRequester))
                     .semantics {
                         collectionItemInfo = CollectionItemInfo(0, 1, index, 1)
                     },
diff --git a/tv/integration-tests/playground/src/main/java/androidx/tv/integration/playground/TopNavigation.kt b/tv/integration-tests/playground/src/main/java/androidx/tv/integration/playground/TopNavigation.kt
index f0ed752..f065bb2 100644
--- a/tv/integration-tests/playground/src/main/java/androidx/tv/integration/playground/TopNavigation.kt
+++ b/tv/integration-tests/playground/src/main/java/androidx/tv/integration/playground/TopNavigation.kt
@@ -26,7 +26,11 @@
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.setValue
+import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.focus.FocusRequester
+import androidx.compose.ui.focus.focusRequester
+import androidx.compose.ui.focus.focusRestorer
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
 import androidx.tv.material3.ExperimentalTvMaterial3Api
@@ -86,27 +90,25 @@
 /**
  * Pill indicator tab row for reference
  */
-@OptIn(ExperimentalTvMaterial3Api::class)
+@OptIn(ExperimentalTvMaterial3Api::class, ExperimentalComposeUiApi::class)
 @Composable
 fun PillIndicatorTabRow(
     tabs: List<String>,
     selectedTabIndex: Int,
     updateSelectedTab: (Int) -> Unit
 ) {
-    val focusRestorerModifiers = createCustomInitialFocusRestorerModifiers()
+    val focusRequester = remember { FocusRequester() }
 
     TabRow(
         selectedTabIndex = selectedTabIndex,
-        modifier = Modifier
-            .then(focusRestorerModifiers.parentModifier)
+        modifier = Modifier.focusRestorer { focusRequester }
     ) {
         tabs.forEachIndexed { index, tab ->
             key(index) {
                 Tab(
                     selected = index == selectedTabIndex,
                     onFocus = { updateSelectedTab(index) },
-                    modifier = Modifier
-                        .ifElse(index == 0, focusRestorerModifiers.childModifier)
+                    modifier = Modifier.ifElse(index == 0, Modifier.focusRequester(focusRequester))
                 ) {
                     Text(
                         text = tab,
@@ -122,14 +124,14 @@
 /**
  * Underlined indicator tab row for reference
  */
-@OptIn(ExperimentalTvMaterial3Api::class)
+@OptIn(ExperimentalTvMaterial3Api::class, ExperimentalComposeUiApi::class)
 @Composable
 fun UnderlinedIndicatorTabRow(
     tabs: List<String>,
     selectedTabIndex: Int,
     updateSelectedTab: (Int) -> Unit
 ) {
-    val focusRestorerModifiers = createCustomInitialFocusRestorerModifiers()
+    val focusRequester = remember { FocusRequester() }
 
     TabRow(
         selectedTabIndex = selectedTabIndex,
@@ -141,14 +143,14 @@
             )
         },
         modifier = Modifier
-            .then(focusRestorerModifiers.parentModifier),
+            .focusRestorer { focusRequester },
     ) {
         tabs.forEachIndexed { index, tab ->
             Tab(
                 selected = index == selectedTabIndex,
                 onFocus = { updateSelectedTab(index) },
                 modifier = Modifier
-                    .ifElse(index == 0, focusRestorerModifiers.childModifier),
+                    .ifElse(index == 0, Modifier.focusRequester(focusRequester)),
                 colors = TabDefaults.underlinedIndicatorTabColors(),
             ) {
                 Text(
diff --git a/tv/integration-tests/playground/src/main/java/androidx/tv/integration/playground/createCustomInitialFocusRestorerModifiers.kt b/tv/integration-tests/playground/src/main/java/androidx/tv/integration/playground/createCustomInitialFocusRestorerModifiers.kt
deleted file mode 100644
index 3f3acbf..0000000
--- a/tv/integration-tests/playground/src/main/java/androidx/tv/integration/playground/createCustomInitialFocusRestorerModifiers.kt
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.tv.integration.playground
-
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.remember
-import androidx.compose.ui.ExperimentalComposeUiApi
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.focus.FocusRequester
-import androidx.compose.ui.focus.focusProperties
-import androidx.compose.ui.focus.focusRequester
-
-/**
- * Assign the parentModifier to the container of items and assign the childModifier to the
- * item that needs to first gain focus. For example, if you want the item at index 0 to get
- * focus for the first time, you can do the following:
- *
- * LazyRow(modifier.then(modifiers.parentModifier) {
- *   item1(modifier.then(modifiers.childModifier) {...}
- *   item2 {...}
- *   item3 {...}
- *   ...
- * }
- */
-data class FocusRequesterModifiers(
-    val parentModifier: Modifier,
-    val childModifier: Modifier
-)
-
-@OptIn(ExperimentalComposeUiApi::class)
-@Composable
-fun createCustomInitialFocusRestorerModifiers(): FocusRequesterModifiers {
-    val focusRequester = remember { FocusRequester() }
-    val childFocusRequester = remember { FocusRequester() }
-
-    val parentModifier = Modifier
-        .focusRequester(focusRequester)
-        .focusProperties {
-            exit = {
-                focusRequester.saveFocusedChild()
-                FocusRequester.Default
-            }
-            enter = {
-                if (!focusRequester.restoreFocusedChild())
-                    childFocusRequester
-                else
-                    FocusRequester.Cancel
-            }
-        }
-
-    val childModifier = Modifier.focusRequester(childFocusRequester)
-
-    return FocusRequesterModifiers(parentModifier, childModifier)
-}
diff --git a/tv/tv-material/api/current.txt b/tv/tv-material/api/current.txt
index ae5d620..e29475f 100644
--- a/tv/tv-material/api/current.txt
+++ b/tv/tv-material/api/current.txt
@@ -609,7 +609,7 @@
     method @androidx.compose.runtime.Composable public static void MaterialTheme(optional androidx.tv.material3.ColorScheme colorScheme, optional androidx.tv.material3.Shapes shapes, optional androidx.tv.material3.Typography typography, kotlin.jvm.functions.Function0<kotlin.Unit> content);
   }
 
-  @SuppressCompatibility @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class NavigationDrawerItemBorder {
+  @androidx.compose.runtime.Immutable public final class NavigationDrawerItemBorder {
     ctor public NavigationDrawerItemBorder(androidx.tv.material3.Border border, androidx.tv.material3.Border focusedBorder, androidx.tv.material3.Border pressedBorder, androidx.tv.material3.Border selectedBorder, androidx.tv.material3.Border disabledBorder, androidx.tv.material3.Border focusedSelectedBorder, androidx.tv.material3.Border focusedDisabledBorder, androidx.tv.material3.Border pressedSelectedBorder);
     method public androidx.tv.material3.Border getBorder();
     method public androidx.tv.material3.Border getDisabledBorder();
@@ -629,7 +629,7 @@
     property public final androidx.tv.material3.Border selectedBorder;
   }
 
-  @SuppressCompatibility @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class NavigationDrawerItemColors {
+  @androidx.compose.runtime.Immutable public final class NavigationDrawerItemColors {
     ctor public NavigationDrawerItemColors(long containerColor, long contentColor, long inactiveContentColor, long focusedContainerColor, long focusedContentColor, long pressedContainerColor, long pressedContentColor, long selectedContainerColor, long selectedContentColor, long disabledContainerColor, long disabledContentColor, long disabledInactiveContentColor, long focusedSelectedContainerColor, long focusedSelectedContentColor, long pressedSelectedContainerColor, long pressedSelectedContentColor);
     method public long getContainerColor();
     method public long getContentColor();
@@ -665,7 +665,7 @@
     property public final long selectedContentColor;
   }
 
-  @SuppressCompatibility @androidx.tv.material3.ExperimentalTvMaterial3Api public final class NavigationDrawerItemDefaults {
+  public final class NavigationDrawerItemDefaults {
     method @androidx.compose.runtime.Composable public void TrailingBadge(String text, optional long containerColor, optional long contentColor);
     method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.NavigationDrawerItemBorder 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.NavigationDrawerItemColors colors(optional long containerColor, optional long contentColor, optional long inactiveContentColor, 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 disabledInactiveContentColor, optional long focusedSelectedContainerColor, optional long focusedSelectedContentColor, optional long pressedSelectedContainerColor, optional long pressedSelectedContentColor);
@@ -699,7 +699,7 @@
     field public static final androidx.tv.material3.NavigationDrawerItemDefaults INSTANCE;
   }
 
-  @SuppressCompatibility @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class NavigationDrawerItemGlow {
+  @androidx.compose.runtime.Immutable public final class NavigationDrawerItemGlow {
     ctor public NavigationDrawerItemGlow(androidx.tv.material3.Glow glow, androidx.tv.material3.Glow focusedGlow, androidx.tv.material3.Glow pressedGlow, androidx.tv.material3.Glow selectedGlow, androidx.tv.material3.Glow focusedSelectedGlow, androidx.tv.material3.Glow pressedSelectedGlow);
     method public androidx.tv.material3.Glow getFocusedGlow();
     method public androidx.tv.material3.Glow getFocusedSelectedGlow();
@@ -716,10 +716,10 @@
   }
 
   public final class NavigationDrawerItemKt {
-    method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void NavigationDrawerItem(androidx.tv.material3.NavigationDrawerScope, boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> leadingContent, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingContent, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingContent, optional float tonalElevation, optional androidx.tv.material3.NavigationDrawerItemShape shape, optional androidx.tv.material3.NavigationDrawerItemColors colors, optional androidx.tv.material3.NavigationDrawerItemScale scale, optional androidx.tv.material3.NavigationDrawerItemBorder border, optional androidx.tv.material3.NavigationDrawerItemGlow glow, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void NavigationDrawerItem(androidx.tv.material3.NavigationDrawerScope, boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> leadingContent, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingContent, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingContent, optional float tonalElevation, optional androidx.tv.material3.NavigationDrawerItemShape shape, optional androidx.tv.material3.NavigationDrawerItemColors colors, optional androidx.tv.material3.NavigationDrawerItemScale scale, optional androidx.tv.material3.NavigationDrawerItemBorder border, optional androidx.tv.material3.NavigationDrawerItemGlow glow, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
   }
 
-  @SuppressCompatibility @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class NavigationDrawerItemScale {
+  @androidx.compose.runtime.Immutable public final class NavigationDrawerItemScale {
     ctor public NavigationDrawerItemScale(@FloatRange(from=0.0) float scale, @FloatRange(from=0.0) float focusedScale, @FloatRange(from=0.0) float pressedScale, @FloatRange(from=0.0) float selectedScale, @FloatRange(from=0.0) float disabledScale, @FloatRange(from=0.0) float focusedSelectedScale, @FloatRange(from=0.0) float focusedDisabledScale, @FloatRange(from=0.0) float pressedSelectedScale);
     method public float getDisabledScale();
     method public float getFocusedDisabledScale();
@@ -745,7 +745,7 @@
     property public final androidx.tv.material3.NavigationDrawerItemScale None;
   }
 
-  @SuppressCompatibility @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class NavigationDrawerItemShape {
+  @androidx.compose.runtime.Immutable public final class NavigationDrawerItemShape {
     ctor public NavigationDrawerItemShape(androidx.compose.ui.graphics.Shape shape, androidx.compose.ui.graphics.Shape focusedShape, androidx.compose.ui.graphics.Shape pressedShape, androidx.compose.ui.graphics.Shape selectedShape, androidx.compose.ui.graphics.Shape disabledShape, androidx.compose.ui.graphics.Shape focusedSelectedShape, androidx.compose.ui.graphics.Shape focusedDisabledShape, androidx.compose.ui.graphics.Shape pressedSelectedShape);
     method public androidx.compose.ui.graphics.Shape getDisabledShape();
     method public androidx.compose.ui.graphics.Shape getFocusedDisabledShape();
@@ -971,20 +971,20 @@
     method @androidx.compose.runtime.Composable public static void Switch(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit>? onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? thumbContent, optional boolean enabled, optional androidx.tv.material3.SwitchColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource);
   }
 
-  @SuppressCompatibility @androidx.tv.material3.ExperimentalTvMaterial3Api public final class TabColors {
+  public final class TabColors {
   }
 
-  @SuppressCompatibility @androidx.tv.material3.ExperimentalTvMaterial3Api public final class TabDefaults {
+  public final class TabDefaults {
     method @androidx.compose.runtime.Composable public androidx.tv.material3.TabColors pillIndicatorTabColors(optional long contentColor, optional long inactiveContentColor, optional long selectedContentColor, optional long focusedContentColor, optional long focusedSelectedContentColor, optional long disabledContentColor, optional long disabledInactiveContentColor, optional long disabledSelectedContentColor);
     method @androidx.compose.runtime.Composable public androidx.tv.material3.TabColors underlinedIndicatorTabColors(optional long contentColor, optional long inactiveContentColor, optional long selectedContentColor, optional long focusedContentColor, optional long focusedSelectedContentColor, optional long disabledContentColor, optional long disabledInactiveContentColor, optional long disabledSelectedContentColor);
     field public static final androidx.tv.material3.TabDefaults INSTANCE;
   }
 
   public final class TabKt {
-    method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void Tab(androidx.tv.material3.TabRowScope, boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onFocus, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional boolean enabled, optional androidx.tv.material3.TabColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void Tab(androidx.tv.material3.TabRowScope, boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onFocus, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional boolean enabled, optional androidx.tv.material3.TabColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
   }
 
-  @SuppressCompatibility @androidx.tv.material3.ExperimentalTvMaterial3Api public final class TabRowDefaults {
+  public final class TabRowDefaults {
     method @androidx.compose.runtime.Composable public void PillIndicator(androidx.compose.ui.unit.DpRect currentTabPosition, boolean doesTabRowHaveFocus, optional androidx.compose.ui.Modifier modifier, optional long activeColor, optional long inactiveColor);
     method @androidx.compose.runtime.Composable public void TabSeparator();
     method @androidx.compose.runtime.Composable public void UnderlinedIndicator(androidx.compose.ui.unit.DpRect currentTabPosition, boolean doesTabRowHaveFocus, optional androidx.compose.ui.Modifier modifier, optional long activeColor, optional long inactiveColor);
@@ -995,10 +995,10 @@
   }
 
   public final class TabRowKt {
-    method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void TabRow(int selectedTabIndex, optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional kotlin.jvm.functions.Function0<kotlin.Unit> separator, optional kotlin.jvm.functions.Function2<? super java.util.List<androidx.compose.ui.unit.DpRect>,? super java.lang.Boolean,kotlin.Unit> indicator, kotlin.jvm.functions.Function1<? super androidx.tv.material3.TabRowScope,kotlin.Unit> tabs);
+    method @androidx.compose.runtime.Composable public static void TabRow(int selectedTabIndex, optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional kotlin.jvm.functions.Function0<kotlin.Unit> separator, optional kotlin.jvm.functions.Function2<? super java.util.List<androidx.compose.ui.unit.DpRect>,? super java.lang.Boolean,kotlin.Unit> indicator, kotlin.jvm.functions.Function1<? super androidx.tv.material3.TabRowScope,kotlin.Unit> tabs);
   }
 
-  @SuppressCompatibility @androidx.tv.material3.ExperimentalTvMaterial3Api public interface TabRowScope {
+  public interface TabRowScope {
     method public boolean getHasFocus();
     property public abstract boolean hasFocus;
   }
diff --git a/tv/tv-material/api/restricted_current.txt b/tv/tv-material/api/restricted_current.txt
index ae5d620..e29475f 100644
--- a/tv/tv-material/api/restricted_current.txt
+++ b/tv/tv-material/api/restricted_current.txt
@@ -609,7 +609,7 @@
     method @androidx.compose.runtime.Composable public static void MaterialTheme(optional androidx.tv.material3.ColorScheme colorScheme, optional androidx.tv.material3.Shapes shapes, optional androidx.tv.material3.Typography typography, kotlin.jvm.functions.Function0<kotlin.Unit> content);
   }
 
-  @SuppressCompatibility @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class NavigationDrawerItemBorder {
+  @androidx.compose.runtime.Immutable public final class NavigationDrawerItemBorder {
     ctor public NavigationDrawerItemBorder(androidx.tv.material3.Border border, androidx.tv.material3.Border focusedBorder, androidx.tv.material3.Border pressedBorder, androidx.tv.material3.Border selectedBorder, androidx.tv.material3.Border disabledBorder, androidx.tv.material3.Border focusedSelectedBorder, androidx.tv.material3.Border focusedDisabledBorder, androidx.tv.material3.Border pressedSelectedBorder);
     method public androidx.tv.material3.Border getBorder();
     method public androidx.tv.material3.Border getDisabledBorder();
@@ -629,7 +629,7 @@
     property public final androidx.tv.material3.Border selectedBorder;
   }
 
-  @SuppressCompatibility @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class NavigationDrawerItemColors {
+  @androidx.compose.runtime.Immutable public final class NavigationDrawerItemColors {
     ctor public NavigationDrawerItemColors(long containerColor, long contentColor, long inactiveContentColor, long focusedContainerColor, long focusedContentColor, long pressedContainerColor, long pressedContentColor, long selectedContainerColor, long selectedContentColor, long disabledContainerColor, long disabledContentColor, long disabledInactiveContentColor, long focusedSelectedContainerColor, long focusedSelectedContentColor, long pressedSelectedContainerColor, long pressedSelectedContentColor);
     method public long getContainerColor();
     method public long getContentColor();
@@ -665,7 +665,7 @@
     property public final long selectedContentColor;
   }
 
-  @SuppressCompatibility @androidx.tv.material3.ExperimentalTvMaterial3Api public final class NavigationDrawerItemDefaults {
+  public final class NavigationDrawerItemDefaults {
     method @androidx.compose.runtime.Composable public void TrailingBadge(String text, optional long containerColor, optional long contentColor);
     method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.NavigationDrawerItemBorder 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.NavigationDrawerItemColors colors(optional long containerColor, optional long contentColor, optional long inactiveContentColor, 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 disabledInactiveContentColor, optional long focusedSelectedContainerColor, optional long focusedSelectedContentColor, optional long pressedSelectedContainerColor, optional long pressedSelectedContentColor);
@@ -699,7 +699,7 @@
     field public static final androidx.tv.material3.NavigationDrawerItemDefaults INSTANCE;
   }
 
-  @SuppressCompatibility @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class NavigationDrawerItemGlow {
+  @androidx.compose.runtime.Immutable public final class NavigationDrawerItemGlow {
     ctor public NavigationDrawerItemGlow(androidx.tv.material3.Glow glow, androidx.tv.material3.Glow focusedGlow, androidx.tv.material3.Glow pressedGlow, androidx.tv.material3.Glow selectedGlow, androidx.tv.material3.Glow focusedSelectedGlow, androidx.tv.material3.Glow pressedSelectedGlow);
     method public androidx.tv.material3.Glow getFocusedGlow();
     method public androidx.tv.material3.Glow getFocusedSelectedGlow();
@@ -716,10 +716,10 @@
   }
 
   public final class NavigationDrawerItemKt {
-    method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void NavigationDrawerItem(androidx.tv.material3.NavigationDrawerScope, boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> leadingContent, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingContent, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingContent, optional float tonalElevation, optional androidx.tv.material3.NavigationDrawerItemShape shape, optional androidx.tv.material3.NavigationDrawerItemColors colors, optional androidx.tv.material3.NavigationDrawerItemScale scale, optional androidx.tv.material3.NavigationDrawerItemBorder border, optional androidx.tv.material3.NavigationDrawerItemGlow glow, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void NavigationDrawerItem(androidx.tv.material3.NavigationDrawerScope, boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> leadingContent, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingContent, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingContent, optional float tonalElevation, optional androidx.tv.material3.NavigationDrawerItemShape shape, optional androidx.tv.material3.NavigationDrawerItemColors colors, optional androidx.tv.material3.NavigationDrawerItemScale scale, optional androidx.tv.material3.NavigationDrawerItemBorder border, optional androidx.tv.material3.NavigationDrawerItemGlow glow, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
   }
 
-  @SuppressCompatibility @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class NavigationDrawerItemScale {
+  @androidx.compose.runtime.Immutable public final class NavigationDrawerItemScale {
     ctor public NavigationDrawerItemScale(@FloatRange(from=0.0) float scale, @FloatRange(from=0.0) float focusedScale, @FloatRange(from=0.0) float pressedScale, @FloatRange(from=0.0) float selectedScale, @FloatRange(from=0.0) float disabledScale, @FloatRange(from=0.0) float focusedSelectedScale, @FloatRange(from=0.0) float focusedDisabledScale, @FloatRange(from=0.0) float pressedSelectedScale);
     method public float getDisabledScale();
     method public float getFocusedDisabledScale();
@@ -745,7 +745,7 @@
     property public final androidx.tv.material3.NavigationDrawerItemScale None;
   }
 
-  @SuppressCompatibility @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class NavigationDrawerItemShape {
+  @androidx.compose.runtime.Immutable public final class NavigationDrawerItemShape {
     ctor public NavigationDrawerItemShape(androidx.compose.ui.graphics.Shape shape, androidx.compose.ui.graphics.Shape focusedShape, androidx.compose.ui.graphics.Shape pressedShape, androidx.compose.ui.graphics.Shape selectedShape, androidx.compose.ui.graphics.Shape disabledShape, androidx.compose.ui.graphics.Shape focusedSelectedShape, androidx.compose.ui.graphics.Shape focusedDisabledShape, androidx.compose.ui.graphics.Shape pressedSelectedShape);
     method public androidx.compose.ui.graphics.Shape getDisabledShape();
     method public androidx.compose.ui.graphics.Shape getFocusedDisabledShape();
@@ -971,20 +971,20 @@
     method @androidx.compose.runtime.Composable public static void Switch(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit>? onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? thumbContent, optional boolean enabled, optional androidx.tv.material3.SwitchColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource);
   }
 
-  @SuppressCompatibility @androidx.tv.material3.ExperimentalTvMaterial3Api public final class TabColors {
+  public final class TabColors {
   }
 
-  @SuppressCompatibility @androidx.tv.material3.ExperimentalTvMaterial3Api public final class TabDefaults {
+  public final class TabDefaults {
     method @androidx.compose.runtime.Composable public androidx.tv.material3.TabColors pillIndicatorTabColors(optional long contentColor, optional long inactiveContentColor, optional long selectedContentColor, optional long focusedContentColor, optional long focusedSelectedContentColor, optional long disabledContentColor, optional long disabledInactiveContentColor, optional long disabledSelectedContentColor);
     method @androidx.compose.runtime.Composable public androidx.tv.material3.TabColors underlinedIndicatorTabColors(optional long contentColor, optional long inactiveContentColor, optional long selectedContentColor, optional long focusedContentColor, optional long focusedSelectedContentColor, optional long disabledContentColor, optional long disabledInactiveContentColor, optional long disabledSelectedContentColor);
     field public static final androidx.tv.material3.TabDefaults INSTANCE;
   }
 
   public final class TabKt {
-    method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void Tab(androidx.tv.material3.TabRowScope, boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onFocus, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional boolean enabled, optional androidx.tv.material3.TabColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void Tab(androidx.tv.material3.TabRowScope, boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onFocus, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional boolean enabled, optional androidx.tv.material3.TabColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
   }
 
-  @SuppressCompatibility @androidx.tv.material3.ExperimentalTvMaterial3Api public final class TabRowDefaults {
+  public final class TabRowDefaults {
     method @androidx.compose.runtime.Composable public void PillIndicator(androidx.compose.ui.unit.DpRect currentTabPosition, boolean doesTabRowHaveFocus, optional androidx.compose.ui.Modifier modifier, optional long activeColor, optional long inactiveColor);
     method @androidx.compose.runtime.Composable public void TabSeparator();
     method @androidx.compose.runtime.Composable public void UnderlinedIndicator(androidx.compose.ui.unit.DpRect currentTabPosition, boolean doesTabRowHaveFocus, optional androidx.compose.ui.Modifier modifier, optional long activeColor, optional long inactiveColor);
@@ -995,10 +995,10 @@
   }
 
   public final class TabRowKt {
-    method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void TabRow(int selectedTabIndex, optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional kotlin.jvm.functions.Function0<kotlin.Unit> separator, optional kotlin.jvm.functions.Function2<? super java.util.List<androidx.compose.ui.unit.DpRect>,? super java.lang.Boolean,kotlin.Unit> indicator, kotlin.jvm.functions.Function1<? super androidx.tv.material3.TabRowScope,kotlin.Unit> tabs);
+    method @androidx.compose.runtime.Composable public static void TabRow(int selectedTabIndex, optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional kotlin.jvm.functions.Function0<kotlin.Unit> separator, optional kotlin.jvm.functions.Function2<? super java.util.List<androidx.compose.ui.unit.DpRect>,? super java.lang.Boolean,kotlin.Unit> indicator, kotlin.jvm.functions.Function1<? super androidx.tv.material3.TabRowScope,kotlin.Unit> tabs);
   }
 
-  @SuppressCompatibility @androidx.tv.material3.ExperimentalTvMaterial3Api public interface TabRowScope {
+  public interface TabRowScope {
     method public boolean getHasFocus();
     property public abstract boolean hasFocus;
   }
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/NavigationDrawerItem.kt b/tv/tv-material/src/main/java/androidx/tv/material3/NavigationDrawerItem.kt
index e2f574c..7bca093 100644
--- a/tv/tv-material/src/main/java/androidx/tv/material3/NavigationDrawerItem.kt
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/NavigationDrawerItem.kt
@@ -62,7 +62,6 @@
  * interactions will still happen internally.
  * @param content main content of this composable
  */
-@ExperimentalTvMaterial3Api // TODO (b/263353219): Remove this before launching beta
 @Composable
 fun NavigationDrawerScope.NavigationDrawerItem(
     selected: Boolean,
@@ -162,7 +161,6 @@
     )
 }
 
-@OptIn(ExperimentalTvMaterial3Api::class)
 @Composable
 private fun NavigationDrawerItemShape.toToggleableListItemShape() =
     ListItemDefaults.shape(
@@ -176,7 +174,6 @@
         pressedSelectedShape = pressedSelectedShape,
     )
 
-@OptIn(ExperimentalTvMaterial3Api::class)
 @Composable
 private fun NavigationDrawerItemColors.toToggleableListItemColors(
     doesNavigationDrawerHaveFocus: Boolean
@@ -199,7 +196,6 @@
         pressedSelectedContentColor = pressedSelectedContentColor,
     )
 
-@OptIn(ExperimentalTvMaterial3Api::class)
 @Composable
 private fun NavigationDrawerItemScale.toToggleableListItemScale() =
     ListItemDefaults.scale(
@@ -213,7 +209,6 @@
         pressedSelectedScale = pressedSelectedScale,
     )
 
-@OptIn(ExperimentalTvMaterial3Api::class)
 @Composable
 private fun NavigationDrawerItemBorder.toToggleableListItemBorder() =
     ListItemDefaults.border(
@@ -227,7 +222,6 @@
         pressedSelectedBorder = pressedSelectedBorder,
     )
 
-@OptIn(ExperimentalTvMaterial3Api::class)
 @Composable
 private fun NavigationDrawerItemGlow.toToggleableListItemGlow() =
     ListItemDefaults.glow(
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/NavigationDrawerItemDefaults.kt b/tv/tv-material/src/main/java/androidx/tv/material3/NavigationDrawerItemDefaults.kt
index abe79a8..a5a25e3 100644
--- a/tv/tv-material/src/main/java/androidx/tv/material3/NavigationDrawerItemDefaults.kt
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/NavigationDrawerItemDefaults.kt
@@ -40,7 +40,6 @@
 /**
  * Contains the default values used by selectable [NavigationDrawerItem]
  */
-@ExperimentalTvMaterial3Api // TODO (b/263353219): Remove this before launching beta
 object NavigationDrawerItemDefaults {
     /**
      * The default Icon size used by [NavigationDrawerItem]
@@ -121,6 +120,7 @@
      * Creates a trailing badge for [NavigationDrawerItem]
      */
     @Composable
+    @OptIn(ExperimentalTvMaterial3Api::class) // TODO: This will be removed once Text API is marked as stable
     fun TrailingBadge(
         text: String,
         containerColor: Color = TrailingBadgeContainerColor,
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/NavigationDrawerItemStyles.kt b/tv/tv-material/src/main/java/androidx/tv/material3/NavigationDrawerItemStyles.kt
index f08e865..5e2dc6e 100644
--- a/tv/tv-material/src/main/java/androidx/tv/material3/NavigationDrawerItemStyles.kt
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/NavigationDrawerItemStyles.kt
@@ -40,7 +40,6 @@
  * @param pressedSelectedShape the shape used when the [NavigationDrawerItem] is enabled,
  * pressed and selected
  */
-@ExperimentalTvMaterial3Api // TODO (b/263353219): Remove this before launching beta
 @Immutable
 class NavigationDrawerItemShape(
     val shape: Shape,
@@ -132,7 +131,6 @@
  * @param pressedSelectedContentColor the content color used when the [NavigationDrawerItem] is
  * enabled, pressed and selected
  */
-@ExperimentalTvMaterial3Api // TODO (b/263353219): Remove this before launching beta
 @Immutable
 class NavigationDrawerItemColors(
     val containerColor: Color,
@@ -232,7 +230,6 @@
  * @param pressedSelectedScale the scale used when the [NavigationDrawerItem] is enabled,
  * pressed and selected
  */
-@ExperimentalTvMaterial3Api // TODO (b/263353219): Remove this before launching beta
 @Immutable
 class NavigationDrawerItemScale(
     @FloatRange(from = 0.0) val scale: Float,
@@ -320,7 +317,6 @@
  * @param pressedSelectedBorder the [Border] used when the [NavigationDrawerItem] is enabled,
  * pressed and selected
  */
-@ExperimentalTvMaterial3Api // TODO (b/263353219): Remove this before launching beta
 @Immutable
 class NavigationDrawerItemBorder(
     val border: Border,
@@ -388,7 +384,6 @@
  * @param pressedSelectedGlow the [Glow] used when the [NavigationDrawerItem] is enabled,
  * pressed and selected
  */
-@ExperimentalTvMaterial3Api // TODO (b/263353219): Remove this before launching beta
 @Immutable
 class NavigationDrawerItemGlow(
     val glow: Glow,
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 4ab89da35..f62a9ee 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
@@ -16,7 +16,6 @@
 
 package androidx.tv.material3
 
-import androidx.compose.animation.animateColorAsState
 import androidx.compose.animation.core.animateFloatAsState
 import androidx.compose.foundation.background
 import androidx.compose.foundation.focusable
@@ -343,13 +342,9 @@
     )
 
     val absoluteElevation = LocalAbsoluteTonalElevation.current + tonalElevation
-    val contentColorAsAnim by animateColorAsState(
-        targetValue = contentColor,
-        label = "Surface.contentColor"
-    )
 
     CompositionLocalProvider(
-        LocalContentColor provides contentColorAsAnim,
+        LocalContentColor provides contentColor,
         LocalAbsoluteTonalElevation provides absoluteElevation
     ) {
         val zIndex by animateFloatAsState(
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/Tab.kt b/tv/tv-material/src/main/java/androidx/tv/material3/Tab.kt
index 1108c8c1..969886e 100644
--- a/tv/tv-material/src/main/java/androidx/tv/material3/Tab.kt
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/Tab.kt
@@ -56,7 +56,6 @@
  * still happen internally.
  * @param content content of the [Tab]
  */
-@ExperimentalTvMaterial3Api
 @Composable
 fun TabRowScope.Tab(
     selected: Boolean,
@@ -106,7 +105,6 @@
  * - See [TabDefaults.underlinedIndicatorTabColors] for the default colors used in a [Tab] when
  * using an Underlined indicator
  */
-@ExperimentalTvMaterial3Api // TODO (b/263353219): Remove this before launching beta
 class TabColors
 internal constructor(
     internal val contentColor: Color,
@@ -147,7 +145,6 @@
     }
 }
 
-@ExperimentalTvMaterial3Api // TODO (b/263353219): Remove this before launching beta
 object TabDefaults {
     /**
      * [Tab]'s content colors to in conjunction with underlined indicator
@@ -163,7 +160,6 @@
      * focused
      * @param disabledSelectedContentColor applied when the current tab is disabled and selected
      */
-    @OptIn(ExperimentalTvMaterial3Api::class)
     @Composable
     fun underlinedIndicatorTabColors(
         contentColor: Color = LocalContentColor.current,
@@ -200,7 +196,6 @@
      * focused
      * @param disabledSelectedContentColor applied when the current tab is disabled and selected
      */
-    @OptIn(ExperimentalTvMaterial3Api::class)
     @Composable
     fun pillIndicatorTabColors(
         contentColor: Color = LocalContentColor.current,
@@ -224,7 +219,6 @@
         )
 }
 
-@OptIn(ExperimentalTvMaterial3Api::class)
 @Composable
 internal fun TabColors.toToggleableSurfaceColors(
     doesTabRowHaveFocus: Boolean,
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 322f2aa..ed819d3 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
@@ -86,7 +86,6 @@
  * * doesTabRowHaveFocus: whether any [Tab] within [TabRow] is focused
  * @param tabs a composable which will render all the tabs
  */
-@ExperimentalTvMaterial3Api // TODO (b/263353219): Remove this before launching beta
 @Composable
 fun TabRow(
     selectedTabIndex: Int,
@@ -190,7 +189,6 @@
     }
 }
 
-@ExperimentalTvMaterial3Api // TODO (b/263353219): Remove this before launching beta
 object TabRowDefaults {
     /** Color of the background of a tab */
     val ContainerColor = Color.Transparent
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/TabRowScope.kt b/tv/tv-material/src/main/java/androidx/tv/material3/TabRowScope.kt
index 27b9848..e98c590 100644
--- a/tv/tv-material/src/main/java/androidx/tv/material3/TabRowScope.kt
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/TabRowScope.kt
@@ -19,7 +19,6 @@
 /**
  * [TabRowScope] is used to provide the doesTabRowHaveFocus state to the [Tab] composable
  */
-@ExperimentalTvMaterial3Api // TODO (b/263353219): Remove this before launching beta
 interface TabRowScope {
     /**
      * Whether any [Tab] within the [TabRow] is focused
@@ -28,7 +27,6 @@
     val hasFocus: Boolean
 }
 
-@OptIn(ExperimentalTvMaterial3Api::class)
 internal class TabRowScopeImpl internal constructor(
     override val hasFocus: Boolean
 ) : TabRowScope
diff --git a/wear/compose/integration-tests/macrobenchmark/build.gradle b/wear/compose/integration-tests/macrobenchmark/build.gradle
index dd9f82f..1b3a97c 100644
--- a/wear/compose/integration-tests/macrobenchmark/build.gradle
+++ b/wear/compose/integration-tests/macrobenchmark/build.gradle
@@ -27,8 +27,6 @@
     namespace "androidx.wear.compose.integration.macrobenchmark"
     targetProjectPath = ":wear:compose:integration-tests:macrobenchmark-target"
     experimentalProperties["android.experimental.self-instrumenting"] = true
-
-    testOptions.animationsDisabled = false
 }
 
 // Create a release build type and make sure it's the only one enabled.