Merge "Revert "Fixed bug having to do with Row/Column not having the right intrinsic settings"" into androidx-main
diff --git a/compose/foundation/foundation/api/current.ignore b/compose/foundation/foundation/api/current.ignore
index dab733e..ea44979 100644
--- a/compose/foundation/foundation/api/current.ignore
+++ b/compose/foundation/foundation/api/current.ignore
@@ -1,5 +1,19 @@
 // Baseline format: 1.0
+AddedAbstractMethod: androidx.compose.foundation.gestures.DraggableAnchors#anchorAt(int):
+    Added method androidx.compose.foundation.gestures.DraggableAnchors.anchorAt(int)
+AddedAbstractMethod: androidx.compose.foundation.gestures.DraggableAnchors#hasPositionFor(T):
+    Added method androidx.compose.foundation.gestures.DraggableAnchors.hasPositionFor(T)
+AddedAbstractMethod: androidx.compose.foundation.gestures.DraggableAnchors#maxPosition():
+    Added method androidx.compose.foundation.gestures.DraggableAnchors.maxPosition()
+AddedAbstractMethod: androidx.compose.foundation.gestures.DraggableAnchors#minPosition():
+    Added method androidx.compose.foundation.gestures.DraggableAnchors.minPosition()
+AddedAbstractMethod: androidx.compose.foundation.gestures.DraggableAnchors#positionAt(int):
+    Added method androidx.compose.foundation.gestures.DraggableAnchors.positionAt(int)
 AddedAbstractMethod: androidx.compose.foundation.lazy.grid.LazyGridItemInfo#getSpan():
     Added method androidx.compose.foundation.lazy.grid.LazyGridItemInfo.getSpan()
 AddedAbstractMethod: androidx.compose.foundation.lazy.grid.LazyGridLayoutInfo#getMaxSpan():
     Added method androidx.compose.foundation.lazy.grid.LazyGridLayoutInfo.getMaxSpan()
+
+
+ParameterNameChange: androidx.compose.foundation.gestures.DraggableAnchors#positionOf(T) parameter #0:
+    Attempted to change parameter name from value to anchor in method androidx.compose.foundation.gestures.DraggableAnchors.positionOf
diff --git a/compose/foundation/foundation/api/current.txt b/compose/foundation/foundation/api/current.txt
index d2cfb40..e3708d9 100644
--- a/compose/foundation/foundation/api/current.txt
+++ b/compose/foundation/foundation/api/current.txt
@@ -413,6 +413,7 @@
     method public static <T> androidx.compose.ui.Modifier anchoredDraggable(androidx.compose.ui.Modifier, androidx.compose.foundation.gestures.AnchoredDraggableState<T> state, boolean reverseDirection, androidx.compose.foundation.gestures.Orientation orientation, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, optional boolean startDragImmediately, optional androidx.compose.foundation.gestures.FlingBehavior? flingBehavior);
     method public static suspend <T> Object? animateTo(androidx.compose.foundation.gestures.AnchoredDraggableState<T>, T targetValue, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float> animationSpec, kotlin.coroutines.Continuation<? super kotlin.Unit>);
     method public static suspend <T> Object? animateToWithDecay(androidx.compose.foundation.gestures.AnchoredDraggableState<T>, T targetValue, float velocity, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float> snapAnimationSpec, optional androidx.compose.animation.core.DecayAnimationSpec<java.lang.Float> decayAnimationSpec, kotlin.coroutines.Continuation<? super java.lang.Float>);
+    method public static inline <T> void forEach(androidx.compose.foundation.gestures.DraggableAnchors<T>, kotlin.jvm.functions.Function2<? super T,? super java.lang.Float,kotlin.Unit> block);
     method public static suspend <T> Object? snapTo(androidx.compose.foundation.gestures.AnchoredDraggableState<T>, T targetValue, kotlin.coroutines.Continuation<? super kotlin.Unit>);
   }
 
@@ -509,14 +510,15 @@
   }
 
   public interface DraggableAnchors<T> {
+    method public T? anchorAt(int index);
     method public T? closestAnchor(float position);
     method public T? closestAnchor(float position, boolean searchUpwards);
-    method public void forEach(kotlin.jvm.functions.Function2<? super T,? super java.lang.Float,kotlin.Unit> block);
     method public int getSize();
-    method public boolean hasAnchorFor(T value);
-    method public float maxAnchor();
-    method public float minAnchor();
-    method public float positionOf(T value);
+    method public boolean hasPositionFor(T anchor);
+    method public float maxPosition();
+    method public float minPosition();
+    method public float positionAt(int index);
+    method public float positionOf(T anchor);
     property public abstract int size;
   }
 
diff --git a/compose/foundation/foundation/api/restricted_current.ignore b/compose/foundation/foundation/api/restricted_current.ignore
index dab733e..ea44979 100644
--- a/compose/foundation/foundation/api/restricted_current.ignore
+++ b/compose/foundation/foundation/api/restricted_current.ignore
@@ -1,5 +1,19 @@
 // Baseline format: 1.0
+AddedAbstractMethod: androidx.compose.foundation.gestures.DraggableAnchors#anchorAt(int):
+    Added method androidx.compose.foundation.gestures.DraggableAnchors.anchorAt(int)
+AddedAbstractMethod: androidx.compose.foundation.gestures.DraggableAnchors#hasPositionFor(T):
+    Added method androidx.compose.foundation.gestures.DraggableAnchors.hasPositionFor(T)
+AddedAbstractMethod: androidx.compose.foundation.gestures.DraggableAnchors#maxPosition():
+    Added method androidx.compose.foundation.gestures.DraggableAnchors.maxPosition()
+AddedAbstractMethod: androidx.compose.foundation.gestures.DraggableAnchors#minPosition():
+    Added method androidx.compose.foundation.gestures.DraggableAnchors.minPosition()
+AddedAbstractMethod: androidx.compose.foundation.gestures.DraggableAnchors#positionAt(int):
+    Added method androidx.compose.foundation.gestures.DraggableAnchors.positionAt(int)
 AddedAbstractMethod: androidx.compose.foundation.lazy.grid.LazyGridItemInfo#getSpan():
     Added method androidx.compose.foundation.lazy.grid.LazyGridItemInfo.getSpan()
 AddedAbstractMethod: androidx.compose.foundation.lazy.grid.LazyGridLayoutInfo#getMaxSpan():
     Added method androidx.compose.foundation.lazy.grid.LazyGridLayoutInfo.getMaxSpan()
+
+
+ParameterNameChange: androidx.compose.foundation.gestures.DraggableAnchors#positionOf(T) parameter #0:
+    Attempted to change parameter name from value to anchor in method androidx.compose.foundation.gestures.DraggableAnchors.positionOf
diff --git a/compose/foundation/foundation/api/restricted_current.txt b/compose/foundation/foundation/api/restricted_current.txt
index 19498c7..37aaab2 100644
--- a/compose/foundation/foundation/api/restricted_current.txt
+++ b/compose/foundation/foundation/api/restricted_current.txt
@@ -415,6 +415,7 @@
     method public static <T> androidx.compose.ui.Modifier anchoredDraggable(androidx.compose.ui.Modifier, androidx.compose.foundation.gestures.AnchoredDraggableState<T> state, boolean reverseDirection, androidx.compose.foundation.gestures.Orientation orientation, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, optional boolean startDragImmediately, optional androidx.compose.foundation.gestures.FlingBehavior? flingBehavior);
     method public static suspend <T> Object? animateTo(androidx.compose.foundation.gestures.AnchoredDraggableState<T>, T targetValue, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float> animationSpec, kotlin.coroutines.Continuation<? super kotlin.Unit>);
     method public static suspend <T> Object? animateToWithDecay(androidx.compose.foundation.gestures.AnchoredDraggableState<T>, T targetValue, float velocity, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float> snapAnimationSpec, optional androidx.compose.animation.core.DecayAnimationSpec<java.lang.Float> decayAnimationSpec, kotlin.coroutines.Continuation<? super java.lang.Float>);
+    method public static inline <T> void forEach(androidx.compose.foundation.gestures.DraggableAnchors<T>, kotlin.jvm.functions.Function2<? super T,? super java.lang.Float,kotlin.Unit> block);
     method public static suspend <T> Object? snapTo(androidx.compose.foundation.gestures.AnchoredDraggableState<T>, T targetValue, kotlin.coroutines.Continuation<? super kotlin.Unit>);
   }
 
@@ -511,14 +512,15 @@
   }
 
   public interface DraggableAnchors<T> {
+    method public T? anchorAt(int index);
     method public T? closestAnchor(float position);
     method public T? closestAnchor(float position, boolean searchUpwards);
-    method public void forEach(kotlin.jvm.functions.Function2<? super T,? super java.lang.Float,kotlin.Unit> block);
     method public int getSize();
-    method public boolean hasAnchorFor(T value);
-    method public float maxAnchor();
-    method public float minAnchor();
-    method public float positionOf(T value);
+    method public boolean hasPositionFor(T anchor);
+    method public float maxPosition();
+    method public float minPosition();
+    method public float positionAt(int index);
+    method public float positionOf(T anchor);
     property public abstract int size;
   }
 
diff --git a/compose/foundation/foundation/benchmark/src/androidTest/java/androidx/compose/foundation/benchmark/DraggableAnchorsBenchmark.kt b/compose/foundation/foundation/benchmark/src/androidTest/java/androidx/compose/foundation/benchmark/DraggableAnchorsBenchmark.kt
index 8b3472f..c500e30 100644
--- a/compose/foundation/foundation/benchmark/src/androidTest/java/androidx/compose/foundation/benchmark/DraggableAnchorsBenchmark.kt
+++ b/compose/foundation/foundation/benchmark/src/androidTest/java/androidx/compose/foundation/benchmark/DraggableAnchorsBenchmark.kt
@@ -102,7 +102,7 @@
     }
 
     @Test
