summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt10
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt23
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transition/link/LinkedTransition.kt2
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt12
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) }
+ }
+ }
}