Add deferTransitionProgress flag to STL (1/2)
This CL adds a new deferTransitionProgress flag to STL to reduce
perceivable jank by waiting for the first expensive composition frame of
a transition to be done before changing the progress of the transition.
This works with gesture-based transitions and one-off transitions.
See b/400688335#comment2 for details.
Bug: 400688335
Test: atest NestedDraggableTest
Flag: EXEMPT new behavior disabled by default
Change-Id: I839529e2bc1d792ae8a37d5ddf3e7c61a12fe3cb
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/gesture/NestedDraggable.kt b/packages/SystemUI/compose/core/src/com/android/compose/gesture/NestedDraggable.kt
index 2ea9c48..362748e 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/gesture/NestedDraggable.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/gesture/NestedDraggable.kt
@@ -112,6 +112,16 @@
interface Controller {
/**
+ * Whether this controller is ready to drag. [onDrag] will be called only if this returns
+ * `true`, and any drag event will be ignored until then.
+ *
+ * This can for instance be used to wait for the content we are dragging to to be composed
+ * before actually dragging, reducing perceivable jank at the beginning of a drag.
+ */
+ val isReadyToDrag: Boolean
+ get() = true
+
+ /**
* Whether drags that were started from nested scrolls should be automatically
* [stopped][onDragStopped] as soon as they don't consume the entire `delta` passed to
* [onDrag].
@@ -274,6 +284,9 @@
/** The pointers currently down, in order of which they were done and mapping to their type. */
private val pointersDown = linkedMapOf<PointerId, PointerType>()
+ /** Whether the next drag event should be ignored. */
+ private var ignoreNextDrag = false
+
init {
delegate(nestedScrollModifierNode(this, nestedScrollDispatcher))
}
@@ -426,6 +439,7 @@
velocityTracker: VelocityTracker,
) {
velocityTracker.addPointerInputChange(change)
+ if (shouldIgnoreDrag(controller)) return
scrollWithOverscroll(delta.toOffset()) { deltaFromOverscroll ->
scrollWithNestedScroll(deltaFromOverscroll) { deltaFromNestedScroll ->
@@ -434,6 +448,23 @@
}
}
+ private fun shouldIgnoreDrag(controller: NestedDraggable.Controller): Boolean {
+ return when {
+ !controller.isReadyToDrag -> {
+ // The controller is not ready yet, so we are waiting for an expensive frame to be
+ // composed. We should ignore this drag and the next one, given that the first delta
+ // after an expensive frame will be large.
+ ignoreNextDrag = true
+ true
+ }
+ ignoreNextDrag -> {
+ ignoreNextDrag = false
+ true
+ }
+ else -> false
+ }
+ }
+
private fun onDragStopped(controller: NestedDraggable.Controller, velocity: Velocity) {
// We launch in the scope of the dispatcher so that the fling is not cancelled if this node
// is removed right after onDragStopped() is called.
@@ -617,6 +648,8 @@
}
private fun scrollWithOverscroll(controller: NestedScrollController, offset: Offset): Offset {
+ if (shouldIgnoreDrag(controller.controller)) return offset
+
return scrollWithOverscroll(offset) { delta ->
val available = delta.toFloat()
val consumed = controller.controller.onDrag(available)
diff --git a/packages/SystemUI/compose/core/tests/src/com/android/compose/gesture/NestedDraggableTest.kt b/packages/SystemUI/compose/core/tests/src/com/android/compose/gesture/NestedDraggableTest.kt
index b247993..b316173 100644
--- a/packages/SystemUI/compose/core/tests/src/com/android/compose/gesture/NestedDraggableTest.kt
+++ b/packages/SystemUI/compose/core/tests/src/com/android/compose/gesture/NestedDraggableTest.kt
@@ -972,6 +972,36 @@
}
@Test
+ fun isReadyToDrag() {
+ var isReadyToDrag by mutableStateOf(false)
+ val draggable = TestDraggable(isReadyToDrag = { isReadyToDrag })
+ val touchSlop =
+ rule.setContentWithTouchSlop {
+ Box(Modifier.fillMaxSize().nestedDraggable(draggable, orientation))
+ }
+
+ rule.onRoot().performTouchInput {
+ down(center)
+ moveBy((touchSlop + 10f).toOffset())
+ }
+
+ assertThat(draggable.onDragStartedCalled).isTrue()
+ assertThat(draggable.onDragDelta).isEqualTo(0f)
+
+ rule.onRoot().performTouchInput { moveBy(20f.toOffset()) }
+ assertThat(draggable.onDragDelta).isEqualTo(0f)
+
+ // Flag as ready to drag. We still ignore the next drag after that.
+ isReadyToDrag = true
+ rule.onRoot().performTouchInput { moveBy(30f.toOffset()) }
+ assertThat(draggable.onDragDelta).isEqualTo(0f)
+
+ // Now we drag.
+ rule.onRoot().performTouchInput { moveBy(40f.toOffset()) }
+ assertThat(draggable.onDragDelta).isEqualTo(40f)
+ }
+
+ @Test
fun consumeNestedPreScroll() {
var consumeNestedPreScroll by mutableStateOf(false)
val draggable = TestDraggable(shouldConsumeNestedPreScroll = { consumeNestedPreScroll })
@@ -1060,6 +1090,7 @@
},
private val shouldConsumeNestedPostScroll: (Float) -> Boolean = { true },
private val shouldConsumeNestedPreScroll: (Float) -> Boolean = { false },
+ private val isReadyToDrag: () -> Boolean = { true },
private val autoStopNestedDrags: Boolean = false,
) : NestedDraggable {
var shouldStartDrag = true
@@ -1092,6 +1123,9 @@
return object : NestedDraggable.Controller {
override val autoStopNestedDrags: Boolean = this@TestDraggable.autoStopNestedDrags
+ override val isReadyToDrag: Boolean
+ get() = isReadyToDrag()
+
override fun onDrag(delta: Float): Float {
onDragCalled = true
onDragDelta += delta
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateContent.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateContent.kt
index b04d89d..0b0df06c 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateContent.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateContent.kt
@@ -20,6 +20,7 @@
import androidx.compose.animation.core.AnimationVector1D
import androidx.compose.animation.core.SpringSpec
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
+import androidx.compose.runtime.withFrameNanos
import com.android.compose.animation.scene.content.state.TransitionState
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
@@ -47,6 +48,11 @@
oneOffAnimation.animatable = it
}
+ if (layoutState.deferTransitionProgress) {
+ // Defer the animation by one frame so that the transition progress is changed only when
+ // the expensive first composition frame is done.
+ withFrameNanos {}
+ }
animatable.animateTo(targetProgress, animationSpec, initialVelocity)
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
index 024ca22..36eafa4 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
@@ -290,6 +290,15 @@
val isDrivingTransition: Boolean
get() = layoutState.transitionState == swipeAnimation.contentTransition
+ override val isReadyToDrag: Boolean
+ get() {
+ return !layoutState.deferTransitionProgress ||
+ with(draggableHandler.layoutImpl.elementStateScope) {
+ swipeAnimation.fromContent.targetSize() != null &&
+ swipeAnimation.toContent.targetSize() != null
+ }
+ }
+
init {
check(!isDrivingTransition) { "Multiple controllers with the same SwipeTransition" }
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
index 4da83c3..a8b676d 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
@@ -462,7 +462,9 @@
// swipes.
.swipeToScene(horizontalDraggableHandler)
.swipeToScene(verticalDraggableHandler)
- .then(LayoutElement(layoutImpl = this))
+ .then(
+ LayoutElement(layoutImpl = this, transitionState = this.state.transitionState)
+ )
) {
LookaheadScope {
if (_lookaheadScope == null) {
@@ -623,23 +625,28 @@
@VisibleForTesting internal fun overlaysOrNullForTest(): Map<OverlayKey, Overlay>? = _overlays
}
-private data class LayoutElement(private val layoutImpl: SceneTransitionLayoutImpl) :
- ModifierNodeElement<LayoutNode>() {
- override fun create(): LayoutNode = LayoutNode(layoutImpl)
+private data class LayoutElement(
+ private val layoutImpl: SceneTransitionLayoutImpl,
+ private val transitionState: TransitionState,
+) : ModifierNodeElement<LayoutNode>() {
+ override fun create(): LayoutNode = LayoutNode(layoutImpl, transitionState)
override fun update(node: LayoutNode) {
node.layoutImpl = layoutImpl
+ node.transitionState = transitionState
}
}
-private class LayoutNode(var layoutImpl: SceneTransitionLayoutImpl) :
- Modifier.Node(), ApproachLayoutModifierNode, LayoutAwareModifierNode {
+private class LayoutNode(
+ var layoutImpl: SceneTransitionLayoutImpl,
+ var transitionState: TransitionState,
+) : Modifier.Node(), ApproachLayoutModifierNode, LayoutAwareModifierNode {
override fun onRemeasured(size: IntSize) {
layoutImpl.lastSize = size
}
override fun isMeasurementApproachInProgress(lookaheadSize: IntSize): Boolean {
- return layoutImpl.state.isTransitioning()
+ return transitionState is TransitionState.Transition.ChangeScene
}
@ExperimentalComposeUiApi
@@ -652,8 +659,7 @@
val width: Int
val height: Int
- val transition =
- layoutImpl.state.currentTransition as? TransitionState.Transition.ChangeScene
+ val transition = transitionState as? TransitionState.Transition.ChangeScene
if (transition == null) {
width = placeable.width
height = placeable.height
@@ -662,6 +668,9 @@
val fromSize = layoutImpl.scene(transition.fromScene).targetSize
val toSize = layoutImpl.scene(transition.toScene).targetSize
+ check(fromSize != Element.SizeUnspecified) { "fromSize is unspecified " }
+ check(toSize != Element.SizeUnspecified) { "toSize is unspecified" }
+
// Optimization: make sure we don't read state.progress if fromSize ==
// toSize to avoid running this code every frame when the layout size does
// not change.
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
index 56e8c45..4e28dd5 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
@@ -234,6 +234,10 @@
* `from` overlay by `to` overlay.
* @param stateLinks the [StateLink] connecting this [SceneTransitionLayoutState] to other
* [SceneTransitionLayoutState]s.
+ * @param deferTransitionProgress whether we should wait for the first composition to be done before
+ * changing the progress of a transition. This can help reduce perceivable jank at the start of a
+ * transition in case the first composition of a content takes a lot of time and we are going to
+ * miss that first frame.
*/
fun MutableSceneTransitionLayoutState(
initialScene: SceneKey,
@@ -246,6 +250,9 @@
canReplaceOverlay: (from: OverlayKey, to: OverlayKey) -> Boolean = { _, _ -> true },
onTransitionStart: (TransitionState.Transition) -> Unit = {},
onTransitionEnd: (TransitionState.Transition) -> Unit = {},
+
+ // TODO(b/400688335): Turn on by default and remove this flag before flexiglass is released.
+ deferTransitionProgress: Boolean = false,
): MutableSceneTransitionLayoutState {
return MutableSceneTransitionLayoutStateImpl(
initialScene,
@@ -258,6 +265,7 @@
canReplaceOverlay,
onTransitionStart,
onTransitionEnd,
+ deferTransitionProgress,
)
}
@@ -272,6 +280,9 @@
canReplaceOverlay: (from: OverlayKey, to: OverlayKey) -> Boolean = { _, _ -> true },
onTransitionStart: (TransitionState.Transition) -> Unit = {},
onTransitionEnd: (TransitionState.Transition) -> Unit = {},
+
+ // TODO(b/400688335): Turn on by default and remove this flag before flexiglass is released.
+ deferTransitionProgress: Boolean = false,
): MutableSceneTransitionLayoutState {
val motionScheme = MaterialTheme.motionScheme
val layoutState = remember {
@@ -286,6 +297,7 @@
canReplaceOverlay = canReplaceOverlay,
onTransitionStart = onTransitionStart,
onTransitionEnd = onTransitionEnd,
+ deferTransitionProgress = deferTransitionProgress,
)
}
@@ -298,6 +310,7 @@
layoutState.canReplaceOverlay = canReplaceOverlay
layoutState.onTransitionStart = onTransitionStart
layoutState.onTransitionEnd = onTransitionEnd
+ layoutState.deferTransitionProgress = deferTransitionProgress
}
return layoutState
}
@@ -317,6 +330,8 @@
},
internal var onTransitionStart: (TransitionState.Transition) -> Unit = {},
internal var onTransitionEnd: (TransitionState.Transition) -> Unit = {},
+ // TODO(b/400688335): Turn on by default and remove this flag before flexiglass is released.
+ internal var deferTransitionProgress: Boolean = false,
) : MutableSceneTransitionLayoutState {
private val creationThread: Thread = Thread.currentThread()
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/UserActionDistanceScopeImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/UserActionDistanceScopeImpl.kt
index 2d2a8154..5d4232d8 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/UserActionDistanceScopeImpl.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/UserActionDistanceScopeImpl.kt
@@ -38,7 +38,7 @@
}
override fun ContentKey.targetSize(): IntSize? {
- return layoutImpl.content(this).targetSize.takeIf { it != IntSize.Zero }
+ return layoutImpl.content(this).targetSize.takeIf { it != Element.SizeUnspecified }
}
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt
index 90bf92a..7492f37 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt
@@ -93,9 +93,10 @@
val containerState = ContainerState()
// Important: All fields in this class should be backed by State given that contents are updated
- // directly during composition, outside of a SideEffect.
+ // directly during composition, outside of a SideEffect, or are observed during composition,
+ // layout or drawing.
var content by mutableStateOf(content)
- var targetSize by mutableStateOf(IntSize.Zero)
+ var targetSize by mutableStateOf(Element.SizeUnspecified)
var userActions by mutableStateOf(actions)
var zIndex by mutableFloatStateOf(zIndex)
@@ -212,9 +213,17 @@
return if (isElevationPossible) delegate(ContainerNode(content.containerState)) else null
}
+ override fun onDetach() {
+ this.content.targetSize = Element.SizeUnspecified
+ }
+
fun update(content: Content, isElevationPossible: Boolean, isInvisible: Boolean) {
- if (content != this.content || isElevationPossible != this.isElevationPossible) {
+ if (content != this.content) {
+ this.content.targetSize = Element.SizeUnspecified
this.content = content
+ }
+
+ if (content != this.content || isElevationPossible != this.isElevationPossible) {
this.isElevationPossible = isElevationPossible
containerDelegate?.let { undelegate(it) }
diff --git a/packages/SystemUI/compose/scene/tests/goldens/edge_verticalReveal_gesture_dragFullyClose.json b/packages/SystemUI/compose/scene/tests/goldens/edge_verticalReveal_gesture_dragFullyClose.json
index 5dbb013..770f859 100644
--- a/packages/SystemUI/compose/scene/tests/goldens/edge_verticalReveal_gesture_dragFullyClose.json
+++ b/packages/SystemUI/compose/scene/tests/goldens/edge_verticalReveal_gesture_dragFullyClose.json
@@ -76,7 +76,7 @@
},
{
"x": 5.2,
- "y": 5.6
+ "y": 5.2
},
{
"x": 5.2,
@@ -326,11 +326,11 @@
},
{
"width": 150,
- "height": 293.2
+ "height": 292.8
},
{
"width": 150,
- "height": 293.2
+ "height": 292.8
},
{
"width": 150,
diff --git a/packages/SystemUI/compose/scene/tests/goldens/edge_verticalReveal_gesture_dragHalfClose.json b/packages/SystemUI/compose/scene/tests/goldens/edge_verticalReveal_gesture_dragHalfClose.json
index 1543d18..6b7de56 100644
--- a/packages/SystemUI/compose/scene/tests/goldens/edge_verticalReveal_gesture_dragHalfClose.json
+++ b/packages/SystemUI/compose/scene/tests/goldens/edge_verticalReveal_gesture_dragHalfClose.json
@@ -81,8 +81,8 @@
"y": 5.2
},
{
- "x": 5.6,
- "y": 6.8
+ "x": 5.2,
+ "y": 5.2
},
{
"x": 5.2,
@@ -344,7 +344,7 @@
},
{
"width": 150,
- "height": 294
+ "height": 292.4
},
{
"width": 150,
diff --git a/packages/SystemUI/compose/scene/tests/goldens/edge_verticalReveal_gesture_flingClose.json b/packages/SystemUI/compose/scene/tests/goldens/edge_verticalReveal_gesture_flingClose.json
index 115483cf..015df8f 100644
--- a/packages/SystemUI/compose/scene/tests/goldens/edge_verticalReveal_gesture_flingClose.json
+++ b/packages/SystemUI/compose/scene/tests/goldens/edge_verticalReveal_gesture_flingClose.json
@@ -84,8 +84,8 @@
"y": 5.2
},
{
- "x": 5.6,
- "y": 6.4
+ "x": 5.2,
+ "y": 5.2
},
{
"x": 5.2,
@@ -259,7 +259,7 @@
},
{
"width": 150,
- "height": 290
+ "height": 288.8
},
{
"width": 150,
@@ -279,34 +279,34 @@
},
{
"width": 150,
- "height": 223.6
+ "height": 224
},
{
"width": 150,
- "height": 182.8
+ "height": 183.2
},
{
"width": 150,
- "height": 141.2
+ "height": 141.6
},
{
"width": 150,
- "height": 104
+ "height": 104.4
},
{
- "width": 147.6,
- "height": 74
+ "width": 148,
+ "height": 74.4
},
{
"width": 139.6,
- "height": 50.8
+ "height": 51.2
},
{
"width": 133.6,
- "height": 32
+ "height": 32.4
},
{
- "width": 129.2,
+ "width": 129.6,
"height": 15.6
},
{
@@ -409,19 +409,19 @@
1,
1,
1,
- 0.99479187,
- 0.8575029,
- 0.65572864,
- 0.4691311,
- 0.3215357,
- 0.21380007,
- 0.13896108,
- 0.0887118,
- 0.05580789,
- 0.03467691,
- 0.021318138,
- 0.0129826665,
- 0.007839739,
+ 0.99532944,
+ 0.8594856,
+ 0.65783304,
+ 0.47089338,
+ 0.32286334,
+ 0.21474117,
+ 0.139602,
+ 0.089136004,
+ 0.056082606,
+ 0.03485179,
+ 0.02142787,
+ 0.013050735,
+ 0.007881463,
0,
0,
0,
diff --git a/packages/SystemUI/compose/scene/tests/goldens/floating_verticalReveal_gesture_dragFullyClose.json b/packages/SystemUI/compose/scene/tests/goldens/floating_verticalReveal_gesture_dragFullyClose.json
index f44d4cd..5ac0621 100644
--- a/packages/SystemUI/compose/scene/tests/goldens/floating_verticalReveal_gesture_dragFullyClose.json
+++ b/packages/SystemUI/compose/scene/tests/goldens/floating_verticalReveal_gesture_dragFullyClose.json
@@ -72,7 +72,7 @@
},
{
"x": 5.2,
- "y": 5.6
+ "y": 5.2
},
{
"x": 5.2,
@@ -306,11 +306,11 @@
},
{
"width": 150,
- "height": 293.2
+ "height": 292.8
},
{
"width": 150,
- "height": 293.2
+ "height": 292.8
},
{
"width": 150,
diff --git a/packages/SystemUI/compose/scene/tests/goldens/floating_verticalReveal_gesture_dragHalfClose.json b/packages/SystemUI/compose/scene/tests/goldens/floating_verticalReveal_gesture_dragHalfClose.json
index 9b68c71..1cae67b 100644
--- a/packages/SystemUI/compose/scene/tests/goldens/floating_verticalReveal_gesture_dragHalfClose.json
+++ b/packages/SystemUI/compose/scene/tests/goldens/floating_verticalReveal_gesture_dragHalfClose.json
@@ -79,8 +79,8 @@
"y": 5.2
},
{
- "x": 5.6,
- "y": 6.8
+ "x": 5.2,
+ "y": 5.2
},
{
"x": 5.2,
@@ -334,7 +334,7 @@
},
{
"width": 150,
- "height": 294
+ "height": 292.4
},
{
"width": 150,
diff --git a/packages/SystemUI/compose/scene/tests/goldens/floating_verticalReveal_gesture_flingClose.json b/packages/SystemUI/compose/scene/tests/goldens/floating_verticalReveal_gesture_flingClose.json
index 86805bd..ca87bc2 100644
--- a/packages/SystemUI/compose/scene/tests/goldens/floating_verticalReveal_gesture_flingClose.json
+++ b/packages/SystemUI/compose/scene/tests/goldens/floating_verticalReveal_gesture_flingClose.json
@@ -83,8 +83,8 @@
"y": 5.2
},
{
- "x": 5.6,
- "y": 6.4
+ "x": 5.2,
+ "y": 5.2
},
{
"x": 5.2,
@@ -254,7 +254,7 @@
},
{
"width": 150,
- "height": 290
+ "height": 288.8
},
{
"width": 150,
@@ -274,27 +274,27 @@
},
{
"width": 150,
- "height": 223.6
+ "height": 224
},
{
"width": 150,
- "height": 182.8
+ "height": 183.2
},
{
"width": 150,
- "height": 141.2
+ "height": 141.6
},
{
"width": 150,
- "height": 104
+ "height": 104.4
},
{
"width": 150,
- "height": 72
+ "height": 72.4
},
{
"width": 150,
- "height": 46
+ "height": 46.4
},
{
"width": 150,
@@ -400,19 +400,19 @@
1,
1,
1,
- 0.99479187,
- 0.8575029,
- 0.65572864,
- 0.4691311,
- 0.3215357,
- 0.21380007,
- 0.13896108,
- 0.0887118,
- 0.05580789,
- 0.03467691,
- 0.021318138,
- 0.0129826665,
- 0.007839739,
+ 0.99532944,
+ 0.8594856,
+ 0.65783304,
+ 0.47089338,
+ 0.32286334,
+ 0.21474117,
+ 0.139602,
+ 0.089136004,
+ 0.056082606,
+ 0.03485179,
+ 0.02142787,
+ 0.013050735,
+ 0.007881463,
0,
0,
0,
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/testing/ElementStateAccessTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/testing/ElementStateAccessTest.kt
index e4a87ba..7d9a32b 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/testing/ElementStateAccessTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/testing/ElementStateAccessTest.kt
@@ -58,17 +58,24 @@
assertThat(semanticNode.lastScaleForTesting).isEqualTo(Scale(1f, 1f))
}
+ at(16) {
+ val semanticNode = onElement(TestElements.Foo).fetchSemanticsNode()
+ assertThat(semanticNode.lastAlphaForTesting).isEqualTo(0.75f)
+ assertThat(semanticNode.lastScaleForTesting).isEqualTo(Scale(0.75f, 0.75f))
+ }
+
at(32) {
val semanticNode = onElement(TestElements.Foo).fetchSemanticsNode()
assertThat(semanticNode.lastAlphaForTesting).isEqualTo(0.5f)
assertThat(semanticNode.lastScaleForTesting).isEqualTo(Scale(0.5f, 0.5f))
}
- at(64) {
+ at(48) {
val semanticNode = onElement(TestElements.Foo).fetchSemanticsNode()
- assertThat(semanticNode.lastAlphaForTesting).isEqualTo(0f)
- assertThat(semanticNode.lastScaleForTesting).isEqualTo(Scale(0f, 0f))
+ assertThat(semanticNode.lastAlphaForTesting).isEqualTo(0.25f)
+ assertThat(semanticNode.lastScaleForTesting).isEqualTo(Scale(0.25f, 0.25f))
}
+
after { onElement(TestElements.Foo).assertDoesNotExist() }
}
}