-    fun hasAnchorFor() {
+    fun hasPositionFor() {
         val anchors = DraggableAnchors {
             DraggableAnchorsSampleValue.Start at 0f
             DraggableAnchorsSampleValue.HalfStart at 100f
@@ -110,11 +110,11 @@
             DraggableAnchorsSampleValue.HalfEnd at 300f
             DraggableAnchorsSampleValue.End at 400f
         }
-        benchmarkRule.measureRepeated { anchors.hasAnchorFor(DraggableAnchorsSampleValue.Center) }
+        benchmarkRule.measureRepeated { anchors.hasPositionFor(DraggableAnchorsSampleValue.Center) }
     }
 
     @Test
-    fun minAnchor() {
+    fun minPosition() {
         val anchors = DraggableAnchors {
             DraggableAnchorsSampleValue.Start at 0f
             DraggableAnchorsSampleValue.HalfStart at 100f
@@ -122,11 +122,11 @@
             DraggableAnchorsSampleValue.HalfEnd at 300f
             DraggableAnchorsSampleValue.End at 400f
         }
-        benchmarkRule.measureRepeated { anchors.minAnchor() }
+        benchmarkRule.measureRepeated { anchors.minPosition() }
     }
 
     @Test
-    fun maxAnchor() {
+    fun maxPosition() {
         val anchors = DraggableAnchors {
             DraggableAnchorsSampleValue.Start at 0f
             DraggableAnchorsSampleValue.HalfStart at 100f
@@ -134,6 +134,6 @@
             DraggableAnchorsSampleValue.HalfEnd at 300f
             DraggableAnchorsSampleValue.End at 400f
         }
-        benchmarkRule.measureRepeated { anchors.maxAnchor() }
+        benchmarkRule.measureRepeated { anchors.maxPosition() }
     }
 }
diff --git a/compose/foundation/foundation/samples/src/main/java/androidx/compose/foundation/samples/AnchoredDraggableSample.kt b/compose/foundation/foundation/samples/src/main/java/androidx/compose/foundation/samples/AnchoredDraggableSample.kt
index baf477f..499c99d 100644
--- a/compose/foundation/foundation/samples/src/main/java/androidx/compose/foundation/samples/AnchoredDraggableSample.kt
+++ b/compose/foundation/foundation/samples/src/main/java/androidx/compose/foundation/samples/AnchoredDraggableSample.kt
@@ -28,6 +28,7 @@
 import androidx.compose.foundation.gestures.ScrollableDefaults
 import androidx.compose.foundation.gestures.anchoredDraggable
 import androidx.compose.foundation.gestures.draggable
+import androidx.compose.foundation.gestures.forEach
 import androidx.compose.foundation.gestures.rememberDraggableState
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
@@ -331,7 +332,10 @@
                     state =
                         rememberDraggableState { delta ->
                             offset =
-                                (offset + delta).coerceIn(anchors.minAnchor(), anchors.maxAnchor())
+                                (offset + delta).coerceIn(
+                                    anchors.minPosition(),
+                                    anchors.maxPosition()
+                                )
                         },
                     orientation = Orientation.Horizontal,
                     onDragStopped = { velocity ->
diff --git a/compose/foundation/foundation/src/androidUnitTest/kotlin/androidx/compose/foundation/gestures/DraggableAnchorsTest.kt b/compose/foundation/foundation/src/androidUnitTest/kotlin/androidx/compose/foundation/gestures/DraggableAnchorsTest.kt
index 73ac5ed..dbe355f 100644
--- a/compose/foundation/foundation/src/androidUnitTest/kotlin/androidx/compose/foundation/gestures/DraggableAnchorsTest.kt
+++ b/compose/foundation/foundation/src/androidUnitTest/kotlin/androidx/compose/foundation/gestures/DraggableAnchorsTest.kt
@@ -68,28 +68,28 @@
     }
 
     @Test
-    fun draggableAnchors_minAnchor() {
+    fun draggableAnchors_minPosition() {
         val anchors = DraggableAnchors {
             A at -100f
             B at 100f
         }
-        assertThat(anchors.minAnchor()).isEqualTo(-100f)
+        assertThat(anchors.minPosition()).isEqualTo(-100f)
     }
 
     @Test
-    fun draggableAnchors_maxAnchor() {
+    fun draggableAnchors_maxPosition() {
         val anchors = DraggableAnchors {
             A at -100f
             B at 100f
         }
-        assertThat(anchors.maxAnchor()).isEqualTo(100f)
+        assertThat(anchors.maxPosition()).isEqualTo(100f)
     }
 
     @Test
-    fun draggableAnchors_hasAnchorFor() {
+    fun draggableAnchors_hasPositionFor() {
         val anchors = DraggableAnchors { A at 100f }
         assertThat(anchors.positionOf(A)).isEqualTo(100f)
-        assertThat(anchors.hasAnchorFor(A)).isTrue()
+        assertThat(anchors.hasPositionFor(A)).isTrue()
     }
 }
 
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/AnchoredDraggable.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/AnchoredDraggable.kt
index c036c6d..9d6d74a 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/AnchoredDraggable.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/AnchoredDraggable.kt
@@ -17,8 +17,6 @@
 package androidx.compose.foundation.gestures
 
 import androidx.annotation.FloatRange
-import androidx.collection.MutableObjectFloatMap
-import androidx.collection.ObjectFloatMap
 import androidx.compose.animation.core.AnimationSpec
 import androidx.compose.animation.core.AnimationState
 import androidx.compose.animation.core.DecayAnimationSpec
@@ -435,8 +433,8 @@
                     availableVelocity ->
                     val consumed = fling(velocity.reverseIfNeeded().toFloat())
                     val currentOffset = state.requireOffset()
-                    val minAnchor = state.anchors.minAnchor()
-                    val maxAnchor = state.anchors.maxAnchor()
+                    val minAnchor = state.anchors.minPosition()
+                    val maxAnchor = state.anchors.maxPosition()
                     // return consumed velocity only if we are reaching the min/max anchors
                     if (currentOffset >= maxAnchor || currentOffset <= minAnchor) {
                         consumed.toVelocity()
@@ -538,27 +536,31 @@
  * Structure that represents the anchors of a [AnchoredDraggableState].
  *
  * See the DraggableAnchors factory method to construct drag anchors using a default implementation.
+ * This structure does not make any guarantees about ordering of the anchors.
  */
 interface DraggableAnchors<T> {
 
+    /** The amount of anchors */
+    val size: Int
+
     /**
-     * Get the anchor position for an associated [value]
+     * Get the anchor position for an associated [anchor]
      *
-     * @param value The value to look up
+     * @param anchor The value to look up
      * @return The position of the anchor, or [Float.NaN] if the anchor does not exist
      */
-    fun positionOf(value: T): Float
+    fun positionOf(anchor: T): Float
 
     /**
-     * Whether there is an anchor position associated with the [value]
+     * Whether there is an anchor position associated with the [anchor]
      *
-     * @param value The value to look up
+     * @param anchor The value to look up
      * @return true if there is an anchor for this value, false if there is no anchor for this value
      */
-    fun hasAnchorFor(value: T): Boolean
+    fun hasPositionFor(anchor: T): Boolean
 
     /**
-     * Find the closest anchor to the [position].
+     * Find the closest anchor value to the [position].
      *
      * @param position The position to start searching from
      * @return The closest anchor or null if the anchors are empty
@@ -566,7 +568,7 @@
     fun closestAnchor(position: Float): T?
 
     /**
-     * Find the closest anchor to the [position], in the specified direction.
+     * Find the closest anchor value to the [position], in the specified direction.
      *
      * @param position The position to start searching from
      * @param searchUpwards Whether to search upwards from the current position or downwards
@@ -575,20 +577,31 @@
     fun closestAnchor(position: Float, searchUpwards: Boolean): T?
 
     /** The smallest anchor, or [Float.NEGATIVE_INFINITY] if the anchors are empty. */
-    fun minAnchor(): Float
+    fun minPosition(): Float
 
     /** The biggest anchor, or [Float.POSITIVE_INFINITY] if the anchors are empty. */
-    fun maxAnchor(): Float
+    fun maxPosition(): Float
+
+    /** Get the anchor key at the specified index, or null if the index is out of bounds. */
+    fun anchorAt(index: Int): T?
 
     /**
-     * Iterate over all the anchors and corresponding positions.
-     *
-     * @param block The action to invoke with the anchor and position
+     * Get the anchor position at the specified index, or [Float.NaN] if the index is out of bounds.
      */
-    fun forEach(block: (anchor: T, position: Float) -> Unit)
+    fun positionAt(index: Int): Float
+}
 
-    /** The amount of anchors */
-    val size: Int
+/**
+ * Iterate over all the anchors.
+ *
+ * @param block The action to invoke with the key and position
+ */
+inline fun <T> DraggableAnchors<T>.forEach(block: (key: T, position: Float) -> Unit) {
+    for (i in 0 until size) {
+        val key =
+            requireNotNull(anchorAt(i)) { "There was no key at index $i. Please report a bug." }
+        block(key, positionAt(i))
+    }
 }
 
 /**
@@ -598,7 +611,8 @@
  */
 class DraggableAnchorsConfig<T> {
 
-    internal val anchors = MutableObjectFloatMap<T>()
+    internal val keys = mutableListOf<T>()
+    internal var positions = FloatArray(size = 5) { Float.NaN }
 
     /**
      * Set the anchor position for [this] anchor.
@@ -607,7 +621,26 @@
      */
     @Suppress("BuilderSetStyle")
     infix fun T.at(position: Float) {
-        anchors[this] = position
+        keys.add(this)
+        if (positions.size < keys.size) {
+            expandPositions()
+        }
+        positions[keys.size - 1] = position
+    }
+
+    internal fun buildPositions(): FloatArray {
+        // We might have expanded more than we actually need, so trim the array
+        return positions.copyOfRange(
+            fromIndex = 0,
+            // toIndex is exclusive, so we need to take the entire keys.size, not just - 1
+            toIndex = keys.size
+        )
+    }
+
+    internal fun buildKeys(): List<T> = keys
+
+    private fun expandPositions() {
+        positions = positions.copyOf(keys.size + 2)
     }
 }
 
@@ -618,8 +651,10 @@
  * @return A new [DraggableAnchors] instance with the anchor positions set by the `builder`
  *   function.
  */
-fun <T : Any> DraggableAnchors(builder: DraggableAnchorsConfig<T>.() -> Unit): DraggableAnchors<T> =
-    MapDraggableAnchors(DraggableAnchorsConfig<T>().apply(builder).anchors)
+fun <T : Any> DraggableAnchors(builder: DraggableAnchorsConfig<T>.() -> Unit): DraggableAnchors<T> {
+    val config = DraggableAnchorsConfig<T>().apply(builder)
+    return DefaultDraggableAnchors(keys = config.buildKeys(), anchors = config.buildPositions())
+}
 
 /**
  * Scope used for suspending anchored drag blocks. Allows to set [AnchoredDraggableState.offset] to
@@ -1094,7 +1129,7 @@
         dragPriority: MutatePriority = MutatePriority.Default,
         block: suspend AnchoredDragScope.(anchor: DraggableAnchors<T>, targetValue: T) -> Unit
     ) {
-        if (anchors.hasAnchorFor(targetValue)) {
+        if (anchors.hasPositionFor(targetValue)) {
             try {
                 dragMutex.mutate(dragPriority) {
                     dragTarget = targetValue
@@ -1128,8 +1163,8 @@
      */
     internal fun newOffsetForDelta(delta: Float) =
         ((if (offset.isNaN()) 0f else offset) + delta).coerceIn(
-            anchors.minAnchor(),
-            anchors.maxAnchor()
+            anchors.minPosition(),
+            anchors.maxPosition()
         )
 
     /**
@@ -1482,84 +1517,95 @@
     }
 }
 
-private fun <T> emptyDraggableAnchors() = MapDraggableAnchors<T>(MutableObjectFloatMap())
+private fun <T> emptyDraggableAnchors() = DefaultDraggableAnchors<T>(emptyList(), FloatArray(0))
 
-private class MapDraggableAnchors<T>(private val anchors: ObjectFloatMap<T>) : DraggableAnchors<T> {
+private val GetOrNan: (Int) -> Float = { Float.NaN }
 
-    override fun positionOf(value: T): Float = anchors.getOrDefault(value, Float.NaN)
+private class DefaultDraggableAnchors<T>(
+    private val keys: List<T>,
+    private val anchors: FloatArray
+) : DraggableAnchors<T> {
 
-    override fun hasAnchorFor(value: T) = anchors.containsKey(value)
+    init {
+        assert(keys.size == anchors.size) {
+            "DraggableAnchors were constructed with " +
+                "inconsistent key-value sizes. Keys: $keys | Anchors: ${anchors.toList()}"
+        }
+    }
+
+    override fun positionOf(anchor: T): Float {
+        val index = keys.indexOf(anchor)
+        return anchors.getOrElse(index, GetOrNan)
+    }
+
+    override fun hasPositionFor(anchor: T) = keys.indexOf(anchor) != -1
 
     override fun closestAnchor(position: Float): T? {
-        var minAnchor: T? = null
+        var minAnchorIndex = -1
         var minDistance = Float.POSITIVE_INFINITY
-        anchors.forEach { anchor, anchorPosition ->
+        anchors.forEachIndexed { index, anchorPosition ->
             val distance = abs(position - anchorPosition)
             if (distance <= minDistance) {
-                minAnchor = anchor
+                minAnchorIndex = index
                 minDistance = distance
             }
         }
-        return minAnchor
+        return keys[minAnchorIndex]
     }
 
     override fun closestAnchor(position: Float, searchUpwards: Boolean): T? {
-        var minAnchor: T? = null
+        var minAnchorIndex = -1
         var minDistance = Float.POSITIVE_INFINITY
-        anchors.forEach { anchor, anchorPosition ->
+        anchors.forEachIndexed { index, anchorPosition ->
             val delta = if (searchUpwards) anchorPosition - position else position - anchorPosition
             val distance = if (delta < 0) Float.POSITIVE_INFINITY else delta
             if (distance <= minDistance) {
-                minAnchor = anchor
+                minAnchorIndex = index
                 minDistance = distance
             }
         }
-        return minAnchor
+        return keys[minAnchorIndex]
     }
 
-    override fun minAnchor() = anchors.minValueOrNaN()
+    override fun minPosition() = anchors.minOrNull() ?: Float.NaN
 
-    override fun maxAnchor() = anchors.maxValueOrNaN()
+    override fun maxPosition() = anchors.maxOrNull() ?: Float.NaN
 
-    override val size: Int
-        get() = anchors.size
+    override val size = anchors.size
+
+    override fun anchorAt(index: Int) = keys.getOrNull(index)
+
+    override fun positionAt(index: Int) = anchors.getOrElse(index, GetOrNan)
 
     override fun equals(other: Any?): Boolean {
         if (this === other) return true
-        if (other !is MapDraggableAnchors<*>) return false
 
-        return anchors == other.anchors
+        other as DefaultDraggableAnchors<*>
+
+        if (keys != other.keys) return false
+        if (!anchors.contentEquals(other.anchors)) return false
+        if (size != other.size) return false
+
+        return true
     }
 
-    override fun hashCode() = 31 * anchors.hashCode()
-
-    override fun toString() = "MapDraggableAnchors($anchors)"
-
-    override fun forEach(block: (anchor: T, position: Float) -> Unit) {
-        anchors.forEach(block)
+    override fun hashCode(): Int {
+        var result = keys.hashCode()
+        result = 31 * result + anchors.contentHashCode()
+        result = 31 * result + size
+        return result
     }
-}
 
-private fun <K> ObjectFloatMap<K>.minValueOrNaN(): Float {
-    if (size == 1) return Float.NaN
-    var minValue = Float.POSITIVE_INFINITY
-    forEachValue { value ->
-        if (value <= minValue) {
-            minValue = value
+    override fun toString() = buildString {
+        append("DraggableAnchors(anchors={")
+        for (i in 0 until size) {
+            append("${anchorAt(0)}=${positionAt(i)}")
+            if (i < size - 1) {
+                append(", ")
+            }
         }
+        append("})")
     }
-    return minValue
-}
-
-private fun <K> ObjectFloatMap<K>.maxValueOrNaN(): Float {
-    if (size == 1) return Float.NaN
-    var maxValue = Float.NEGATIVE_INFINITY
-    forEachValue { value ->
-        if (value >= maxValue) {
-            maxValue = value
-        }
-    }
-    return maxValue
 }
 
 internal val AnchoredDraggableMinFlingVelocity = 125.dp
diff --git a/compose/material/material/src/androidUnitTest/kotlin/androidx/compose/material/DraggableAnchorsTest.kt b/compose/material/material/src/androidUnitTest/kotlin/androidx/compose/material/DraggableAnchorsTest.kt
index 1925376..420079f 100644
--- a/compose/material/material/src/androidUnitTest/kotlin/androidx/compose/material/DraggableAnchorsTest.kt
+++ b/compose/material/material/src/androidUnitTest/kotlin/androidx/compose/material/DraggableAnchorsTest.kt
@@ -70,7 +70,7 @@
     }
 
     @Test
-    fun draggableAnchors_minAnchor() {
+    fun draggableAnchors_minPosition() {
         val anchors = DraggableAnchors {
             A at -100f
             B at 100f
@@ -79,7 +79,7 @@
     }
 
     @Test
-    fun draggableAnchors_maxAnchor() {
+    fun draggableAnchors_maxPosition() {
         val anchors = DraggableAnchors {
             A at -100f
             B at 100f
@@ -88,7 +88,7 @@
     }
 
     @Test
-    fun draggableAnchors_hasAnchorFor() {
+    fun draggableAnchors_hasPositionFor() {
         val anchors = DraggableAnchors { A at 100f }
         assertThat(anchors.positionOf(A)).isEqualTo(100f)
         assertThat(anchors.hasAnchorFor(A)).isTrue()
diff --git a/compose/ui/ui-graphics/src/androidInstrumentedTest/kotlin/androidx/compose/ui/graphics/layer/AndroidGraphicsLayerTest.kt b/compose/ui/ui-graphics/src/androidInstrumentedTest/kotlin/androidx/compose/ui/graphics/layer/AndroidGraphicsLayerTest.kt
index 5c539bbe..350d763 100644
--- a/compose/ui/ui-graphics/src/androidInstrumentedTest/kotlin/androidx/compose/ui/graphics/layer/AndroidGraphicsLayerTest.kt
+++ b/compose/ui/ui-graphics/src/androidInstrumentedTest/kotlin/androidx/compose/ui/graphics/layer/AndroidGraphicsLayerTest.kt
@@ -16,7 +16,6 @@
 
 package androidx.compose.ui.graphics.layer
 
-import android.graphics.Bitmap
 import android.graphics.Canvas
 import android.graphics.ColorFilter
 import android.graphics.PixelFormat
@@ -44,7 +43,6 @@
 import androidx.compose.ui.graphics.PixelMap
 import androidx.compose.ui.graphics.TestActivity
 import androidx.compose.ui.graphics.TileMode
-import androidx.compose.ui.graphics.asImageBitmap
 import androidx.compose.ui.graphics.compositeOver
 import androidx.compose.ui.graphics.drawscope.DrawScope
 import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
@@ -150,8 +148,7 @@
                     .toImageBitmap()
                     .toPixelMap()
                     .verifyQuadrants(Color.Red, Color.Red, Color.Red, Color.Red)
-            },
-            verifySoftwareRender = false // Only supported in hardware accelerated use cases
+            }
         )
     }
 
@@ -196,6 +193,9 @@
         )
     }
 
+    // this test is failing on API 21 as there toImageBitmap() is using software rendering
+    // and we reverted the software rendering b/333866398
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP_MR1)
     @Test
     fun testPersistenceDrawAfterHwuiDiscardsDisplaylists() {
         // Layer persistence calls should not fail even if the DisplayList is discarded beforehand
@@ -212,8 +212,7 @@
                     }
                 drawIntoCanvas { layer.drawForPersistence(it) }
             },
-            verify = { it.verifyQuadrants(Color.Red, Color.Red, Color.Red, Color.Red) },
-            verifySoftwareRender = false
+            verify = { it.verifyQuadrants(Color.Red, Color.Red, Color.Red, Color.Red) }
         )
     }
 
@@ -741,8 +740,7 @@
                 }
                 assertTrue(shadowPixelCount > 0)
             },
-            usePixelCopy = true,
-            verifySoftwareRender = false // Elevation only supported with hardware acceleration
+            usePixelCopy = true
         )
     }
 
@@ -819,7 +817,6 @@
                 }
             },
             usePixelCopy = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O,
-            verifySoftwareRender = false // Elevation only supported with hardware acceleration
         )
     }
 
@@ -877,8 +874,7 @@
                 }
                 Assert.assertTrue(shadowPixelCount > 0)
             },
-            usePixelCopy = true,
-            verifySoftwareRender = false // Elevation only supported with hardware acceleration
+            usePixelCopy = true
         )
     }
 
@@ -971,8 +967,7 @@
                     )
                 }
             },
-            usePixelCopy = true,
-            verifySoftwareRender = false // Elevation only supported with hardware acceleration
+            usePixelCopy = true
         )
     }
 
@@ -1008,8 +1003,7 @@
                 }
                 assertTrue(nonPureRedCount > 0)
             },
-            entireScene = false,
-            verifySoftwareRender = false // RenderEffect only supported with hardware acceleration
+            entireScene = false
         )
     }
 
@@ -1122,8 +1116,7 @@
                     assertPixelColor(Color.Black, 0, height - 1)
                     assertPixelColor(expectedCenter, width / 2, height / 2)
                 }
-            },
-            verifySoftwareRender = false // ModulateAlpha only supported with hardware acceleration
+            }
         )
     }
 
@@ -1488,8 +1481,7 @@
         block: DrawScope.(GraphicsContext) -> Unit,
         verify: (suspend (PixelMap) -> Unit)? = null,
         entireScene: Boolean = false,
-        usePixelCopy: Boolean = false,
-        verifySoftwareRender: Boolean = true
+        usePixelCopy: Boolean = false
     ) {
         var scenario: ActivityScenario<TestActivity>? = null
         var androidGraphicsContext: GraphicsContext? = null
@@ -1583,16 +1575,6 @@
                         bitmap.toPixelMap()
                     }
                 runBlocking { verify(pixelMap) }
-                if (verifySoftwareRender) {
-                    val softwareRenderLatch = CountDownLatch(1)
-                    var softwareBitmap: Bitmap? = null
-                    testActivity!!.runOnUiThread {
-                        softwareBitmap = doSoftwareRender(target)
-                        softwareRenderLatch.countDown()
-                    }
-                    assertTrue(softwareRenderLatch.await(300, TimeUnit.MILLISECONDS))
-                    runBlocking { verify(softwareBitmap!!.asImageBitmap().toPixelMap()) }
-                }
             }
         } finally {
             val detachLatch = CountDownLatch(1)
@@ -1613,13 +1595,6 @@
         }
     }
 
-    private fun doSoftwareRender(target: View): Bitmap {
-        val bitmap = Bitmap.createBitmap(target.width, target.height, Bitmap.Config.ARGB_8888)
-        val softwareCanvas = Canvas(bitmap)
-        target.draw(softwareCanvas)
-        return bitmap
-    }
-
     private class GraphicsContextHostDrawable(
         val graphicsContext: GraphicsContext,
         val block: DrawScope.(GraphicsContext) -> Unit
diff --git a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/AndroidGraphicsContext.android.kt b/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/AndroidGraphicsContext.android.kt
index dbe1c2f..5081429 100644
--- a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/AndroidGraphicsContext.android.kt
+++ b/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/AndroidGraphicsContext.android.kt
@@ -131,35 +131,29 @@
     override fun createGraphicsLayer(): GraphicsLayer {
         synchronized(lock) {
             val ownerId = getUniqueDrawingId(ownerView)
-            val reusedLayer = layerManager.takeFromCache(ownerId)
-            val layer =
-                if (reusedLayer != null) {
-                    reusedLayer
+            val layerImpl =
+                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+                    GraphicsLayerV29(ownerId)
+                } else if (
+                    isRenderNodeCompatible && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
+                ) {
+                    try {
+                        GraphicsLayerV23(ownerView, ownerId)
+                    } catch (_: Throwable) {
+                        // If we ever failed to create an instance of the RenderNode stub
+                        // based
+                        // GraphicsLayer, always fallback to creation of View based layers
+                        // as it is
+                        // unlikely that subsequent attempts to create a GraphicsLayer with
+                        // RenderNode
+                        // stubs would be successful.
+                        isRenderNodeCompatible = false
+                        GraphicsViewLayer(obtainViewLayerContainer(ownerView), ownerId)
+                    }
                 } else {
-                    val layerImpl =
-                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
-                            GraphicsLayerV29()
-                        } else if (
-                            isRenderNodeCompatible && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
-                        ) {
-                            try {
-                                GraphicsLayerV23(ownerView)
-                            } catch (_: Throwable) {
-                                // If we ever failed to create an instance of the RenderNode stub
-                                // based
-                                // GraphicsLayer, always fallback to creation of View based layers
-                                // as it is
-                                // unlikely that subsequent attempts to create a GraphicsLayer with
-                                // RenderNode
-                                // stubs would be successful.
-                                isRenderNodeCompatible = false
-                                GraphicsViewLayer(obtainViewLayerContainer(ownerView))
-                            }
-                        } else {
-                            GraphicsViewLayer(obtainViewLayerContainer(ownerView))
-                        }
-                    GraphicsLayer(layerImpl, layerManager, ownerId)
+                    GraphicsViewLayer(obtainViewLayerContainer(ownerView), ownerId)
                 }
+            val layer = GraphicsLayer(layerImpl, layerManager)
             layerManager.persist(layer)
             return layer
         }
diff --git a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/AndroidGraphicsLayer.android.kt b/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/AndroidGraphicsLayer.android.kt
index 829d419..bbd27e7 100644
--- a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/AndroidGraphicsLayer.android.kt
+++ b/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/AndroidGraphicsLayer.android.kt
@@ -36,7 +36,6 @@
 import androidx.compose.ui.graphics.RenderEffect
 import androidx.compose.ui.graphics.asAndroidPath
 import androidx.compose.ui.graphics.asImageBitmap
-import androidx.compose.ui.graphics.drawscope.CanvasDrawScope
 import androidx.compose.ui.graphics.drawscope.DefaultDensity
 import androidx.compose.ui.graphics.drawscope.DrawScope
 import androidx.compose.ui.graphics.layer.LayerManager.Companion.isRobolectric
@@ -50,11 +49,7 @@
 
 @Suppress("NotCloseable")
 actual class GraphicsLayer
-internal constructor(
-    internal val impl: GraphicsLayerImpl,
-    private val layerManager: LayerManager,
-    ownerViewId: Long
-) {
+internal constructor(internal val impl: GraphicsLayerImpl, private val layerManager: LayerManager) {
     private var density = DefaultDensity
     private var layoutDirection = LayoutDirection.Ltr
     private var drawBlock: DrawScope.() -> Unit = {}
@@ -69,7 +64,6 @@
     private var outlinePath: Path? = null
     private var roundRectClipPath: Path? = null
     private var usePathForClip = false
-    private var softwareDrawScope: CanvasDrawScope? = null
 
     // Paint used only in Software rendering scenarios for API 21 when rendering to a Bitmap
     private var softwareLayerPaint: Paint? = null
@@ -466,7 +460,7 @@
     }
 
     internal fun drawForPersistence(canvas: Canvas) {
-        if (canvas.nativeCanvas.isHardwareAccelerated || impl.supportsSoftwareRendering) {
+        if (canvas.nativeCanvas.isHardwareAccelerated) {
             recreateDisplayListIfNeeded()
             impl.draw(canvas)
         }
@@ -535,13 +529,7 @@
 
         parentLayer?.addSubLayer(this)
 
-        if (canvas.nativeCanvas.isHardwareAccelerated || impl.supportsSoftwareRendering) {
-            impl.draw(canvas)
-        } else {
-            val drawScope = softwareDrawScope ?: CanvasDrawScope().also { softwareDrawScope = it }
-            drawScope.draw(density, layoutDirection, canvas, size.toSize(), drawBlock)
-        }
-
+        impl.draw(canvas)
         if (willClipPath) {
             canvas.restore()
         }
@@ -562,10 +550,8 @@
         discardContentIfReleasedAndHaveNoParentLayerUsages()
     }
 
-    private var skipOutlineConfiguration = false
-
     private fun configureOutline() {
-        if (outlineDirty && !skipOutlineConfiguration) {
+        if (outlineDirty) {
             val outlineIsNeeded = clip || shadowElevation > 0f
             if (!outlineIsNeeded) {
                 impl.setOutline(null)
@@ -593,8 +579,8 @@
                     impl.setOutline(roundRectOutline)
                 }
             }
-            outlineDirty = false
         }
+        outlineDirty = false
     }
 
     private inline fun <T> resolveOutlinePosition(block: (Offset, Size) -> T): T {
@@ -676,8 +662,8 @@
      * The uniqueDrawingId of the owner view of this graphics layer. This is used by tooling to
      * match a layer to the associated owner View.
      */
-    var ownerViewId: Long = ownerViewId
-        private set
+    val ownerViewId: Long
+        get() = impl.ownerId
 
     actual val outline: Outline
         get() {
@@ -820,51 +806,6 @@
      */
     actual suspend fun toImageBitmap(): ImageBitmap = SnapshotImpl.toBitmap(this).asImageBitmap()
 
-    internal fun reuse(ownerViewId: Long) {
-        // apply new owner id
-        this.ownerViewId = ownerViewId
-
-        // mark the layer as not released
-        isReleased = false
-
-        // prepare the implementation to be reused
-        impl.onReused()
-
-        // forget the previous draw lambda
-        drawBlock = {}
-
-        // multiple of the setters can cause configureOutline() calls, however we don't want
-        // to execute it multiple times, so we set this flag to true
-        skipOutlineConfiguration = true
-
-        // reset properties to the default values
-        alpha = 1f
-        blendMode = BlendMode.SrcOver
-        colorFilter = null
-        pivotOffset = Offset.Unspecified
-        scaleX = 1f
-        scaleY = 1f
-        translationX = 0f
-        translationY = 0f
-        shadowElevation = 0f
-        rotationX = 0f
-        rotationY = 0f
-        rotationZ = 0f
-        ambientShadowColor = Color.Black
-        spotShadowColor = Color.Black
-        cameraDistance = DefaultCameraDistance
-        renderEffect = null
-        compositingStrategy = CompositingStrategy.Auto
-        clip = false
-        size = IntSize.Zero
-        topLeft = IntOffset.Zero
-        setRectOutline()
-
-        // unset this flag. if outlineDirty is true we will call configureOutline() again when
-        // the layer will be drawn for the first time.
-        skipOutlineConfiguration = false
-    }
-
     companion object {
 
         // See b/340578758, fallback to software rendering for Robolectric tests
@@ -891,6 +832,12 @@
      */
     val layerId: Long
 
+    /**
+     * The uniqueDrawingId of the owner view of this graphics layer. This is used by tooling to
+     * match a layer to the associated owner AndroidComposeView.
+     */
+    val ownerId: Long
+
     /** @see GraphicsLayer.compositingStrategy */
     var compositingStrategy: CompositingStrategy
 
@@ -957,14 +904,6 @@
      */
     fun setOutline(outline: AndroidOutline?)
 
-    /**
-     * Flag to determine if the layer implementation has a software backed implementation On Android
-     * L we conditionally also record drawing commands into a Picture as it does not natively
-     * support rendering into a Bitmap with hardware acceleration
-     */
-    val supportsSoftwareRendering: Boolean
-        get() = false
-
     /** Draw the GraphicsLayer into the provided canvas */
     fun draw(canvas: Canvas)
 
@@ -985,8 +924,6 @@
     /** Calculate the current transformation matrix for the layer implementation */
     fun calculateMatrix(): android.graphics.Matrix
 
-    fun onReused() {}
-
     companion object {
         val DefaultDrawBlock: DrawScope.() -> Unit = { drawRect(Color.Transparent) }
     }
diff --git a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/GraphicsLayerV23.android.kt b/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/GraphicsLayerV23.android.kt
index 02d56e4..59cd922 100644
--- a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/GraphicsLayerV23.android.kt
+++ b/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/GraphicsLayerV23.android.kt
@@ -47,6 +47,7 @@
 @RequiresApi(Build.VERSION_CODES.M)
 internal class GraphicsLayerV23(
     ownerView: View,
+    override val ownerId: Long,
     private val canvasHolder: CanvasHolder = CanvasHolder(),
     private val canvasDrawScope: CanvasDrawScope = CanvasDrawScope()
 ) : GraphicsLayerImpl {
diff --git a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/GraphicsLayerV29.android.kt b/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/GraphicsLayerV29.android.kt
index 97691ec..7330a3d 100644
--- a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/GraphicsLayerV29.android.kt
+++ b/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/GraphicsLayerV29.android.kt
@@ -44,6 +44,7 @@
 /** GraphicsLayer implementation for Android Q+ that uses the public RenderNode API */
 @RequiresApi(Build.VERSION_CODES.Q)
 internal class GraphicsLayerV29(
+    override val ownerId: Long,
     private val canvasHolder: CanvasHolder = CanvasHolder(),
     private val canvasDrawScope: CanvasDrawScope = CanvasDrawScope()
 ) : GraphicsLayerImpl {
diff --git a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/GraphicsViewLayer.android.kt b/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/GraphicsViewLayer.android.kt
index edde423..26389c5 100644
--- a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/GraphicsViewLayer.android.kt
+++ b/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/GraphicsViewLayer.android.kt
@@ -102,10 +102,6 @@
         this.parentLayer = parentLayer
     }
 
-    fun resetDrawBlock() {
-        drawBlock = DefaultDrawBlock
-    }
-
     init {
         setWillNotDraw(false) // we WILL draw
         this.clipBounds = null
@@ -157,6 +153,7 @@
 
 internal class GraphicsViewLayer(
     private val layerContainer: DrawChildContainer,
+    override val ownerId: Long,
     val canvasHolder: CanvasHolder = CanvasHolder(),
     canvasDrawScope: CanvasDrawScope = CanvasDrawScope()
 ) : GraphicsLayerImpl {
@@ -445,8 +442,6 @@
         }
     }
 
-    override val supportsSoftwareRendering: Boolean = mayRenderInSoftware
-
     private fun recordDrawingOperations() {
         try {
             canvasHolder.drawInto(PlaceholderCanvas) {
@@ -491,12 +486,6 @@
         layerContainer.removeViewInLayout(viewLayer)
     }
 
-    override fun onReused() {
-        viewLayer.resetDrawBlock()
-        // it was removed in discardDisplayList()
-        layerContainer.addView(viewLayer)
-    }
-
     companion object {
 
         val mayRenderInSoftware = !isLockHardwareCanvasAvailable()
diff --git a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/LayerManager.android.kt b/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/LayerManager.android.kt
index e11287f..ce86b5f 100644
--- a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/LayerManager.android.kt
+++ b/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/LayerManager.android.kt
@@ -19,8 +19,6 @@
 import android.graphics.PixelFormat
 import android.media.ImageReader
 import android.os.Build
-import android.os.Build.VERSION.SDK_INT
-import android.os.Build.VERSION_CODES.M
 import android.os.Looper
 import android.os.Message
 import android.view.Surface
@@ -37,8 +35,7 @@
  */
 internal class LayerManager(val canvasHolder: CanvasHolder) {
 
-    private val activeLayerSet = mutableScatterSetOf<GraphicsLayer>()
-    private val nonActiveLayerCache = WeakCache<GraphicsLayer>()
+    private val layerSet = mutableScatterSetOf<GraphicsLayer>()
 
     /**
      * Create a placeholder ImageReader instance that we will use to issue a single draw call for
@@ -50,15 +47,12 @@
 
     private val handler =
         HandlerCompat.createAsync(Looper.getMainLooper()) {
-            persistLayers(activeLayerSet)
+            persistLayers(layerSet)
             true
         }
 
-    fun takeFromCache(ownerId: Long): GraphicsLayer? =
-        nonActiveLayerCache.pop()?.also { it.reuse(ownerId) }
-
     fun persist(layer: GraphicsLayer) {
-        activeLayerSet.add(layer)
+        layerSet.add(layer)
         if (!handler.hasMessages(0)) {
             // we don't run persistLayers() synchronously in order to do less work as there
             // might be a lot of new layers created during one frame. however we also want
@@ -71,11 +65,8 @@
     }
 
     fun release(layer: GraphicsLayer) {
-        if (activeLayerSet.remove(layer)) {
+        if (layerSet.remove(layer)) {
             layer.discardDisplayList()
-            if (SDK_INT >= M) { // L throws during RenderThread when reusing the Views.
-                nonActiveLayerCache.push(layer)
-            }
         }
     }
 
@@ -137,7 +128,7 @@
      */
     fun updateLayerPersistence() {
         destroy()
-        persistLayers(activeLayerSet)
+        persistLayers(layerSet)
     }
 
     companion object {
diff --git a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/WeakCache.android.kt b/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/WeakCache.android.kt
deleted file mode 100644
index 807ae0d..0000000
--- a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/layer/WeakCache.android.kt
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.compose.ui.graphics.layer
-
-import androidx.compose.runtime.collection.mutableVectorOf
-import java.lang.ref.Reference
-import java.lang.ref.ReferenceQueue
-import java.lang.ref.WeakReference
-
-// It is a copy from androidx.compose.ui.platform
-/**
- * A simple collection that keeps values as [WeakReference]s. Elements are added with [push] and
- * removed with [pop].
- */
-internal class WeakCache<T> {
-    private val values = mutableVectorOf<Reference<T>>()
-    private val referenceQueue = ReferenceQueue<T>()
-
-    /**
-     * Add [element] to the collection as a [WeakReference]. It will be removed when garbage
-     * collected or from [pop].
-     */
-    fun push(element: T) {
-        clearWeakReferences()
-        values += WeakReference(element, referenceQueue)
-    }
-
-    /**
-     * Remove an element from the collection and return it. If no element is available, `null` is
-     * returned.
-     */
-    fun pop(): T? {
-        clearWeakReferences()
-
-        while (values.isNotEmpty()) {
-            val item = values.removeAt(values.lastIndex).get()
-            if (item != null) {
-                return item
-            }
-        }
-        return null
-    }
-
-    /**
-     * The number of elements currently in the collection. This may change between calls if the
-     * references have been garbage collected.
-     */
-    val size: Int
-        get() {
-            clearWeakReferences()
-            return values.size
-        }
-
-    private fun clearWeakReferences() {
-        do {
-            val item: Reference<out T>? = referenceQueue.poll()
-            if (item != null) {
-                @Suppress("UNCHECKED_CAST") values.remove(item as Reference<T>)
-            }
-        } while (item != null)
-    }
-}
diff --git a/compose/ui/ui-graphics/src/androidUnitTest/kotlin/androidx/compose/ui/graphics/layer/RobolectricGraphicsLayerTest.kt b/compose/ui/ui-graphics/src/androidUnitTest/kotlin/androidx/compose/ui/graphics/layer/RobolectricGraphicsLayerTest.kt
index 8755ec4..851a970 100644
--- a/compose/ui/ui-graphics/src/androidUnitTest/kotlin/androidx/compose/ui/graphics/layer/RobolectricGraphicsLayerTest.kt
+++ b/compose/ui/ui-graphics/src/androidUnitTest/kotlin/androidx/compose/ui/graphics/layer/RobolectricGraphicsLayerTest.kt
@@ -65,6 +65,7 @@
 import org.junit.Assert
 import org.junit.Assert.assertEquals
 import org.junit.Assert.assertTrue
+import org.junit.Ignore
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.robolectric.annotation.Config
@@ -82,6 +83,7 @@
         val TEST_SIZE = IntSize(TEST_WIDTH, TEST_HEIGHT)
     }
 
+    @Ignore("Software rendering support was reverted. b/333866398")
     @Test
     fun testGraphicsLayerBitmap() {
         lateinit var layer: GraphicsLayer
@@ -119,6 +121,7 @@
         )
     }
 
+    @Ignore("Software rendering support was reverted. b/333866398")
     @Test
     fun testDrawLayer() {
         var layer: GraphicsLayer? = null
@@ -139,6 +142,7 @@
         )
     }
 
+    @Ignore("Software rendering support was reverted. b/333866398")
     @Test
     fun testDrawAfterDiscard() {
         var layer: GraphicsLayer? = null
@@ -160,6 +164,7 @@
         )
     }
 
+    @Ignore("Software rendering support was reverted. b/333866398")
     @Test
     fun testPersistenceDrawAfterHwuiDiscardsDisplaylists() {
         // Layer persistence calls should not fail even if the DisplayList is discarded beforehand
@@ -177,6 +182,7 @@
         )
     }
 
+    @Ignore("Software rendering support was reverted. b/333866398")
     @Test
     fun testRecordLayerWithSize() {
         graphicsLayerTest(
@@ -191,6 +197,7 @@
         )
     }
 
+    @Ignore("Software rendering support was reverted. b/333866398")
     @Test
     fun testRecordLayerWithOffset() {
         var layer: GraphicsLayer? = null
@@ -213,6 +220,7 @@
         )
     }
 
+    @Ignore("Software rendering support was reverted. b/333866398")
     @Test
     fun testSetOffset() {
         var layer: GraphicsLayer? = null
@@ -238,6 +246,7 @@
         )
     }
 
+    @Ignore("Software rendering support was reverted. b/333866398")
     @Test
     fun testSetAlpha() {
         var layer: GraphicsLayer? = null
@@ -266,6 +275,7 @@
         )
     }
 
+    @Ignore("Software rendering support was reverted. b/333866398")
     @Test
     fun testSetScaleX() {
         var layer: GraphicsLayer? = null
@@ -294,6 +304,7 @@
         )
     }
 
+    @Ignore("Software rendering support was reverted. b/333866398")
     @Test
     fun testSetScaleY() {
         var layer: GraphicsLayer? = null
@@ -322,6 +333,7 @@
         )
     }
 
+    @Ignore("Software rendering support was reverted. b/333866398")
     @Test
     fun testDefaultPivot() {
         var layer: GraphicsLayer? = null
@@ -347,6 +359,7 @@
         )
     }
 
+    @Ignore("Software rendering support was reverted. b/333866398")
     @Test
     fun testBottomRightPivot() {
         var layer: GraphicsLayer? = null
@@ -371,6 +384,7 @@
         )
     }
 
+    @Ignore("Software rendering support was reverted. b/333866398")
     @Test
     fun testTranslationX() {
         var layer: GraphicsLayer? = null
@@ -393,6 +407,7 @@
         )
     }
 
