Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 109a166c authored by Jordan Demeulenaere's avatar Jordan Demeulenaere Committed by Android (Google) Code Review
Browse files

Merge "Don't remove finished transitions early when other transitions run" into main

parents 93d7e93f d590a3dd
Loading
Loading
Loading
Loading
+18 −30
Original line number Diff line number Diff line
@@ -411,9 +411,7 @@ internal class MutableSceneTransitionLayoutStateImpl(
                    if (tooManyTransitions) logTooManyTransitions()

                    // Force finish all transitions.
                    while (currentTransitions.isNotEmpty()) {
                        finishTransition(transitionStates[0] as TransitionState.Transition)
                    }
                    currentTransitions.fastForEach { finishTransition(it) }

                    // We finished all transitions, so we are now idle. We remove this state so that
                    // we end up only with the new transition after appending it.
@@ -475,46 +473,36 @@ internal class MutableSceneTransitionLayoutStateImpl(
        // Mark this transition as finished.
        finishedTransitions.add(transition)

        // Keep a reference to the last transition, in case we remove all transitions and should
        // settle to Idle.
        if (finishedTransitions.size != transitionStates.size) {
            // Some transitions were not finished, so we won't settle to idle.
            return
        }

        // Keep a reference to the last transition, in case all transitions are finished and we
        // should settle to Idle.
        val lastTransition = transitionStates.last()

        // Remove all first n finished transitions.
        var i = 0
        val nStates = transitionStates.size
        while (i < nStates) {
            val t = transitionStates[i]
            if (!finishedTransitions.contains(t)) {
                // Stop here.
                break
        transitionStates.fastForEach { state ->
            if (!finishedTransitions.contains(state)) {
                // Some transitions were not finished, so we won't settle to idle.
                return
            }

            // Remove the transition from the set of finished transitions.
            finishedTransitions.remove(t)
            i++
        }

        // If all transitions are finished, we are idle.
        if (i == nStates) {
            check(finishedTransitions.isEmpty())
            val idle =
                TransitionState.Idle(lastTransition.currentScene, lastTransition.currentOverlays)
        val idle = TransitionState.Idle(lastTransition.currentScene, lastTransition.currentOverlays)
        Log.i(TAG, "all transitions finished. idle=$idle")
        finishedTransitions.clear()
        this.transitionStates = listOf(idle)
        } else if (i > 0) {
            this.transitionStates = transitionStates.subList(fromIndex = i, toIndex = nStates)
        }
    }

    override fun snapToScene(scene: SceneKey, currentOverlays: Set<OverlayKey>) {
        checkThread()

        // Force finish all transitions.
        while (currentTransitions.isNotEmpty()) {
            finishTransition(transitionStates[0] as TransitionState.Transition)
        }
        currentTransitions.fastForEach { finishTransition(it) }

        check(transitionStates.size == 1)
        check(currentTransitions.isEmpty())
        transitionStates = listOf(TransitionState.Idle(scene, currentOverlays))
    }

+26 −8
Original line number Diff line number Diff line
@@ -198,23 +198,30 @@ class SceneTransitionLayoutStateTest {
        assertThat(state.currentTransitions).containsExactly(aToB, bToC).inOrder()

        // C => A. This should automatically call freezeAndAnimateToCurrentState() on bToC.
        state.startTransitionImmediately(animationScope = backgroundScope, cToA)
        val cToAJob = state.startTransitionImmediately(animationScope = backgroundScope, cToA)
        assertThat(frozenTransitions).containsExactly(aToB, bToC)
        assertThat(state.finishedTransitions).isEmpty()
        assertThat(state.currentTransitions).containsExactly(aToB, bToC, cToA).inOrder()

        // Mark bToC as finished. The list of current transitions does not change because aToB is
        // still not marked as finished.
        // Mark aToB and bToC as finished. The list of current transitions does not change because
        // cToA is still running.
        aToB.finish()
        aToBJob.join()
        assertThat(state.finishedTransitions).containsExactly(aToB)
        assertThat(state.currentTransitions).containsExactly(aToB, bToC, cToA).inOrder()

        bToC.finish()
        bToCJob.join()
        assertThat(state.finishedTransitions).containsExactly(bToC)
        assertThat(state.finishedTransitions).containsExactly(aToB, 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.
        aToB.finish()
        aToBJob.join()
        // Mark cToA as finished. This should clear all transitions and settle to idle.
        cToA.finish()
        cToAJob.join()
        assertThat(state.finishedTransitions).isEmpty()
        assertThat(state.currentTransitions).containsExactly(cToA).inOrder()
        assertThat(state.currentTransitions).isEmpty()
        assertThat(state.transitionState).isIdle()
        assertThat(state.transitionState).hasCurrentScene(SceneA)
    }

    @Test
@@ -473,4 +480,15 @@ class SceneTransitionLayoutStateTest {
                    "SceneKey(debugName=SceneB)"
            )
    }

    @Test
    fun snapToScene_multipleTransitions() = runMonotonicClockTest {
        val state = MutableSceneTransitionLayoutState(SceneA)
        state.startTransitionImmediately(this, transition(SceneA, SceneB))
        state.startTransitionImmediately(this, transition(SceneB, SceneC))
        state.snapToScene(SceneC)

        assertThat(state.transitionState).isIdle()
        assertThat(state.transitionState).hasCurrentScene(SceneC)
    }
}
+2 −2
Original line number Diff line number Diff line
@@ -379,8 +379,8 @@ class SceneTransitionLayoutTest {
        assertThat(transition).hasProgress(0.5f)
        rule.waitForIdle()

        // B and C are composed.
        rule.onNodeWithTag("aRoot").assertDoesNotExist()
        // A, B and C are still composed given that B => C is not finished yet.
        rule.onNodeWithTag("aRoot").assertExists()
        rule.onNodeWithTag("bRoot").assertExists()
        rule.onNodeWithTag("cRoot").assertExists()