Loading packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt +57 −0 Original line number Diff line number Diff line Loading @@ -269,6 +269,54 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() { 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 fun isInTransitionToAnyState() = testScope.runTest { Loading @@ -276,6 +324,7 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() { assertEquals( listOf( false, true, // The repo is seeded with a transition from OFF to LOCKSCREEN. false, ), Loading @@ -288,6 +337,7 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() { assertEquals( listOf( false, true, false, true, Loading @@ -301,6 +351,7 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() { assertEquals( listOf( false, true, false, true, Loading @@ -314,6 +365,7 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() { assertEquals( listOf( false, true, false, true, Loading @@ -330,6 +382,7 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() { assertEquals( listOf( false, true, false, ), Loading @@ -345,6 +398,7 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() { assertEquals( listOf( false, true, false, true, Loading @@ -359,6 +413,7 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() { assertEquals( listOf( false, true, false, true, Loading @@ -379,6 +434,7 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() { assertEquals( listOf( false, true, false, true, Loading @@ -398,6 +454,7 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() { assertEquals( listOf( false, true, false, true, Loading packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt +27 −18 Original line number Diff line number Diff line Loading @@ -119,24 +119,7 @@ class KeyguardTransitionRepositoryImpl @Inject constructor() : KeyguardTransitio init { // Seed with transitions signaling a boot into lockscreen state. If updating this, please // also update FakeKeyguardTransitionRepository. emitTransition( TransitionStep( KeyguardState.OFF, KeyguardState.LOCKSCREEN, 0f, TransitionState.STARTED, KeyguardTransitionRepositoryImpl::class.simpleName!!, ) ) emitTransition( TransitionStep( KeyguardState.OFF, KeyguardState.LOCKSCREEN, 1f, TransitionState.FINISHED, KeyguardTransitionRepositoryImpl::class.simpleName!!, ) ) initialTransitionSteps.forEach(::emitTransition) } override fun startTransition(info: TransitionInfo): UUID? { Loading Loading @@ -256,5 +239,31 @@ class KeyguardTransitionRepositoryImpl @Inject constructor() : KeyguardTransitio companion object { 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, ), ) } } packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt +38 −20 Original line number Diff line number Diff line Loading @@ -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 { // Collect non-canceled steps and emit transition values. 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.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 */ Loading Loading @@ -202,8 +237,6 @@ constructor( val dozingToLockscreenTransition: Flow<TransitionStep> = repository.transition(DOZING, LOCKSCREEN) val transitions = repository.transitions /** Receive all [TransitionStep] matching a filter of [from]->[to] */ fun transition(from: KeyguardState, to: KeyguardState): Flow<TransitionStep> { return repository.transition(from, to) Loading Loading @@ -249,21 +282,6 @@ constructor( .map { aodAvailable -> if (aodAvailable) AOD else 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. * Loading packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt +4 −19 Original line number Diff line number Diff line Loading @@ -18,7 +18,6 @@ package com.android.systemui.keyguard.data.repository import android.annotation.FloatRange import android.util.Log import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionInfo Loading Loading @@ -48,21 +47,8 @@ class FakeKeyguardTransitionRepository @Inject constructor() : KeyguardTransitio override val transitions: SharedFlow<TransitionStep> = _transitions init { _transitions.tryEmit( TransitionStep( transitionState = TransitionState.STARTED, from = KeyguardState.OFF, to = KeyguardState.LOCKSCREEN, ) ) _transitions.tryEmit( TransitionStep( transitionState = TransitionState.FINISHED, from = KeyguardState.OFF, to = KeyguardState.LOCKSCREEN, ) ) // Seed the fake repository with the same initial steps the actual repository uses. KeyguardTransitionRepositoryImpl.initialTransitionSteps.forEach { _transitions.tryEmit(it) } } /** Loading Loading @@ -207,16 +193,15 @@ class FakeKeyguardTransitionRepository @Inject constructor() : KeyguardTransitio suspend fun sendTransitionSteps( steps: List<TransitionStep>, testScope: TestScope, validateStep: Boolean = true validateSteps: Boolean = true ) { steps.forEach { sendTransitionStep(step = it, validateStep = validateStep) sendTransitionStep(step = it, validateStep = validateSteps) testScope.testScheduler.runCurrent() } } override fun startTransition(info: TransitionInfo): UUID? { Log.i("TEST", "Start transition: ", Exception()) return if (info.animator == null) UUID.randomUUID() else null } Loading Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt +57 −0 Original line number Diff line number Diff line Loading @@ -269,6 +269,54 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() { 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 fun isInTransitionToAnyState() = testScope.runTest { Loading @@ -276,6 +324,7 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() { assertEquals( listOf( false, true, // The repo is seeded with a transition from OFF to LOCKSCREEN. false, ), Loading @@ -288,6 +337,7 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() { assertEquals( listOf( false, true, false, true, Loading @@ -301,6 +351,7 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() { assertEquals( listOf( false, true, false, true, Loading @@ -314,6 +365,7 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() { assertEquals( listOf( false, true, false, true, Loading @@ -330,6 +382,7 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() { assertEquals( listOf( false, true, false, ), Loading @@ -345,6 +398,7 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() { assertEquals( listOf( false, true, false, true, Loading @@ -359,6 +413,7 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() { assertEquals( listOf( false, true, false, true, Loading @@ -379,6 +434,7 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() { assertEquals( listOf( false, true, false, true, Loading @@ -398,6 +454,7 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() { assertEquals( listOf( false, true, false, true, Loading
packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt +27 −18 Original line number Diff line number Diff line Loading @@ -119,24 +119,7 @@ class KeyguardTransitionRepositoryImpl @Inject constructor() : KeyguardTransitio init { // Seed with transitions signaling a boot into lockscreen state. If updating this, please // also update FakeKeyguardTransitionRepository. emitTransition( TransitionStep( KeyguardState.OFF, KeyguardState.LOCKSCREEN, 0f, TransitionState.STARTED, KeyguardTransitionRepositoryImpl::class.simpleName!!, ) ) emitTransition( TransitionStep( KeyguardState.OFF, KeyguardState.LOCKSCREEN, 1f, TransitionState.FINISHED, KeyguardTransitionRepositoryImpl::class.simpleName!!, ) ) initialTransitionSteps.forEach(::emitTransition) } override fun startTransition(info: TransitionInfo): UUID? { Loading Loading @@ -256,5 +239,31 @@ class KeyguardTransitionRepositoryImpl @Inject constructor() : KeyguardTransitio companion object { 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, ), ) } }
packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt +38 −20 Original line number Diff line number Diff line Loading @@ -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 { // Collect non-canceled steps and emit transition values. 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.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 */ Loading Loading @@ -202,8 +237,6 @@ constructor( val dozingToLockscreenTransition: Flow<TransitionStep> = repository.transition(DOZING, LOCKSCREEN) val transitions = repository.transitions /** Receive all [TransitionStep] matching a filter of [from]->[to] */ fun transition(from: KeyguardState, to: KeyguardState): Flow<TransitionStep> { return repository.transition(from, to) Loading Loading @@ -249,21 +282,6 @@ constructor( .map { aodAvailable -> if (aodAvailable) AOD else 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. * Loading
packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt +4 −19 Original line number Diff line number Diff line Loading @@ -18,7 +18,6 @@ package com.android.systemui.keyguard.data.repository import android.annotation.FloatRange import android.util.Log import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionInfo Loading Loading @@ -48,21 +47,8 @@ class FakeKeyguardTransitionRepository @Inject constructor() : KeyguardTransitio override val transitions: SharedFlow<TransitionStep> = _transitions init { _transitions.tryEmit( TransitionStep( transitionState = TransitionState.STARTED, from = KeyguardState.OFF, to = KeyguardState.LOCKSCREEN, ) ) _transitions.tryEmit( TransitionStep( transitionState = TransitionState.FINISHED, from = KeyguardState.OFF, to = KeyguardState.LOCKSCREEN, ) ) // Seed the fake repository with the same initial steps the actual repository uses. KeyguardTransitionRepositoryImpl.initialTransitionSteps.forEach { _transitions.tryEmit(it) } } /** Loading Loading @@ -207,16 +193,15 @@ class FakeKeyguardTransitionRepository @Inject constructor() : KeyguardTransitio suspend fun sendTransitionSteps( steps: List<TransitionStep>, testScope: TestScope, validateStep: Boolean = true validateSteps: Boolean = true ) { steps.forEach { sendTransitionStep(step = it, validateStep = validateStep) sendTransitionStep(step = it, validateStep = validateSteps) testScope.testScheduler.runCurrent() } } override fun startTransition(info: TransitionInfo): UUID? { Log.i("TEST", "Start transition: ", Exception()) return if (info.animator == null) UUID.randomUUID() else null } Loading