+    @Ignore("Software rendering support was reverted. b/333866398")
     @Test
     fun testRectOutlineWithNonZeroTopLeft() {
         graphicsLayerTest(
@@ -414,6 +429,7 @@
         )
     }
 
+    @Ignore("Software rendering support was reverted. b/333866398")
     @Test
     fun testRoundRectOutlineWithNonZeroTopLeft() {
         graphicsLayerTest(
@@ -435,6 +451,7 @@
         )
     }
 
+    @Ignore("Software rendering support was reverted. b/333866398")
     @Test
     fun testRecordOverwritesPreviousRecord() {
         graphicsLayerTest(
@@ -448,6 +465,7 @@
         )
     }
 
+    @Ignore("Software rendering support was reverted. b/333866398")
     @Test
     fun testTranslationY() {
         var layer: GraphicsLayer? = null
@@ -470,6 +488,7 @@
         )
     }
 
+    @Ignore("Software rendering support was reverted. b/333866398")
     @Test
     fun testRotationX() {
         var layer: GraphicsLayer? = null
@@ -498,6 +517,7 @@
         )
     }
 
+    @Ignore("Software rendering support was reverted. b/333866398")
     @Test
     fun testRotationY() {
         var layer: GraphicsLayer? = null
@@ -525,6 +545,7 @@
         )
     }
 
