Merge "Cache checkAbiRelease even though it has no outputs" into androidx-main
diff --git a/appfunctions/appfunctions-common/api/current.txt b/appfunctions/appfunctions-common/api/current.txt
index ba35715..997db32 100644
--- a/appfunctions/appfunctions-common/api/current.txt
+++ b/appfunctions/appfunctions-common/api/current.txt
@@ -38,7 +38,6 @@
   }
 
   public abstract class AppFunctionException extends java.lang.Exception {
-    ctor public AppFunctionException(int errorCode, optional String? errorMessage);
     method public final String? getErrorMessage();
     property public final String? errorMessage;
     field public static final androidx.appfunctions.AppFunctionException.Companion Companion;
@@ -81,9 +80,9 @@
   }
 
   public final class AppFunctionUnknownException extends androidx.appfunctions.AppFunctionException {
-    ctor public AppFunctionUnknownException(int unknownErrorCode, optional String? errorMessage);
-    method public int getUnknownErrorCode();
-    property public final int unknownErrorCode;
+    ctor public AppFunctionUnknownException(int errorCode, optional String? errorMessage);
+    method public int getErrorCode();
+    property public final int errorCode;
   }
 
 }
diff --git a/appfunctions/appfunctions-common/api/restricted_current.txt b/appfunctions/appfunctions-common/api/restricted_current.txt
index ba35715..997db32 100644
--- a/appfunctions/appfunctions-common/api/restricted_current.txt
+++ b/appfunctions/appfunctions-common/api/restricted_current.txt
@@ -38,7 +38,6 @@
   }
 
   public abstract class AppFunctionException extends java.lang.Exception {
-    ctor public AppFunctionException(int errorCode, optional String? errorMessage);
     method public final String? getErrorMessage();
     property public final String? errorMessage;
     field public static final androidx.appfunctions.AppFunctionException.Companion Companion;
@@ -81,9 +80,9 @@
   }
 
   public final class AppFunctionUnknownException extends androidx.appfunctions.AppFunctionException {
-    ctor public AppFunctionUnknownException(int unknownErrorCode, optional String? errorMessage);
-    method public int getUnknownErrorCode();
-    property public final int unknownErrorCode;
+    ctor public AppFunctionUnknownException(int errorCode, optional String? errorMessage);
+    method public int getErrorCode();
+    property public final int errorCode;
   }
 
 }
diff --git a/appfunctions/appfunctions-common/src/androidTest/java/androidx/appfunctions/AppFunctionAppExceptionsTest.kt b/appfunctions/appfunctions-common/src/androidTest/java/androidx/appfunctions/AppFunctionAppExceptionsTest.kt
index 2172ea5..2e43099 100644
--- a/appfunctions/appfunctions-common/src/androidTest/java/androidx/appfunctions/AppFunctionAppExceptionsTest.kt
+++ b/appfunctions/appfunctions-common/src/androidTest/java/androidx/appfunctions/AppFunctionAppExceptionsTest.kt
@@ -22,17 +22,17 @@
 class AppFunctionAppExceptionsTest {
     @Test
     fun testErrorCategory_AppError() {
-        assertThat(AppFunctionAppUnknownException().errorCode)
+        assertThat(AppFunctionAppUnknownException().internalErrorCode)
             .isEqualTo(AppFunctionException.ERROR_APP_UNKNOWN_ERROR)
         assertThat(AppFunctionAppUnknownException().errorCategory)
             .isEqualTo(AppFunctionException.ERROR_CATEGORY_APP)
 
-        assertThat(AppFunctionPermissionRequiredException().errorCode)
+        assertThat(AppFunctionPermissionRequiredException().internalErrorCode)
             .isEqualTo(AppFunctionException.ERROR_PERMISSION_REQUIRED)
         assertThat(AppFunctionPermissionRequiredException().errorCategory)
             .isEqualTo(AppFunctionException.ERROR_CATEGORY_APP)
 
-        assertThat(AppFunctionNotSupportedException().errorCode)
+        assertThat(AppFunctionNotSupportedException().internalErrorCode)
             .isEqualTo(AppFunctionException.ERROR_NOT_SUPPORTED)
         assertThat(AppFunctionNotSupportedException().errorCategory)
             .isEqualTo(AppFunctionException.ERROR_CATEGORY_APP)
diff --git a/appfunctions/appfunctions-common/src/androidTest/java/androidx/appfunctions/AppFunctionExceptionTest.kt b/appfunctions/appfunctions-common/src/androidTest/java/androidx/appfunctions/AppFunctionExceptionTest.kt
index a8cbef9..c2e0b38 100644
--- a/appfunctions/appfunctions-common/src/androidTest/java/androidx/appfunctions/AppFunctionExceptionTest.kt
+++ b/appfunctions/appfunctions-common/src/androidTest/java/androidx/appfunctions/AppFunctionExceptionTest.kt
@@ -110,7 +110,7 @@
         val exception = AppFunctionException.fromPlatformExtensionsClass(platformException)
 
         assertThat(exception).isInstanceOf(exceptionClass)
-        assertThat(exception.errorCode).isEqualTo(errorCode)
+        assertThat(exception.internalErrorCode).isEqualTo(errorCode)
         assertThat(exception.errorMessage).isEqualTo("testMessage")
         assertThat(exception.extras.getString("testKey")).isEqualTo("testValue")
     }
diff --git a/appfunctions/appfunctions-common/src/androidTest/java/androidx/appfunctions/AppFunctionRequestExceptionsTest.kt b/appfunctions/appfunctions-common/src/androidTest/java/androidx/appfunctions/AppFunctionRequestExceptionsTest.kt
index f98c39f..51fa82f6 100644
--- a/appfunctions/appfunctions-common/src/androidTest/java/androidx/appfunctions/AppFunctionRequestExceptionsTest.kt
+++ b/appfunctions/appfunctions-common/src/androidTest/java/androidx/appfunctions/AppFunctionRequestExceptionsTest.kt
@@ -22,37 +22,37 @@
 class AppFunctionRequestExceptionsTest {
     @Test
     fun testErrorCategory_RequestError() {
-        assertThat(AppFunctionDeniedException().errorCode)
+        assertThat(AppFunctionDeniedException().internalErrorCode)
             .isEqualTo(AppFunctionException.ERROR_DENIED)
         assertThat(AppFunctionDeniedException().errorCategory)
             .isEqualTo(AppFunctionException.ERROR_CATEGORY_REQUEST_ERROR)
 
-        assertThat(AppFunctionInvalidArgumentException().errorCode)
+        assertThat(AppFunctionInvalidArgumentException().internalErrorCode)
             .isEqualTo(AppFunctionException.ERROR_INVALID_ARGUMENT)
         assertThat(AppFunctionInvalidArgumentException().errorCategory)
             .isEqualTo(AppFunctionException.ERROR_CATEGORY_REQUEST_ERROR)
 
-        assertThat(AppFunctionDisabledException().errorCode)
+        assertThat(AppFunctionDisabledException().internalErrorCode)
             .isEqualTo(AppFunctionException.ERROR_DISABLED)
         assertThat(AppFunctionDisabledException().errorCategory)
             .isEqualTo(AppFunctionException.ERROR_CATEGORY_REQUEST_ERROR)
 
-        assertThat(AppFunctionFunctionNotFoundException().errorCode)
+        assertThat(AppFunctionFunctionNotFoundException().internalErrorCode)
             .isEqualTo(AppFunctionException.ERROR_FUNCTION_NOT_FOUND)
         assertThat(AppFunctionFunctionNotFoundException().errorCategory)
             .isEqualTo(AppFunctionException.ERROR_CATEGORY_REQUEST_ERROR)
 
-        assertThat(AppFunctionElementNotFoundException().errorCode)
+        assertThat(AppFunctionElementNotFoundException().internalErrorCode)
             .isEqualTo(AppFunctionException.ERROR_RESOURCE_NOT_FOUND)
         assertThat(AppFunctionElementNotFoundException().errorCategory)
             .isEqualTo(AppFunctionException.ERROR_CATEGORY_REQUEST_ERROR)
 
-        assertThat(AppFunctionLimitExceededException().errorCode)
+        assertThat(AppFunctionLimitExceededException().internalErrorCode)
             .isEqualTo(AppFunctionException.ERROR_LIMIT_EXCEEDED)
         assertThat(AppFunctionLimitExceededException().errorCategory)
             .isEqualTo(AppFunctionException.ERROR_CATEGORY_REQUEST_ERROR)
 
-        assertThat(AppFunctionElementAlreadyExistsException().errorCode)
+        assertThat(AppFunctionElementAlreadyExistsException().internalErrorCode)
             .isEqualTo(AppFunctionException.ERROR_RESOURCE_ALREADY_EXISTS)
         assertThat(AppFunctionElementAlreadyExistsException().errorCategory)
             .isEqualTo(AppFunctionException.ERROR_CATEGORY_REQUEST_ERROR)
diff --git a/appfunctions/appfunctions-common/src/androidTest/java/androidx/appfunctions/AppFunctionSystemExceptionsTest.kt b/appfunctions/appfunctions-common/src/androidTest/java/androidx/appfunctions/AppFunctionSystemExceptionsTest.kt
index 89ccbf0..0722f0a 100644
--- a/appfunctions/appfunctions-common/src/androidTest/java/androidx/appfunctions/AppFunctionSystemExceptionsTest.kt
+++ b/appfunctions/appfunctions-common/src/androidTest/java/androidx/appfunctions/AppFunctionSystemExceptionsTest.kt
@@ -22,12 +22,12 @@
 class AppFunctionSystemExceptionsTest {
     @Test
     fun testErrorCategory_SystemError() {
-        assertThat(AppFunctionSystemUnknownException().errorCode)
+        assertThat(AppFunctionSystemUnknownException().internalErrorCode)
             .isEqualTo(AppFunctionException.ERROR_SYSTEM_ERROR)
         assertThat(AppFunctionSystemUnknownException().errorCategory)
             .isEqualTo(AppFunctionException.ERROR_CATEGORY_SYSTEM)
 
-        assertThat(AppFunctionCancelledException().errorCode)
+        assertThat(AppFunctionCancelledException().internalErrorCode)
             .isEqualTo(AppFunctionException.ERROR_CANCELLED)
         assertThat(AppFunctionCancelledException().errorCategory)
             .isEqualTo(AppFunctionException.ERROR_CATEGORY_SYSTEM)
diff --git a/appfunctions/appfunctions-common/src/main/java/androidx/appfunctions/AppFunctionException.kt b/appfunctions/appfunctions-common/src/main/java/androidx/appfunctions/AppFunctionException.kt
index e273dd4..39f28e8 100644
--- a/appfunctions/appfunctions-common/src/main/java/androidx/appfunctions/AppFunctionException.kt
+++ b/appfunctions/appfunctions-common/src/main/java/androidx/appfunctions/AppFunctionException.kt
@@ -28,27 +28,16 @@
 public abstract class AppFunctionException
 internal constructor(
     /** The error code. */
-    @ErrorCode internal val errorCode: Int,
+    @ErrorCode internal val internalErrorCode: Int,
     /** The error message. */
     public val errorMessage: String?,
     internal val extras: Bundle
 ) : Exception(errorMessage) {
-    /**
-     * Create an [AppFunctionException].
-     *
-     * @param errorCode The error code.
-     * @param errorMessage The error message.
-     */
-    public constructor(
-        @ErrorCode errorCode: Int,
-        errorMessage: String? = null,
-    ) : this(errorCode, errorMessage, Bundle.EMPTY)
-
     @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
     public fun toPlatformExtensionsClass():
         com.android.extensions.appfunctions.AppFunctionException {
         return com.android.extensions.appfunctions.AppFunctionException(
-            errorCode,
+            internalErrorCode,
             errorMessage,
             extras
         )
@@ -66,7 +55,7 @@
      */
     @ErrorCategory
     internal val errorCategory: Int =
-        when (errorCode) {
+        when (internalErrorCode) {
             in 1000..1999 -> ERROR_CATEGORY_REQUEST_ERROR
             in 2000..2999 -> ERROR_CATEGORY_SYSTEM
             in 3000..3999 -> ERROR_CATEGORY_APP
@@ -291,18 +280,24 @@
 /**
  * Thrown when an unknown error has occurred.
  *
- * <p> This Exception is used when the error doesn't belong to any other AppFunctionException. Note
- * that this different from [AppFunctionAppUnknownException], in that the error wasn't necessarily
- * caused by the app.
+ * <p> This Exception is used when the error doesn't belong to any other AppFunctionException. This
+ * may happen due to version skews in the error codes between the platform and the sdk. E.g. if the
+ * app is running on a newer platform version (with a new error code) and an older sdk.
+ *
+ * <p>Note that this is different from [AppFunctionAppUnknownException], in that the error wasn't
+ * necessarily caused by the app.
  */
 public class AppFunctionUnknownException
-internal constructor(
-    public val unknownErrorCode: Int,
-    errorMessage: String? = null,
-    extras: Bundle
-) : AppFunctionException(unknownErrorCode, errorMessage, extras) {
+internal constructor(public val errorCode: Int, errorMessage: String? = null, extras: Bundle) :
+    AppFunctionException(errorCode, errorMessage, extras) {
+    /**
+     * Create an [AppFunctionUnknownException].
+     *
+     * @param errorCode The error code.
+     * @param errorMessage The error message.
+     */
     public constructor(
-        unknownErrorCode: Int,
+        errorCode: Int,
         errorMessage: String? = null
-    ) : this(unknownErrorCode, errorMessage, Bundle.EMPTY)
+    ) : this(errorCode, errorMessage, Bundle.EMPTY)
 }
diff --git a/benchmark/benchmark-common/api/current.txt b/benchmark/benchmark-common/api/current.txt
index 44c9777..6dea054 100644
--- a/benchmark/benchmark-common/api/current.txt
+++ b/benchmark/benchmark-common/api/current.txt
@@ -54,6 +54,11 @@
 
   @SuppressCompatibility @androidx.benchmark.ExperimentalBenchmarkConfigApi public final class MicrobenchmarkConfig {
     ctor public MicrobenchmarkConfig();
+    ctor public MicrobenchmarkConfig(optional java.util.List<? extends androidx.benchmark.MetricCapture> metrics);
+    ctor public MicrobenchmarkConfig(optional java.util.List<? extends androidx.benchmark.MetricCapture> metrics, optional boolean traceAppTagEnabled);
+    ctor public MicrobenchmarkConfig(optional java.util.List<? extends androidx.benchmark.MetricCapture> metrics, optional boolean traceAppTagEnabled, optional boolean perfettoSdkTracingEnabled);
+    ctor public MicrobenchmarkConfig(optional java.util.List<? extends androidx.benchmark.MetricCapture> metrics, optional boolean traceAppTagEnabled, optional boolean perfettoSdkTracingEnabled, optional androidx.benchmark.ProfilerConfig? profiler);
+    ctor public MicrobenchmarkConfig(optional java.util.List<? extends androidx.benchmark.MetricCapture> metrics, optional boolean traceAppTagEnabled, optional boolean perfettoSdkTracingEnabled, optional androidx.benchmark.ProfilerConfig? profiler, optional Integer? warmupCount);
     ctor public MicrobenchmarkConfig(optional java.util.List<? extends androidx.benchmark.MetricCapture> metrics, optional boolean traceAppTagEnabled, optional boolean perfettoSdkTracingEnabled, optional androidx.benchmark.ProfilerConfig? profiler, optional Integer? warmupCount, optional Integer? measurementCount);
     method public Integer? getMeasurementCount();
     method public java.util.List<androidx.benchmark.MetricCapture> getMetrics();
diff --git a/benchmark/benchmark-common/api/restricted_current.txt b/benchmark/benchmark-common/api/restricted_current.txt
index f25ea8e..c94bb5b 100644
--- a/benchmark/benchmark-common/api/restricted_current.txt
+++ b/benchmark/benchmark-common/api/restricted_current.txt
@@ -57,6 +57,11 @@
 
   @SuppressCompatibility @androidx.benchmark.ExperimentalBenchmarkConfigApi public final class MicrobenchmarkConfig {
     ctor public MicrobenchmarkConfig();
+    ctor public MicrobenchmarkConfig(optional java.util.List<? extends androidx.benchmark.MetricCapture> metrics);
+    ctor public MicrobenchmarkConfig(optional java.util.List<? extends androidx.benchmark.MetricCapture> metrics, optional boolean traceAppTagEnabled);
+    ctor public MicrobenchmarkConfig(optional java.util.List<? extends androidx.benchmark.MetricCapture> metrics, optional boolean traceAppTagEnabled, optional boolean perfettoSdkTracingEnabled);
+    ctor public MicrobenchmarkConfig(optional java.util.List<? extends androidx.benchmark.MetricCapture> metrics, optional boolean traceAppTagEnabled, optional boolean perfettoSdkTracingEnabled, optional androidx.benchmark.ProfilerConfig? profiler);
+    ctor public MicrobenchmarkConfig(optional java.util.List<? extends androidx.benchmark.MetricCapture> metrics, optional boolean traceAppTagEnabled, optional boolean perfettoSdkTracingEnabled, optional androidx.benchmark.ProfilerConfig? profiler, optional Integer? warmupCount);
     ctor public MicrobenchmarkConfig(optional java.util.List<? extends androidx.benchmark.MetricCapture> metrics, optional boolean traceAppTagEnabled, optional boolean perfettoSdkTracingEnabled, optional androidx.benchmark.ProfilerConfig? profiler, optional Integer? warmupCount, optional Integer? measurementCount);
     method public Integer? getMeasurementCount();
     method public java.util.List<androidx.benchmark.MetricCapture> getMetrics();
diff --git a/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/DeviceInfoTest.kt b/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/DeviceInfoTest.kt
index 456635c..61d9775 100644
--- a/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/DeviceInfoTest.kt
+++ b/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/DeviceInfoTest.kt
@@ -62,6 +62,26 @@
     }
 
     @Test
+    fun willMethodTracingAffectMeasurements() {
+        // first clause - 26 through 30 (inclusive) affected
+        assertFalse(DeviceInfo.willMethodTracingAffectMeasurements(25, -1))
+        assertTrue(DeviceInfo.willMethodTracingAffectMeasurements(26, -1L))
+        assertTrue(DeviceInfo.willMethodTracingAffectMeasurements(30, -1L))
+        assertFalse(DeviceInfo.willMethodTracingAffectMeasurements(31, 310000000L))
+
+        // second clause - art API 34 regression
+        assertFalse(DeviceInfo.willMethodTracingAffectMeasurements(33, 330000000L))
+        assertTrue(DeviceInfo.willMethodTracingAffectMeasurements(33, 340000000L))
+        assertTrue(DeviceInfo.willMethodTracingAffectMeasurements(33, 341513000L - 1))
+        assertFalse(DeviceInfo.willMethodTracingAffectMeasurements(33, 341513000L))
+
+        // third clause - art API 34 regression and internal build ID
+        assertFalse(DeviceInfo.willMethodTracingAffectMeasurements(33, 990090000L))
+        assertTrue(DeviceInfo.willMethodTracingAffectMeasurements(34, 990090000L))
+        assertFalse(DeviceInfo.willMethodTracingAffectMeasurements(35, 990090000L))
+    }
+
+    @Test
     fun artMainlineVersion() =
         validateArtMainlineVersion(artMainlineVersion = DeviceInfo.artMainlineVersion)
 }
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/DeviceInfo.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/DeviceInfo.kt
index 3083747..002ab09 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/DeviceInfo.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/DeviceInfo.kt
@@ -302,6 +302,16 @@
     private const val ART_MAINLINE_MIN_VERSION_VERIFY_CLEARS_RUNTIME_IMAGE = 350800000L
 
     /**
+     * ART mainline 990090000 means the module is built from source in the system image and isn't
+     * updatable, and thus expectations should be conservative - assume that any potential bug on
+     * the current SDK version may be present on this device.
+     *
+     * Ideally, we'd have a minimum release build ID, but these may not be consistently and easily
+     * sortable.
+     */
+    private const val ART_MAINLINE_INTERNAL_BUILD_MIN = 990000000
+
+    /**
      * Used when mainline version failed to detect, but this is accepted due to low API level (<34)
      * where presence isn't guaranteed (e.g. go devices)
      */
@@ -320,15 +330,18 @@
             else -> ART_MAINLINE_VERSION_UNDETECTED
         }
 
-    val methodTracingAffectsMeasurements =
-        Build.VERSION.SDK_INT in 26..30 || // b/313868903
-            artMainlineVersion in ART_MAINLINE_VERSIONS_AFFECTING_METHOD_TRACING // b/303660864
+    fun willMethodTracingAffectMeasurements(sdkInt: Int, artVersion: Long): Boolean =
+        sdkInt in 26..30 || // b/313868903
+            artVersion in ART_MAINLINE_VERSIONS_AFFECTING_METHOD_TRACING || // b/303660864
+            (sdkInt == 34 && artVersion >= ART_MAINLINE_INTERNAL_BUILD_MIN) // b/303686344#comment31
 
-    fun isClassLoadTracingAvailable(targetApiLevel: Int, targetArtMainlineVersion: Long?): Boolean =
-        targetApiLevel >= 35 ||
-            (targetApiLevel >= 31 &&
-                (targetArtMainlineVersion == null ||
-                    targetArtMainlineVersion >= ART_MAINLINE_MIN_VERSION_CLASS_LOAD_TRACING))
+    val methodTracingAffectsMeasurements =
+        willMethodTracingAffectMeasurements(Build.VERSION.SDK_INT, artMainlineVersion)
+
+    fun isClassLoadTracingAvailable(sdkInt: Int, artVersion: Long?): Boolean =
+        sdkInt >= 35 ||
+            (sdkInt >= 31 &&
+                (artVersion == null || artVersion >= ART_MAINLINE_MIN_VERSION_CLASS_LOAD_TRACING))
 
     val supportsClassLoadTracing =
         isClassLoadTracingAvailable(Build.VERSION.SDK_INT, artMainlineVersion)
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/MicrobenchmarkConfig.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/MicrobenchmarkConfig.kt
index 102de5e..d2dd087 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/MicrobenchmarkConfig.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/MicrobenchmarkConfig.kt
@@ -23,6 +23,7 @@
  */
 @ExperimentalBenchmarkConfigApi
 class MicrobenchmarkConfig
+@JvmOverloads
 constructor(
     /**
      * Timing metrics for primary phase, post-warmup
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Metric.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Metric.kt
index 4810691..aaa9668 100644
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Metric.kt
+++ b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Metric.kt
@@ -23,9 +23,7 @@
 import androidx.benchmark.Shell
 import androidx.benchmark.macro.BatteryCharge.hasMinimumCharge
 import androidx.benchmark.macro.PowerMetric.Companion.deviceSupportsHighPrecisionTracking
-import androidx.benchmark.macro.PowerMetric.Type
 import androidx.benchmark.macro.PowerRail.hasMetrics
-import androidx.benchmark.macro.TraceSectionMetric.Mode
 import androidx.benchmark.macro.perfetto.BatteryDischargeQuery
 import androidx.benchmark.macro.perfetto.FrameTimingQuery
 import androidx.benchmark.macro.perfetto.FrameTimingQuery.SubMetric
@@ -730,8 +728,8 @@
                 .asMeasurements("artVerifyClass") +
             if (
                 DeviceInfo.isClassLoadTracingAvailable(
-                    targetApiLevel = captureInfo.apiLevel,
-                    targetArtMainlineVersion = captureInfo.artMainlineVersion
+                    sdkInt = captureInfo.apiLevel,
+                    artVersion = captureInfo.artMainlineVersion
                 )
             ) {
                 traceSession
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/metalava/MetalavaRunner.kt b/buildSrc/private/src/main/kotlin/androidx/build/metalava/MetalavaRunner.kt
index 3325d22..f445c79 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/metalava/MetalavaRunner.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/metalava/MetalavaRunner.kt
@@ -186,6 +186,12 @@
                 )
                 .joinToString()
         )
+    // Acronyms that can be used in their all-caps form. "SQ" is included to allow "SQLite".
+    val allowedAcronyms = listOf("SQL", "SQ", "URL", "EGL", "GL", "KHR")
+    for (acronym in allowedAcronyms) {
+        args.add("--api-lint-allowed-acronym")
+        args.add(acronym)
+    }
     val javaOnlyIssues = listOf("MissingJvmstatic", "ArrayReturn", "ValueClassDefinition")
     val javaOnlyErrorLevel =
         if (targetsJavaConsumers) {
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/AudioRestrictionController.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/AudioRestrictionController.kt
index 5a1ac48..954bda9 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/AudioRestrictionController.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/AudioRestrictionController.kt
@@ -67,8 +67,9 @@
         get() = synchronized(lock) { field }
         set(value: AudioRestrictionMode) {
             synchronized(lock) {
+                val previousMode = computeAudioRestrictionMode()
                 field = value
-                updateListenersMode()
+                updateListenersMode(previousMode)
             }
         }
 
@@ -80,15 +81,17 @@
         mode: AudioRestrictionMode
     ) {
         synchronized(lock) {
+            val previousMode = computeAudioRestrictionMode()
             audioRestrictionModeMap[cameraGraph] = mode
-            updateListenersMode()
+            updateListenersMode(previousMode)
         }
     }
 
     override fun removeCameraGraph(cameraGraph: CameraGraph) {
         synchronized(lock) {
+            val previousMode = computeAudioRestrictionMode()
             audioRestrictionModeMap.remove(cameraGraph)
-            updateListenersMode()
+            updateListenersMode(previousMode)
         }
     }
 
@@ -128,10 +131,12 @@
     }
 
     @GuardedBy("lock")
-    private fun updateListenersMode() {
+    private fun updateListenersMode(previousMode: AudioRestrictionMode? = null) {
         val mode = computeAudioRestrictionMode()
-        for (listener in activeListeners) {
-            listener.onCameraAudioRestrictionUpdated(mode)
+        if (previousMode != null && mode != previousMode) {
+            for (listener in activeListeners) {
+                listener.onCameraAudioRestrictionUpdated(mode)
+            }
         }
     }
 }
diff --git a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/compat/AudioRestrictionControllerImplTest.kt b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/compat/AudioRestrictionControllerImplTest.kt
index acdb35f..53b462e 100644
--- a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/compat/AudioRestrictionControllerImplTest.kt
+++ b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/compat/AudioRestrictionControllerImplTest.kt
@@ -97,8 +97,8 @@
             AUDIO_RESTRICTION_VIBRATION
         )
 
-        // Whenever a setter method is called, an update should be called on the listener
-        verify(listener1, times(2))
+        // If the mode hasn't changed, there shouldn't be a second update call
+        verify(listener1, times(1))
             .onCameraAudioRestrictionUpdated(AUDIO_RESTRICTION_VIBRATION_SOUND)
         verify(listener1, never()).onCameraAudioRestrictionUpdated(AUDIO_RESTRICTION_VIBRATION)
     }
@@ -114,8 +114,8 @@
         )
         audioRestrictionController.globalAudioRestrictionMode = AUDIO_RESTRICTION_VIBRATION
 
-        // Whenever a setter method is called, an update should be called on the listener
-        verify(listener1, times(2))
+        // If the mode hasn't changed, there shouldn't be a second update call
+        verify(listener1, times(1))
             .onCameraAudioRestrictionUpdated(AUDIO_RESTRICTION_VIBRATION_SOUND)
         verify(listener1, never()).onCameraAudioRestrictionUpdated(AUDIO_RESTRICTION_VIBRATION)
     }
@@ -134,7 +134,7 @@
             AUDIO_RESTRICTION_VIBRATION
         )
 
-        verify(listener1, times(2))
+        verify(listener1, times(1))
             .onCameraAudioRestrictionUpdated(AUDIO_RESTRICTION_VIBRATION_SOUND)
 
         audioRestrictionController.removeCameraGraph(cameraGraph1)
diff --git a/compose/foundation/foundation-layout/api/current.txt b/compose/foundation/foundation-layout/api/current.txt
index 0576ad7..7b4c673 100644
--- a/compose/foundation/foundation-layout/api/current.txt
+++ b/compose/foundation/foundation-layout/api/current.txt
@@ -111,81 +111,81 @@
     method @androidx.compose.runtime.Stable public androidx.compose.ui.Modifier weight(androidx.compose.ui.Modifier, @FloatRange(from=0.0, fromInclusive=false) float weight, optional boolean fill);
   }
 
-  @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final class ContextualFlowColumnOverflow extends androidx.compose.foundation.layout.FlowLayoutOverflow {
-    field public static final androidx.compose.foundation.layout.ContextualFlowColumnOverflow.Companion Companion;
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final class ContextualFlowColumnOverflow extends androidx.compose.foundation.layout.FlowLayoutOverflow {
+    field @Deprecated public static final androidx.compose.foundation.layout.ContextualFlowColumnOverflow.Companion Companion;
   }
 
-  public static final class ContextualFlowColumnOverflow.Companion {
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowColumnOverflow expandIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowColumnOverflowScope,kotlin.Unit> content);
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.ContextualFlowColumnOverflow expandOrCollapseIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowColumnOverflowScope,kotlin.Unit> expandIndicator, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowColumnOverflowScope,kotlin.Unit> collapseIndicator, optional int minColumnsToShowCollapse, optional float minWidthToShowCollapse);
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowColumnOverflow getClip();
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowColumnOverflow getVisible();
-    property @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.ContextualFlowColumnOverflow Clip;
-    property @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.ContextualFlowColumnOverflow Visible;
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public static final class ContextualFlowColumnOverflow.Companion {
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowColumnOverflow expandIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowColumnOverflowScope,kotlin.Unit> content);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.ContextualFlowColumnOverflow expandOrCollapseIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowColumnOverflowScope,kotlin.Unit> expandIndicator, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowColumnOverflowScope,kotlin.Unit> collapseIndicator, optional int minColumnsToShowCollapse, optional float minWidthToShowCollapse);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowColumnOverflow getClip();
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowColumnOverflow getVisible();
+    property @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.ContextualFlowColumnOverflow Clip;
+    property @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.ContextualFlowColumnOverflow Visible;
   }
 
-  @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public interface ContextualFlowColumnOverflowScope extends androidx.compose.foundation.layout.FlowColumnOverflowScope {
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public interface ContextualFlowColumnOverflowScope extends androidx.compose.foundation.layout.FlowColumnOverflowScope {
   }
 
-  @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public interface ContextualFlowColumnScope extends androidx.compose.foundation.layout.ColumnScope {
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.ui.Modifier fillMaxColumnWidth(androidx.compose.ui.Modifier, optional @FloatRange(from=0.0, to=1.0) float fraction);
-    method public int getIndexInLine();
-    method public int getLineIndex();
-    method public float getMaxHeightInLine();
-    method public float getMaxWidth();
-    property public abstract int indexInLine;
-    property public abstract int lineIndex;
-    property public abstract float maxHeightInLine;
-    property public abstract float maxWidth;
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public interface ContextualFlowColumnScope extends androidx.compose.foundation.layout.ColumnScope {
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.ui.Modifier fillMaxColumnWidth(androidx.compose.ui.Modifier, optional @FloatRange(from=0.0, to=1.0) float fraction);
+    method @Deprecated public int getIndexInLine();
+    method @Deprecated public int getLineIndex();
+    method @Deprecated public float getMaxHeightInLine();
+    method @Deprecated public float getMaxWidth();
+    property @Deprecated public abstract int indexInLine;
+    property @Deprecated public abstract int lineIndex;
+    property @Deprecated public abstract float maxHeightInLine;
+    property @Deprecated public abstract float maxWidth;
   }
 
   public final class ContextualFlowLayoutKt {
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public static void ContextualFlowColumn(int itemCount, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, optional androidx.compose.ui.Alignment.Horizontal itemHorizontalAlignment, optional int maxItemsInEachColumn, optional int maxLines, optional androidx.compose.foundation.layout.ContextualFlowColumnOverflow overflow, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.layout.ContextualFlowColumnScope,? super java.lang.Integer,kotlin.Unit> content);
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public static void ContextualFlowRow(int itemCount, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.ui.Alignment.Vertical itemVerticalAlignment, optional int maxItemsInEachRow, optional int maxLines, optional androidx.compose.foundation.layout.ContextualFlowRowOverflow overflow, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.layout.ContextualFlowRowScope,? super java.lang.Integer,kotlin.Unit> content);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public static void ContextualFlowColumn(int itemCount, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, optional androidx.compose.ui.Alignment.Horizontal itemHorizontalAlignment, optional int maxItemsInEachColumn, optional int maxLines, optional androidx.compose.foundation.layout.ContextualFlowColumnOverflow overflow, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.layout.ContextualFlowColumnScope,? super java.lang.Integer,kotlin.Unit> content);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public static void ContextualFlowRow(int itemCount, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.ui.Alignment.Vertical itemVerticalAlignment, optional int maxItemsInEachRow, optional int maxLines, optional androidx.compose.foundation.layout.ContextualFlowRowOverflow overflow, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.layout.ContextualFlowRowScope,? super java.lang.Integer,kotlin.Unit> content);
   }
 
-  @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final class ContextualFlowRowOverflow extends androidx.compose.foundation.layout.FlowLayoutOverflow {
-    field public static final androidx.compose.foundation.layout.ContextualFlowRowOverflow.Companion Companion;
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final class ContextualFlowRowOverflow extends androidx.compose.foundation.layout.FlowLayoutOverflow {
+    field @Deprecated public static final androidx.compose.foundation.layout.ContextualFlowRowOverflow.Companion Companion;
   }
 
-  public static final class ContextualFlowRowOverflow.Companion {
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowRowOverflow expandIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowRowOverflowScope,kotlin.Unit> content);
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.ContextualFlowRowOverflow expandOrCollapseIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowRowOverflowScope,kotlin.Unit> expandIndicator, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowRowOverflowScope,kotlin.Unit> collapseIndicator, optional int minRowsToShowCollapse, optional float minHeightToShowCollapse);
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowRowOverflow getClip();
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowRowOverflow getVisible();
-    property @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.ContextualFlowRowOverflow Clip;
-    property @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.ContextualFlowRowOverflow Visible;
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public static final class ContextualFlowRowOverflow.Companion {
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowRowOverflow expandIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowRowOverflowScope,kotlin.Unit> content);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.ContextualFlowRowOverflow expandOrCollapseIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowRowOverflowScope,kotlin.Unit> expandIndicator, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowRowOverflowScope,kotlin.Unit> collapseIndicator, optional int minRowsToShowCollapse, optional float minHeightToShowCollapse);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowRowOverflow getClip();
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowRowOverflow getVisible();
+    property @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.ContextualFlowRowOverflow Clip;
+    property @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.ContextualFlowRowOverflow Visible;
   }
 
-  @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public interface ContextualFlowRowOverflowScope extends androidx.compose.foundation.layout.FlowRowOverflowScope {
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public interface ContextualFlowRowOverflowScope extends androidx.compose.foundation.layout.FlowRowOverflowScope {
   }
 
-  @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public interface ContextualFlowRowScope extends androidx.compose.foundation.layout.RowScope {
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.ui.Modifier fillMaxRowHeight(androidx.compose.ui.Modifier, optional @FloatRange(from=0.0, to=1.0) float fraction);
-    method public int getIndexInLine();
-    method public int getLineIndex();
-    method public float getMaxHeight();
-    method public float getMaxWidthInLine();
-    property public abstract int indexInLine;
-    property public abstract int lineIndex;
-    property public abstract float maxHeight;
-    property public abstract float maxWidthInLine;
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public interface ContextualFlowRowScope extends androidx.compose.foundation.layout.RowScope {
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.ui.Modifier fillMaxRowHeight(androidx.compose.ui.Modifier, optional @FloatRange(from=0.0, to=1.0) float fraction);
+    method @Deprecated public int getIndexInLine();
+    method @Deprecated public int getLineIndex();
+    method @Deprecated public float getMaxHeight();
+    method @Deprecated public float getMaxWidthInLine();
+    property @Deprecated public abstract int indexInLine;
+    property @Deprecated public abstract int lineIndex;
+    property @Deprecated public abstract float maxHeight;
+    property @Deprecated public abstract float maxWidthInLine;
   }
 
   @SuppressCompatibility @kotlin.RequiresOptIn(message="The API of this layout is experimental and is likely to change in the future.") @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface ExperimentalLayoutApi {
   }
 
-  @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final class FlowColumnOverflow extends androidx.compose.foundation.layout.FlowLayoutOverflow {
-    field public static final androidx.compose.foundation.layout.FlowColumnOverflow.Companion Companion;
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final class FlowColumnOverflow extends androidx.compose.foundation.layout.FlowLayoutOverflow {
+    field @Deprecated public static final androidx.compose.foundation.layout.FlowColumnOverflow.Companion Companion;
   }
 
-  public static final class FlowColumnOverflow.Companion {
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowColumnOverflow expandIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowColumnOverflowScope,kotlin.Unit> content);
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.FlowColumnOverflow expandOrCollapseIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowColumnOverflowScope,kotlin.Unit> expandIndicator, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowColumnOverflowScope,kotlin.Unit> collapseIndicator, optional int minColumnsToShowCollapse, optional float minWidthToShowCollapse);
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowColumnOverflow getClip();
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowColumnOverflow getVisible();
-    property @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.FlowColumnOverflow Clip;
-    property @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.FlowColumnOverflow Visible;
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public static final class FlowColumnOverflow.Companion {
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowColumnOverflow expandIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowColumnOverflowScope,kotlin.Unit> content);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.FlowColumnOverflow expandOrCollapseIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowColumnOverflowScope,kotlin.Unit> expandIndicator, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowColumnOverflowScope,kotlin.Unit> collapseIndicator, optional int minColumnsToShowCollapse, optional float minWidthToShowCollapse);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowColumnOverflow getClip();
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowColumnOverflow getVisible();
+    property @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.FlowColumnOverflow Clip;
+    property @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.FlowColumnOverflow Visible;
   }
 
   @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public interface FlowColumnOverflowScope extends androidx.compose.foundation.layout.FlowColumnScope {
@@ -200,24 +200,26 @@
   }
 
   public final class FlowLayoutKt {
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public static void FlowColumn(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, optional androidx.compose.ui.Alignment.Horizontal itemHorizontalAlignment, optional int maxItemsInEachColumn, optional int maxLines, optional androidx.compose.foundation.layout.FlowColumnOverflow overflow, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowColumnScope,kotlin.Unit> content);
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public static void FlowRow(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.ui.Alignment.Vertical itemVerticalAlignment, optional int maxItemsInEachRow, optional int maxLines, optional androidx.compose.foundation.layout.FlowRowOverflow overflow, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowRowScope,kotlin.Unit> content);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public static void FlowColumn(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, optional androidx.compose.ui.Alignment.Horizontal itemHorizontalAlignment, optional int maxItemsInEachColumn, optional int maxLines, optional androidx.compose.foundation.layout.FlowColumnOverflow overflow, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowColumnScope,kotlin.Unit> content);
+    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public static void FlowColumn(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, optional androidx.compose.ui.Alignment.Horizontal itemHorizontalAlignment, optional int maxItemsInEachColumn, optional int maxLines, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowColumnScope,kotlin.Unit> content);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public static void FlowRow(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.ui.Alignment.Vertical itemVerticalAlignment, optional int maxItemsInEachRow, optional int maxLines, optional androidx.compose.foundation.layout.FlowRowOverflow overflow, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowRowScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void FlowRow(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.ui.Alignment.Vertical itemVerticalAlignment, optional int maxItemsInEachRow, optional int maxLines, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowRowScope,kotlin.Unit> content);
   }
 
-  @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public abstract sealed class FlowLayoutOverflow {
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public abstract sealed class FlowLayoutOverflow {
   }
 
-  @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final class FlowRowOverflow extends androidx.compose.foundation.layout.FlowLayoutOverflow {
-    field public static final androidx.compose.foundation.layout.FlowRowOverflow.Companion Companion;
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final class FlowRowOverflow extends androidx.compose.foundation.layout.FlowLayoutOverflow {
+    field @Deprecated public static final androidx.compose.foundation.layout.FlowRowOverflow.Companion Companion;
   }
 
-  public static final class FlowRowOverflow.Companion {
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowRowOverflow expandIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowRowOverflowScope,kotlin.Unit> content);
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.FlowRowOverflow expandOrCollapseIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowRowOverflowScope,kotlin.Unit> expandIndicator, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowRowOverflowScope,kotlin.Unit> collapseIndicator, optional int minRowsToShowCollapse, optional float minHeightToShowCollapse);
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowRowOverflow getClip();
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowRowOverflow getVisible();
-    property @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.FlowRowOverflow Clip;
-    property @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.FlowRowOverflow Visible;
+  @Deprecated public static final class FlowRowOverflow.Companion {
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowRowOverflow expandIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowRowOverflowScope,kotlin.Unit> content);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.FlowRowOverflow expandOrCollapseIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowRowOverflowScope,kotlin.Unit> expandIndicator, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowRowOverflowScope,kotlin.Unit> collapseIndicator, optional int minRowsToShowCollapse, optional float minHeightToShowCollapse);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowRowOverflow getClip();
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowRowOverflow getVisible();
+    property @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.FlowRowOverflow Clip;
+    property @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.FlowRowOverflow Visible;
   }
 
   @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public interface FlowRowOverflowScope extends androidx.compose.foundation.layout.FlowRowScope {
diff --git a/compose/foundation/foundation-layout/api/restricted_current.txt b/compose/foundation/foundation-layout/api/restricted_current.txt
index 1a68ea9..438f4c8 100644
--- a/compose/foundation/foundation-layout/api/restricted_current.txt
+++ b/compose/foundation/foundation-layout/api/restricted_current.txt
@@ -116,81 +116,81 @@
     method @androidx.compose.runtime.Stable public androidx.compose.ui.Modifier weight(androidx.compose.ui.Modifier, @FloatRange(from=0.0, fromInclusive=false) float weight, optional boolean fill);
   }
 
-  @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final class ContextualFlowColumnOverflow extends androidx.compose.foundation.layout.FlowLayoutOverflow {
-    field public static final androidx.compose.foundation.layout.ContextualFlowColumnOverflow.Companion Companion;
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final class ContextualFlowColumnOverflow extends androidx.compose.foundation.layout.FlowLayoutOverflow {
+    field @Deprecated public static final androidx.compose.foundation.layout.ContextualFlowColumnOverflow.Companion Companion;
   }
 
-  public static final class ContextualFlowColumnOverflow.Companion {
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowColumnOverflow expandIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowColumnOverflowScope,kotlin.Unit> content);
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.ContextualFlowColumnOverflow expandOrCollapseIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowColumnOverflowScope,kotlin.Unit> expandIndicator, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowColumnOverflowScope,kotlin.Unit> collapseIndicator, optional int minColumnsToShowCollapse, optional float minWidthToShowCollapse);
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowColumnOverflow getClip();
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowColumnOverflow getVisible();
-    property @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.ContextualFlowColumnOverflow Clip;
-    property @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.ContextualFlowColumnOverflow Visible;
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public static final class ContextualFlowColumnOverflow.Companion {
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowColumnOverflow expandIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowColumnOverflowScope,kotlin.Unit> content);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.ContextualFlowColumnOverflow expandOrCollapseIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowColumnOverflowScope,kotlin.Unit> expandIndicator, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowColumnOverflowScope,kotlin.Unit> collapseIndicator, optional int minColumnsToShowCollapse, optional float minWidthToShowCollapse);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowColumnOverflow getClip();
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowColumnOverflow getVisible();
+    property @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.ContextualFlowColumnOverflow Clip;
+    property @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.ContextualFlowColumnOverflow Visible;
   }
 
-  @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public interface ContextualFlowColumnOverflowScope extends androidx.compose.foundation.layout.FlowColumnOverflowScope {
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public interface ContextualFlowColumnOverflowScope extends androidx.compose.foundation.layout.FlowColumnOverflowScope {
   }
 
-  @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public interface ContextualFlowColumnScope extends androidx.compose.foundation.layout.ColumnScope {
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.ui.Modifier fillMaxColumnWidth(androidx.compose.ui.Modifier, optional @FloatRange(from=0.0, to=1.0) float fraction);
-    method public int getIndexInLine();
-    method public int getLineIndex();
-    method public float getMaxHeightInLine();
-    method public float getMaxWidth();
-    property public abstract int indexInLine;
-    property public abstract int lineIndex;
-    property public abstract float maxHeightInLine;
-    property public abstract float maxWidth;
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public interface ContextualFlowColumnScope extends androidx.compose.foundation.layout.ColumnScope {
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.ui.Modifier fillMaxColumnWidth(androidx.compose.ui.Modifier, optional @FloatRange(from=0.0, to=1.0) float fraction);
+    method @Deprecated public int getIndexInLine();
+    method @Deprecated public int getLineIndex();
+    method @Deprecated public float getMaxHeightInLine();
+    method @Deprecated public float getMaxWidth();
+    property @Deprecated public abstract int indexInLine;
+    property @Deprecated public abstract int lineIndex;
+    property @Deprecated public abstract float maxHeightInLine;
+    property @Deprecated public abstract float maxWidth;
   }
 
   public final class ContextualFlowLayoutKt {
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public static void ContextualFlowColumn(int itemCount, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, optional androidx.compose.ui.Alignment.Horizontal itemHorizontalAlignment, optional int maxItemsInEachColumn, optional int maxLines, optional androidx.compose.foundation.layout.ContextualFlowColumnOverflow overflow, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.layout.ContextualFlowColumnScope,? super java.lang.Integer,kotlin.Unit> content);
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public static void ContextualFlowRow(int itemCount, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.ui.Alignment.Vertical itemVerticalAlignment, optional int maxItemsInEachRow, optional int maxLines, optional androidx.compose.foundation.layout.ContextualFlowRowOverflow overflow, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.layout.ContextualFlowRowScope,? super java.lang.Integer,kotlin.Unit> content);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public static void ContextualFlowColumn(int itemCount, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, optional androidx.compose.ui.Alignment.Horizontal itemHorizontalAlignment, optional int maxItemsInEachColumn, optional int maxLines, optional androidx.compose.foundation.layout.ContextualFlowColumnOverflow overflow, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.layout.ContextualFlowColumnScope,? super java.lang.Integer,kotlin.Unit> content);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public static void ContextualFlowRow(int itemCount, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.ui.Alignment.Vertical itemVerticalAlignment, optional int maxItemsInEachRow, optional int maxLines, optional androidx.compose.foundation.layout.ContextualFlowRowOverflow overflow, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.layout.ContextualFlowRowScope,? super java.lang.Integer,kotlin.Unit> content);
   }
 
-  @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final class ContextualFlowRowOverflow extends androidx.compose.foundation.layout.FlowLayoutOverflow {
-    field public static final androidx.compose.foundation.layout.ContextualFlowRowOverflow.Companion Companion;
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final class ContextualFlowRowOverflow extends androidx.compose.foundation.layout.FlowLayoutOverflow {
+    field @Deprecated public static final androidx.compose.foundation.layout.ContextualFlowRowOverflow.Companion Companion;
   }
 
-  public static final class ContextualFlowRowOverflow.Companion {
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowRowOverflow expandIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowRowOverflowScope,kotlin.Unit> content);
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.ContextualFlowRowOverflow expandOrCollapseIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowRowOverflowScope,kotlin.Unit> expandIndicator, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowRowOverflowScope,kotlin.Unit> collapseIndicator, optional int minRowsToShowCollapse, optional float minHeightToShowCollapse);
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowRowOverflow getClip();
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowRowOverflow getVisible();
-    property @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.ContextualFlowRowOverflow Clip;
-    property @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.ContextualFlowRowOverflow Visible;
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public static final class ContextualFlowRowOverflow.Companion {
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowRowOverflow expandIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowRowOverflowScope,kotlin.Unit> content);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.ContextualFlowRowOverflow expandOrCollapseIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowRowOverflowScope,kotlin.Unit> expandIndicator, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowRowOverflowScope,kotlin.Unit> collapseIndicator, optional int minRowsToShowCollapse, optional float minHeightToShowCollapse);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowRowOverflow getClip();
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowRowOverflow getVisible();
+    property @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.ContextualFlowRowOverflow Clip;
+    property @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.ContextualFlowRowOverflow Visible;
   }
 
-  @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public interface ContextualFlowRowOverflowScope extends androidx.compose.foundation.layout.FlowRowOverflowScope {
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public interface ContextualFlowRowOverflowScope extends androidx.compose.foundation.layout.FlowRowOverflowScope {
   }
 
-  @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public interface ContextualFlowRowScope extends androidx.compose.foundation.layout.RowScope {
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.ui.Modifier fillMaxRowHeight(androidx.compose.ui.Modifier, optional @FloatRange(from=0.0, to=1.0) float fraction);
-    method public int getIndexInLine();
-    method public int getLineIndex();
-    method public float getMaxHeight();
-    method public float getMaxWidthInLine();
-    property public abstract int indexInLine;
-    property public abstract int lineIndex;
-    property public abstract float maxHeight;
-    property public abstract float maxWidthInLine;
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public interface ContextualFlowRowScope extends androidx.compose.foundation.layout.RowScope {
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.ui.Modifier fillMaxRowHeight(androidx.compose.ui.Modifier, optional @FloatRange(from=0.0, to=1.0) float fraction);
+    method @Deprecated public int getIndexInLine();
+    method @Deprecated public int getLineIndex();
+    method @Deprecated public float getMaxHeight();
+    method @Deprecated public float getMaxWidthInLine();
+    property @Deprecated public abstract int indexInLine;
+    property @Deprecated public abstract int lineIndex;
+    property @Deprecated public abstract float maxHeight;
+    property @Deprecated public abstract float maxWidthInLine;
   }
 
   @SuppressCompatibility @kotlin.RequiresOptIn(message="The API of this layout is experimental and is likely to change in the future.") @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface ExperimentalLayoutApi {
   }
 
-  @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final class FlowColumnOverflow extends androidx.compose.foundation.layout.FlowLayoutOverflow {
-    field public static final androidx.compose.foundation.layout.FlowColumnOverflow.Companion Companion;
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final class FlowColumnOverflow extends androidx.compose.foundation.layout.FlowLayoutOverflow {
+    field @Deprecated public static final androidx.compose.foundation.layout.FlowColumnOverflow.Companion Companion;
   }
 
-  public static final class FlowColumnOverflow.Companion {
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowColumnOverflow expandIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowColumnOverflowScope,kotlin.Unit> content);
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.FlowColumnOverflow expandOrCollapseIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowColumnOverflowScope,kotlin.Unit> expandIndicator, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowColumnOverflowScope,kotlin.Unit> collapseIndicator, optional int minColumnsToShowCollapse, optional float minWidthToShowCollapse);
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowColumnOverflow getClip();
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowColumnOverflow getVisible();
-    property @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.FlowColumnOverflow Clip;
-    property @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.FlowColumnOverflow Visible;
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public static final class FlowColumnOverflow.Companion {
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowColumnOverflow expandIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowColumnOverflowScope,kotlin.Unit> content);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.FlowColumnOverflow expandOrCollapseIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowColumnOverflowScope,kotlin.Unit> expandIndicator, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowColumnOverflowScope,kotlin.Unit> collapseIndicator, optional int minColumnsToShowCollapse, optional float minWidthToShowCollapse);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowColumnOverflow getClip();
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowColumnOverflow getVisible();
+    property @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.FlowColumnOverflow Clip;
+    property @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.FlowColumnOverflow Visible;
   }
 
   @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public interface FlowColumnOverflowScope extends androidx.compose.foundation.layout.FlowColumnScope {
@@ -205,26 +205,28 @@
   }
 
   public final class FlowLayoutKt {
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public static void FlowColumn(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, optional androidx.compose.ui.Alignment.Horizontal itemHorizontalAlignment, optional int maxItemsInEachColumn, optional int maxLines, optional androidx.compose.foundation.layout.FlowColumnOverflow overflow, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowColumnScope,kotlin.Unit> content);
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public static void FlowRow(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.ui.Alignment.Vertical itemVerticalAlignment, optional int maxItemsInEachRow, optional int maxLines, optional androidx.compose.foundation.layout.FlowRowOverflow overflow, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowRowScope,kotlin.Unit> content);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public static void FlowColumn(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, optional androidx.compose.ui.Alignment.Horizontal itemHorizontalAlignment, optional int maxItemsInEachColumn, optional int maxLines, optional androidx.compose.foundation.layout.FlowColumnOverflow overflow, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowColumnScope,kotlin.Unit> content);
+    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public static void FlowColumn(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, optional androidx.compose.ui.Alignment.Horizontal itemHorizontalAlignment, optional int maxItemsInEachColumn, optional int maxLines, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowColumnScope,kotlin.Unit> content);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public static void FlowRow(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.ui.Alignment.Vertical itemVerticalAlignment, optional int maxItemsInEachRow, optional int maxLines, optional androidx.compose.foundation.layout.FlowRowOverflow overflow, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowRowScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void FlowRow(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.ui.Alignment.Vertical itemVerticalAlignment, optional int maxItemsInEachRow, optional int maxLines, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowRowScope,kotlin.Unit> content);
     method @androidx.compose.runtime.Composable @kotlin.PublishedApi internal static androidx.compose.ui.layout.MeasurePolicy columnMeasurementHelper(androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, int maxItemsInMainAxis);
     method @androidx.compose.runtime.Composable @kotlin.PublishedApi internal static androidx.compose.ui.layout.MeasurePolicy rowMeasurementHelper(androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, int maxItemsInMainAxis);
   }
 
-  @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public abstract sealed class FlowLayoutOverflow {
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public abstract sealed class FlowLayoutOverflow {
   }
 
-  @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final class FlowRowOverflow extends androidx.compose.foundation.layout.FlowLayoutOverflow {
-    field public static final androidx.compose.foundation.layout.FlowRowOverflow.Companion Companion;
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final class FlowRowOverflow extends androidx.compose.foundation.layout.FlowLayoutOverflow {
+    field @Deprecated public static final androidx.compose.foundation.layout.FlowRowOverflow.Companion Companion;
   }
 
-  public static final class FlowRowOverflow.Companion {
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowRowOverflow expandIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowRowOverflowScope,kotlin.Unit> content);
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.FlowRowOverflow expandOrCollapseIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowRowOverflowScope,kotlin.Unit> expandIndicator, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowRowOverflowScope,kotlin.Unit> collapseIndicator, optional int minRowsToShowCollapse, optional float minHeightToShowCollapse);
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowRowOverflow getClip();
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowRowOverflow getVisible();
-    property @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.FlowRowOverflow Clip;
-    property @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.FlowRowOverflow Visible;
+  @Deprecated public static final class FlowRowOverflow.Companion {
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowRowOverflow expandIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowRowOverflowScope,kotlin.Unit> content);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.FlowRowOverflow expandOrCollapseIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowRowOverflowScope,kotlin.Unit> expandIndicator, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowRowOverflowScope,kotlin.Unit> collapseIndicator, optional int minRowsToShowCollapse, optional float minHeightToShowCollapse);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowRowOverflow getClip();
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowRowOverflow getVisible();
+    property @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.FlowRowOverflow Clip;
+    property @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.FlowRowOverflow Visible;
   }
 
   @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public interface FlowRowOverflowScope extends androidx.compose.foundation.layout.FlowRowScope {
diff --git a/compose/foundation/foundation-layout/samples/src/main/java/androidx/compose/foundation/layout/samples/ContextualFlowColumnSample.kt b/compose/foundation/foundation-layout/samples/src/main/java/androidx/compose/foundation/layout/samples/ContextualFlowColumnSample.kt
index 6a7c208..96dae13 100644
--- a/compose/foundation/foundation-layout/samples/src/main/java/androidx/compose/foundation/layout/samples/ContextualFlowColumnSample.kt
+++ b/compose/foundation/foundation-layout/samples/src/main/java/androidx/compose/foundation/layout/samples/ContextualFlowColumnSample.kt
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+@file:Suppress("DEPRECATION")
+
 package androidx.compose.foundation.layout.samples
 
 import androidx.annotation.Sampled
diff --git a/compose/foundation/foundation-layout/samples/src/main/java/androidx/compose/foundation/layout/samples/ContextualFlowRowSample.kt b/compose/foundation/foundation-layout/samples/src/main/java/androidx/compose/foundation/layout/samples/ContextualFlowRowSample.kt
index f0eda4d..d10e927 100644
--- a/compose/foundation/foundation-layout/samples/src/main/java/androidx/compose/foundation/layout/samples/ContextualFlowRowSample.kt
+++ b/compose/foundation/foundation-layout/samples/src/main/java/androidx/compose/foundation/layout/samples/ContextualFlowRowSample.kt
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+@file:Suppress("DEPRECATION")
+
 package androidx.compose.foundation.layout.samples
 
 import androidx.annotation.Sampled
diff --git a/compose/foundation/foundation-layout/samples/src/main/java/androidx/compose/foundation/layout/samples/FlowColumnSample.kt b/compose/foundation/foundation-layout/samples/src/main/java/androidx/compose/foundation/layout/samples/FlowColumnSample.kt
index ca95c71..5b45c21 100644
--- a/compose/foundation/foundation-layout/samples/src/main/java/androidx/compose/foundation/layout/samples/FlowColumnSample.kt
+++ b/compose/foundation/foundation-layout/samples/src/main/java/androidx/compose/foundation/layout/samples/FlowColumnSample.kt
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+@file:Suppress("DEPRECATION")
+
 package androidx.compose.foundation.layout.samples
 
 import androidx.annotation.Sampled
diff --git a/compose/foundation/foundation-layout/samples/src/main/java/androidx/compose/foundation/layout/samples/FlowRowSample.kt b/compose/foundation/foundation-layout/samples/src/main/java/androidx/compose/foundation/layout/samples/FlowRowSample.kt
index 15f5304..cd41109 100644
--- a/compose/foundation/foundation-layout/samples/src/main/java/androidx/compose/foundation/layout/samples/FlowRowSample.kt
+++ b/compose/foundation/foundation-layout/samples/src/main/java/androidx/compose/foundation/layout/samples/FlowRowSample.kt
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+@file:Suppress("DEPRECATION")
+
 package androidx.compose.foundation.layout.samples
 
 import androidx.annotation.Sampled
diff --git a/compose/foundation/foundation-layout/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/layout/ContextualFlowRowColumnTest.kt b/compose/foundation/foundation-layout/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/layout/ContextualFlowRowColumnTest.kt
index 086f752..1ee8cd1 100644
--- a/compose/foundation/foundation-layout/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/layout/ContextualFlowRowColumnTest.kt
+++ b/compose/foundation/foundation-layout/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/layout/ContextualFlowRowColumnTest.kt
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+@file:Suppress("DEPRECATION")
+
 package androidx.compose.foundation.layout
 
 import androidx.compose.foundation.background
diff --git a/compose/foundation/foundation-layout/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/layout/FlowRowColumnTest.kt b/compose/foundation/foundation-layout/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/layout/FlowRowColumnTest.kt
index 9c2a063..f7038c5 100644
--- a/compose/foundation/foundation-layout/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/layout/FlowRowColumnTest.kt
+++ b/compose/foundation/foundation-layout/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/layout/FlowRowColumnTest.kt
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+@file:Suppress("DEPRECATION")
+
 package androidx.compose.foundation.layout
 
 import androidx.compose.foundation.background
diff --git a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/ContextualFlowLayout.kt b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/ContextualFlowLayout.kt
index a22b962..885285d 100644
--- a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/ContextualFlowLayout.kt
+++ b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/ContextualFlowLayout.kt
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+@file:Suppress("DEPRECATION")
+
 package androidx.compose.foundation.layout
 
 import androidx.annotation.FloatRange
@@ -62,6 +64,7 @@
  * @see FlowRow
  * @see ContextualFlowColumn
  */
+@Deprecated("ContextualFlowLayouts are no longer maintained")
 @Composable
 @ExperimentalLayoutApi
 fun ContextualFlowRow(
@@ -136,6 +139,7 @@
  * @see FlowColumn
  * @see ContextualFlowRow
  */
+@Deprecated("ContextualFlowLayouts are no longer maintained")
 @Composable
 @ExperimentalLayoutApi
 fun ContextualFlowColumn(
@@ -181,6 +185,7 @@
 }
 
 /** Defines the scope for items within a [ContextualFlowRow]. */
+@Deprecated("ContextualFlowLayouts are no longer maintained")
 @LayoutScopeMarker
 @Stable
 @ExperimentalLayoutApi
@@ -248,18 +253,21 @@
 }
 
 /** Scope for the overflow [ContextualFlowRow]. */
+@Deprecated("ContextualFlowLayouts are no longer maintained")
 @LayoutScopeMarker
 @Stable
 @ExperimentalLayoutApi
 interface ContextualFlowRowOverflowScope : FlowRowOverflowScope
 
 /** Scope for the overflow [ContextualFlowColumn]. */
+@Deprecated("ContextualFlowLayouts are no longer maintained")
 @LayoutScopeMarker
 @Stable
 @ExperimentalLayoutApi
 interface ContextualFlowColumnOverflowScope : FlowColumnOverflowScope
 
 /** Provides a scope for items within a [ContextualFlowColumn]. */
+@Deprecated("ContextualFlowLayouts are no longer maintained")
 @LayoutScopeMarker
 @Stable
 @ExperimentalLayoutApi
diff --git a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/FlowLayout.kt b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/FlowLayout.kt
index 8417dd1..0b50860 100644
--- a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/FlowLayout.kt
+++ b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/FlowLayout.kt
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+@file:Suppress("DEPRECATION")
+
 package androidx.compose.foundation.layout
 
 import androidx.annotation.FloatRange
@@ -80,9 +82,9 @@
  * @param overflow The strategy to handle overflowing items
  * @param content The content as a [RowScope]
  * @see FlowColumn
- * @see ContextualFlowRow
  * @see [androidx.compose.foundation.layout.Row]
  */
+@Deprecated("The overflow parameter has been deprecated")
 @Composable
 @ExperimentalLayoutApi
 fun FlowRow(
@@ -117,6 +119,58 @@
 }
 
 /**
+ * [FlowRow] is a layout that fills items from left to right (ltr) in LTR layouts or right to left
+ * (rtl) in RTL layouts and when it runs out of space, moves to the next "row" or "line" positioned
+ * on the bottom, and then continues filling items until the items run out.
+ *
+ * Example:
+ *
+ * @sample androidx.compose.foundation.layout.samples.SimpleFlowRow
+ *
+ * When a Modifier [RowScope.weight] is provided, it scales the item based on the number items that
+ * fall on the row it was placed in.
+ *
+ * Note that if two or more Text components are placed in a [Row], normally they should be aligned
+ * by their first baselines. [FlowRow] as a general purpose container does not do it automatically
+ * so developers need to handle this manually. This is achieved by adding a
+ * [RowScope.alignByBaseline] modifier to every such Text component. By default this modifier aligns
+ * by [androidx.compose.ui.layout.FirstBaseline]. If, however, you need to align Texts by
+ * [androidx.compose.ui.layout.LastBaseline] for example, use a more general [RowScope.alignBy]
+ * modifier.
+ *
+ * @param modifier The modifier to be applied to the Row.
+ * @param horizontalArrangement The horizontal arrangement of the layout's children.
+ * @param verticalArrangement The vertical arrangement of the layout's virtual rows.
+ * @param itemVerticalAlignment The cross axis/vertical alignment of an item in the column.
+ * @param maxItemsInEachRow The maximum number of items per row
+ * @param maxLines The max number of rows
+ * @param content The content as a [RowScope]
+ * @see FlowColumn
+ * @see [androidx.compose.foundation.layout.Row]
+ */
+@OptIn(ExperimentalLayoutApi::class)
+@Composable
+fun FlowRow(
+    modifier: Modifier = Modifier,
+    horizontalArrangement: Arrangement.Horizontal = Arrangement.Start,
+    verticalArrangement: Arrangement.Vertical = Arrangement.Top,
+    itemVerticalAlignment: Alignment.Vertical = Alignment.Top,
+    maxItemsInEachRow: Int = Int.MAX_VALUE,
+    maxLines: Int = Int.MAX_VALUE,
+    content: @Composable FlowRowScope.() -> Unit
+) =
+    FlowRow(
+        modifier,
+        horizontalArrangement,
+        verticalArrangement,
+        itemVerticalAlignment,
+        maxItemsInEachRow,
+        maxLines,
+        FlowRowOverflow.Clip,
+        content,
+    )
+
+/**
  * [FlowColumn] is a layout that fills items from top to bottom, and when it runs out of space on
  * the bottom, moves to the next "column" or "line" on the right or left based on ltr or rtl
  * layouts, and then continues filling items from top to bottom.
@@ -144,6 +198,7 @@
  * @see ContextualFlowColumn
  * @see [androidx.compose.foundation.layout.Column]
  */
+@Deprecated("The overflow parameter has been deprecated")
 @Composable
 @ExperimentalLayoutApi
 fun FlowColumn(
@@ -176,6 +231,54 @@
     Layout(contents = list, measurePolicy = measurePolicy, modifier = modifier)
 }
 
+/**
+ * [FlowColumn] is a layout that fills items from top to bottom, and when it runs out of space on
+ * the bottom, moves to the next "column" or "line" on the right or left based on ltr or rtl
+ * layouts, and then continues filling items from top to bottom.
+ *
+ * It supports ltr in LTR layouts, by placing the first column to the left, and then moving to the
+ * right It supports rtl in RTL layouts, by placing the first column to the right, and then moving
+ * to the left
+ *
+ * Example:
+ *
+ * @sample androidx.compose.foundation.layout.samples.SimpleFlowColumn
+ *
+ * When a Modifier [ColumnScope.weight] is provided, it scales the item based on the number items
+ * that fall on the column it was placed in.
+ *
+ * @param modifier The modifier to be applied to the Row.
+ * @param verticalArrangement The vertical arrangement of the layout's children.
+ * @param horizontalArrangement The horizontal arrangement of the layout's virtual columns
+ * @param itemHorizontalAlignment The cross axis/horizontal alignment of an item in the column.
+ * @param maxItemsInEachColumn The maximum number of items per column
+ * @param maxLines The max number of rows
+ * @param content The content as a [ColumnScope]
+ * @see FlowRow
+ * @see [androidx.compose.foundation.layout.Column]
+ */
+@Composable
+@ExperimentalLayoutApi
+fun FlowColumn(
+    modifier: Modifier = Modifier,
+    verticalArrangement: Arrangement.Vertical = Arrangement.Top,
+    horizontalArrangement: Arrangement.Horizontal = Arrangement.Start,
+    itemHorizontalAlignment: Alignment.Horizontal = Alignment.Start,
+    maxItemsInEachColumn: Int = Int.MAX_VALUE,
+    maxLines: Int = Int.MAX_VALUE,
+    content: @Composable FlowColumnScope.() -> Unit
+) =
+    FlowColumn(
+        modifier,
+        verticalArrangement,
+        horizontalArrangement,
+        itemHorizontalAlignment,
+        maxItemsInEachColumn,
+        maxLines,
+        FlowColumnOverflow.Clip,
+        content,
+    )
+
 /** Scope for the children of [FlowRow]. */
 @LayoutScopeMarker
 @Stable
diff --git a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/FlowLayoutBuildingBlocks.kt b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/FlowLayoutBuildingBlocks.kt
index 956bd2c..5f056b2 100644
--- a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/FlowLayoutBuildingBlocks.kt
+++ b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/FlowLayoutBuildingBlocks.kt
@@ -64,6 +64,7 @@
         return ellipsisInfo
     }
 
+    @Suppress("DEPRECATION")
     fun getWrapInfo(
         nextItemHasNext: Boolean,
         nextIndexInLine: Int,
diff --git a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/FlowLayoutOverflow.kt b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/FlowLayoutOverflow.kt
index 686fcc8..5912c7c 100644
--- a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/FlowLayoutOverflow.kt
+++ b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/FlowLayoutOverflow.kt
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+@file:Suppress("DEPRECATION")
+
 package androidx.compose.foundation.layout
 
 import androidx.collection.IntIntPair
@@ -54,6 +56,7 @@
  * - [expandOrCollapseIndicator]: Extends the [expandIndicator] functionality by adding a 'Collapse'
  *   option. After expanding the content, users can choose to collapse it back to the summary view.
  */
+@Deprecated("FlowLayout overflow is no longer maintained")
 @ExperimentalLayoutApi
 class FlowRowOverflow
 private constructor(
@@ -188,6 +191,7 @@
  * - [expandOrCollapseIndicator]: Extends the [expandIndicator] functionality by adding a 'Collapse'
  *   option. After expanding the content, users can choose to collapse it back to the summary view.
  */
+@Deprecated("FlowLayout overflow is no longer maintained")
 @ExperimentalLayoutApi
 class FlowColumnOverflow
 private constructor(
@@ -204,6 +208,8 @@
         seeMoreGetter,
         collapseGetter
     ) {
+    @Deprecated("FlowLayout overflow is no longer maintained")
+    @ExperimentalLayoutApi
     companion object {
         /** Display all content, even if there is not enough space in the specified bounds. */
         @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
@@ -323,6 +329,7 @@
  * - [expandOrCollapseIndicator]: Extends the [expandIndicator] functionality by adding a 'Collapse'
  *   option. After expanding the content, users can choose to collapse it back to the summary view.
  */
+@Deprecated("ContextualFlowLayouts are no longer maintained")
 @ExperimentalLayoutApi
 class ContextualFlowRowOverflow
 private constructor(
@@ -340,6 +347,8 @@
         collapseGetter
     ) {
 
+    @Deprecated("FlowLayout overflow is no longer maintained")
+    @ExperimentalLayoutApi
     companion object {
         /** Display all content, even if there is not enough space in the specified bounds. */
         @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
@@ -462,6 +471,7 @@
  * - [expandOrCollapseIndicator]: Extends the [expandIndicator] functionality by adding a 'Collapse'
  *   option. After expanding the content, users can choose to collapse it back to the summary view.
  */
+@Deprecated("ContextualFlowLayouts are no longer maintained")
 @ExperimentalLayoutApi
 class ContextualFlowColumnOverflow
 private constructor(
@@ -479,6 +489,8 @@
         collapseGetter
     ) {
 
+    @Deprecated("ContextualFlowLayouts are no longer maintained")
+    @ExperimentalLayoutApi
     companion object {
         /** Display all content, even if there is not enough space in the specified bounds. */
         @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
@@ -596,6 +608,7 @@
  * @see [ContextualFlowRowOverflow]
  * @see [ContextualFlowColumnOverflow]
  */
+@Deprecated("FlowLayout overflow is no longer maintained")
 @ExperimentalLayoutApi
 sealed class FlowLayoutOverflow(
     internal val type: OverflowType,
diff --git a/compose/material3/material3/api/current.txt b/compose/material3/material3/api/current.txt
index 48ebe5e..b4c8ef0 100644
--- a/compose/material3/material3/api/current.txt
+++ b/compose/material3/material3/api/current.txt
@@ -402,11 +402,15 @@
   public final class CheckboxDefaults {
     method @androidx.compose.runtime.Composable public androidx.compose.material3.CheckboxColors colors();
     method @androidx.compose.runtime.Composable public androidx.compose.material3.CheckboxColors colors(optional long checkedColor, optional long uncheckedColor, optional long checkmarkColor, optional long disabledCheckedColor, optional long disabledUncheckedColor, optional long disabledIndeterminateColor);
+    method public float getStrokeWidth();
+    property public final float StrokeWidth;
     field public static final androidx.compose.material3.CheckboxDefaults INSTANCE;
   }
 
   public final class CheckboxKt {
+    method @androidx.compose.runtime.Composable public static void Checkbox(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit>? onCheckedChange, androidx.compose.ui.graphics.drawscope.Stroke checkmarkStroke, androidx.compose.ui.graphics.drawscope.Stroke outlineStroke, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.CheckboxColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource);
     method @androidx.compose.runtime.Composable public static void Checkbox(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit>? onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.CheckboxColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource);
+    method @androidx.compose.runtime.Composable public static void TriStateCheckbox(androidx.compose.ui.state.ToggleableState state, kotlin.jvm.functions.Function0<kotlin.Unit>? onClick, androidx.compose.ui.graphics.drawscope.Stroke checkmarkStroke, androidx.compose.ui.graphics.drawscope.Stroke outlineStroke, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.CheckboxColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource);
     method @androidx.compose.runtime.Composable public static void TriStateCheckbox(androidx.compose.ui.state.ToggleableState state, kotlin.jvm.functions.Function0<kotlin.Unit>? onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.CheckboxColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource);
   }
 
diff --git a/compose/material3/material3/api/restricted_current.txt b/compose/material3/material3/api/restricted_current.txt
index 48ebe5e..b4c8ef0 100644
--- a/compose/material3/material3/api/restricted_current.txt
+++ b/compose/material3/material3/api/restricted_current.txt
@@ -402,11 +402,15 @@
   public final class CheckboxDefaults {
     method @androidx.compose.runtime.Composable public androidx.compose.material3.CheckboxColors colors();
     method @androidx.compose.runtime.Composable public androidx.compose.material3.CheckboxColors colors(optional long checkedColor, optional long uncheckedColor, optional long checkmarkColor, optional long disabledCheckedColor, optional long disabledUncheckedColor, optional long disabledIndeterminateColor);
+    method public float getStrokeWidth();
+    property public final float StrokeWidth;
     field public static final androidx.compose.material3.CheckboxDefaults INSTANCE;
   }
 
   public final class CheckboxKt {
+    method @androidx.compose.runtime.Composable public static void Checkbox(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit>? onCheckedChange, androidx.compose.ui.graphics.drawscope.Stroke checkmarkStroke, androidx.compose.ui.graphics.drawscope.Stroke outlineStroke, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.CheckboxColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource);
     method @androidx.compose.runtime.Composable public static void Checkbox(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit>? onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.CheckboxColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource);
+    method @androidx.compose.runtime.Composable public static void TriStateCheckbox(androidx.compose.ui.state.ToggleableState state, kotlin.jvm.functions.Function0<kotlin.Unit>? onClick, androidx.compose.ui.graphics.drawscope.Stroke checkmarkStroke, androidx.compose.ui.graphics.drawscope.Stroke outlineStroke, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.CheckboxColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource);
     method @androidx.compose.runtime.Composable public static void TriStateCheckbox(androidx.compose.ui.state.ToggleableState state, kotlin.jvm.functions.Function0<kotlin.Unit>? onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.CheckboxColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource);
   }
 
diff --git a/compose/material3/material3/integration-tests/material3-catalog/src/main/java/androidx/compose/material3/catalog/library/model/Examples.kt b/compose/material3/material3/integration-tests/material3-catalog/src/main/java/androidx/compose/material3/catalog/library/model/Examples.kt
index 6ab1a76..16faf52 100644
--- a/compose/material3/material3/integration-tests/material3-catalog/src/main/java/androidx/compose/material3/catalog/library/model/Examples.kt
+++ b/compose/material3/material3/integration-tests/material3-catalog/src/main/java/androidx/compose/material3/catalog/library/model/Examples.kt
@@ -43,6 +43,7 @@
 import androidx.compose.material3.samples.CardSample
 import androidx.compose.material3.samples.CenteredHorizontalFloatingToolbarWithFabSample
 import androidx.compose.material3.samples.CenteredVerticalFloatingToolbarWithFabSample
+import androidx.compose.material3.samples.CheckboxRoundedStrokesSample
 import androidx.compose.material3.samples.CheckboxSample
 import androidx.compose.material3.samples.CheckboxWithTextSample
 import androidx.compose.material3.samples.ChipGroupReflowSample
@@ -248,6 +249,7 @@
 import androidx.compose.material3.samples.ToggleButtonWithIconSample
 import androidx.compose.material3.samples.TonalSplitButtonSample
 import androidx.compose.material3.samples.TonalToggleButtonSample
+import androidx.compose.material3.samples.TriStateCheckboxRoundedStrokesSample
 import androidx.compose.material3.samples.TriStateCheckboxSample
 import androidx.compose.material3.samples.TwoLineListItem
 import androidx.compose.material3.samples.VerticalFloatingToolbarWithFabSample
@@ -585,12 +587,26 @@
             CheckboxWithTextSample()
         },
         Example(
+            name = "CheckboxRoundedStrokesSample",
+            description = CheckboxesExampleDescription,
+            sourceUrl = CheckboxesExampleSourceUrl
+        ) {
+            CheckboxRoundedStrokesSample()
+        },
+        Example(
             name = "TriStateCheckboxSample",
             description = CheckboxesExampleDescription,
             sourceUrl = CheckboxesExampleSourceUrl
         ) {
             TriStateCheckboxSample()
-        }
+        },
+        Example(
+            name = "TriStateCheckboxRoundedStrokesSample",
+            description = CheckboxesExampleDescription,
+            sourceUrl = CheckboxesExampleSourceUrl
+        ) {
+            TriStateCheckboxRoundedStrokesSample()
+        },
     )
 
 private const val ChipsExampleDescription = "Chips examples"
diff --git a/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/CheckboxSamples.kt b/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/CheckboxSamples.kt
index c15860d..61d6130 100644
--- a/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/CheckboxSamples.kt
+++ b/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/CheckboxSamples.kt
@@ -27,6 +27,7 @@
 import androidx.compose.foundation.selection.toggleable
 import androidx.compose.foundation.selection.triStateToggleable
 import androidx.compose.material3.Checkbox
+import androidx.compose.material3.CheckboxDefaults
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.Text
 import androidx.compose.material3.TriStateCheckbox
@@ -35,10 +36,15 @@
 import androidx.compose.runtime.remember
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.StrokeCap
+import androidx.compose.ui.graphics.StrokeJoin
+import androidx.compose.ui.graphics.drawscope.Stroke
+import androidx.compose.ui.platform.LocalDensity
 import androidx.compose.ui.semantics.Role
 import androidx.compose.ui.state.ToggleableState
 import androidx.compose.ui.tooling.preview.Preview
 import androidx.compose.ui.unit.dp
+import kotlin.math.floor
 
 @Preview
 @Sampled
@@ -79,6 +85,29 @@
 @Preview
 @Sampled
 @Composable
+fun CheckboxRoundedStrokesSample() {
+    val strokeWidthPx = with(LocalDensity.current) { floor(CheckboxDefaults.StrokeWidth.toPx()) }
+    val checkmarkStroke =
+        remember(strokeWidthPx) {
+            Stroke(
+                width = strokeWidthPx,
+                cap = StrokeCap.Round,
+                join = StrokeJoin.Round,
+            )
+        }
+    val outlineStroke = remember(strokeWidthPx) { Stroke(width = strokeWidthPx) }
+    val checkedState = remember { mutableStateOf(true) }
+    Checkbox(
+        checked = checkedState.value,
+        onCheckedChange = { checkedState.value = it },
+        checkmarkStroke = checkmarkStroke,
+        outlineStroke = outlineStroke
+    )
+}
+
+@Preview
+@Sampled
+@Composable
 fun TriStateCheckboxSample() {
     Column {
         // define dependent checkboxes states
@@ -146,3 +175,96 @@
         }
     }
 }
+
+@Preview
+@Sampled
+@Composable
+fun TriStateCheckboxRoundedStrokesSample() {
+    val strokeWidthPx = with(LocalDensity.current) { floor(CheckboxDefaults.StrokeWidth.toPx()) }
+    val checkmarkStroke =
+        remember(strokeWidthPx) {
+            Stroke(
+                width = strokeWidthPx,
+                cap = StrokeCap.Round,
+                join = StrokeJoin.Round,
+            )
+        }
+    val outlineStroke = remember(strokeWidthPx) { Stroke(width = strokeWidthPx) }
+    Column {
+        // define dependent checkboxes states
+        val (state, onStateChange) = remember { mutableStateOf(true) }
+        val (state2, onStateChange2) = remember { mutableStateOf(true) }
+
+        // TriStateCheckbox state reflects state of dependent checkboxes
+        val parentState =
+            remember(state, state2) {
+                if (state && state2) ToggleableState.On
+                else if (!state && !state2) ToggleableState.Off else ToggleableState.Indeterminate
+            }
+        // click on TriStateCheckbox can set state for dependent checkboxes
+        val onParentClick = {
+            val s = parentState != ToggleableState.On
+            onStateChange(s)
+            onStateChange2(s)
+        }
+
+        // The sample below composes just basic checkboxes which are not fully accessible on their
+        // own. See the CheckboxWithTextSample as a way to ensure your checkboxes are fully
+        // accessible.
+        Row(
+            verticalAlignment = Alignment.CenterVertically,
+            modifier =
+                Modifier.triStateToggleable(
+                    state = parentState,
+                    onClick = onParentClick,
+                    role = Role.Checkbox
+                )
+        ) {
+            TriStateCheckbox(
+                state = parentState,
+                onClick = null,
+                checkmarkStroke = checkmarkStroke,
+                outlineStroke = outlineStroke
+            )
+            Text("Receive Emails")
+        }
+        Spacer(Modifier.size(25.dp))
+        Column(Modifier.padding(24.dp, 0.dp, 0.dp, 0.dp)) {
+            Row(
+                verticalAlignment = Alignment.CenterVertically,
+                modifier =
+                    Modifier.toggleable(
+                        value = state,
+                        onValueChange = onStateChange,
+                        role = Role.Checkbox
+                    )
+            ) {
+                Checkbox(
+                    checked = state,
+                    onCheckedChange = null,
+                    checkmarkStroke = checkmarkStroke,
+                    outlineStroke = outlineStroke
+                )
+                Text("Daily")
+            }
+            Spacer(Modifier.size(25.dp))
+            Row(
+                verticalAlignment = Alignment.CenterVertically,
+                modifier =
+                    Modifier.toggleable(
+                        value = state2,
+                        onValueChange = onStateChange2,
+                        role = Role.Checkbox
+                    )
+            ) {
+                Checkbox(
+                    checked = state2,
+                    onCheckedChange = null,
+                    checkmarkStroke = checkmarkStroke,
+                    outlineStroke = outlineStroke
+                )
+                Text("Weekly")
+            }
+        }
+    }
+}
diff --git a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/CheckboxScreenshotTest.kt b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/CheckboxScreenshotTest.kt
index 7a2851b..e54b4b2 100644
--- a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/CheckboxScreenshotTest.kt
+++ b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/CheckboxScreenshotTest.kt
@@ -29,8 +29,12 @@
 import androidx.compose.ui.focus.FocusRequester
 import androidx.compose.ui.focus.focusRequester
 import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.StrokeCap
+import androidx.compose.ui.graphics.StrokeJoin
+import androidx.compose.ui.graphics.drawscope.Stroke
 import androidx.compose.ui.input.InputMode
 import androidx.compose.ui.input.InputModeManager
+import androidx.compose.ui.platform.LocalDensity
 import androidx.compose.ui.platform.LocalInputModeManager
 import androidx.compose.ui.platform.testTag
 import androidx.compose.ui.state.ToggleableState
@@ -311,6 +315,73 @@
         assertToggeableAgainstGolden("checkBox_${scheme.name}_customCheckboxColorsConstruct")
     }
 
+    @Test
+    fun checkBox_customStroke_checked() {
+        rule.setMaterialContent(scheme.colorScheme) {
+            val stroke =
+                Stroke(
+                    width = with(LocalDensity.current) { CheckboxDefaults.StrokeWidth.toPx() },
+                    cap = StrokeCap.Round,
+                    join = StrokeJoin.Round
+                )
+            Box(wrap.testTag(wrapperTestTag)) {
+                Checkbox(
+                    modifier = wrap,
+                    checked = true,
+                    onCheckedChange = {},
+                    checkmarkStroke = stroke,
+                    outlineStroke = stroke
+                )
+            }
+        }
+        assertToggeableAgainstGolden("checkBox_${scheme.name}_customStroke_checked")
+    }
+
+    @Test
+    fun checkBox_customStroke_unchecked() {
+        rule.setMaterialContent(scheme.colorScheme) {
+            // Have the stroke thinner so we can verify it's being applied to the rounded box.
+            val stroke =
+                Stroke(
+                    width = with(LocalDensity.current) { CheckboxDefaults.StrokeWidth.toPx() / 4 },
+                    cap = StrokeCap.Round,
+                    join = StrokeJoin.Round
+                )
+            Box(wrap.testTag(wrapperTestTag)) {
+                Checkbox(
+                    modifier = wrap,
+                    checked = false,
+                    onCheckedChange = {},
+                    checkmarkStroke = stroke,
+                    outlineStroke = stroke
+                )
+            }
+        }
+        assertToggeableAgainstGolden("checkBox_${scheme.name}_customStroke_unchecked")
+    }
+
+    @Test
+    fun checkBox_customStroke_indeterminate() {
+        rule.setMaterialContent(scheme.colorScheme) {
+            val stroke =
+                Stroke(
+                    width = with(LocalDensity.current) { CheckboxDefaults.StrokeWidth.toPx() },
+                    cap = StrokeCap.Round,
+                    join = StrokeJoin.Round
+                )
+            Box(wrap.testTag(wrapperTestTag)) {
+                TriStateCheckbox(
+                    state = ToggleableState.Indeterminate,
+                    checkmarkStroke = stroke,
+                    outlineStroke = stroke,
+                    modifier = wrap,
+                    onClick = {}
+                )
+            }
+        }
+        assertToggeableAgainstGolden("checkBox_${scheme.name}_customStroke_indeterminate")
+    }
+
     @Composable
     private fun Checkboxes(colors: CheckboxColors) {
         TriStateCheckbox(state = ToggleableState.Off, onClick = {}, colors = colors)
diff --git a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/CheckboxTest.kt b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/CheckboxTest.kt
index 3b1550a..b979580 100644
--- a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/CheckboxTest.kt
+++ b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/CheckboxTest.kt
@@ -27,6 +27,8 @@
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.graphics.drawscope.Stroke
+import androidx.compose.ui.platform.LocalDensity
 import androidx.compose.ui.platform.testTag
 import androidx.compose.ui.semantics.Role
 import androidx.compose.ui.semantics.SemanticsProperties
@@ -54,6 +56,7 @@
 import androidx.compose.ui.test.onNodeWithTag
 import androidx.compose.ui.test.performClick
 import androidx.compose.ui.test.performTouchInput
+import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
@@ -230,11 +233,72 @@
         )
     }
 
-    @OptIn(ExperimentalMaterial3Api::class)
+    @Test
+    fun checkBoxTest_MaterialSize_WhenChecked_withThickStroke_withoutMinimumTouchTarget() {
+        materialSizeTestForValue(
+            checkboxValue = On,
+            clickable = false, // Ensure a minimum size with clickable false and no min touch target
+            minimumTouchTarget = false,
+            strokeWidth = CheckboxDefaults.StrokeWidth * 3
+        )
+    }
+
+    @Test
+    fun checkBoxTest_MaterialSize_WhenChecked_withThinStroke_withoutMinimumTouchTarget() {
+        materialSizeTestForValue(
+            checkboxValue = On,
+            clickable = false, // Ensure a minimum size with clickable false and no min touch target
+            minimumTouchTarget = false,
+            strokeWidth = CheckboxDefaults.StrokeWidth / 3
+        )
+    }
+
+    @Test
+    fun checkBoxTest_MaterialSize_WhenUnchecked_withThickStroke_withoutMinimumTouchTarget() {
+        materialSizeTestForValue(
+            checkboxValue = Off,
+            clickable = false, // Ensure a minimum size with clickable false and no min touch target
+            minimumTouchTarget = false,
+            strokeWidth = CheckboxDefaults.StrokeWidth * 3
+        )
+    }
+
+    @Test
+    fun checkBoxTest_MaterialSize_WhenUnchecked_withThinStroke_withoutMinimumTouchTarget() {
+        materialSizeTestForValue(
+            checkboxValue = Off,
+            clickable = false, // Ensure a minimum size with clickable false and no min touch target
+            minimumTouchTarget = false,
+            strokeWidth = CheckboxDefaults.StrokeWidth / 3
+        )
+    }
+
+    @Test
+    fun checkBoxTest_MaterialSize_WhenIndeterminate_withThickStroke_withoutMinimumTouchTarget() {
+        materialSizeTestForValue(
+            checkboxValue = Indeterminate,
+            clickable = false, // Ensure a minimum size with clickable false and no min touch target
+            minimumTouchTarget = false,
+            strokeWidth = CheckboxDefaults.StrokeWidth * 3
+        )
+    }
+
+    @Test
+    fun checkBoxTest_MaterialSize_WhenIndeterminate_withThinStroke_withoutMinimumTouchTarget() {
+        materialSizeTestForValue(
+            checkboxValue = Indeterminate,
+            clickable = false, // Ensure a minimum size with clickable false and no min touch target
+            minimumTouchTarget = false,
+            strokeWidth = CheckboxDefaults.StrokeWidth / 3
+        )
+    }
+
+    @OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
     private fun materialSizeTestForValue(
         checkboxValue: ToggleableState,
         clickable: Boolean,
-        minimumTouchTarget: Boolean
+        minimumTouchTarget: Boolean,
+        strokeWidth: Dp? = null,
     ) {
         rule
             .setMaterialContentForSizeAssertions {
@@ -242,14 +306,29 @@
                     LocalMinimumInteractiveComponentSize provides
                         if (minimumTouchTarget) 48.dp else 0.dp
                 ) {
-                    TriStateCheckbox(
-                        state = checkboxValue,
-                        onClick =
-                            if (clickable) {
-                                {}
-                            } else null,
-                        enabled = false
-                    )
+                    if (strokeWidth == null) {
+                        TriStateCheckbox(
+                            state = checkboxValue,
+                            onClick =
+                                if (clickable) {
+                                    {}
+                                } else null,
+                            enabled = false
+                        )
+                    } else {
+                        val strokeWidthPx =
+                            Stroke(width = with(LocalDensity.current) { strokeWidth.toPx() })
+                        TriStateCheckbox(
+                            state = checkboxValue,
+                            onClick =
+                                if (clickable) {
+                                    {}
+                                } else null,
+                            enabled = false,
+                            checkmarkStroke = strokeWidthPx,
+                            outlineStroke = strokeWidthPx
+                        )
+                    }
                 }
             }
             .run {
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Checkbox.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Checkbox.kt
index 0fd3f81..1888a07 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Checkbox.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Checkbox.kt
@@ -48,6 +48,7 @@
 import androidx.compose.ui.graphics.drawscope.Fill
 import androidx.compose.ui.graphics.drawscope.Stroke
 import androidx.compose.ui.graphics.takeOrElse
+import androidx.compose.ui.platform.LocalDensity
 import androidx.compose.ui.semantics.Role
 import androidx.compose.ui.state.ToggleableState
 import androidx.compose.ui.unit.dp
@@ -96,6 +97,7 @@
     colors: CheckboxColors = CheckboxDefaults.colors(),
     interactionSource: MutableInteractionSource? = null
 ) {
+    val strokeWidthPx = with(LocalDensity.current) { floor(CheckboxDefaults.StrokeWidth.toPx()) }
     TriStateCheckbox(
         state = ToggleableState(checked),
         onClick =
@@ -104,6 +106,72 @@
             } else {
                 null
             },
+        checkmarkStroke = Stroke(width = strokeWidthPx, cap = StrokeCap.Square),
+        outlineStroke = Stroke(width = strokeWidthPx),
+        modifier = modifier,
+        enabled = enabled,
+        colors = colors,
+        interactionSource = interactionSource
+    )
+}
+
+/**
+ * <a href="https://m3.material.io/components/checkbox/overview" class="external"
+ * target="_blank">Material Design checkbox</a>.
+ *
+ * Checkboxes allow users to select one or more items from a set. Checkboxes can turn an option on
+ * or off.
+ *
+ * ![Checkbox
+ * image](https://developer.android.com/images/reference/androidx/compose/material3/checkbox.png)
+ *
+ * This Checkbox function offers greater flexibility in visual customization. Using the [Stroke]
+ * parameters, you can control the appearance of both the checkmark and the box that surrounds it.
+ *
+ * A sample of a `Checkbox` that uses a [Stroke] with rounded [StrokeCap] and
+ * [androidx.compose.ui.graphics.StrokeJoin]:
+ *
+ * @sample androidx.compose.material3.samples.CheckboxRoundedStrokesSample
+ * @param checked whether this checkbox is checked or unchecked
+ * @param onCheckedChange called when this checkbox is clicked. If `null`, then this checkbox will
+ *   not be interactable, unless something else handles its input events and updates its state.
+ * @param checkmarkStroke stroke for the checkmark.
+ * @param outlineStroke stroke for the checkmark's box outline. Note that this stroke is applied
+ *   when drawing the outline's rounded rectangle, so attributions such as
+ *   [androidx.compose.ui.graphics.StrokeJoin] will be ignored.
+ * @param modifier the [Modifier] to be applied to this checkbox
+ * @param enabled controls the enabled state of this checkbox. When `false`, this component will not
+ *   respond to user input, and it will appear visually disabled and disabled to accessibility
+ *   services.
+ * @param colors [CheckboxColors] that will be used to resolve the colors used for this checkbox in
+ *   different states. See [CheckboxDefaults.colors].
+ * @param interactionSource an optional hoisted [MutableInteractionSource] for observing and
+ *   emitting [Interaction]s for this checkbox. You can use this to change the checkbox's appearance
+ *   or preview the checkbox in different states. Note that if `null` is provided, interactions will
+ *   still happen internally.
+ * @see [TriStateCheckbox] if you require support for an indeterminate state.
+ */
+@Composable
+fun Checkbox(
+    checked: Boolean,
+    onCheckedChange: ((Boolean) -> Unit)?,
+    checkmarkStroke: Stroke,
+    outlineStroke: Stroke,
+    modifier: Modifier = Modifier,
+    enabled: Boolean = true,
+    colors: CheckboxColors = CheckboxDefaults.colors(),
+    interactionSource: MutableInteractionSource? = null
+) {
+    TriStateCheckbox(
+        state = ToggleableState(checked),
+        onClick =
+            if (onCheckedChange != null) {
+                { onCheckedChange(!checked) }
+            } else {
+                null
+            },
+        checkmarkStroke = checkmarkStroke,
+        outlineStroke = outlineStroke,
         modifier = modifier,
         enabled = enabled,
         colors = colors,
@@ -148,6 +216,68 @@
     colors: CheckboxColors = CheckboxDefaults.colors(),
     interactionSource: MutableInteractionSource? = null
 ) {
+    val strokeWidthPx = with(LocalDensity.current) { floor(CheckboxDefaults.StrokeWidth.toPx()) }
+    TriStateCheckbox(
+        state = state,
+        onClick = onClick,
+        checkmarkStroke = Stroke(width = strokeWidthPx, cap = StrokeCap.Square),
+        outlineStroke = Stroke(width = strokeWidthPx),
+        modifier = modifier,
+        enabled = enabled,
+        colors = colors,
+        interactionSource = interactionSource
+    )
+}
+
+/**
+ * <a href="https://m3.material.io/components/checkbox/guidelines" class="external"
+ * target="_blank">Material Design checkbox</a> parent.
+ *
+ * Checkboxes can have a parent-child relationship with other checkboxes. When the parent checkbox
+ * is checked, all child checkboxes are checked. If a parent checkbox is unchecked, all child
+ * checkboxes are unchecked. If some, but not all, child checkboxes are checked, the parent checkbox
+ * becomes an indeterminate checkbox.
+ *
+ * ![Checkbox
+ * image](https://developer.android.com/images/reference/androidx/compose/material3/indeterminate-checkbox.png)
+ *
+ * This Checkbox function offers greater flexibility in visual customization. Using the [Stroke]
+ * parameters, you can control the appearance of both the checkmark and the box that surrounds it.
+ *
+ * A sample of a `TriStateCheckbox` that uses a [Stroke] with rounded [StrokeCap] and
+ * [androidx.compose.ui.graphics.StrokeJoin]:
+ *
+ * @sample androidx.compose.material3.samples.TriStateCheckboxRoundedStrokesSample
+ * @param state whether this checkbox is checked, unchecked, or in an indeterminate state
+ * @param onClick called when this checkbox is clicked. If `null`, then this checkbox will not be
+ *   interactable, unless something else handles its input events and updates its [state].
+ * @param checkmarkStroke stroke for the checkmark.
+ * @param outlineStroke stroke for the checkmark's box outline. Note that this stroke is applied
+ *   when drawing the outline's rounded rectangle, so attributions such as
+ *   [androidx.compose.ui.graphics.StrokeJoin] will be ignored.
+ * @param modifier the [Modifier] to be applied to this checkbox
+ * @param enabled controls the enabled state of this checkbox. When `false`, this component will not
+ *   respond to user input, and it will appear visually disabled and disabled to accessibility
+ *   services.
+ * @param colors [CheckboxColors] that will be used to resolve the colors used for this checkbox in
+ *   different states. See [CheckboxDefaults.colors].
+ * @param interactionSource an optional hoisted [MutableInteractionSource] for observing and
+ *   emitting [Interaction]s for this checkbox. You can use this to change the checkbox's appearance
+ *   or preview the checkbox in different states. Note that if `null` is provided, interactions will
+ *   still happen internally.
+ * @see [Checkbox] if you want a simple component that represents Boolean state
+ */
+@Composable
+fun TriStateCheckbox(
+    state: ToggleableState,
+    onClick: (() -> Unit)?,
+    checkmarkStroke: Stroke,
+    outlineStroke: Stroke,
+    modifier: Modifier = Modifier,
+    enabled: Boolean = true,
+    colors: CheckboxColors = CheckboxDefaults.colors(),
+    interactionSource: MutableInteractionSource? = null
+) {
     val toggleableModifier =
         if (onClick != null) {
             Modifier.triStateToggleable(
@@ -175,7 +305,9 @@
                 )
                 .then(toggleableModifier)
                 .padding(CheckboxDefaultPadding),
-        colors = colors
+        colors = colors,
+        checkmarkStroke = checkmarkStroke,
+        outlineStroke = outlineStroke
     )
 }
 
@@ -255,6 +387,12 @@
                     )
                     .also { defaultCheckboxColorsCached = it }
         }
+
+    /**
+     * The default stroke width for a [Checkbox]. This width will be used for the checkmark when the
+     * `Checkbox` is in a checked or indeterminate states, or for the outline when it's unchecked.
+     */
+    val StrokeWidth = 2.dp
 }
 
 @Composable
@@ -262,7 +400,9 @@
     enabled: Boolean,
     value: ToggleableState,
     modifier: Modifier,
-    colors: CheckboxColors
+    colors: CheckboxColors,
+    checkmarkStroke: Stroke,
+    outlineStroke: Stroke,
 ) {
     val transition = updateTransition(value)
     val defaultAnimationSpec = MotionSchemeKeyTokens.DefaultSpatial.value<Float>()
@@ -306,31 +446,24 @@
     val boxColor = colors.boxColor(enabled, value)
     val borderColor = colors.borderColor(enabled, value)
     Canvas(modifier.wrapContentSize(Alignment.Center).requiredSize(CheckboxSize)) {
-        val strokeWidthPx = floor(StrokeWidth.toPx())
         drawBox(
             boxColor = boxColor.value,
             borderColor = borderColor.value,
             radius = RadiusSize.toPx(),
-            strokeWidth = strokeWidthPx
+            stroke = outlineStroke
         )
         drawCheck(
             checkColor = checkColor.value,
             checkFraction = checkDrawFraction.value,
             crossCenterGravitation = checkCenterGravitationShiftFraction.value,
-            strokeWidthPx = strokeWidthPx,
+            stroke = checkmarkStroke,
             drawingCache = checkCache
         )
     }
 }
 
-private fun DrawScope.drawBox(
-    boxColor: Color,
-    borderColor: Color,
-    radius: Float,
-    strokeWidth: Float
-) {
-    val halfStrokeWidth = strokeWidth / 2.0f
-    val stroke = Stroke(strokeWidth)
+private fun DrawScope.drawBox(boxColor: Color, borderColor: Color, radius: Float, stroke: Stroke) {
+    val halfStrokeWidth = stroke.width / 2.0f
     val checkboxSize = size.width
     if (boxColor == borderColor) {
         drawRoundRect(
@@ -342,15 +475,15 @@
     } else {
         drawRoundRect(
             boxColor,
-            topLeft = Offset(strokeWidth, strokeWidth),
-            size = Size(checkboxSize - strokeWidth * 2, checkboxSize - strokeWidth * 2),
-            cornerRadius = CornerRadius(max(0f, radius - strokeWidth)),
+            topLeft = Offset(stroke.width, stroke.width),
+            size = Size(checkboxSize - stroke.width * 2, checkboxSize - stroke.width * 2),
+            cornerRadius = CornerRadius(max(0f, radius - stroke.width)),
             style = Fill
         )
         drawRoundRect(
             borderColor,
             topLeft = Offset(halfStrokeWidth, halfStrokeWidth),
-            size = Size(checkboxSize - strokeWidth, checkboxSize - strokeWidth),
+            size = Size(checkboxSize - stroke.width, checkboxSize - stroke.width),
             cornerRadius = CornerRadius(radius - halfStrokeWidth),
             style = stroke
         )
@@ -361,10 +494,9 @@
     checkColor: Color,
     checkFraction: Float,
     crossCenterGravitation: Float,
-    strokeWidthPx: Float,
+    stroke: Stroke,
     drawingCache: CheckDrawingCache
 ) {
-    val stroke = Stroke(width = strokeWidthPx, cap = StrokeCap.Square)
     val width = size.width
     val checkCrossX = 0.4f
     val checkCrossY = 0.7f
@@ -380,13 +512,13 @@
     val gravitatedRightY = lerp(rightY, 0.5f, crossCenterGravitation)
 
     with(drawingCache) {
-        checkPath.reset()
+        checkPath.rewind()
         checkPath.moveTo(width * leftX, width * gravitatedLeftY)
         checkPath.lineTo(width * gravitatedCrossX, width * gravitatedCrossY)
         checkPath.lineTo(width * rightX, width * gravitatedRightY)
         // TODO: replace with proper declarative non-android alternative when ready (b/158188351)
         pathMeasure.setPath(checkPath, false)
-        pathToDraw.reset()
+        pathToDraw.rewind()
         pathMeasure.getSegment(0f, pathMeasure.length * checkFraction, pathToDraw, true)
     }
     drawPath(drawingCache.pathToDraw, checkColor, style = stroke)
@@ -607,5 +739,4 @@
 // TODO(b/188529841): Update the padding and size when the Checkbox spec is finalized.
 private val CheckboxDefaultPadding = 2.dp
 private val CheckboxSize = 20.dp
-private val StrokeWidth = 2.dp
 private val RadiusSize = 2.dp
diff --git a/compose/ui/ui-graphics/lint-baseline.xml b/compose/ui/ui-graphics/lint-baseline.xml
index 3255d39..862a7fe 100644
--- a/compose/ui/ui-graphics/lint-baseline.xml
+++ b/compose/ui/ui-graphics/lint-baseline.xml
@@ -1,13 +1,13 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.7.0-alpha02" type="baseline" client="gradle" dependencies="false" name="AGP (8.7.0-alpha02)" variant="all" version="8.7.0-alpha02">
+<issues format="6" by="lint 8.9.0-alpha06" type="baseline" client="gradle" dependencies="false" name="AGP (8.9.0-alpha06)" variant="all" version="8.9.0-alpha06">
 
     <issue
         id="NewApi"
-        message="This Kotlin extension function will be hidden by `java.util.SequencedCollection` starting in API 35"
-        errorLine1="                val node = s.removeLastKt()"
-        errorLine2="                           ~~~~~~~~~~~~~~~~">
+        message="Call requires API level 23 (current min is 21): `android.view.View#setForeground`"
+        errorLine1="                                foreground = GraphicsContextHostDrawable(graphicsContext, block)"
+        errorLine2="                                           ~">
         <location
-            file="src/commonMain/kotlin/androidx/compose/ui/graphics/IntervalTree.kt"/>
+            file="src/androidInstrumentedTest/kotlin/androidx/compose/ui/graphics/layer/AndroidGraphicsLayerTest.kt"/>
     </issue>
 
     <issue
diff --git a/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/platform/URLSpanCache.android.kt b/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/platform/URLSpanCache.android.kt
index 6418529..209fdb9 100644
--- a/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/platform/URLSpanCache.android.kt
+++ b/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/platform/URLSpanCache.android.kt
@@ -42,8 +42,6 @@
  *
  * See b/253292081.
  */
-// "URL" violates naming guidelines, but that is intentional to match the platform API.
-@Suppress("AcronymName")
 @OptIn(ExperimentalTextApi::class)
 @InternalTextApi
 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@@ -54,11 +52,9 @@
     private val linkSpansWithListenerByAnnotation =
         WeakHashMap<AnnotatedString.Range<LinkAnnotation>, ComposeClickableSpan>()
 
-    @Suppress("AcronymName")
     fun toURLSpan(urlAnnotation: UrlAnnotation): URLSpan =
         spansByAnnotation.getOrPut(urlAnnotation) { URLSpan(urlAnnotation.url) }
 
-    @Suppress("AcronymName")
     fun toURLSpan(urlRange: AnnotatedString.Range<LinkAnnotation.Url>): URLSpan =
         urlSpansByAnnotation.getOrPut(urlRange) { URLSpan(urlRange.item.url) }
 
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/LookaheadScopeTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/LookaheadScopeTest.kt
index 73d5f2c..57eb795 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/LookaheadScopeTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/LookaheadScopeTest.kt
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+@file:Suppress("DEPRECATION")
+
 package androidx.compose.ui.layout
 
 import androidx.activity.ComponentActivity
@@ -1282,6 +1284,7 @@
         }
     }
 
+    @Suppress("DEPRECATION")
     @OptIn(ExperimentalLayoutApi::class)
     @Test
     fun testNestedLookaheadPlacement() {
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/FocusSearchLeftInteropTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/FocusSearchLeftInteropTest.kt
index dacdc31..cfeedac 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/FocusSearchLeftInteropTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/FocusSearchLeftInteropTest.kt
@@ -47,6 +47,7 @@
 import androidx.compose.ui.test.requestFocus
 import androidx.compose.ui.unit.dp
 import androidx.test.filters.MediumTest
+import androidx.test.filters.SdkSuppress
 import androidx.test.platform.app.InstrumentationRegistry
 import com.google.common.truth.Truth.assertThat
 import org.junit.Rule
@@ -448,6 +449,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 23) // b/387310914 -- flaky on API 21
     fun viewComposableInRow() {
         // Arrange.
         setContent {
diff --git a/core/core-ktx/api/api_lint.ignore b/core/core-ktx/api/api_lint.ignore
index 3cac25a..2373a95 100644
--- a/core/core-ktx/api/api_lint.ignore
+++ b/core/core-ktx/api/api_lint.ignore
@@ -1,8 +1,4 @@
 // Baseline format: 1.0
-AcronymName: androidx.core.database.sqlite.SQLiteDatabaseKt:
-    Acronyms should not be capitalized in class names: was `SQLiteDatabaseKt`, should this be `SqLiteDatabaseKt`?
-
-
 AutoBoxing: androidx.core.database.CursorKt#getDoubleOrNull(android.database.Cursor, int):
     Must avoid boxed primitives (`java.lang.Double`)
 AutoBoxing: androidx.core.database.CursorKt#getFloatOrNull(android.database.Cursor, int):
diff --git a/core/core/api/api_lint.ignore b/core/core/api/api_lint.ignore
index c28cad6..966f30a 100644
--- a/core/core/api/api_lint.ignore
+++ b/core/core/api/api_lint.ignore
@@ -1,6 +1,4 @@
 // Baseline format: 1.0
-AcronymName: androidx.core.database.sqlite.SQLiteCursorCompat:
-    Acronyms should not be capitalized in class names: was `SQLiteCursorCompat`, should this be `SqLiteCursorCompat`?
 AcronymName: androidx.core.graphics.ColorUtils#blendARGB(int, int, float):
     Acronyms should not be capitalized in method names: was `blendARGB`, should this be `blendArgb`?
 AcronymName: androidx.core.graphics.ColorUtils#blendHSL(float[], float[], float, float[]):
diff --git a/credentials/credentials/src/androidTest/java/androidx/credentials/CredentialProviderFactoryTest.kt b/credentials/credentials/src/androidTest/java/androidx/credentials/CredentialProviderFactoryTest.kt
index 30a90a7..979a543 100644
--- a/credentials/credentials/src/androidTest/java/androidx/credentials/CredentialProviderFactoryTest.kt
+++ b/credentials/credentials/src/androidTest/java/androidx/credentials/CredentialProviderFactoryTest.kt
@@ -17,6 +17,7 @@
 
 import android.os.Build
 import androidx.credentials.ClearCredentialStateRequest.Companion.TYPE_CLEAR_RESTORE_CREDENTIAL
+import androidx.credentials.internal.FormFactorHelper
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SdkSuppress
 import androidx.test.filters.SmallTest
@@ -239,4 +240,36 @@
         assertThat(credentialProviderFactory.getBestAvailableProvider(request))
             .isEqualTo(expectedProvider)
     }
+
+    @Test
+    fun getBestAvailableProvider_onTV_preUSuccess() {
+        if (!FormFactorHelper.isTV(context)) {
+            return
+        }
+        clearState()
+        val expectedPreUProvider = FakeProvider(success = true)
+        credentialProviderFactory.testMode = true
+        credentialProviderFactory.testPreUProvider = expectedPreUProvider
+
+        val actualProvider = credentialProviderFactory.getBestAvailableProvider()
+
+        assertThat(actualProvider).isNotNull()
+        assertThat(actualProvider).isEqualTo(expectedPreUProvider)
+    }
+
+    @Test
+    fun getBestAvailableProvider_onAuto_preUSuccess() {
+        if (!FormFactorHelper.isAuto(context)) {
+            return
+        }
+        clearState()
+        val expectedPreUProvider = FakeProvider(success = true)
+        credentialProviderFactory.testMode = true
+        credentialProviderFactory.testPreUProvider = expectedPreUProvider
+
+        val actualProvider = credentialProviderFactory.getBestAvailableProvider()
+
+        assertThat(actualProvider).isNotNull()
+        assertThat(actualProvider).isEqualTo(expectedPreUProvider)
+    }
 }
diff --git a/credentials/credentials/src/main/java/androidx/credentials/CredentialProviderFactory.kt b/credentials/credentials/src/main/java/androidx/credentials/CredentialProviderFactory.kt
index 0155a98..9d811357 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/CredentialProviderFactory.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/CredentialProviderFactory.kt
@@ -24,6 +24,7 @@
 import androidx.annotation.RestrictTo
 import androidx.annotation.VisibleForTesting
 import androidx.credentials.ClearCredentialStateRequest.Companion.TYPE_CLEAR_RESTORE_CREDENTIAL
+import androidx.credentials.internal.FormFactorHelper
 
 /** Factory that returns the credential provider to be used by Credential Manager. */
 @OptIn(ExperimentalDigitalCredentialApi::class)
@@ -94,6 +95,10 @@
      * library. Post-U, providers will be registered with the framework, and enabled by the user.
      */
     fun getBestAvailableProvider(shouldFallbackToPreU: Boolean = true): CredentialProvider? {
+        if (FormFactorHelper.isTV(context) || FormFactorHelper.isAuto(context)) {
+            return tryCreateClosedSourceProviderFromManifest()
+        }
+
         if (Build.VERSION.SDK_INT >= 34) { // Android U
             val postUProvider = tryCreatePostUProvider()
             if (postUProvider == null && shouldFallbackToPreU) {
diff --git a/credentials/credentials/src/main/java/androidx/credentials/internal/FormFactorHelper.kt b/credentials/credentials/src/main/java/androidx/credentials/internal/FormFactorHelper.kt
new file mode 100644
index 0000000..e669f38
--- /dev/null
+++ b/credentials/credentials/src/main/java/androidx/credentials/internal/FormFactorHelper.kt
@@ -0,0 +1,48 @@
+/*
+ * 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.credentials.internal
+
+import android.content.Context
+import android.content.pm.PackageManager
+import androidx.annotation.RestrictTo
+
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+object FormFactorHelper {
+    /** Determines whether the device is a TV. */
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    @JvmStatic
+    fun isTV(ctx: Context): Boolean {
+        val pm = ctx.packageManager
+        return pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK)
+    }
+
+    /** Determines whether the device is a Wearable. */
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    @JvmStatic
+    fun isWear(ctx: Context): Boolean {
+        val pm = ctx.packageManager
+        return pm.hasSystemFeature(PackageManager.FEATURE_WATCH)
+    }
+
+    /** Determines whether the device is a Auto. */
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    @JvmStatic
+    fun isAuto(ctx: Context): Boolean {
+        val pm = ctx.packageManager
+        return pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)
+    }
+}
diff --git a/development/update_studio.sh b/development/update_studio.sh
index d4b0ff3..9d33240 100755
--- a/development/update_studio.sh
+++ b/development/update_studio.sh
@@ -15,8 +15,8 @@
 
 # Versions that the user should update when running this script
 echo Getting Studio version and link
-AGP_VERSION=${1:-8.9.0-alpha01}
-STUDIO_VERSION_STRING=${2:-"Android Studio Meerkat | 2024.3.1 Canary 1"}
+AGP_VERSION=${1:-8.9.0-beta01}
+STUDIO_VERSION_STRING=${2:-"Android Studio Meerkat | 2024.3.1 Beta 1"}
 
 # Get studio version number from version name
 STUDIO_IFRAME_LINK=`curl "https://developer.android.com/studio/archive.html" | grep "<iframe " | sed "s/.* src=\"\([^\"]*\)\".*/\1/g"`
@@ -68,7 +68,7 @@
              | tail -n +3 \
              | sed '$ d') # Remove the last line
 
-ATP_VERSION=${4:-0.0.9-alpha02}
+ATP_VERSION=${4:-0.0.9-alpha03}
 ARTIFACTS_TO_DOWNLOAD+="com.google.testing.platform:android-test-plugin:$ATP_VERSION,"
 ARTIFACTS_TO_DOWNLOAD+="com.google.testing.platform:launcher:$ATP_VERSION,"
 ARTIFACTS_TO_DOWNLOAD+="com.google.testing.platform:android-driver-instrumentation:$ATP_VERSION,"
diff --git a/docs-tip-of-tree/build.gradle b/docs-tip-of-tree/build.gradle
index 5b7b2a45..7a218f8 100644
--- a/docs-tip-of-tree/build.gradle
+++ b/docs-tip-of-tree/build.gradle
@@ -249,7 +249,7 @@
     docs(project(":navigation:navigation-fragment"))
     docs(project(":navigation:navigation-fragment-compose"))
     docs(project(":navigation:navigation-fragment-ktx"))
-    docs(project(":navigation:navigation-runtime"))
+    kmpDocs(project(":navigation:navigation-runtime"))
     docs(project(":navigation:navigation-runtime-ktx"))
     docs(project(":navigation:navigation-testing"))
     docs(project(":navigation:navigation-ui"))
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 510a96e..52b9bda 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -2,13 +2,13 @@
 # -----------------------------------------------------------------------------
 # All of the following should be updated in sync.
 # -----------------------------------------------------------------------------
-androidGradlePlugin = "8.9.0-alpha01"
+androidGradlePlugin = "8.9.0-beta01"
 # NOTE: When updating the lint version we also need to update the `api` version
 # supported by `IssueRegistry`'s.' For e.g. r.android.com/1331903
-androidLint = "31.9.0-alpha01"
+androidLint = "31.9.0-beta01"
 # Once you have a chosen version of AGP to upgrade to, go to
 # https://developer.android.com/studio/archive and find the matching version of Studio.
-androidStudio = "2024.3.1.1"
+androidStudio = "2024.3.1.10"
 # -----------------------------------------------------------------------------
 
 androidLintMin = "31.1.0"
diff --git a/gradle/verification-keyring.keys b/gradle/verification-keyring.keys
index 322947c..b9e6596 100644
--- a/gradle/verification-keyring.keys
+++ b/gradle/verification-keyring.keys
@@ -4081,6 +4081,40 @@
 =Q+9k
 -----END PGP PUBLIC KEY BLOCK-----
 
+pub    EB095DA7D2F6AC0E
+sub    603D72C90616CD6B
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: BCPG v@RELEASE_NAME@
+
+mQGNBGBm/LQBDADMr/VPcTvE6k3wEYxq5kZusnDCDTsI6RK51d4oMwaRc3Z0jtZ0
+CfyWocZBok4rMbZAVnE3Q8pMyikGGUnc8ZsWoPEmJyCpw/2Orj0QqZhIgYMQ31Uq
+tiGZF/G4w9phLIkFgU9BLGYjRNM69R0oE/Tj8mjguvnKzYM3GjkY6nDsgWCM5TJX
+01k4sdLs0dVg86m4keq+SeS9uEwnINZTh6kQUKsW6aHvvPXze/UPoaZqxgXDjF+F
+JrPwW8yDllkbzpbo53ulz1TL5RsIH3daUwxXG3ciovUXG/b2ZRuWjtH7Gn/AvCNL
+0RXdHK3A2I23zCooOE+we2D45QUHm/vcmvsnbxOU7Tslm2DsnYxBjf5dAl2yZn+J
+FSrV91Bbd5ZXi1UkkGjBzAgbHDwdMvL9K6fTO9NwjXyBpiHy6ukIOObn9uIgDSSa
+xPnqgeykSv+RZEea8ML4BSif5RJYlmILEzJhH4rtX9X+t8BZv+ZoaN6p/qYg4/2+
+XfSUPmCJjlUaIUUAEQEAAbkBjQRgZvy0AQwAtuysL4l1wLjDIgva/+mD76cekxRu
+54s7zYOkh/87NIZ6tPkPlw/w+m7CEohurx2sQSPrClJoaMqxlPgRCmmj5JQVEC79
+9pkvJZb+QwslD57P84LYntiqpr+nmmR6vgDlZxaiRa6OVUllUTYwDpHcQ8MocXan
+e4iAea99acxL60zOimPeaPVK9tXZQ1nKPVIWs6RSYna54FFZn0uXfG4Qx8xEAXYd
+cUj5oEh4JFtEcP+55YVWopfi+zIQwwJ7JaO6ZZhHco4OpCwTauB/hX2SVdSijV32
+O9IhHXO3xPIi+5RC/iwHrhF3kexNLlfVWMnb/RWC7ROQXdUEK4YQGLy7+dFd7lKQ
+5gbUoAhuqWOnHyaSAyNlFGum3FR5oroad0eKS5jzk2n4UMPNDAoo7yEi1cdCrykD
+Jeb1GQD6ucQx+oqLkc1OGwqVjJU3FDQj/yvSCPKmst9lSGS3JH9l6ac033Db2qAP
+kUxnhw2xN4LHk2Ioovn5SZu1IUzH8/i+HhpfABEBAAGJAbYEGAEKACAWIQR0QPH3
+0nusEV+VPVXrCV2n0vasDgUCYGb8tAIbDAAKCRDrCV2n0vasDkSBC/91fDW0V6U8
+pRwW6HFruAnq/0uQ2gISrmDlpJzsgSO6HQQfho1T/7uuYhnBGyU4dxIF4G9A+Ehh
+2iwhB90JzCNLstTW6ueSWMK+4hvBpfx3kCbs2oxu0z8ZHroxE9I7e5XqDQOazANn
+eLRZJ5SArg1dFGYveBRlyjE55CmDQyj58aJkMbLAAJrdrMkFZHwbeBKOs3ph0zn5
+NvSBDUP8A3wlUXuSySeXYCUIj2k4Q6zJodnhP76ivfpu0eZn4UnD0sI8YdoJOsNK
+gDRO6fR9kEEh/XGY082B1Ad6tO2nea1MIVF0GIgfh3ezd3YcG4Rip0uqIPr7yxpT
+mVEA8wVvpWg8+wY2/xvLuHtZD59bK4KlQ9m+4W5WhursrdUfSI2EuXNp7xYwNRVf
+elApmsOOWqONqWg4leirxkWUMz7XDArDPuei4Qk8VF4/0yfGOVSh8VHQrIauzqrN
+p4LbYC9sii1fqxQTFVGPPhv6Wujd/eUuUeURZbKgpHIfniDXLiaTUyc=
+=aMmv
+-----END PGP PUBLIC KEY BLOCK-----
+
 pub    EB380DC13C39F675
 uid    Mark Vedder <[email protected]>
 
diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml
index 5f5b0c8..c5a4c74 100644
--- a/gradle/verification-metadata.xml
+++ b/gradle/verification-metadata.xml
@@ -316,6 +316,7 @@
          <trusted-key id="719F7C29985A8E95F58F47194D8159D6A1159B69" group="dev.zacsweers.moshix"/>
          <trusted-key id="720746177725A89207A7075BFD5DEA07FCB690A8" group="org.codehaus.mojo"/>
          <trusted-key id="73976C9C39C1479B84E2641A5A68A2249128E2C6" group="com.google.crypto.tink" name="tink-android"/>
+         <trusted-key id="7440F1F7D27BAC115F953D55EB095DA7D2F6AC0E" group="org.tensorflow"/>
          <trusted-key id="748F15B2CF9BA8F024155E6ED7C92B70FA1C814D" group="org.apache.logging.log4j"/>
          <trusted-key id="7615AD56144DF2376F49D98B1669C4BB543E0445" group="com.google.errorprone"/>
          <trusted-key id="7616EB882DAF57A11477AAF559A252FB1199D873" group="com.google.code.findbugs"/>
diff --git a/graphics/graphics-core/src/androidTest/java/androidx/graphics/opengl/egl/EGLManagerTest.kt b/graphics/graphics-core/src/androidTest/java/androidx/graphics/opengl/egl/EGLManagerTest.kt
index 99d7e6f..1f9d6a8 100644
--- a/graphics/graphics-core/src/androidTest/java/androidx/graphics/opengl/egl/EGLManagerTest.kt
+++ b/graphics/graphics-core/src/androidTest/java/androidx/graphics/opengl/egl/EGLManagerTest.kt
@@ -62,7 +62,6 @@
 
 @RunWith(AndroidJUnit4::class)
 @SmallTest
-@Suppress("AcronymName")
 class EGLManagerTest {
 
     @Test
diff --git a/graphics/graphics-core/src/androidTest/java/androidx/graphics/opengl/egl/EGLTestActivity.kt b/graphics/graphics-core/src/androidTest/java/androidx/graphics/opengl/egl/EGLTestActivity.kt
index 622f973..ce80fb8 100644
--- a/graphics/graphics-core/src/androidTest/java/androidx/graphics/opengl/egl/EGLTestActivity.kt
+++ b/graphics/graphics-core/src/androidTest/java/androidx/graphics/opengl/egl/EGLTestActivity.kt
@@ -33,7 +33,6 @@
 
 const val TAG: String = "EGLTestActivity"
 
-@Suppress("AcronymName")
 class EGLTestActivity : Activity() {
 
     private val mGLRenderer = GLRenderer()
diff --git a/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/GLFrontBufferedRenderer.kt b/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/GLFrontBufferedRenderer.kt
index 2fd880c..659b5a7 100644
--- a/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/GLFrontBufferedRenderer.kt
+++ b/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/GLFrontBufferedRenderer.kt
@@ -74,7 +74,6 @@
  * https://developer.android.com/reference/android/hardware/HardwareBuffer
  */
 @RequiresApi(Build.VERSION_CODES.Q)
-@Suppress("AcronymName")
 class GLFrontBufferedRenderer<T>
 @JvmOverloads
 constructor(
diff --git a/graphics/graphics-core/src/main/java/androidx/graphics/opengl/GLFrameBufferRenderer.kt b/graphics/graphics-core/src/main/java/androidx/graphics/opengl/GLFrameBufferRenderer.kt
index 2a1683a..bad5d25 100644
--- a/graphics/graphics-core/src/main/java/androidx/graphics/opengl/GLFrameBufferRenderer.kt
+++ b/graphics/graphics-core/src/main/java/androidx/graphics/opengl/GLFrameBufferRenderer.kt
@@ -48,7 +48,6 @@
  * buffers as well as fine grained control over synchronization of buffer content.
  */
 @RequiresApi(Build.VERSION_CODES.Q)
-@Suppress("AcronymName")
 class GLFrameBufferRenderer
 internal constructor(
     private val surfaceControlProvider: SurfaceControlProvider,
@@ -195,7 +194,6 @@
          *   thread
          * @return The builder instance
          */
-        @Suppress("AcronymName")
         fun setGLRenderer(glRenderer: GLRenderer?): Builder {
             mGLRenderer = glRenderer
             return this
@@ -339,7 +337,7 @@
      * OpenGL.
      */
     val glRenderer: GLRenderer
-        @Suppress("AcronymName") @JvmName("getGLRenderer") get() = mGLRenderer
+        @JvmName("getGLRenderer") get() = mGLRenderer
 
     /**
      * Returns the [SyncStrategy] used for determining when to create [SyncFenceCompat] objects in
diff --git a/graphics/graphics-core/src/main/java/androidx/graphics/opengl/GLRenderer.kt b/graphics/graphics-core/src/main/java/androidx/graphics/opengl/GLRenderer.kt
index 40ec7af..a595864 100644
--- a/graphics/graphics-core/src/main/java/androidx/graphics/opengl/GLRenderer.kt
+++ b/graphics/graphics-core/src/main/java/androidx/graphics/opengl/GLRenderer.kt
@@ -43,7 +43,6 @@
  *   the EGL context. This is invoked on the GL Thread
  */
 // GL is the industry standard for referencing OpenGL vs Gl (lowercase l)
-@Suppress("AcronymName")
 class GLRenderer(
     eglSpecFactory: () -> EGLSpec = { EGLSpec.V14 },
     eglConfigFactory: EGLManager.() -> EGLConfig = {
@@ -265,7 +264,6 @@
      *
      * These callbacks are invoked on the backing thread.
      */
-    @Suppress("AcronymName")
     fun registerEGLContextCallback(callback: EGLContextCallback) {
         mEglContextCallback.add(callback)
         mGLThread?.addEGLCallback(callback)
@@ -277,7 +275,6 @@
      *
      * These callbacks are invoked on the backing thread
      */
-    @Suppress("AcronymName")
     fun unregisterEGLContextCallback(callback: EGLContextCallback) {
         mEglContextCallback.remove(callback)
         mGLThread?.removeEGLCallback(callback)
@@ -288,7 +285,6 @@
      * places to setup and tear down any dependencies that are used for drawing content within a
      * frame (ex. compiling shaders)
      */
-    @Suppress("AcronymName")
     interface EGLContextCallback {
 
         /**
@@ -297,7 +293,7 @@
          * called. This will be invoked after [GLRenderer.start].
          */
         // Suppressing CallbackMethodName due to b/238939160
-        @Suppress("AcronymName", "CallbackMethodName")
+        @Suppress("CallbackMethodName")
         @WorkerThread
         fun onEGLContextCreated(eglManager: EGLManager)
 
@@ -306,7 +302,7 @@
          * This is invoked after [GLRenderer.stop] is processed.
          */
         // Suppressing CallbackMethodName due to b/238939160
-        @Suppress("AcronymName", "CallbackMethodName")
+        @Suppress("CallbackMethodName")
         @WorkerThread
         fun onEGLContextDestroyed(eglManager: EGLManager)
     }
diff --git a/graphics/graphics-core/src/main/java/androidx/graphics/opengl/egl/EGLConfigAttributes.kt b/graphics/graphics-core/src/main/java/androidx/graphics/opengl/egl/EGLConfigAttributes.kt
index d609721..86f1b5c 100644
--- a/graphics/graphics-core/src/main/java/androidx/graphics/opengl/egl/EGLConfigAttributes.kt
+++ b/graphics/graphics-core/src/main/java/androidx/graphics/opengl/egl/EGLConfigAttributes.kt
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-@file:Suppress("AcronymName")
-
 package androidx.graphics.opengl.egl
 
 import android.opengl.EGL14
@@ -89,7 +87,6 @@
  * }
  * ```
  */
-@Suppress("AcronymName")
 class EGLConfigAttributes internal constructor(@PublishedApi internal val attrs: IntArray) {
 
     /**
@@ -197,7 +194,6 @@
          * EGL Attributes to create an 8 bit EGL config for red, green, blue, and alpha channels as
          * well as an 8 bit stencil size
          */
-        @Suppress("AcronymName")
         @JvmField
         val RGBA_8888 = EGLConfigAttributes {
             EGL14.EGL_RENDERABLE_TYPE to EGL14.EGL_OPENGL_ES2_BIT
@@ -215,7 +211,6 @@
          * EGL Attributes to create a 10 bit EGL config for red, green, blue, channels and a 2 bit
          * alpha channels. This does not include any bits for depth and stencil buffers.
          */
-        @Suppress("AcronymName")
         @JvmField
         val RGBA_1010102 = EGLConfigAttributes {
             EGL14.EGL_RENDERABLE_TYPE to EGL14.EGL_OPENGL_ES2_BIT
@@ -232,7 +227,6 @@
          * EGL Attributes to create a 16 bit floating point EGL config for red, green, blue and
          * alpha channels without a depth or stencil channel.
          */
-        @Suppress("AcronymName")
         @JvmField
         val RGBA_F16 = EGLConfigAttributes {
             EGL14.EGL_RENDERABLE_TYPE to EGL14.EGL_OPENGL_ES2_BIT
diff --git a/graphics/graphics-core/src/main/java/androidx/graphics/opengl/egl/EGLManager.kt b/graphics/graphics-core/src/main/java/androidx/graphics/opengl/egl/EGLManager.kt
index 7540cf3..68afce4e 100644
--- a/graphics/graphics-core/src/main/java/androidx/graphics/opengl/egl/EGLManager.kt
+++ b/graphics/graphics-core/src/main/java/androidx/graphics/opengl/egl/EGLManager.kt
@@ -28,7 +28,6 @@
  * Class responsible for configuration of EGL related resources. This includes initialization of the
  * corresponding EGL Display as well as EGL Context, among other EGL related facilities.
  */
-@Suppress("AcronymName")
 class EGLManager(eglSpec: EGLSpec = EGLSpec.V14) {
 
     private var mEglConfig: EGLConfig? = null
@@ -124,27 +123,27 @@
     }
 
     val eglSpec: EGLSpec
-        @Suppress("AcronymName") @JvmName("getEGLSpec") get() = mEglSpec
+        @JvmName("getEGLSpec") get() = mEglSpec
 
     /**
      * Returns the EGL version that is supported. This parameter is configured after [initialize] is
      * invoked.
      */
     val eglVersion: EGLVersion
-        @Suppress("AcronymName") @JvmName("getEGLVersion") get() = mEglVersion
+        @JvmName("getEGLVersion") get() = mEglVersion
 
     /**
      * Returns the current EGLContext. This parameter is configured after [initialize] is invoked
      */
     val eglContext: EGLContext?
-        @Suppress("AcronymName") @JvmName("getEGLContext") get() = mEglContext
+        @JvmName("getEGLContext") get() = mEglContext
 
     /**
      * Returns the [EGLConfig] used to load the current [EGLContext]. This is configured after
      * [createContext] is invoked.
      */
     val eglConfig: EGLConfig?
-        @Suppress("AcronymName") @JvmName("getEGLConfig") get() = mEglConfig
+        @JvmName("getEGLConfig") get() = mEglConfig
 
     /**
      * Determines whether the extension with the provided name is supported. The string provided is
diff --git a/graphics/graphics-core/src/main/java/androidx/graphics/opengl/egl/EGLSpec.kt b/graphics/graphics-core/src/main/java/androidx/graphics/opengl/egl/EGLSpec.kt
index a233503..fdc7e4f 100644
--- a/graphics/graphics-core/src/main/java/androidx/graphics/opengl/egl/EGLSpec.kt
+++ b/graphics/graphics-core/src/main/java/androidx/graphics/opengl/egl/EGLSpec.kt
@@ -45,7 +45,6 @@
  *
  * EGLSpec is not thread safe and is up to the caller of these methods to guarantee thread safety.
  */
-@Suppress("AcronymName")
 interface EGLSpec {
 
     /**
@@ -224,7 +223,6 @@
      *
      * See www.khronos.org/registry/EGL/extensions/ANDROID/EGL_ANDROID_get_native_client_buffer.txt
      */
-    @Suppress("AcronymName")
     @RequiresApi(Build.VERSION_CODES.O)
     fun eglCreateImageFromHardwareBuffer(hardwareBuffer: HardwareBuffer): EGLImageKHR?
 
@@ -240,7 +238,7 @@
      * @param image EGLImageKHR to be destroyed
      * @return `true` if the destruction of the EGLImageKHR object was successful, `false` otherwise
      */
-    @Suppress("AcronymName") fun eglDestroyImageKHR(image: EGLImageKHR): Boolean
+    fun eglDestroyImageKHR(image: EGLImageKHR): Boolean
 
     /**
      * Creates a sync object of the specified type associated with the specified display, and
@@ -260,7 +258,6 @@
      * @return the [EGLSyncKHR] object to be used as a fence or null if this extension is not
      *   supported
      */
-    @Suppress("AcronymName")
     fun eglCreateSyncKHR(type: Int, attributes: EGLConfigAttributes?): EGLSyncKHR?
 
     /**
@@ -280,7 +277,6 @@
      *   not matching the display that was used to create this sync object. Additionally if the
      *   queried attribute is not supported for the sync object, false is returned.
      */
-    @Suppress("AcronymName")
     fun eglGetSyncAttribKHR(
         sync: EGLSyncKHR,
         @EGLSyncAttribute attribute: Int,
@@ -301,7 +297,7 @@
      *   or if the display provided in this method does not match the display used to create this
      *   sync in [eglCreateSyncKHR].
      */
-    @Suppress("AcronymName") fun eglDestroySyncKHR(sync: EGLSyncKHR): Boolean
+    fun eglDestroySyncKHR(sync: EGLSyncKHR): Boolean
 
     /**
      * Blocks the calling thread until the specified sync object is signalled or until
@@ -342,7 +338,6 @@
      *   [EGL_TIMEOUT_EXPIRED_KHR] if the sync did not signal within the specified timeout, or
      *   [EGL_FALSE] if an error occurs.
      */
-    @Suppress("AcronymName")
     fun eglClientWaitSyncKHR(
         sync: EGLSyncKHR,
         flags: Int,
@@ -550,7 +545,6 @@
  * @param error Error code reported via eglGetError
  * @param msg Optional message describing the exception being thrown
  */
-@Suppress("AcronymName")
 class EGLException(val error: Int, val msg: String = "") : RuntimeException() {
 
     override val message: String
@@ -563,7 +557,6 @@
  * @param major Major version of the EGL implementation
  * @param minor Minor version of the EGL implementation
  */
-@Suppress("AcronymName")
 data class EGLVersion(val major: Int, val minor: Int) {
 
     override fun toString(): String {
diff --git a/graphics/graphics-core/src/main/java/androidx/graphics/surface/SurfaceControlCompat.kt b/graphics/graphics-core/src/main/java/androidx/graphics/surface/SurfaceControlCompat.kt
index 182f845..0cc0d41 100644
--- a/graphics/graphics-core/src/main/java/androidx/graphics/surface/SurfaceControlCompat.kt
+++ b/graphics/graphics-core/src/main/java/androidx/graphics/surface/SurfaceControlCompat.kt
@@ -58,7 +58,6 @@
          *
          * Various transformations that can be applied to a buffer.
          */
-        @Suppress("AcronymName")
         @IntDef(
             value =
                 [
diff --git a/graphics/graphics-core/src/main/java/androidx/opengl/EGLExt.kt b/graphics/graphics-core/src/main/java/androidx/opengl/EGLExt.kt
index 299c046..757b98b 100644
--- a/graphics/graphics-core/src/main/java/androidx/opengl/EGLExt.kt
+++ b/graphics/graphics-core/src/main/java/androidx/opengl/EGLExt.kt
@@ -28,7 +28,6 @@
 import androidx.opengl.EGLExt.Companion.eglCreateSyncKHR
 
 /** Utility class that provides some helper methods for interacting EGL Extension APIs */
-@Suppress("AcronymName")
 class EGLExt private constructor() {
 
     companion object {
@@ -191,7 +190,6 @@
 
         /** Specifies the types of attributes that can be queried in [eglGetSyncAttribKHR] */
         @RestrictTo(RestrictTo.Scope.LIBRARY)
-        @Suppress("AcronymName")
         @IntDef(value = [EGL_SYNC_TYPE_KHR, EGL_SYNC_STATUS_KHR, EGL_SYNC_CONDITION_KHR])
         annotation class EGLSyncAttribute
 
@@ -246,7 +244,6 @@
 
         /** Specifies the type of fence to create in [eglCreateSyncKHR] */
         @RestrictTo(RestrictTo.Scope.LIBRARY)
-        @Suppress("AcronymName")
         @IntDef(value = [EGL_SYNC_FENCE_KHR, EGL_SYNC_NATIVE_FENCE_ANDROID])
         annotation class EGLFenceType
 
@@ -290,7 +287,6 @@
         /** Specifies various return values for the [eglClientWaitSyncKHR] method */
         @RestrictTo(RestrictTo.Scope.LIBRARY)
         @Target(AnnotationTarget.TYPE)
-        @Suppress("AcronymName")
         @IntDef(value = [EGL_CONDITION_SATISFIED_KHR, EGL_TIMEOUT_EXPIRED_KHR, EGL_FALSE])
         annotation class EGLClientWaitResult
 
@@ -368,7 +364,6 @@
          * @return True if the destruction of the EGLImageKHR object was successful, false otherwise
          */
         @JvmStatic
-        @Suppress("AcronymName")
         fun eglDestroyImageKHR(eglDisplay: EGLDisplay, image: EGLImageKHR): Boolean =
             EGLBindings.nDestroyImageKHR(eglDisplay.nativeHandle, image.nativeHandle)
 
@@ -406,7 +401,6 @@
          *   supported
          */
         @JvmStatic
-        @Suppress("AcronymName")
         fun eglCreateSyncKHR(
             eglDisplay: EGLDisplay,
             @EGLFenceType type: Int,
@@ -441,7 +435,6 @@
          *   returned.
          */
         @JvmStatic
-        @Suppress("AcronymName")
         fun eglGetSyncAttribKHR(
             eglDisplay: EGLDisplay,
             sync: EGLSyncKHR,
@@ -498,7 +491,6 @@
          *   [EGL_FALSE] if an error occurs.
          */
         @JvmStatic
-        @Suppress("AcronymName")
         fun eglClientWaitSyncKHR(
             eglDisplay: EGLDisplay,
             sync: EGLSyncKHR,
@@ -557,7 +549,6 @@
          *   this sync in eglCreateSyncKHR.
          */
         @JvmStatic
-        @Suppress("AcronymName")
         fun eglDestroySyncKHR(eglDisplay: EGLDisplay, eglSync: EGLSyncKHR): Boolean =
             EGLBindings.nDestroySyncKHR(eglDisplay.nativeHandle, eglSync.nativeHandle)
 
diff --git a/graphics/graphics-core/src/main/java/androidx/opengl/EGLHandle.kt b/graphics/graphics-core/src/main/java/androidx/opengl/EGLHandle.kt
index 6c66383..8b30e32 100644
--- a/graphics/graphics-core/src/main/java/androidx/opengl/EGLHandle.kt
+++ b/graphics/graphics-core/src/main/java/androidx/opengl/EGLHandle.kt
@@ -17,7 +17,6 @@
 package androidx.opengl
 
 /** Interface used to wrap native EGL objects to create type safe objects */
-@Suppress("AcronymName")
 interface EGLHandle {
     /**
      * Returns the native handle of the wrapped EGL object. This handle can be cast to the
diff --git a/graphics/graphics-core/src/main/java/androidx/opengl/EGLImageKHR.kt b/graphics/graphics-core/src/main/java/androidx/opengl/EGLImageKHR.kt
index 84ea358..eaea90d 100644
--- a/graphics/graphics-core/src/main/java/androidx/opengl/EGLImageKHR.kt
+++ b/graphics/graphics-core/src/main/java/androidx/opengl/EGLImageKHR.kt
@@ -21,7 +21,6 @@
  * APIs). This is similar to EGL's EGLImage API except the KHR suffix indicates it is generated as
  * part of the extension APIs namely through [EGLExt.eglCreateImageFromHardwareBuffer]
  */
-@Suppress("AcronymName")
 class EGLImageKHR(override val nativeHandle: Long) : EGLHandle {
 
     override fun equals(other: Any?): Boolean {
diff --git a/graphics/graphics-core/src/main/java/androidx/opengl/EGLSyncKHR.kt b/graphics/graphics-core/src/main/java/androidx/opengl/EGLSyncKHR.kt
index 3b20756..fc90ac4 100644
--- a/graphics/graphics-core/src/main/java/androidx/opengl/EGLSyncKHR.kt
+++ b/graphics/graphics-core/src/main/java/androidx/opengl/EGLSyncKHR.kt
@@ -21,7 +21,6 @@
  * suffix indicates it is generated as part of the extension APIs namely through
  * [EGLExt.eglCreateSyncKHR].
  */
-@Suppress("AcronymName")
 class EGLSyncKHR(override val nativeHandle: Long) : EGLHandle {
     override fun equals(other: Any?): Boolean {
         if (this === other) return true
diff --git a/lifecycle/lifecycle-viewmodel-navigation3/api/current.txt b/lifecycle/lifecycle-viewmodel-navigation3/api/current.txt
index 927612c..170aefd 100644
--- a/lifecycle/lifecycle-viewmodel-navigation3/api/current.txt
+++ b/lifecycle/lifecycle-viewmodel-navigation3/api/current.txt
@@ -2,7 +2,7 @@
 package androidx.lifecycle.viewmodel.navigation3 {
 
   public final class ViewModelStoreNavLocalProvider implements androidx.navigation3.NavLocalProvider {
-    method @androidx.compose.runtime.Composable public void ProvideToBackStack(java.util.List<?> backStack);
+    method @androidx.compose.runtime.Composable public void ProvideToBackStack(java.util.List<?> backStack, kotlin.jvm.functions.Function0<kotlin.Unit> content);
     method @androidx.compose.runtime.Composable public <T> void ProvideToEntry(androidx.navigation3.NavEntry<T> entry);
     field public static final androidx.lifecycle.viewmodel.navigation3.ViewModelStoreNavLocalProvider INSTANCE;
   }
diff --git a/lifecycle/lifecycle-viewmodel-navigation3/api/restricted_current.txt b/lifecycle/lifecycle-viewmodel-navigation3/api/restricted_current.txt
index 927612c..170aefd 100644
--- a/lifecycle/lifecycle-viewmodel-navigation3/api/restricted_current.txt
+++ b/lifecycle/lifecycle-viewmodel-navigation3/api/restricted_current.txt
@@ -2,7 +2,7 @@
 package androidx.lifecycle.viewmodel.navigation3 {
 
   public final class ViewModelStoreNavLocalProvider implements androidx.navigation3.NavLocalProvider {
-    method @androidx.compose.runtime.Composable public void ProvideToBackStack(java.util.List<?> backStack);
+    method @androidx.compose.runtime.Composable public void ProvideToBackStack(java.util.List<?> backStack, kotlin.jvm.functions.Function0<kotlin.Unit> content);
     method @androidx.compose.runtime.Composable public <T> void ProvideToEntry(androidx.navigation3.NavEntry<T> entry);
     field public static final androidx.lifecycle.viewmodel.navigation3.ViewModelStoreNavLocalProvider INSTANCE;
   }
diff --git a/lifecycle/lifecycle-viewmodel-navigation3/src/androidMain/kotlin/androidx/lifecycle/viewmodel/navigation3/ViewModelStoreNavLocalProvider.android.kt b/lifecycle/lifecycle-viewmodel-navigation3/src/androidMain/kotlin/androidx/lifecycle/viewmodel/navigation3/ViewModelStoreNavLocalProvider.android.kt
index 37b32ac..aed0618 100644
--- a/lifecycle/lifecycle-viewmodel-navigation3/src/androidMain/kotlin/androidx/lifecycle/viewmodel/navigation3/ViewModelStoreNavLocalProvider.android.kt
+++ b/lifecycle/lifecycle-viewmodel-navigation3/src/androidMain/kotlin/androidx/lifecycle/viewmodel/navigation3/ViewModelStoreNavLocalProvider.android.kt
@@ -50,10 +50,11 @@
 public object ViewModelStoreNavLocalProvider : NavLocalProvider {
 
     @Composable
-    override fun ProvideToBackStack(backStack: List<Any>) {
+    override fun ProvideToBackStack(backStack: List<Any>, content: @Composable () -> Unit) {
         val entryViewModelStoreProvider = viewModel { EntryViewModel() }
         entryViewModelStoreProvider.ownerInBackStack.clear()
         entryViewModelStoreProvider.ownerInBackStack.addAll(backStack)
+        content.invoke()
     }
 
     @Composable
@@ -88,36 +89,36 @@
         }
 
         val savedStateRegistryOwner = LocalSavedStateRegistryOwner.current
-        CompositionLocalProvider(
-            LocalViewModelStoreOwner provides
-                object :
-                    ViewModelStoreOwner,
-                    SavedStateRegistryOwner by savedStateRegistryOwner,
-                    HasDefaultViewModelProviderFactory {
-                    override val viewModelStore: ViewModelStore
-                        get() = viewModelStore
+        val childViewModelOwner = remember {
+            object :
+                ViewModelStoreOwner,
+                SavedStateRegistryOwner by savedStateRegistryOwner,
+                HasDefaultViewModelProviderFactory {
+                override val viewModelStore: ViewModelStore
+                    get() = viewModelStore
 
-                    override val defaultViewModelProviderFactory: ViewModelProvider.Factory
-                        get() = SavedStateViewModelFactory(null, savedStateRegistryOwner)
+                override val defaultViewModelProviderFactory: ViewModelProvider.Factory
+                    get() = SavedStateViewModelFactory(null, savedStateRegistryOwner)
 
-                    override val defaultViewModelCreationExtras: CreationExtras
-                        get() =
-                            MutableCreationExtras().also {
-                                it[SAVED_STATE_REGISTRY_OWNER_KEY] = savedStateRegistryOwner
-                                it[VIEW_MODEL_STORE_OWNER_KEY] = this
-                            }
-
-                    init {
-                        require(this.lifecycle.currentState == Lifecycle.State.INITIALIZED) {
-                            "The Lifecycle state is already beyond INITIALIZED. The " +
-                                "ViewModelStoreNavLocalProvider requires adding the " +
-                                "SavedStateNavLocalProvider to ensure support for " +
-                                "SavedStateHandles."
+                override val defaultViewModelCreationExtras: CreationExtras
+                    get() =
+                        MutableCreationExtras().also {
+                            it[SAVED_STATE_REGISTRY_OWNER_KEY] = savedStateRegistryOwner
+                            it[VIEW_MODEL_STORE_OWNER_KEY] = this
                         }
-                        enableSavedStateHandles()
+
+                init {
+                    require(this.lifecycle.currentState == Lifecycle.State.INITIALIZED) {
+                        "The Lifecycle state is already beyond INITIALIZED. The " +
+                            "ViewModelStoreNavLocalProvider requires adding the " +
+                            "SavedStateNavLocalProvider to ensure support for " +
+                            "SavedStateHandles."
                     }
+                    enableSavedStateHandles()
                 }
-        ) {
+            }
+        }
+        CompositionLocalProvider(LocalViewModelStoreOwner provides childViewModelOwner) {
             entry.content.invoke(key)
         }
     }
diff --git a/lifecycle/lifecycle-viewmodel-savedstate/api/current.txt b/lifecycle/lifecycle-viewmodel-savedstate/api/current.txt
index 74041ee..e9b8ced 100644
--- a/lifecycle/lifecycle-viewmodel-savedstate/api/current.txt
+++ b/lifecycle/lifecycle-viewmodel-savedstate/api/current.txt
@@ -50,10 +50,8 @@
 package androidx.lifecycle.serialization {
 
   public final class SavedStateHandleDelegatesKt {
-    method public static inline <reified T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.lifecycle.SavedStateHandle, String key, kotlin.jvm.functions.Function0<? extends T> init);
-    method public static <T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.lifecycle.SavedStateHandle, String key, kotlinx.serialization.KSerializer<T> serializer, kotlin.jvm.functions.Function0<? extends T> init);
-    method public static inline <reified T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.lifecycle.SavedStateHandle, kotlin.jvm.functions.Function0<? extends T> init);
-    method public static <T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.lifecycle.SavedStateHandle, kotlinx.serialization.KSerializer<T> serializer, kotlin.jvm.functions.Function0<? extends T> init);
+    method public static inline <reified T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.lifecycle.SavedStateHandle, optional String? key, kotlin.jvm.functions.Function0<? extends T> init);
+    method public static <T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.lifecycle.SavedStateHandle, kotlinx.serialization.KSerializer<T> serializer, optional String? key, kotlin.jvm.functions.Function0<? extends T> init);
   }
 
 }
diff --git a/lifecycle/lifecycle-viewmodel-savedstate/api/restricted_current.txt b/lifecycle/lifecycle-viewmodel-savedstate/api/restricted_current.txt
index 74041ee..e9b8ced 100644
--- a/lifecycle/lifecycle-viewmodel-savedstate/api/restricted_current.txt
+++ b/lifecycle/lifecycle-viewmodel-savedstate/api/restricted_current.txt
@@ -50,10 +50,8 @@
 package androidx.lifecycle.serialization {
 
   public final class SavedStateHandleDelegatesKt {
-    method public static inline <reified T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.lifecycle.SavedStateHandle, String key, kotlin.jvm.functions.Function0<? extends T> init);
-    method public static <T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.lifecycle.SavedStateHandle, String key, kotlinx.serialization.KSerializer<T> serializer, kotlin.jvm.functions.Function0<? extends T> init);
-    method public static inline <reified T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.lifecycle.SavedStateHandle, kotlin.jvm.functions.Function0<? extends T> init);
-    method public static <T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.lifecycle.SavedStateHandle, kotlinx.serialization.KSerializer<T> serializer, kotlin.jvm.functions.Function0<? extends T> init);
+    method public static inline <reified T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.lifecycle.SavedStateHandle, optional String? key, kotlin.jvm.functions.Function0<? extends T> init);
+    method public static <T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.lifecycle.SavedStateHandle, kotlinx.serialization.KSerializer<T> serializer, optional String? key, kotlin.jvm.functions.Function0<? extends T> init);
   }
 
 }
diff --git a/lifecycle/lifecycle-viewmodel-savedstate/bcv/native/current.txt b/lifecycle/lifecycle-viewmodel-savedstate/bcv/native/current.txt
index 7a78cde..3b9bf81 100644
--- a/lifecycle/lifecycle-viewmodel-savedstate/bcv/native/current.txt
+++ b/lifecycle/lifecycle-viewmodel-savedstate/bcv/native/current.txt
@@ -42,7 +42,5 @@
 
 final fun (androidx.lifecycle.viewmodel/CreationExtras).androidx.lifecycle/createSavedStateHandle(): androidx.lifecycle/SavedStateHandle // androidx.lifecycle/createSavedStateHandle|createSavedStateHandle@androidx.lifecycle.viewmodel.CreationExtras(){}[0]
 final fun <#A: androidx.lifecycle/ViewModelStoreOwner & androidx.savedstate/SavedStateRegistryOwner> (#A).androidx.lifecycle/enableSavedStateHandles() // androidx.lifecycle/enableSavedStateHandles|enableSavedStateHandles@0:0(){0§<androidx.savedstate.SavedStateRegistryOwner&androidx.lifecycle.ViewModelStoreOwner>}[0]
-final fun <#A: kotlin/Any> (androidx.lifecycle/SavedStateHandle).androidx.lifecycle.serialization/saved(kotlin/String, kotlinx.serialization/KSerializer<#A>, kotlin/Function0<#A>): kotlin.properties/ReadWriteProperty<kotlin/Any?, #A> // androidx.lifecycle.serialization/saved|[email protected](kotlin.String;kotlinx.serialization.KSerializer<0:0>;kotlin.Function0<0:0>){0§<kotlin.Any>}[0]
-final fun <#A: kotlin/Any> (androidx.lifecycle/SavedStateHandle).androidx.lifecycle.serialization/saved(kotlinx.serialization/KSerializer<#A>, kotlin/Function0<#A>): kotlin.properties/ReadWriteProperty<kotlin/Any?, #A> // androidx.lifecycle.serialization/saved|[email protected](kotlinx.serialization.KSerializer<0:0>;kotlin.Function0<0:0>){0§<kotlin.Any>}[0]
-final inline fun <#A: reified kotlin/Any> (androidx.lifecycle/SavedStateHandle).androidx.lifecycle.serialization/saved(kotlin/String, noinline kotlin/Function0<#A>): kotlin.properties/ReadWriteProperty<kotlin/Any?, #A> // androidx.lifecycle.serialization/saved|[email protected](kotlin.String;kotlin.Function0<0:0>){0§<kotlin.Any>}[0]
-final inline fun <#A: reified kotlin/Any> (androidx.lifecycle/SavedStateHandle).androidx.lifecycle.serialization/saved(noinline kotlin/Function0<#A>): kotlin.properties/ReadWriteProperty<kotlin/Any?, #A> // androidx.lifecycle.serialization/saved|[email protected](kotlin.Function0<0:0>){0§<kotlin.Any>}[0]
+final fun <#A: kotlin/Any> (androidx.lifecycle/SavedStateHandle).androidx.lifecycle.serialization/saved(kotlinx.serialization/KSerializer<#A>, kotlin/String? = ..., kotlin/Function0<#A>): kotlin.properties/ReadWriteProperty<kotlin/Any?, #A> // androidx.lifecycle.serialization/saved|[email protected](kotlinx.serialization.KSerializer<0:0>;kotlin.String?;kotlin.Function0<0:0>){0§<kotlin.Any>}[0]
+final inline fun <#A: reified kotlin/Any> (androidx.lifecycle/SavedStateHandle).androidx.lifecycle.serialization/saved(kotlin/String? = ..., noinline kotlin/Function0<#A>): kotlin.properties/ReadWriteProperty<kotlin/Any?, #A> // androidx.lifecycle.serialization/saved|[email protected](kotlin.String?;kotlin.Function0<0:0>){0§<kotlin.Any>}[0]
diff --git a/lifecycle/lifecycle-viewmodel-savedstate/src/commonMain/kotlin/androidx/lifecycle/serialization/SavedStateHandleDelegates.kt b/lifecycle/lifecycle-viewmodel-savedstate/src/commonMain/kotlin/androidx/lifecycle/serialization/SavedStateHandleDelegates.kt
index a964d34..edd1bc10 100644
--- a/lifecycle/lifecycle-viewmodel-savedstate/src/commonMain/kotlin/androidx/lifecycle/serialization/SavedStateHandleDelegates.kt
+++ b/lifecycle/lifecycle-viewmodel-savedstate/src/commonMain/kotlin/androidx/lifecycle/serialization/SavedStateHandleDelegates.kt
@@ -27,67 +27,34 @@
 
 /**
  * Returns a property delegate that uses [SavedStateHandle] to save and restore a value of type [T]
- * with fully qualified property or variable name as key and the default serializer.
- *
- * @sample androidx.lifecycle.delegate
- * @param init The function to provide the initial value of the property.
- * @return A property delegate that manages the saving and restoring of the value.
- */
-public inline fun <reified T : Any> SavedStateHandle.saved(
-    noinline init: () -> T,
-): ReadWriteProperty<Any?, T> {
-    return saved(serializer(), init)
-}
-
-/**
- * Returns a property delegate that uses [SavedStateHandle] to save and restore a value of type [T]
  * with the default serializer.
  *
  * @sample androidx.lifecycle.delegateExplicitKey
- * @param key The [String] key to use for storing the value in the [SavedStateHandle].
+ * @param key An optional [String] key to use for storing the value in the [SavedStateHandle]. A
+ *   default key will be generated if it's omitted or when 'null' is passed.
  * @param init The function to provide the initial value of the property.
  * @return A property delegate that manages the saving and restoring of the value.
  */
 public inline fun <reified T : Any> SavedStateHandle.saved(
-    key: String,
+    key: String? = null,
     noinline init: () -> T,
 ): ReadWriteProperty<Any?, T> {
-    return saved(key, serializer(), init)
-}
-
-/**
- * Returns a property delegate that uses [SavedStateHandle] to save and restore a value of type [T]
- * with fully qualified property or variable name as key.
- *
- * @sample androidx.lifecycle.delegateExplicitSerializer
- * @param serializer The [KSerializer] to use for serializing and deserializing the value.
- * @param init The function to provide the initial value of the property.
- * @return A property delegate that manages the saving and restoring of the value.
- */
-public fun <T : Any> SavedStateHandle.saved(
-    serializer: KSerializer<T>,
-    init: () -> T,
-): ReadWriteProperty<Any?, T> {
-    return SavedStateHandleDelegate(
-        savedStateHandle = this,
-        key = null,
-        serializer = serializer,
-        init = init
-    )
+    return saved(serializer(), key, init)
 }
 
 /**
  * Returns a property delegate that uses [SavedStateHandle] to save and restore a value of type [T].
  *
  * @sample androidx.lifecycle.delegateExplicitKeyAndSerializer
- * @param key The [String] key to use for storing the value in the [SavedStateHandle].
  * @param serializer The [KSerializer] to use for serializing and deserializing the value.
+ * @param key An optional [String] key to use for storing the value in the [SavedStateHandle]. A
+ *   default key will be generated if it's omitted or when 'null' is passed.
  * @param init The function to provide the initial value of the property.
  * @return A property delegate that manages the saving and restoring of the value.
  */
 public fun <T : Any> SavedStateHandle.saved(
-    key: String,
     serializer: KSerializer<T>,
+    key: String? = null,
     init: () -> T,
 ): ReadWriteProperty<Any?, T> {
     return SavedStateHandleDelegate(
diff --git a/lint-checks/src/test/java/androidx/build/lint/replacewith/ReplaceWithDetectorImportsTest.kt b/lint-checks/src/test/java/androidx/build/lint/replacewith/ReplaceWithDetectorImportsTest.kt
index 1be5a54..6c38fa8 100644
--- a/lint-checks/src/test/java/androidx/build/lint/replacewith/ReplaceWithDetectorImportsTest.kt
+++ b/lint-checks/src/test/java/androidx/build/lint/replacewith/ReplaceWithDetectorImportsTest.kt
@@ -16,6 +16,8 @@
 
 package androidx.build.lint.replacewith
 
+import androidx.build.lint.ReplaceWithDetector
+import com.android.tools.lint.checks.infrastructure.TestLintTask
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
@@ -217,6 +219,13 @@
         """
                 .trimIndent()
 
-        check(*input).expect(expected).expectFixDiffs(expectedFixDiffs)
+        // Move to check(*input) when b/391690668 is fixed and verifyFixedFileSyntax is removed.
+        TestLintTask.lint()
+            .files(ANDROIDX_REPLACE_WITH_KT, ANDROIDX_ANY_THREAD_KT, *input)
+            .issues(ReplaceWithDetector.ISSUE)
+            .verifyFixedFileSyntax(false)
+            .run()
+            .expect(expected)
+            .expectFixDiffs(expectedFixDiffs)
     }
 }
diff --git a/lint-checks/src/test/java/androidx/build/lint/replacewith/ReplaceWithDetectorPropertyTest.kt b/lint-checks/src/test/java/androidx/build/lint/replacewith/ReplaceWithDetectorPropertyTest.kt
index 407c0b7..fb2cf44 100644
--- a/lint-checks/src/test/java/androidx/build/lint/replacewith/ReplaceWithDetectorPropertyTest.kt
+++ b/lint-checks/src/test/java/androidx/build/lint/replacewith/ReplaceWithDetectorPropertyTest.kt
@@ -16,6 +16,8 @@
 
 package androidx.build.lint.replacewith
 
+import androidx.build.lint.ReplaceWithDetector
+import com.android.tools.lint.checks.infrastructure.TestLintTask
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
@@ -60,6 +62,13 @@
         """
                 .trimIndent()
 
-        check(*input).expect(expected).expectFixDiffs(expectedFixDiffs)
+        // Move to check(*input) when b/391690668 is fixed and verifyFixedFileSyntax is removed.
+        TestLintTask.lint()
+            .files(ANDROIDX_REPLACE_WITH_KT, ANDROIDX_ANY_THREAD_KT, *input)
+            .issues(ReplaceWithDetector.ISSUE)
+            .verifyFixedFileSyntax(false)
+            .run()
+            .expect(expected)
+            .expectFixDiffs(expectedFixDiffs)
     }
 }
diff --git a/navigation/navigation-runtime/bcv/native/current.txt b/navigation/navigation-runtime/bcv/native/current.txt
new file mode 100644
index 0000000..47e0dc0
--- /dev/null
+++ b/navigation/navigation-runtime/bcv/native/current.txt
@@ -0,0 +1,11 @@
+// Klib ABI Dump
+// Targets: [iosArm64, iosSimulatorArm64, iosX64, linuxArm64, linuxX64, macosArm64, macosX64]
+// Rendering settings:
+// - Signature version: 2
+// - Show manifest properties: true
+// - Show declarations: true
+
+// Library unique name: <androidx.navigation:navigation-runtime>
+open annotation class androidx.navigation/NavDeepLinkSaveStateControl : kotlin/Annotation { // androidx.navigation/NavDeepLinkSaveStateControl|null[0]
+    constructor <init>() // androidx.navigation/NavDeepLinkSaveStateControl.<init>|<init>(){}[0]
+}
diff --git a/navigation/navigation-runtime/build.gradle b/navigation/navigation-runtime/build.gradle
index 1ad4631..c71a4c0 100644
--- a/navigation/navigation-runtime/build.gradle
+++ b/navigation/navigation-runtime/build.gradle
@@ -24,49 +24,132 @@
 
 import androidx.build.KotlinTarget
 import androidx.build.LibraryType
+import androidx.build.PlatformIdentifier
+import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
 
 plugins {
     id("AndroidXPlugin")
     id("com.android.library")
-    id("kotlin-android")
     alias(libs.plugins.kotlinSerialization)
 }
 
+androidXMultiplatform {
+    android()
+    desktop()
+    mac()
+    linux()
+    ios()
+
+    defaultPlatform(PlatformIdentifier.ANDROID)
+
+    sourceSets {
+        commonMain {
+            dependencies {
+                api(libs.kotlinStdlib)
+                api(libs.kotlinCoroutinesCore)
+                api(project(":navigation:navigation-common"))
+                api("androidx.lifecycle:lifecycle-common:2.6.2")
+                api("androidx.lifecycle:lifecycle-runtime:2.6.2")
+                api("androidx.lifecycle:lifecycle-viewmodel:2.6.2")
+
+                implementation(libs.kotlinSerializationCore)
+                implementation("androidx.collection:collection:1.4.2")
+            }
+        }
+        commonTest {
+            dependencies {
+                implementation(libs.kotlinTest)
+            }
+        }
+        nonAndroidMain {
+            dependsOn(commonMain)
+        }
+        nonAndroidTest {
+            dependsOn(commonTest)
+        }
+        jvmCommonMain {
+            dependsOn(commonMain)
+        }
+        jvmCommonTest {
+            dependsOn(commonTest)
+        }
+        desktopMain {
+            dependsOn(jvmCommonMain)
+            dependsOn(nonAndroidMain)
+        }
+        desktopTest {
+            dependsOn(jvmCommonTest)
+            dependsOn(nonAndroidTest)
+        }
+        androidMain {
+            dependsOn(jvmCommonMain)
+            dependencies {
+                api("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2")
+                api("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2")
+                api("androidx.activity:activity-ktx:1.7.1")
+                api("androidx.core:core-ktx:1.8.0")
+                api("androidx.annotation:annotation-experimental:1.4.1")
+            }
+        }
+        androidUnitTest {
+            dependsOn(commonTest)
+        }
+        androidInstrumentedTest {
+            dependsOn(commonTest)
+            dependencies {
+                implementation("androidx.annotation:annotation:1.8.0")
+                implementation("androidx.lifecycle:lifecycle-viewmodel-savedstate:2.6.2")
+                implementation("androidx.lifecycle:lifecycle-common:2.6.2")
+                implementation("androidx.lifecycle:lifecycle-runtime:2.6.2")
+                implementation("androidx.lifecycle:lifecycle-runtime-testing:2.6.2")
+                implementation(project(":internal-testutils-navigation"))
+                implementation(project(":internal-testutils-runtime"))
+                implementation(libs.hamcrestCore)
+                implementation(libs.junit)
+                implementation(libs.kotlinTest)
+                implementation(libs.testCore)
+                implementation(libs.testExtJunit)
+                implementation(libs.testExtTruth)
+                implementation(libs.testMonitor)
+                implementation(libs.testRunner)
+                implementation(libs.testRules)
+                implementation(libs.espressoIntents)
+                implementation(libs.truth)
+                implementation(libs.dexmakerMockito)
+                implementation(libs.mockitoCore)
+            }
+        }
+        nonJvmCommonMain {
+            dependsOn(nonAndroidMain)
+        }
+        nonJvmCommonTest {
+            dependsOn(nonAndroidTest)
+        }
+        nativeMain {
+            dependsOn(nonJvmCommonMain)
+        }
+        linuxMain.dependsOn(nativeMain)
+        darwinMain.dependsOn(nativeMain)
+        nativeTest {
+            dependsOn(nonJvmCommonTest)
+        }
+        linuxTest.dependsOn(nativeTest)
+        darwinTest.dependsOn(nativeTest)
+        targets.configureEach { target ->
+            if (target.platformType == KotlinPlatformType.native) {
+                if (target.konanTarget.family.appleFamily) {
+                    target.compilations["main"].defaultSourceSet.dependsOn(darwinMain)
+                    target.compilations["test"].defaultSourceSet.dependsOn(darwinTest)
+                } else if (target.konanTarget.family == org.jetbrains.kotlin.konan.target.Family.LINUX) {
+                    target.compilations["main"].defaultSourceSet.dependsOn(linuxMain)
+                    target.compilations["test"].defaultSourceSet.dependsOn(linuxTest)
+                }
+            }
+        }
+    }
+}
+
 dependencies {
-    api(libs.kotlinStdlib)
-    api(libs.kotlinCoroutinesCore)
-    api(project(":navigation:navigation-common"))
-    api("androidx.activity:activity-ktx:1.7.1")
-    api("androidx.core:core-ktx:1.8.0")
-    api("androidx.lifecycle:lifecycle-common:2.6.2")
-    api("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2")
-    api("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2")
-    api("androidx.annotation:annotation-experimental:1.4.1")
-
-    implementation(libs.kotlinSerializationCore)
-    implementation("androidx.collection:collection:1.4.2")
-
-    androidTestImplementation("androidx.annotation:annotation:1.8.0")
-    androidTestImplementation("androidx.lifecycle:lifecycle-viewmodel-savedstate:2.6.2")
-    androidTestImplementation("androidx.lifecycle:lifecycle-common:2.6.2")
-    androidTestImplementation("androidx.lifecycle:lifecycle-runtime:2.6.2")
-    androidTestImplementation("androidx.lifecycle:lifecycle-runtime-testing:2.6.2")
-    androidTestImplementation(project(":internal-testutils-navigation"))
-    androidTestImplementation(project(":internal-testutils-runtime"))
-    androidTestImplementation(libs.hamcrestCore)
-    androidTestImplementation(libs.junit)
-    androidTestImplementation(libs.kotlinTest)
-    androidTestImplementation(libs.testCore)
-    androidTestImplementation(libs.testExtJunit)
-    androidTestImplementation(libs.testExtTruth)
-    androidTestImplementation(libs.testMonitor)
-    androidTestImplementation(libs.testRunner)
-    androidTestImplementation(libs.testRules)
-    androidTestImplementation(libs.espressoIntents)
-    androidTestImplementation(libs.truth)
-    androidTestImplementation(libs.dexmakerMockito)
-    androidTestImplementation(libs.mockitoCore)
-
     lintPublish(project(":navigation:navigation-runtime-lint"))
 }
 
diff --git a/navigation/navigation-runtime/src/androidTest/AndroidManifest.xml b/navigation/navigation-runtime/src/androidInstrumentedTest/AndroidManifest.xml
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/AndroidManifest.xml
rename to navigation/navigation-runtime/src/androidInstrumentedTest/AndroidManifest.xml
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/ActivityNavigatorDestinationBuilderTest.kt b/navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/ActivityNavigatorDestinationBuilderTest.kt
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/java/androidx/navigation/ActivityNavigatorDestinationBuilderTest.kt
rename to navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/ActivityNavigatorDestinationBuilderTest.kt
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/ActivityNavigatorExtrasTest.kt b/navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/ActivityNavigatorExtrasTest.kt
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/java/androidx/navigation/ActivityNavigatorExtrasTest.kt
rename to navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/ActivityNavigatorExtrasTest.kt
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/ActivityNavigatorTest.kt b/navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/ActivityNavigatorTest.kt
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/java/androidx/navigation/ActivityNavigatorTest.kt
rename to navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/ActivityNavigatorTest.kt
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/ActivityTest.kt b/navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/ActivityTest.kt
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/java/androidx/navigation/ActivityTest.kt
rename to navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/ActivityTest.kt
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/FloatingWindowTest.kt b/navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/FloatingWindowTest.kt
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/java/androidx/navigation/FloatingWindowTest.kt
rename to navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/FloatingWindowTest.kt
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavBackStackEntryLifecycleTest.kt b/navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/NavBackStackEntryLifecycleTest.kt
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavBackStackEntryLifecycleTest.kt
rename to navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/NavBackStackEntryLifecycleTest.kt
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavBackStackEntryTest.kt b/navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/NavBackStackEntryTest.kt
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavBackStackEntryTest.kt
rename to navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/NavBackStackEntryTest.kt
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerActivityTest.kt b/navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/NavControllerActivityTest.kt
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerActivityTest.kt
rename to navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/NavControllerActivityTest.kt
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerRouteTest.kt b/navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/NavControllerRouteTest.kt
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerRouteTest.kt
rename to navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/NavControllerRouteTest.kt
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerTest.kt b/navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/NavControllerTest.kt
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerTest.kt
rename to navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/NavControllerTest.kt
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerViewModelTest.kt b/navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/NavControllerViewModelTest.kt
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerViewModelTest.kt
rename to navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/NavControllerViewModelTest.kt
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavDeepLinkBuilderTest.kt b/navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/NavDeepLinkBuilderTest.kt
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavDeepLinkBuilderTest.kt
rename to navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/NavDeepLinkBuilderTest.kt
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavHostTest.kt b/navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/NavHostTest.kt
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavHostTest.kt
rename to navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/NavHostTest.kt
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavInflaterTest.kt b/navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/NavInflaterTest.kt
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavInflaterTest.kt
rename to navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/NavInflaterTest.kt
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/ViewTest.kt b/navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/ViewTest.kt
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/java/androidx/navigation/ViewTest.kt
rename to navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/ViewTest.kt
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/test/FloatingTestNavigator.kt b/navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/test/FloatingTestNavigator.kt
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/java/androidx/navigation/test/FloatingTestNavigator.kt
rename to navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/test/FloatingTestNavigator.kt
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/test/SupportingFloatingTestNavigator.kt b/navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/test/SupportingFloatingTestNavigator.kt
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/java/androidx/navigation/test/SupportingFloatingTestNavigator.kt
rename to navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/test/SupportingFloatingTestNavigator.kt
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/test/SupportingTestNavigator.kt b/navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/test/SupportingTestNavigator.kt
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/java/androidx/navigation/test/SupportingTestNavigator.kt
rename to navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/test/SupportingTestNavigator.kt
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/test/TestEnum.java b/navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/test/TestEnum.kt
similarity index 86%
rename from navigation/navigation-runtime/src/androidTest/java/androidx/navigation/test/TestEnum.java
rename to navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/test/TestEnum.kt
index f3a5276..11e2eb167 100644
--- a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/test/TestEnum.java
+++ b/navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/test/TestEnum.kt
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-package androidx.navigation.test;
+package androidx.navigation.test
 
-public enum TestEnum {
-    VALUE_ONE, VALUE_TWO
+public enum class TestEnum {
+    VALUE_ONE,
+    VALUE_TWO
 }
diff --git a/navigation/navigation-runtime/src/androidTest/res/navigation/nav_applicationid_arg.xml b/navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_applicationid_arg.xml
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/res/navigation/nav_applicationid_arg.xml
rename to navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_applicationid_arg.xml
diff --git a/navigation/navigation-runtime/src/androidTest/res/navigation/nav_arguments.xml b/navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_arguments.xml
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/res/navigation/nav_arguments.xml
rename to navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_arguments.xml
diff --git a/navigation/navigation-runtime/src/androidTest/res/navigation/nav_deeplink.xml b/navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_deeplink.xml
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/res/navigation/nav_deeplink.xml
rename to navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_deeplink.xml
diff --git a/navigation/navigation-runtime/src/androidTest/res/navigation/nav_default_arguments.xml b/navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_default_arguments.xml
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/res/navigation/nav_default_arguments.xml
rename to navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_default_arguments.xml
diff --git a/navigation/navigation-runtime/src/androidTest/res/navigation/nav_first.xml b/navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_first.xml
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/res/navigation/nav_first.xml
rename to navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_first.xml
diff --git a/navigation/navigation-runtime/src/androidTest/res/navigation/nav_floating.xml b/navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_floating.xml
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/res/navigation/nav_floating.xml
rename to navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_floating.xml
diff --git a/navigation/navigation-runtime/src/androidTest/res/navigation/nav_invalid_argument_arg_type.xml b/navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_invalid_argument_arg_type.xml
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/res/navigation/nav_invalid_argument_arg_type.xml
rename to navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_invalid_argument_arg_type.xml
diff --git a/navigation/navigation-runtime/src/androidTest/res/navigation/nav_invalid_argument_default_value.xml b/navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_invalid_argument_default_value.xml
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/res/navigation/nav_invalid_argument_default_value.xml
rename to navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_invalid_argument_default_value.xml
diff --git a/navigation/navigation-runtime/src/androidTest/res/navigation/nav_invalid_start_destination.xml b/navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_invalid_start_destination.xml
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/res/navigation/nav_invalid_start_destination.xml
rename to navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_invalid_start_destination.xml
diff --git a/navigation/navigation-runtime/src/androidTest/res/navigation/nav_missing_start_destination.xml b/navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_missing_start_destination.xml
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/res/navigation/nav_missing_start_destination.xml
rename to navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_missing_start_destination.xml
diff --git a/navigation/navigation-runtime/src/androidTest/res/navigation/nav_multiple_navigation.xml b/navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_multiple_navigation.xml
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/res/navigation/nav_multiple_navigation.xml
rename to navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_multiple_navigation.xml
diff --git a/navigation/navigation-runtime/src/androidTest/res/navigation/nav_nested_start_destination.xml b/navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_nested_start_destination.xml
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/res/navigation/nav_nested_start_destination.xml
rename to navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_nested_start_destination.xml
diff --git a/navigation/navigation-runtime/src/androidTest/res/navigation/nav_non_start_nest.xml b/navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_non_start_nest.xml
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/res/navigation/nav_non_start_nest.xml
rename to navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_non_start_nest.xml
diff --git a/navigation/navigation-runtime/src/androidTest/res/navigation/nav_root.xml b/navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_root.xml
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/res/navigation/nav_root.xml
rename to navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_root.xml
diff --git a/navigation/navigation-runtime/src/androidTest/res/navigation/nav_second.xml b/navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_second.xml
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/res/navigation/nav_second.xml
rename to navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_second.xml
diff --git a/navigation/navigation-runtime/src/androidTest/res/navigation/nav_simple.xml b/navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_simple.xml
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/res/navigation/nav_simple.xml
rename to navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_simple.xml
diff --git a/navigation/navigation-runtime/src/androidTest/res/navigation/nav_start_destination.xml b/navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_start_destination.xml
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/res/navigation/nav_start_destination.xml
rename to navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_start_destination.xml
diff --git a/navigation/navigation-runtime/src/androidTest/res/values/styles.xml b/navigation/navigation-runtime/src/androidInstrumentedTest/res/values/styles.xml
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/res/values/styles.xml
rename to navigation/navigation-runtime/src/androidInstrumentedTest/res/values/styles.xml
diff --git a/navigation/navigation-runtime/src/androidTest/res/values/values.xml b/navigation/navigation-runtime/src/androidInstrumentedTest/res/values/values.xml
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/res/values/values.xml
rename to navigation/navigation-runtime/src/androidInstrumentedTest/res/values/values.xml
diff --git a/navigation/navigation-runtime/src/main/AndroidManifest.xml b/navigation/navigation-runtime/src/androidMain/AndroidManifest.xml
similarity index 100%
rename from navigation/navigation-runtime/src/main/AndroidManifest.xml
rename to navigation/navigation-runtime/src/androidMain/AndroidManifest.xml
diff --git a/navigation/navigation-runtime/src/main/baseline-prof.txt b/navigation/navigation-runtime/src/androidMain/baseline-prof.txt
similarity index 100%
rename from navigation/navigation-runtime/src/main/baseline-prof.txt
rename to navigation/navigation-runtime/src/androidMain/baseline-prof.txt
diff --git a/navigation/navigation-runtime/src/main/java/androidx/navigation/package-info.java b/navigation/navigation-runtime/src/androidMain/java/androidx/navigation/package-info.java
similarity index 100%
rename from navigation/navigation-runtime/src/main/java/androidx/navigation/package-info.java
rename to navigation/navigation-runtime/src/androidMain/java/androidx/navigation/package-info.java
diff --git a/navigation/navigation-runtime/src/main/java/androidx/navigation/Activity.kt b/navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/Activity.android.kt
similarity index 94%
rename from navigation/navigation-runtime/src/main/java/androidx/navigation/Activity.kt
rename to navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/Activity.android.kt
index 8bf71cd..a0f3b6b 100644
--- a/navigation/navigation-runtime/src/main/java/androidx/navigation/Activity.kt
+++ b/navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/Activity.android.kt
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+@file:JvmName("ActivityKt")
+@file:JvmMultifileClass
+
 package androidx.navigation
 
 import android.app.Activity
diff --git a/navigation/navigation-runtime/src/main/java/androidx/navigation/ActivityNavArgsLazy.kt b/navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/ActivityNavArgsLazy.android.kt
similarity index 95%
rename from navigation/navigation-runtime/src/main/java/androidx/navigation/ActivityNavArgsLazy.kt
rename to navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/ActivityNavArgsLazy.android.kt
index f1d9052..bf50861 100644
--- a/navigation/navigation-runtime/src/main/java/androidx/navigation/ActivityNavArgsLazy.kt
+++ b/navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/ActivityNavArgsLazy.android.kt
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+@file:JvmName("ActivityNavArgsLazyKt")
+@file:JvmMultifileClass
+
 package androidx.navigation
 
 import android.app.Activity
diff --git a/navigation/navigation-runtime/src/main/java/androidx/navigation/ActivityNavigator.kt b/navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/ActivityNavigator.android.kt
similarity index 100%
rename from navigation/navigation-runtime/src/main/java/androidx/navigation/ActivityNavigator.kt
rename to navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/ActivityNavigator.android.kt
diff --git a/navigation/navigation-runtime/src/main/java/androidx/navigation/ActivityNavigatorDestinationBuilder.kt b/navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/ActivityNavigatorDestinationBuilder.android.kt
similarity index 97%
rename from navigation/navigation-runtime/src/main/java/androidx/navigation/ActivityNavigatorDestinationBuilder.kt
rename to navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/ActivityNavigatorDestinationBuilder.android.kt
index 8fdb188..9be7470 100644
--- a/navigation/navigation-runtime/src/main/java/androidx/navigation/ActivityNavigatorDestinationBuilder.kt
+++ b/navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/ActivityNavigatorDestinationBuilder.android.kt
@@ -14,7 +14,8 @@
  * limitations under the License.
  */
 
-@file:Suppress("NOTHING_TO_INLINE")
+@file:JvmName("ActivityNavigatorDestinationBuilderKt")
+@file:JvmMultifileClass
 
 package androidx.navigation
 
diff --git a/navigation/navigation-runtime/src/main/java/androidx/navigation/ActivityNavigatorExtras.kt b/navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/ActivityNavigatorExtras.android.kt
similarity index 94%
rename from navigation/navigation-runtime/src/main/java/androidx/navigation/ActivityNavigatorExtras.kt
rename to navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/ActivityNavigatorExtras.android.kt
index f280a1a..1611117 100644
--- a/navigation/navigation-runtime/src/main/java/androidx/navigation/ActivityNavigatorExtras.kt
+++ b/navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/ActivityNavigatorExtras.android.kt
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+@file:JvmName("ActivityNavigatorExtrasKt")
+@file:JvmMultifileClass
+
 package androidx.navigation
 
 import androidx.core.app.ActivityOptionsCompat
diff --git a/navigation/navigation-runtime/src/main/java/androidx/navigation/NavBackStackEntryState.kt b/navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/NavBackStackEntryState.android.kt
similarity index 100%
rename from navigation/navigation-runtime/src/main/java/androidx/navigation/NavBackStackEntryState.kt
rename to navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/NavBackStackEntryState.android.kt
diff --git a/navigation/navigation-runtime/src/main/java/androidx/navigation/NavController.kt b/navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/NavController.android.kt
similarity index 99%
rename from navigation/navigation-runtime/src/main/java/androidx/navigation/NavController.kt
rename to navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/NavController.android.kt
index 4eed05f..145193d 100644
--- a/navigation/navigation-runtime/src/main/java/androidx/navigation/NavController.kt
+++ b/navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/NavController.android.kt
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+@file:JvmName("NavControllerKt")
+@file:JvmMultifileClass
+
 package androidx.navigation
 
 import android.app.Activity
diff --git a/navigation/navigation-runtime/src/main/java/androidx/navigation/NavControllerViewModel.kt b/navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/NavControllerViewModel.android.kt
similarity index 100%
rename from navigation/navigation-runtime/src/main/java/androidx/navigation/NavControllerViewModel.kt
rename to navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/NavControllerViewModel.android.kt
diff --git a/navigation/navigation-runtime/src/main/java/androidx/navigation/NavDeepLinkBuilder.kt b/navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/NavDeepLinkBuilder.android.kt
similarity index 100%
rename from navigation/navigation-runtime/src/main/java/androidx/navigation/NavDeepLinkBuilder.kt
rename to navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/NavDeepLinkBuilder.android.kt
diff --git a/navigation/navigation-runtime/src/main/java/androidx/navigation/NavHost.kt b/navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/NavHost.android.kt
similarity index 98%
rename from navigation/navigation-runtime/src/main/java/androidx/navigation/NavHost.kt
rename to navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/NavHost.android.kt
index 30024a2..b21b710 100644
--- a/navigation/navigation-runtime/src/main/java/androidx/navigation/NavHost.kt
+++ b/navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/NavHost.android.kt
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+@file:JvmName("NavHostKt")
+@file:JvmMultifileClass
+
 package androidx.navigation
 
 import androidx.annotation.IdRes
diff --git a/navigation/navigation-runtime/src/main/java/androidx/navigation/NavHostController.kt b/navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/NavHostController.android.kt
similarity index 100%
rename from navigation/navigation-runtime/src/main/java/androidx/navigation/NavHostController.kt
rename to navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/NavHostController.android.kt
diff --git a/navigation/navigation-runtime/src/main/java/androidx/navigation/NavInflater.kt b/navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/NavInflater.android.kt
similarity index 100%
rename from navigation/navigation-runtime/src/main/java/androidx/navigation/NavInflater.kt
rename to navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/NavInflater.android.kt
diff --git a/navigation/navigation-runtime/src/main/java/androidx/navigation/Navigation.kt b/navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/Navigation.android.kt
similarity index 100%
rename from navigation/navigation-runtime/src/main/java/androidx/navigation/Navigation.kt
rename to navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/Navigation.android.kt
diff --git a/navigation/navigation-runtime/src/main/java/androidx/navigation/View.kt b/navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/View.android.kt
similarity index 94%
rename from navigation/navigation-runtime/src/main/java/androidx/navigation/View.kt
rename to navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/View.android.kt
index 55db610..c5db4bc 100644
--- a/navigation/navigation-runtime/src/main/java/androidx/navigation/View.kt
+++ b/navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/View.android.kt
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+@file:JvmName("ViewKt")
+@file:JvmMultifileClass
+
 package androidx.navigation
 
 import android.view.View
diff --git a/navigation/navigation-runtime/src/main/res-public/values/public_attrs.xml b/navigation/navigation-runtime/src/androidMain/res-public/values/public_attrs.xml
similarity index 100%
rename from navigation/navigation-runtime/src/main/res-public/values/public_attrs.xml
rename to navigation/navigation-runtime/src/androidMain/res-public/values/public_attrs.xml
diff --git a/navigation/navigation-runtime/src/main/res/values/attrs.xml b/navigation/navigation-runtime/src/androidMain/res/values/attrs.xml
similarity index 100%
rename from navigation/navigation-runtime/src/main/res/values/attrs.xml
rename to navigation/navigation-runtime/src/androidMain/res/values/attrs.xml
diff --git a/navigation/navigation-runtime/src/main/res/values/ids.xml b/navigation/navigation-runtime/src/androidMain/res/values/ids.xml
similarity index 100%
rename from navigation/navigation-runtime/src/main/res/values/ids.xml
rename to navigation/navigation-runtime/src/androidMain/res/values/ids.xml
diff --git a/navigation/navigation-runtime/src/main/java/androidx/navigation/NavDeepLinkSaveStateControl.kt b/navigation/navigation-runtime/src/commonMain/kotlin/androidx/navigation/NavDeepLinkSaveStateControl.kt
similarity index 94%
rename from navigation/navigation-runtime/src/main/java/androidx/navigation/NavDeepLinkSaveStateControl.kt
rename to navigation/navigation-runtime/src/commonMain/kotlin/androidx/navigation/NavDeepLinkSaveStateControl.kt
index 469b038..5e7015f 100644
--- a/navigation/navigation-runtime/src/main/java/androidx/navigation/NavDeepLinkSaveStateControl.kt
+++ b/navigation/navigation-runtime/src/commonMain/kotlin/androidx/navigation/NavDeepLinkSaveStateControl.kt
@@ -16,7 +16,6 @@
 
 package androidx.navigation
 
-/** @see NavController.enableDeepLinkSaveState */
 @Retention(AnnotationRetention.BINARY)
 @Target(AnnotationTarget.FUNCTION)
 @RequiresOptIn(level = RequiresOptIn.Level.WARNING)
diff --git a/navigation3/navigation3/api/current.txt b/navigation3/navigation3/api/current.txt
index 1fe0724..587a03d 100644
--- a/navigation3/navigation3/api/current.txt
+++ b/navigation3/navigation3/api/current.txt
@@ -45,42 +45,44 @@
     method public static inline kotlin.jvm.functions.Function1<java.lang.Object,androidx.navigation3.NavEntry<? extends java.lang.Object?>> entryProvider(optional kotlin.jvm.functions.Function1<java.lang.Object,? extends androidx.navigation3.NavEntry<? extends java.lang.Object?>> fallback, kotlin.jvm.functions.Function1<? super androidx.navigation3.EntryProviderBuilder,kotlin.Unit> builder);
   }
 
+  public final class NavBackStackProviderKt {
+    method @androidx.compose.runtime.Composable public static <T> void NavBackStackProvider(java.util.List<? extends T> backStack, java.util.List<? extends androidx.navigation3.NavLocalProvider> localProviders, kotlin.jvm.functions.Function1<? super T,? extends androidx.navigation3.NavEntry<T>> entryProvider, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.navigation3.NavEntry<T>>,kotlin.Unit> content);
+  }
+
   public final class NavDisplay {
-    method public java.util.Map<java.lang.String,java.lang.Object> isDialog(boolean boolean);
+    method public java.util.Map<java.lang.String,java.lang.Object> popTransition(androidx.compose.animation.EnterTransition? enter, androidx.compose.animation.ExitTransition? exit);
     method public java.util.Map<java.lang.String,java.lang.Object> transition(androidx.compose.animation.EnterTransition? enter, androidx.compose.animation.ExitTransition? exit);
     field public static final androidx.navigation3.NavDisplay INSTANCE;
   }
 
   public final class NavDisplay_androidKt {
-    method @androidx.compose.runtime.Composable public static <T> void NavDisplay(java.util.List<? extends T> backstack, optional androidx.compose.ui.Modifier modifier, optional java.util.List<? extends androidx.navigation3.NavLocalProvider> localProviders, optional androidx.compose.ui.Alignment contentAlignment, optional androidx.compose.animation.SizeTransform? sizeTransform, optional androidx.compose.animation.EnterTransition enterTransition, optional androidx.compose.animation.ExitTransition exitTransition, optional kotlin.jvm.functions.Function0<kotlin.Unit> onBack, kotlin.jvm.functions.Function1<? super T,? extends androidx.navigation3.NavEntry<? extends T>> entryProvider);
+    method @androidx.compose.runtime.Composable public static <T> void NavDisplay(java.util.List<? extends T> backstack, optional androidx.compose.ui.Modifier modifier, optional java.util.List<? extends androidx.navigation3.NavLocalProvider> localProviders, optional androidx.compose.ui.Alignment contentAlignment, optional androidx.compose.animation.SizeTransform? sizeTransform, optional androidx.compose.animation.EnterTransition enterTransition, optional androidx.compose.animation.ExitTransition exitTransition, optional androidx.compose.animation.EnterTransition popEnterTransition, optional androidx.compose.animation.ExitTransition popExitTransition, optional kotlin.jvm.functions.Function0<kotlin.Unit> onBack, kotlin.jvm.functions.Function1<? super T,? extends androidx.navigation3.NavEntry<? extends T>> entryProvider);
   }
 
   public class NavEntry<T> {
     ctor public NavEntry(T key, optional java.util.Map<java.lang.String,?> featureMap, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> content);
-    method public final kotlin.jvm.functions.Function1<T,kotlin.Unit> getContent();
-    method public final java.util.Map<java.lang.String,java.lang.Object> getFeatureMap();
-    method public final T getKey();
-    property public final kotlin.jvm.functions.Function1<T,kotlin.Unit> content;
-    property public final java.util.Map<java.lang.String,java.lang.Object> featureMap;
-    property public final T key;
+    method public kotlin.jvm.functions.Function1<T,kotlin.Unit> getContent();
+    method public java.util.Map<java.lang.String,java.lang.Object> getFeatureMap();
+    method public T getKey();
+    property public kotlin.jvm.functions.Function1<T,kotlin.Unit> content;
+    property public java.util.Map<java.lang.String,java.lang.Object> featureMap;
+    property public T key;
+  }
+
+  public class NavEntryWrapper<T> extends androidx.navigation3.NavEntry<T> {
+    ctor public NavEntryWrapper(androidx.navigation3.NavEntry<T> navEntry);
+    method public final androidx.navigation3.NavEntry<T> getNavEntry();
+    property public kotlin.jvm.functions.Function1<T,kotlin.Unit> content;
+    property public java.util.Map<java.lang.String,java.lang.Object> featureMap;
+    property public T key;
+    property public final androidx.navigation3.NavEntry<T> navEntry;
   }
 
   public interface NavLocalProvider {
-    method @androidx.compose.runtime.Composable public default void ProvideToBackStack(java.util.List<?> backStack);
+    method @androidx.compose.runtime.Composable public default void ProvideToBackStack(java.util.List<?> backStack, kotlin.jvm.functions.Function0<kotlin.Unit> content);
     method @androidx.compose.runtime.Composable public <T> void ProvideToEntry(androidx.navigation3.NavEntry<T> entry);
   }
 
-  public final class NavWrapperManager {
-    ctor public NavWrapperManager();
-    ctor public NavWrapperManager(optional java.util.List<? extends androidx.navigation3.NavLocalProvider> navLocalProviders);
-    method @androidx.compose.runtime.Composable public <T> void ContentForEntry(androidx.navigation3.NavEntry<T> entry);
-    method @androidx.compose.runtime.Composable public void PrepareBackStack(java.util.List<?> backStack);
-  }
-
-  public final class NavWrapperManagerKt {
-    method @androidx.compose.runtime.Composable public static androidx.navigation3.NavWrapperManager rememberNavWrapperManager(java.util.List<? extends androidx.navigation3.NavLocalProvider> navLocalProviders);
-  }
-
   public final class SaveableStateNavLocalProvider implements androidx.navigation3.NavLocalProvider {
     ctor public SaveableStateNavLocalProvider();
     method @androidx.compose.runtime.Composable public <T> void ProvideToEntry(androidx.navigation3.NavEntry<T> entry);
diff --git a/navigation3/navigation3/api/restricted_current.txt b/navigation3/navigation3/api/restricted_current.txt
index 1fe0724..587a03d 100644
--- a/navigation3/navigation3/api/restricted_current.txt
+++ b/navigation3/navigation3/api/restricted_current.txt
@@ -45,42 +45,44 @@
     method public static inline kotlin.jvm.functions.Function1<java.lang.Object,androidx.navigation3.NavEntry<? extends java.lang.Object?>> entryProvider(optional kotlin.jvm.functions.Function1<java.lang.Object,? extends androidx.navigation3.NavEntry<? extends java.lang.Object?>> fallback, kotlin.jvm.functions.Function1<? super androidx.navigation3.EntryProviderBuilder,kotlin.Unit> builder);
   }
 
+  public final class NavBackStackProviderKt {
+    method @androidx.compose.runtime.Composable public static <T> void NavBackStackProvider(java.util.List<? extends T> backStack, java.util.List<? extends androidx.navigation3.NavLocalProvider> localProviders, kotlin.jvm.functions.Function1<? super T,? extends androidx.navigation3.NavEntry<T>> entryProvider, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.navigation3.NavEntry<T>>,kotlin.Unit> content);
+  }
+
   public final class NavDisplay {
-    method public java.util.Map<java.lang.String,java.lang.Object> isDialog(boolean boolean);
+    method public java.util.Map<java.lang.String,java.lang.Object> popTransition(androidx.compose.animation.EnterTransition? enter, androidx.compose.animation.ExitTransition? exit);
     method public java.util.Map<java.lang.String,java.lang.Object> transition(androidx.compose.animation.EnterTransition? enter, androidx.compose.animation.ExitTransition? exit);
     field public static final androidx.navigation3.NavDisplay INSTANCE;
   }
 
   public final class NavDisplay_androidKt {
-    method @androidx.compose.runtime.Composable public static <T> void NavDisplay(java.util.List<? extends T> backstack, optional androidx.compose.ui.Modifier modifier, optional java.util.List<? extends androidx.navigation3.NavLocalProvider> localProviders, optional androidx.compose.ui.Alignment contentAlignment, optional androidx.compose.animation.SizeTransform? sizeTransform, optional androidx.compose.animation.EnterTransition enterTransition, optional androidx.compose.animation.ExitTransition exitTransition, optional kotlin.jvm.functions.Function0<kotlin.Unit> onBack, kotlin.jvm.functions.Function1<? super T,? extends androidx.navigation3.NavEntry<? extends T>> entryProvider);
+    method @androidx.compose.runtime.Composable public static <T> void NavDisplay(java.util.List<? extends T> backstack, optional androidx.compose.ui.Modifier modifier, optional java.util.List<? extends androidx.navigation3.NavLocalProvider> localProviders, optional androidx.compose.ui.Alignment contentAlignment, optional androidx.compose.animation.SizeTransform? sizeTransform, optional androidx.compose.animation.EnterTransition enterTransition, optional androidx.compose.animation.ExitTransition exitTransition, optional androidx.compose.animation.EnterTransition popEnterTransition, optional androidx.compose.animation.ExitTransition popExitTransition, optional kotlin.jvm.functions.Function0<kotlin.Unit> onBack, kotlin.jvm.functions.Function1<? super T,? extends androidx.navigation3.NavEntry<? extends T>> entryProvider);
   }
 
   public class NavEntry<T> {
     ctor public NavEntry(T key, optional java.util.Map<java.lang.String,?> featureMap, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> content);
-    method public final kotlin.jvm.functions.Function1<T,kotlin.Unit> getContent();
-    method public final java.util.Map<java.lang.String,java.lang.Object> getFeatureMap();
-    method public final T getKey();
-    property public final kotlin.jvm.functions.Function1<T,kotlin.Unit> content;
-    property public final java.util.Map<java.lang.String,java.lang.Object> featureMap;
-    property public final T key;
+    method public kotlin.jvm.functions.Function1<T,kotlin.Unit> getContent();
+    method public java.util.Map<java.lang.String,java.lang.Object> getFeatureMap();
+    method public T getKey();
+    property public kotlin.jvm.functions.Function1<T,kotlin.Unit> content;
+    property public java.util.Map<java.lang.String,java.lang.Object> featureMap;
+    property public T key;
+  }
+
+  public class NavEntryWrapper<T> extends androidx.navigation3.NavEntry<T> {
+    ctor public NavEntryWrapper(androidx.navigation3.NavEntry<T> navEntry);
+    method public final androidx.navigation3.NavEntry<T> getNavEntry();
+    property public kotlin.jvm.functions.Function1<T,kotlin.Unit> content;
+    property public java.util.Map<java.lang.String,java.lang.Object> featureMap;
+    property public T key;
+    property public final androidx.navigation3.NavEntry<T> navEntry;
   }
 
   public interface NavLocalProvider {
-    method @androidx.compose.runtime.Composable public default void ProvideToBackStack(java.util.List<?> backStack);
+    method @androidx.compose.runtime.Composable public default void ProvideToBackStack(java.util.List<?> backStack, kotlin.jvm.functions.Function0<kotlin.Unit> content);
     method @androidx.compose.runtime.Composable public <T> void ProvideToEntry(androidx.navigation3.NavEntry<T> entry);
   }
 
-  public final class NavWrapperManager {
-    ctor public NavWrapperManager();
-    ctor public NavWrapperManager(optional java.util.List<? extends androidx.navigation3.NavLocalProvider> navLocalProviders);
-    method @androidx.compose.runtime.Composable public <T> void ContentForEntry(androidx.navigation3.NavEntry<T> entry);
-    method @androidx.compose.runtime.Composable public void PrepareBackStack(java.util.List<?> backStack);
-  }
-
-  public final class NavWrapperManagerKt {
-    method @androidx.compose.runtime.Composable public static androidx.navigation3.NavWrapperManager rememberNavWrapperManager(java.util.List<? extends androidx.navigation3.NavLocalProvider> navLocalProviders);
-  }
-
   public final class SaveableStateNavLocalProvider implements androidx.navigation3.NavLocalProvider {
     ctor public SaveableStateNavLocalProvider();
     method @androidx.compose.runtime.Composable public <T> void ProvideToEntry(androidx.navigation3.NavEntry<T> entry);
diff --git a/navigation3/navigation3/samples/src/main/kotlin/androidx/navigation3/samples/NavDisplaySamples.kt b/navigation3/navigation3/samples/src/main/kotlin/androidx/navigation3/samples/NavDisplaySamples.kt
index d4728e8..64c39b0 100644
--- a/navigation3/navigation3/samples/src/main/kotlin/androidx/navigation3/samples/NavDisplaySamples.kt
+++ b/navigation3/navigation3/samples/src/main/kotlin/androidx/navigation3/samples/NavDisplaySamples.kt
@@ -21,6 +21,8 @@
 import androidx.compose.animation.slideOutHorizontally
 import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
 import androidx.lifecycle.ViewModel
 import androidx.lifecycle.viewmodel.compose.viewModel
 import androidx.lifecycle.viewmodel.navigation3.ViewModelStoreNavLocalProvider
@@ -38,6 +40,7 @@
 @Composable
 fun BaseNav() {
     val backStack = rememberMutableStateListOf(Profile)
+    val showDialog = remember { mutableStateOf(false) }
     NavDisplay(
         backstack = backStack,
         localProviders = listOf(SavedStateNavLocalProvider, ViewModelStoreNavLocalProvider),
@@ -55,8 +58,8 @@
                 ) {
                     Scrollable({ backStack.add(it) }) { backStack.removeLast() }
                 }
-                entry<Dialog>(featureMap = NavDisplay.isDialog(true)) {
-                    DialogContent { backStack.removeLast() }
+                entry<DialogBase> {
+                    DialogBase(onClick = { showDialog.value = true }) { backStack.removeLast() }
                 }
                 entry<Dashboard>(
                     NavDisplay.transition(slideInHorizontally { it }, slideOutHorizontally { it })
@@ -66,4 +69,7 @@
                 }
             }
     )
+    if (showDialog.value) {
+        DialogContent(onDismissRequest = { showDialog.value = false })
+    }
 }
diff --git a/navigation3/navigation3/samples/src/main/kotlin/androidx/navigation3/samples/NavigationSamples.kt b/navigation3/navigation3/samples/src/main/kotlin/androidx/navigation3/samples/NavigationSamples.kt
index 3702017..6a5ec92 100644
--- a/navigation3/navigation3/samples/src/main/kotlin/androidx/navigation3/samples/NavigationSamples.kt
+++ b/navigation3/navigation3/samples/src/main/kotlin/androidx/navigation3/samples/NavigationSamples.kt
@@ -42,6 +42,7 @@
 import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
+import androidx.compose.ui.window.Dialog
 import androidx.savedstate.serialization.decodeFromSavedState
 import androidx.savedstate.serialization.encodeToSavedState
 import kotlinx.serialization.InternalSerializationApi
@@ -66,7 +67,7 @@
 }
 
 @Serializable
-object Dialog {
+object DialogBase {
     val resourceId: Int = R.string.dialog
 }
 
@@ -85,7 +86,7 @@
         Divider(color = Color.Black)
         NavigateButton(stringResource(Scrollable.resourceId)) { navigateTo(Scrollable) }
         Divider(color = Color.Black)
-        NavigateButton(stringResource(Dialog.resourceId)) { navigateTo(Dialog) }
+        NavigateButton(stringResource(DialogBase.resourceId)) { navigateTo(DialogBase) }
         Spacer(Modifier.weight(1f))
         NavigateBackButton(onBack)
     }
@@ -112,13 +113,24 @@
 }
 
 @Composable
-fun DialogContent(onBack: () -> Unit) {
-    val dialogWidth = 300.dp
-    val dialogHeight = 300.dp
-    Column(Modifier.size(dialogWidth, dialogHeight).background(Color.White).padding(8.dp)) {
+fun DialogBase(onClick: () -> Unit, onBack: () -> Unit) {
+    Column(Modifier.fillMaxSize()) {
+        Text(stringResource(R.string.dialog))
+        Button(onClick = onClick) { Text("Show Dialog") }
+        Spacer(Modifier.weight(1f))
         NavigateBackButton(onBack)
-        LazyColumn(modifier = Modifier.weight(1f)) {
-            items(phrases) { phrase -> Text(phrase, fontSize = 16.sp) }
+    }
+}
+
+@Composable
+fun DialogContent(onDismissRequest: () -> Unit) {
+    Dialog(onDismissRequest = onDismissRequest) {
+        val dialogWidth = 300.dp
+        val dialogHeight = 300.dp
+        Column(Modifier.size(dialogWidth, dialogHeight).background(Color.White).padding(8.dp)) {
+            LazyColumn(modifier = Modifier.weight(1f)) {
+                items(phrases) { phrase -> Text(phrase, fontSize = 16.sp) }
+            }
         }
     }
 }
diff --git a/navigation3/navigation3/src/androidInstrumentedTest/kotlin/androidx/navigation3/AnimatedTest.kt b/navigation3/navigation3/src/androidInstrumentedTest/kotlin/androidx/navigation3/AnimatedTest.kt
index 6fb5955..be69875 100644
--- a/navigation3/navigation3/src/androidInstrumentedTest/kotlin/androidx/navigation3/AnimatedTest.kt
+++ b/navigation3/navigation3/src/androidInstrumentedTest/kotlin/androidx/navigation3/AnimatedTest.kt
@@ -138,7 +138,637 @@
         composeTestRule.onNodeWithText(first).assertDoesNotExist()
         composeTestRule.onNodeWithText(second).assertExists()
     }
+
+    @Test
+    fun testPop() {
+        lateinit var backstack: MutableList<Any>
+        val testDuration = DEFAULT_TRANSITION_DURATION_MILLISECOND / 5
+        composeTestRule.setContent {
+            backstack = remember { mutableStateListOf(first, second) }
+            NavDisplay(backstack) {
+                when (it) {
+                    first ->
+                        NavEntry(
+                            first,
+                            featureMap =
+                                NavDisplay.popTransition(
+                                    enter = fadeIn(tween(testDuration)),
+                                    exit = fadeOut(tween(testDuration))
+                                )
+                        ) {
+                            Text(first)
+                        }
+                    second ->
+                        NavEntry(
+                            second,
+                        ) {
+                            Text(second)
+                        }
+                    else -> error("Invalid key passed")
+                }
+            }
+        }
+
+        composeTestRule.waitForIdle()
+        composeTestRule.onNodeWithText(second).assertIsDisplayed()
+        assertThat(backstack).containsExactly(first, second)
+
+        composeTestRule.mainClock.autoAdvance = false
+        composeTestRule.runOnIdle { backstack.removeAt(1) }
+
+        // advance by a duration that is much shorter than the default duration
+        // to ensure that the custom animation is used and has completed after this
+        composeTestRule.mainClock.advanceTimeBy((testDuration * 1.5).toLong())
+
+        composeTestRule.waitForIdle()
+        // pop to first
+        assertThat(backstack).containsExactly(first)
+        composeTestRule.onNodeWithText(first).assertIsDisplayed()
+        composeTestRule.onNodeWithText(second).assertDoesNotExist()
+    }
+
+    @Test
+    fun testPopMultiple() {
+        lateinit var backstack: MutableList<Any>
+        val testDuration = DEFAULT_TRANSITION_DURATION_MILLISECOND / 5
+        composeTestRule.setContent {
+            backstack = remember { mutableStateListOf(first, second, third) }
+            NavDisplay(backstack) {
+                when (it) {
+                    first ->
+                        NavEntry(
+                            first,
+                            featureMap =
+                                NavDisplay.popTransition(
+                                    enter = fadeIn(tween(testDuration)),
+                                    exit = fadeOut(tween(testDuration))
+                                )
+                        ) {
+                            Text(first)
+                        }
+                    second ->
+                        NavEntry(
+                            second,
+                        ) {
+                            Text(second)
+                        }
+                    third ->
+                        NavEntry(
+                            third,
+                        ) {
+                            Text(third)
+                        }
+                    else -> error("Invalid key passed")
+                }
+            }
+        }
+
+        composeTestRule.waitForIdle()
+        composeTestRule.onNodeWithText(third).assertIsDisplayed()
+        assertThat(backstack).containsExactly(first, second, third)
+
+        composeTestRule.mainClock.autoAdvance = false
+        composeTestRule.runOnIdle {
+            backstack.removeAt(2)
+            backstack.removeAt(1)
+        }
+
+        // advance by a duration that is much shorter than the default duration
+        // to ensure that the custom animation is used and has completed after this
+        composeTestRule.mainClock.advanceTimeBy((testDuration * 1.5).toLong())
+
+        composeTestRule.waitForIdle()
+        // pop to first
+        assertThat(backstack).containsExactly(first)
+        composeTestRule.onNodeWithText(first).assertIsDisplayed()
+        composeTestRule.onNodeWithText(second).assertDoesNotExist()
+        composeTestRule.onNodeWithText(third).assertDoesNotExist()
+    }
+
+    @Test
+    fun testPopNavigate() {
+        lateinit var backstack: MutableList<Any>
+        val testDuration = DEFAULT_TRANSITION_DURATION_MILLISECOND / 5
+        composeTestRule.setContent {
+            backstack = remember { mutableStateListOf(first, second) }
+            NavDisplay(backstack) {
+                when (it) {
+                    first ->
+                        NavEntry(
+                            first,
+                        ) {
+                            Text(first)
+                        }
+                    second ->
+                        NavEntry(
+                            second,
+                        ) {
+                            Text(second)
+                        }
+                    third ->
+                        NavEntry(
+                            third,
+                            featureMap =
+                                NavDisplay.transition(
+                                    enter = fadeIn(tween(testDuration)),
+                                    exit = fadeOut(tween(testDuration))
+                                )
+                        ) {
+                            Text(third)
+                        }
+                    else -> error("Invalid key passed")
+                }
+            }
+        }
+
+        composeTestRule.waitForIdle()
+        composeTestRule.onNodeWithText(second).assertIsDisplayed()
+        assertThat(backstack).containsExactly(first, second)
+
+        composeTestRule.mainClock.autoAdvance = false
+        composeTestRule.runOnIdle {
+            backstack.removeAt(1)
+            backstack.add(third)
+        }
+
+        // advance by a duration that is much shorter than the default duration
+        // to ensure that the custom animation is used and has completed after this
+        composeTestRule.mainClock.advanceTimeBy((testDuration * 1.5).toLong())
+        // not pop
+        composeTestRule.waitForIdle()
+        assertThat(backstack).containsExactly(first, third)
+        composeTestRule.onNodeWithText(first).assertDoesNotExist()
+        composeTestRule.onNodeWithText(second).assertDoesNotExist()
+        composeTestRule.onNodeWithText(third).assertIsDisplayed()
+    }
+
+    @Test
+    fun testCentrePop() {
+        lateinit var backstack: MutableList<Any>
+        val testDuration = DEFAULT_TRANSITION_DURATION_MILLISECOND / 5
+        composeTestRule.setContent {
+            backstack = remember { mutableStateListOf(first, second, third) }
+            NavDisplay(backstack) {
+                when (it) {
+                    first ->
+                        NavEntry(
+                            first,
+                        ) {
+                            Text(first)
+                        }
+                    second ->
+                        NavEntry(
+                            second,
+                        ) {
+                            Text(second)
+                        }
+                    third ->
+                        NavEntry(
+                            third,
+                            featureMap =
+                                NavDisplay.transition(
+                                    enter = fadeIn(tween(testDuration)),
+                                    exit = fadeOut(tween(testDuration))
+                                )
+                        ) {
+                            Text(third)
+                        }
+                    else -> error("Invalid key passed")
+                }
+            }
+        }
+
+        composeTestRule.waitForIdle()
+        composeTestRule.onNodeWithText(third).assertIsDisplayed()
+        assertThat(backstack).containsExactly(first, second, third)
+
+        composeTestRule.mainClock.autoAdvance = false
+        composeTestRule.runOnIdle { backstack.removeAt(1) }
+
+        // advance by a duration that is much shorter than the default duration
+        // to ensure that the custom animation is used and has completed after this
+        composeTestRule.mainClock.advanceTimeBy((testDuration * 1.5).toLong())
+        // not pop
+        composeTestRule.waitForIdle()
+        assertThat(backstack).containsExactly(first, third)
+        composeTestRule.onNodeWithText(first).assertDoesNotExist()
+        composeTestRule.onNodeWithText(second).assertDoesNotExist()
+        composeTestRule.onNodeWithText(third).assertIsDisplayed()
+    }
+
+    @Test
+    fun testCentreNavigate() {
+        lateinit var backstack: MutableList<Any>
+        val testDuration = DEFAULT_TRANSITION_DURATION_MILLISECOND / 5
+        composeTestRule.setContent {
+            backstack = remember { mutableStateListOf(first, third) }
+            NavDisplay(backstack) {
+                when (it) {
+                    first ->
+                        NavEntry(
+                            first,
+                        ) {
+                            Text(first)
+                        }
+                    second ->
+                        NavEntry(
+                            second,
+                        ) {
+                            Text(second)
+                        }
+                    third ->
+                        NavEntry(
+                            third,
+                            featureMap =
+                                NavDisplay.transition(
+                                    enter = fadeIn(tween(testDuration)),
+                                    exit = fadeOut(tween(testDuration))
+                                )
+                        ) {
+                            Text(third)
+                        }
+                    else -> error("Invalid key passed")
+                }
+            }
+        }
+
+        composeTestRule.waitForIdle()
+        composeTestRule.onNodeWithText(third).assertIsDisplayed()
+        assertThat(backstack).containsExactly(first, third)
+
+        composeTestRule.mainClock.autoAdvance = false
+        composeTestRule.runOnIdle { backstack.add(1, second) }
+
+        // advance by a duration that is much shorter than the default duration
+        // to ensure that the custom animation is used and has completed after this
+        composeTestRule.mainClock.advanceTimeBy((testDuration * 1.5).toLong())
+        // not pop
+        composeTestRule.waitForIdle()
+        assertThat(backstack).containsExactly(first, second, third)
+        composeTestRule.onNodeWithText(first).assertDoesNotExist()
+        composeTestRule.onNodeWithText(second).assertDoesNotExist()
+        composeTestRule.onNodeWithText(third).assertIsDisplayed()
+    }
+
+    @Test
+    fun testCentrePopAndEndPop() {
+        lateinit var backstack: MutableList<Any>
+        val testDuration = DEFAULT_TRANSITION_DURATION_MILLISECOND / 5
+        composeTestRule.setContent {
+            backstack = remember { mutableStateListOf(first, second, third, fourth) }
+            NavDisplay(backstack) {
+                when (it) {
+                    first ->
+                        NavEntry(
+                            first,
+                        ) {
+                            Text(first)
+                        }
+                    second ->
+                        NavEntry(
+                            second,
+                        ) {
+                            Text(second)
+                        }
+                    third ->
+                        NavEntry(
+                            third,
+                            NavDisplay.transition(
+                                enter = fadeIn(tween(testDuration)),
+                                exit = fadeOut(tween(testDuration))
+                            )
+                        ) {
+                            Text(third)
+                        }
+                    fourth ->
+                        NavEntry(
+                            fourth,
+                        ) {
+                            Text(fourth)
+                        }
+                    else -> error("Invalid key passed")
+                }
+            }
+        }
+
+        composeTestRule.waitForIdle()
+        composeTestRule.onNodeWithText(fourth).assertIsDisplayed()
+        assertThat(backstack).containsExactly(first, second, third, fourth)
+
+        composeTestRule.mainClock.autoAdvance = false
+        composeTestRule.runOnIdle {
+            backstack.removeAt(3)
+            backstack.removeAt(1)
+        }
+
+        // advance by a duration that is much shorter than the default duration
+        // to ensure that the custom animation is used and has completed after this
+        composeTestRule.mainClock.advanceTimeBy((testDuration * 1.5).toLong())
+        // not pop
+        composeTestRule.waitForIdle()
+        assertThat(backstack).containsExactly(first, third)
+        composeTestRule.onNodeWithText(first).assertDoesNotExist()
+        composeTestRule.onNodeWithText(second).assertDoesNotExist()
+        composeTestRule.onNodeWithText(third).assertIsDisplayed()
+        composeTestRule.onNodeWithText(fourth).assertDoesNotExist()
+    }
+
+    @Test
+    fun testCentrePopAndEndNavigate() {
+        lateinit var backstack: MutableList<Any>
+        val testDuration = DEFAULT_TRANSITION_DURATION_MILLISECOND / 5
+        composeTestRule.setContent {
+            backstack = remember { mutableStateListOf(first, second, third) }
+            NavDisplay(backstack) {
+                when (it) {
+                    first ->
+                        NavEntry(
+                            first,
+                        ) {
+                            Text(first)
+                        }
+                    second ->
+                        NavEntry(
+                            second,
+                        ) {
+                            Text(second)
+                        }
+                    third ->
+                        NavEntry(
+                            third,
+                        ) {
+                            Text(third)
+                        }
+                    fourth ->
+                        NavEntry(
+                            fourth,
+                            featureMap =
+                                NavDisplay.transition(
+                                    enter = fadeIn(tween(testDuration)),
+                                    exit = fadeOut(tween(testDuration))
+                                )
+                        ) {
+                            Text(fourth)
+                        }
+                    else -> error("Invalid key passed")
+                }
+            }
+        }
+
+        composeTestRule.waitForIdle()
+        composeTestRule.onNodeWithText(third).assertIsDisplayed()
+        assertThat(backstack).containsExactly(first, second, third)
+
+        composeTestRule.mainClock.autoAdvance = false
+        composeTestRule.runOnIdle {
+            backstack.removeAt(1)
+            backstack.add(fourth)
+        }
+
+        // advance by a duration that is much shorter than the default duration
+        // to ensure that the custom animation is used and has completed after this
+        composeTestRule.mainClock.advanceTimeBy((testDuration * 1.5).toLong())
+
+        composeTestRule.waitForIdle()
+        assertThat(backstack).containsExactly(first, third, fourth)
+        composeTestRule.onNodeWithText(first).assertDoesNotExist()
+        composeTestRule.onNodeWithText(third).assertDoesNotExist()
+        composeTestRule.onNodeWithText(fourth).assertIsDisplayed()
+    }
+
+    @Test
+    fun testCentreNavigateAndEndPop() {
+        lateinit var backstack: MutableList<Any>
+        val testDuration = DEFAULT_TRANSITION_DURATION_MILLISECOND / 5
+        composeTestRule.setContent {
+            backstack = remember { mutableStateListOf(first, third, fourth) }
+            NavDisplay(backstack) {
+                when (it) {
+                    first ->
+                        NavEntry(
+                            first,
+                        ) {
+                            Text(first)
+                        }
+                    second ->
+                        NavEntry(
+                            second,
+                        ) {
+                            Text(second)
+                        }
+                    third ->
+                        NavEntry(
+                            third,
+                            featureMap =
+                                NavDisplay.transition(
+                                    enter = fadeIn(tween(testDuration)),
+                                    exit = fadeOut(tween(testDuration))
+                                )
+                        ) {
+                            Text(third)
+                        }
+                    fourth ->
+                        NavEntry(
+                            fourth,
+                        ) {
+                            Text(fourth)
+                        }
+                    else -> error("Invalid key passed")
+                }
+            }
+        }
+
+        composeTestRule.waitForIdle()
+        composeTestRule.onNodeWithText(fourth).assertIsDisplayed()
+        assertThat(backstack).containsExactly(first, third, fourth)
+        composeTestRule.mainClock.autoAdvance = false
+        composeTestRule.runOnIdle {
+            backstack.removeAt(2)
+            backstack.add(1, second)
+        }
+
+        // advance by a duration that is much shorter than the default duration
+        // to ensure that the custom animation is used and has completed after this
+        composeTestRule.mainClock.advanceTimeBy((testDuration * 1.5).toLong())
+        // not pop
+        composeTestRule.waitForIdle()
+        assertThat(backstack).containsExactly(first, second, third)
+        composeTestRule.onNodeWithText(first).assertDoesNotExist()
+        composeTestRule.onNodeWithText(second).assertDoesNotExist()
+        composeTestRule.onNodeWithText(third).assertIsDisplayed()
+        composeTestRule.onNodeWithText(fourth).assertDoesNotExist()
+    }
+
+    @Test
+    fun testCentreNavigateAndEndNavigate() {
+        lateinit var backstack: MutableList<Any>
+        val testDuration = DEFAULT_TRANSITION_DURATION_MILLISECOND / 5
+        composeTestRule.setContent {
+            backstack = remember { mutableStateListOf(first, third) }
+            NavDisplay(backstack) {
+                when (it) {
+                    first ->
+                        NavEntry(
+                            first,
+                        ) {
+                            Text(first)
+                        }
+                    second ->
+                        NavEntry(
+                            second,
+                        ) {
+                            Text(second)
+                        }
+                    third ->
+                        NavEntry(
+                            third,
+                        ) {
+                            Text(third)
+                        }
+                    fourth ->
+                        NavEntry(
+                            fourth,
+                            NavDisplay.transition(
+                                enter = fadeIn(tween(testDuration)),
+                                exit = fadeOut(tween(testDuration))
+                            )
+                        ) {
+                            Text(fourth)
+                        }
+                    else -> error("Invalid key passed")
+                }
+            }
+        }
+
+        composeTestRule.waitForIdle()
+        composeTestRule.onNodeWithText(third).assertIsDisplayed()
+        assertThat(backstack).containsExactly(first, third)
+
+        composeTestRule.mainClock.autoAdvance = false
+        composeTestRule.runOnIdle {
+            backstack.add(1, second)
+            backstack.add(fourth)
+        }
+
+        // advance by a duration that is much shorter than the default duration
+        // to ensure that the custom animation is used and has completed after this
+        composeTestRule.mainClock.advanceTimeBy((testDuration * 1.5).toLong())
+        // not pop
+        composeTestRule.waitForIdle()
+        assertThat(backstack).containsExactly(first, second, third, fourth)
+        composeTestRule.onNodeWithText(first).assertDoesNotExist()
+        composeTestRule.onNodeWithText(second).assertDoesNotExist()
+        composeTestRule.onNodeWithText(third).assertDoesNotExist()
+        composeTestRule.onNodeWithText(fourth).assertIsDisplayed()
+    }
+
+    @Test
+    fun testSameStack() {
+        lateinit var backstack: MutableList<Any>
+        val testDuration = DEFAULT_TRANSITION_DURATION_MILLISECOND / 5
+        composeTestRule.setContent {
+            backstack = remember { mutableStateListOf(first, second) }
+            NavDisplay(backstack) {
+                when (it) {
+                    first ->
+                        NavEntry(
+                            first,
+                        ) {
+                            Text(first)
+                        }
+                    second ->
+                        NavEntry(
+                            second,
+                            NavDisplay.transition(
+                                enter = fadeIn(tween(testDuration)),
+                                exit = fadeOut(tween(testDuration))
+                            )
+                        ) {
+                            Text(second)
+                        }
+                    else -> error("Invalid key passed")
+                }
+            }
+        }
+
+        composeTestRule.waitForIdle()
+        composeTestRule.onNodeWithText(second).assertIsDisplayed()
+        assertThat(backstack).containsExactly(first, second)
+
+        composeTestRule.mainClock.autoAdvance = false
+        composeTestRule.runOnIdle {
+            backstack.removeAt(1)
+            backstack.add(second)
+        }
+
+        // advance by a duration that is much shorter than the default duration
+        // to ensure that the custom animation is used and has completed after this
+        composeTestRule.mainClock.advanceTimeBy((testDuration * 1.5).toLong())
+        // not pop
+        composeTestRule.waitForIdle()
+        assertThat(backstack).containsExactly(first, second)
+        composeTestRule.onNodeWithText(first).assertDoesNotExist()
+        composeTestRule.onNodeWithText(second).assertIsDisplayed()
+    }
+
+    @Test
+    fun testDuplicateLastEntry() {
+        lateinit var backstack: MutableList<Any>
+        val testDuration = DEFAULT_TRANSITION_DURATION_MILLISECOND / 5
+        composeTestRule.setContent {
+            backstack = remember { mutableStateListOf(first, second, third) }
+            NavDisplay(backstack) {
+                when (it) {
+                    first ->
+                        NavEntry(
+                            first,
+                        ) {
+                            Text(first)
+                        }
+                    second ->
+                        NavEntry(
+                            second,
+                            featureMap =
+                                NavDisplay.transition(
+                                    enter = fadeIn(tween(testDuration)),
+                                    exit = fadeOut(tween(testDuration))
+                                )
+                        ) {
+                            Text(second)
+                        }
+                    third ->
+                        NavEntry(
+                            third,
+                        ) {
+                            Text(third)
+                        }
+                    else -> error("Invalid key passed")
+                }
+            }
+        }
+
+        composeTestRule.waitForIdle()
+        composeTestRule.onNodeWithText(first).assertDoesNotExist()
+        composeTestRule.onNodeWithText(second).assertDoesNotExist()
+        composeTestRule.onNodeWithText(third).assertIsDisplayed()
+        assertThat(backstack).containsExactly(first, second, third)
+
+        composeTestRule.mainClock.autoAdvance = false
+        composeTestRule.runOnIdle { backstack.add(second) }
+
+        // advance by a duration that is much shorter than the default duration
+        // to ensure that the custom animation is used and has completed after this
+        composeTestRule.mainClock.advanceTimeBy((testDuration * 1.5).toLong())
+        // not pop
+        composeTestRule.waitForIdle()
+        assertThat(backstack).containsExactly(first, second, third, second)
+        composeTestRule.onNodeWithText(first).assertDoesNotExist()
+        composeTestRule.onNodeWithText(third).assertDoesNotExist()
+        composeTestRule.onNodeWithText(second).assertIsDisplayed()
+    }
 }
 
 private const val first = "first"
 private const val second = "second"
+private const val third = "third"
+private const val fourth = "fourth"
diff --git a/navigation3/navigation3/src/androidInstrumentedTest/kotlin/androidx/navigation3/NavWrapperManagerTest.kt b/navigation3/navigation3/src/androidInstrumentedTest/kotlin/androidx/navigation3/NavBackStackProviderTest.kt
similarity index 67%
rename from navigation3/navigation3/src/androidInstrumentedTest/kotlin/androidx/navigation3/NavWrapperManagerTest.kt
rename to navigation3/navigation3/src/androidInstrumentedTest/kotlin/androidx/navigation3/NavBackStackProviderTest.kt
index 646df38..6d199e3 100644
--- a/navigation3/navigation3/src/androidInstrumentedTest/kotlin/androidx/navigation3/NavWrapperManagerTest.kt
+++ b/navigation3/navigation3/src/androidInstrumentedTest/kotlin/androidx/navigation3/NavBackStackProviderTest.kt
@@ -27,18 +27,22 @@
 
 @LargeTest
 @RunWith(AndroidJUnit4::class)
-class NavWrapperManagerTest {
+class NavBackStackProviderTest {
     @get:Rule val composeTestRule = createComposeRule()
 
     @Test
     fun callWrapperFunctions() {
         var calledWrapBackStack = false
         var calledWrapContent = false
-        val wrapper =
+        val provider =
             object : NavLocalProvider {
                 @Composable
-                override fun ProvideToBackStack(backStack: List<Any>) {
+                override fun ProvideToBackStack(
+                    backStack: List<Any>,
+                    content: @Composable () -> Unit
+                ) {
                     calledWrapBackStack = true
+                    content.invoke()
                 }
 
                 @Composable
@@ -47,11 +51,14 @@
                 }
             }
 
-        val manager = NavWrapperManager(listOf(wrapper))
-
         composeTestRule.setContent {
-            manager.PrepareBackStack(listOf("something"))
-            manager.ContentForEntry(NavEntry("myKey") {})
+            NavBackStackProvider(
+                backStack = listOf("something"),
+                localProviders = listOf(provider),
+                entryProvider = { NavEntry("something") {} }
+            ) { records ->
+                records.last().content.invoke("something")
+            }
         }
 
         assertThat(calledWrapBackStack).isTrue()
@@ -62,11 +69,15 @@
     fun callWrapperFunctionsOnce() {
         var calledWrapBackStackCount = 0
         var calledWrapContentCount = 0
-        val wrapper =
+        val provider =
             object : NavLocalProvider {
                 @Composable
-                override fun ProvideToBackStack(backStack: List<Any>) {
+                override fun ProvideToBackStack(
+                    backStack: List<Any>,
+                    content: @Composable () -> Unit
+                ) {
                     calledWrapBackStackCount++
+                    content.invoke()
                 }
 
                 @Composable
@@ -75,11 +86,14 @@
                 }
             }
 
-        val manager = NavWrapperManager(listOf(wrapper, wrapper))
-
         composeTestRule.setContent {
-            manager.PrepareBackStack(listOf("something"))
-            manager.ContentForEntry(NavEntry("myKey") {})
+            NavBackStackProvider(
+                backStack = listOf("something"),
+                localProviders = listOf(provider, provider),
+                entryProvider = { NavEntry("something") {} }
+            ) { records ->
+                records.last().content.invoke("something")
+            }
         }
 
         assertThat(calledWrapBackStackCount).isEqualTo(1)
diff --git a/navigation3/navigation3/src/androidInstrumentedTest/kotlin/androidx/navigation3/NavDisplayTest.kt b/navigation3/navigation3/src/androidInstrumentedTest/kotlin/androidx/navigation3/NavDisplayTest.kt
index 614eb88..3342fbf 100644
--- a/navigation3/navigation3/src/androidInstrumentedTest/kotlin/androidx/navigation3/NavDisplayTest.kt
+++ b/navigation3/navigation3/src/androidInstrumentedTest/kotlin/androidx/navigation3/NavDisplayTest.kt
@@ -18,6 +18,7 @@
 
 import androidx.activity.OnBackPressedDispatcher
 import androidx.activity.compose.LocalOnBackPressedDispatcherOwner
+import androidx.compose.material3.Button
 import androidx.compose.material3.Text
 import androidx.compose.runtime.MutableState
 import androidx.compose.runtime.mutableStateListOf
@@ -28,6 +29,8 @@
 import androidx.compose.ui.test.isDisplayed
 import androidx.compose.ui.test.junit4.createComposeRule
 import androidx.compose.ui.test.onNodeWithText
+import androidx.compose.ui.test.performClick
+import androidx.compose.ui.window.Dialog
 import androidx.kruth.assertThat
 import androidx.savedstate.SavedStateRegistry
 import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -78,20 +81,28 @@
     fun testDialog() {
         lateinit var backstack: MutableList<Any>
         composeTestRule.setContent {
+            var showDialog = remember { mutableStateOf(false) }
             backstack = remember { mutableStateListOf(first) }
             NavDisplay(backstack = backstack) {
                 when (it) {
-                    first -> NavEntry(first) { Text(first) }
-                    second -> NavEntry(second, NavDisplay.isDialog(true)) { Text(second) }
+                    first ->
+                        NavEntry(first) {
+                            Button(onClick = { showDialog.value = true }) { Text(first) }
+                        }
                     else -> error("Invalid key passed")
                 }
             }
+            if (showDialog.value) {
+                Dialog(onDismissRequest = {}) { Text(second) }
+            }
         }
 
         assertThat(composeTestRule.onNodeWithText(first).isDisplayed()).isTrue()
 
-        composeTestRule.runOnIdle { backstack.add(second) }
+        composeTestRule.waitForIdle()
+        composeTestRule.onNodeWithText(first).performClick()
 
+        composeTestRule.waitForIdle()
         // Both first and second should be showing if we are on a dialog.
         assertThat(composeTestRule.onNodeWithText(first).isDisplayed()).isTrue()
         assertThat(composeTestRule.onNodeWithText(second).isDisplayed()).isTrue()
diff --git a/navigation3/navigation3/src/androidMain/kotlin/androidx/navigation3/NavDisplay.android.kt b/navigation3/navigation3/src/androidMain/kotlin/androidx/navigation3/NavDisplay.android.kt
index fdc1e24..7f693f6 100644
--- a/navigation3/navigation3/src/androidMain/kotlin/androidx/navigation3/NavDisplay.android.kt
+++ b/navigation3/navigation3/src/androidMain/kotlin/androidx/navigation3/NavDisplay.android.kt
@@ -28,8 +28,11 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
-import androidx.compose.ui.window.Dialog
 import androidx.navigation3.NavDisplay.DEFAULT_TRANSITION_DURATION_MILLISECOND
+import androidx.navigation3.NavDisplay.ENTER_TRANSITION_KEY
+import androidx.navigation3.NavDisplay.EXIT_TRANSITION_KEY
+import androidx.navigation3.NavDisplay.POP_ENTER_TRANSITION_KEY
+import androidx.navigation3.NavDisplay.POP_EXIT_TRANSITION_KEY
 
 /** Object that indicates the features that can be handled by the [NavDisplay] */
 public object NavDisplay {
@@ -42,15 +45,17 @@
         else mapOf(ENTER_TRANSITION_KEY to enter, EXIT_TRANSITION_KEY to exit)
 
     /**
-     * Function to be called on the [NavEntry.featureMap] to notify the [NavDisplay] that the
-     * content should be displayed inside of a [Dialog]
+     * Function to be called on the [NavEntry.featureMap] to notify the [NavDisplay] that, when
+     * popping from backstack, the content should be animated using the provided transitions.
      */
-    public fun isDialog(boolean: Boolean): Map<String, Any> =
-        if (!boolean) emptyMap() else mapOf(DIALOG_KEY to true)
+    public fun popTransition(enter: EnterTransition?, exit: ExitTransition?): Map<String, Any> =
+        if (enter == null || exit == null) emptyMap()
+        else mapOf(POP_ENTER_TRANSITION_KEY to enter, POP_EXIT_TRANSITION_KEY to exit)
 
     internal const val ENTER_TRANSITION_KEY = "enterTransition"
     internal const val EXIT_TRANSITION_KEY = "exitTransition"
-    internal const val DIALOG_KEY = "dialog"
+    internal const val POP_ENTER_TRANSITION_KEY = "popEnterTransition"
+    internal const val POP_EXIT_TRANSITION_KEY = "popExitTransition"
     internal const val DEFAULT_TRANSITION_DURATION_MILLISECOND = 700
 }
 
@@ -58,19 +63,22 @@
  * Display for Composable content that displays a single pane of content at a time, but can move
  * that content in and out with customized transitions.
  *
- * The NavDisplay displays the content associated with the last key on the back stack in most
- * circumstances. If that content wants to be displayed as a dialog, as communicated by adding
- * [NavDisplay.isDialog] to a [NavEntry.featureMap], then the last key's content is a dialog and the
- * second to last key is a displayed in the background.
+ * The NavDisplay displays the content associated with the last key on the back stack.
  *
  * @param backstack the collection of keys that represents the state that needs to be handled
  * @param localProviders list of [NavLocalProvider] to add information to the provided entriess
  * @param modifier the modifier to be applied to the layout.
  * @param contentAlignment The [Alignment] of the [AnimatedContent]
- * @param enterTransition Default [EnterTransition] for all [NavEntry]s. Can be overridden
+ * @param enterTransition Default [EnterTransition] when navigating to [NavEntry]s. Can be
+ *   overridden individually for each [NavEntry] by passing in the entry's transitions through
+ *   [NavEntry.featureMap].
+ * @param exitTransition Default [ExitTransition] when navigating to [NavEntry]s. Can be overridden
  *   individually for each [NavEntry] by passing in the entry's transitions through
  *   [NavEntry.featureMap].
- * @param exitTransition Default [ExitTransition] for all [NavEntry]s. Can be overridden
+ * @param popEnterTransition Default [EnterTransition] when popping [NavEntry]s. Can be overridden
+ *   individually for each [NavEntry] by passing in the entry's transitions through
+ *   [NavEntry.featureMap].
+ * @param popExitTransition Default [ExitTransition] when popping [NavEntry]s. Can be overridden
  *   individually for each [NavEntry] by passing in the entry's transitions through
  *   [NavEntry.featureMap].
  * @param onBack a callback for handling system back presses
@@ -98,55 +106,79 @@
                     DEFAULT_TRANSITION_DURATION_MILLISECOND,
                 )
         ),
+    popEnterTransition: EnterTransition =
+        fadeIn(
+            animationSpec =
+                tween(
+                    DEFAULT_TRANSITION_DURATION_MILLISECOND,
+                )
+        ),
+    popExitTransition: ExitTransition =
+        fadeOut(
+            animationSpec =
+                tween(
+                    DEFAULT_TRANSITION_DURATION_MILLISECOND,
+                )
+        ),
     onBack: () -> Unit = { if (backstack is MutableList) backstack.removeAt(backstack.size - 1) },
     entryProvider: (key: T) -> NavEntry<out T>
 ) {
     require(backstack.isNotEmpty()) { "NavDisplay backstack cannot be empty" }
 
-    val wrapperManager: NavWrapperManager = rememberNavWrapperManager(localProviders)
     BackHandler(backstack.size > 1, onBack)
-    wrapperManager.PrepareBackStack(backStack = backstack)
-    val key = backstack.last()
-    val entry = entryProvider.invoke(key)
+    @Suppress("UNCHECKED_CAST")
+    NavBackStackProvider(backstack, localProviders, entryProvider as (T) -> NavEntry<T>) { entries
+        ->
 
-    // Incoming entry defines transitions, otherwise it uses default transitions from NavDisplay
-    val finalEnterTransition =
-        entry.featureMap[NavDisplay.ENTER_TRANSITION_KEY] as? EnterTransition ?: enterTransition
-    val finalExitTransition =
-        entry.featureMap[NavDisplay.EXIT_TRANSITION_KEY] as? ExitTransition ?: exitTransition
+        // Make a copy shallow copy so that transition.currentState and transition.targetState are
+        // different backstack instances. This ensures currentState reflects the old backstack when
+        // the backstack (targetState) is updated.
+        val newStack = backstack.toList()
+        val entry = entries.last()
 
-    val isDialog = entry.featureMap[NavDisplay.DIALOG_KEY] == true
-
-    // if there is a dialog, we should create a transition with the next to last entry instead.
-    val transition =
-        if (isDialog) {
-            if (backstack.size > 1) {
-                val previousKey = backstack[backstack.size - 2]
-                val previousEntry = entryProvider.invoke(previousKey)
-                updateTransition(targetState = previousEntry, label = previousKey.toString())
+        val transition = updateTransition(targetState = newStack, label = newStack.toString())
+        val isPop = isPop(transition.currentState, newStack)
+        // Incoming entry defines transitions, otherwise it uses default transitions from
+        // NavDisplay
+        val finalEnterTransition =
+            if (isPop) {
+                entry.featureMap[POP_ENTER_TRANSITION_KEY] as? EnterTransition ?: popEnterTransition
             } else {
-                null
+                entry.featureMap[ENTER_TRANSITION_KEY] as? EnterTransition ?: enterTransition
             }
-        } else {
-            updateTransition(targetState = entry, label = key.toString())
+        val finalExitTransition =
+            if (isPop) {
+                entry.featureMap[POP_EXIT_TRANSITION_KEY] as? ExitTransition ?: popExitTransition
+            } else {
+                entry.featureMap[EXIT_TRANSITION_KEY] as? ExitTransition ?: exitTransition
+            }
+        transition.AnimatedContent(
+            modifier = modifier,
+            transitionSpec = {
+                ContentTransform(
+                    targetContentEnter = finalEnterTransition,
+                    initialContentExit = finalExitTransition,
+                    sizeTransform = sizeTransform
+                )
+            },
+            contentAlignment = contentAlignment,
+            contentKey = { it.last() }
+        ) { innerStack ->
+            val lastKey = innerStack.last()
+            entries.findLast { entry -> entry.key == lastKey }?.content?.invoke(lastKey)
         }
-
-    transition?.AnimatedContent(
-        modifier = modifier,
-        transitionSpec = {
-            ContentTransform(
-                targetContentEnter = finalEnterTransition,
-                initialContentExit = finalExitTransition,
-                sizeTransform = sizeTransform
-            )
-        },
-        contentAlignment = contentAlignment,
-        contentKey = { it.key }
-    ) { innerEntry ->
-        wrapperManager.ContentForEntry(innerEntry)
     }
+}
 
-    if (isDialog) {
-        Dialog(onBack) { wrapperManager.ContentForEntry(entry) }
-    }
+private fun <T : Any> isPop(oldBackStack: List<T>, newBackStack: List<T>): Boolean {
+    // entire stack replaced
+    if (oldBackStack.first() != newBackStack.first()) return false
+    // navigated
+    if (newBackStack.size > oldBackStack.size) return false
+
+    val divergingIndex =
+        newBackStack.indices.firstOrNull { index -> newBackStack[index] != oldBackStack[index] }
+    // if newBackStack never diverged from oldBackStack, then it is a clean subset of the oldStack
+    // and is a pop
+    return divergingIndex == null
 }
diff --git a/navigation3/navigation3/src/commonMain/kotlin/androidx/navigation3/NavBackStackProvider.kt b/navigation3/navigation3/src/commonMain/kotlin/androidx/navigation3/NavBackStackProvider.kt
new file mode 100644
index 0000000..5c048b5
--- /dev/null
+++ b/navigation3/navigation3/src/commonMain/kotlin/androidx/navigation3/NavBackStackProvider.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2025 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.navigation3
+
+import androidx.compose.runtime.Composable
+import kotlin.collections.plus
+
+/**
+ * Function that provides all of the [NavEntry]s wrapped with the given [NavLocalProvider]s. It is
+ * responsible for executing the functions provided by each [NavLocalProvider] appropriately.
+ *
+ * Note: the order in which the [NavLocalProvider]s are added to the list determines their scope,
+ * i.e. a [NavLocalProvider] added earlier in a list has its data available to those added later.
+ *
+ * @param backStack the list of keys that represent the backstack
+ * @param localProviders the [NavLocalProvider]s that are providing data to the content
+ * @param entryProvider a function that returns the [NavEntry] for a given key
+ * @param content the content to be displayed
+ */
+@Composable
+public fun <T : Any> NavBackStackProvider(
+    backStack: List<T>,
+    localProviders: List<NavLocalProvider>,
+    entryProvider: (key: T) -> NavEntry<T>,
+    content: @Composable (List<NavEntry<T>>) -> Unit
+) {
+    val finalProviders = (listOf(SaveableStateNavLocalProvider()) + localProviders).distinct()
+
+    // Generates a list of entries that are wrapped with the given providers
+    val entries =
+        backStack.map {
+            val entry = entryProvider.invoke(it)
+            finalProviders.distinct().foldRight(entry) { provider: NavLocalProvider, wrappedEntry ->
+                object : NavEntryWrapper<T>(wrappedEntry) {
+                    override val content: @Composable ((T) -> Unit)
+                        get() = { provider.ProvideToEntry(wrappedEntry) }
+                }
+            }
+        }
+
+    // Provides the entire backstack to the previously wrapped entries
+    finalProviders
+        .distinct()
+        .foldRight<NavLocalProvider, @Composable () -> Unit>({ content(entries) }) {
+            provider: NavLocalProvider,
+            wrappedContent ->
+            { provider.ProvideToBackStack(backStack = backStack, wrappedContent) }
+        }
+        .invoke()
+}
diff --git a/navigation3/navigation3/src/commonMain/kotlin/androidx/navigation3/NavEntry.kt b/navigation3/navigation3/src/commonMain/kotlin/androidx/navigation3/NavEntry.kt
index e8fc674..727f809 100644
--- a/navigation3/navigation3/src/commonMain/kotlin/androidx/navigation3/NavEntry.kt
+++ b/navigation3/navigation3/src/commonMain/kotlin/androidx/navigation3/NavEntry.kt
@@ -27,7 +27,7 @@
  * @param content content for this entry to be displayed when this entry is active
  */
 public open class NavEntry<T : Any>(
-    public val key: T,
-    public val featureMap: Map<String, Any> = emptyMap(),
-    public val content: @Composable (T) -> Unit,
+    public open val key: T,
+    public open val featureMap: Map<String, Any> = emptyMap(),
+    public open val content: @Composable (T) -> Unit
 )
diff --git a/navigation3/navigation3/src/commonMain/kotlin/androidx/navigation3/NavEntryWrapper.kt b/navigation3/navigation3/src/commonMain/kotlin/androidx/navigation3/NavEntryWrapper.kt
new file mode 100644
index 0000000..c24a68e
--- /dev/null
+++ b/navigation3/navigation3/src/commonMain/kotlin/androidx/navigation3/NavEntryWrapper.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2025 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.navigation3
+
+import androidx.compose.runtime.Composable
+
+/**
+ * Class that wraps a [NavEntry] within another [NavEntry].
+ *
+ * This provides a nesting mechanism for [NavEntry]s that allows properly nested content.
+ *
+ * @param navEntry the [NavEntry] to wrap
+ */
+public open class NavEntryWrapper<T : Any>(public val navEntry: NavEntry<T>) :
+    NavEntry<T>(navEntry.key, navEntry.featureMap, navEntry.content) {
+    override val key: T
+        get() = navEntry.key
+
+    override val featureMap: Map<String, Any>
+        get() = navEntry.featureMap
+
+    override val content: @Composable (T) -> Unit
+        get() = navEntry.content
+}
diff --git a/navigation3/navigation3/src/commonMain/kotlin/androidx/navigation3/NavLocalProvider.kt b/navigation3/navigation3/src/commonMain/kotlin/androidx/navigation3/NavLocalProvider.kt
index b3fbeb2..f40365d 100644
--- a/navigation3/navigation3/src/commonMain/kotlin/androidx/navigation3/NavLocalProvider.kt
+++ b/navigation3/navigation3/src/commonMain/kotlin/androidx/navigation3/NavLocalProvider.kt
@@ -32,7 +32,9 @@
      *
      * This function is called by the [NavWrapperManager] and should not be called directly.
      */
-    @Composable public fun ProvideToBackStack(backStack: List<Any>): Unit = Unit
+    @Composable
+    public fun ProvideToBackStack(backStack: List<Any>, content: @Composable () -> Unit): Unit =
+        content.invoke()
 
     /**
      * Allows a [NavLocalProvider] to provide information to a single entry.
diff --git a/navigation3/navigation3/src/commonMain/kotlin/androidx/navigation3/NavWrapperManager.kt b/navigation3/navigation3/src/commonMain/kotlin/androidx/navigation3/NavWrapperManager.kt
deleted file mode 100644
index a994b16..0000000
--- a/navigation3/navigation3/src/commonMain/kotlin/androidx/navigation3/NavWrapperManager.kt
+++ /dev/null
@@ -1,73 +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.navigation3
-
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.remember
-
-/** Creates a [NavLocalProvider]. */
-@Composable
-public fun rememberNavWrapperManager(navLocalProviders: List<NavLocalProvider>): NavWrapperManager {
-    return remember { NavWrapperManager(navLocalProviders) }
-}
-
-/**
- * Class that manages all of the provided [NavLocalProvider]. It is responsible for executing the
- * functions provided by each [NavLocalProvider] appropriately.
- *
- * Note: the order in which the [NavLocalProvider]s are added to the list determines their scope,
- * i.e. a [NavLocalProvider] added earlier in a list has its data available to those added later.
- *
- * @param navLocalProviders the [NavLocalProvider]s that are providing data to the content
- */
-public class NavWrapperManager(navLocalProviders: List<NavLocalProvider> = emptyList()) {
-    /**
-     * Final list of wrappers. This always adds a [SaveableStateNavLocalProvider] by default, as it
-     * is required. It then filters out any duplicates to ensure there is always one instance of any
-     * wrapper at a given time.
-     */
-    private val finalWrappers =
-        (navLocalProviders + listOf(SaveableStateNavLocalProvider())).distinct()
-
-    /**
-     * Calls the [NavLocalProvider.ProvideToBackStack] functions on each wrapper
-     *
-     * This function is called by the [NavDisplay](reference/androidx/navigation/NavDisplay) and
-     * should not be called directly.
-     */
-    @Composable
-    public fun PrepareBackStack(backStack: List<Any>) {
-        finalWrappers.distinct().forEach { it.ProvideToBackStack(backStack = backStack) }
-    }
-
-    /**
-     * Calls the [NavLocalProvider.ProvideToEntry] functions on each wrapper.
-     *
-     * This function is called by the [NavDisplay](reference/androidx/navigation/NavDisplay) and
-     * should not be called directly.
-     */
-    @Composable
-    public fun <T : Any> ContentForEntry(entry: NavEntry<T>) {
-        val key = entry.key
-        finalWrappers
-            .distinct()
-            .foldRight(entry.content) { wrapper, contentLambda ->
-                { wrapper.ProvideToEntry(NavEntry(key, entry.featureMap, content = contentLambda)) }
-            }
-            .invoke(key)
-    }
-}
diff --git a/navigation3/navigation3/src/commonMain/kotlin/androidx/navigation3/SaveableStateNavLocalProvider.kt b/navigation3/navigation3/src/commonMain/kotlin/androidx/navigation3/SaveableStateNavLocalProvider.kt
index 69451da..76d4238 100644
--- a/navigation3/navigation3/src/commonMain/kotlin/androidx/navigation3/SaveableStateNavLocalProvider.kt
+++ b/navigation3/navigation3/src/commonMain/kotlin/androidx/navigation3/SaveableStateNavLocalProvider.kt
@@ -36,7 +36,7 @@
     private var backstackSize = 0
 
     @Composable
-    override fun ProvideToBackStack(backStack: List<Any>) {
+    override fun ProvideToBackStack(backStack: List<Any>, content: @Composable () -> Unit) {
         DisposableEffect(key1 = backStack) {
             refCount.clear()
             onDispose {}
@@ -64,6 +64,7 @@
                 }
             }
         }
+        content.invoke()
     }
 
     @Composable
diff --git a/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/BitmapFetcher.kt b/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/BitmapFetcher.kt
index 8b223f0..f8c0f61 100644
--- a/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/BitmapFetcher.kt
+++ b/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/BitmapFetcher.kt
@@ -24,12 +24,11 @@
 import androidx.annotation.MainThread
 import androidx.annotation.VisibleForTesting
 import androidx.pdf.PdfDocument
+import androidx.pdf.util.RectUtils
 import kotlin.math.roundToInt
-import kotlinx.coroutines.CancellationException
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Job
 import kotlinx.coroutines.ensureActive
-import kotlinx.coroutines.job
 import kotlinx.coroutines.launch
 
 /**
@@ -56,6 +55,7 @@
      */
     private val maxTileBackgroundSizePx = Point(maxBitmapSizePx.x / 2, maxBitmapSizePx.y / 2)
 
+    /** True if this fetcher is ready to fetch bitmaps for the page */
     var isActive: Boolean = false
         set(value) {
             // Debounce setting the field to the same value
@@ -64,41 +64,102 @@
             if (field) onActive() else onInactive()
         }
 
+    /** The bitmaps to draw for this page, as [PageContents] */
     @get:MainThread var pageContents: PageContents? = null
 
+    /** The [PdfDocument.BitmapSource] from which to obtain [Bitmap]s, only used while [isActive] */
     private var bitmapSource: PdfDocument.BitmapSource? = null
-    @VisibleForTesting var currentRenderingScale: Float? = null
-    @VisibleForTesting var renderingJob: Job? = null
 
-    /**
-     * Notify this fetcher that the zoom level / scale factor of the UI has changed, and that it
-     * ought to consider fetching new bitmaps
-     */
-    fun onScaleChanged(scale: Float) {
-        if (!shouldRenderNewBitmaps(scale)) return
+    /** The scale, i.e. zoom level for which we're actively fetching [Bitmap]s */
+    @VisibleForTesting var currentFetchingScale: Float? = null
 
-        currentRenderingScale = scale
-        renderingJob?.cancel()
-        renderingJob =
-            if (needsTiling(scale)) {
-                fetchTiles(scale)
-            } else {
-                fetchNewBitmap(scale)
-            }
-        renderingJob?.invokeOnCompletion { cause ->
-            // We only want to reset these states when we completed naturally
-            if (cause is CancellationException) return@invokeOnCompletion
-            renderingJob = null
-            currentRenderingScale = null
+    /** The [BitmapRequestHandle] for any ongoing fetch */
+    @VisibleForTesting var fetchingWorkHandle: BitmapRequestHandle? = null
+
+    /** Update the view area and scale for which we should be fetching bitmaps */
+    fun updateViewProperties(scale: Float, viewArea: Rect) {
+        // Scale the provided viewArea, and clip it to the scaled bounds of the page
+        // Carefully avoid mutating the provided Rect
+        val scaledViewArea = Rect(viewArea)
+        RectUtils.scale(scaledViewArea, scale)
+        scaledViewArea.intersect(0, 0, (pageSize.x * scale).toInt(), (pageSize.y * scale).toInt())
+        if (shouldFetchNewContents(scale)) {
+            // Scale has changed, fetch entirely new PageContents
+            fetchNewContents(scale, scaledViewArea)
+        } else {
+            // View area has changed, fetch new tiles and discard obsolete ones IFF we're tiling
+            maybeUpdateTiling(scale, scaledViewArea)
         }
     }
 
-    private fun shouldRenderNewBitmaps(scale: Float): Boolean {
-        val renderingAtCurrentScale =
-            currentRenderingScale == scale && renderingJob?.isActive == true
-        val renderedAtCurrentScale = pageContents?.let { it.renderedScale == scale } ?: false
+    /** Discard all bitmaps in the current tiling */
+    fun discardTileBitmaps() {
+        (pageContents as? TileBoard)?.let { for (tile in it.tiles) tile.bitmap = null }
+    }
 
-        return !renderedAtCurrentScale && !renderingAtCurrentScale
+    private fun maybeUpdateTiling(scale: Float, scaledViewArea: Rect) {
+        // Exit early if we're not tiling
+        val currentTileBoard = pageContents as? TileBoard ?: return
+        val currentTilingWork = fetchingWorkHandle as? TileBoardRequestHandle
+        val tileRequests = mutableMapOf<Int, SingleBitmapRequestHandle>()
+        var tileJob: Job? = null
+        for (tile in currentTileBoard.tiles) {
+            val ongoingRequest = currentTilingWork?.tileRequestHandles?.get(tile.index)
+            if (
+                tile.rectPx.intersects(
+                    scaledViewArea.left,
+                    scaledViewArea.top,
+                    scaledViewArea.right,
+                    scaledViewArea.bottom
+                )
+            ) {
+                // Tile is visible, make sure we have, or have requested, a Bitmap for it
+                if (ongoingRequest?.isActive == true) {
+                    // Continue tracking the active request for this tile
+                    tileRequests[tile.index] = ongoingRequest
+                } else if (tile.bitmap == null) {
+                    // Make a new request for this tile
+                    tileJob = fetchBitmap(tile, scale, tileJob)
+                    tileRequests[tile.index] = SingleBitmapRequestHandle(tileJob)
+                }
+            } else {
+                // Tile is no longer visible, cancel any active request and clean up the Bitmap
+                ongoingRequest?.cancel()
+                tile.bitmap = null
+            }
+        }
+        if (tileRequests.isNotEmpty()) {
+            fetchingWorkHandle =
+                TileBoardRequestHandle(tileRequests, currentTilingWork?.backgroundRequestHandle)
+            currentFetchingScale = scale
+        }
+    }
+
+    /**
+     * Notify this fetcher that the zoom level / scale factor of the UI has changed, and that it
+     * ought to fetch new bitmaps
+     */
+    private fun fetchNewContents(scale: Float, scaledViewArea: Rect) {
+        fetchingWorkHandle?.cancel()
+        fetchingWorkHandle =
+            if (needsTiling(scale)) {
+                fetchTiles(scale, scaledViewArea)
+            } else {
+                fetchNewBitmap(scale)
+            }
+        currentFetchingScale = scale
+    }
+
+    /**
+     * Returns true if this fetcher should start fetching a net-new [PageContents], i.e. if the
+     * scaled has changed since we started or finished fetching the previous set of Bitmaps
+     */
+    private fun shouldFetchNewContents(scale: Float): Boolean {
+        val fetchingAtCurrentScale =
+            currentFetchingScale == scale && fetchingWorkHandle?.isActive == true
+        val fetchedAtCurrentScale = pageContents?.let { it.bitmapScale == scale } == true
+
+        return !fetchedAtCurrentScale && !fetchingAtCurrentScale
     }
 
     /** Prepare to start fetching bitmaps */
@@ -111,73 +172,102 @@
      * this fetcher
      */
     private fun onInactive() {
-        currentRenderingScale = null
+        currentFetchingScale = null
         pageContents = null
-        renderingJob?.cancel()
-        renderingJob = null
+        fetchingWorkHandle?.cancel()
+        fetchingWorkHandle = null
         bitmapSource?.close()
         bitmapSource = null
     }
 
     /** Fetch a [FullPageBitmap] */
-    private fun fetchNewBitmap(scale: Float): Job {
-        return backgroundScope.launch {
-            val size = limitBitmapSize(scale, maxBitmapSizePx)
-            // If our BitmapSource is null that means this fetcher is inactive and we should
-            // stop what we're doing
-            val bitmap = bitmapSource?.getBitmap(size) ?: return@launch
-            ensureActive()
-            pageContents = FullPageBitmap(bitmap, scale)
-            onPageUpdate()
-        }
+    private fun fetchNewBitmap(scale: Float): SingleBitmapRequestHandle {
+        val job =
+            backgroundScope.launch {
+                val size = limitBitmapSize(scale, maxBitmapSizePx)
+                // If our BitmapSource is null that means this fetcher is inactive and we should
+                // stop what we're doing
+                val bitmap = bitmapSource?.getBitmap(size) ?: return@launch
+                ensureActive()
+                pageContents = FullPageBitmap(bitmap, scale)
+                onPageUpdate()
+            }
+        return SingleBitmapRequestHandle(job)
     }
 
     /** Fetch a [TileBoard] */
-    private fun fetchTiles(scale: Float): Job {
+    private fun fetchTiles(scale: Float, scaledViewArea: Rect): TileBoardRequestHandle {
         val pageSizePx = Point((pageSize.x * scale).roundToInt(), (pageSize.y * scale).roundToInt())
         val tileBoard = TileBoard(tileSizePx, pageSizePx, scale)
-        // Re-use an existing background bitmap if we have one to avoid unnecessary re-rendering
+        // Re-use an existing background bitmap if we have one to avoid unnecessary re-fetching
         // and jank
-        val prevBackground = (tileBoard as? TileBoard)?.backgroundBitmap
+        val prevBackground = tileBoard.backgroundBitmap
         if (prevBackground != null) {
             tileBoard.backgroundBitmap = prevBackground
             pageContents = tileBoard
             onPageUpdate()
         }
-        return backgroundScope.launch {
-            // Render a new background bitmap if we must
+        val backgroundRequest =
             if (prevBackground == null) {
-                // If our BitmapSource is null that means this fetcher is inactive and we should
-                // stop what we're doing
-                val backgroundSize = limitBitmapSize(scale, maxTileBackgroundSizePx)
-                val bitmap = bitmapSource?.getBitmap(backgroundSize) ?: return@launch
-                pageContents = tileBoard
-                ensureActive()
-                tileBoard.backgroundBitmap = bitmap
-                onPageUpdate()
+                val job =
+                    backgroundScope.launch {
+                        ensureActive()
+                        val backgroundSize = limitBitmapSize(scale, maxTileBackgroundSizePx)
+                        val bitmap = bitmapSource?.getBitmap(backgroundSize) ?: return@launch
+                        pageContents = tileBoard
+                        ensureActive()
+                        tileBoard.backgroundBitmap = bitmap
+                        onPageUpdate()
+                    }
+                SingleBitmapRequestHandle(job)
+            } else {
+                null
             }
-            for (tile in tileBoard.tiles) {
-                renderBitmap(tile, coroutineContext.job, scale)
+        val tileRequests = mutableMapOf<Int, SingleBitmapRequestHandle>()
+        // Used to sequence requests so tiles are loaded left-to-right and top-to-bottom
+        var tileJob: Job? = null
+        for (tile in tileBoard.tiles) {
+            val tileRect = tile.rectPx
+            if (
+                scaledViewArea.intersects(
+                    tileRect.left,
+                    tileRect.top,
+                    tileRect.right,
+                    tileRect.bottom
+                )
+            ) {
+                tileJob = fetchBitmap(tile, scale, tileJob)
+                tileRequests[tile.index] = SingleBitmapRequestHandle(tileJob)
             }
         }
+        return TileBoardRequestHandle(tileRequests.toMap(), backgroundRequest)
     }
 
-    /** Render a [Bitmap] for this [TileBoard.Tile] */
-    private suspend fun renderBitmap(tile: TileBoard.Tile, thisJob: Job, scale: Float) {
-        thisJob.ensureActive()
-        val left = tile.offsetPx.x
-        val top = tile.offsetPx.y
-        val tileRect = Rect(left, top, left + tile.exactSizePx.x, top + tile.exactSizePx.y)
-        // If our BitmapSource is null that means this fetcher is inactive and we should
-        // stop what we're doing
-        val bitmap =
-            bitmapSource?.getBitmap(
-                Size((pageSize.x * scale).roundToInt(), (pageSize.y * scale).roundToInt()),
-                tileRect
-            ) ?: return
-        thisJob.ensureActive()
-        tile.bitmap = bitmap
-        onPageUpdate()
+    /**
+     * Fetch a [Bitmap] for this [TileBoard.Tile]
+     *
+     * @param tile the [TileBoard.Tile] to fetch a bitmap for
+     * @param scale the scale factor of the bitmap
+     * @param prevJob the [Job] that is fetching a bitmap for the tile left or above [tile], i.e. to
+     *   guarantee tiles are loaded left-to-right and top-to-bottom
+     */
+    private fun fetchBitmap(tile: TileBoard.Tile, scale: Float, prevJob: Job?): Job {
+        val job =
+            backgroundScope.launch {
+                prevJob?.join()
+                ensureActive()
+                // If our BitmapSource is null that means this fetcher is inactive and we should
+                // stop what we're doing
+                val bitmap =
+                    bitmapSource?.getBitmap(
+                        Size((pageSize.x * scale).roundToInt(), (pageSize.y * scale).roundToInt()),
+                        tile.rectPx
+                    ) ?: return@launch
+                ensureActive()
+                tile.bitmap = bitmap
+                onPageUpdate()
+            }
+        return job
     }
 
     /** True if the [pageSize] * [scale] exceeds [maxBitmapSizePx] */
@@ -206,13 +296,56 @@
     }
 }
 
+/** Represents a cancellable handle to a request for one or more [Bitmap]s */
+internal sealed interface BitmapRequestHandle {
+    /** True if this request is active */
+    val isActive: Boolean
+
+    /** Cancel this request completely */
+    fun cancel()
+}
+
+/** Cancellable [BitmapRequestHandle] for a single [Bitmap] */
+internal class SingleBitmapRequestHandle(private val job: Job) : BitmapRequestHandle {
+    override val isActive: Boolean
+        get() = job.isActive
+
+    override fun cancel() {
+        job.cancel()
+    }
+}
+
+/**
+ * Cancellable [BitmapRequestHandle] for a full [TileBoard], composing multiple
+ * [SingleBitmapRequestHandle] for the low-res background and each high-res tile
+ */
+internal class TileBoardRequestHandle(
+    /** Map of [TileBoard.Tile.index] to a [BitmapRequestHandle] to fetch that tile's bitmap */
+    val tileRequestHandles: Map<Int, SingleBitmapRequestHandle>,
+    /**
+     * [SingleBitmapRequestHandle] to fetch a low-res background for this tiling, or null if we
+     * re-used the background from a previous tiling
+     */
+    val backgroundRequestHandle: SingleBitmapRequestHandle? = null
+) : BitmapRequestHandle {
+    override val isActive: Boolean
+        get() =
+            tileRequestHandles.values.any { it.isActive } ||
+                backgroundRequestHandle?.isActive == true
+
+    override fun cancel() {
+        tileRequestHandles.values.forEach { it.cancel() }
+        backgroundRequestHandle?.cancel()
+    }
+}
+
 /** Represents the [Bitmap] or [Bitmap]s used to render this page */
 internal sealed interface PageContents {
-    val renderedScale: Float
+    val bitmapScale: Float
 }
 
 /** A singular [Bitmap] depicting the full page, when full page rendering is used */
-internal class FullPageBitmap(val bitmap: Bitmap, override val renderedScale: Float) : PageContents
+internal class FullPageBitmap(val bitmap: Bitmap, override val bitmapScale: Float) : PageContents
 
 /**
  * A set of [Bitmap]s that depict the full page as a rectangular grid of individual bitmap tiles.
@@ -221,7 +354,7 @@
 internal class TileBoard(
     val tileSizePx: Point,
     val pageSizePx: Point,
-    override val renderedScale: Float
+    override val bitmapScale: Float
 ) : PageContents {
 
     /** The low res background [Bitmap] for this [TileBoard] */
@@ -239,7 +372,7 @@
     val tiles = Array(numRows * numCols) { index -> Tile(index) }
 
     /** An individual [Tile] in this [TileBoard] */
-    inner class Tile(index: Int) {
+    inner class Tile(val index: Int) {
         /** The x position of this tile in the tile board */
         private val rowIdx = index / numCols
 
@@ -248,7 +381,7 @@
 
         /**
          * The offset of this [Tile] from the origin of the page in pixels, used in computations
-         * where an exact pixel size is expected, e.g. rendering bitmaps
+         * where an exact pixel size is expected, e.g. fetching bitmaps
          */
         val offsetPx = Point(colIdx * tileSizePx.x, rowIdx * tileSizePx.y)
 
@@ -259,6 +392,10 @@
                 minOf(tileSizePx.y, pageSizePx.y - offsetPx.y),
             )
 
+        /** The exact pixel location of this tile in the scaled page */
+        val rectPx =
+            Rect(offsetPx.x, offsetPx.y, offsetPx.x + exactSizePx.x, offsetPx.y + exactSizePx.y)
+
         /** The high res [Bitmap] for this [Tile] */
         var bitmap: Bitmap? = null
     }
diff --git a/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/Page.kt b/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/Page.kt
index 48d9f6f..5cfabbc 100644
--- a/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/Page.kt
+++ b/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/Page.kt
@@ -39,7 +39,7 @@
     /** The 0-based index of this page in the PDF */
     private val pageNum: Int,
     /** The size of this PDF page, in content coordinates */
-    pageSizePx: Point,
+    pageSize: Point,
     /** The [PdfDocument] this [Page] belongs to */
     private val pdfDocument: PdfDocument,
     /** The [CoroutineScope] to use for background work */
@@ -64,7 +64,7 @@
     private val bitmapFetcher =
         BitmapFetcher(
             pageNum,
-            pageSizePx,
+            pageSize,
             pdfDocument,
             backgroundScope,
             maxBitmapSizePx,
@@ -91,17 +91,34 @@
     internal var links: PdfDocument.PdfPageLinks? = null
         private set
 
-    fun updateState(zoom: Float, isFlinging: Boolean = false) {
+    /**
+     * Puts this page into a "visible" state, and / or updates various properties related to the
+     * page's visible state
+     *
+     * @param zoom the current scale
+     * @param viewArea the portion of the page that's visible, in content coordinates
+     * @param stablePosition true if position is not actively changing, e.g. during a fling
+     */
+    fun setVisible(zoom: Float, viewArea: Rect, stablePosition: Boolean = true) {
         bitmapFetcher.isActive = true
-        bitmapFetcher.onScaleChanged(zoom)
-        if (!isFlinging) {
+        bitmapFetcher.updateViewProperties(zoom, viewArea)
+        if (stablePosition) {
             maybeFetchLinks()
             if (isTouchExplorationEnabled) {
-                fetchPageText()
+                maybeFetchPageText()
             }
         }
     }
 
+    /**
+     * Puts this page into a "nearly visible" state, discarding only high res bitmaps and retaining
+     * lighter weight data in case the page becomes visible again
+     */
+    fun setNearlyVisible() {
+        bitmapFetcher.discardTileBitmaps()
+    }
+
+    /** Puts this page into an "invisible" state, i.e. retaining only the minimum data required */
     fun setInvisible() {
         bitmapFetcher.isActive = false
         pageText = null
@@ -112,7 +129,7 @@
         fetchLinksJob = null
     }
 
-    private fun fetchPageText() {
+    private fun maybeFetchPageText() {
         if (fetchPageTextJob?.isActive == true || pageText != null) return
 
         fetchPageTextJob =
@@ -171,7 +188,7 @@
                 canvas.drawBitmap(
                     bitmap, /* src */
                     null,
-                    locationForTile(tile, tileBoard.renderedScale, locationInView),
+                    locationForTile(tile, tileBoard.bitmapScale, locationInView),
                     BMP_PAINT
                 )
             }
diff --git a/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/PageLayoutManager.kt b/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/PageLayoutManager.kt
index 2844056..90156e5 100644
--- a/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/PageLayoutManager.kt
+++ b/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/PageLayoutManager.kt
@@ -21,6 +21,7 @@
 import android.graphics.Rect
 import android.graphics.RectF
 import android.util.Range
+import android.util.SparseArray
 import androidx.pdf.PdfDocument
 import kotlin.math.ceil
 import kotlin.math.floor
@@ -107,6 +108,30 @@
     }
 
     /**
+     * Returns a [SparseArray] containing [Rect]s indicating the visible region of each visible
+     * page, in page coordinates.
+     */
+    fun getVisiblePageAreas(pages: Range<Int>, viewport: Rect): SparseArray<Rect> {
+        val ret = SparseArray<Rect>(pages.upper - pages.lower + 1)
+        for (i in pages.lower..pages.upper) {
+            ret.put(i, getPageVisibleArea(i, viewport))
+        }
+        return ret
+    }
+
+    private fun getPageVisibleArea(pageNum: Int, viewport: Rect): Rect {
+        val pageLocation = getPageLocation(pageNum, viewport)
+        val pageWidth = pageLocation.right - pageLocation.left
+        val pageHeight = pageLocation.bottom - pageLocation.top
+        return Rect(
+            maxOf(viewport.left - pageLocation.left, 0),
+            maxOf(viewport.top - pageLocation.top, 0),
+            minOf(viewport.right - pageLocation.left, pageWidth),
+            minOf(viewport.bottom - pageLocation.top, pageHeight),
+        )
+    }
+
+    /**
      * Returns the current View-coordinate location of a 0-indexed [pageNum] given the [viewport]
      */
     fun getPageLocation(pageNum: Int, viewport: Rect): Rect {
diff --git a/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/PageManager.kt b/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/PageManager.kt
index 322ee54..e32dbae 100644
--- a/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/PageManager.kt
+++ b/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/PageManager.kt
@@ -78,29 +78,41 @@
     private val highlights: MutableMap<Int, MutableList<Highlight>> = mutableMapOf()
 
     /**
-     * Updates the internal state of [Page]s owned by this manager in response to a viewport change
+     * Updates the visibility state of [Page]s owned by this manager.
+     *
+     * @param visiblePageAreas the visible area of each visible page, in page coordinates
+     * @param currentZoomLevel the current zoom level
+     * @param stablePosition true if we don't believe our position is actively changing
      */
-    fun maybeUpdatePageState(
-        visiblePages: Range<Int>,
+    fun updatePageVisibilities(
+        visiblePageAreas: SparseArray<Rect>,
         currentZoomLevel: Float,
-        isFlinging: Boolean
+        stablePosition: Boolean
     ) {
         // Start preparing UI for visible pages
-        for (i in visiblePages.lower..visiblePages.upper) {
-            pages[i]?.updateState(currentZoomLevel, isFlinging)
+        visiblePageAreas.keyIterator().forEach { pageNum ->
+            pages[pageNum]?.setVisible(
+                currentZoomLevel,
+                visiblePageAreas.get(pageNum),
+                stablePosition
+            )
         }
 
-        // Hide pages that are well outside the viewport. We deliberately don't set pages that
-        // are within nearPages, but outside visible pages to invisible to avoid rendering churn
-        // for pages likely to return to the viewport.
+        // We put pages that are near the viewport in a "nearly visible" state where some data is
+        // retained. We release all data from pages well outside the viewport
         val nearPages =
             Range(
-                maxOf(0, visiblePages.lower - pagePrefetchRadius),
-                minOf(visiblePages.upper + pagePrefetchRadius, pdfDocument.pageCount - 1),
+                maxOf(0, visiblePageAreas.keyAt(0) - pagePrefetchRadius),
+                minOf(
+                    visiblePageAreas.keyAt(visiblePageAreas.size() - 1) + pagePrefetchRadius,
+                    pdfDocument.pageCount - 1
+                ),
             )
         for (pageNum in pages.keyIterator()) {
             if (pageNum < nearPages.lower || pageNum > nearPages.upper) {
                 pages[pageNum]?.setInvisible()
+            } else if (!visiblePageAreas.contains(pageNum)) {
+                pages[pageNum]?.setNearlyVisible()
             }
         }
     }
@@ -109,12 +121,12 @@
      * Updates the set of [Page]s owned by this manager when a new Page's dimensions are loaded.
      * Dimensions are the minimum data required to instantiate a page.
      */
-    fun onPageSizeReceived(
+    fun addPage(
         pageNum: Int,
         size: Point,
-        isVisible: Boolean,
         currentZoomLevel: Float,
-        isFlinging: Boolean
+        stablePosition: Boolean,
+        viewArea: Rect? = null
     ) {
         if (pages.contains(pageNum)) return
         val page =
@@ -128,7 +140,12 @@
                     onPageUpdate = { _invalidationSignalFlow.tryEmit(Unit) },
                     onPageTextReady = { pageNumber -> _pageTextReadyFlow.tryEmit(pageNumber) }
                 )
-                .apply { if (isVisible) updateState(currentZoomLevel, isFlinging) }
+                .apply {
+                    // If the page is visible, let it know
+                    if (viewArea != null) {
+                        setVisible(currentZoomLevel, viewArea, stablePosition)
+                    }
+                }
         pages.put(pageNum, page)
     }
 
@@ -151,7 +168,7 @@
      * Sets all [Page]s owned by this manager to invisible, i.e. to reduce memory when the host
      * [PdfView] is not in an interactive state.
      */
-    fun onDetached() {
+    fun cleanup() {
         for (page in pages.valueIterator()) {
             page.setInvisible()
         }
diff --git a/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/PdfView.kt b/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/PdfView.kt
index 2621d74..8885cb3 100644
--- a/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/PdfView.kt
+++ b/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/PdfView.kt
@@ -40,6 +40,7 @@
 import android.view.ScaleGestureDetector
 import android.view.View
 import androidx.annotation.CallSuper
+import androidx.annotation.MainThread
 import androidx.annotation.RestrictTo
 import androidx.annotation.VisibleForTesting
 import androidx.core.graphics.toRectF
@@ -105,9 +106,9 @@
         set(value) {
             checkMainThread()
             value?.let {
-                val reset = field != null && field?.uri != value.uri
+                if (field == value) return
                 field = it
-                if (reset) reset()
+                reset()
                 onDocumentSet()
             }
         }
@@ -232,6 +233,22 @@
     /** Whether we are in a fling movement. This is used to detect the end of that movement */
     private var isFling = false
 
+    /**
+     * Returns true if neither zoom nor scroll are actively changing. Does not account for
+     * externally-driven changes in position (e.g. a animating scrollY or zoom)
+     */
+    private val positionIsStable: Boolean
+        get() {
+            val zoomIsChanging = gestureTracker.matches(GestureTracker.Gesture.ZOOM)
+            val scrollIsChanging =
+                gestureTracker.matches(
+                    GestureTracker.Gesture.DRAG,
+                    GestureTracker.Gesture.DRAG_X,
+                    GestureTracker.Gesture.DRAG_Y
+                ) || isFling
+            return !zoomIsChanging && !scrollIsChanging
+        }
+
     // To avoid allocations during drawing
     private val visibleAreaRect = Rect()
 
@@ -251,9 +268,6 @@
     @VisibleForTesting
     internal var isTouchExplorationEnabled: Boolean =
         Accessibility.get().isTouchExplorationEnabled(context)
-        set(value) {
-            field = value
-        }
 
     private var selectionStateManager: SelectionStateManager? = null
     private val selectionRenderer = SelectionRenderer(context)
@@ -515,7 +529,7 @@
         super.onDetachedFromWindow()
         stopCollectingData()
         awaitingFirstLayout = true
-        pageManager?.onDetached()
+        pageManager?.cleanup()
     }
 
     override fun onSaveInstanceState(): Parcelable? {
@@ -555,11 +569,11 @@
             postInvalidateOnAnimation()
         } else if (isFling) {
             isFling = false
-            // Once the fling has ended, prompt the page manager to start fetching data for pages
-            // that we don't fetch during a fling
-            pageManager?.maybeUpdatePageState(visiblePages, zoom, isFling)
             // We hide the action mode during a fling, so reveal it when the fling is over
             updateSelectionActionModeVisibility()
+            // Once the fling has ended, prompt the page manager to start fetching data for pages
+            // that we don't fetch during a fling
+            maybeUpdatePageVisibility()
         }
     }
 
@@ -675,6 +689,7 @@
      * Launches a tree of coroutines to collect data from helper classes while we're attached to a
      * visible window
      */
+    @MainThread
     private fun startCollectingData() {
         val mainScope =
             CoroutineScope(HandlerCompat.createAsync(handler.looper).asCoroutineDispatcher())
@@ -688,7 +703,17 @@
                     launch {
                         manager.dimensions.collect { onPageDimensionsReceived(it.first, it.second) }
                     }
-                    launch { manager.visiblePages.collect { onVisiblePagesChanged() } }
+                    launch { manager.visiblePages.collect { maybeUpdatePageVisibility() } }
+                }
+            // Don't let two copies of this run concurrently
+            val visiblePagesToJoin = visiblePagesCollector?.apply { cancel() }
+            visiblePagesCollector =
+                mainScope.launch(start = CoroutineStart.UNDISPATCHED) {
+                    manager.visiblePages.collect {
+                        // Prevent 2 copies from running concurrently
+                        visiblePagesToJoin?.join()
+                        maybeUpdatePageVisibility()
+                    }
                 }
         }
         pageManager?.let { manager ->
@@ -825,13 +850,12 @@
         onViewportChanged()
         // Don't fetch new Bitmaps while the user is actively zooming, to avoid jank and rendering
         // churn
-        if (!gestureTracker.matches(GestureTracker.Gesture.ZOOM)) {
-            pageManager?.maybeUpdatePageState(visiblePages, zoom, isFling)
-        }
+        if (positionIsStable) maybeUpdatePageVisibility()
     }
 
     private fun onViewportChanged() {
         pageLayoutManager?.onViewportChanged(scrollY, height, zoom)
+        if (positionIsStable) maybeUpdatePageVisibility()
         accessibilityPageHelper?.invalidateRoot()
         updateSelectionActionModeVisibility()
     }
@@ -890,18 +914,11 @@
         return RectF(viewport).intersects(leftEdge, topEdge, rightEdge, bottomEdge)
     }
 
-    /**
-     * Invoked by gesture handlers to let this view know that its position has stabilized, i.e. it's
-     * not actively changing due to user input
-     */
-    internal fun onStableZoom() {
-        pageManager?.maybeUpdatePageState(visiblePages, zoom, isFling)
-    }
-
     private fun reset() {
         // Stop any in progress fling when we open a new document
         scroller.forceFinished(true)
         scrollTo(0, 0)
+        pageManager?.cleanup()
         zoom = DEFAULT_INIT_ZOOM
         pageManager = null
         pageLayoutManager = null
@@ -909,20 +926,22 @@
         stopCollectingData()
     }
 
-    /** React to a change in visible pages (load new pages and clean up old ones) */
-    private fun onVisiblePagesChanged() {
-        pageManager?.maybeUpdatePageState(visiblePages, zoom, isFling)
+    private fun maybeUpdatePageVisibility() {
+        val visiblePageAreas =
+            pageLayoutManager?.getVisiblePageAreas(visiblePages, getVisibleAreaInContentCoords())
+                ?: return
+        pageManager?.updatePageVisibilities(visiblePageAreas, zoom, positionIsStable)
     }
 
     /** React to a page's dimensions being made available */
     private fun onPageDimensionsReceived(pageNum: Int, size: Point) {
-        pageManager?.onPageSizeReceived(
-            pageNum,
-            size,
-            visiblePages.contains(pageNum),
-            zoom,
-            isFling
-        )
+        val pageLocation =
+            if (visiblePages.contains(pageNum)) {
+                pageLayoutManager?.getPageLocation(pageNum, getVisibleAreaInContentCoords())
+            } else {
+                null
+            }
+        pageManager?.addPage(pageNum, size, zoom, isFling, pageLocation)
         // Learning the dimensions of a page can change our understanding of the content that's in
         // the viewport
         pageLayoutManager?.onViewportChanged(scrollY, height, zoom)
@@ -1182,7 +1201,9 @@
         }
 
         override fun onGestureEnd(gesture: GestureTracker.Gesture?) {
-            if (gesture == GestureTracker.Gesture.ZOOM) onStableZoom()
+            // Update page visibility after scroll / zoom gestures end, because we avoid fetching
+            // certain data while those gestures are in progress
+            if (gesture in ZOOM_OR_SCROLL_GESTURES) maybeUpdatePageVisibility()
             totalX = 0f
             totalY = 0f
             straightenCurrentVerticalScroll = true
@@ -1390,6 +1411,14 @@
 
         private const val DEFAULT_PAGE_PREFETCH_RADIUS: Int = 2
 
+        private val ZOOM_OR_SCROLL_GESTURES =
+            setOf(
+                GestureTracker.Gesture.ZOOM,
+                GestureTracker.Gesture.DRAG,
+                GestureTracker.Gesture.DRAG_X,
+                GestureTracker.Gesture.DRAG_Y
+            )
+
         private fun checkMainThread() {
             check(Looper.myLooper() == Looper.getMainLooper()) {
                 "Property must be set on the main thread"
diff --git a/pdf/pdf-viewer/src/test/kotlin/androidx/pdf/view/BitmapFetcherTest.kt b/pdf/pdf-viewer/src/test/kotlin/androidx/pdf/view/BitmapFetcherTest.kt
index fc60503..048f51b 100644
--- a/pdf/pdf-viewer/src/test/kotlin/androidx/pdf/view/BitmapFetcherTest.kt
+++ b/pdf/pdf-viewer/src/test/kotlin/androidx/pdf/view/BitmapFetcherTest.kt
@@ -16,7 +16,9 @@
 
 package androidx.pdf.view
 
+import android.graphics.Bitmap
 import android.graphics.Point
+import android.graphics.Rect
 import androidx.pdf.PdfDocument
 import com.google.common.truth.Truth.assertThat
 import kotlin.math.roundToInt
@@ -48,6 +50,7 @@
 
     private val maxBitmapSizePx = Point(2048, 2048)
     private val pageSize = Point(512, 512)
+    private val fullPageViewArea = Rect(0, 0, pageSize.x, pageSize.y)
 
     private lateinit var bitmapFetcher: BitmapFetcher
     private lateinit var tileSizePx: Point
@@ -72,23 +75,23 @@
 
     @Test
     fun setInactive_cancelsWorkAndFreesBitmaps() {
-        bitmapFetcher.onScaleChanged(1.5f)
-        assertThat(bitmapFetcher.renderingJob?.isActive).isTrue()
+        bitmapFetcher.updateViewProperties(1.5f, fullPageViewArea)
+        assertThat(bitmapFetcher.fetchingWorkHandle?.isActive).isTrue()
 
         bitmapFetcher.isActive = false
-        assertThat(bitmapFetcher.renderingJob).isNull()
+        assertThat(bitmapFetcher.fetchingWorkHandle).isNull()
         assertThat(bitmapFetcher.pageContents).isNull()
     }
 
     @Test
-    fun setScale_rendersFullPageBitmap() {
-        bitmapFetcher.onScaleChanged(1.5f)
+    fun lowScale_fullPageViewArea_fetchesFullPageBitmap() {
+        bitmapFetcher.updateViewProperties(1.5f, fullPageViewArea)
 
         testDispatcher.scheduler.runCurrent()
 
         val pageBitmaps = bitmapFetcher.pageContents
         assertThat(pageBitmaps).isInstanceOf(FullPageBitmap::class.java)
-        assertThat(pageBitmaps?.renderedScale).isEqualTo(1.5f)
+        assertThat(pageBitmaps?.bitmapScale).isEqualTo(1.5f)
         pageBitmaps as FullPageBitmap // Make smartcast work nicely below
         assertThat(pageBitmaps.bitmap.width).isEqualTo((pageSize.x * 1.5f).roundToInt())
         assertThat(pageBitmaps.bitmap.height).isEqualTo((pageSize.y * 1.5f).roundToInt())
@@ -96,14 +99,33 @@
     }
 
     @Test
-    fun setScale_rendersTileBoard() {
-        bitmapFetcher.onScaleChanged(5.0f)
+    fun lowScale_partialPageViewArea_fetchesFullPageBitmap() {
+        // 1.5 scale, viewing the lower right half of the page
+        bitmapFetcher.updateViewProperties(
+            1.5f,
+            viewArea = Rect(pageSize.x / 2, pageSize.y / 2, pageSize.x, pageSize.y)
+        )
+
+        testDispatcher.scheduler.runCurrent()
+
+        val pageBitmaps = bitmapFetcher.pageContents
+        assertThat(pageBitmaps).isInstanceOf(FullPageBitmap::class.java)
+        assertThat(pageBitmaps?.bitmapScale).isEqualTo(1.5f)
+        pageBitmaps as FullPageBitmap // Make smartcast work nicely below
+        assertThat(pageBitmaps.bitmap.width).isEqualTo((pageSize.x * 1.5f).roundToInt())
+        assertThat(pageBitmaps.bitmap.height).isEqualTo((pageSize.y * 1.5f).roundToInt())
+        assertThat(invalidationCounter).isEqualTo(1)
+    }
+
+    @Test
+    fun highScale_fullPageViewArea_fetchesTileBoard() {
+        bitmapFetcher.updateViewProperties(5.0f, fullPageViewArea)
 
         testDispatcher.scheduler.runCurrent()
 
         val pageBitmaps = bitmapFetcher.pageContents
         assertThat(pageBitmaps).isInstanceOf(TileBoard::class.java)
-        assertThat(pageBitmaps?.renderedScale).isEqualTo(5.0f)
+        assertThat(pageBitmaps?.bitmapScale).isEqualTo(5.0f)
         pageBitmaps as TileBoard // Make smartcast work nicely below
 
         // Check the properties of an arbitrary full-size tile
@@ -123,21 +145,54 @@
         assertThat(row3Col3.offsetPx).isEqualTo(Point(tileSizePx.x * 3, tileSizePx.y * 3))
         assertThat(row3Col3.exactSizePx).isEqualTo(row3Col3Size)
 
+        for (tile in pageBitmaps.tiles) {
+            assertThat(tile.bitmap).isNotNull()
+        }
+
         // 1 invalidation for the low-res background, 1 for each tile * 16 tiles
         assertThat(invalidationCounter).isEqualTo(17)
     }
 
     @Test
-    fun setScale_toRenderedValue_noNewWork() {
+    fun highScale_partialPageViewArea_fetchesPartialTileBoard() {
+        // 1.5 scale, viewing the lower right half of the page
+        bitmapFetcher.updateViewProperties(
+            5.0f,
+            viewArea = Rect(pageSize.x / 2, pageSize.y / 2, pageSize.x, pageSize.y)
+        )
+
+        testDispatcher.scheduler.runCurrent()
+
+        val pageBitmaps = bitmapFetcher.pageContents
+        assertThat(pageBitmaps).isInstanceOf(TileBoard::class.java)
+        assertThat(pageBitmaps?.bitmapScale).isEqualTo(5.0f)
+        pageBitmaps as TileBoard // Make smartcast work nicely below
+        // This is all tiles in row >= 0 && col >= 0 (row 1 and col 1 are partially visible)
+        val expectedVisibleIndices = setOf(5, 6, 7, 9, 10, 11, 13, 14, 15)
+
+        for (tile in pageBitmaps.tiles) {
+            if (tile.index in expectedVisibleIndices) {
+                assertThat(tile.bitmap).isNotNull()
+            } else {
+                assertThat(tile.bitmap).isNull()
+            }
+        }
+
+        // 1 invalidation for the low-res background, 1 for each visible tile * 9 visible tiles
+        assertThat(invalidationCounter).isEqualTo(10)
+    }
+
+    @Test
+    fun changeScale_toFetchedValue_noNewWork() {
         bitmapFetcher.isActive = true
 
-        bitmapFetcher.onScaleChanged(1.5f)
+        bitmapFetcher.updateViewProperties(1.5f, fullPageViewArea)
         testDispatcher.scheduler.runCurrent()
         val firstBitmaps = bitmapFetcher.pageContents
-        bitmapFetcher.onScaleChanged(1.5f)
+        bitmapFetcher.updateViewProperties(1.5f, fullPageViewArea)
 
         // We shouldn't have started a new Job the second time onScaleChanged to the same value
-        assertThat(bitmapFetcher.renderingJob).isNull()
+        assertThat(bitmapFetcher.fetchingWorkHandle?.isActive).isFalse()
         // And we should still have the same bitmaps
         assertThat(bitmapFetcher.pageContents).isEqualTo(firstBitmaps)
         // 1 total invalidation
@@ -145,20 +200,20 @@
     }
 
     @Test
-    fun setScale_toRenderingValue_noNewWork() {
-        bitmapFetcher.onScaleChanged(1.5f)
-        val firstJob = bitmapFetcher.renderingJob
-        bitmapFetcher.onScaleChanged(1.5f)
+    fun changeScale_toFetchingValue_noNewWork() {
+        bitmapFetcher.updateViewProperties(1.5f, fullPageViewArea)
+        val firstJob = bitmapFetcher.fetchingWorkHandle
+        bitmapFetcher.updateViewProperties(1.5f, fullPageViewArea)
 
         // This should be the same Job we started the first time onScaleChanged
-        assertThat(bitmapFetcher.renderingJob).isEqualTo(firstJob)
+        assertThat(bitmapFetcher.fetchingWorkHandle).isEqualTo(firstJob)
         // 0 invalidations because we're still rendering
         assertThat(invalidationCounter).isEqualTo(0)
     }
 
     @Test
-    fun setScale_afterInactive_rendersNewBitmaps() {
-        bitmapFetcher.onScaleChanged(1.5f)
+    fun changeScale_afterInactive_fetchesNewBitmaps() {
+        bitmapFetcher.updateViewProperties(1.5f, fullPageViewArea)
         testDispatcher.scheduler.runCurrent()
         assertThat(bitmapFetcher.pageContents).isNotNull()
         assertThat(invalidationCounter).isEqualTo(1)
@@ -167,47 +222,106 @@
         assertThat(bitmapFetcher.pageContents).isNull()
 
         bitmapFetcher.isActive = true
-        bitmapFetcher.onScaleChanged(1.5f)
+        bitmapFetcher.updateViewProperties(1.5f, fullPageViewArea)
         testDispatcher.scheduler.runCurrent()
         assertThat(bitmapFetcher.pageContents).isNotNull()
         assertThat(invalidationCounter).isEqualTo(2)
     }
 
     @Test
-    fun setScale_fromFullPage_toTiled() {
-        bitmapFetcher.onScaleChanged(1.5f)
+    fun changeScale_lowToHigh_fullPageToTiling() {
+        bitmapFetcher.updateViewProperties(1.5f, fullPageViewArea)
         testDispatcher.scheduler.runCurrent()
         val fullPageBitmap = bitmapFetcher.pageContents
         assertThat(fullPageBitmap).isInstanceOf(FullPageBitmap::class.java)
-        assertThat(fullPageBitmap?.renderedScale).isEqualTo(1.5f)
+        assertThat(fullPageBitmap?.bitmapScale).isEqualTo(1.5f)
         assertThat(invalidationCounter).isEqualTo(1)
 
-        bitmapFetcher.onScaleChanged(5.0f)
+        bitmapFetcher.updateViewProperties(5.0f, fullPageViewArea)
         testDispatcher.scheduler.runCurrent()
         val tileBoard = bitmapFetcher.pageContents
         assertThat(tileBoard).isInstanceOf(TileBoard::class.java)
-        assertThat(tileBoard?.renderedScale).isEqualTo(5.0f)
+        assertThat(tileBoard?.bitmapScale).isEqualTo(5.0f)
         // 1 invalidation for the previous full page bitmap + 1 for the low res background
         // + (1 for each tile * 16 tiles)
         assertThat(invalidationCounter).isEqualTo(18)
     }
 
     @Test
-    fun setScale_fromTiled_toFullPage() {
-        bitmapFetcher.onScaleChanged(5.0f)
+    fun changeScale_highToLow_tilingToFullPage() {
+        bitmapFetcher.updateViewProperties(5.0f, fullPageViewArea)
         testDispatcher.scheduler.runCurrent()
         val tileBoard = bitmapFetcher.pageContents
         assertThat(tileBoard).isInstanceOf(TileBoard::class.java)
-        assertThat(tileBoard?.renderedScale).isEqualTo(5.0f)
+        assertThat(tileBoard?.bitmapScale).isEqualTo(5.0f)
         // 1 invalidation for the low res background + (1 for each tile * 16 tiles)
         assertThat(invalidationCounter).isEqualTo(17)
 
-        bitmapFetcher.onScaleChanged(1.5f)
+        bitmapFetcher.updateViewProperties(1.5f, fullPageViewArea)
         testDispatcher.scheduler.runCurrent()
         val fullPageBitmap = bitmapFetcher.pageContents
         assertThat(fullPageBitmap).isInstanceOf(FullPageBitmap::class.java)
-        assertThat(fullPageBitmap?.renderedScale).isEqualTo(1.5f)
+        assertThat(fullPageBitmap?.bitmapScale).isEqualTo(1.5f)
         // 1 additional invalidation for the new full page bitmap
         assertThat(invalidationCounter).isEqualTo(18)
     }
+
+    @Test
+    fun changeViewArea_overlapWithPrevious() {
+        // 5.0 scale, viewing the lower right half of the page
+        bitmapFetcher.updateViewProperties(
+            5.0f,
+            Rect(pageSize.x / 2, pageSize.y / 2, pageSize.x, pageSize.y)
+        )
+        testDispatcher.scheduler.runCurrent()
+        val originalTileBoard = bitmapFetcher.pageContents
+        assertThat(originalTileBoard).isInstanceOf(TileBoard::class.java)
+        // This is all tiles in row > 0 && col > 0 (row 1 and col 1 are partially visible)
+        val originalVisibleIndices = setOf(5, 6, 7, 9, 10, 11, 13, 14, 15)
+        val originalBitmaps = mutableMapOf<Int, Bitmap>()
+        for (tile in (originalTileBoard as TileBoard).tiles) {
+            if (tile.index in originalVisibleIndices) {
+                assertThat(tile.bitmap).isNotNull()
+                originalBitmaps[tile.index] = requireNotNull(tile.bitmap)
+            } else {
+                assertThat(tile.bitmap).isNull()
+            }
+        }
+        // 1 invalidation for the low-res background, 1 for each visible tile
+        val originalInvalidations = invalidationCounter
+        assertThat(originalInvalidations).isEqualTo(originalVisibleIndices.size + 1)
+
+        // 5.0 scale, viewing the middle of the page offset by 1/4 of the page's dimensions
+        bitmapFetcher.updateViewProperties(
+            5.0f,
+            Rect(pageSize.x / 4, pageSize.y / 4, pageSize.x * 3 / 4, pageSize.y * 3 / 4)
+        )
+        testDispatcher.scheduler.runCurrent()
+        val newTileBoard = bitmapFetcher.pageContents
+        // We should re-use the previous tile board
+        assertThat(newTileBoard).isEqualTo(originalTileBoard)
+        // This is all tiles in row < 3 and col < 3 (row 0 and 2, col 0 and 2 are partially visible)
+        val newVisibleIndices = setOf(0, 1, 2, 4, 5, 6, 8, 9, 10)
+        // This is all tiles that are visible in both view areas (original and new)
+        val expectedRetainedIndices = originalVisibleIndices.intersect(newVisibleIndices)
+        for (tile in (newTileBoard as TileBoard).tiles) {
+            if (tile.index in expectedRetainedIndices) {
+                // We should have re-used the previous tile Bitmap
+                assertThat(tile.bitmap).isNotNull()
+                assertThat(tile.bitmap).isEqualTo(originalBitmaps[tile.index])
+            } else if (tile.index in newVisibleIndices) {
+                // We should have fetched a new tile Bitmap
+                assertThat(tile.bitmap).isNotNull()
+            } else {
+                // We should have cleaned up the Bitmap
+                assertThat(tile.bitmap).isNull()
+            }
+        }
+
+        // Invalidations before the view area changed + 1 for each *newly* visible tile
+        assertThat(invalidationCounter)
+            .isEqualTo(
+                originalInvalidations + (newVisibleIndices.size - expectedRetainedIndices.size)
+            )
+    }
 }
diff --git a/pdf/pdf-viewer/src/test/kotlin/androidx/pdf/view/PageTest.kt b/pdf/pdf-viewer/src/test/kotlin/androidx/pdf/view/PageTest.kt
index f360178..ad18636 100644
--- a/pdf/pdf-viewer/src/test/kotlin/androidx/pdf/view/PageTest.kt
+++ b/pdf/pdf-viewer/src/test/kotlin/androidx/pdf/view/PageTest.kt
@@ -73,7 +73,7 @@
     private fun createPage(isTouchExplorationEnabled: Boolean): Page {
         return Page(
             0,
-            pageSizePx = PAGE_SIZE,
+            pageSize = PAGE_SIZE,
             pdfDocument,
             testScope,
             MAX_BITMAP_SIZE,
@@ -97,7 +97,7 @@
     fun draw_withoutBitmap() {
         // Notably we don't call testDispatcher.scheduler.runCurrent(), so we start, but do not
         // finish, fetching a Bitmap
-        page.updateState(zoom = 1.5F)
+        page.setVisible(zoom = 1.5F, FULL_PAGE_RECT)
         val locationInView = Rect(-60, 125, -60 + PAGE_SIZE.x, 125 + PAGE_SIZE.y)
 
         page.draw(canvasSpy, locationInView, listOf())
@@ -107,7 +107,7 @@
 
     @Test
     fun draw_withBitmap() {
-        page.updateState(zoom = 1.5F)
+        page.setVisible(zoom = 1.5F, FULL_PAGE_RECT)
         testDispatcher.scheduler.runCurrent()
         val locationInView = Rect(50, -100, 50 + PAGE_SIZE.x, -100 + PAGE_SIZE.y)
 
@@ -127,7 +127,7 @@
 
     @Test
     fun draw_withHighlight() {
-        page.updateState(zoom = 1.5F)
+        page.setVisible(zoom = 1.5F, FULL_PAGE_RECT)
         testDispatcher.scheduler.runCurrent()
         val leftEdgeInView = 650
         val topEdgeInView = -320
@@ -158,7 +158,7 @@
 
     @Test
     fun updateState_withTouchExplorationEnabled_fetchesPageText() {
-        page.updateState(zoom = 1.0f)
+        page.setVisible(zoom = 1.0f, FULL_PAGE_RECT)
         testDispatcher.scheduler.runCurrent()
         assertThat(page.pageText).isEqualTo("SampleText")
         assertThat(pageTextReadyCounter).isEqualTo(1)
@@ -167,7 +167,7 @@
     @Test
     fun setVisible_withTouchExplorationDisabled_doesNotFetchPageText() {
         page = createPage(isTouchExplorationEnabled = false)
-        page.updateState(zoom = 1.0f)
+        page.setVisible(zoom = 1.0f, FULL_PAGE_RECT)
         testDispatcher.scheduler.runCurrent()
 
         assertThat(page.pageText).isEqualTo(null)
@@ -176,20 +176,20 @@
 
     @Test
     fun updateState_doesNotFetchPageTextIfAlreadyFetched() {
-        page.updateState(zoom = 1.0f)
+        page.setVisible(zoom = 1.0f, FULL_PAGE_RECT)
         testDispatcher.scheduler.runCurrent()
         assertThat(page.pageText).isEqualTo("SampleText")
         assertThat(pageTextReadyCounter).isEqualTo(1)
 
-        page.updateState(zoom = 1.0f)
+        page.setVisible(zoom = 1.0f, FULL_PAGE_RECT)
         testDispatcher.scheduler.runCurrent()
         assertThat(page.pageText).isEqualTo("SampleText")
         assertThat(pageTextReadyCounter).isEqualTo(1)
     }
 
     @Test
-    fun setInvisible_cancelsPageTextFetch() {
-        page.updateState(zoom = 1.0f)
+    fun setPageInvisible_cancelsTextFetch() {
+        page.setVisible(zoom = 1.0f, FULL_PAGE_RECT)
         page.setInvisible()
         testDispatcher.scheduler.runCurrent()
         assertThat(page.pageText).isNull()
@@ -198,4 +198,5 @@
 }
 
 val PAGE_SIZE = Point(100, 150)
+val FULL_PAGE_RECT = Rect(0, 0, PAGE_SIZE.x, PAGE_SIZE.y)
 val MAX_BITMAP_SIZE = Point(500, 500)
diff --git a/room/room-common/api/api_lint.ignore b/room/room-common/api/api_lint.ignore
index 0f16720..934672f 100644
--- a/room/room-common/api/api_lint.ignore
+++ b/room/room-common/api/api_lint.ignore
@@ -1,8 +1,4 @@
 // Baseline format: 1.0
-AcronymName: androidx.room.ColumnInfo.SQLiteTypeAffinity:
-    Acronyms should not be capitalized in class names: was `SQLiteTypeAffinity`, should this be `SqLiteTypeAffinity`?
-
-
 GetterSetterNames: androidx.room.ColumnInfo#index:
     Invalid name for boolean property `index`. Should start with one of `has`, `can`, `should`, `is`.
 GetterSetterNames: androidx.room.Database#exportSchema:
diff --git a/room/room-paging/src/androidMain/kotlin/androidx/room/paging/util/RoomPagingUtil.android.kt b/room/room-paging/src/androidMain/kotlin/androidx/room/paging/util/RoomPagingUtil.android.kt
index 35104e8..cd0fa67 100644
--- a/room/room-paging/src/androidMain/kotlin/androidx/room/paging/util/RoomPagingUtil.android.kt
+++ b/room/room-paging/src/androidMain/kotlin/androidx/room/paging/util/RoomPagingUtil.android.kt
@@ -31,7 +31,6 @@
  *
  * Any loaded data or queued loads prior to returning INVALID will be discarded
  */
-@get:Suppress("AcronymName")
 @get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
 public val INVALID: LoadResult<Any, Any> = LoadResult.Invalid<Any, Any>()
 
diff --git a/room/room-runtime/src/androidMain/kotlin/androidx/room/support/QueryInterceptorDatabase.android.kt b/room/room-runtime/src/androidMain/kotlin/androidx/room/support/QueryInterceptorDatabase.android.kt
index 58dce9f..01dc16b 100644
--- a/room/room-runtime/src/androidMain/kotlin/androidx/room/support/QueryInterceptorDatabase.android.kt
+++ b/room/room-runtime/src/androidMain/kotlin/androidx/room/support/QueryInterceptorDatabase.android.kt
@@ -111,17 +111,11 @@
         return delegate.query(query)
     }
 
-    // Suppress warning about `SQL` in execSQL not being camel case. This is an override function
-    // and it can't be renamed.
-    @Suppress("AcronymName")
     override fun execSQL(sql: String) {
         queryCallbackScope.launch { queryCallback.onQuery(sql, emptyList()) }
         delegate.execSQL(sql)
     }
 
-    // Suppress warning about `SQL` in execSQL not being camel case. This is an override function
-    // and it can't be renamed.
-    @Suppress("AcronymName")
     override fun execSQL(sql: String, bindArgs: Array<out Any?>) {
         val argsCopy = bindArgs.toList()
         queryCallbackScope.launch { queryCallback.onQuery(sql, argsCopy) }
diff --git a/room/room-runtime/src/commonMain/kotlin/androidx/room/Transactor.kt b/room/room-runtime/src/commonMain/kotlin/androidx/room/Transactor.kt
index 105f220..7ba38d0 100644
--- a/room/room-runtime/src/commonMain/kotlin/androidx/room/Transactor.kt
+++ b/room/room-runtime/src/commonMain/kotlin/androidx/room/Transactor.kt
@@ -42,7 +42,6 @@
 }
 
 /** Executes a single SQL statement that returns no values. */
-@Suppress("AcronymName") // SQL is a known term and should remain capitalized
 suspend fun PooledConnection.execSQL(sql: String) {
     usePrepared(sql) { it.step() }
 }
@@ -78,7 +77,6 @@
      *
      * @see Transactor.withTransaction
      */
-    @Suppress("AcronymName") // SQL is a known term and should remain capitalized
     enum class SQLiteTransactionType {
         /**
          * The transaction mode that does not start the actual transaction until the database is
diff --git a/savedstate/savedstate/api/current.txt b/savedstate/savedstate/api/current.txt
index 7249870..2c7e9e3d 100644
--- a/savedstate/savedstate/api/current.txt
+++ b/savedstate/savedstate/api/current.txt
@@ -169,10 +169,8 @@
   }
 
   public final class SavedStateRegistryOwnerDelegatesKt {
-    method public static inline <reified T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.savedstate.SavedStateRegistryOwner, String key, kotlin.jvm.functions.Function0<? extends T> init);
-    method public static <T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.savedstate.SavedStateRegistryOwner, String key, kotlinx.serialization.KSerializer<T> serializer, kotlin.jvm.functions.Function0<? extends T> init);
-    method public static inline <reified T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.savedstate.SavedStateRegistryOwner, kotlin.jvm.functions.Function0<? extends T> init);
-    method public static <T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.savedstate.SavedStateRegistryOwner, kotlinx.serialization.KSerializer<T> serializer, kotlin.jvm.functions.Function0<? extends T> init);
+    method public static inline <reified T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.savedstate.SavedStateRegistryOwner, optional String? key, kotlin.jvm.functions.Function0<? extends T> init);
+    method public static <T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.savedstate.SavedStateRegistryOwner, kotlinx.serialization.KSerializer<T> serializer, optional String? key, kotlin.jvm.functions.Function0<? extends T> init);
   }
 
 }
diff --git a/savedstate/savedstate/api/restricted_current.txt b/savedstate/savedstate/api/restricted_current.txt
index c5c3df3..f87e8a6 100644
--- a/savedstate/savedstate/api/restricted_current.txt
+++ b/savedstate/savedstate/api/restricted_current.txt
@@ -194,10 +194,8 @@
   }
 
   public final class SavedStateRegistryOwnerDelegatesKt {
-    method public static inline <reified T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.savedstate.SavedStateRegistryOwner, String key, kotlin.jvm.functions.Function0<? extends T> init);
-    method public static <T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.savedstate.SavedStateRegistryOwner, String key, kotlinx.serialization.KSerializer<T> serializer, kotlin.jvm.functions.Function0<? extends T> init);
-    method public static inline <reified T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.savedstate.SavedStateRegistryOwner, kotlin.jvm.functions.Function0<? extends T> init);
-    method public static <T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.savedstate.SavedStateRegistryOwner, kotlinx.serialization.KSerializer<T> serializer, kotlin.jvm.functions.Function0<? extends T> init);
+    method public static inline <reified T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.savedstate.SavedStateRegistryOwner, optional String? key, kotlin.jvm.functions.Function0<? extends T> init);
+    method public static <T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.savedstate.SavedStateRegistryOwner, kotlinx.serialization.KSerializer<T> serializer, optional String? key, kotlin.jvm.functions.Function0<? extends T> init);
   }
 
 }
diff --git a/savedstate/savedstate/bcv/native/current.txt b/savedstate/savedstate/bcv/native/current.txt
index e96770a..9b72797 100644
--- a/savedstate/savedstate/bcv/native/current.txt
+++ b/savedstate/savedstate/bcv/native/current.txt
@@ -161,15 +161,13 @@
 final const val androidx.savedstate/DEFAULT_LONG // androidx.savedstate/DEFAULT_LONG|{}DEFAULT_LONG[0]
     final fun <get-DEFAULT_LONG>(): kotlin/Long // androidx.savedstate/DEFAULT_LONG.<get-DEFAULT_LONG>|<get-DEFAULT_LONG>(){}[0]
 
-final fun <#A: kotlin/Any> (androidx.savedstate/SavedStateRegistryOwner).androidx.savedstate.serialization/saved(kotlin/String, kotlinx.serialization/KSerializer<#A>, kotlin/Function0<#A>): kotlin.properties/ReadWriteProperty<kotlin/Any?, #A> // androidx.savedstate.serialization/saved|[email protected](kotlin.String;kotlinx.serialization.KSerializer<0:0>;kotlin.Function0<0:0>){0§<kotlin.Any>}[0]
-final fun <#A: kotlin/Any> (androidx.savedstate/SavedStateRegistryOwner).androidx.savedstate.serialization/saved(kotlinx.serialization/KSerializer<#A>, kotlin/Function0<#A>): kotlin.properties/ReadWriteProperty<kotlin/Any?, #A> // androidx.savedstate.serialization/saved|[email protected](kotlinx.serialization.KSerializer<0:0>;kotlin.Function0<0:0>){0§<kotlin.Any>}[0]
+final fun <#A: kotlin/Any> (androidx.savedstate/SavedStateRegistryOwner).androidx.savedstate.serialization/saved(kotlinx.serialization/KSerializer<#A>, kotlin/String? = ..., kotlin/Function0<#A>): kotlin.properties/ReadWriteProperty<kotlin/Any?, #A> // androidx.savedstate.serialization/saved|[email protected](kotlinx.serialization.KSerializer<0:0>;kotlin.String?;kotlin.Function0<0:0>){0§<kotlin.Any>}[0]
 final fun <#A: kotlin/Any> androidx.savedstate.serialization/decodeFromSavedState(kotlinx.serialization/DeserializationStrategy<#A>, androidx.savedstate/SavedState): #A // androidx.savedstate.serialization/decodeFromSavedState|decodeFromSavedState(kotlinx.serialization.DeserializationStrategy<0:0>;androidx.savedstate.SavedState){0§<kotlin.Any>}[0]
 final fun <#A: kotlin/Any> androidx.savedstate.serialization/encodeToSavedState(kotlinx.serialization/SerializationStrategy<#A>, #A): androidx.savedstate/SavedState // androidx.savedstate.serialization/encodeToSavedState|encodeToSavedState(kotlinx.serialization.SerializationStrategy<0:0>;0:0){0§<kotlin.Any>}[0]
 final fun <#A: kotlin/Any?> androidx.savedstate.serialization.serializers/MutableStateFlowSerializer(kotlinx.serialization/KSerializer<#A>): kotlinx.serialization/KSerializer<kotlinx.coroutines.flow/MutableStateFlow<#A>> // androidx.savedstate.serialization.serializers/MutableStateFlowSerializer|MutableStateFlowSerializer(kotlinx.serialization.KSerializer<0:0>){0§<kotlin.Any?>}[0]
 final inline fun <#A: kotlin/Any?> (androidx.savedstate/SavedState).androidx.savedstate/read(kotlin/Function1<androidx.savedstate/SavedStateReader, #A>): #A // androidx.savedstate/read|[email protected](kotlin.Function1<androidx.savedstate.SavedStateReader,0:0>){0§<kotlin.Any?>}[0]
 final inline fun <#A: kotlin/Any?> (androidx.savedstate/SavedState).androidx.savedstate/write(kotlin/Function1<androidx.savedstate/SavedStateWriter, #A>): #A // androidx.savedstate/write|[email protected](kotlin.Function1<androidx.savedstate.SavedStateWriter,0:0>){0§<kotlin.Any?>}[0]
-final inline fun <#A: reified kotlin/Any> (androidx.savedstate/SavedStateRegistryOwner).androidx.savedstate.serialization/saved(kotlin/String, noinline kotlin/Function0<#A>): kotlin.properties/ReadWriteProperty<kotlin/Any?, #A> // androidx.savedstate.serialization/saved|[email protected](kotlin.String;kotlin.Function0<0:0>){0§<kotlin.Any>}[0]
-final inline fun <#A: reified kotlin/Any> (androidx.savedstate/SavedStateRegistryOwner).androidx.savedstate.serialization/saved(noinline kotlin/Function0<#A>): kotlin.properties/ReadWriteProperty<kotlin/Any?, #A> // androidx.savedstate.serialization/saved|[email protected](kotlin.Function0<0:0>){0§<kotlin.Any>}[0]
+final inline fun <#A: reified kotlin/Any> (androidx.savedstate/SavedStateRegistryOwner).androidx.savedstate.serialization/saved(kotlin/String? = ..., noinline kotlin/Function0<#A>): kotlin.properties/ReadWriteProperty<kotlin/Any?, #A> // androidx.savedstate.serialization/saved|[email protected](kotlin.String?;kotlin.Function0<0:0>){0§<kotlin.Any>}[0]
 final inline fun <#A: reified kotlin/Any> androidx.savedstate.serialization/decodeFromSavedState(androidx.savedstate/SavedState): #A // androidx.savedstate.serialization/decodeFromSavedState|decodeFromSavedState(androidx.savedstate.SavedState){0§<kotlin.Any>}[0]
 final inline fun <#A: reified kotlin/Any> androidx.savedstate.serialization/encodeToSavedState(#A): androidx.savedstate/SavedState // androidx.savedstate.serialization/encodeToSavedState|encodeToSavedState(0:0){0§<kotlin.Any>}[0]
 final inline fun <#A: reified kotlin/Any?> androidx.savedstate.serialization.serializers/MutableStateFlowSerializer(): kotlinx.serialization/KSerializer<kotlinx.coroutines.flow/MutableStateFlow<#A>> // androidx.savedstate.serialization.serializers/MutableStateFlowSerializer|MutableStateFlowSerializer(){0§<kotlin.Any?>}[0]
diff --git a/savedstate/savedstate/src/commonMain/kotlin/androidx/savedstate/serialization/SavedStateRegistryOwnerDelegates.kt b/savedstate/savedstate/src/commonMain/kotlin/androidx/savedstate/serialization/SavedStateRegistryOwnerDelegates.kt
index a890db3..c11359f 100644
--- a/savedstate/savedstate/src/commonMain/kotlin/androidx/savedstate/serialization/SavedStateRegistryOwnerDelegates.kt
+++ b/savedstate/savedstate/src/commonMain/kotlin/androidx/savedstate/serialization/SavedStateRegistryOwnerDelegates.kt
@@ -28,16 +28,17 @@
  * within the [SavedStateRegistry] of this [SavedStateRegistryOwner].
  *
  * @sample androidx.savedstate.serialization.savedStateRegistryOwner_saved_withKey_withSerializer
- * @param key The [String] key to use for storing the value in the [SavedStateRegistry].
  * @param serializer The [KSerializer] to use for serializing and deserializing the value.
+ * @param key An optional [String] key to use for storing the value in the [SavedStateRegistry]. A
+ *   default key will be generated if it's omitted or when 'null' is passed.
  * @param init The function to provide the initial value of the property.
  * @return A property delegate provider that manages the saving and restoring of the value.
  * @see encodeToSavedState
  * @see decodeFromSavedState
  */
 public fun <T : Any> SavedStateRegistryOwner.saved(
-    key: String,
     serializer: KSerializer<T>,
+    key: String? = null,
     init: () -> T,
 ): ReadWriteProperty<Any?, T> {
     return SavedStateRegistryOwnerDelegate(
@@ -52,34 +53,9 @@
  * Returns a property delegate provider that manages the saving and restoring of a value of type [T]
  * within the [SavedStateRegistry] of this [SavedStateRegistryOwner].
  *
- * This is a convenience overload that uses the name of the property as the key for storing the
- * value in the [SavedStateRegistry]
- *
- * @sample androidx.savedstate.serialization.savedStateRegistryOwner_saved_withSerializer
- * @param serializer The [KSerializer] to use for serializing and deserializing the value.
- * @param init The function to provide the initial value of the property.
- * @return A property delegate provider that manages the saving and restoring of the value.
- * @see encodeToSavedState
- * @see decodeFromSavedState
- */
-public fun <T : Any> SavedStateRegistryOwner.saved(
-    serializer: KSerializer<T>,
-    init: () -> T,
-): ReadWriteProperty<Any?, T> {
-    return SavedStateRegistryOwnerDelegate(
-        registry = savedStateRegistry,
-        key = null,
-        serializer = serializer,
-        init = init
-    )
-}
-
-/**
- * Returns a property delegate provider that manages the saving and restoring of a value of type [T]
- * within the [SavedStateRegistry] of this [SavedStateRegistryOwner].
- *
  * @sample androidx.savedstate.serialization.savedStateRegistryOwner_saved_withKey
- * @param key The [String] key to use for storing the value in the [SavedStateRegistry].
+ * @param key An optional [String] key to use for storing the value in the [SavedStateRegistry]. A
+ *   default key will be generated if it's omitted or when 'null' is passed.
  * @param init The function to provide the initial value of the property.
  * @return A property delegate provider that manages the saving and restoring of the value.
  * @see encodeToSavedState
@@ -87,30 +63,9 @@
  * @see serializer
  */
 public inline fun <reified T : Any> SavedStateRegistryOwner.saved(
-    key: String,
+    key: String? = null,
     noinline init: () -> T,
-): ReadWriteProperty<Any?, T> = saved(key = key, serializer = serializer(), init = init)
-
-/**
- * Returns a property delegate provider that manages the saving and restoring of a value of type [T]
- * within the [SavedStateRegistry] of this [SavedStateRegistryOwner].
- *
- * This is a convenience overload that uses the [serializer] function to obtain the serializer for
- * the reified type [T].
- *
- * The name of the property will be used as the key for storing the value in the
- * [SavedStateRegistry].
- *
- * @sample androidx.savedstate.serialization.savedStateRegistryOwner_saved
- * @param init The function to provide the initial value of the property.
- * @return A property delegate provider that manages the saving and restoring of the value.
- * @see encodeToSavedState
- * @see decodeFromSavedState
- * @see serializer
- */
-public inline fun <reified T : Any> SavedStateRegistryOwner.saved(
-    noinline init: () -> T,
-): ReadWriteProperty<Any?, T> = saved(serializer = serializer(), init = init)
+): ReadWriteProperty<Any?, T> = saved(serializer = serializer(), key = key, init = init)
 
 private class SavedStateRegistryOwnerDelegate<T : Any>(
     private val registry: SavedStateRegistry,
diff --git a/settings.gradle b/settings.gradle
index cf922fc..6597c4d 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -33,7 +33,7 @@
         if (agpOverride != null) {
             classpath("com.android.settings:com.android.settings.gradle.plugin:$agpOverride")
         } else {
-            classpath("com.android.settings:com.android.settings.gradle.plugin:8.9.0-alpha01")
+            classpath("com.android.settings:com.android.settings.gradle.plugin:8.9.0-beta01")
         }
         // set guava version to be compatible with Depdendency analysis gradle plugin
         classpath("com.google.guava:guava:33.3.1-jre")
diff --git a/slidingpanelayout/slidingpanelayout/api/current.txt b/slidingpanelayout/slidingpanelayout/api/current.txt
index 072d9d3..6090e13 100644
--- a/slidingpanelayout/slidingpanelayout/api/current.txt
+++ b/slidingpanelayout/slidingpanelayout/api/current.txt
@@ -13,6 +13,7 @@
     method public boolean closePane();
     method @Deprecated @ColorInt public int getCoveredFadeColor();
     method public final int getLockMode();
+    method @Px public final int getPaneSpacing();
     method @Px public int getParallaxDistance();
     method @Deprecated @ColorInt public int getSliderFadeColor();
     method public final int getSplitDividerPosition();
@@ -33,6 +34,7 @@
     method public final void setLockMode(int);
     method public final void setOnUserResizingDividerClickListener(android.view.View.OnClickListener? listener);
     method public final void setOverlappingEnabled(boolean);
+    method public final void setPaneSpacing(int);
     method @Deprecated public void setPanelSlideListener(androidx.slidingpanelayout.widget.SlidingPaneLayout.PanelSlideListener? listener);
     method public void setParallaxDistance(@Px int);
     method @Deprecated public void setShadowDrawable(android.graphics.drawable.Drawable? drawable);
@@ -58,6 +60,7 @@
     property public final boolean isUserResizable;
     property public final boolean isUserResizingEnabled;
     property public final int lockMode;
+    property @Px public final int paneSpacing;
     property @Px public int parallaxDistance;
     property @Deprecated @ColorInt public int sliderFadeColor;
     property public final int splitDividerPosition;
diff --git a/slidingpanelayout/slidingpanelayout/api/res-current.txt b/slidingpanelayout/slidingpanelayout/api/res-current.txt
index 88c866a..6da1d9a 100644
--- a/slidingpanelayout/slidingpanelayout/api/res-current.txt
+++ b/slidingpanelayout/slidingpanelayout/api/res-current.txt
@@ -1,6 +1,7 @@
 attr isChildClippingToResizeDividerEnabled
 attr isOverlappingEnabled
 attr isUserResizingEnabled
+attr paneSpacing
 attr userResizeBehavior
 attr userResizingDividerDrawable
 attr userResizingDividerTint
diff --git a/slidingpanelayout/slidingpanelayout/api/restricted_current.txt b/slidingpanelayout/slidingpanelayout/api/restricted_current.txt
index 072d9d3..6090e13 100644
--- a/slidingpanelayout/slidingpanelayout/api/restricted_current.txt
+++ b/slidingpanelayout/slidingpanelayout/api/restricted_current.txt
@@ -13,6 +13,7 @@
     method public boolean closePane();
     method @Deprecated @ColorInt public int getCoveredFadeColor();
     method public final int getLockMode();
+    method @Px public final int getPaneSpacing();
     method @Px public int getParallaxDistance();
     method @Deprecated @ColorInt public int getSliderFadeColor();
     method public final int getSplitDividerPosition();
@@ -33,6 +34,7 @@
     method public final void setLockMode(int);
     method public final void setOnUserResizingDividerClickListener(android.view.View.OnClickListener? listener);
     method public final void setOverlappingEnabled(boolean);
+    method public final void setPaneSpacing(int);
     method @Deprecated public void setPanelSlideListener(androidx.slidingpanelayout.widget.SlidingPaneLayout.PanelSlideListener? listener);
     method public void setParallaxDistance(@Px int);
     method @Deprecated public void setShadowDrawable(android.graphics.drawable.Drawable? drawable);
@@ -58,6 +60,7 @@
     property public final boolean isUserResizable;
     property public final boolean isUserResizingEnabled;
     property public final int lockMode;
+    property @Px public final int paneSpacing;
     property @Px public int parallaxDistance;
     property @Deprecated @ColorInt public int sliderFadeColor;
     property public final int splitDividerPosition;
diff --git a/slidingpanelayout/slidingpanelayout/src/androidTest/java/androidx/slidingpanelayout/widget/FoldTest.kt b/slidingpanelayout/slidingpanelayout/src/androidTest/java/androidx/slidingpanelayout/widget/FoldTest.kt
index da4b909..c200c3d 100644
--- a/slidingpanelayout/slidingpanelayout/src/androidTest/java/androidx/slidingpanelayout/widget/FoldTest.kt
+++ b/slidingpanelayout/slidingpanelayout/src/androidTest/java/androidx/slidingpanelayout/widget/FoldTest.kt
@@ -137,4 +137,36 @@
             assertThat(findViewX(R.id.list_pane)).isLessThan(findViewX(R.id.detail_pane))
         }
     }
+
+    @Test
+    fun testFold_hasPaneSpacing() {
+        val foldWidth = 10
+        val paneSpacing = 20
+
+        TestActivity.onActivityCreated = { activity ->
+            val spl =
+                activity.layoutInflater.inflate(R.layout.activity_test_fold_layout, null, false)
+                    as SlidingPaneLayout
+            spl.paneSpacing = paneSpacing
+            activity.setContentView(spl)
+        }
+
+        with(ActivityScenario.launch(TestActivity::class.java)) {
+            withActivity {
+                val testFeature =
+                    FoldingFeature(activity = this, orientation = VERTICAL, size = foldWidth)
+                val info = WindowLayoutInfo(listOf(testFeature))
+                rule.overrideWindowLayoutInfo(info)
+            }
+
+            val spl = findViewById(R.id.sliding_pane_fold_layout) as SlidingPaneLayout
+            val listPane = findViewById(R.id.list_pane)
+            val detailPane = findViewById(R.id.detail_pane)
+
+            assertThat(spl.isSlideable).isFalse()
+            val expectedWidth = (spl.width - foldWidth - paneSpacing) / 2
+            assertThat(listPane.width).isEqualTo(expectedWidth)
+            assertThat(detailPane.width).isEqualTo(expectedWidth)
+        }
+    }
 }
diff --git a/slidingpanelayout/slidingpanelayout/src/androidTest/java/androidx/slidingpanelayout/widget/SlidingPaneLayoutTest.kt b/slidingpanelayout/slidingpanelayout/src/androidTest/java/androidx/slidingpanelayout/widget/SlidingPaneLayoutTest.kt
index 903261a..6093130 100644
--- a/slidingpanelayout/slidingpanelayout/src/androidTest/java/androidx/slidingpanelayout/widget/SlidingPaneLayoutTest.kt
+++ b/slidingpanelayout/slidingpanelayout/src/androidTest/java/androidx/slidingpanelayout/widget/SlidingPaneLayoutTest.kt
@@ -284,6 +284,14 @@
         assertWithMessage("isUserResizingEnabled").that(view.isUserResizingEnabled).isTrue()
         assertWithMessage("isUserResizable").that(view.isUserResizable).isTrue()
     }
+
+    @Test
+    fun userResizingDividerWidthInflated() {
+        val context = InstrumentationRegistry.getInstrumentation().context
+        val inflater = LayoutInflater.from(context)
+        val view = inflater.inflate(R.layout.pane_spacing, null) as SlidingPaneLayout
+        assertWithMessage("paneSpacing is inflated").that(view.paneSpacing).isEqualTo(24)
+    }
 }
 
 private fun View.measureAndLayout(width: Int, height: Int) {
diff --git a/slidingpanelayout/slidingpanelayout/src/androidTest/java/androidx/slidingpanelayout/widget/UserResizeModeTest.kt b/slidingpanelayout/slidingpanelayout/src/androidTest/java/androidx/slidingpanelayout/widget/UserResizeModeTest.kt
index dede582..cbbbc57 100644
--- a/slidingpanelayout/slidingpanelayout/src/androidTest/java/androidx/slidingpanelayout/widget/UserResizeModeTest.kt
+++ b/slidingpanelayout/slidingpanelayout/src/androidTest/java/androidx/slidingpanelayout/widget/UserResizeModeTest.kt
@@ -103,6 +103,28 @@
     }
 
     @Test
+    fun layoutWithPaneSpacing() {
+        val context = InstrumentationRegistry.getInstrumentation().context
+        val spl = createTestSpl(context)
+        val leftPane = spl[0]
+        val rightPane = spl[1]
+
+        spl.paneSpacing = 20
+        spl.isUserResizingEnabled = true
+        spl.measureAndLayoutForTest(width = 100)
+
+        assertWithMessage("leftPane width").that(leftPane.width).isEqualTo(40)
+        assertWithMessage("rightPane width").that(rightPane.width).isEqualTo(40)
+
+        // userResizeMode is disabled, paneSpacing should still be the same.
+        spl.isUserResizingEnabled = false
+        spl.measureAndLayoutForTest(width = 100)
+
+        assertWithMessage("leftPane width").that(leftPane.width).isEqualTo(40)
+        assertWithMessage("rightPane width").that(rightPane.width).isEqualTo(40)
+    }
+
+    @Test
     fun layoutTooSmallForPadding() {
         val context = InstrumentationRegistry.getInstrumentation().context
         val spl = createTestSpl(context)
@@ -133,6 +155,30 @@
     }
 
     @Test
+    fun layoutTooSmallForPaneSpacing() {
+        val context = InstrumentationRegistry.getInstrumentation().context
+        val spl = createTestSpl(context)
+        val leftPane = spl[0]
+        val rightPane = spl[1]
+        val splWidth = 100
+
+        spl.paneSpacing = 200
+        spl.measureAndLayoutForTest(splWidth, 0)
+
+        assertWithMessage("SlidingPaneLayout width").that(spl.width).isEqualTo(splWidth)
+        assertWithMessage("leftPane width is zero").that(leftPane.width).isEqualTo(0)
+        assertWithMessage("rightPane width is zero").that(rightPane.width).isEqualTo(0)
+
+        assertWithMessage("leftPane left is zero").that(leftPane.left).isEqualTo(0)
+        assertWithMessage("rightPane left is width").that(rightPane.left).isEqualTo(splWidth)
+
+        // SlidingPaneLayout switch to overlapping mode if paneSpacing is too large.
+        spl.isOverlappingEnabled = true
+        spl.measureAndLayoutForTest(splWidth, 0)
+        assertWithMessage("SlidingPaneLayout is slideable").that(spl.isSlideable).isTrue()
+    }
+
+    @Test
     fun dragDividerWithTouchCapturingPanes() {
         val context = InstrumentationRegistry.getInstrumentation().context
         val spl = createTestSpl(context, childPanesAcceptTouchEvents = true)
@@ -253,6 +299,23 @@
     }
 
     @Test
+    fun visualDividerPositionClipsChildren_hasPaneSpacing() {
+        val context = InstrumentationRegistry.getInstrumentation().context
+        val spl = createTestSpl(context)
+        spl.splitDividerPosition = 35
+        spl.paneSpacing = 10
+        spl.drawToBitmap()
+        assertWithMessage("left child clip")
+            .that((spl[0] as TestPaneView).clipBoundsAtLastDraw)
+            .isEqualTo(Rect(0, 0, 30, 100))
+        spl.splitDividerPosition = 65
+        spl.drawToBitmap()
+        assertWithMessage("right child clip")
+            .that(((spl[1] as ViewGroup)[0] as TestPaneView).clipBoundsAtLastDraw)
+            .isEqualTo(Rect(20, 0, 50, 100))
+    }
+
+    @Test
     fun disablingDividerClippingDoesNotClipChildren() {
         val context = InstrumentationRegistry.getInstrumentation().context
         val spl = createTestSpl(context)
@@ -294,6 +357,30 @@
     }
 
     @Test
+    fun paneSpacingAffectsLayout() {
+        val context = InstrumentationRegistry.getInstrumentation().context
+        val spl = createTestSpl(context)
+        assertWithMessage("layout requested after SlidingPaneLayout creation")
+            .that(spl.isLayoutRequested)
+            .isFalse()
+        spl.splitDividerPosition = 35
+        assertWithMessage("layout requested by splitDividerPosition change")
+            .that(spl.isLayoutRequested)
+            .isTrue()
+        spl.measureAndLayoutForTest()
+        assertWithMessage("first child expected width").that(spl[0].width).isEqualTo(35)
+        assertWithMessage("second child expected width").that(spl[1].width).isEqualTo(65)
+
+        spl.paneSpacing = 10
+        assertWithMessage("layout requested by splitDividerPosition change (2)")
+            .that(spl.isLayoutRequested)
+            .isTrue()
+        spl.measureAndLayoutForTest()
+        assertWithMessage("first child expected width").that(spl[0].width).isEqualTo(30)
+        assertWithMessage("second child expected width").that(spl[1].width).isEqualTo(60)
+    }
+
+    @Test
     fun splitDividerPositionDoesNotChangePadding() {
         val context = InstrumentationRegistry.getInstrumentation().context
         val spl = createTestSpl(context)
@@ -336,6 +423,39 @@
     }
 
     @Test
+    fun zeroSpaceForOnePane_paneSpacingTakeChildWidth() {
+        val context = InstrumentationRegistry.getInstrumentation().context
+        val spl = createTestSpl(context)
+        val splWidth = 100
+        val paneSpacing = 20
+        spl.paneSpacing = 20
+        spl.splitDividerPosition = 10
+        spl.measureAndLayoutForTest(width = splWidth)
+        assertWithMessage("left pane has zero width").that(spl[0].width).isEqualTo(0)
+
+        spl.splitDividerPosition = 5
+        spl.measureAndLayoutForTest(width = splWidth)
+        assertWithMessage("left pane has zero width").that(spl[0].width).isEqualTo(0)
+        assertWithMessage("right pane takes remaining width")
+            .that(spl[1].width)
+            .isEqualTo(splWidth - paneSpacing)
+
+        spl.splitDividerPosition = 90
+        spl.measureAndLayoutForTest(width = splWidth)
+        assertWithMessage("left pane takes remaining width")
+            .that(spl[0].width)
+            .isEqualTo(splWidth - paneSpacing)
+        assertWithMessage("right pane has zero width").that(spl[1].width).isEqualTo(0)
+
+        spl.splitDividerPosition = 95
+        spl.measureAndLayoutForTest(width = splWidth)
+        assertWithMessage("left pane takes remaining width")
+            .that(spl[0].width)
+            .isEqualTo(splWidth - paneSpacing)
+        assertWithMessage("right pane has zero width").that(spl[1].width).isEqualTo(0)
+    }
+
+    @Test
     fun zeroSpaceForOnePanePaddedLayout() {
         val context = InstrumentationRegistry.getInstrumentation().context
         val spl = createTestSpl(context)
@@ -349,6 +469,49 @@
     }
 
     @Test
+    fun visualDividerPositionRange() {
+        val context = InstrumentationRegistry.getInstrumentation().context
+        val spl = createTestSpl(context)
+        val splWidth = 100
+        spl.splitDividerPosition = 0
+        spl.setPadding(4, 0, 8, 0)
+        spl.measureAndLayoutForTest(width = splWidth)
+        assertWithMessage("visualDividerPosition is clamped to view left")
+            .that(spl.visualDividerPosition)
+            .isEqualTo(4)
+        spl.splitDividerPosition = spl.width
+
+        spl.measureAndLayoutForTest(width = splWidth)
+        assertWithMessage("visualDividerPosition is clamped to view right")
+            .that(spl.visualDividerPosition)
+            .isEqualTo(splWidth - 8)
+    }
+
+    @Test
+    fun visualDividerPositionRange_hasPaneSpacing() {
+        val context = InstrumentationRegistry.getInstrumentation().context
+        val spl = createTestSpl(context)
+        val splWidth = 100
+        val paneSpacing = 19
+        val paneSpacingLeftHalf = 9
+        val paneSpacingRightHalf = 10
+        spl.splitDividerPosition = 0
+        spl.setPadding(4, 0, 8, 0)
+        spl.paneSpacing = paneSpacing
+        spl.measureAndLayoutForTest(width = splWidth)
+        assertWithMessage("visualDividerPosition is clamped to view left")
+            .that(spl.visualDividerPosition)
+            .isEqualTo(4 + paneSpacingLeftHalf)
+
+        spl.splitDividerPosition = spl.width
+
+        spl.measureAndLayoutForTest(width = splWidth)
+        assertWithMessage("visualDividerPosition is clamped to view right")
+            .that(spl.visualDividerPosition)
+            .isEqualTo(splWidth - 8 - paneSpacingRightHalf)
+    }
+
+    @Test
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.Q)
     fun gestureExclusionRectsUpdated() {
         val context = InstrumentationRegistry.getInstrumentation().context
diff --git a/slidingpanelayout/slidingpanelayout/src/androidTest/res/layout/pane_spacing.xml b/slidingpanelayout/slidingpanelayout/src/androidTest/res/layout/pane_spacing.xml
new file mode 100644
index 0000000..0991f8b
--- /dev/null
+++ b/slidingpanelayout/slidingpanelayout/src/androidTest/res/layout/pane_spacing.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  Copyright 2025 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.
+  -->
+
+<androidx.slidingpanelayout.widget.SlidingPaneLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    app:paneSpacing="24px"/>
\ No newline at end of file
diff --git a/slidingpanelayout/slidingpanelayout/src/main/java/androidx/slidingpanelayout/widget/SlidingPaneLayout.kt b/slidingpanelayout/slidingpanelayout/src/main/java/androidx/slidingpanelayout/widget/SlidingPaneLayout.kt
index 6649789..cc8d907 100644
--- a/slidingpanelayout/slidingpanelayout/src/main/java/androidx/slidingpanelayout/widget/SlidingPaneLayout.kt
+++ b/slidingpanelayout/slidingpanelayout/src/main/java/androidx/slidingpanelayout/widget/SlidingPaneLayout.kt
@@ -133,7 +133,7 @@
      */
     fun splitViewPositions(
         foldingFeature: FoldingFeature?,
-        parentView: View,
+        parentView: SlidingPaneLayout,
         outLeftRect: Rect,
         outRightRect: Rect,
     ): Boolean {
@@ -149,15 +149,16 @@
             foldingFeature.bounds.top == 0 &&
                 getFoldBoundsInView(foldingFeature, parentView, splitPosition)
         ) {
+            val paneSpacing = parentView.paneSpacing
             outLeftRect.set(
                 parentView.paddingLeft,
                 parentView.paddingTop,
-                max(parentView.paddingLeft, splitPosition.left),
+                max(parentView.paddingLeft, splitPosition.left - paneSpacing / 2),
                 parentView.height - parentView.paddingBottom
             )
             val rightBound = parentView.width - parentView.paddingRight
             outRightRect.set(
-                min(rightBound, splitPosition.right),
+                min(rightBound, splitPosition.right + (paneSpacing + 1) / 2),
                 parentView.paddingTop,
                 rightBound,
                 parentView.height - parentView.paddingBottom
@@ -495,7 +496,15 @@
             when {
                 !isUserResizable -> -1
                 isDividerDragging -> draggableDividerHandler.dragPositionX
-                splitDividerPosition >= 0 -> splitDividerPosition
+                splitDividerPosition >= 0 -> {
+                    val paneSpacing =
+                        [email protected]
+                            .coerceAtMost(width - paddingLeft - paddingRight)
+                            .coerceAtLeast(0)
+                    splitDividerPosition
+                        .coerceAtMost(width - paddingRight - (paneSpacing + 1) / 2)
+                        .coerceAtLeast(paddingLeft + paneSpacing / 2)
+                }
                 else -> {
                     val leftChild: View
                     val rightChild: View
@@ -564,6 +573,22 @@
             }
         }
 
+    /**
+     * Set the amount of space between two panes in the side by side mode, in the unit of pixel. The
+     * added space is centered at the [visualDividerPosition], and the half of the specified width
+     * will be added to the left of [visualDividerPosition] and half will be added to the right. Its
+     * default value is 0 pixel.
+     */
+    @get:Px
+    var paneSpacing: Int = 0
+        set(value) {
+            require(value >= 0) { "paneSpacing can't be negative, but the given value is: $value" }
+            if (value != field) {
+                field = value
+                requestLayout()
+            }
+        }
+
     private var onUserResizingDividerClickListener: OnClickListener? = null
 
     /**
@@ -631,6 +656,8 @@
                     1 -> USER_RESIZE_RELAYOUT_WHEN_MOVED
                     else -> error("$behaviorConstant is not a valid userResizeBehavior value")
                 }
+
+            paneSpacing = getDimensionPixelSize(R.styleable.SlidingPaneLayout_paneSpacing, 0)
         }
         accessibilityManager =
             context.getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager
@@ -911,7 +938,10 @@
         var canSlide = false
         val isLayoutRtl = isLayoutRtl
         val widthAvailable = (widthSize - paddingLeft - paddingRight).coerceAtLeast(0)
-        var widthRemaining = widthAvailable
+        // Coerce the paneSpacing so that it at most equals to widthAvailable.
+        val paneSpacing = paneSpacing.coerceAtMost(widthAvailable).coerceAtLeast(0)
+
+        var widthRemaining = widthAvailable - paneSpacing
         val childCount = childCount
         if (childCount > 2) {
             error("SlidingPaneLayout: More than two child views are not supported.")
@@ -1032,17 +1062,26 @@
                                     (lp.weight * widthToDistribute / weightSum).roundToInt()
                                 measuredWidth + addedWidth
                             } else { // Explicit dividing line is defined
+                                val paneSpacingLeftHalf = paneSpacing / 2
+                                val paneSpacingRightHalf = paneSpacing - paneSpacingLeftHalf
                                 val clampedPos =
                                     dividerPos
-                                        .coerceAtMost(width - paddingRight)
-                                        .coerceAtLeast(paddingLeft)
+                                        .coerceAtMost(
+                                            widthSize - paddingRight - paneSpacingRightHalf
+                                        )
+                                        .coerceAtLeast(paddingLeft + paneSpacingLeftHalf)
                                 val availableWidthDivider = clampedPos - paddingLeft
                                 if ((index == 0) xor isLayoutRtl) {
-                                    availableWidthDivider - lp.horizontalMargin
+                                    availableWidthDivider -
+                                        lp.horizontalMargin -
+                                        paneSpacingLeftHalf
                                 } else {
                                     // padding accounted for in widthAvailable;
                                     // dividerPos includes left padding
-                                    widthAvailable - lp.horizontalMargin - availableWidthDivider
+                                    widthAvailable -
+                                        lp.horizontalMargin -
+                                        availableWidthDivider -
+                                        paneSpacingRightHalf
                                 }
                             }
                         }
@@ -1211,16 +1250,21 @@
             val childBottom = paddingTop + child.measuredHeight
             child.layout(childLeft, paddingTop, childRight, childBottom)
 
+            val paneSpacing =
+                paneSpacing.coerceAtMost(width - paddingStart - paddingEnd).coerceAtLeast(0)
             // If a folding feature separates the content, we use its width as the extra
             // offset for the next child, in order to avoid rendering the content under it.
-            var nextXOffset = 0
-            if (
-                foldingFeature != null &&
-                    foldingFeature.orientation == FoldingFeature.Orientation.VERTICAL &&
-                    foldingFeature.isSeparating
-            ) {
-                nextXOffset = foldingFeature.bounds.width()
-            }
+            val nextXOffset =
+                if (
+                    foldingFeature != null &&
+                        foldingFeature.orientation == FoldingFeature.Orientation.VERTICAL &&
+                        foldingFeature.isSeparating
+                ) {
+                    foldingFeature.bounds.width() + paneSpacing
+                } else {
+                    // paneSpacing added between panes.
+                    paneSpacing
+                }
             nextXStart += child.width + abs(nextXOffset)
         }
         if (isUserResizable) {
@@ -1461,15 +1505,17 @@
         }
         if (!isSlideable && isChildClippingToResizeDividerEnabled) {
             val visualDividerPosition = visualDividerPosition
+            val paneSpacing =
+                paneSpacing.coerceAtMost(width - paddingLeft - paddingRight).coerceAtLeast(0)
             if (visualDividerPosition >= 0) {
                 with(tmpRect) {
                     if (isLayoutRtl xor (child === getChildAt(0))) {
                         // left child
                         left = paddingLeft
-                        right = visualDividerPosition
+                        right = visualDividerPosition - paneSpacing / 2
                     } else {
                         // right child
-                        left = visualDividerPosition
+                        left = visualDividerPosition + (paneSpacing + 1) / 2
                         right = width - paddingRight
                     }
                     top = paddingTop
@@ -1975,7 +2021,10 @@
             node.contentDescription = context.getString(R.string.draggable_divider_handler)
             node.isScrollable = true
 
-            if (visualDividerPosition > 0) {
+            val paneSpacing =
+                paneSpacing.coerceAtMost(width - paddingLeft - paddingRight).coerceAtLeast(0)
+
+            if (visualDividerPosition > paddingLeft + paneSpacing / 2) {
                 node.addAction(AccessibilityActionCompat.ACTION_SCROLL_LEFT)
                 if (isLayoutRtl) {
                     node.addAction(AccessibilityActionCompat.ACTION_SCROLL_FORWARD)
@@ -1988,7 +2037,7 @@
                     context.getString(R.string.draggable_divider_handler_state_left_edge)
             }
 
-            if (visualDividerPosition < width) {
+            if (visualDividerPosition < width - paddingRight - (paneSpacing + 1) / 2) {
                 node.addAction(AccessibilityActionCompat.ACTION_SCROLL_RIGHT)
                 if (isLayoutRtl) {
                     node.addAction(AccessibilityActionCompat.ACTION_SCROLL_BACKWARD)
@@ -2155,7 +2204,7 @@
     }
 
     private fun sendAccessibilityEventForDivider(eventType: Int) {
-        parent.requestSendAccessibilityEvent(
+        parent?.requestSendAccessibilityEvent(
             this,
             @Suppress("DEPRECATION")
             AccessibilityEvent.obtain().apply {
diff --git a/slidingpanelayout/slidingpanelayout/src/main/res/values/attrs.xml b/slidingpanelayout/slidingpanelayout/src/main/res/values/attrs.xml
index 14c032e..a0ee796 100644
--- a/slidingpanelayout/slidingpanelayout/src/main/res/values/attrs.xml
+++ b/slidingpanelayout/slidingpanelayout/src/main/res/values/attrs.xml
@@ -25,6 +25,7 @@
             <enum name="relayoutWhenComplete" value="0"/>
             <enum name="relayoutWhenMoved" value="1"/>
         </attr>
+        <attr name="paneSpacing" format="dimension"/>
     </declare-styleable>
     <declare-styleable name="SlidingPaneLayout_Layout">
         <attr name="android:layout_weight"/>
diff --git a/slidingpanelayout/slidingpanelayout/src/main/res/values/public.xml b/slidingpanelayout/slidingpanelayout/src/main/res/values/public.xml
index c8e7a8f..7912408 100644
--- a/slidingpanelayout/slidingpanelayout/src/main/res/values/public.xml
+++ b/slidingpanelayout/slidingpanelayout/src/main/res/values/public.xml
@@ -21,4 +21,5 @@
     <public type="attr" name="userResizingDividerTint"/>
     <public type="attr" name="isChildClippingToResizeDividerEnabled"/>
     <public type="attr" name="userResizeBehavior"/>
+    <public type="attr" name="paneSpacing"/>
 </resources>
diff --git a/sqlite/sqlite-bundled/api/api_lint.ignore b/sqlite/sqlite-bundled/api/api_lint.ignore
deleted file mode 100644
index 1ad4322..0000000
--- a/sqlite/sqlite-bundled/api/api_lint.ignore
+++ /dev/null
@@ -1,5 +0,0 @@
-// Baseline format: 1.0
-AcronymName: androidx.sqlite.driver.bundled.BundledSQLite:
-    Acronyms should not be capitalized in class names: was `BundledSQLite`, should this be `BundledSqLite`?
-AcronymName: androidx.sqlite.driver.bundled.BundledSQLiteDriver:
-    Acronyms should not be capitalized in class names: was `BundledSQLiteDriver`, should this be `BundledSqLiteDriver`?
diff --git a/sqlite/sqlite-framework/api/api_lint.ignore b/sqlite/sqlite-framework/api/api_lint.ignore
deleted file mode 100644
index 03491a3..0000000
--- a/sqlite/sqlite-framework/api/api_lint.ignore
+++ /dev/null
@@ -1,5 +0,0 @@
-// Baseline format: 1.0
-AcronymName: androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory:
-    Acronyms should not be capitalized in class names: was `FrameworkSQLiteOpenHelperFactory`, should this be `FrameworkSqLiteOpenHelperFactory`?
-AcronymName: androidx.sqlite.driver.AndroidSQLiteDriver:
-    Acronyms should not be capitalized in class names: was `AndroidSQLiteDriver`, should this be `AndroidSqLiteDriver`?
diff --git a/sqlite/sqlite-ktx/api/api_lint.ignore b/sqlite/sqlite-ktx/api/api_lint.ignore
deleted file mode 100644
index 3948bf5..0000000
--- a/sqlite/sqlite-ktx/api/api_lint.ignore
+++ /dev/null
@@ -1,3 +0,0 @@
-// Baseline format: 1.0
-AcronymName: androidx.sqlite.db.SupportSQLiteDatabaseKt:
-    Acronyms should not be capitalized in class names: was `SupportSQLiteDatabaseKt`, should this be `SupportSqLiteDatabaseKt`?
diff --git a/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SimpleSQLiteQuery.android.kt b/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SimpleSQLiteQuery.android.kt
index 1939a45..4bf9c1b 100644
--- a/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SimpleSQLiteQuery.android.kt
+++ b/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SimpleSQLiteQuery.android.kt
@@ -23,7 +23,6 @@
  * @param bindArgs The bind argument value that will replace the placeholders in the query.
  * @constructor Creates an SQL query with the sql string and the bind arguments.
  */
-@Suppress("AcronymName") // SQL is a known term and should remain capitalized
 public class SimpleSQLiteQuery(
     private val query: String,
     @Suppress("ArrayReturn") // Due to legacy API
@@ -45,7 +44,6 @@
      *
      * @param [statement] The SQL query to execute. Cannot include bind parameters.
      */
-    @Suppress("AcronymName") // SQL is a known term and should remain capitalized
     override fun bindTo(statement: SupportSQLiteProgram) {
         bind(statement, bindArgs)
     }
@@ -62,7 +60,6 @@
          */
         @JvmStatic
         public fun bind(
-            @Suppress("AcronymName") // SQL is a known term and should remain capitalized
             statement: SupportSQLiteProgram,
             @Suppress("ArrayReturn") // Due to legacy API
             bindArgs: Array<out Any?>?
@@ -78,12 +75,7 @@
             }
         }
 
-        private fun bind(
-            @Suppress("AcronymName") // SQL is a known term and should remain capitalized
-            statement: SupportSQLiteProgram,
-            index: Int,
-            arg: Any?
-        ) {
+        private fun bind(statement: SupportSQLiteProgram, index: Int, arg: Any?) {
             // extracted from android.database.sqlite.SQLiteConnection
             if (arg == null) {
                 statement.bindNull(index)
diff --git a/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteDatabase.android.kt b/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteDatabase.android.kt
index 5c6d9dd..ba6f65c 100644
--- a/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteDatabase.android.kt
+++ b/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteDatabase.android.kt
@@ -29,7 +29,6 @@
  * A database abstraction which removes the framework dependency and allows swapping underlying sql
  * versions. It mimics the behavior of [android.database.sqlite.SQLiteDatabase]
  */
-@Suppress("AcronymName") // SQL is a known term and should remain capitalized
 public interface SupportSQLiteDatabase : Closeable {
     /**
      * Compiles the given SQL statement.
@@ -250,7 +249,6 @@
     public fun yieldIfContendedSafely(sleepAfterYieldDelayMillis: Long): Boolean
 
     /** Is true if [execPerConnectionSQL] is supported by the implementation. */
-    @get:Suppress("AcronymName") // To keep consistency with framework method name.
     public val isExecPerConnectionSQLSupported: Boolean
         get() = false
 
@@ -275,7 +273,6 @@
      * @throws UnsupportedOperationException if this operation is not supported. To check if it
      *   supported use [isExecPerConnectionSQLSupported]
      */
-    @Suppress("AcronymName") // To keep consistency with framework method name.
     public fun execPerConnectionSQL(
         sql: String,
         @SuppressLint("ArrayReturn") bindArgs: Array<out Any?>?
@@ -425,9 +422,7 @@
      *   not supported.
      * @throws SQLException if the SQL string is invalid
      */
-    @Suppress("AcronymName") // SQL is a known term and should remain capitalized
-    @Throws(SQLException::class)
-    public fun execSQL(sql: String)
+    @Throws(SQLException::class) public fun execSQL(sql: String)
 
     /**
      * Execute a single SQL statement that does not return any data.
@@ -441,9 +436,7 @@
      * @param bindArgs only byte[], String, Long and Double are supported in selectionArgs.
      * @throws SQLException if the SQL string is invalid
      */
-    @Suppress("AcronymName") // SQL is a known term and should remain capitalized
-    @Throws(SQLException::class)
-    public fun execSQL(sql: String, bindArgs: Array<out Any?>)
+    @Throws(SQLException::class) public fun execSQL(sql: String, bindArgs: Array<out Any?>)
 
     /** Is true if the database is opened as read only. */
     public val isReadOnly: Boolean
diff --git a/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteOpenHelper.android.kt b/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteOpenHelper.android.kt
index 2be3a94..c597f84 100644
--- a/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteOpenHelper.android.kt
+++ b/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteOpenHelper.android.kt
@@ -31,7 +31,6 @@
  * that class requires overriding certain methods, support implementation uses [Factory.create] to
  * create this and [Callback] to implement the methods that should be overridden.
  */
-@Suppress("AcronymName") // SQL is a known term and should remain capitalized
 public interface SupportSQLiteOpenHelper : Closeable {
     /**
      * Return the name of the SQLite database being opened, as given to the constructor. `null`
diff --git a/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteProgram.android.kt b/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteProgram.android.kt
index 572879d..37965b1 100644
--- a/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteProgram.android.kt
+++ b/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteProgram.android.kt
@@ -18,7 +18,6 @@
 import java.io.Closeable
 
 /** An interface to map the behavior of [android.database.sqlite.SQLiteProgram]. */
-@Suppress("AcronymName") // SQL is a known term and should remain capitalized
 public interface SupportSQLiteProgram : Closeable {
     /**
      * Bind a NULL value to this statement. The value remains bound until [.clearBindings] is
diff --git a/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteQuery.android.kt b/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteQuery.android.kt
index 3db42f5..657b85a3 100644
--- a/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteQuery.android.kt
+++ b/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteQuery.android.kt
@@ -19,7 +19,6 @@
  * A query with typed bindings. It is better to use this API instead of
  * [android.database.sqlite.SQLiteDatabase.rawQuery] because it allows binding type safe parameters.
  */
-@Suppress("AcronymName") // SQL is a known term and should remain capitalized
 public interface SupportSQLiteQuery {
     /** The SQL query. This query can have placeholders(?) for bind arguments. */
     public val sql: String
diff --git a/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteQueryBuilder.android.kt b/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteQueryBuilder.android.kt
index 770820c..49ec1f3 100644
--- a/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteQueryBuilder.android.kt
+++ b/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteQueryBuilder.android.kt
@@ -18,7 +18,6 @@
 import java.util.regex.Pattern
 
 /** A simple query builder to create SQL SELECT queries. */
-@Suppress("AcronymName") // SQL is a known term and should remain capitalized
 public class SupportSQLiteQueryBuilder private constructor(private val table: String) {
     private var distinct = false
     private var columns: Array<out String>? = null
diff --git a/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteStatement.android.kt b/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteStatement.android.kt
index a5c36ae..bf1bca3 100644
--- a/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteStatement.android.kt
+++ b/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteStatement.android.kt
@@ -16,7 +16,6 @@
 package androidx.sqlite.db
 
 /** An interface to map the behavior of [android.database.sqlite.SQLiteStatement]. */
-@Suppress("AcronymName") // SQL is a known term and should remain capitalized
 public interface SupportSQLiteStatement : SupportSQLiteProgram {
     /**
      * Execute this SQL statement, if it is not a SELECT / INSERT / DELETE / UPDATE, for example
diff --git a/sqlite/sqlite/src/commonMain/kotlin/androidx/sqlite/SQLite.kt b/sqlite/sqlite/src/commonMain/kotlin/androidx/sqlite/SQLite.kt
index 9b63cba..653b597 100644
--- a/sqlite/sqlite/src/commonMain/kotlin/androidx/sqlite/SQLite.kt
+++ b/sqlite/sqlite/src/commonMain/kotlin/androidx/sqlite/SQLite.kt
@@ -13,7 +13,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@file:Suppress("AcronymName") // SQL is a known term and should remain capitalized
 @file:JvmName("SQLite")
 
 package androidx.sqlite
@@ -53,13 +52,11 @@
 public annotation class DataType
 
 /** Executes a single SQL statement that returns no values. */
-@Suppress("AcronymName") // SQL is a known term and should remain capitalized
 public fun SQLiteConnection.execSQL(sql: String) {
     prepare(sql).use { it.step() }
 }
 
 /** Throws a [SQLiteException] with its message formed by the given [errorCode] amd [errorMsg]. */
-@Suppress("AcronymName") // SQL is a known term and should remain capitalized
 public fun throwSQLiteException(errorCode: Int, errorMsg: String?): Nothing {
     val message = buildString {
         append("Error code: $errorCode")
diff --git a/sqlite/sqlite/src/commonMain/kotlin/androidx/sqlite/SQLiteConnection.kt b/sqlite/sqlite/src/commonMain/kotlin/androidx/sqlite/SQLiteConnection.kt
index 14b76d4..e988034 100644
--- a/sqlite/sqlite/src/commonMain/kotlin/androidx/sqlite/SQLiteConnection.kt
+++ b/sqlite/sqlite/src/commonMain/kotlin/androidx/sqlite/SQLiteConnection.kt
@@ -24,7 +24,7 @@
  *
  * See also [Database Connection](https://www.sqlite.org/c3ref/sqlite3.html)
  */
-@Suppress("NotCloseable", "AcronymName") // SQL is a known term and should remain capitalized
+@Suppress("NotCloseable")
 public interface SQLiteConnection : AutoCloseable {
     /**
      * Prepares a new SQL statement.
diff --git a/sqlite/sqlite/src/commonMain/kotlin/androidx/sqlite/SQLiteDriver.kt b/sqlite/sqlite/src/commonMain/kotlin/androidx/sqlite/SQLiteDriver.kt
index 5cb23bf..a1f3e50 100644
--- a/sqlite/sqlite/src/commonMain/kotlin/androidx/sqlite/SQLiteDriver.kt
+++ b/sqlite/sqlite/src/commonMain/kotlin/androidx/sqlite/SQLiteDriver.kt
@@ -17,7 +17,6 @@
 package androidx.sqlite
 
 /** An interface to open database connections. */
-@Suppress("AcronymName") // SQL is a known term and should remain capitalized
 public interface SQLiteDriver {
     /**
      * Opens a new database connection.
diff --git a/sqlite/sqlite/src/commonMain/kotlin/androidx/sqlite/SQLiteStatement.kt b/sqlite/sqlite/src/commonMain/kotlin/androidx/sqlite/SQLiteStatement.kt
index 7f42c8b..8b319b9 100644
--- a/sqlite/sqlite/src/commonMain/kotlin/androidx/sqlite/SQLiteStatement.kt
+++ b/sqlite/sqlite/src/commonMain/kotlin/androidx/sqlite/SQLiteStatement.kt
@@ -26,7 +26,7 @@
  *
  * See also [Prepared Statement](https://www.sqlite.org/c3ref/stmt.html)
  */
-@Suppress("NotCloseable", "AcronymName") // SQL is a known term and should remain capitalized
+@Suppress("NotCloseable")
 public interface SQLiteStatement : AutoCloseable {
     /**
      * Binds a ByteArray value to this statement at an index.
diff --git a/webkit/webkit/src/main/java/androidx/webkit/URLUtilCompat.java b/webkit/webkit/src/main/java/androidx/webkit/URLUtilCompat.java
index 4761400..487fc51 100644
--- a/webkit/webkit/src/main/java/androidx/webkit/URLUtilCompat.java
+++ b/webkit/webkit/src/main/java/androidx/webkit/URLUtilCompat.java
@@ -34,7 +34,6 @@
  *
  * @see android.webkit.URLUtil
  */
-@SuppressWarnings("AcronymName") // Compat class for similarly named URLUtil in Android SDK
 public final class URLUtilCompat {
 
     private URLUtilCompat() {} // Class should not be instantiated
diff --git a/window/window-demos/demo/lint-baseline.xml b/window/window-demos/demo/lint-baseline.xml
index 57a5f51..d4d73fc 100644
--- a/window/window-demos/demo/lint-baseline.xml
+++ b/window/window-demos/demo/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.8.0-alpha08" type="baseline" client="gradle" dependencies="false" name="AGP (8.8.0-alpha08)" variant="all" version="8.8.0-alpha08">
+<issues format="6" by="lint 8.9.0-alpha06" type="baseline" client="gradle" dependencies="false" name="AGP (8.9.0-alpha06)" variant="all" version="8.9.0-alpha06">
 
     <issue
         id="NewApi"
@@ -29,19 +29,19 @@
     </issue>
 
     <issue
-        id="WrongConstant"
-        message="Must be one or more of: LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON, LayoutParams.FLAG_DIM_BEHIND, LayoutParams.FLAG_BLUR_BEHIND, LayoutParams.FLAG_NOT_FOCUSABLE, LayoutParams.FLAG_NOT_TOUCHABLE, LayoutParams.FLAG_NOT_TOUCH_MODAL, LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING, LayoutParams.FLAG_KEEP_SCREEN_ON, LayoutParams.FLAG_LAYOUT_IN_SCREEN, LayoutParams.FLAG_LAYOUT_NO_LIMITS, LayoutParams.FLAG_FULLSCREEN, LayoutParams.FLAG_FORCE_NOT_FULLSCREEN, LayoutParams.FLAG_DITHER, LayoutParams.FLAG_SECURE, LayoutParams.FLAG_SCALED, LayoutParams.FLAG_IGNORE_CHEEK_PRESSES, LayoutParams.FLAG_LAYOUT_INSET_DECOR, LayoutParams.FLAG_ALT_FOCUSABLE_IM, LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH, LayoutParams.FLAG_SHOW_WHEN_LOCKED, LayoutParams.FLAG_SHOW_WALLPAPER, LayoutParams.FLAG_TURN_SCREEN_ON, LayoutParams.FLAG_DISMISS_KEYGUARD, LayoutParams.FLAG_SPLIT_TOUCH, LayoutParams.FLAG_HARDWARE_ACCELERATED, LayoutParams.FLAG_LAYOUT_IN_OVERSCAN, LayoutParams.FLAG_TRANSLUCENT_STATUS, LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, LayoutParams.FLAG_LOCAL_FOCUS_MODE, LayoutParams.FLAG_LAYOUT_ATTACHED_IN_DECOR, LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS"
-        errorLine1="                        ?.or(android.R.attr.showWhenLocked or android.R.attr.turnScreenOn)"
-        errorLine2="                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        id="NewApi"
+        message="Call requires API level 30 (current min is 23): `android.view.WindowManager.LayoutParams#setFitInsetsTypes`"
+        errorLine1="            attrs.fitInsetsTypes = WindowInsets.Type.statusBars()"
+        errorLine2="                                 ~">
         <location
-            file="src/main/java/androidx/window/demo/PresentationActivity.kt"/>
+            file="src/main/java/androidx/window/demo/embedding/SplitImeActivityPlaceholder.kt"/>
     </issue>
 
     <issue
         id="WrongConstant"
         message="Must be one or more of: LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON, LayoutParams.FLAG_DIM_BEHIND, LayoutParams.FLAG_BLUR_BEHIND, LayoutParams.FLAG_NOT_FOCUSABLE, LayoutParams.FLAG_NOT_TOUCHABLE, LayoutParams.FLAG_NOT_TOUCH_MODAL, LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING, LayoutParams.FLAG_KEEP_SCREEN_ON, LayoutParams.FLAG_LAYOUT_IN_SCREEN, LayoutParams.FLAG_LAYOUT_NO_LIMITS, LayoutParams.FLAG_FULLSCREEN, LayoutParams.FLAG_FORCE_NOT_FULLSCREEN, LayoutParams.FLAG_DITHER, LayoutParams.FLAG_SECURE, LayoutParams.FLAG_SCALED, LayoutParams.FLAG_IGNORE_CHEEK_PRESSES, LayoutParams.FLAG_LAYOUT_INSET_DECOR, LayoutParams.FLAG_ALT_FOCUSABLE_IM, LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH, LayoutParams.FLAG_SHOW_WHEN_LOCKED, LayoutParams.FLAG_SHOW_WALLPAPER, LayoutParams.FLAG_TURN_SCREEN_ON, LayoutParams.FLAG_DISMISS_KEYGUARD, LayoutParams.FLAG_SPLIT_TOUCH, LayoutParams.FLAG_HARDWARE_ACCELERATED, LayoutParams.FLAG_LAYOUT_IN_OVERSCAN, LayoutParams.FLAG_TRANSLUCENT_STATUS, LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, LayoutParams.FLAG_LOCAL_FOCUS_MODE, LayoutParams.FLAG_LAYOUT_ATTACHED_IN_DECOR, LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS"
         errorLine1="                        ?.or(android.R.attr.showWhenLocked or android.R.attr.turnScreenOn)"
-        errorLine2="                                                              ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        errorLine2="                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="src/main/java/androidx/window/demo/PresentationActivity.kt"/>
     </issue>
diff --git a/xr/compose/material3/material3/build.gradle b/xr/compose/material3/material3/build.gradle
index 0cad526..ec48d06 100644
--- a/xr/compose/material3/material3/build.gradle
+++ b/xr/compose/material3/material3/build.gradle
@@ -42,7 +42,7 @@
     implementation(project(":compose:material3:material3"))
     implementation(project(":compose:material3:material3-adaptive-navigation-suite"))
 
-    implementation(project(":xr:compose:compose"))
+    implementation("androidx.xr.compose:compose:1.0.0-alpha01")
 }
 
 android {