Merge "Remove unnecessary Snapshot.withoutReadObservation" into androidx-main
diff --git a/compose/material3/adaptive/adaptive-layout/api/current.txt b/compose/material3/adaptive/adaptive-layout/api/current.txt
index 2336343..b4cd5c9 100644
--- a/compose/material3/adaptive/adaptive-layout/api/current.txt
+++ b/compose/material3/adaptive/adaptive-layout/api/current.txt
@@ -110,12 +110,28 @@
     property @androidx.compose.runtime.Composable public abstract String description;
   }
 
-  public static final class PaneExpansionAnchor.Offset extends androidx.compose.material3.adaptive.layout.PaneExpansionAnchor {
-    ctor public PaneExpansionAnchor.Offset(float offset);
-    method @androidx.compose.runtime.Composable public String getDescription();
-    method public float getOffset();
-    property @androidx.compose.runtime.Composable public String description;
+  public abstract static class PaneExpansionAnchor.Offset extends androidx.compose.material3.adaptive.layout.PaneExpansionAnchor {
+    method public final int getDirection();
+    method public final float getOffset();
+    property public final int direction;
     property public final float offset;
+    field public static final androidx.compose.material3.adaptive.layout.PaneExpansionAnchor.Offset.Companion Companion;
+  }
+
+  public static final class PaneExpansionAnchor.Offset.Companion {
+    method public androidx.compose.material3.adaptive.layout.PaneExpansionAnchor.Offset fromEnd(float offset);
+    method public androidx.compose.material3.adaptive.layout.PaneExpansionAnchor.Offset fromStart(float offset);
+  }
+
+  @kotlin.jvm.JvmInline public static final value class PaneExpansionAnchor.Offset.Direction {
+    field public static final androidx.compose.material3.adaptive.layout.PaneExpansionAnchor.Offset.Direction.Companion Companion;
+  }
+
+  public static final class PaneExpansionAnchor.Offset.Direction.Companion {
+    method public int getFromEnd();
+    method public int getFromStart();
+    property public final int FromEnd;
+    property public final int FromStart;
   }
 
   public static final class PaneExpansionAnchor.Proportion extends androidx.compose.material3.adaptive.layout.PaneExpansionAnchor {
diff --git a/compose/material3/adaptive/adaptive-layout/api/restricted_current.txt b/compose/material3/adaptive/adaptive-layout/api/restricted_current.txt
index 2336343..b4cd5c9 100644
--- a/compose/material3/adaptive/adaptive-layout/api/restricted_current.txt
+++ b/compose/material3/adaptive/adaptive-layout/api/restricted_current.txt
@@ -110,12 +110,28 @@
     property @androidx.compose.runtime.Composable public abstract String description;
   }
 
-  public static final class PaneExpansionAnchor.Offset extends androidx.compose.material3.adaptive.layout.PaneExpansionAnchor {
-    ctor public PaneExpansionAnchor.Offset(float offset);
-    method @androidx.compose.runtime.Composable public String getDescription();
-    method public float getOffset();
-    property @androidx.compose.runtime.Composable public String description;
+  public abstract static class PaneExpansionAnchor.Offset extends androidx.compose.material3.adaptive.layout.PaneExpansionAnchor {
+    method public final int getDirection();
+    method public final float getOffset();
+    property public final int direction;
     property public final float offset;
+    field public static final androidx.compose.material3.adaptive.layout.PaneExpansionAnchor.Offset.Companion Companion;
+  }
+
+  public static final class PaneExpansionAnchor.Offset.Companion {
+    method public androidx.compose.material3.adaptive.layout.PaneExpansionAnchor.Offset fromEnd(float offset);
+    method public androidx.compose.material3.adaptive.layout.PaneExpansionAnchor.Offset fromStart(float offset);
+  }
+
+  @kotlin.jvm.JvmInline public static final value class PaneExpansionAnchor.Offset.Direction {
+    field public static final androidx.compose.material3.adaptive.layout.PaneExpansionAnchor.Offset.Direction.Companion Companion;
+  }
+
+  public static final class PaneExpansionAnchor.Offset.Direction.Companion {
+    method public int getFromEnd();
+    method public int getFromStart();
+    property public final int FromEnd;
+    property public final int FromStart;
   }
 
   public static final class PaneExpansionAnchor.Proportion extends androidx.compose.material3.adaptive.layout.PaneExpansionAnchor {
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidInstrumentedTest/kotlin/androidx/compose/material3/adaptive/layout/PaneExpansionStateTest.kt b/compose/material3/adaptive/adaptive-layout/src/androidInstrumentedTest/kotlin/androidx/compose/material3/adaptive/layout/PaneExpansionStateTest.kt
index 681cae4..344c0f6 100644
--- a/compose/material3/adaptive/adaptive-layout/src/androidInstrumentedTest/kotlin/androidx/compose/material3/adaptive/layout/PaneExpansionStateTest.kt
+++ b/compose/material3/adaptive/adaptive-layout/src/androidInstrumentedTest/kotlin/androidx/compose/material3/adaptive/layout/PaneExpansionStateTest.kt
@@ -233,7 +233,7 @@
                         ThreePaneScaffoldRole.Secondary,
                         ThreePaneScaffoldRole.Tertiary
                     ),
-                    PaneExpansionStateData(7, 0.8F, 9, PaneExpansionAnchor.Offset(200.dp))
+                    PaneExpansionStateData(7, 0.8F, 9, PaneExpansionAnchor.Offset.fromStart(200.dp))
                 ),
                 Pair(
                     TwoPaneExpansionStateKeyImpl(
@@ -271,12 +271,12 @@
 @OptIn(ExperimentalMaterial3AdaptiveApi::class)
 private val MockAnchor0 = PaneExpansionAnchor.Proportion(0f)
 @OptIn(ExperimentalMaterial3AdaptiveApi::class)
-private val MockAnchor1 = PaneExpansionAnchor.Offset(200.dp)
+private val MockAnchor1 = PaneExpansionAnchor.Offset.fromStart(200.dp)
 @OptIn(ExperimentalMaterial3AdaptiveApi::class)
 private val MockAnchor2 = PaneExpansionAnchor.Proportion(0.5f)
 @OptIn(ExperimentalMaterial3AdaptiveApi::class)
-private val MockAnchor3 = PaneExpansionAnchor.Offset((-200).dp)
+private val MockAnchor3 = PaneExpansionAnchor.Offset.fromEnd(200.dp)
 @OptIn(ExperimentalMaterial3AdaptiveApi::class)
 private val MockAnchor4 = PaneExpansionAnchor.Proportion(1f)
 @OptIn(ExperimentalMaterial3AdaptiveApi::class)
-private val MockAnchor5 = PaneExpansionAnchor.Offset(500.dp)
+private val MockAnchor5 = PaneExpansionAnchor.Offset.fromStart(500.dp)
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidInstrumentedTest/kotlin/androidx/compose/material3/adaptive/layout/ThreePaneScaffoldTest.kt b/compose/material3/adaptive/adaptive-layout/src/androidInstrumentedTest/kotlin/androidx/compose/material3/adaptive/layout/ThreePaneScaffoldTest.kt
index a7fd150..3677863 100644
--- a/compose/material3/adaptive/adaptive-layout/src/androidInstrumentedTest/kotlin/androidx/compose/material3/adaptive/layout/ThreePaneScaffoldTest.kt
+++ b/compose/material3/adaptive/adaptive-layout/src/androidInstrumentedTest/kotlin/androidx/compose/material3/adaptive/layout/ThreePaneScaffoldTest.kt
@@ -303,7 +303,7 @@
                     anchors =
                         listOf(
                             PaneExpansionAnchor.Proportion(0f),
-                            PaneExpansionAnchor.Offset(MockPaneExpansionMiddleAnchor)
+                            PaneExpansionAnchor.Offset.fromStart(MockPaneExpansionMiddleAnchor)
                         )
                 )
             mockDraggingPx = with(LocalDensity.current) { 200.dp.toPx() }
@@ -340,7 +340,7 @@
         rule.runOnIdle {
             scope.launch {
                 mockPaneExpansionState.animateTo(
-                    PaneExpansionAnchor.Offset(MockPaneExpansionMiddleAnchor)
+                    PaneExpansionAnchor.Offset.fromStart(MockPaneExpansionMiddleAnchor)
                 )
             }
         }
@@ -368,7 +368,7 @@
         rule.runOnIdle {
             scope.launch {
                 mockPaneExpansionState.animateTo(
-                    PaneExpansionAnchor.Offset(MockPaneExpansionMiddleAnchor),
+                    PaneExpansionAnchor.Offset.fromStart(MockPaneExpansionMiddleAnchor),
                     200F
                 )
             }
@@ -394,7 +394,7 @@
         rule.runOnIdle {
             scope.launch {
                 assertFailsWith<IllegalArgumentException> {
-                    mockPaneExpansionState.animateTo(PaneExpansionAnchor.Offset(10.dp))
+                    mockPaneExpansionState.animateTo(PaneExpansionAnchor.Offset.fromStart(10.dp))
                 }
             }
         }
@@ -411,7 +411,7 @@
 private val MockPaneExpansionAnchors =
     listOf(
         PaneExpansionAnchor.Proportion(0f),
-        PaneExpansionAnchor.Offset(MockPaneExpansionMiddleAnchor),
+        PaneExpansionAnchor.Offset.fromStart(MockPaneExpansionMiddleAnchor),
         PaneExpansionAnchor.Proportion(1f),
     )
 
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/kotlin/androidx/compose/material3/adaptive/layout/Strings.android.kt b/compose/material3/adaptive/adaptive-layout/src/androidMain/kotlin/androidx/compose/material3/adaptive/layout/Strings.android.kt
index a563fe9..5bab1c8 100644
--- a/compose/material3/adaptive/adaptive-layout/src/androidMain/kotlin/androidx/compose/material3/adaptive/layout/Strings.android.kt
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/kotlin/androidx/compose/material3/adaptive/layout/Strings.android.kt
@@ -59,7 +59,12 @@
             get() =
                 Strings(R.string.m3_adaptive_default_pane_expansion_proportion_anchor_description)
 
-        actual inline val defaultPaneExpansionOffsetAnchorDescription
-            get() = Strings(R.string.m3_adaptive_default_pane_expansion_offset_anchor_description)
+        actual inline val defaultPaneExpansionStartOffsetAnchorDescription
+            get() =
+                Strings(R.string.m3_adaptive_default_pane_expansion_start_offset_anchor_description)
+
+        actual inline val defaultPaneExpansionEndOffsetAnchorDescription
+            get() =
+                Strings(R.string.m3_adaptive_default_pane_expansion_end_offset_anchor_description)
     }
 }
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-as/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-as/strings.xml
index d550f15..120b08a 100644
--- a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-as/strings.xml
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-as/strings.xml
@@ -20,5 +20,4 @@
     <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"পে’ন সম্প্ৰসাৰণ কৰিবলৈ টনা হেণ্ডেল"</string>
     <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"পে’নৰ বিভাজন %sলৈ সলনি কৰক"</string>
     <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d শতাংশ"</string>
-    <string name="m3_adaptive_default_pane_expansion_offset_anchor_description" msgid="8189074525698747223">"%d DPs"</string>
 </resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-en-rCA/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-en-rCA/strings.xml
index 33e0970..c1e08b3 100644
--- a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-en-rCA/strings.xml
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-en-rCA/strings.xml
@@ -20,5 +20,4 @@
     <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Pane expansion drag handle"</string>
     <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Change pane split to %s"</string>
     <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d percent"</string>
-    <string name="m3_adaptive_default_pane_expansion_offset_anchor_description" msgid="8189074525698747223">"%d DPs"</string>
 </resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-hi/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-hi/strings.xml
index d25df6b..f333cf2 100644
--- a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-hi/strings.xml
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-hi/strings.xml
@@ -20,5 +20,4 @@
     <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"पैनल को बड़ा करने के लिए, खींचकर छोड़ने वाला हैंडल"</string>
     <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"पैनल स्प्लिट को %s में बदलें"</string>
     <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d प्रतिशत"</string>
-    <string name="m3_adaptive_default_pane_expansion_offset_anchor_description" msgid="8189074525698747223">"%d डीपी"</string>
 </resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ja/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ja/strings.xml
index c287ba9..bfbceb0 100644
--- a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ja/strings.xml
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ja/strings.xml
@@ -20,5 +20,4 @@
     <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"ペインの展開のドラッグ ハンドル"</string>
     <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"ペインの分割を %s に変更"</string>
     <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d パーセント"</string>
-    <string name="m3_adaptive_default_pane_expansion_offset_anchor_description" msgid="8189074525698747223">"%d DP"</string>
 </resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ka/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ka/strings.xml
index d5cbb1b..f9f4e65 100644
--- a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ka/strings.xml
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ka/strings.xml
@@ -20,5 +20,4 @@
     <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"არეს გაფართოების სახელური ჩავლებისთვის"</string>
     <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"არეს გაყოფის შეცვლა %s-ით"</string>
     <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d პროცენტი"</string>
-    <string name="m3_adaptive_default_pane_expansion_offset_anchor_description" msgid="8189074525698747223">"%d DPs"</string>
 </resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ml/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ml/strings.xml
index 0747fcb..2b63179c 100644
--- a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ml/strings.xml
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ml/strings.xml
@@ -20,5 +20,4 @@
     <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"പെയിൻ വികസിപ്പിക്കാനായി വലിച്ചിടുന്നതിനുള്ള ഹാൻഡിൽ"</string>
     <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"പെയിൻ വിഭജനം %s ആയി മാറ്റുക"</string>
     <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d ശതമാനം"</string>
-    <string name="m3_adaptive_default_pane_expansion_offset_anchor_description" msgid="8189074525698747223">"%d DP-കൾ"</string>
 </resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ms/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ms/strings.xml
index 81f4fb8..889db66e 100644
--- a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ms/strings.xml
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ms/strings.xml
@@ -20,5 +20,4 @@
     <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Pemegang seret pengembangan anak tetingkap"</string>
     <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Tukar anak tetingkap terpisah kepada %s"</string>
     <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d peratus"</string>
-    <string name="m3_adaptive_default_pane_expansion_offset_anchor_description" msgid="8189074525698747223">"%d DP"</string>
 </resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-pl/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-pl/strings.xml
index 19a0cd0..ec85843 100644
--- a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-pl/strings.xml
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-pl/strings.xml
@@ -20,5 +20,4 @@
     <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Uchwyt do przeciągania panelu"</string>
     <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Zmień podział panelu na %s"</string>
     <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d procent"</string>
-    <string name="m3_adaptive_default_pane_expansion_offset_anchor_description" msgid="8189074525698747223">"%d DP"</string>
 </resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-pt-rPT/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-pt-rPT/strings.xml
index 2dae797..115f3c0 100644
--- a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-pt-rPT/strings.xml
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-pt-rPT/strings.xml
@@ -20,5 +20,4 @@
     <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Indicador para arrastar de expansão do painel"</string>
     <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Altere a divisão do painel para %s"</string>
     <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d por cento"</string>
-    <string name="m3_adaptive_default_pane_expansion_offset_anchor_description" msgid="8189074525698747223">"%d DPs"</string>
 </resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values/strings.xml
index 38b807f..94e3ffa 100644
--- a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values/strings.xml
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values/strings.xml
@@ -28,7 +28,14 @@
     <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description">
         %d percent
     </string>
-    <!-- Spoken description of a pane expansion anchor point based on offset in DPs a user can
-         anchor the pane expansion to. -->
-    <string name="m3_adaptive_default_pane_expansion_offset_anchor_description">%d DPs</string>
+    <!-- Spoken description of a pane expansion anchor point based on offset from start in DPs a
+         user can anchor the pane expansion to. -->
+    <string name="m3_adaptive_default_pane_expansion_start_offset_anchor_description">
+        %d DPs from start
+    </string>
+    <!-- Spoken description of a pane expansion anchor point based on offset from end in DPs a user
+         can anchor the pane expansion to. -->
+    <string name="m3_adaptive_default_pane_expansion_end_offset_anchor_description">
+        %d DPs from end
+    </string>
 </resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/commonMain/kotlin/androidx/compose/material3/adaptive/layout/PaneExpansionState.kt b/compose/material3/adaptive/adaptive-layout/src/commonMain/kotlin/androidx/compose/material3/adaptive/layout/PaneExpansionState.kt
index 0fce429..733dc1f 100644
--- a/compose/material3/adaptive/adaptive-layout/src/commonMain/kotlin/androidx/compose/material3/adaptive/layout/PaneExpansionState.kt
+++ b/compose/material3/adaptive/adaptive-layout/src/commonMain/kotlin/androidx/compose/material3/adaptive/layout/PaneExpansionState.kt
@@ -588,7 +588,10 @@
      * [PaneExpansionAnchor] implementation that specifies the anchor position in the proportion of
      * the total size of the layout at the start side of the anchor.
      *
-     * @property proportion the proportion of the layout at the start side of the anchor. layout.
+     * @param proportion the proportion of the layout at the start side of the anchor. For example,
+     *   if the current layout from the start to the end is list-detail, when the proportion value
+     *   is 0.3 and this anchor is used, the list pane will occupy 30% of the layout and the detail
+     *   pane will occupy 70% of it.
      */
     class Proportion(@FloatRange(0.0, 1.0) val proportion: Float) : PaneExpansionAnchor() {
         override val type = ProportionType
@@ -616,40 +619,107 @@
     }
 
     /**
-     * [PaneExpansionAnchor] implementation that specifies the anchor position in the offset in
-     * [Dp]. If a positive value is provided, the offset will be treated as a start offset, on the
-     * other hand, if a negative value is provided, the absolute value of the provided offset will
-     * be used as an end offset. For example, if -150.dp is provided, the resulted anchor will be at
-     * the position that is 150dp away from the end side of the associated layout.
+     * [PaneExpansionAnchor] implementation that specifies the anchor position based on the offset
+     * in [Dp].
      *
      * @property offset the offset of the anchor in [Dp].
      */
-    class Offset(val offset: Dp) : PaneExpansionAnchor() {
-        override val type = OffsetType
-
-        override val description
-            @Composable
-            get() =
-                getString(Strings.defaultPaneExpansionOffsetAnchorDescription, offset.value.toInt())
-
-        override fun positionIn(totalSizePx: Int, density: Density) =
-            with(density) { offset.roundToPx() }.let { if (it < 0) totalSizePx + it else it }
+    abstract class Offset internal constructor(val offset: Dp, override internal val type: Int) :
+        PaneExpansionAnchor() {
+        /**
+         * Indicates the direction of the offset.
+         *
+         * @see Direction.FromStart
+         * @see Direction.FromEnd
+         */
+        val direction: Direction = Direction(type)
 
         override fun equals(other: Any?): Boolean {
             if (this === other) return true
             if (other !is Offset) return false
-            return offset == other.offset
+            return offset == other.offset && direction == other.direction
         }
 
         override fun hashCode(): Int {
-            return offset.hashCode()
+            return offset.hashCode() * 31 + direction.hashCode()
+        }
+
+        /** Represents the direction from where the offset will be calculated. */
+        @JvmInline
+        value class Direction internal constructor(internal val value: Int) {
+            companion object {
+                /**
+                 * Indicates the offset will be calculated from the start. For example, if the
+                 * offset is 150.dp, the resulted anchor will be at the position that is 150dp away
+                 * from the start side of the associated layout.
+                 */
+                val FromStart = Direction(OffsetFromStartType)
+
+                /**
+                 * Indicates the offset will be calculated from the end. For example, if the offset
+                 * is 150.dp, the resulted anchor will be at the position that is 150dp away from
+                 * the end side of the associated layout.
+                 */
+                val FromEnd = Direction(OffsetFromEndType)
+            }
+        }
+
+        private class StartOffset(offset: Dp) : Offset(offset, OffsetFromStartType) {
+            override val description
+                @Composable
+                get() =
+                    getString(
+                        Strings.defaultPaneExpansionStartOffsetAnchorDescription,
+                        offset.value.toInt()
+                    )
+
+            override fun positionIn(totalSizePx: Int, density: Density) =
+                with(density) { offset.roundToPx() }
+        }
+
+        private class EndOffset(offset: Dp) : Offset(offset, OffsetFromEndType) {
+            override val description
+                @Composable
+                get() =
+                    getString(
+                        Strings.defaultPaneExpansionEndOffsetAnchorDescription,
+                        offset.value.toInt()
+                    )
+
+            override fun positionIn(totalSizePx: Int, density: Density) =
+                totalSizePx - with(density) { offset.roundToPx() }
+        }
+
+        companion object {
+            /**
+             * Create an [androidx.compose.material3.adaptive.layout.PaneExpansionAnchor.Offset]
+             * anchor from the start side of the layout.
+             *
+             * @param offset offset to be used in [Dp].
+             */
+            fun fromStart(offset: Dp): Offset {
+                require(offset >= 0.dp) { "Offset must larger than or equal to 0 dp." }
+                return StartOffset(offset)
+            }
+
+            /**
+             * Create an [androidx.compose.material3.adaptive.layout.PaneExpansionAnchor.Offset]
+             * anchor from the end side of the layout.
+             *
+             * @param offset offset to be used in [Dp].
+             */
+            fun fromEnd(offset: Dp): Offset {
+                require(offset >= 0.dp) { "Offset must larger than or equal to 0 dp." }
+                return EndOffset(offset)
+            }
         }
     }
 
     internal companion object {
         internal const val UnspecifiedType = 0
         internal const val ProportionType = 1
-        internal const val OffsetType = 2
+        internal const val OffsetFromStartType = 2
+        internal const val OffsetFromEndType = 3
     }
 }
 
@@ -725,8 +795,10 @@
                 when (currentAnchorType) {
                     PaneExpansionAnchor.ProportionType ->
                         PaneExpansionAnchor.Proportion(it[6] as Float)
-                    PaneExpansionAnchor.OffsetType ->
-                        PaneExpansionAnchor.Offset((it[6] as Float).dp)
+                    PaneExpansionAnchor.OffsetFromStartType ->
+                        PaneExpansionAnchor.Offset.fromStart((it[6] as Float).dp)
+                    PaneExpansionAnchor.OffsetFromEndType ->
+                        PaneExpansionAnchor.Offset.fromEnd((it[6] as Float).dp)
                     else -> null
                 }
             object : Map.Entry<PaneExpansionStateKey, PaneExpansionStateData> {
diff --git a/compose/material3/adaptive/adaptive-layout/src/commonMain/kotlin/androidx/compose/material3/adaptive/layout/Strings.kt b/compose/material3/adaptive/adaptive-layout/src/commonMain/kotlin/androidx/compose/material3/adaptive/layout/Strings.kt
index 4ff2966..e11af66 100644
--- a/compose/material3/adaptive/adaptive-layout/src/commonMain/kotlin/androidx/compose/material3/adaptive/layout/Strings.kt
+++ b/compose/material3/adaptive/adaptive-layout/src/commonMain/kotlin/androidx/compose/material3/adaptive/layout/Strings.kt
@@ -27,7 +27,8 @@
         val defaultPaneExpansionDragHandleContentDescription: Strings
         val defaultPaneExpansionDragHandleActionDescription: Strings
         val defaultPaneExpansionProportionAnchorDescription: Strings
-        val defaultPaneExpansionOffsetAnchorDescription: Strings
+        val defaultPaneExpansionStartOffsetAnchorDescription: Strings
+        val defaultPaneExpansionEndOffsetAnchorDescription: Strings
     }
 }
 