+    @Ignore("Software rendering support was reverted. b/333866398")
     @Test
     fun testRotationZ() {
         var layer: GraphicsLayer? = null
@@ -579,6 +600,7 @@
         )
     }
 
+    @Ignore("Software rendering support was reverted. b/333866398")
     @Test
     fun testUnboundedClip() {
         var layer: GraphicsLayer?
@@ -602,6 +624,7 @@
         )
     }
 
+    @Ignore("Software rendering support was reverted. b/333866398")
     @Test
     fun testBoundedClip() {
         var layer: GraphicsLayer?
@@ -632,6 +655,7 @@
         )
     }
 
+    @Ignore("Software rendering support was reverted. b/333866398")
     @Test
     fun testCompositingStrategyAuto() {
         var layer: GraphicsLayer?
@@ -671,6 +695,7 @@
         )
     }
 
+    @Ignore("Software rendering support was reverted. b/333866398")
     @Test
     fun testCompositingStrategyOffscreen() {
         var layer: GraphicsLayer?
@@ -704,6 +729,7 @@
         )
     }
 
+    @Ignore("Software rendering support was reverted. b/333866398")
     @Test
     fun testCameraDistanceWithRotationY() {
         var layer: GraphicsLayer?
@@ -732,6 +758,7 @@
         )
     }
 
