summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Jordan Demeulenaere <jdemeulenaere@google.com> 2024-08-14 07:52:40 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2024-08-14 07:52:40 +0000
commit49e8ac3ef24b1f244c9d64fa1ee6d5c54bda316e (patch)
treeeecce9e7eff5c4ef0b10e4d0cb5a17f449dc4fe4
parentbf02dcb171c7deb09c96929238fd08b25d31ce53 (diff)
parent02d1eb602902603b745c37708ef53425070b26bf (diff)
Merge changes Ic671bb7b,If5a43f75 into main
* changes: Clean-up STLState.finishTransition() Change default current scene of test transitions
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt56
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt3
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/PredictiveBackHandler.kt2
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt112
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/ContentState.kt7
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt11
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt79
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/Transition.kt2
8 files changed, 118 insertions, 154 deletions
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt
index 68a6c9836875..920c234174d0 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt
@@ -17,7 +17,6 @@
package com.android.compose.animation.scene
import com.android.compose.animation.scene.content.state.TransitionState
-import kotlin.math.absoluteValue
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
@@ -63,47 +62,30 @@ internal fun CoroutineScope.animateToScene(
if (transitionState.toScene == target) {
// The user is currently swiping to [target] but didn't release their pointer yet:
// animate the progress to `1`.
-
check(transitionState.fromScene == transitionState.currentScene)
- val progress = transitionState.progress
- if ((1f - progress).absoluteValue < ProgressVisibilityThreshold) {
- // The transition is already finished (progress ~= 1): no need to animate. We
- // finish the current transition early to make sure that the current state
- // change is committed.
- layoutState.finishTransition(transitionState, target)
- null
- } else {
- // The transition is in progress: start the canned animation at the same
- // progress as it was in.
- animateToScene(
- layoutState,
- target,
- transitionKey,
- isInitiatedByUserInput,
- replacedTransition = transitionState,
- )
- }
+
+ // The transition is in progress: start the canned animation at the same
+ // progress as it was in.
+ animateToScene(
+ layoutState,
+ target,
+ transitionKey,
+ isInitiatedByUserInput,
+ replacedTransition = transitionState,
+ )
} else if (transitionState.fromScene == target) {
// There is a transition from [target] to another scene: simply animate the same
// transition progress to `0`.
check(transitionState.toScene == transitionState.currentScene)
- val progress = transitionState.progress
- if (progress.absoluteValue < ProgressVisibilityThreshold) {
- // The transition is at progress ~= 0: no need to animate.We finish the current
- // transition early to make sure that the current state change is committed.
- layoutState.finishTransition(transitionState, target)
- null
- } else {
- animateToScene(
- layoutState,
- target,
- transitionKey,
- isInitiatedByUserInput,
- reversed = true,
- replacedTransition = transitionState,
- )
- }
+ animateToScene(
+ layoutState,
+ target,
+ transitionKey,
+ isInitiatedByUserInput,
+ reversed = true,
+ replacedTransition = transitionState,
+ )
} else {
// Generic interruption; the current transition is neither from or to [target].
val interruptionResult =
@@ -185,7 +167,7 @@ private fun CoroutineScope.animateToScene(
oneOffAnimation = oneOffAnimation,
targetProgress = targetProgress,
startTransition = { layoutState.startTransition(transition, chain) },
- finishTransition = { layoutState.finishTransition(transition, targetScene) },
+ finishTransition = { layoutState.finishTransition(transition) },
)
return transition
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 712fe6b2ff50..9c3896b90124 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
@@ -777,7 +777,8 @@ private class SwipeTransition(
fun snapToScene(scene: SceneKey) {
cancelOffsetAnimation()
- layoutState.finishTransition(this, idleScene = scene)
+ check(currentScene == scene)
+ layoutState.finishTransition(this)
}
override fun finish(): Job {
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/PredictiveBackHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/PredictiveBackHandler.kt
index fe16ef75118b..2fbdf7c1a501 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/PredictiveBackHandler.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/PredictiveBackHandler.kt
@@ -129,7 +129,7 @@ private class PredictiveBackTransition(
try {
animatable.animateTo(targetProgress)
} finally {
- state.finishTransition(this@PredictiveBackTransition, scene)
+ state.finishTransition(this@PredictiveBackTransition)
}
}
.also { animationJob = it }
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 a6c6a80941fc..44f5964feacb 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
@@ -167,8 +167,6 @@ internal class MutableSceneTransitionLayoutStateImpl(
override val transitionState: TransitionState
get() = transitionStates.last()
- private val activeTransitionLinks = mutableMapOf<StateLink, LinkedTransition>()
-
override val currentTransitions: List<TransitionState.Transition>
get() {
if (transitionStates.last() is TransitionState.Idle) {
@@ -180,12 +178,8 @@ internal class MutableSceneTransitionLayoutStateImpl(
}
}
- /**
- * The mapping of transitions that are finished, i.e. for which [finishTransition] was called,
- * to their idle scene.
- */
- @VisibleForTesting
- internal val finishedTransitions = mutableMapOf<TransitionState.Transition, SceneKey>()
+ /** The transitions that are finished, i.e. for which [finishTransition] was called. */
+ @VisibleForTesting internal val finishedTransitions = mutableSetOf<TransitionState.Transition>()
internal fun checkThread() {
val current = Thread.currentThread()
@@ -261,7 +255,7 @@ internal class MutableSceneTransitionLayoutStateImpl(
}
// Handle transition links.
- cancelActiveTransitionLinks()
+ currentTransition?.let { cancelActiveTransitionLinks(it) }
setupTransitionLinks(transition)
if (!enableInterruptions) {
@@ -289,8 +283,7 @@ internal class MutableSceneTransitionLayoutStateImpl(
// Force finish all transitions.
while (currentTransitions.isNotEmpty()) {
- val transition = transitionStates[0] as TransitionState.Transition
- finishTransition(transition, transition.currentScene)
+ finishTransition(transitionStates[0] as TransitionState.Transition)
}
// We finished all transitions, so we are now idle. We remove this state so that
@@ -328,18 +321,17 @@ internal class MutableSceneTransitionLayoutStateImpl(
)
}
- private fun cancelActiveTransitionLinks() {
- for ((link, linkedTransition) in activeTransitionLinks) {
- link.target.finishTransition(linkedTransition, linkedTransition.currentScene)
+ private fun cancelActiveTransitionLinks(transition: TransitionState.Transition) {
+ transition.activeTransitionLinks.forEach { (link, linkedTransition) ->
+ link.target.finishTransition(linkedTransition)
}
- activeTransitionLinks.clear()
+ transition.activeTransitionLinks.clear()
}
- private fun setupTransitionLinks(transitionState: TransitionState) {
- if (transitionState !is TransitionState.Transition) return
+ private fun setupTransitionLinks(transition: TransitionState.Transition) {
stateLinks.fastForEach { stateLink ->
val matchingLinks =
- stateLink.transitionLinks.fastFilter { it.isMatchingLink(transitionState) }
+ stateLink.transitionLinks.fastFilter { it.isMatchingLink(transition) }
if (matchingLinks.isEmpty()) return@fastForEach
if (matchingLinks.size > 1) error("More than one link matched.")
@@ -350,31 +342,27 @@ internal class MutableSceneTransitionLayoutStateImpl(
val linkedTransition =
LinkedTransition(
- originalTransition = transitionState,
+ originalTransition = transition,
fromScene = targetCurrentScene,
toScene = matchingLink.targetTo,
key = matchingLink.targetTransitionKey,
)
stateLink.target.startTransition(linkedTransition)
- activeTransitionLinks[stateLink] = linkedTransition
+ transition.activeTransitionLinks[stateLink] = linkedTransition
}
}
/**
- * Notify that [transition] was finished and that we should settle to [idleScene]. This will do
- * nothing if [transition] was interrupted since it was started.
+ * Notify that [transition] was finished and that it settled to its
+ * [currentScene][TransitionState.currentScene]. This will do nothing if [transition] was
+ * interrupted since it was started.
*/
- internal fun finishTransition(transition: TransitionState.Transition, idleScene: SceneKey) {
+ internal fun finishTransition(transition: TransitionState.Transition) {
checkThread()
- val existingIdleScene = finishedTransitions[transition]
- if (existingIdleScene != null) {
+ if (finishedTransitions.contains(transition)) {
// This transition was already finished.
- check(idleScene == existingIdleScene) {
- "Transition $transition was finished multiple times with different " +
- "idleScene ($existingIdleScene != $idleScene)"
- }
return
}
@@ -386,15 +374,15 @@ internal class MutableSceneTransitionLayoutStateImpl(
check(transitionStates.fastAll { it is TransitionState.Transition })
- // Mark this transition as finished and save the scene it is settling at.
- finishedTransitions[transition] = idleScene
+ // Mark this transition as finished.
+ finishedTransitions.add(transition)
// Finish all linked transitions.
- finishActiveTransitionLinks(idleScene)
+ finishActiveTransitionLinks(transition)
- // Keep a reference to the idle scene of the last removed transition, in case we remove all
- // transitions and should settle to Idle.
- var lastRemovedIdleScene: SceneKey? = null
+ // Keep a reference to the last transition, in case we remove all transitions and should
+ // settle to Idle.
+ val lastTransition = transitionStates.last()
// Remove all first n finished transitions.
var i = 0
@@ -407,14 +395,14 @@ internal class MutableSceneTransitionLayoutStateImpl(
}
// Remove the transition from the set of finished transitions.
- lastRemovedIdleScene = finishedTransitions.remove(t)
+ finishedTransitions.remove(t)
i++
}
// If all transitions are finished, we are idle.
if (i == nStates) {
check(finishedTransitions.isEmpty())
- this.transitionStates = listOf(TransitionState.Idle(checkNotNull(lastRemovedIdleScene)))
+ this.transitionStates = listOf(TransitionState.Idle(lastTransition.currentScene))
} else if (i > 0) {
this.transitionStates = transitionStates.subList(fromIndex = i, toIndex = nStates)
}
@@ -426,28 +414,18 @@ internal class MutableSceneTransitionLayoutStateImpl(
// Force finish all transitions.
while (currentTransitions.isNotEmpty()) {
val transition = transitionStates[0] as TransitionState.Transition
- finishTransition(transition, transition.currentScene)
+ finishTransition(transition)
}
check(transitionStates.size == 1)
transitionStates = listOf(TransitionState.Idle(scene))
}
- private fun finishActiveTransitionLinks(idleScene: SceneKey) {
- val previousTransition = this.transitionState as? TransitionState.Transition ?: return
- for ((link, linkedTransition) in activeTransitionLinks) {
- if (previousTransition.fromScene == idleScene) {
- // The transition ended by arriving at the fromScene, move link to Idle(fromScene).
- link.target.finishTransition(linkedTransition, linkedTransition.fromScene)
- } else if (previousTransition.toScene == idleScene) {
- // The transition ended by arriving at the toScene, move link to Idle(toScene).
- link.target.finishTransition(linkedTransition, linkedTransition.toScene)
- } else {
- // The transition was interrupted by something else, we reset to initial state.
- link.target.finishTransition(linkedTransition, linkedTransition.fromScene)
- }
+ private fun finishActiveTransitionLinks(transition: TransitionState.Transition) {
+ for ((link, linkedTransition) in transition.activeTransitionLinks) {
+ link.target.finishTransition(linkedTransition)
}
- activeTransitionLinks.clear()
+ transition.activeTransitionLinks.clear()
}
/**
@@ -465,31 +443,21 @@ internal class MutableSceneTransitionLayoutStateImpl(
fun isProgressCloseTo(value: Float) = (progress - value).absoluteValue <= threshold
- fun finishAllTransitions(lastTransitionIdleScene: SceneKey) {
+ fun finishAllTransitions() {
// Force finish all transitions.
while (currentTransitions.isNotEmpty()) {
- val transition = transitionStates[0] as TransitionState.Transition
- val idleScene =
- if (transitionStates.size == 1) {
- lastTransitionIdleScene
- } else {
- transition.currentScene
- }
-
- finishTransition(transition, idleScene)
+ finishTransition(transitionStates[0] as TransitionState.Transition)
}
}
- return when {
- isProgressCloseTo(0f) -> {
- finishAllTransitions(transition.fromScene)
- true
- }
- isProgressCloseTo(1f) -> {
- finishAllTransitions(transition.toScene)
- true
- }
- else -> false
+ val shouldSnap =
+ (isProgressCloseTo(0f) && transition.currentScene == transition.fromScene) ||
+ (isProgressCloseTo(1f) && transition.currentScene == transition.toScene)
+ return if (shouldSnap) {
+ finishAllTransitions()
+ true
+ } else {
+ false
}
}
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/ContentState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/ContentState.kt
index add393441794..0bd676bb9858 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/ContentState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/ContentState.kt
@@ -29,6 +29,8 @@ import com.android.compose.animation.scene.SceneTransitionLayoutImpl
import com.android.compose.animation.scene.TransformationSpec
import com.android.compose.animation.scene.TransformationSpecImpl
import com.android.compose.animation.scene.TransitionKey
+import com.android.compose.animation.scene.transition.link.LinkedTransition
+import com.android.compose.animation.scene.transition.link.StateLink
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
@@ -110,6 +112,9 @@ sealed interface ContentState<out T : ContentKey> {
*/
private var interruptionDecay: Animatable<Float, AnimationVector1D>? = null
+ /** The map of active links that connects this transition to other transitions. */
+ internal val activeTransitionLinks = mutableMapOf<StateLink, LinkedTransition>()
+
init {
check(fromContent != toContent)
check(
@@ -131,7 +136,7 @@ sealed interface ContentState<out T : ContentKey> {
* animation is complete or cancel it to snap the animation. Calling [finish] multiple
* times will return the same [Job].
*/
- abstract fun finish(): Job
+ internal abstract fun finish(): Job
/**
* Whether we are transitioning. If [from] or [to] is empty, we will also check that they
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
index 75f44ff9cfe0..60cefb0c0ac4 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
@@ -1380,8 +1380,8 @@ class ElementTest {
// Manually finish the transition.
rule.runOnUiThread {
- state.finishTransition(aToB, SceneB)
- state.finishTransition(bToC, SceneC)
+ state.finishTransition(aToB)
+ state.finishTransition(bToC)
}
rule.waitForIdle()
assertThat(state.transitionState).isIdle()
@@ -1482,7 +1482,7 @@ class ElementTest {
// Manually finish A => B so only B => C is remaining.
bToCInterruptionProgress = 0f
- rule.runOnUiThread { state.finishTransition(aToB, SceneB) }
+ rule.runOnUiThread { state.finishTransition(aToB) }
rule
.onNode(isElement(TestElements.Foo, SceneB))
.assertPositionInRootIsEqualTo(offsetInB.x, offsetInB.y)
@@ -2002,6 +2002,7 @@ class ElementTest {
transition(
from = SceneB,
to = SceneC,
+ current = { SceneB },
progress = { 0f },
interruptionProgress = { interruptionProgress },
onFinish = neverFinish(),
@@ -2018,8 +2019,8 @@ class ElementTest {
// 100%. We should be at (20dp, 20dp), unless the interruption deltas have not been
// correctly cleaned.
rule.runOnUiThread {
- state.finishTransition(aToB, idleScene = SceneB)
- state.finishTransition(bToC, idleScene = SceneB)
+ state.finishTransition(aToB)
+ state.finishTransition(bToC)
state.startTransition(
transition(
from = SceneB,
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
index 6b417ee5a468..c8ac580bf5ba 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
@@ -18,7 +18,9 @@ package com.android.compose.animation.scene
import android.util.Log
import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.compose.animation.scene.TestScenes.SceneA
@@ -110,16 +112,6 @@ class SceneTransitionLayoutStateTest {
}
@Test
- fun setTargetScene_transitionToOriginalScene() = runMonotonicClockTest {
- val state = MutableSceneTransitionLayoutState(SceneA)
- assertThat(state.setTargetScene(SceneB, coroutineScope = this)).isNotNull()
-
- // Progress is 0f, so we don't animate at all and directly snap back to A.
- assertThat(state.setTargetScene(SceneA, coroutineScope = this)).isNull()
- assertThat(state.transitionState).isEqualTo(TransitionState.Idle(SceneA))
- }
-
- @Test
fun setTargetScene_coroutineScopeCancelled() = runMonotonicClockTest {
val state = MutableSceneTransitionLayoutState(SceneA)
@@ -180,7 +172,7 @@ class SceneTransitionLayoutStateTest {
assertThat(childState.isTransitioning(SceneA, SceneB)).isTrue()
assertThat(parentState.isTransitioning(SceneC, SceneD)).isTrue()
- childState.finishTransition(childTransition, SceneB)
+ childState.finishTransition(childTransition)
assertThat(childState.transitionState).isEqualTo(TransitionState.Idle(SceneB))
assertThat(parentState.transitionState).isEqualTo(TransitionState.Idle(SceneD))
}
@@ -217,7 +209,7 @@ class SceneTransitionLayoutStateTest {
assertThat(parentState.isTransitioning(SceneC, SceneD)).isTrue()
assertThat(parentParentState.isTransitioning(SceneB, SceneC)).isTrue()
- childState.finishTransition(childTransition, SceneB)
+ childState.finishTransition(childTransition)
assertThat(childState.transitionState).isEqualTo(TransitionState.Idle(SceneB))
assertThat(parentState.transitionState).isEqualTo(TransitionState.Idle(SceneD))
assertThat(parentParentState.transitionState).isEqualTo(TransitionState.Idle(SceneC))
@@ -241,13 +233,13 @@ class SceneTransitionLayoutStateTest {
fun linkedTransition_reverseTransitionIsNotLinked() {
val (parentState, childState) = setupLinkedStates()
- val childTransition = transition(SceneB, SceneA)
+ val childTransition = transition(SceneB, SceneA, current = { SceneB })
childState.startTransition(childTransition)
assertThat(childState.isTransitioning(SceneB, SceneA)).isTrue()
assertThat(parentState.transitionState).isEqualTo(TransitionState.Idle(SceneC))
- childState.finishTransition(childTransition, SceneB)
+ childState.finishTransition(childTransition)
assertThat(childState.transitionState).isEqualTo(TransitionState.Idle(SceneB))
assertThat(parentState.transitionState).isEqualTo(TransitionState.Idle(SceneC))
}
@@ -256,27 +248,15 @@ class SceneTransitionLayoutStateTest {
fun linkedTransition_startsLinkAndFinishesLinkInFromState() {
val (parentState, childState) = setupLinkedStates()
- val childTransition = transition(SceneA, SceneB)
+ val childTransition = transition(SceneA, SceneB, current = { SceneA })
childState.startTransition(childTransition)
- childState.finishTransition(childTransition, SceneA)
+ childState.finishTransition(childTransition)
assertThat(childState.transitionState).isEqualTo(TransitionState.Idle(SceneA))
assertThat(parentState.transitionState).isEqualTo(TransitionState.Idle(SceneC))
}
@Test
- fun linkedTransition_startsLinkAndFinishesLinkInUnknownState() {
- val (parentState, childState) = setupLinkedStates()
-
- val childTransition = transition(SceneA, SceneB)
- childState.startTransition(childTransition)
-
- childState.finishTransition(childTransition, SceneD)
- assertThat(childState.transitionState).isEqualTo(TransitionState.Idle(SceneD))
- assertThat(parentState.transitionState).isEqualTo(TransitionState.Idle(SceneC))
- }
-
- @Test
fun linkedTransition_startsLinkButLinkedStateIsTakenOver() = runTest {
val (parentState, childState) = setupLinkedStates()
@@ -295,7 +275,7 @@ class SceneTransitionLayoutStateTest {
childState.startTransition(childTransition)
parentState.startTransition(parentTransition)
- childState.finishTransition(childTransition, SceneB)
+ childState.finishTransition(childTransition)
assertThat(childState.transitionState).isEqualTo(TransitionState.Idle(SceneB))
assertThat(parentState.transitionState).isEqualTo(parentTransition)
}
@@ -341,7 +321,9 @@ class SceneTransitionLayoutStateTest {
@Test
fun snapToIdleIfClose_snapToStart() = runMonotonicClockTest {
val state = MutableSceneTransitionLayoutStateImpl(SceneA, SceneTransitions.Empty)
- state.startTransition(transition(from = SceneA, to = SceneB, progress = { 0.2f }))
+ state.startTransition(
+ transition(from = SceneA, to = SceneB, current = { SceneA }, progress = { 0.2f })
+ )
assertThat(state.isTransitioning()).isTrue()
// Ignore the request if the progress is not close to 0 or 1, using the threshold.
@@ -399,6 +381,31 @@ class SceneTransitionLayoutStateTest {
}
@Test
+ fun snapToIdleIfClose_closeButNotCurrentScene() = runMonotonicClockTest {
+ val state = MutableSceneTransitionLayoutStateImpl(SceneA, SceneTransitions.Empty)
+ var progress by mutableStateOf(0f)
+ var currentScene by mutableStateOf(SceneB)
+ state.startTransition(
+ transition(
+ from = SceneA,
+ to = SceneB,
+ current = { currentScene },
+ progress = { progress }
+ )
+ )
+ assertThat(state.isTransitioning()).isTrue()
+
+ // Ignore the request if we are close to a scene that is not the current scene
+ assertThat(state.snapToIdleIfClose(threshold = 0.1f)).isFalse()
+ assertThat(state.isTransitioning()).isTrue()
+
+ progress = 1f
+ currentScene = SceneA
+ assertThat(state.snapToIdleIfClose(threshold = 0.1f)).isFalse()
+ assertThat(state.isTransitioning()).isTrue()
+ }
+
+ @Test
fun linkedTransition_fuzzyLinksAreMatchedAndStarted() {
val (parentState, childState) = setupLinkedStates(SceneC, SceneA, null, null, null, SceneD)
val childTransition = transition(SceneA, SceneB)
@@ -407,7 +414,7 @@ class SceneTransitionLayoutStateTest {
assertThat(childState.isTransitioning(SceneA, SceneB)).isTrue()
assertThat(parentState.isTransitioning(SceneC, SceneD)).isTrue()
- childState.finishTransition(childTransition, SceneB)
+ childState.finishTransition(childTransition)
assertThat(childState.transitionState).isEqualTo(TransitionState.Idle(SceneB))
assertThat(parentState.transitionState).isEqualTo(TransitionState.Idle(SceneD))
}
@@ -417,13 +424,13 @@ class SceneTransitionLayoutStateTest {
val (parentState, childState) =
setupLinkedStates(SceneC, SceneA, SceneA, null, null, SceneD)
- val childTransition = transition(SceneA, SceneB)
+ val childTransition = transition(SceneA, SceneB, current = { SceneA })
childState.startTransition(childTransition)
assertThat(childState.isTransitioning(SceneA, SceneB)).isTrue()
assertThat(parentState.isTransitioning(SceneC, SceneD)).isTrue()
- childState.finishTransition(childTransition, SceneA)
+ childState.finishTransition(childTransition)
assertThat(childState.transitionState).isEqualTo(TransitionState.Idle(SceneA))
assertThat(parentState.transitionState).isEqualTo(TransitionState.Idle(SceneC))
}
@@ -595,12 +602,12 @@ class SceneTransitionLayoutStateTest {
// Mark bToC as finished. The list of current transitions does not change because aToB is
// still not marked as finished.
- state.finishTransition(bToC, idleScene = bToC.currentScene)
- assertThat(state.finishedTransitions).containsExactly(bToC, bToC.currentScene)
+ state.finishTransition(bToC)
+ assertThat(state.finishedTransitions).containsExactly(bToC)
assertThat(state.currentTransitions).containsExactly(aToB, bToC, cToA).inOrder()
// Mark aToB as finished. This will remove both aToB and bToC from the list of transitions.
- state.finishTransition(aToB, idleScene = aToB.currentScene)
+ state.finishTransition(aToB)
assertThat(state.finishedTransitions).isEmpty()
assertThat(state.currentTransitions).containsExactly(cToA).inOrder()
}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/Transition.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/Transition.kt
index 91bd7e1800cd..e4e410828d0a 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/Transition.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/Transition.kt
@@ -29,7 +29,7 @@ import kotlinx.coroutines.test.TestScope
fun transition(
from: SceneKey,
to: SceneKey,
- current: () -> SceneKey = { from },
+ current: () -> SceneKey = { to },
progress: () -> Float = { 0f },
progressVelocity: () -> Float = { 0f },
previewProgress: () -> Float = { 0f },