diff --git a/compose/material3/adaptive/adaptive-layout/src/jvmStubsMain/kotlin/androidx/compose/material3/adaptive/layout/Strings.jvmStubs.kt b/compose/material3/adaptive/adaptive-layout/src/jvmStubsMain/kotlin/androidx/compose/material3/adaptive/layout/Strings.jvmStubs.kt
index a419136..11184b6 100644
--- a/compose/material3/adaptive/adaptive-layout/src/jvmStubsMain/kotlin/androidx/compose/material3/adaptive/layout/Strings.jvmStubs.kt
+++ b/compose/material3/adaptive/adaptive-layout/src/jvmStubsMain/kotlin/androidx/compose/material3/adaptive/layout/Strings.jvmStubs.kt
@@ -39,7 +39,9 @@
             implementedInJetBrainsFork()
         actual val defaultPaneExpansionProportionAnchorDescription: Strings =
             implementedInJetBrainsFork()
-        actual val defaultPaneExpansionOffsetAnchorDescription: Strings =
+        actual val defaultPaneExpansionStartOffsetAnchorDescription: Strings =
+            implementedInJetBrainsFork()
+        actual val defaultPaneExpansionEndOffsetAnchorDescription: Strings =
             implementedInJetBrainsFork()
     }
 }
diff --git a/compose/material3/adaptive/samples/src/main/java/androidx/compose/material3/adaptive/samples/ThreePaneScaffoldSample.kt b/compose/material3/adaptive/samples/src/main/java/androidx/compose/material3/adaptive/samples/ThreePaneScaffoldSample.kt
index 798e57e..5181bf1 100644
--- a/compose/material3/adaptive/samples/src/main/java/androidx/compose/material3/adaptive/samples/ThreePaneScaffoldSample.kt
+++ b/compose/material3/adaptive/samples/src/main/java/androidx/compose/material3/adaptive/samples/ThreePaneScaffoldSample.kt
@@ -438,8 +438,8 @@
 private val PaneExpansionAnchors =
     listOf(
         PaneExpansionAnchor.Proportion(0f),
-        PaneExpansionAnchor.Proportion(0.25f),
+        PaneExpansionAnchor.Offset.fromStart(360.dp),
         PaneExpansionAnchor.Proportion(0.5f),
-        PaneExpansionAnchor.Proportion(0.75f),
+        PaneExpansionAnchor.Offset.fromEnd(360.dp),
         PaneExpansionAnchor.Proportion(1f),
     )