+    @Ignore("Software rendering support was reverted. b/333866398")
     @Test
     fun testTintColorFilter() {
         var layer: GraphicsLayer?
@@ -756,6 +783,7 @@
         )
     }
 
+    @Ignore("Software rendering support was reverted. b/333866398")
     @Test
     fun testBlendMode() {
         var layer: GraphicsLayer?
@@ -807,6 +835,7 @@
         )
     }
 
+    @Ignore("Software rendering support was reverted. b/333866398")
     @Test
     fun testRectOutlineClip() {
         var layer: GraphicsLayer?
@@ -851,6 +880,7 @@
         )
     }
 
+    @Ignore("Software rendering support was reverted. b/333866398")
     @Test
     fun testPathOutlineClip() {
         var layer: GraphicsLayer?
@@ -906,6 +936,7 @@
         )
     }
 
+    @Ignore("Software rendering support was reverted. b/333866398")
     @Test
     fun testRoundRectOutlineClip() {
         var layer: GraphicsLayer?
@@ -960,6 +991,7 @@
         )
     }
 
+    @Ignore("Software rendering support was reverted. b/333866398")
     @Test
     fun setOutlineExtensionAppliesValuesCorrectly() {
         graphicsLayerTest(
@@ -984,6 +1016,7 @@
         )
     }
 
