diff options
4 files changed, 40 insertions, 7 deletions
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 61332b61ed1b..057e4f1b2ee7 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 @@ -372,12 +372,12 @@ internal class MutableSceneTransitionLayoutStateImpl( // Handle transition links. previousTransition?.let { cancelActiveTransitionLinks(it) } - if (stateLinks.isNotEmpty()) { - coroutineScope { setupTransitionLinks(transition) } - } + coroutineScope { + setupTransitionLinks(transition) - // Run the transition until it is finished. - transition.run() + // Run the transition until it is finished. + transition.runInternal() + } } finally { finishTransition(transition) } diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt index 7d29a68e3a8d..2c3a925b9a8f 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt @@ -36,6 +36,7 @@ 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.CompletableDeferred import kotlinx.coroutines.launch /** The state associated to a [SceneTransitionLayout] at some specific point in time. */ @@ -283,6 +284,12 @@ sealed interface TransitionState { /** The map of active links that connects this transition to other transitions. */ internal val activeTransitionLinks = mutableMapOf<StateLink, LinkedTransition>() + /** Whether this transition was already started. */ + private var wasStarted = false + + /** A completable to [await] this transition. */ + private val completable = CompletableDeferred<Unit>() + init { check(fromContent != toContent) check( @@ -328,7 +335,7 @@ sealed interface TransitionState { } /** Run this transition and return once it is finished. */ - abstract suspend fun run() + protected abstract suspend fun run() /** * Freeze this transition state so that neither [currentScene] nor [currentOverlays] will @@ -341,6 +348,20 @@ sealed interface TransitionState { */ abstract fun freezeAndAnimateToCurrentState() + /** Wait for this transition to finish. */ + internal suspend fun await() = completable.await() + + internal suspend fun runInternal() { + check(!wasStarted) { "A Transition can be started only once." } + wasStarted = true + + try { + run() + } finally { + completable.complete(Unit) + } + } + internal fun updateOverscrollSpecs( fromSpec: OverscrollSpecImpl?, toSpec: OverscrollSpecImpl?, diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transition/link/LinkedTransition.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transition/link/LinkedTransition.kt index 42ba9ba95e07..d7cb26c87358 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transition/link/LinkedTransition.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transition/link/LinkedTransition.kt @@ -50,7 +50,7 @@ internal class LinkedTransition( get() = originalTransition.progressVelocity override suspend fun run() { - originalTransition.run() + originalTransition.await() } override fun freezeAndAnimateToCurrentState() { 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 a2b263b9f9ed..597d24c29c10 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 @@ -42,6 +42,7 @@ import kotlinx.coroutines.cancelAndJoin import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.consumeAsFlow import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking import kotlinx.coroutines.test.runTest import org.junit.Assert.assertThrows import org.junit.Rule @@ -777,4 +778,15 @@ class SceneTransitionLayoutStateTest { assertThat(transition.progressTo(SceneA)).isEqualTo(1f - 0.2f) assertThrows(IllegalArgumentException::class.java) { transition.progressTo(SceneC) } } + + @Test + fun transitionCanBeStartedOnlyOnce() = runTest { + val state = MutableSceneTransitionLayoutState(SceneA) + val transition = transition(from = SceneA, to = SceneB) + + state.startTransitionImmediately(backgroundScope, transition) + assertThrows(IllegalStateException::class.java) { + runBlocking { state.startTransition(transition) } + } + } } |