summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt4
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt19
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt39
3 files changed, 58 insertions, 4 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..ffd95643c122 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
@@ -614,8 +614,8 @@ internal class MutableSceneTransitionLayoutStateImpl(
}
val shouldSnap =
- (isProgressCloseTo(0f) && transition.currentScene == transition.fromContent) ||
- (isProgressCloseTo(1f) && transition.currentScene == transition.toContent)
+ (isProgressCloseTo(0f) && transition.isFromCurrentContent()) ||
+ (isProgressCloseTo(1f) && transition.isToCurrentContent())
return if (shouldSnap) {
finishAllTransitions()
true
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..ccabe3d01d26 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
@@ -129,7 +129,7 @@ sealed interface TransitionState {
* starting a swipe transition to show [overlay] and will be `true` only once the swipe
* transition is committed.
*/
- protected abstract val isEffectivelyShown: Boolean
+ abstract val isEffectivelyShown: Boolean
init {
check(
@@ -164,7 +164,7 @@ sealed interface TransitionState {
* [fromOverlay] by [toOverlay] and will [toOverlay] once the swipe transition is
* committed.
*/
- protected abstract val effectivelyShownOverlay: OverlayKey
+ abstract val effectivelyShownOverlay: OverlayKey
init {
check(fromOverlay != toOverlay)
@@ -327,6 +327,21 @@ sealed interface TransitionState {
}
}
+ /** Whether [fromContent] is effectively the current content of the transition. */
+ internal fun isFromCurrentContent() = isCurrentContent(expectedFrom = true)
+
+ /** Whether [toContent] is effectively the current content of the transition. */
+ internal fun isToCurrentContent() = isCurrentContent(expectedFrom = false)
+
+ private fun isCurrentContent(expectedFrom: Boolean): Boolean {
+ val expectedContent = if (expectedFrom) fromContent else toContent
+ return when (this) {
+ is ChangeScene -> currentScene == expectedContent
+ is ReplaceOverlay -> effectivelyShownOverlay == expectedContent
+ is ShowOrHideOverlay -> isEffectivelyShown == (expectedContent == overlay)
+ }
+ }
+
/** Run this transition and return once it is finished. */
abstract suspend fun run()
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..75339a8a2a73 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
@@ -23,6 +23,7 @@ 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.TestOverlays.OverlayA
import com.android.compose.animation.scene.TestScenes.SceneA
import com.android.compose.animation.scene.TestScenes.SceneB
import com.android.compose.animation.scene.TestScenes.SceneC
@@ -327,6 +328,25 @@ class SceneTransitionLayoutStateTest {
}
@Test
+ fun snapToIdleIfClose_snapToStart_overlays() = runMonotonicClockTest {
+ val state = MutableSceneTransitionLayoutStateImpl(SceneA, SceneTransitions.Empty)
+ state.startTransitionImmediately(
+ animationScope = backgroundScope,
+ transition(SceneA, OverlayA, isEffectivelyShown = { false }, progress = { 0.2f }),
+ )
+ assertThat(state.isTransitioning()).isTrue()
+
+ // Ignore the request if the progress is not close to 0 or 1, using the threshold.
+ assertThat(state.snapToIdleIfClose(threshold = 0.1f)).isFalse()
+ assertThat(state.isTransitioning()).isTrue()
+
+ // Go to the initial scene if it is close to 0.
+ assertThat(state.snapToIdleIfClose(threshold = 0.2f)).isTrue()
+ assertThat(state.isTransitioning()).isFalse()
+ assertThat(state.transitionState).isEqualTo(TransitionState.Idle(SceneA))
+ }
+
+ @Test
fun snapToIdleIfClose_snapToEnd() = runMonotonicClockTest {
val state = MutableSceneTransitionLayoutStateImpl(SceneA, SceneTransitions.Empty)
state.startTransitionImmediately(
@@ -346,6 +366,25 @@ class SceneTransitionLayoutStateTest {
}
@Test
+ fun snapToIdleIfClose_snapToEnd_overlays() = runMonotonicClockTest {
+ val state = MutableSceneTransitionLayoutStateImpl(SceneA, SceneTransitions.Empty)
+ state.startTransitionImmediately(
+ animationScope = backgroundScope,
+ transition(SceneA, OverlayA, isEffectivelyShown = { true }, progress = { 0.8f }),
+ )
+ assertThat(state.isTransitioning()).isTrue()
+
+ // Ignore the request if the progress is not close to 0 or 1, using the threshold.
+ assertThat(state.snapToIdleIfClose(threshold = 0.1f)).isFalse()
+ assertThat(state.isTransitioning()).isTrue()
+
+ // Go to the final scene if it is close to 1.
+ assertThat(state.snapToIdleIfClose(threshold = 0.2f)).isTrue()
+ assertThat(state.isTransitioning()).isFalse()
+ assertThat(state.transitionState).isEqualTo(TransitionState.Idle(SceneA, setOf(OverlayA)))
+ }
+
+ @Test
fun snapToIdleIfClose_multipleTransitions() = runMonotonicClockTest {
val state = MutableSceneTransitionLayoutStateImpl(SceneA, SceneTransitions.Empty)