+    @Ignore("Software rendering support was reverted. b/333866398")
     @Test
     fun testSwitchingFromClipToBoundsToClipToOutline() {
         val targetColor = Color.Red
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/GraphicsLayerOwnerLayer.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/GraphicsLayerOwnerLayer.android.kt
index 7b42b55..2f492d15 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/GraphicsLayerOwnerLayer.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/GraphicsLayerOwnerLayer.android.kt
@@ -28,6 +28,7 @@
 import androidx.compose.ui.graphics.Matrix
 import androidx.compose.ui.graphics.Outline
 import androidx.compose.ui.graphics.Paint
+import androidx.compose.ui.graphics.Path
 import androidx.compose.ui.graphics.ReusableGraphicsLayerScope
 import androidx.compose.ui.graphics.TransformOrigin
 import androidx.compose.ui.graphics.drawscope.CanvasDrawScope
@@ -37,6 +38,7 @@
 import androidx.compose.ui.graphics.layer.GraphicsLayer
 import androidx.compose.ui.graphics.layer.drawLayer
 import androidx.compose.ui.graphics.layer.setOutline
+import androidx.compose.ui.graphics.nativeCanvas
 import androidx.compose.ui.layout.GraphicLayerInfo
 import androidx.compose.ui.node.OwnedLayer
 import androidx.compose.ui.unit.Density
@@ -75,6 +77,7 @@
     private var mutatedFields: Int = 0
     private var transformOrigin: TransformOrigin = TransformOrigin.Center
     private var outline: Outline? = null
+    private var tmpPath: Path? = null
     /**
      * Optional paint used when the RenderNode is rendered on a software backed canvas and is
      * somewhat transparent (i.e. alpha less than 1.0f)
@@ -223,13 +226,53 @@
     private var drawnWithEnabledZ = false
 
     override fun drawLayer(canvas: Canvas, parentLayer: GraphicsLayer?) {
-        updateDisplayList()
-        drawnWithEnabledZ = graphicsLayer.shadowElevation > 0
-        scope.drawContext.also {
-            it.canvas = canvas
-            it.graphicsLayer = parentLayer
+        val androidCanvas = canvas.nativeCanvas
+        if (androidCanvas.isHardwareAccelerated) {
+            updateDisplayList()
+            drawnWithEnabledZ = graphicsLayer.shadowElevation > 0
+            scope.drawContext.also {
+                it.canvas = canvas
+                it.graphicsLayer = parentLayer
+            }
+            scope.drawLayer(graphicsLayer)
+        } else {
+            // TODO ideally there should be some solution for drawing a layer on a software
+            //  accelerated canvas built in right into GraphicsLayer, as this workaround is not
+            //  solving all the use cases. For example, some one can use layers directly via
+            //        drawWithContent {
+            //            layer.record {
+            //                [email protected]()
+            //            }
+            //            drawLayer(layer)
+            //        }
+            //  and if someone would try to draw the whole ComposeView on software accelerated
+            //  canvas it will just crash saying RenderNodes can't be drawn into this canvas.
+            //  This issue is tracked in b/333866398
+            val left = graphicsLayer.topLeft.x.toFloat()
+            val top = graphicsLayer.topLeft.y.toFloat()
+            val right = left + size.width
+            val bottom = top + size.height
+            // If there is alpha applied, we must render into an offscreen buffer to
+            // properly blend the contents of this layer against the background content
+            if (graphicsLayer.alpha < 1.0f) {
+                val paint =
+                    (softwareLayerPaint ?: Paint().also { softwareLayerPaint = it }).apply {
+                        alpha = graphicsLayer.alpha
+                    }
+                androidCanvas.saveLayer(left, top, right, bottom, paint.asFrameworkPaint())
+            } else {
+                canvas.save()
+            }
+            // If we are software rendered we must translate the canvas based on the offset provided
+            // in the move call which operates directly on the RenderNode
+            canvas.translate(left, top)
+            canvas.concat(getMatrix())
+            if (graphicsLayer.clip) {
+                clipManually(canvas)
+            }
+            drawBlock?.invoke(canvas, null)
+            canvas.restore()
         }
-        scope.drawLayer(graphicsLayer)
     }
 
     override fun updateDisplayList() {
@@ -299,6 +342,7 @@
             requireNotNull(context) {
                 "currently reuse is only supported when we manage the layer lifecycle"
             }
+        require(graphicsLayer.isReleased) { "layer should have been released before reuse" }
 
         // recreate a layer
         graphicsLayer = context.createGraphicsLayer()
@@ -371,4 +415,27 @@
                 1.0f
             )
         }
+
+    /**
+     * Manually clips the content of the RenderNodeLayer in the provided canvas. This is used only
+     * in software rendered use cases
+     */
+    private fun clipManually(canvas: Canvas) {
+        if (graphicsLayer.clip) {
+            when (val outline = graphicsLayer.outline) {
+                is Outline.Rectangle -> {
+                    canvas.clipRect(outline.rect)
+                }
+                is Outline.Rounded -> {
+                    val path = tmpPath ?: Path().also { tmpPath = it }
+                    path.reset()
+                    path.addRoundRect(outline.roundRect)
+                    canvas.clipPath(path)
+                }
+                is Outline.Generic -> {
+                    canvas.clipPath(outline.path)
+                }
+            }
+        }
+    }
 }
