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

Commit d76a16bc authored by Josh Tsuji's avatar Josh Tsuji
Browse files

Fix issues with transitionValue after cancellations.

Bug: 330185445
Test: atest KeyguardTransitionInteractorTest
Flag: NA
Change-Id: Iff6c73d7f1ce728967cf499f197978d0e6fc4659
parent 56dee36a
Loading
Loading
Loading
Loading
+57 −0
Original line number Original line Diff line number Diff line
@@ -269,6 +269,54 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() {
            assertThat(startedSteps).isEqualTo(listOf(0f, 0.5f, 1f, 1f, 0.5f, 0f))
            assertThat(startedSteps).isEqualTo(listOf(0f, 0.5f, 1f, 1f, 0.5f, 0f))
        }
        }


    @Test
    fun transitionValue_canceled_toAnotherState() =
        testScope.runTest {
            val transitionValuesGone by collectValues(underTest.transitionValue(state = GONE))
            val transitionValuesAod by collectValues(underTest.transitionValue(state = AOD))
            val transitionValuesLs by collectValues(underTest.transitionValue(state = LOCKSCREEN))

            listOf(
                    TransitionStep(GONE, AOD, 0f, STARTED),
                    TransitionStep(GONE, AOD, 0.5f, RUNNING),
                    TransitionStep(GONE, AOD, 0.5f, CANCELED),
                    TransitionStep(AOD, LOCKSCREEN, 0.5f, STARTED),
                    TransitionStep(AOD, LOCKSCREEN, 0.7f, RUNNING),
                    TransitionStep(AOD, LOCKSCREEN, 1f, FINISHED),
                )
                .forEach {
                    repository.sendTransitionStep(it)
                    runCurrent()
                }

            assertThat(transitionValuesGone).isEqualTo(listOf(1f, 0.5f, 0f))
            assertThat(transitionValuesAod).isEqualTo(listOf(0f, 0.5f, 0.5f, 0.3f, 0f))
            assertThat(transitionValuesLs).isEqualTo(listOf(0.5f, 0.7f, 1f))
        }

    @Test
    fun transitionValue_canceled_backToOriginalState() =
        testScope.runTest {
            val transitionValuesGone by collectValues(underTest.transitionValue(state = GONE))
            val transitionValuesAod by collectValues(underTest.transitionValue(state = AOD))

            listOf(
                    TransitionStep(GONE, AOD, 0f, STARTED),
                    TransitionStep(GONE, AOD, 0.5f, RUNNING),
                    TransitionStep(GONE, AOD, 1f, CANCELED),
                    TransitionStep(AOD, GONE, 0.5f, STARTED),
                    TransitionStep(AOD, GONE, 0.7f, RUNNING),
                    TransitionStep(AOD, GONE, 1f, FINISHED),
                )
                .forEach {
                    repository.sendTransitionStep(it)
                    runCurrent()
                }

            assertThat(transitionValuesGone).isEqualTo(listOf(1f, 0.5f, 0.5f, 0.7f, 1f))
            assertThat(transitionValuesAod).isEqualTo(listOf(0f, 0.5f, 0.5f, 0.3f, 0f))
        }

    @Test
    @Test
    fun isInTransitionToAnyState() =
    fun isInTransitionToAnyState() =
        testScope.runTest {
        testScope.runTest {
@@ -276,6 +324,7 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() {


            assertEquals(
            assertEquals(
                listOf(
                listOf(
                    false,
                    true, // The repo is seeded with a transition from OFF to LOCKSCREEN.
                    true, // The repo is seeded with a transition from OFF to LOCKSCREEN.
                    false,
                    false,
                ),
                ),
@@ -288,6 +337,7 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() {


            assertEquals(
            assertEquals(
                listOf(
                listOf(
                    false,
                    true,
                    true,
                    false,
                    false,
                    true,
                    true,
@@ -301,6 +351,7 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() {


            assertEquals(
            assertEquals(
                listOf(
                listOf(
                    false,
                    true,
                    true,
                    false,
                    false,
                    true,
                    true,
@@ -314,6 +365,7 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() {


            assertEquals(
            assertEquals(
                listOf(
                listOf(
                    false,
                    true,
                    true,
                    false,
                    false,
                    true,
                    true,
@@ -330,6 +382,7 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() {


            assertEquals(
            assertEquals(
                listOf(
                listOf(
                    false,
                    true,
                    true,
                    false,
                    false,
                ),
                ),
@@ -345,6 +398,7 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() {


            assertEquals(
            assertEquals(
                listOf(
                listOf(
                    false,
                    true,
                    true,
                    false,
                    false,
                    true,
                    true,
@@ -359,6 +413,7 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() {


            assertEquals(
            assertEquals(
                listOf(
                listOf(
                    false,
                    true,
                    true,
                    false,
                    false,
                    true,
                    true,
@@ -379,6 +434,7 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() {


            assertEquals(
            assertEquals(
                listOf(
                listOf(
                    false,
                    true,
                    true,
                    false,
                    false,
                    true,
                    true,
@@ -398,6 +454,7 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() {


            assertEquals(
            assertEquals(
                listOf(
                listOf(
                    false,
                    true,
                    true,
                    false,
                    false,
                    true,
                    true,
+27 −18
Original line number Original line Diff line number Diff line
@@ -119,24 +119,7 @@ class KeyguardTransitionRepositoryImpl @Inject constructor() : KeyguardTransitio
    init {
    init {
        // Seed with transitions signaling a boot into lockscreen state. If updating this, please
        // Seed with transitions signaling a boot into lockscreen state. If updating this, please
        // also update FakeKeyguardTransitionRepository.
        // also update FakeKeyguardTransitionRepository.
        emitTransition(
        initialTransitionSteps.forEach(::emitTransition)
            TransitionStep(
                KeyguardState.OFF,
                KeyguardState.LOCKSCREEN,
                0f,
                TransitionState.STARTED,
                KeyguardTransitionRepositoryImpl::class.simpleName!!,
            )
        )
        emitTransition(
            TransitionStep(
                KeyguardState.OFF,
                KeyguardState.LOCKSCREEN,
                1f,
                TransitionState.FINISHED,
                KeyguardTransitionRepositoryImpl::class.simpleName!!,
            )
        )
    }
    }


    override fun startTransition(info: TransitionInfo): UUID? {
    override fun startTransition(info: TransitionInfo): UUID? {
@@ -256,5 +239,31 @@ class KeyguardTransitionRepositoryImpl @Inject constructor() : KeyguardTransitio


    companion object {
    companion object {
        private const val TAG = "KeyguardTransitionRepository"
        private const val TAG = "KeyguardTransitionRepository"

        /**
         * Transition steps to seed the repository with, so that all of the transition interactor
         * flows emit reasonable initial values.
         */
        val initialTransitionSteps: List<TransitionStep> =
            listOf(
                TransitionStep(
                    KeyguardState.OFF,
                    KeyguardState.OFF,
                    1f,
                    TransitionState.FINISHED,
                ),
                TransitionStep(
                    KeyguardState.OFF,
                    KeyguardState.LOCKSCREEN,
                    0f,
                    TransitionState.STARTED,
                ),
                TransitionStep(
                    KeyguardState.OFF,
                    KeyguardState.LOCKSCREEN,
                    1f,
                    TransitionState.FINISHED,
                ),
            )
    }
    }
}
}
+38 −20
Original line number Original line Diff line number Diff line
@@ -91,13 +91,48 @@ constructor(
        }
        }
    }
    }


    val transitions = repository.transitions

    /**
     * A pair of the most recent STARTED step, and the transition step immediately preceding it. The
     * transition framework enforces that the previous step is either a CANCELED or FINISHED step,
     * and that the previous step was *to* the state the STARTED step is *from*.
     *
     * This flow can be used to access the previous step to determine whether it was CANCELED or
     * FINISHED. In the case of a CANCELED step, we can also figure out which state we were coming
     * from when we were canceled.
     */
    val startedStepWithPrecedingStep =
        transitions
            .pairwise()
            .filter { it.newValue.transitionState == TransitionState.STARTED }
            .shareIn(scope, SharingStarted.Eagerly)

    init {
    init {
        // Collect non-canceled steps and emit transition values.
        scope.launch(mainDispatcher) {
        scope.launch(mainDispatcher) {
            repository.transitions.collect { step ->
            repository.transitions
                .filter { it.transitionState != TransitionState.CANCELED }
                .collect { step ->
                    getTransitionValueFlow(step.from).emit(1f - step.value)
                    getTransitionValueFlow(step.from).emit(1f - step.value)
                    getTransitionValueFlow(step.to).emit(step.value)
                    getTransitionValueFlow(step.to).emit(step.value)
                }
                }
        }
        }

        // If a transition from state A -> B is canceled in favor of a transition from B -> C, we
        // need to ensure we emit transitionValue(A) = 0f, since no further steps will be emitted
        // where the from or to states are A. This would leave transitionValue(A) stuck at an
        // arbitrary non-zero value.
        scope.launch(mainDispatcher) {
            startedStepWithPrecedingStep.collect { (prevStep, startedStep) ->
                if (
                    prevStep.transitionState == TransitionState.CANCELED &&
                        startedStep.to != prevStep.from
                ) {
                    getTransitionValueFlow(prevStep.from).emit(0f)
                }
            }
        }
    }
    }


    /** (any)->GONE transition information */
    /** (any)->GONE transition information */
@@ -202,8 +237,6 @@ constructor(
    val dozingToLockscreenTransition: Flow<TransitionStep> =
    val dozingToLockscreenTransition: Flow<TransitionStep> =
        repository.transition(DOZING, LOCKSCREEN)
        repository.transition(DOZING, LOCKSCREEN)


    val transitions = repository.transitions

    /** Receive all [TransitionStep] matching a filter of [from]->[to] */
    /** Receive all [TransitionStep] matching a filter of [from]->[to] */
    fun transition(from: KeyguardState, to: KeyguardState): Flow<TransitionStep> {
    fun transition(from: KeyguardState, to: KeyguardState): Flow<TransitionStep> {
        return repository.transition(from, to)
        return repository.transition(from, to)
@@ -249,21 +282,6 @@ constructor(
            .map { aodAvailable -> if (aodAvailable) AOD else DOZING }
            .map { aodAvailable -> if (aodAvailable) AOD else DOZING }
            .stateIn(scope, SharingStarted.Eagerly, DOZING)
            .stateIn(scope, SharingStarted.Eagerly, DOZING)


    /**
     * A pair of the most recent STARTED step, and the transition step immediately preceding it. The
     * transition framework enforces that the previous step is either a CANCELED or FINISHED step,
     * and that the previous step was *to* the state the STARTED step is *from*.
     *
     * This flow can be used to access the previous step to determine whether it was CANCELED or
     * FINISHED. In the case of a CANCELED step, we can also figure out which state we were coming
     * from when we were canceled.
     */
    val startedStepWithPrecedingStep =
        transitions
            .pairwise()
            .filter { it.newValue.transitionState == TransitionState.STARTED }
            .stateIn(scope, SharingStarted.Eagerly, null)

    /**
    /**
     * The last [KeyguardState] to which we [TransitionState.FINISHED] a transition.
     * The last [KeyguardState] to which we [TransitionState.FINISHED] a transition.
     *
     *
+4 −19
Original line number Original line Diff line number Diff line
@@ -18,7 +18,6 @@
package com.android.systemui.keyguard.data.repository
package com.android.systemui.keyguard.data.repository


import android.annotation.FloatRange
import android.annotation.FloatRange
import android.util.Log
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionInfo
import com.android.systemui.keyguard.shared.model.TransitionInfo
@@ -48,21 +47,8 @@ class FakeKeyguardTransitionRepository @Inject constructor() : KeyguardTransitio
    override val transitions: SharedFlow<TransitionStep> = _transitions
    override val transitions: SharedFlow<TransitionStep> = _transitions


    init {
    init {
        _transitions.tryEmit(
        // Seed the fake repository with the same initial steps the actual repository uses.
            TransitionStep(
        KeyguardTransitionRepositoryImpl.initialTransitionSteps.forEach { _transitions.tryEmit(it) }
                transitionState = TransitionState.STARTED,
                from = KeyguardState.OFF,
                to = KeyguardState.LOCKSCREEN,
            )
        )

        _transitions.tryEmit(
            TransitionStep(
                transitionState = TransitionState.FINISHED,
                from = KeyguardState.OFF,
                to = KeyguardState.LOCKSCREEN,
            )
        )
    }
    }


    /**
    /**
@@ -207,16 +193,15 @@ class FakeKeyguardTransitionRepository @Inject constructor() : KeyguardTransitio
    suspend fun sendTransitionSteps(
    suspend fun sendTransitionSteps(
        steps: List<TransitionStep>,
        steps: List<TransitionStep>,
        testScope: TestScope,
        testScope: TestScope,
        validateStep: Boolean = true
        validateSteps: Boolean = true
    ) {
    ) {
        steps.forEach {
        steps.forEach {
            sendTransitionStep(step = it, validateStep = validateStep)
            sendTransitionStep(step = it, validateStep = validateSteps)
            testScope.testScheduler.runCurrent()
            testScope.testScheduler.runCurrent()
        }
        }
    }
    }


    override fun startTransition(info: TransitionInfo): UUID? {
    override fun startTransition(info: TransitionInfo): UUID? {
        Log.i("TEST", "Start transition: ", Exception())
        return if (info.animator == null) UUID.randomUUID() else null
        return if (info.animator == null) UUID.randomUUID() else null
    }
    }