diff --git a/lifecycle/lifecycle-viewmodel-navigation3/api/current.txt b/lifecycle/lifecycle-viewmodel-navigation3/api/current.txt
index b6bdb70..cdddc41 100644
--- a/lifecycle/lifecycle-viewmodel-navigation3/api/current.txt
+++ b/lifecycle/lifecycle-viewmodel-navigation3/api/current.txt
@@ -1,10 +1,10 @@
 // Signature format: 4.0
 package androidx.lifecycle.viewmodel.navigation3 {
 
-  public final class ViewModelStoreNavContentWrapper implements androidx.navigation3.NavContentWrapper {
-    method @androidx.compose.runtime.Composable public void WrapBackStack(java.util.List<?> backStack);
-    method @androidx.compose.runtime.Composable public <T> void WrapContent(androidx.navigation3.NavRecord<T> record);
-    field public static final androidx.lifecycle.viewmodel.navigation3.ViewModelStoreNavContentWrapper INSTANCE;
+  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 <T> void ProvideToRecord(androidx.navigation3.NavRecord<T> record);
+    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 b6bdb70..cdddc41 100644
--- a/lifecycle/lifecycle-viewmodel-navigation3/api/restricted_current.txt
+++ b/lifecycle/lifecycle-viewmodel-navigation3/api/restricted_current.txt
@@ -1,10 +1,10 @@
 // Signature format: 4.0
 package androidx.lifecycle.viewmodel.navigation3 {
 
-  public final class ViewModelStoreNavContentWrapper implements androidx.navigation3.NavContentWrapper {
-    method @androidx.compose.runtime.Composable public void WrapBackStack(java.util.List<?> backStack);
-    method @androidx.compose.runtime.Composable public <T> void WrapContent(androidx.navigation3.NavRecord<T> record);
-    field public static final androidx.lifecycle.viewmodel.navigation3.ViewModelStoreNavContentWrapper INSTANCE;
+  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 <T> void ProvideToRecord(androidx.navigation3.NavRecord<T> record);
+    field public static final androidx.lifecycle.viewmodel.navigation3.ViewModelStoreNavLocalProvider INSTANCE;
   }
 
 }
diff --git a/lifecycle/lifecycle-viewmodel-navigation3/src/androidInstrumentedTest/kotlin/androidx/lifecycle/viewmodel/navigation3/ViewModelStoreNavContentWrapperTest.kt b/lifecycle/lifecycle-viewmodel-navigation3/src/androidInstrumentedTest/kotlin/androidx/lifecycle/viewmodel/navigation3/ViewModelStoreNavContentWrapperTest.kt
index f0efd6c..702fd5e 100644
--- a/lifecycle/lifecycle-viewmodel-navigation3/src/androidInstrumentedTest/kotlin/androidx/lifecycle/viewmodel/navigation3/ViewModelStoreNavContentWrapperTest.kt
+++ b/lifecycle/lifecycle-viewmodel-navigation3/src/androidInstrumentedTest/kotlin/androidx/lifecycle/viewmodel/navigation3/ViewModelStoreNavContentWrapperTest.kt
@@ -27,8 +27,7 @@
 import androidx.lifecycle.viewmodel.compose.viewModel
 import androidx.navigation3.NavDisplay
 import androidx.navigation3.NavRecord
-import androidx.navigation3.SavedStateNavContentWrapper
-import androidx.navigation3.rememberNavWrapperManager
+import androidx.navigation3.SavedStateNavLocalProvider
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
 import kotlin.test.Test
@@ -37,13 +36,13 @@
 
 @LargeTest
 @RunWith(AndroidJUnit4::class)
-class ViewModelStoreNavContentWrapperTest {
+class ViewModelStoreNavLocalProviderTest {
     @get:Rule val composeTestRule = createComposeRule()
 
     @Test
     fun testViewModelProvided() {
-        val savedStateWrapper = SavedStateNavContentWrapper
-        val viewModelWrapper = ViewModelStoreNavContentWrapper
+        val savedStateWrapper = SavedStateNavLocalProvider
+        val viewModelWrapper = ViewModelStoreNavLocalProvider
         lateinit var viewModel1: MyViewModel
         lateinit var viewModel2: MyViewModel
         val record1Arg = "record1 Arg"
@@ -59,11 +58,11 @@
                 viewModel2.myArg = record2Arg
             }
         composeTestRule.setContent {
-            savedStateWrapper.WrapContent(
-                NavRecord(record1.key) { viewModelWrapper.WrapContent(record1) }
+            savedStateWrapper.ProvideToRecord(
+                NavRecord(record1.key) { viewModelWrapper.ProvideToRecord(record1) }
             )
-            savedStateWrapper.WrapContent(
-                NavRecord(record2.key) { viewModelWrapper.WrapContent(record2) }
+            savedStateWrapper.ProvideToRecord(
+                NavRecord(record2.key) { viewModelWrapper.ProvideToRecord(record2) }
             )
         }
 
@@ -78,8 +77,8 @@
     }
 
     @Test
-    fun testViewModelNoSavedStateNavContentWrapper() {
-        val viewModelWrapper = ViewModelStoreNavContentWrapper
+    fun testViewModelNoSavedStateNavLocalProvider() {
+        val viewModelWrapper = ViewModelStoreNavLocalProvider
         lateinit var viewModel1: MyViewModel
         val record1Arg = "record1 Arg"
         val record1 =
@@ -88,14 +87,14 @@
                 viewModel1.myArg = record1Arg
             }
         try {
-            composeTestRule.setContent { viewModelWrapper.WrapContent(record1) }
+            composeTestRule.setContent { viewModelWrapper.ProvideToRecord(record1) }
         } catch (e: Exception) {
             assertThat(e)
                 .hasMessageThat()
                 .isEqualTo(
                     "The Lifecycle state is already beyond INITIALIZED. The " +
-                        "ViewModelStoreNavContentWrapper requires adding the " +
-                        "SavedStateNavContentWrapper to ensure support for " +
+                        "ViewModelStoreNavLocalProvider requires adding the " +
+                        "SavedStateNavLocalProvider to ensure support for " +
                         "SavedStateHandles."
                 )
         }
@@ -106,13 +105,9 @@
         lateinit var backStack: MutableList<Any>
         composeTestRule.setContent {
             backStack = remember { mutableStateListOf("Home") }
-            val manager =
-                rememberNavWrapperManager(
-                    listOf(SavedStateNavContentWrapper, ViewModelStoreNavContentWrapper)
-                )
             NavDisplay(
                 backstack = backStack,
-                wrapperManager = manager,
+                localProviders = listOf(SavedStateNavLocalProvider, ViewModelStoreNavLocalProvider),
                 onBack = { backStack.removeAt(backStack.lastIndex) },
             ) { key ->
                 when (key) {
@@ -160,13 +155,9 @@
         lateinit var viewModel: SavedStateViewModel
         composeTestRule.setContent {
             backStack = remember { mutableStateListOf("Home") }
-            val manager =
-                rememberNavWrapperManager(
-                    listOf(SavedStateNavContentWrapper, ViewModelStoreNavContentWrapper)
-                )
             NavDisplay(
                 backstack = backStack,
-                wrapperManager = manager,
+                localProviders = listOf(SavedStateNavLocalProvider, ViewModelStoreNavLocalProvider),
                 onBack = { backStack.removeAt(backStack.lastIndex) },
             ) { key ->
                 when (key) {
diff --git a/lifecycle/lifecycle-viewmodel-navigation3/src/androidMain/kotlin/androidx/lifecycle/viewmodel/navigation3/ViewModelStoreNavContentWrapper.android.kt b/lifecycle/lifecycle-viewmodel-navigation3/src/androidMain/kotlin/androidx/lifecycle/viewmodel/navigation3/ViewModelStoreNavContentWrapper.android.kt
index 79402711..95d9e3d 100644
--- a/lifecycle/lifecycle-viewmodel-navigation3/src/androidMain/kotlin/androidx/lifecycle/viewmodel/navigation3/ViewModelStoreNavContentWrapper.android.kt
+++ b/lifecycle/lifecycle-viewmodel-navigation3/src/androidMain/kotlin/androidx/lifecycle/viewmodel/navigation3/ViewModelStoreNavContentWrapper.android.kt
@@ -35,7 +35,7 @@
 import androidx.lifecycle.viewmodel.MutableCreationExtras
 import androidx.lifecycle.viewmodel.compose.LocalViewModelStoreOwner
 import androidx.lifecycle.viewmodel.compose.viewModel
-import androidx.navigation3.NavContentWrapper
+import androidx.navigation3.NavLocalProvider
 import androidx.navigation3.NavRecord
 import androidx.savedstate.SavedStateRegistryOwner
 import androidx.savedstate.compose.LocalSavedStateRegistryOwner
@@ -44,20 +44,20 @@
  * Provides the content of a [NavRecord] with a [ViewModelStoreOwner] and provides that
  * [ViewModelStoreOwner] as a [LocalViewModelStoreOwner] so that it is available within the content.
  *
- * This requires that usage of the [SavedStateNavContentWrapper] to ensure that the [NavRecord]
+ * This requires that usage of the [SavedStateNavLocalProvider] to ensure that the [NavRecord]
  * scoped [ViewModel]s can properly provide access to [SavedStateHandle]s
  */
-public object ViewModelStoreNavContentWrapper : NavContentWrapper {
+public object ViewModelStoreNavLocalProvider : NavLocalProvider {
 
     @Composable
-    override fun WrapBackStack(backStack: List<Any>) {
+    override fun ProvideToBackStack(backStack: List<Any>) {
         val recordViewModelStoreProvider = viewModel { RecordViewModel() }
         recordViewModelStoreProvider.ownerInBackStack.clear()
         recordViewModelStoreProvider.ownerInBackStack.addAll(backStack)
     }
 
     @Composable
-    override fun <T : Any> WrapContent(record: NavRecord<T>) {
+    override fun <T : Any> ProvideToRecord(record: NavRecord<T>) {
         val key = record.key
         val recordViewModelStoreProvider = viewModel { RecordViewModel() }
         val viewModelStore = recordViewModelStoreProvider.viewModelStoreForKey(key)
@@ -110,8 +110,8 @@
                     init {
                         require(this.lifecycle.currentState == Lifecycle.State.INITIALIZED) {
                             "The Lifecycle state is already beyond INITIALIZED. The " +
-                                "ViewModelStoreNavContentWrapper requires adding the " +
-                                "SavedStateNavContentWrapper to ensure support for " +
+                                "ViewModelStoreNavLocalProvider requires adding the " +
+                                "SavedStateNavLocalProvider to ensure support for " +
                                 "SavedStateHandles."
                         }
                         enableSavedStateHandles()
diff --git a/navigation3/navigation3/api/current.txt b/navigation3/navigation3/api/current.txt
index ec7e433..1c23099 100644
--- a/navigation3/navigation3/api/current.txt
+++ b/navigation3/navigation3/api/current.txt
@@ -1,11 +1,6 @@
 // Signature format: 4.0
 package androidx.navigation3 {
 
-  public interface NavContentWrapper {
-    method @androidx.compose.runtime.Composable public default void WrapBackStack(java.util.List<?> backStack);
-    method @androidx.compose.runtime.Composable public <T> void WrapContent(androidx.navigation3.NavRecord<T> record);
-  }
-
   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> transition(androidx.compose.animation.EnterTransition? enter, androidx.compose.animation.ExitTransition? exit);
@@ -13,7 +8,12 @@
   }
 
   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 androidx.navigation3.NavWrapperManager wrapperManager, 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.NavRecord<? extends T>> recordProvider);
+    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.NavRecord<? extends T>> recordProvider);
+  }
+
+  public interface NavLocalProvider {
+    method @androidx.compose.runtime.Composable public default void ProvideToBackStack(java.util.List<?> backStack);
+    method @androidx.compose.runtime.Composable public <T> void ProvideToRecord(androidx.navigation3.NavRecord<T> record);
   }
 
   public final class NavRecord<T> {
@@ -28,13 +28,13 @@
 
   public final class NavWrapperManager {
     ctor public NavWrapperManager();
-    ctor public NavWrapperManager(optional java.util.List<? extends androidx.navigation3.NavContentWrapper> navContentWrappers);
+    ctor public NavWrapperManager(optional java.util.List<? extends androidx.navigation3.NavLocalProvider> navLocalProviders);
     method @androidx.compose.runtime.Composable public <T> void ContentForRecord(androidx.navigation3.NavRecord<T> record);
     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.NavContentWrapper> navContentWrappers);
+    method @androidx.compose.runtime.Composable public static androidx.navigation3.NavWrapperManager rememberNavWrapperManager(java.util.List<? extends androidx.navigation3.NavLocalProvider> navLocalProviders);
   }
 
   public final class RecordClassProvider<T> {
@@ -81,14 +81,14 @@
     method public static inline kotlin.jvm.functions.Function1<java.lang.Object,androidx.navigation3.NavRecord<? extends java.lang.Object?>> recordProvider(optional kotlin.jvm.functions.Function1<java.lang.Object,? extends androidx.navigation3.NavRecord<? extends java.lang.Object?>> fallback, kotlin.jvm.functions.Function1<? super androidx.navigation3.RecordProviderBuilder,kotlin.Unit> builder);
   }
 
-  public final class SaveableStateNavContentWrapper implements androidx.navigation3.NavContentWrapper {
-    ctor public SaveableStateNavContentWrapper();
-    method @androidx.compose.runtime.Composable public <T> void WrapContent(androidx.navigation3.NavRecord<T> record);
+  public final class SaveableStateNavLocalProvider implements androidx.navigation3.NavLocalProvider {
+    ctor public SaveableStateNavLocalProvider();
+    method @androidx.compose.runtime.Composable public <T> void ProvideToRecord(androidx.navigation3.NavRecord<T> record);
   }
 
-  public final class SavedStateNavContentWrapper implements androidx.navigation3.NavContentWrapper {
-    method @androidx.compose.runtime.Composable public <T> void WrapContent(androidx.navigation3.NavRecord<T> record);
-    field public static final androidx.navigation3.SavedStateNavContentWrapper INSTANCE;
+  public final class SavedStateNavLocalProvider implements androidx.navigation3.NavLocalProvider {
+    method @androidx.compose.runtime.Composable public <T> void ProvideToRecord(androidx.navigation3.NavRecord<T> record);
+    field public static final androidx.navigation3.SavedStateNavLocalProvider INSTANCE;
   }
 
 }
diff --git a/navigation3/navigation3/api/restricted_current.txt b/navigation3/navigation3/api/restricted_current.txt
index ec7e433..1c23099 100644
--- a/navigation3/navigation3/api/restricted_current.txt
+++ b/navigation3/navigation3/api/restricted_current.txt
@@ -1,11 +1,6 @@
 // Signature format: 4.0
 package androidx.navigation3 {
 
-  public interface NavContentWrapper {
-    method @androidx.compose.runtime.Composable public default void WrapBackStack(java.util.List<?> backStack);
-    method @androidx.compose.runtime.Composable public <T> void WrapContent(androidx.navigation3.NavRecord<T> record);
-  }
-
   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> transition(androidx.compose.animation.EnterTransition? enter, androidx.compose.animation.ExitTransition? exit);
@@ -13,7 +8,12 @@
   }
 
   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 androidx.navigation3.NavWrapperManager wrapperManager, 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.NavRecord<? extends T>> recordProvider);
+    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.NavRecord<? extends T>> recordProvider);
+  }
+
+  public interface NavLocalProvider {
+    method @androidx.compose.runtime.Composable public default void ProvideToBackStack(java.util.List<?> backStack);
+    method @androidx.compose.runtime.Composable public <T> void ProvideToRecord(androidx.navigation3.NavRecord<T> record);
   }
 
   public final class NavRecord<T> {
@@ -28,13 +28,13 @@
 
   public final class NavWrapperManager {
     ctor public NavWrapperManager();
-    ctor public NavWrapperManager(optional java.util.List<? extends androidx.navigation3.NavContentWrapper> navContentWrappers);
+    ctor public NavWrapperManager(optional java.util.List<? extends androidx.navigation3.NavLocalProvider> navLocalProviders);
     method @androidx.compose.runtime.Composable public <T> void ContentForRecord(androidx.navigation3.NavRecord<T> record);
     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.NavContentWrapper> navContentWrappers);
+    method @androidx.compose.runtime.Composable public static androidx.navigation3.NavWrapperManager rememberNavWrapperManager(java.util.List<? extends androidx.navigation3.NavLocalProvider> navLocalProviders);
   }
 
   public final class RecordClassProvider<T> {
@@ -81,14 +81,14 @@
     method public static inline kotlin.jvm.functions.Function1<java.lang.Object,androidx.navigation3.NavRecord<? extends java.lang.Object?>> recordProvider(optional kotlin.jvm.functions.Function1<java.lang.Object,? extends androidx.navigation3.NavRecord<? extends java.lang.Object?>> fallback, kotlin.jvm.functions.Function1<? super androidx.navigation3.RecordProviderBuilder,kotlin.Unit> builder);
   }
 
-  public final class SaveableStateNavContentWrapper implements androidx.navigation3.NavContentWrapper {
-    ctor public SaveableStateNavContentWrapper();
-    method @androidx.compose.runtime.Composable public <T> void WrapContent(androidx.navigation3.NavRecord<T> record);
+  public final class SaveableStateNavLocalProvider implements androidx.navigation3.NavLocalProvider {
+    ctor public SaveableStateNavLocalProvider();
+    method @androidx.compose.runtime.Composable public <T> void ProvideToRecord(androidx.navigation3.NavRecord<T> record);
   }
 
-  public final class SavedStateNavContentWrapper implements androidx.navigation3.NavContentWrapper {
-    method @androidx.compose.runtime.Composable public <T> void WrapContent(androidx.navigation3.NavRecord<T> record);
-    field public static final androidx.navigation3.SavedStateNavContentWrapper INSTANCE;
+  public final class SavedStateNavLocalProvider implements androidx.navigation3.NavLocalProvider {
+    method @androidx.compose.runtime.Composable public <T> void ProvideToRecord(androidx.navigation3.NavRecord<T> record);
+    field public static final androidx.navigation3.SavedStateNavLocalProvider INSTANCE;
   }
 
 }
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 fa6ff47..3ed2eae 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
@@ -23,13 +23,12 @@
 import androidx.compose.runtime.Composable
 import androidx.lifecycle.ViewModel
 import androidx.lifecycle.viewmodel.compose.viewModel
-import androidx.lifecycle.viewmodel.navigation3.ViewModelStoreNavContentWrapper
+import androidx.lifecycle.viewmodel.navigation3.ViewModelStoreNavLocalProvider
 import androidx.navigation3.NavDisplay
 import androidx.navigation3.NavRecord
-import androidx.navigation3.SavedStateNavContentWrapper
+import androidx.navigation3.SavedStateNavLocalProvider
 import androidx.navigation3.record
 import androidx.navigation3.recordProvider
-import androidx.navigation3.rememberNavWrapperManager
 
 class ProfileViewModel : ViewModel() {
     val name = "no user"
@@ -39,13 +38,9 @@
 @Composable
 fun BaseNav() {
     val backStack = rememberMutableStateListOf(Profile)
-    val manager =
-        rememberNavWrapperManager(
-            listOf(SavedStateNavContentWrapper, ViewModelStoreNavContentWrapper)
-        )
     NavDisplay(
         backstack = backStack,
-        wrapperManager = manager,
+        localProviders = listOf(SavedStateNavLocalProvider, ViewModelStoreNavLocalProvider),
         onBack = { backStack.removeLast() },
         recordProvider =
             recordProvider({ NavRecord(Unit) { Text(text = "Invalid Key") } }) {
diff --git a/navigation3/navigation3/src/androidInstrumentedTest/kotlin/androidx/navigation3/NavDisplayTest.kt b/navigation3/navigation3/src/androidInstrumentedTest/kotlin/androidx/navigation3/NavDisplayTest.kt
index 584873a..c2b34e8 100644
--- a/navigation3/navigation3/src/androidInstrumentedTest/kotlin/androidx/navigation3/NavDisplayTest.kt
+++ b/navigation3/navigation3/src/androidInstrumentedTest/kotlin/androidx/navigation3/NavDisplayTest.kt
@@ -166,8 +166,7 @@
         composeTestRule.setContent {
             mainRegistry = LocalSavedStateRegistryOwner.current.savedStateRegistry
             backstack = remember { mutableStateListOf(first) }
-            val manager = rememberNavWrapperManager(listOf(SavedStateNavContentWrapper))
-            NavDisplay(backstack = backstack, wrapperManager = manager) {
+            NavDisplay(backstack = backstack, localProviders = listOf(SavedStateNavLocalProvider)) {
                 when (it) {
                     first ->
                         NavRecord(first) {
diff --git a/navigation3/navigation3/src/androidInstrumentedTest/kotlin/androidx/navigation3/NavWrapperManagerTest.kt b/navigation3/navigation3/src/androidInstrumentedTest/kotlin/androidx/navigation3/NavWrapperManagerTest.kt
index be41543..4481373 100644
--- a/navigation3/navigation3/src/androidInstrumentedTest/kotlin/androidx/navigation3/NavWrapperManagerTest.kt
+++ b/navigation3/navigation3/src/androidInstrumentedTest/kotlin/androidx/navigation3/NavWrapperManagerTest.kt
@@ -35,14 +35,14 @@
         var calledWrapBackStack = false
         var calledWrapContent = false
         val wrapper =
-            object : NavContentWrapper {
+            object : NavLocalProvider {
                 @Composable
-                override fun WrapBackStack(backStack: List<Any>) {
+                override fun ProvideToBackStack(backStack: List<Any>) {
                     calledWrapBackStack = true
                 }
 
                 @Composable
-                override fun <T : Any> WrapContent(record: NavRecord<T>) {
+                override fun <T : Any> ProvideToRecord(record: NavRecord<T>) {
                     calledWrapContent = true
                 }
             }
@@ -63,14 +63,14 @@
         var calledWrapBackStackCount = 0
         var calledWrapContentCount = 0
         val wrapper =
-            object : NavContentWrapper {
+            object : NavLocalProvider {
                 @Composable
-                override fun WrapBackStack(backStack: List<Any>) {
+                override fun ProvideToBackStack(backStack: List<Any>) {
                     calledWrapBackStackCount++
                 }
 
                 @Composable
-                override fun <T : Any> WrapContent(record: NavRecord<T>) {
+                override fun <T : Any> ProvideToRecord(record: NavRecord<T>) {
                     calledWrapContentCount++
                 }
             }
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 37179b2..3aba31e 100644
--- a/navigation3/navigation3/src/androidMain/kotlin/androidx/navigation3/NavDisplay.android.kt
+++ b/navigation3/navigation3/src/androidMain/kotlin/androidx/navigation3/NavDisplay.android.kt
@@ -64,7 +64,7 @@
  * the second to last key is a displayed in the background.
  *
  * @param backstack the collection of keys that represents the state that needs to be handled
- * @param wrapperManager the manager that combines all of the [NavContentWrapper]s
+ * @param localProviders list of [NavLocalProvider] to add information to the provided records
  * @param modifier the modifier to be applied to the layout.
  * @param contentAlignment The [Alignment] of the [AnimatedContent]
  *     * @param enterTransition Default [EnterTransition] for all [NavRecord]s. Can be overridden
@@ -82,7 +82,7 @@
 public fun <T : Any> NavDisplay(
     backstack: List<T>,
     modifier: Modifier = Modifier,
-    wrapperManager: NavWrapperManager = rememberNavWrapperManager(emptyList()),
+    localProviders: List<NavLocalProvider> = emptyList(),
     contentAlignment: Alignment = Alignment.TopStart,
     sizeTransform: SizeTransform? = null,
     enterTransition: EnterTransition =
@@ -104,6 +104,7 @@
 ) {
     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()
diff --git a/navigation3/navigation3/src/commonMain/kotlin/androidx/navigation3/NavContentWrapper.kt b/navigation3/navigation3/src/commonMain/kotlin/androidx/navigation3/NavLocalProvider.kt
similarity index 73%
rename from navigation3/navigation3/src/commonMain/kotlin/androidx/navigation3/NavContentWrapper.kt
rename to navigation3/navigation3/src/commonMain/kotlin/androidx/navigation3/NavLocalProvider.kt
index 42d1652..f8456cd 100644
--- a/navigation3/navigation3/src/commonMain/kotlin/androidx/navigation3/NavContentWrapper.kt
+++ b/navigation3/navigation3/src/commonMain/kotlin/androidx/navigation3/NavLocalProvider.kt
@@ -22,23 +22,23 @@
  * Interface that offers the ability to provide information to some Composable content that is
  * integrated with a [NavDisplay](reference/androidx/navigation/NavDisplay).
  *
- * Information can be provided to the entire back stack via [NavContentWrapper.WrapBackStack] or to
- * a single record via [NavContentWrapper.WrapContent].
+ * Information can be provided to the entire back stack via [NavLocalProvider.ProvideToBackStack] or
+ * to a single record via [NavLocalProvider.ProvideToRecord].
  */
-public interface NavContentWrapper {
+public interface NavLocalProvider {
 
     /**
-     * Allows a [NavContentWrapper] to execute on the entire backstack.
+     * Allows a [NavLocalProvider] to provide to the entire backstack.
      *
      * This function is called by the [NavWrapperManager] and should not be called directly.
      */
-    @Composable public fun WrapBackStack(backStack: List<Any>): Unit = Unit
+    @Composable public fun ProvideToBackStack(backStack: List<Any>): Unit = Unit
 
     /**
-     * Allows a [NavContentWrapper] to provide information to the content of a single record.
+     * Allows a [NavLocalProvider] to provide information to a single record.
      *
      * This function is called by the [NavDisplay](reference/androidx/navigation/NavDisplay) and
      * should not be called directly.
      */
-    @Composable public fun <T : Any> WrapContent(record: NavRecord<T>)
+    @Composable public fun <T : Any> ProvideToRecord(record: NavRecord<T>)
 }
diff --git a/navigation3/navigation3/src/commonMain/kotlin/androidx/navigation3/NavWrapperManager.kt b/navigation3/navigation3/src/commonMain/kotlin/androidx/navigation3/NavWrapperManager.kt
index 4a137df..38eb9f8 100644
--- a/navigation3/navigation3/src/commonMain/kotlin/androidx/navigation3/NavWrapperManager.kt
+++ b/navigation3/navigation3/src/commonMain/kotlin/androidx/navigation3/NavWrapperManager.kt
@@ -19,45 +19,43 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.remember
 
-/** Creates a [NavContentWrapper]. */
+/** Creates a [NavLocalProvider]. */
 @Composable
-public fun rememberNavWrapperManager(
-    navContentWrappers: List<NavContentWrapper>
-): NavWrapperManager {
-    return remember { NavWrapperManager(navContentWrappers) }
+public fun rememberNavWrapperManager(navLocalProviders: List<NavLocalProvider>): NavWrapperManager {
+    return remember { NavWrapperManager(navLocalProviders) }
 }
 
 /**
- * Class that manages all of the provided [NavContentWrapper]. It is responsible for executing the
- * functions provided by each [NavContentWrapper] appropriately.
+ * 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 [NavContentWrapper]s are added to the list determines their scope,
- * i.e. a [NavContentWrapper] added earlier in a list has its data available to those added later.
+ * 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 navContentWrappers the [NavContentWrapper]s that are providing data to the content
+ * @param navLocalProviders the [NavLocalProvider]s that are providing data to the content
  */
-public class NavWrapperManager(navContentWrappers: List<NavContentWrapper> = emptyList()) {
+public class NavWrapperManager(navLocalProviders: List<NavLocalProvider> = emptyList()) {
     /**
-     * Final list of wrappers. This always adds a [SaveableStateNavContentWrapper] by default, as it
+     * 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 =
-        (navContentWrappers + listOf(SaveableStateNavContentWrapper())).distinct()
+        (navLocalProviders + listOf(SaveableStateNavLocalProvider())).distinct()
 
     /**
-     * Calls the [NavContentWrapper.WrapBackStack] functions on each wrapper
+     * 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.WrapBackStack(backStack = backStack) }
+        finalWrappers.distinct().forEach { it.ProvideToBackStack(backStack = backStack) }
     }
 
     /**
-     * Calls the [NavContentWrapper.WrapContent] functions on each wrapper.
+     * Calls the [NavLocalProvider.ProvideToRecord] functions on each wrapper.
      *
      * This function is called by the [NavDisplay](reference/androidx/navigation/NavDisplay) and
      * should not be called directly.
@@ -68,7 +66,11 @@
         finalWrappers
             .distinct()
             .foldRight(record.content) { wrapper, contentLambda ->
-                { wrapper.WrapContent(NavRecord(key, record.featureMap, content = contentLambda)) }
+                {
+                    wrapper.ProvideToRecord(
+                        NavRecord(key, record.featureMap, content = contentLambda)
+                    )
+                }
             }
             .invoke(key)
     }
diff --git a/navigation3/navigation3/src/commonMain/kotlin/androidx/navigation3/SaveableStateNavContentWrapper.kt b/navigation3/navigation3/src/commonMain/kotlin/androidx/navigation3/SaveableStateNavLocalProvider.kt
similarity index 90%
rename from navigation3/navigation3/src/commonMain/kotlin/androidx/navigation3/SaveableStateNavContentWrapper.kt
rename to navigation3/navigation3/src/commonMain/kotlin/androidx/navigation3/SaveableStateNavLocalProvider.kt
index 9c6443f..ce143cd 100644
--- a/navigation3/navigation3/src/commonMain/kotlin/androidx/navigation3/SaveableStateNavContentWrapper.kt
+++ b/navigation3/navigation3/src/commonMain/kotlin/androidx/navigation3/SaveableStateNavLocalProvider.kt
@@ -27,16 +27,16 @@
  * Wraps the content of a [NavRecord] with a [SaveableStateHolder.SaveableStateProvider] to ensure
  * that calls to [rememberSaveable] within the content work properly and that state can be saved.
  *
- * This [NavContentWrapper] is the only one that is **required** as saving state is considered a
+ * This [NavLocalProvider] is the only one that is **required** as saving state is considered a
  * non-optional feature.
  */
-public class SaveableStateNavContentWrapper : NavContentWrapper {
+public class SaveableStateNavLocalProvider : NavLocalProvider {
     private var savedStateHolder: SaveableStateHolder? = null
     private val refCount: MutableObjectIntMap<Any> = MutableObjectIntMap()
     private var backstackSize = 0
 
     @Composable
-    override fun WrapBackStack(backStack: List<Any>) {
+    override fun ProvideToBackStack(backStack: List<Any>) {
         DisposableEffect(key1 = backStack) {
             refCount.clear()
             onDispose {}
@@ -56,7 +56,7 @@
                                 .getOrElse(key) {
                                     error(
                                         "Attempting to incorrectly dispose of backstack state in " +
-                                            "SaveableStateNavContentWrapper"
+                                            "SaveableStateNavLocalProvider"
                                     )
                                 }
                                 .minus(1)
@@ -67,7 +67,7 @@
     }
 
     @Composable
-    public override fun <T : Any> WrapContent(record: NavRecord<T>) {
+    public override fun <T : Any> ProvideToRecord(record: NavRecord<T>) {
         val key = record.key
         DisposableEffect(key1 = key) {
             refCount[key] = refCount.getOrDefault(key, 0).plus(1)
@@ -85,7 +85,7 @@
                             .getOrElse(key) {
                                 error(
                                     "Attempting to incorrectly dispose of state associated with " +
-                                        "key $key in SaveableStateNavContentWrapper"
+                                        "key $key in SaveableStateNavLocalProvider"
                                 )
                             }
                             .minus(1)
diff --git a/navigation3/navigation3/src/commonMain/kotlin/androidx/navigation3/SavedStateNavContentWrapper.kt b/navigation3/navigation3/src/commonMain/kotlin/androidx/navigation3/SavedStateNavLocalProvider.kt
similarity index 95%
rename from navigation3/navigation3/src/commonMain/kotlin/androidx/navigation3/SavedStateNavContentWrapper.kt
rename to navigation3/navigation3/src/commonMain/kotlin/androidx/navigation3/SavedStateNavLocalProvider.kt
index c651c3d..4676d82 100644
--- a/navigation3/navigation3/src/commonMain/kotlin/androidx/navigation3/SavedStateNavContentWrapper.kt
+++ b/navigation3/navigation3/src/commonMain/kotlin/androidx/navigation3/SavedStateNavLocalProvider.kt
@@ -37,10 +37,10 @@
  * [SavedStateRegistryOwner] as a [LocalSavedStateRegistryOwner] so that it is available within the
  * content.
  */
-public object SavedStateNavContentWrapper : NavContentWrapper {
+public object SavedStateNavLocalProvider : NavLocalProvider {
 
     @Composable
-    override fun <T : Any> WrapContent(record: NavRecord<T>) {
+    override fun <T : Any> ProvideToRecord(record: NavRecord<T>) {
         val key = record.key
         val childRegistry by
             rememberSaveable(
diff --git a/room/room-paging/build.gradle b/room/room-paging/build.gradle
index e0ab2c1..3805343 100644
--- a/room/room-paging/build.gradle
+++ b/room/room-paging/build.gradle
@@ -41,7 +41,6 @@
                 api(libs.kotlinStdlib)
                 api("androidx.paging:paging-common:3.3.2")
                 api(project(":room:room-runtime"))
-                implementation(libs.atomicFu)
             }
         }
 
@@ -66,6 +65,9 @@
 
         nativeMain {
             dependsOn(jvmNativeMain)
+            dependencies {
+                implementation(libs.atomicFu)
+            }
         }
 
         androidInstrumentedTest {
diff --git a/room/room-paging/src/androidMain/kotlin/androidx/room/paging/LimitOffsetPagingSource.android.kt b/room/room-paging/src/androidMain/kotlin/androidx/room/paging/LimitOffsetPagingSource.android.kt
index 4128526..66cbfa3 100644
--- a/room/room-paging/src/androidMain/kotlin/androidx/room/paging/LimitOffsetPagingSource.android.kt
+++ b/room/room-paging/src/androidMain/kotlin/androidx/room/paging/LimitOffsetPagingSource.android.kt
@@ -61,7 +61,7 @@
     private val implementation = CommonLimitOffsetImpl(tables, this, ::convertRows)
 
     public actual val itemCount: Int
-        get() = implementation.itemCount.value
+        get() = implementation.itemCount.get()
 
     override val jumpingSupported: Boolean
         get() = true
diff --git a/room/room-paging/src/commonMain/kotlin/androidx/room/paging/LimitOffsetPagingSource.kt b/room/room-paging/src/commonMain/kotlin/androidx/room/paging/LimitOffsetPagingSource.kt
index edd5950..9c5783d4 100644
--- a/room/room-paging/src/commonMain/kotlin/androidx/room/paging/LimitOffsetPagingSource.kt
+++ b/room/room-paging/src/commonMain/kotlin/androidx/room/paging/LimitOffsetPagingSource.kt
@@ -24,11 +24,12 @@
 import androidx.room.RoomDatabase
 import androidx.room.RoomRawQuery
 import androidx.room.Transactor.SQLiteTransactionType
+import androidx.room.concurrent.AtomicBoolean
+import androidx.room.concurrent.AtomicInt
 import androidx.room.paging.util.INITIAL_ITEM_COUNT
 import androidx.room.paging.util.queryDatabase
 import androidx.room.paging.util.queryItemCount
 import androidx.room.useReaderConnection
-import kotlinx.atomicfu.atomic
 import kotlinx.coroutines.CancellationException
 import kotlinx.coroutines.Job
 import kotlinx.coroutines.launch
@@ -70,9 +71,9 @@
     private val db = pagingSource.db
     private val sourceQuery = pagingSource.sourceQuery
 
-    internal val itemCount = atomic(INITIAL_ITEM_COUNT)
+    internal val itemCount = AtomicInt(INITIAL_ITEM_COUNT)
 
-    private val invalidationFlowStarted = atomic(false)
+    private val invalidationFlowStarted = AtomicBoolean(false)
     private var invalidationFlowJob: Job? = null
 
     init {
@@ -80,7 +81,7 @@
     }
 
     suspend fun load(params: LoadParams<Int>): LoadResult<Int, Value> {
-        if (invalidationFlowStarted.compareAndSet(expect = false, update = true)) {
+        if (invalidationFlowStarted.compareAndSet(false, true)) {
             invalidationFlowJob =
                 db.getCoroutineScope().launch {
                     db.invalidationTracker.createFlow(*tables, emitInitialState = false).collect {
@@ -92,7 +93,7 @@
                 }
         }
 
-        val tempCount = itemCount.value
+        val tempCount = itemCount.get()
         // if itemCount is < 0, then it is initial load
         return try {
             if (tempCount == INITIAL_ITEM_COUNT) {
@@ -119,7 +120,7 @@
         return db.useReaderConnection { connection ->
             connection.withTransaction(SQLiteTransactionType.DEFERRED) {
                 val tempCount = queryItemCount(sourceQuery, db)
-                itemCount.value = tempCount
+                itemCount.set(tempCount)
                 queryDatabase(
                     params = params,
                     sourceQuery = sourceQuery,
diff --git a/room/room-paging/src/jvmNativeMain/kotlin/androidx/room/paging/LimitOffsetPagingSource.jvmNative.kt b/room/room-paging/src/jvmNativeMain/kotlin/androidx/room/paging/LimitOffsetPagingSource.jvmNative.kt
index 1f4235e..77f4bd2 100644
--- a/room/room-paging/src/jvmNativeMain/kotlin/androidx/room/paging/LimitOffsetPagingSource.jvmNative.kt
+++ b/room/room-paging/src/jvmNativeMain/kotlin/androidx/room/paging/LimitOffsetPagingSource.jvmNative.kt
@@ -41,7 +41,7 @@
     private val implementation = CommonLimitOffsetImpl(tables, this, ::convertRows)
 
     public actual val itemCount: Int
-        get() = implementation.itemCount.value
+        get() = implementation.itemCount.get()
 
     override val jumpingSupported: Boolean
         get() = true
diff --git a/room/room-runtime/bcv/native/current.txt b/room/room-runtime/bcv/native/current.txt
index 984bd87..89d7a96 100644
--- a/room/room-runtime/bcv/native/current.txt
+++ b/room/room-runtime/bcv/native/current.txt
@@ -222,6 +222,24 @@
     final object Companion // androidx.room/EntityUpsertAdapter.Companion|null[0]
 }
 
+final class androidx.room.concurrent/AtomicBoolean { // androidx.room.concurrent/AtomicBoolean|null[0]
+    constructor <init>(kotlin/Boolean) // androidx.room.concurrent/AtomicBoolean.<init>|<init>(kotlin.Boolean){}[0]
+
+    final fun compareAndSet(kotlin/Boolean, kotlin/Boolean): kotlin/Boolean // androidx.room.concurrent/AtomicBoolean.compareAndSet|compareAndSet(kotlin.Boolean;kotlin.Boolean){}[0]
+    final fun get(): kotlin/Boolean // androidx.room.concurrent/AtomicBoolean.get|get(){}[0]
+}
+
+final class androidx.room.concurrent/AtomicInt { // androidx.room.concurrent/AtomicInt|null[0]
+    constructor <init>(kotlin/Int) // androidx.room.concurrent/AtomicInt.<init>|<init>(kotlin.Int){}[0]
+
+    final fun compareAndSet(kotlin/Int, kotlin/Int): kotlin/Boolean // androidx.room.concurrent/AtomicInt.compareAndSet|compareAndSet(kotlin.Int;kotlin.Int){}[0]
+    final fun decrementAndGet(): kotlin/Int // androidx.room.concurrent/AtomicInt.decrementAndGet|decrementAndGet(){}[0]
+    final fun get(): kotlin/Int // androidx.room.concurrent/AtomicInt.get|get(){}[0]
+    final fun getAndIncrement(): kotlin/Int // androidx.room.concurrent/AtomicInt.getAndIncrement|getAndIncrement(){}[0]
+    final fun incrementAndGet(): kotlin/Int // androidx.room.concurrent/AtomicInt.incrementAndGet|incrementAndGet(){}[0]
+    final fun set(kotlin/Int) // androidx.room.concurrent/AtomicInt.set|set(kotlin.Int){}[0]
+}
+
 final class androidx.room.util/ByteArrayWrapper { // androidx.room.util/ByteArrayWrapper|null[0]
     constructor <init>(kotlin/ByteArray) // androidx.room.util/ByteArrayWrapper.<init>|<init>(kotlin.ByteArray){}[0]
 
diff --git a/room/room-runtime/build.gradle b/room/room-runtime/build.gradle
index dc736fd..4fd3768 100644
--- a/room/room-runtime/build.gradle
+++ b/room/room-runtime/build.gradle
@@ -110,7 +110,6 @@
                 api("androidx.collection:collection:1.4.2")
                 api("androidx.annotation:annotation:1.8.1")
                 api(libs.kotlinCoroutinesCore)
-                implementation(libs.atomicFu)
             }
         }
         commonTest {
@@ -180,6 +179,7 @@
             dependsOn(jvmNativeMain)
             dependencies {
                 api(project(":sqlite:sqlite-framework"))
+                implementation(libs.atomicFu)
             }
         }
         nativeTest {
diff --git a/room/room-runtime/src/androidInstrumentedTest/kotlin/androidx/room/coroutines/BundledSQLiteConnectionPoolTest.kt b/room/room-runtime/src/androidInstrumentedTest/kotlin/androidx/room/coroutines/BundledSQLiteConnectionPoolTest.kt
index ab9a93b..f876d37 100644
--- a/room/room-runtime/src/androidInstrumentedTest/kotlin/androidx/room/coroutines/BundledSQLiteConnectionPoolTest.kt
+++ b/room/room-runtime/src/androidInstrumentedTest/kotlin/androidx/room/coroutines/BundledSQLiteConnectionPoolTest.kt
@@ -18,6 +18,7 @@
 
 import androidx.kruth.assertThat
 import androidx.room.Transactor
+import androidx.room.concurrent.AtomicInt
 import androidx.sqlite.SQLiteDriver
 import androidx.sqlite.driver.bundled.BundledSQLiteDriver
 import androidx.test.filters.LargeTest
@@ -27,7 +28,6 @@
 import kotlin.test.AfterTest
 import kotlin.test.BeforeTest
 import kotlin.test.Test
-import kotlinx.atomicfu.atomic
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.InternalCoroutinesApi
@@ -130,7 +130,7 @@
 
     /** A CoroutineDispatcher that dispatches every block into a new thread */
     private class NewThreadDispatcher : CoroutineDispatcher() {
-        private val idCounter = atomic(0)
+        private val idCounter = AtomicInt(0)
 
         @OptIn(InternalCoroutinesApi::class)
         override fun dispatchYield(context: CoroutineContext, block: Runnable) {
diff --git a/room/room-runtime/src/androidMain/kotlin/androidx/room/InvalidationTracker.android.kt b/room/room-runtime/src/androidMain/kotlin/androidx/room/InvalidationTracker.android.kt
index 04caeb7..9b5e5d8 100644
--- a/room/room-runtime/src/androidMain/kotlin/androidx/room/InvalidationTracker.android.kt
+++ b/room/room-runtime/src/androidMain/kotlin/androidx/room/InvalidationTracker.android.kt
@@ -21,12 +21,12 @@
 import androidx.annotation.WorkerThread
 import androidx.lifecycle.LiveData
 import androidx.room.InvalidationTracker.Observer
+import androidx.room.concurrent.ReentrantLock
+import androidx.room.concurrent.withLock
 import androidx.room.support.AutoCloser
 import androidx.sqlite.SQLiteConnection
 import java.lang.ref.WeakReference
 import java.util.concurrent.Callable
-import kotlinx.atomicfu.locks.reentrantLock
-import kotlinx.atomicfu.locks.withLock
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.merge
 import kotlinx.coroutines.runBlocking
@@ -65,7 +65,7 @@
         )
 
     private val observerMap = mutableMapOf<Observer, ObserverWrapper>()
-    private val observerMapLock = reentrantLock()
+    private val observerMapLock = ReentrantLock()
 
     private var autoCloser: AutoCloser? = null
 
diff --git a/room/room-runtime/src/androidUnitTest/kotlin/androidx/room/InvalidationTrackerTest.kt b/room/room-runtime/src/androidUnitTest/kotlin/androidx/room/InvalidationTrackerTest.kt
index bbe94dc..c5e76f9 100644
--- a/room/room-runtime/src/androidUnitTest/kotlin/androidx/room/InvalidationTrackerTest.kt
+++ b/room/room-runtime/src/androidUnitTest/kotlin/androidx/room/InvalidationTrackerTest.kt
@@ -19,6 +19,8 @@
 import androidx.annotation.RequiresApi
 import androidx.kruth.assertThat
 import androidx.kruth.assertThrows
+import androidx.room.concurrent.AtomicBoolean
+import androidx.room.concurrent.AtomicInt
 import androidx.sqlite.SQLiteConnection
 import androidx.sqlite.SQLiteDriver
 import androidx.sqlite.SQLiteStatement
@@ -27,7 +29,6 @@
 import java.util.concurrent.CountDownLatch
 import java.util.concurrent.TimeUnit
 import kotlin.collections.removeFirst as removeFirstKt
-import kotlinx.atomicfu.atomic
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.TimeoutCancellationException
 import kotlinx.coroutines.cancelAndJoin
@@ -346,12 +347,12 @@
     fun refreshAndCloseDbWithSlowObserver() = runTest {
         // Validates that a slow observer will finish notification after database closing
         val invalidatedLatch = CountDownLatch(1)
-        val invalidated = atomic(false)
+        val invalidated = AtomicBoolean(false)
         tracker.addObserver(
             object : InvalidationTracker.Observer("a") {
                 override fun onInvalidated(tables: Set<String>) {
                     invalidatedLatch.countDown()
-                    assertThat(invalidated.compareAndSet(expect = false, update = true)).isTrue()
+                    assertThat(invalidated.compareAndSet(false, true)).isTrue()
                     runBlocking { delay(100) }
                 }
             }
@@ -361,7 +362,7 @@
         testScheduler.advanceUntilIdle()
         invalidatedLatch.await()
         roomDatabase.close()
-        assertThat(invalidated.value).isTrue()
+        assertThat(invalidated.get()).isTrue()
     }
 
     @Test
@@ -473,7 +474,7 @@
 
     @Test
     fun weakObserver() = runTest {
-        val invalidated = atomic(0)
+        val invalidated = AtomicInt(0)
         var observer: InvalidationTracker.Observer? =
             object : InvalidationTracker.Observer("a") {
                 override fun onInvalidated(tables: Set<String>) {
@@ -484,7 +485,7 @@
 
         sqliteDriver.setInvalidatedTables(0)
         tracker.awaitRefreshAsync()
-        assertThat(invalidated.value).isEqualTo(1)
+        assertThat(invalidated.get()).isEqualTo(1)
 
         // Attempt to perform garbage collection in a loop so that weak observer is discarded
         // and it stops receiving invalidation notifications. If GC fails to collect the observer
@@ -511,7 +512,7 @@
 
         sqliteDriver.setInvalidatedTables(0)
         tracker.awaitRefreshAsync()
-        assertThat(invalidated.value).isEqualTo(1)
+        assertThat(invalidated.get()).isEqualTo(1)
     }
 
     @Test
diff --git a/room/room-runtime/src/commonMain/kotlin/androidx/room/InvalidationTracker.kt b/room/room-runtime/src/commonMain/kotlin/androidx/room/InvalidationTracker.kt
index 1997321..5730b60 100644
--- a/room/room-runtime/src/commonMain/kotlin/androidx/room/InvalidationTracker.kt
+++ b/room/room-runtime/src/commonMain/kotlin/androidx/room/InvalidationTracker.kt
@@ -18,16 +18,16 @@
 
 import androidx.annotation.RestrictTo
 import androidx.room.Transactor.SQLiteTransactionType
+import androidx.room.concurrent.AtomicBoolean
+import androidx.room.concurrent.ReentrantLock
 import androidx.room.concurrent.ifNotClosed
+import androidx.room.concurrent.withLock
 import androidx.room.util.getCoroutineContext
 import androidx.sqlite.SQLiteConnection
 import androidx.sqlite.SQLiteException
 import androidx.sqlite.execSQL
 import kotlin.jvm.JvmOverloads
 import kotlin.jvm.JvmSuppressWildcards
-import kotlinx.atomicfu.atomic
-import kotlinx.atomicfu.locks.reentrantLock
-import kotlinx.atomicfu.locks.withLock
 import kotlinx.coroutines.CoroutineName
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.FlowCollector
@@ -162,7 +162,7 @@
      * queue to be done asynchronously, this flag is used to control excessive scheduling of
      * refreshes.
      */
-    private val pendingRefresh = atomic(false)
+    private val pendingRefresh = AtomicBoolean(false)
 
     /** Callback to allow or disallow [refreshInvalidation] from proceeding. */
     internal var onAllowRefresh: () -> Boolean = { true }
@@ -484,7 +484,7 @@
  */
 internal class ObservedTableStates(size: Int) {
 
-    private val lock = reentrantLock()
+    private val lock = ReentrantLock()
 
     // The number of observers per table
     private val tableObserversCount = LongArray(size)
diff --git a/room/room-runtime/src/commonMain/kotlin/androidx/room/concurrent/Atomics.kt b/room/room-runtime/src/commonMain/kotlin/androidx/room/concurrent/Atomics.kt
new file mode 100644
index 0000000..04abb13
--- /dev/null
+++ b/room/room-runtime/src/commonMain/kotlin/androidx/room/concurrent/Atomics.kt
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+@file:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+
+package androidx.room.concurrent
+
+import androidx.annotation.RestrictTo
+
+expect class AtomicInt {
+    constructor(initialValue: Int)
+
+    fun get(): Int
+
+    fun set(value: Int)
+
+    fun compareAndSet(expect: Int, update: Int): Boolean
+
+    fun incrementAndGet(): Int
+
+    fun getAndIncrement(): Int
+
+    fun decrementAndGet(): Int
+}
+
+internal inline fun AtomicInt.loop(action: (Int) -> Unit): Nothing {
+    while (true) {
+        action(get())
+    }
+}
+
+expect class AtomicBoolean {
+    constructor(initialValue: Boolean)
+
+    fun get(): Boolean
+
+    fun compareAndSet(expect: Boolean, update: Boolean): Boolean
+}
diff --git a/room/room-runtime/src/commonMain/kotlin/androidx/room/concurrent/CloseBarrier.kt b/room/room-runtime/src/commonMain/kotlin/androidx/room/concurrent/CloseBarrier.kt
index 8bf4a24..e499315 100644
--- a/room/room-runtime/src/commonMain/kotlin/androidx/room/concurrent/CloseBarrier.kt
+++ b/room/room-runtime/src/commonMain/kotlin/androidx/room/concurrent/CloseBarrier.kt
@@ -16,11 +16,6 @@
 
 package androidx.room.concurrent
 
-import kotlinx.atomicfu.atomic
-import kotlinx.atomicfu.locks.SynchronizedObject
-import kotlinx.atomicfu.locks.synchronized
-import kotlinx.atomicfu.loop
-
 /**
  * A barrier that can be used to perform a cleanup action once, waiting for registered parties
  * (blockers) to finish using the protected resource.
@@ -40,9 +35,10 @@
  *   blockers.
  */
 internal class CloseBarrier(private val closeAction: () -> Unit) : SynchronizedObject() {
-    private val blockers = atomic(0)
-    private val closeInitiated = atomic(false)
-    private val isClosed by closeInitiated
+    private val blockers = AtomicInt(0)
+    private val closeInitiated = AtomicBoolean(false)
+    private val isClosed: Boolean
+        get() = closeInitiated.get()
 
     /**
      * Blocks the [closeAction] from occurring.
@@ -72,7 +68,7 @@
     internal fun unblock(): Unit =
         synchronized(this) {
             blockers.decrementAndGet()
-            check(blockers.value >= 0) { "Unbalanced call to unblock() detected." }
+            check(blockers.get() >= 0) { "Unbalanced call to unblock() detected." }
         }
 
     /**
diff --git a/room/room-runtime/src/commonMain/kotlin/androidx/room/concurrent/ExclusiveLock.kt b/room/room-runtime/src/commonMain/kotlin/androidx/room/concurrent/ExclusiveLock.kt
index de1c2e5..2d34dd7 100644
--- a/room/room-runtime/src/commonMain/kotlin/androidx/room/concurrent/ExclusiveLock.kt
+++ b/room/room-runtime/src/commonMain/kotlin/androidx/room/concurrent/ExclusiveLock.kt
@@ -16,11 +16,6 @@
 
 package androidx.room.concurrent
 
-import kotlinx.atomicfu.locks.ReentrantLock
-import kotlinx.atomicfu.locks.SynchronizedObject
-import kotlinx.atomicfu.locks.reentrantLock
-import kotlinx.atomicfu.locks.synchronized
-
 /**
  * An exclusive lock for in-process and multi-process synchronization.
  *
@@ -59,7 +54,7 @@
 
         private fun getThreadLock(key: String): ReentrantLock =
             synchronized(this) {
-                return threadLocksMap.getOrPut(key) { reentrantLock() }
+                return threadLocksMap.getOrPut(key) { ReentrantLock() }
             }
 
         private fun getFileLock(key: String) = FileLock(key)
diff --git a/room/room-runtime/src/commonMain/kotlin/androidx/room/concurrent/ReentrantLock.kt b/room/room-runtime/src/commonMain/kotlin/androidx/room/concurrent/ReentrantLock.kt
new file mode 100644
index 0000000..444ef7c
--- /dev/null
+++ b/room/room-runtime/src/commonMain/kotlin/androidx/room/concurrent/ReentrantLock.kt
@@ -0,0 +1,34 @@
+/*
+ * 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.room.concurrent
+
+internal expect class ReentrantLock() {
+    fun lock(): Unit
+
+    fun tryLock(): Boolean
+
+    fun unlock(): Unit
+}
+
+internal inline fun <T> ReentrantLock.withLock(block: () -> T): T {
+    lock()
+    try {
+        return block()
+    } finally {
+        unlock()
+    }
+}
diff --git a/room/room-runtime/src/commonMain/kotlin/androidx/room/concurrent/Synchronized.kt b/room/room-runtime/src/commonMain/kotlin/androidx/room/concurrent/Synchronized.kt
new file mode 100644
index 0000000..1515bdf
--- /dev/null
+++ b/room/room-runtime/src/commonMain/kotlin/androidx/room/concurrent/Synchronized.kt
@@ -0,0 +1,21 @@
+/*
+ * 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.room.concurrent
+
+internal expect open class SynchronizedObject()
+
+internal expect inline fun <T> synchronized(lock: SynchronizedObject, block: () -> T): T
diff --git a/room/room-runtime/src/commonMain/kotlin/androidx/room/coroutines/ConnectionPoolImpl.kt b/room/room-runtime/src/commonMain/kotlin/androidx/room/coroutines/ConnectionPoolImpl.kt
index 185e412..ae49a2e 100644
--- a/room/room-runtime/src/commonMain/kotlin/androidx/room/coroutines/ConnectionPoolImpl.kt
+++ b/room/room-runtime/src/commonMain/kotlin/androidx/room/coroutines/ConnectionPoolImpl.kt
@@ -19,6 +19,8 @@
 import androidx.room.TransactionScope
 import androidx.room.Transactor
 import androidx.room.Transactor.SQLiteTransactionType
+import androidx.room.concurrent.AtomicBoolean
+import androidx.room.concurrent.AtomicInt
 import androidx.room.concurrent.ThreadLocal
 import androidx.room.concurrent.asContextElement
 import androidx.room.concurrent.currentThreadId
@@ -35,7 +37,6 @@
 import kotlin.coroutines.CoroutineContext
 import kotlin.coroutines.coroutineContext
 import kotlin.time.Duration.Companion.seconds
-import kotlinx.atomicfu.atomic
 import kotlinx.coroutines.TimeoutCancellationException
 import kotlinx.coroutines.channels.Channel
 import kotlinx.coroutines.sync.Mutex
@@ -50,8 +51,9 @@
 
     private val threadLocal = ThreadLocal<PooledConnectionImpl>()
 
-    private val _isClosed = atomic(false)
-    private val isClosed by _isClosed
+    private val _isClosed = AtomicBoolean(false)
+    private val isClosed: Boolean
+        get() = _isClosed.get()
 
     // Amount of time to wait to acquire a connection before throwing, Android uses 30 seconds in
     // its pool, so we do too here, but IDK if that is a good number. This timeout is unrelated to
@@ -195,7 +197,7 @@
 }
 
 private class Pool(val capacity: Int, val connectionFactory: () -> SQLiteConnection) {
-    private val size = atomic(0)
+    private val size = AtomicInt(0)
     private val connections = arrayOfNulls<ConnectionWithLock>(capacity)
     private val channel =
         Channel<ConnectionWithLock>(capacity = capacity, onUndeliveredElement = { recycle(it) })
@@ -211,7 +213,7 @@
     }
 
     private fun tryOpenNewConnection() {
-        val currentSize = size.value
+        val currentSize = size.get()
         if (currentSize >= capacity) {
             // Capacity reached
             return
@@ -322,8 +324,9 @@
 ) : Transactor, RawConnectionAccessor {
     private val transactionStack = ArrayDeque<TransactionItem>()
 
-    private val _isRecycled = atomic(false)
-    private val isRecycled by _isRecycled
+    private val _isRecycled = AtomicBoolean(false)
+    private val isRecycled: Boolean
+        get() = _isRecycled.get()
 
     override val rawConnection: SQLiteConnection
         get() = delegate
diff --git a/room/room-runtime/src/commonTest/kotlin/androidx/room/concurrent/CloseBarrierTest.kt b/room/room-runtime/src/commonTest/kotlin/androidx/room/concurrent/CloseBarrierTest.kt
index 75f64d1..3133b3a 100644
--- a/room/room-runtime/src/commonTest/kotlin/androidx/room/concurrent/CloseBarrierTest.kt
+++ b/room/room-runtime/src/commonTest/kotlin/androidx/room/concurrent/CloseBarrierTest.kt
@@ -19,7 +19,6 @@
 import androidx.kruth.assertThat
 import androidx.kruth.assertThrows
 import kotlin.test.Test
-import kotlinx.atomicfu.atomic
 import kotlinx.coroutines.DelicateCoroutinesApi
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.launch
@@ -34,9 +33,9 @@
     @Test
     @OptIn(ExperimentalCoroutinesApi::class, DelicateCoroutinesApi::class)
     fun oneBlocker() = runTest {
-        val actionPerformed = atomic(false)
+        val actionPerformed = AtomicBoolean(false)
         val closeBarrier = CloseBarrier {
-            assertThat(actionPerformed.compareAndSet(expect = false, update = true)).isTrue()
+            assertThat(actionPerformed.compareAndSet(false, true)).isTrue()
         }
         val jobLaunched = Mutex(locked = true)
 
@@ -52,14 +51,14 @@
 
         // yield for launch and verify the close action has not been performed
         yield()
-        jobLaunched.withLock { assertThat(actionPerformed.value).isFalse() }
+        jobLaunched.withLock { assertThat(actionPerformed.get()).isFalse() }
 
         // unblock the barrier, close job should complete
         closeBarrier.unblock()
         closeJob.join()
 
         // verify action was performed
-        assertThat(actionPerformed.value).isTrue()
+        assertThat(actionPerformed.get()).isTrue()
 
         // verify a new block is not granted since the barrier is already close
         assertThat(closeBarrier.block()).isFalse()
@@ -67,15 +66,15 @@
 
     @Test
     fun noBlockers() = runTest {
-        val actionPerformed = atomic(false)
+        val actionPerformed = AtomicBoolean(false)
         val closeBarrier = CloseBarrier {
-            assertThat(actionPerformed.compareAndSet(expect = false, update = true)).isTrue()
+            assertThat(actionPerformed.compareAndSet(false, true)).isTrue()
         }
 
         // Validate close action is performed immediately if there are no blockers
         closeBarrier.close()
 
-        assertThat(actionPerformed.value).isTrue()
+        assertThat(actionPerformed.get()).isTrue()
     }
 
     @Test
@@ -89,9 +88,9 @@
     @Test
     @OptIn(ExperimentalCoroutinesApi::class, DelicateCoroutinesApi::class)
     fun noStarvation() = runTest {
-        val actionPerformed = atomic(false)
+        val actionPerformed = AtomicBoolean(false)
         val closeBarrier = CloseBarrier {
-            assertThat(actionPerformed.compareAndSet(expect = false, update = true)).isTrue()
+            assertThat(actionPerformed.compareAndSet(false, true)).isTrue()
         }
         val jobLaunched = Mutex(locked = true)
 
@@ -111,12 +110,12 @@
         // yield for launch and verify the close action has not been performed in an attempt to
         // get the block / unblock loop going
         yield()
-        jobLaunched.withLock { assertThat(actionPerformed.value).isFalse() }
+        jobLaunched.withLock { assertThat(actionPerformed.get()).isFalse() }
 
         // initiate the close action, test should not deadlock (or timeout) meaning the barrier
         // will not cause the caller to starve
         closeBarrier.close()
         blockerJob.join()
-        assertThat(actionPerformed.value).isTrue()
+        assertThat(actionPerformed.get()).isTrue()
     }
 }
diff --git a/room/room-runtime/src/commonTest/kotlin/androidx/room/coroutines/BaseConnectionPoolTest.kt b/room/room-runtime/src/commonTest/kotlin/androidx/room/coroutines/BaseConnectionPoolTest.kt
index cff6dbd..f86b7b6 100644
--- a/room/room-runtime/src/commonTest/kotlin/androidx/room/coroutines/BaseConnectionPoolTest.kt
+++ b/room/room-runtime/src/commonTest/kotlin/androidx/room/coroutines/BaseConnectionPoolTest.kt
@@ -19,6 +19,7 @@
 import androidx.kruth.assertThat
 import androidx.room.PooledConnection
 import androidx.room.Transactor
+import androidx.room.concurrent.AtomicInt
 import androidx.room.deferredTransaction
 import androidx.room.exclusiveTransaction
 import androidx.room.execSQL
@@ -34,7 +35,6 @@
 import kotlin.test.Test
 import kotlin.test.assertFailsWith
 import kotlin.test.fail
-import kotlinx.atomicfu.atomic
 import kotlinx.coroutines.DelicateCoroutinesApi
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -463,7 +463,7 @@
     @Test
     fun singleConnectionPool() = runTest {
         val multiThreadContext = newFixedThreadPoolContext(2, "Test-Threads")
-        val connectionsOpened = atomic(0)
+        val connectionsOpened = AtomicInt(0)
         val actualDriver = setupDriver()
         val driver =
             object : SQLiteDriver by actualDriver {
@@ -487,12 +487,12 @@
         jobs.joinAll()
         pool.close()
         multiThreadContext.close()
-        assertThat(connectionsOpened.value).isEqualTo(1)
+        assertThat(connectionsOpened.get()).isEqualTo(1)
     }
 
     @Test
     fun openOneConnectionWhenUsedSerially() = runTest {
-        val connectionsOpened = atomic(0)
+        val connectionsOpened = AtomicInt(0)
         val actualDriver = setupDriver()
         val driver =
             object : SQLiteDriver by actualDriver {
@@ -518,7 +518,7 @@
             }
         }
         pool.close()
-        assertThat(connectionsOpened.value).isEqualTo(1)
+        assertThat(connectionsOpened.get()).isEqualTo(1)
     }
 
     @Test
@@ -689,7 +689,7 @@
                 actual.close()
             }
         }
-        val connectionArrCount = atomic(0)
+        val connectionArrCount = AtomicInt(0)
         val connectionsArr = arrayOfNulls<CloseAwareConnection>(4)
         val actualDriver = setupDriver()
         val driver =
@@ -714,7 +714,7 @@
                 launch(multiThreadContext) { pool.useReaderConnection { barrier.withLock {} } }
             jobs.add(job)
         }
-        while (connectionArrCount.value < 4) {
+        while (connectionArrCount.get() < 4) {
             delay(100)
         }
         barrier.unlock()
diff --git a/room/room-runtime/src/jvmAndroidMain/kotlin/androidx/room/concurrent/Atomics.jvmAndroid.kt b/room/room-runtime/src/jvmAndroidMain/kotlin/androidx/room/concurrent/Atomics.jvmAndroid.kt
new file mode 100644
index 0000000..00255dc
--- /dev/null
+++ b/room/room-runtime/src/jvmAndroidMain/kotlin/androidx/room/concurrent/Atomics.jvmAndroid.kt
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+@file:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+
+package androidx.room.concurrent
+
+import androidx.annotation.RestrictTo
+
+actual typealias AtomicInt = java.util.concurrent.atomic.AtomicInteger
+
+actual typealias AtomicBoolean = java.util.concurrent.atomic.AtomicBoolean
diff --git a/room/room-runtime/src/jvmAndroidMain/kotlin/androidx/room/concurrent/ReentrantLock.jvmAndroid.kt b/room/room-runtime/src/jvmAndroidMain/kotlin/androidx/room/concurrent/ReentrantLock.jvmAndroid.kt
new file mode 100644
index 0000000..dc8fdab
--- /dev/null
+++ b/room/room-runtime/src/jvmAndroidMain/kotlin/androidx/room/concurrent/ReentrantLock.jvmAndroid.kt
@@ -0,0 +1,19 @@
+/*
+ * 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.room.concurrent
+
+internal actual typealias ReentrantLock = java.util.concurrent.locks.ReentrantLock
diff --git a/room/room-runtime/src/jvmAndroidMain/kotlin/androidx/room/concurrent/Synchronized.jvmAndroid.kt b/room/room-runtime/src/jvmAndroidMain/kotlin/androidx/room/concurrent/Synchronized.jvmAndroid.kt
new file mode 100644
index 0000000..fae30d5
--- /dev/null
+++ b/room/room-runtime/src/jvmAndroidMain/kotlin/androidx/room/concurrent/Synchronized.jvmAndroid.kt
@@ -0,0 +1,22 @@
+/*
+ * 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.room.concurrent
+
+internal actual typealias SynchronizedObject = Any
+
+internal actual inline fun <T> synchronized(lock: SynchronizedObject, block: () -> T): T =
+    kotlin.synchronized(lock, block)
diff --git a/room/room-runtime/src/nativeMain/kotlin/androidx/room/concurrent/Atomics.native.kt b/room/room-runtime/src/nativeMain/kotlin/androidx/room/concurrent/Atomics.native.kt
new file mode 100644
index 0000000..46b4012
--- /dev/null
+++ b/room/room-runtime/src/nativeMain/kotlin/androidx/room/concurrent/Atomics.native.kt
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+@file:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+
+package androidx.room.concurrent
+
+import androidx.annotation.RestrictTo
+import kotlin.concurrent.AtomicInt as KotlinAtomicInt
+
+actual class AtomicInt actual constructor(initialValue: Int) {
+    private val delegate: KotlinAtomicInt = KotlinAtomicInt(initialValue)
+
+    actual fun get(): Int = delegate.value
+
+    actual fun set(value: Int) {
+        delegate.value = value
+    }
+
+    actual fun compareAndSet(expect: Int, update: Int): Boolean =
+        delegate.compareAndSet(expect, update)
+
+    actual fun incrementAndGet(): Int = delegate.incrementAndGet()
+
+    actual fun getAndIncrement(): Int = delegate.getAndIncrement()
+
+    actual fun decrementAndGet(): Int = delegate.decrementAndGet()
+}
+
+actual class AtomicBoolean actual constructor(initialValue: Boolean) {
+    private val delegate: KotlinAtomicInt = KotlinAtomicInt(toInt(initialValue))
+
+    actual fun get(): Boolean = delegate.value == 1
+
+    actual fun compareAndSet(expect: Boolean, update: Boolean): Boolean =
+        delegate.compareAndSet(toInt(expect), toInt(update))
+
+    private fun toInt(value: Boolean) = if (value) 1 else 0
+}
diff --git a/room/room-runtime/src/nativeMain/kotlin/androidx/room/concurrent/ReentrantLock.native.kt b/room/room-runtime/src/nativeMain/kotlin/androidx/room/concurrent/ReentrantLock.native.kt
new file mode 100644
index 0000000..544fa01
--- /dev/null
+++ b/room/room-runtime/src/nativeMain/kotlin/androidx/room/concurrent/ReentrantLock.native.kt
@@ -0,0 +1,19 @@
+/*
+ * 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.room.concurrent
+
+internal actual typealias ReentrantLock = kotlinx.atomicfu.locks.SynchronizedObject
diff --git a/room/room-runtime/src/nativeMain/kotlin/androidx/room/concurrent/Synchronized.native.kt b/room/room-runtime/src/nativeMain/kotlin/androidx/room/concurrent/Synchronized.native.kt
new file mode 100644
index 0000000..7691045
--- /dev/null
+++ b/room/room-runtime/src/nativeMain/kotlin/androidx/room/concurrent/Synchronized.native.kt
@@ -0,0 +1,22 @@
+/*
+ * 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.room.concurrent
+
+internal actual typealias SynchronizedObject = kotlinx.atomicfu.locks.SynchronizedObject
+
+internal actual inline fun <T> synchronized(lock: SynchronizedObject, block: () -> T): T =
+    kotlinx.atomicfu.locks.synchronized(lock, block)
diff --git a/wear/protolayout/protolayout-material3/api/current.txt b/wear/protolayout/protolayout-material3/api/current.txt
index 8942afc..eae2d58 100644
--- a/wear/protolayout/protolayout-material3/api/current.txt
+++ b/wear/protolayout/protolayout-material3/api/current.txt
@@ -204,17 +204,6 @@
     method public static androidx.wear.protolayout.LayoutElementBuilders.LayoutElement textEdgeButton(androidx.wear.protolayout.material3.MaterialScope, androidx.wear.protolayout.ModifiersBuilders.Clickable onClick, optional androidx.wear.protolayout.modifiers.LayoutModifier modifier, optional androidx.wear.protolayout.material3.ButtonColors colors, kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement> labelContent);
   }
 
-  public final class EdgeButtonStyle {
-    field public static final androidx.wear.protolayout.material3.EdgeButtonStyle.Companion Companion;
-    field public static final androidx.wear.protolayout.material3.EdgeButtonStyle DEFAULT;
-    field public static final androidx.wear.protolayout.material3.EdgeButtonStyle TOP_ALIGN;
-  }
-
-  public static final class EdgeButtonStyle.Companion {
-    property public final androidx.wear.protolayout.material3.EdgeButtonStyle DEFAULT;
-    property public final androidx.wear.protolayout.material3.EdgeButtonStyle TOP_ALIGN;
-  }
-
   public final class GraphicDataCardStyle {
     field public static final androidx.wear.protolayout.material3.GraphicDataCardStyle.Companion Companion;
   }
diff --git a/wear/protolayout/protolayout-material3/api/restricted_current.txt b/wear/protolayout/protolayout-material3/api/restricted_current.txt
index 8942afc..eae2d58 100644
--- a/wear/protolayout/protolayout-material3/api/restricted_current.txt
+++ b/wear/protolayout/protolayout-material3/api/restricted_current.txt
@@ -204,17 +204,6 @@
     method public static androidx.wear.protolayout.LayoutElementBuilders.LayoutElement textEdgeButton(androidx.wear.protolayout.material3.MaterialScope, androidx.wear.protolayout.ModifiersBuilders.Clickable onClick, optional androidx.wear.protolayout.modifiers.LayoutModifier modifier, optional androidx.wear.protolayout.material3.ButtonColors colors, kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement> labelContent);
   }
 
-  public final class EdgeButtonStyle {
-    field public static final androidx.wear.protolayout.material3.EdgeButtonStyle.Companion Companion;
-    field public static final androidx.wear.protolayout.material3.EdgeButtonStyle DEFAULT;
-    field public static final androidx.wear.protolayout.material3.EdgeButtonStyle TOP_ALIGN;
-  }
-
-  public static final class EdgeButtonStyle.Companion {
-    property public final androidx.wear.protolayout.material3.EdgeButtonStyle DEFAULT;
-    property public final androidx.wear.protolayout.material3.EdgeButtonStyle TOP_ALIGN;
-  }
-
   public final class GraphicDataCardStyle {
     field public static final androidx.wear.protolayout.material3.GraphicDataCardStyle.Companion Companion;
   }
diff --git a/wear/protolayout/protolayout-material3/src/androidTest/java/androidx/wear/protolayout/material3/TestCasesGenerator.kt b/wear/protolayout/protolayout-material3/src/androidTest/java/androidx/wear/protolayout/material3/TestCasesGenerator.kt
index 6b02da5..4537676 100644
--- a/wear/protolayout/protolayout-material3/src/androidTest/java/androidx/wear/protolayout/material3/TestCasesGenerator.kt
+++ b/wear/protolayout/protolayout-material3/src/androidTest/java/androidx/wear/protolayout/material3/TestCasesGenerator.kt
@@ -83,14 +83,17 @@
         testCases["primarylayout_edgebuttonfilled_buttongroup_iconoverride_golden$goldenSuffix"] =
             materialScope(
                 ApplicationProvider.getApplicationContext(),
-                deviceParameters,
+                // renderer version 1.302 has no asymmetrical corner support, so edgebutton will use
+                // its fallback style
+                deviceParameters.copy(VersionInfo.Builder().setMajor(1).setMinor(302).build()),
                 allowDynamicTheme = false
             ) {
                 primaryLayoutWithOverrideIcon(
                     mainSlot = {
                         text(
-                            text = "Text in the main slot that overflows".layoutString,
-                            color = colorScheme.secondary
+                            text = "Overflow main text and fallback edge button".layoutString,
+                            color = colorScheme.secondary,
+                            maxLines = 3
                         )
                     },
                     bottomSlot = {
@@ -476,11 +479,23 @@
         testCases["primarylayout_circularprogressindicators_fallback__golden$NORMAL_SCALE_SUFFIX"] =
             materialScope(
                 ApplicationProvider.getApplicationContext(),
+                // renderer with version 1.302 has no DashedArcLine or asymmetrical corners support
                 deviceConfiguration =
-                    deviceParameters.copy(VersionInfo.Builder().setMajor(1).setMinor(402).build()),
+                    deviceParameters.copy(VersionInfo.Builder().setMajor(1).setMinor(302).build()),
                 allowDynamicTheme = false
             ) {
-                primaryLayout(mainSlot = { progressIndicatorGroup() })
+                primaryLayout(
+                    mainSlot = { progressIndicatorGroup() },
+                    bottomSlot = {
+                        iconEdgeButton(
+                            onClick = clickable,
+                            iconContent = { icon(ICON_ID) },
+                            modifier =
+                                LayoutModifier.contentDescription(CONTENT_DESCRIPTION_PLACEHOLDER),
+                            colors = filledTonalButtonColors()
+                        )
+                    }
+                )
             }
 
         return collectTestCases(testCases)
diff --git a/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/EdgeButton.kt b/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/EdgeButton.kt
index e503797..5c438b7 100644
--- a/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/EdgeButton.kt
+++ b/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/EdgeButton.kt
@@ -27,8 +27,10 @@
 import androidx.wear.protolayout.ModifiersBuilders.Clickable
 import androidx.wear.protolayout.ModifiersBuilders.Padding
 import androidx.wear.protolayout.ModifiersBuilders.SEMANTICS_ROLE_BUTTON
+import androidx.wear.protolayout.expression.VersionBuilders.VersionInfo
 import androidx.wear.protolayout.material3.ButtonDefaults.filledButtonColors
 import androidx.wear.protolayout.material3.EdgeButtonDefaults.BOTTOM_MARGIN_DP
+import androidx.wear.protolayout.material3.EdgeButtonDefaults.CONTAINER_HEIGHT_DP
 import androidx.wear.protolayout.material3.EdgeButtonDefaults.EDGE_BUTTON_HEIGHT_DP
 import androidx.wear.protolayout.material3.EdgeButtonDefaults.HORIZONTAL_MARGIN_PERCENT_LARGE
 import androidx.wear.protolayout.material3.EdgeButtonDefaults.HORIZONTAL_MARGIN_PERCENT_SMALL
@@ -37,8 +39,16 @@
 import androidx.wear.protolayout.material3.EdgeButtonDefaults.TEXT_SIDE_PADDING_DP
 import androidx.wear.protolayout.material3.EdgeButtonDefaults.TEXT_TOP_PADDING_DP
 import androidx.wear.protolayout.material3.EdgeButtonDefaults.TOP_CORNER_RADIUS
-import androidx.wear.protolayout.material3.EdgeButtonStyle.Companion.DEFAULT
-import androidx.wear.protolayout.material3.EdgeButtonStyle.Companion.TOP_ALIGN
+import androidx.wear.protolayout.material3.EdgeButtonFallbackDefaults.BOTTOM_MARGIN_FALLBACK_DP
+import androidx.wear.protolayout.material3.EdgeButtonFallbackDefaults.CORNER_RADIUS_FALLBACK_DP
+import androidx.wear.protolayout.material3.EdgeButtonFallbackDefaults.EDGE_BUTTON_HEIGHT_FALLBACK_DP
+import androidx.wear.protolayout.material3.EdgeButtonFallbackDefaults.ICON_SIDE_PADDING_FALLBACK_DP
+import androidx.wear.protolayout.material3.EdgeButtonFallbackDefaults.ICON_SIZE_FALLBACK_DP
+import androidx.wear.protolayout.material3.EdgeButtonFallbackDefaults.TEXT_SIDE_PADDING_FALLBACK_DP
+import androidx.wear.protolayout.material3.EdgeButtonStyle.Companion.ICON
+import androidx.wear.protolayout.material3.EdgeButtonStyle.Companion.ICON_FALLBACK
+import androidx.wear.protolayout.material3.EdgeButtonStyle.Companion.TEXT
+import androidx.wear.protolayout.material3.EdgeButtonStyle.Companion.TEXT_FALLBACK
 import androidx.wear.protolayout.modifiers.LayoutModifier
 import androidx.wear.protolayout.modifiers.background
 import androidx.wear.protolayout.modifiers.clickable
@@ -50,6 +60,7 @@
 import androidx.wear.protolayout.modifiers.semanticsRole
 import androidx.wear.protolayout.modifiers.tag
 import androidx.wear.protolayout.modifiers.toProtoLayoutModifiers
+import androidx.wear.protolayout.types.dp
 
 /**
  * ProtoLayout Material3 component edge button that offers a single slot to take an icon or similar
@@ -82,14 +93,22 @@
     modifier: LayoutModifier = LayoutModifier,
     colors: ButtonColors = filledButtonColors(),
     iconContent: (MaterialScope.() -> LayoutElement)
-): LayoutElement =
-    edgeButton(onClick = onClick, modifier = modifier, colors = colors, style = DEFAULT) {
+): LayoutElement {
+    val style =
+        if (deviceConfiguration.rendererSchemaVersion.hasAsymmetricalCornersSupport()) {
+            ICON
+        } else {
+            ICON_FALLBACK
+        }
+
+    return edgeButton(onClick = onClick, modifier = modifier, colors = colors, style = style) {
         withStyle(
                 defaultIconStyle =
-                    IconStyle(size = ICON_SIZE_DP.toDp(), tintColor = colors.iconColor)
+                    IconStyle(size = style.iconSizeDp.dp, tintColor = colors.iconColor)
             )
             .iconContent()
     }
+}
 
 /**
  * ProtoLayout Material3 component edge button that offers a single slot to take a text or similar
@@ -123,7 +142,17 @@
     colors: ButtonColors = filledButtonColors(),
     labelContent: (MaterialScope.() -> LayoutElement)
 ): LayoutElement =
-    edgeButton(onClick = onClick, modifier = modifier, colors = colors, style = TOP_ALIGN) {
+    edgeButton(
+        onClick = onClick,
+        modifier = modifier,
+        colors = colors,
+        style =
+            if (deviceConfiguration.rendererSchemaVersion.hasAsymmetricalCornersSupport()) {
+                TEXT
+            } else {
+                TEXT_FALLBACK
+            }
+    ) {
         withStyle(
                 defaultTextElementStyle =
                     TextElementStyle(
@@ -156,8 +185,8 @@
  * @param modifier Modifiers to set to this element. It's highly recommended to set a content
  *   description using [contentDescription].
  * @param style The style used for the inner content, specifying how the content should be aligned.
- *   It is recommended to use [EdgeButtonStyle.TOP_ALIGN] for long, wide content. If not set,
- *   defaults to [EdgeButtonStyle.DEFAULT] which center-aligns the content.
+ *   It is recommended to use [EdgeButtonStyle.TEXT] for long, wide content. If not set, defaults to
+ *   [EdgeButtonStyle.ICON] which center-aligns the content.
  * @param content The inner content to be put inside of this edge button.
  * @sample androidx.wear.protolayout.material3.samples.edgeButtonSampleIcon
  */
@@ -166,7 +195,7 @@
     onClick: Clickable,
     colors: ButtonColors,
     modifier: LayoutModifier = LayoutModifier,
-    style: EdgeButtonStyle = DEFAULT,
+    style: EdgeButtonStyle = ICON,
     content: MaterialScope.() -> LayoutElement
 ): LayoutElement {
     val containerWidth = deviceConfiguration.screenWidthDp.toDp()
@@ -175,50 +204,83 @@
         else HORIZONTAL_MARGIN_PERCENT_SMALL
     val edgeButtonWidth: Float =
         (100f - 2f * horizontalMarginPercent) * deviceConfiguration.screenWidthDp / 100f
-    val bottomCornerRadiusX = edgeButtonWidth / 2f
-    val bottomCornerRadiusY = EDGE_BUTTON_HEIGHT_DP - TOP_CORNER_RADIUS
 
     var mod =
         (LayoutModifier.semanticsRole(SEMANTICS_ROLE_BUTTON) then modifier)
             .clickable(onClick)
             .background(colors.containerColor)
-            .clip(TOP_CORNER_RADIUS)
-            .clipBottomLeft(bottomCornerRadiusX, bottomCornerRadiusY)
-            .clipBottomRight(bottomCornerRadiusX, bottomCornerRadiusY)
+            .clip(style.topCornerRadiusDp)
+
+    if (deviceConfiguration.rendererSchemaVersion.hasAsymmetricalCornersSupport()) {
+        val bottomCornerRadiusX = edgeButtonWidth / 2f
+        val bottomCornerRadiusY = style.buttonHeightDp - style.topCornerRadiusDp
+        mod =
+            mod.clipBottomLeft(bottomCornerRadiusX, bottomCornerRadiusY)
+                .clipBottomRight(bottomCornerRadiusX, bottomCornerRadiusY)
+    }
 
     style.padding?.let { mod = mod.padding(it) }
 
-    val button = Box.Builder().setHeight(EDGE_BUTTON_HEIGHT_DP.toDp()).setWidth(dp(edgeButtonWidth))
-    button
-        .setVerticalAlignment(style.verticalAlignment)
-        .setHorizontalAlignment(LayoutElementBuilders.HORIZONTAL_ALIGN_CENTER)
-        .addContent(content())
+    val button =
+        Box.Builder()
+            .setHeight(style.buttonHeightDp.dp)
+            .setWidth(dp(edgeButtonWidth))
+            .setVerticalAlignment(style.verticalAlignment)
+            .setHorizontalAlignment(LayoutElementBuilders.HORIZONTAL_ALIGN_CENTER)
+            .addContent(content())
+            .setModifiers(mod.toProtoLayoutModifiers())
+            .build()
 
     return Box.Builder()
-        .setHeight((EDGE_BUTTON_HEIGHT_DP + BOTTOM_MARGIN_DP).toDp())
+        .setHeight(CONTAINER_HEIGHT_DP.dp)
         .setWidth(containerWidth)
-        .setVerticalAlignment(LayoutElementBuilders.VERTICAL_ALIGN_TOP)
+        .setVerticalAlignment(LayoutElementBuilders.VERTICAL_ALIGN_BOTTOM)
         .setHorizontalAlignment(LayoutElementBuilders.HORIZONTAL_ALIGN_CENTER)
-        .addContent(button.setModifiers(mod.toProtoLayoutModifiers()).build())
-        .setModifiers(LayoutModifier.tag(METADATA_TAG).toProtoLayoutModifiers())
+        .addContent(button)
+        .setModifiers(
+            LayoutModifier.tag(METADATA_TAG)
+                .padding(padding(bottom = style.bottomMarginDp.toFloat()))
+                .toProtoLayoutModifiers()
+        )
         .build()
 }
 
-/** Provides style values for edge button component. */
-public class EdgeButtonStyle
-private constructor(
+/**
+ * Provides style values for edge button component.
+ *
+ * An [edgeButton] has a wrapper container with the screen width, and fixed height of
+ * [CONTAINER_HEIGHT_DP].
+ *
+ * The visible button box has height of [buttonHeightDp], it is centered horizontally in side the
+ * wrapper container with [HORIZONTAL_MARGIN_PERCENT_SMALL] or [HORIZONTAL_MARGIN_PERCENT_LARGE]
+ * depending on the screen size. It is then horizontally aligned to the bottom with bottom margin of
+ * [bottomMarginDp].
+ *
+ * The visible button box has its top two corners clipped with the [topCornerRadiusDp], while its
+ * bottom two corners will be clipped fully both horizontally and vertically to achieving the edge
+ * hugging shape. In the fallback implementation, without asymmetrical corners support, the
+ * [topCornerRadiusDp] is applied to all four corners.
+ *
+ * The content (icon or text) of the button is located inside the visible button box with [padding],
+ * horizontally centered and vertically aligned with the given [verticalAlignment].
+ */
+internal class EdgeButtonStyle
+internal constructor(
     @VerticalAlignment internal val verticalAlignment: Int = VERTICAL_ALIGN_CENTER,
-    internal val padding: Padding? = null
+    internal val padding: Padding? = null,
+    @Dimension(DP) internal val buttonHeightDp: Float = EDGE_BUTTON_HEIGHT_DP,
+    @Dimension(DP) internal val bottomMarginDp: Float = BOTTOM_MARGIN_DP,
+    @Dimension(DP) internal val iconSizeDp: Float = ICON_SIZE_DP,
+    @Dimension(DP) internal val topCornerRadiusDp: Float = TOP_CORNER_RADIUS
 ) {
-    public companion object {
+    internal companion object {
         /**
-         * Style variation for having content of the edge button anchored to the top.
+         * Style variation for having text content with edge hugging shape.
          *
-         * This should be used for text-like content, or the content that is wide, to accommodate
-         * for more space.
+         * The text is vertically aligned to top with [TEXT_TOP_PADDING_DP] to to accommodate for
+         * more horizontal space.
          */
-        @JvmField
-        public val TOP_ALIGN: EdgeButtonStyle =
+        internal val TEXT: EdgeButtonStyle =
             EdgeButtonStyle(
                 verticalAlignment = LayoutElementBuilders.VERTICAL_ALIGN_TOP,
                 padding =
@@ -230,28 +292,101 @@
             )
 
         /**
-         * Default style variation for having content of the edge button center aligned.
+         * Style variation for having icon content with edge hugging shape.
          *
-         * This should be used for icon-like or small, round content that doesn't occupy a lot of
-         * space.
+         * The icon is centered in the visible button box with the size of [ICON_SIZE_DP].
          */
-        @JvmField public val DEFAULT: EdgeButtonStyle = EdgeButtonStyle()
+        internal val ICON: EdgeButtonStyle = EdgeButtonStyle()
+
+        /**
+         * Style variation for fallback implementation with text content, when there is no
+         * asymmetrical corners support.
+         *
+         * Without the edge hugging shape, the [topCornerRadius] value is a full cornered value and
+         * is applied to all four corners. To avoid being clipped by the screen edge, the visible
+         * button box is pushed upwards with a bigger bottom margin of [BOTTOM_MARGIN_FALLBACK_DP].
+         * Also the box height shrinks to [EDGE_BUTTON_HEIGHT_FALLBACK_DP].
+         *
+         * Its text content is center placed with a increased horizontal padding of
+         * [TEXT_SIDE_PADDING_FALLBACK_DP].
+         */
+        internal val TEXT_FALLBACK: EdgeButtonStyle =
+            EdgeButtonStyle(
+                verticalAlignment = VERTICAL_ALIGN_CENTER,
+                padding =
+                    padding(
+                        start = TEXT_SIDE_PADDING_FALLBACK_DP,
+                        end = TEXT_SIDE_PADDING_FALLBACK_DP,
+                    ),
+                buttonHeightDp = EDGE_BUTTON_HEIGHT_FALLBACK_DP,
+                topCornerRadiusDp = CORNER_RADIUS_FALLBACK_DP,
+                bottomMarginDp = BOTTOM_MARGIN_FALLBACK_DP
+            )
+
+        /**
+         * Style variation for fallback implementation with icon content, when there is no
+         * asymmetrical corners support.
+         *
+         * Without the edge hugging shape, the [topCornerRadius] value is a full cornered value and
+         * is applied to all four corners. To avoid being clipped by the screen, the visible button
+         * box is pushed upwards with a bigger bottom margin of [BOTTOM_MARGIN_FALLBACK_DP]. Also
+         * the box height shrinks to [EDGE_BUTTON_HEIGHT_FALLBACK_DP]
+         *
+         * Its icon content center placed with increased horizontal padding
+         * [ICON_SIDE_PADDING_FALLBACK_DP]. Also, the icon size is also increased to
+         * [ICON_SIZE_FALLBACK_DP].
+         */
+        internal val ICON_FALLBACK: EdgeButtonStyle =
+            EdgeButtonStyle(
+                verticalAlignment = VERTICAL_ALIGN_CENTER,
+                padding =
+                    padding(
+                        start = ICON_SIDE_PADDING_FALLBACK_DP,
+                        end = ICON_SIDE_PADDING_FALLBACK_DP,
+                    ),
+                buttonHeightDp = EDGE_BUTTON_HEIGHT_FALLBACK_DP,
+                topCornerRadiusDp = CORNER_RADIUS_FALLBACK_DP,
+                bottomMarginDp = BOTTOM_MARGIN_FALLBACK_DP,
+                iconSizeDp = ICON_SIZE_FALLBACK_DP
+            )
     }
 }
 
 internal object EdgeButtonDefaults {
-    @Dimension(DP) internal const val TOP_CORNER_RADIUS: Float = 17f
+    @Dimension(DP) internal const val TOP_CORNER_RADIUS = 17f
     /** The horizontal margin used for width of the EdgeButton, below the 225dp breakpoint. */
-    internal const val HORIZONTAL_MARGIN_PERCENT_SMALL: Float = 24f
+    internal const val HORIZONTAL_MARGIN_PERCENT_SMALL = 24f
     /** The horizontal margin used for width of the EdgeButton, above the 225dp breakpoint. */
-    internal const val HORIZONTAL_MARGIN_PERCENT_LARGE: Float = 26f
-    internal const val BOTTOM_MARGIN_DP: Int = 3
-    internal const val EDGE_BUTTON_HEIGHT_DP: Int = 46
-    internal const val METADATA_TAG: String = "EB"
-    internal const val ICON_SIZE_DP = 24
-    internal const val TEXT_TOP_PADDING_DP = 12f
-    internal const val TEXT_SIDE_PADDING_DP = 8f
+    internal const val HORIZONTAL_MARGIN_PERCENT_LARGE = 26f
+    @Dimension(DP) internal const val BOTTOM_MARGIN_DP = 3f
+    @Dimension(DP) internal const val EDGE_BUTTON_HEIGHT_DP = 46f
+    @Dimension(DP) internal const val CONTAINER_HEIGHT_DP = EDGE_BUTTON_HEIGHT_DP + BOTTOM_MARGIN_DP
+    internal const val METADATA_TAG = "EB"
+    @Dimension(DP) internal const val ICON_SIZE_DP = 24f
+    @Dimension(DP) internal const val TEXT_TOP_PADDING_DP = 12f
+    @Dimension(DP) internal const val TEXT_SIDE_PADDING_DP = 8f
+}
+
+/**
+ * This object provides constants and styles of the fallback layout for [iconEdgeButton] and
+ * [textEdgeButton] when the renderer version is lower than 1.3.3 where asymmetrical corners support
+ * is not available.
+ */
+internal object EdgeButtonFallbackDefaults {
+    @Dimension(DP) internal const val ICON_SIZE_FALLBACK_DP = 26f
+    @Dimension(DP) internal const val EDGE_BUTTON_HEIGHT_FALLBACK_DP = 40f
+    @Dimension(DP) internal const val BOTTOM_MARGIN_FALLBACK_DP = 7f
+    @Dimension(DP)
+    internal const val CORNER_RADIUS_FALLBACK_DP = EDGE_BUTTON_HEIGHT_FALLBACK_DP / 2f
+    @Dimension(DP) internal const val TEXT_SIDE_PADDING_FALLBACK_DP = 14f
+    @Dimension(DP) internal const val ICON_SIDE_PADDING_FALLBACK_DP = 20f
 }
 
 internal fun LayoutElement.isSlotEdgeButton(): Boolean =
     this is Box && METADATA_TAG == this.modifiers?.metadata?.toTagName()
+
+/**
+ * Checks whether the renderer has support for asymmetrical corners, which is added in version
+ * 1.303.
+ */
+private fun VersionInfo.hasAsymmetricalCornersSupport() = major > 1 || (major == 1 && minor >= 303)
diff --git a/wear/protolayout/protolayout-material3/src/test/java/androidx/wear/protolayout/material3/EdgeButtonTest.kt b/wear/protolayout/protolayout-material3/src/test/java/androidx/wear/protolayout/material3/EdgeButtonTest.kt
index c8c40e5..15636ae 100644
--- a/wear/protolayout/protolayout-material3/src/test/java/androidx/wear/protolayout/material3/EdgeButtonTest.kt
+++ b/wear/protolayout/protolayout-material3/src/test/java/androidx/wear/protolayout/material3/EdgeButtonTest.kt
@@ -25,8 +25,11 @@
 import androidx.wear.protolayout.LayoutElementBuilders.Image
 import androidx.wear.protolayout.expression.AppDataKey
 import androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32
-import androidx.wear.protolayout.material3.EdgeButtonDefaults.BOTTOM_MARGIN_DP
+import androidx.wear.protolayout.expression.VersionBuilders.VersionInfo
+import androidx.wear.protolayout.material3.EdgeButtonDefaults.CONTAINER_HEIGHT_DP
 import androidx.wear.protolayout.material3.EdgeButtonDefaults.EDGE_BUTTON_HEIGHT_DP
+import androidx.wear.protolayout.material3.EdgeButtonFallbackDefaults.EDGE_BUTTON_HEIGHT_FALLBACK_DP
+import androidx.wear.protolayout.material3.EdgeButtonFallbackDefaults.ICON_SIZE_FALLBACK_DP
 import androidx.wear.protolayout.modifiers.LayoutModifier
 import androidx.wear.protolayout.modifiers.clickable
 import androidx.wear.protolayout.modifiers.contentDescription
@@ -41,6 +44,7 @@
 import androidx.wear.protolayout.testing.isClickable
 import androidx.wear.protolayout.types.LayoutString
 import androidx.wear.protolayout.types.asLayoutConstraint
+import androidx.wear.protolayout.types.dp
 import androidx.wear.protolayout.types.layoutString
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -54,14 +58,14 @@
         LayoutElementAssertionsProvider(ICON_EDGE_BUTTON)
             .onRoot()
             .assert(hasWidth(DEVICE_CONFIGURATION.screenWidthDp.toDp()))
-            .assert(hasHeight((EDGE_BUTTON_HEIGHT_DP + BOTTOM_MARGIN_DP).toDp()))
+            .assert(hasHeight(CONTAINER_HEIGHT_DP.dp))
     }
 
     @Test
     fun visibleHeight() {
         LayoutElementAssertionsProvider(ICON_EDGE_BUTTON)
             .onElement(isClickable())
-            .assert(hasHeight(EDGE_BUTTON_HEIGHT_DP.toDp()))
+            .assert(hasHeight(EDGE_BUTTON_HEIGHT_DP.dp))
     }
 
     @Test
@@ -163,6 +167,29 @@
             .assert(hasColor(COLOR_SCHEME.onPrimary.staticArgb))
     }
 
+    @Test
+    fun containerFallbackSize() {
+        LayoutElementAssertionsProvider(ICON_EDGE_BUTTON_FALLBACK)
+            .onRoot()
+            .assert(hasWidth(DEVICE_CONFIGURATION.screenWidthDp.toDp()))
+            .assert(hasHeight(CONTAINER_HEIGHT_DP.dp))
+    }
+
+    @Test
+    fun visibleFallbackHeight() {
+        LayoutElementAssertionsProvider(ICON_EDGE_BUTTON_FALLBACK)
+            .onElement(isClickable())
+            .assert(hasHeight(EDGE_BUTTON_HEIGHT_FALLBACK_DP.dp))
+    }
+
+    @Test
+    fun iconFallbackSize() {
+        LayoutElementAssertionsProvider(ICON_EDGE_BUTTON_FALLBACK)
+            .onElement(hasImage(RES_ID))
+            .assert(hasWidth(ICON_SIZE_FALLBACK_DP.dp))
+            .assert(hasHeight(ICON_SIZE_FALLBACK_DP.dp))
+    }
+
     companion object {
         private val CONTEXT = getApplicationContext() as Context
         private val COLOR_SCHEME = ColorScheme()
@@ -171,6 +198,14 @@
             DeviceParametersBuilders.DeviceParameters.Builder()
                 .setScreenWidthDp(192)
                 .setScreenHeightDp(192)
+                .setRendererSchemaVersion(VersionInfo.Builder().setMajor(99).setMinor(999).build())
+                .build()
+
+        private val DEVICE_CONFIGURATION_WITH_OLD_RENDERER =
+            DeviceParametersBuilders.DeviceParameters.Builder()
+                .setScreenWidthDp(192)
+                .setScreenHeightDp(192)
+                .setRendererSchemaVersion(VersionInfo.Builder().setMajor(1).setMinor(302).build())
                 .build()
 
         private val CLICKABLE =
@@ -188,5 +223,18 @@
                     icon(RES_ID)
                 }
             }
+        private val ICON_EDGE_BUTTON_FALLBACK =
+            materialScope(
+                CONTEXT,
+                DEVICE_CONFIGURATION_WITH_OLD_RENDERER,
+                allowDynamicTheme = false
+            ) {
+                iconEdgeButton(
+                    onClick = CLICKABLE,
+                    modifier = LayoutModifier.contentDescription(CONTENT_DESCRIPTION)
+                ) {
+                    icon(RES_ID)
+                }
+            }
     }
 }