diff --git a/privacysandbox/ads/ads-adservices/api/1.1.0-beta08.txt b/privacysandbox/ads/ads-adservices/api/1.1.0-beta08.txt
index b25a1b0..dca5235 100644
--- a/privacysandbox/ads/ads-adservices/api/1.1.0-beta08.txt
+++ b/privacysandbox/ads/ads-adservices/api/1.1.0-beta08.txt
@@ -92,11 +92,11 @@
   }
 
   @SuppressCompatibility @androidx.privacysandbox.ads.adservices.common.ExperimentalFeatures.Ext10OptIn public final class GetAdSelectionDataRequest {
-    ctor public GetAdSelectionDataRequest(optional androidx.privacysandbox.ads.adservices.common.AdTechIdentifier? seller, optional android.net.Uri? coordinatorOriginUri);
+    ctor public GetAdSelectionDataRequest(androidx.privacysandbox.ads.adservices.common.AdTechIdentifier seller, optional android.net.Uri? coordinatorOriginUri);
     method public android.net.Uri? getCoordinatorOriginUri();
-    method public androidx.privacysandbox.ads.adservices.common.AdTechIdentifier? getSeller();
+    method public androidx.privacysandbox.ads.adservices.common.AdTechIdentifier getSeller();
     property public final android.net.Uri? coordinatorOriginUri;
-    property public final androidx.privacysandbox.ads.adservices.common.AdTechIdentifier? seller;
+    property public final androidx.privacysandbox.ads.adservices.common.AdTechIdentifier seller;
   }
 
   @SuppressCompatibility @androidx.privacysandbox.ads.adservices.common.ExperimentalFeatures.Ext10OptIn public final class PersistAdSelectionResultRequest {
diff --git a/privacysandbox/ads/ads-adservices/api/current.txt b/privacysandbox/ads/ads-adservices/api/current.txt
index b25a1b0..dca5235 100644
--- a/privacysandbox/ads/ads-adservices/api/current.txt
+++ b/privacysandbox/ads/ads-adservices/api/current.txt
@@ -92,11 +92,11 @@
   }
 
   @SuppressCompatibility @androidx.privacysandbox.ads.adservices.common.ExperimentalFeatures.Ext10OptIn public final class GetAdSelectionDataRequest {
-    ctor public GetAdSelectionDataRequest(optional androidx.privacysandbox.ads.adservices.common.AdTechIdentifier? seller, optional android.net.Uri? coordinatorOriginUri);
+    ctor public GetAdSelectionDataRequest(androidx.privacysandbox.ads.adservices.common.AdTechIdentifier seller, optional android.net.Uri? coordinatorOriginUri);
     method public android.net.Uri? getCoordinatorOriginUri();
-    method public androidx.privacysandbox.ads.adservices.common.AdTechIdentifier? getSeller();
+    method public androidx.privacysandbox.ads.adservices.common.AdTechIdentifier getSeller();
     property public final android.net.Uri? coordinatorOriginUri;
-    property public final androidx.privacysandbox.ads.adservices.common.AdTechIdentifier? seller;
+    property public final androidx.privacysandbox.ads.adservices.common.AdTechIdentifier seller;
   }
 
   @SuppressCompatibility @androidx.privacysandbox.ads.adservices.common.ExperimentalFeatures.Ext10OptIn public final class PersistAdSelectionResultRequest {
diff --git a/privacysandbox/ads/ads-adservices/api/restricted_1.1.0-beta08.txt b/privacysandbox/ads/ads-adservices/api/restricted_1.1.0-beta08.txt
index b25a1b0..dca5235 100644
--- a/privacysandbox/ads/ads-adservices/api/restricted_1.1.0-beta08.txt
+++ b/privacysandbox/ads/ads-adservices/api/restricted_1.1.0-beta08.txt
@@ -92,11 +92,11 @@
   }
 
   @SuppressCompatibility @androidx.privacysandbox.ads.adservices.common.ExperimentalFeatures.Ext10OptIn public final class GetAdSelectionDataRequest {
-    ctor public GetAdSelectionDataRequest(optional androidx.privacysandbox.ads.adservices.common.AdTechIdentifier? seller, optional android.net.Uri? coordinatorOriginUri);
+    ctor public GetAdSelectionDataRequest(androidx.privacysandbox.ads.adservices.common.AdTechIdentifier seller, optional android.net.Uri? coordinatorOriginUri);
     method public android.net.Uri? getCoordinatorOriginUri();
-    method public androidx.privacysandbox.ads.adservices.common.AdTechIdentifier? getSeller();
+    method public androidx.privacysandbox.ads.adservices.common.AdTechIdentifier getSeller();
     property public final android.net.Uri? coordinatorOriginUri;
-    property public final androidx.privacysandbox.ads.adservices.common.AdTechIdentifier? seller;
+    property public final androidx.privacysandbox.ads.adservices.common.AdTechIdentifier seller;
   }
 
   @SuppressCompatibility @androidx.privacysandbox.ads.adservices.common.ExperimentalFeatures.Ext10OptIn public final class PersistAdSelectionResultRequest {
diff --git a/privacysandbox/ads/ads-adservices/api/restricted_current.txt b/privacysandbox/ads/ads-adservices/api/restricted_current.txt
index b25a1b0..dca5235 100644
--- a/privacysandbox/ads/ads-adservices/api/restricted_current.txt
+++ b/privacysandbox/ads/ads-adservices/api/restricted_current.txt
@@ -92,11 +92,11 @@
   }
 
   @SuppressCompatibility @androidx.privacysandbox.ads.adservices.common.ExperimentalFeatures.Ext10OptIn public final class GetAdSelectionDataRequest {
-    ctor public GetAdSelectionDataRequest(optional androidx.privacysandbox.ads.adservices.common.AdTechIdentifier? seller, optional android.net.Uri? coordinatorOriginUri);
+    ctor public GetAdSelectionDataRequest(androidx.privacysandbox.ads.adservices.common.AdTechIdentifier seller, optional android.net.Uri? coordinatorOriginUri);
     method public android.net.Uri? getCoordinatorOriginUri();
-    method public androidx.privacysandbox.ads.adservices.common.AdTechIdentifier? getSeller();
+    method public androidx.privacysandbox.ads.adservices.common.AdTechIdentifier getSeller();
     property public final android.net.Uri? coordinatorOriginUri;
-    property public final androidx.privacysandbox.ads.adservices.common.AdTechIdentifier? seller;
+    property public final androidx.privacysandbox.ads.adservices.common.AdTechIdentifier seller;
   }
 
   @SuppressCompatibility @androidx.privacysandbox.ads.adservices.common.ExperimentalFeatures.Ext10OptIn public final class PersistAdSelectionResultRequest {
diff --git a/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/adselection/GetAdSelectionDataRequest.kt b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/adselection/GetAdSelectionDataRequest.kt
index 650e8c0..e84646b 100644
--- a/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/adselection/GetAdSelectionDataRequest.kt
+++ b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/adselection/GetAdSelectionDataRequest.kt
@@ -43,7 +43,7 @@
 @ExperimentalFeatures.Ext10OptIn
 class GetAdSelectionDataRequest
 public constructor(
-    val seller: AdTechIdentifier? = null,
+    val seller: AdTechIdentifier,
     @property:ExperimentalFeatures.Ext12OptIn val coordinatorOriginUri: Uri? = null
 ) {
     /** Checks whether two [GetAdSelectionDataRequest] objects contain the same information. */
@@ -88,7 +88,7 @@
                 request: GetAdSelectionDataRequest
             ): android.adservices.adselection.GetAdSelectionDataRequest {
                 return android.adservices.adselection.GetAdSelectionDataRequest.Builder()
-                    .setSeller(request.seller?.convertToAdServices())
+                    .setSeller(request.seller.convertToAdServices())
                     .setCoordinatorOriginUri(request.coordinatorOriginUri)
                     .build()
             }
@@ -103,7 +103,7 @@
                 request: GetAdSelectionDataRequest
             ): android.adservices.adselection.GetAdSelectionDataRequest {
                 return android.adservices.adselection.GetAdSelectionDataRequest.Builder()
-                    .setSeller(request.seller?.convertToAdServices())
+                    .setSeller(request.seller.convertToAdServices())
                     .build()
             }
         }
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/CheckboxButton.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/CheckboxButton.kt
index 4b87bb5..38adf08 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/CheckboxButton.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/CheckboxButton.kt
@@ -20,18 +20,32 @@
 import androidx.compose.animation.core.TweenSpec
 import androidx.compose.animation.core.tween
 import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
 import androidx.compose.foundation.interaction.Interaction
 import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.BoxScope
+import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.IntrinsicSize
 import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.RowScope
+import androidx.compose.foundation.layout.Spacer
 import androidx.compose.foundation.layout.defaultMinSize
+import androidx.compose.foundation.layout.fillMaxHeight
 import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.layout.wrapContentHeight
+import androidx.compose.foundation.selection.toggleable
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.Immutable
 import androidx.compose.runtime.State
+import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.draw.drawWithCache
 import androidx.compose.ui.geometry.CornerRadius
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.geometry.Size
@@ -41,11 +55,14 @@
 import androidx.compose.ui.graphics.drawscope.Fill
 import androidx.compose.ui.graphics.drawscope.Stroke
 import androidx.compose.ui.graphics.takeOrElse
+import androidx.compose.ui.semantics.Role
 import androidx.compose.ui.semantics.contentDescription
+import androidx.compose.ui.semantics.role
 import androidx.compose.ui.semantics.semantics
 import androidx.compose.ui.unit.dp
 import androidx.wear.compose.material3.tokens.CheckboxButtonTokens
 import androidx.wear.compose.material3.tokens.MotionTokens
+import androidx.wear.compose.material3.tokens.ShapeTokens
 import androidx.wear.compose.material3.tokens.SplitCheckboxButtonTokens
 import androidx.wear.compose.materialcore.animateSelectionColor
 
@@ -228,18 +245,77 @@
     contentPadding: PaddingValues = CheckboxButtonDefaults.ContentPadding,
     secondaryLabel: @Composable (RowScope.() -> Unit)? = null,
     label: @Composable RowScope.() -> Unit
-) =
-    androidx.wear.compose.materialcore.SplitToggleButton(
-        checked = checked,
-        onCheckedChange = onCheckedChange,
-        label =
-            provideScopeContent(
-                contentColor = colors.contentColor(enabled = enabled, checked = checked),
-                textStyle = SplitCheckboxButtonTokens.LabelFont.value,
-                content = label
-            ),
-        onClick = onContainerClick,
-        toggleControl = {
+) {
+    val containerColor = colors.containerColor(enabled, checked).value
+    Row(
+        verticalAlignment = Alignment.CenterVertically,
+        modifier =
+            modifier
+                .defaultMinSize(minHeight = MIN_HEIGHT)
+                .height(IntrinsicSize.Min)
+                .width(IntrinsicSize.Max)
+                .clip(shape = shape)
+    ) {
+        Row(
+            modifier =
+                Modifier.clickable(
+                        enabled = enabled,
+                        onClick = onContainerClick,
+                        indication = ripple(),
+                        interactionSource = containerInteractionSource,
+                        onClickLabel = containerClickLabel,
+                    )
+                    .semantics { role = Role.Button }
+                    .fillMaxHeight()
+                    .clip(SPLIT_SECTIONS_SHAPE)
+                    .background(containerColor)
+                    .padding(contentPadding)
+                    .weight(1.0f),
+            verticalAlignment = Alignment.CenterVertically,
+        ) {
+            Labels(
+                label =
+                    provideScopeContent(
+                        contentColor = colors.contentColor(enabled = enabled, checked = checked),
+                        textStyle = SplitCheckboxButtonTokens.LabelFont.value,
+                        content = label
+                    ),
+                secondaryLabel =
+                    provideNullableScopeContent(
+                        contentColor =
+                            colors.secondaryContentColor(enabled = enabled, checked = checked),
+                        textStyle = SplitCheckboxButtonTokens.SecondaryLabelFont.value,
+                        content = secondaryLabel
+                    ),
+            )
+        }
+
+        Spacer(modifier = Modifier.size(2.dp))
+
+        val splitBackground = colors.splitContainerColor(enabled, checked).value
+        Box(
+            modifier =
+                Modifier.toggleable(
+                        enabled = enabled,
+                        value = checked,
+                        onValueChange = onCheckedChange,
+                        indication = ripple(),
+                        interactionSource = toggleInteractionSource
+                    )
+                    .fillMaxHeight()
+                    .clip(SPLIT_SECTIONS_SHAPE)
+                    .background(containerColor)
+                    .drawWithCache {
+                        onDrawWithContent {
+                            drawRect(color = splitBackground)
+                            drawContent()
+                        }
+                    }
+                    .align(Alignment.CenterVertically)
+                    .width(SPLIT_WIDTH)
+                    .wrapContentHeight(align = Alignment.CenterVertically)
+                    .padding(contentPadding)
+        ) {
             Checkbox(
                 checked = checked,
                 enabled = enabled,
@@ -256,30 +332,9 @@
                     colors.checkmarkColor(enabled = enabled, checked = checked)
                 }
             )
-        },
-        selectionControl = null,
-        modifier = modifier.defaultMinSize(minHeight = MIN_HEIGHT).height(IntrinsicSize.Min),
-        secondaryLabel =
-            provideNullableScopeContent(
-                contentColor = colors.secondaryContentColor(enabled = enabled, checked = checked),
-                textStyle = SplitCheckboxButtonTokens.SecondaryLabelFont.value,
-                content = secondaryLabel
-            ),
-        backgroundColor = { isEnabled, isChecked ->
-            colors.containerColor(enabled = isEnabled, checked = isChecked)
-        },
-        splitBackgroundColor = { isEnabled, isChecked ->
-            colors.splitContainerColor(enabled = isEnabled, checked = isChecked)
-        },
-        enabled = enabled,
-        checkedInteractionSource = toggleInteractionSource,
-        clickInteractionSource = containerInteractionSource,
-        onClickLabel = containerClickLabel,
-        contentPadding = contentPadding,
-        shape = shape,
-        labelSpacerSize = CheckboxButtonDefaults.LabelSpacerSize,
-        ripple = ripple()
-    )
+        }
+    }
+}
 
 /** Contains the default values used by [CheckboxButton]s and [SplitCheckboxButton]s */
 object CheckboxButtonDefaults {
@@ -1375,16 +1430,33 @@
     )
 }
 
+@Composable
+private fun RowScope.Labels(
+    label: @Composable RowScope.() -> Unit,
+    secondaryLabel: @Composable (RowScope.() -> Unit)?
+) {
+    Column(modifier = Modifier.weight(1.0f)) {
+        Row(content = label)
+        if (secondaryLabel != null) {
+            Spacer(modifier = Modifier.size(CheckboxButtonDefaults.LabelSpacerSize))
+            Row(content = secondaryLabel)
+        }
+    }
+}
+
 private val TOGGLE_CONTROL_SPACING = 6.dp
 private val ICON_SPACING = 6.dp
 private val MIN_HEIGHT = 52.dp
 
-private val CHECKBOX_WIDTH = 32.dp
+private val CHECKBOX_WIDTH = 24.dp
 private val CHECKBOX_HEIGHT = 24.dp
 private val BOX_STROKE = 2.dp
 private val BOX_RADIUS = 2.dp
 private val BOX_SIZE = 18.dp
 
+private val SPLIT_WIDTH = 52.dp
+private val SPLIT_SECTIONS_SHAPE = ShapeTokens.CornerExtraSmall
+
 private val COLOR_ANIMATION_SPEC: AnimationSpec<Color> =
     tween(MotionTokens.DurationMedium1, 0, MotionTokens.EasingStandardDecelerate)
 private val PROGRESS_ANIMATION_SPEC: TweenSpec<Float> =
diff --git a/wear/protolayout/protolayout/api/current.txt b/wear/protolayout/protolayout/api/current.txt
index afcfb3e..6298259 100644
--- a/wear/protolayout/protolayout/api/current.txt
+++ b/wear/protolayout/protolayout/api/current.txt
@@ -591,6 +591,9 @@
     method public androidx.wear.protolayout.TypeBuilders.BoolProp? getUnderline();
     method @SuppressCompatibility @androidx.wear.protolayout.expression.ProtoLayoutExperimental public androidx.wear.protolayout.LayoutElementBuilders.FontVariantProp? getVariant();
     method public androidx.wear.protolayout.LayoutElementBuilders.FontWeightProp? getWeight();
+    field @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=400) public static final String DEFAULT_SYSTEM_FONT = "default";
+    field @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=400) public static final String ROBOTO_FLEX_FONT = "roboto-flex";
+    field @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=400) public static final String ROBOTO_FONT = "roboto";
   }
 
   public static final class LayoutElementBuilders.FontStyle.Builder {
@@ -610,9 +613,6 @@
     method @SuppressCompatibility @androidx.wear.protolayout.expression.ProtoLayoutExperimental @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=0) public androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder setVariant(int);
     method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=0) public androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder setWeight(androidx.wear.protolayout.LayoutElementBuilders.FontWeightProp);
     method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=0) public androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder setWeight(int);
-    field @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=400) public static final String DEFAULT_SYSTEM_FONT = "default";
-    field @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=400) public static final String ROBOTO_FLEX_FONT = "roboto-flex";
-    field @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=400) public static final String ROBOTO_FONT = "roboto";
   }
 
   @Deprecated public static final class LayoutElementBuilders.FontStyles {
diff --git a/wear/protolayout/protolayout/api/restricted_current.txt b/wear/protolayout/protolayout/api/restricted_current.txt
index afcfb3e..6298259 100644
--- a/wear/protolayout/protolayout/api/restricted_current.txt
+++ b/wear/protolayout/protolayout/api/restricted_current.txt
@@ -591,6 +591,9 @@
     method public androidx.wear.protolayout.TypeBuilders.BoolProp? getUnderline();
     method @SuppressCompatibility @androidx.wear.protolayout.expression.ProtoLayoutExperimental public androidx.wear.protolayout.LayoutElementBuilders.FontVariantProp? getVariant();
     method public androidx.wear.protolayout.LayoutElementBuilders.FontWeightProp? getWeight();
+    field @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=400) public static final String DEFAULT_SYSTEM_FONT = "default";
+    field @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=400) public static final String ROBOTO_FLEX_FONT = "roboto-flex";
+    field @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=400) public static final String ROBOTO_FONT = "roboto";
   }
 
   public static final class LayoutElementBuilders.FontStyle.Builder {
@@ -610,9 +613,6 @@
     method @SuppressCompatibility @androidx.wear.protolayout.expression.ProtoLayoutExperimental @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=0) public androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder setVariant(int);
     method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=0) public androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder setWeight(androidx.wear.protolayout.LayoutElementBuilders.FontWeightProp);
     method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=0) public androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder setWeight(int);
-    field @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=400) public static final String DEFAULT_SYSTEM_FONT = "default";
-    field @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=400) public static final String ROBOTO_FLEX_FONT = "roboto-flex";
-    field @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=400) public static final String ROBOTO_FONT = "roboto";
   }
 
   @Deprecated public static final class LayoutElementBuilders.FontStyles {
diff --git a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/LayoutElementBuilders.java b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/LayoutElementBuilders.java
index 044e01d..c63519e 100644
--- a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/LayoutElementBuilders.java
+++ b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/LayoutElementBuilders.java
@@ -715,6 +715,32 @@
             return Collections.unmodifiableList(list);
         }
 
+        /** The recommended font family names to be used within {@link FontStyle}. */
+        @RequiresSchemaVersion(major = 1, minor = 400)
+        @RestrictTo(RestrictTo.Scope.LIBRARY)
+        @Retention(RetentionPolicy.SOURCE)
+        @StringDef(
+                value = {DEFAULT_SYSTEM_FONT, ROBOTO_FONT, ROBOTO_FLEX_FONT},
+                open = true)
+        public @interface FontFamilyName {}
+
+        /**
+         * Font family name that uses default system font. Supported in any renderer version.
+         */
+        @RequiresSchemaVersion(major = 1, minor = 400)
+        public static final String DEFAULT_SYSTEM_FONT = "default";
+
+        /** Font family name that uses Roboto font. Supported in renderers supporting 1.4. */
+        @RequiresSchemaVersion(major = 1, minor = 400)
+        public static final String ROBOTO_FONT = "roboto";
+
+        /**
+         * Font family name that uses Roboto Flex variable font. Supported in renderers
+         * supporting 1.4.
+         */
+        @RequiresSchemaVersion(major = 1, minor = 400)
+        public static final String ROBOTO_FLEX_FONT = "roboto-flex";
+
         /** Get the fingerprint for this object, or null if unknown. */
         @RestrictTo(Scope.LIBRARY_GROUP)
         @Nullable
@@ -1024,32 +1050,6 @@
                 return this;
             }
 
-            /** The recommended font family names to be used within {@link FontStyle}. */
-            @RequiresSchemaVersion(major = 1, minor = 400)
-            @RestrictTo(RestrictTo.Scope.LIBRARY)
-            @Retention(RetentionPolicy.SOURCE)
-            @StringDef(
-                    value = {DEFAULT_SYSTEM_FONT, ROBOTO_FONT, ROBOTO_FLEX_FONT},
-                    open = true)
-            public @interface FontFamilyName {}
-
-            /**
-             * Font family name that uses default system font. Supported in any renderer version.
-             */
-            @RequiresSchemaVersion(major = 1, minor = 400)
-            public static final String DEFAULT_SYSTEM_FONT = "default";
-
-            /** Font family name that uses Roboto font. Supported in renderers supporting 1.4. */
-            @RequiresSchemaVersion(major = 1, minor = 400)
-            public static final String ROBOTO_FONT = "roboto";
-
-            /**
-             * Font family name that uses Roboto Flex variable font. Supported in renderers
-             * supporting 1.4.
-             */
-            @RequiresSchemaVersion(major = 1, minor = 400)
-            public static final String ROBOTO_FLEX_FONT = "roboto-flex";
-
             /**
              * Sets the preferred font families for this {@link FontStyle}.
              *
diff --git a/wear/protolayout/protolayout/src/test/java/androidx/wear/protolayout/LayoutElementBuildersTest.java b/wear/protolayout/protolayout/src/test/java/androidx/wear/protolayout/LayoutElementBuildersTest.java
index 8620e76..1653411 100644
--- a/wear/protolayout/protolayout/src/test/java/androidx/wear/protolayout/LayoutElementBuildersTest.java
+++ b/wear/protolayout/protolayout/src/test/java/androidx/wear/protolayout/LayoutElementBuildersTest.java
@@ -21,7 +21,7 @@
 import static androidx.wear.protolayout.DimensionBuilders.expand;
 import static androidx.wear.protolayout.DimensionBuilders.sp;
 import static androidx.wear.protolayout.DimensionBuilders.weight;
-import static androidx.wear.protolayout.LayoutElementBuilders.FontStyle.Builder.ROBOTO_FLEX_FONT;
+import static androidx.wear.protolayout.LayoutElementBuilders.FontStyle.ROBOTO_FLEX_FONT;
 import static androidx.wear.protolayout.LayoutElementBuilders.TABULAR_OPTION_TAG;
 import static androidx.wear.protolayout.LayoutElementBuilders.WEIGHT_AXIS_TAG;
 import static androidx.wear.protolayout.LayoutElementBuilders.WIDTH_AXIS_TAG;