Loading packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractorTest.kt +1 −1 Original line number Diff line number Diff line Loading @@ -81,7 +81,7 @@ class FromDreamingTransitionInteractorTest(flags: FlagsParameterization?) : Sysu this.fakeKeyguardTransitionRepository = FakeKeyguardTransitionRepository( // This test sends transition steps manually in the test cases. sendTransitionStepsOnStartTransition = false, initiallySendTransitionStepsOnStartTransition = false, testScope = testScope, ) Loading packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorTest.kt +77 −5 Original line number Diff line number Diff line Loading @@ -27,15 +27,13 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectValues import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepositorySpy import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository import com.android.systemui.keyguard.data.repository.keyguardOcclusionRepository import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.StatusBarState import com.android.systemui.keyguard.shared.model.StatusBarState.KEYGUARD import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.keyguard.util.KeyguardTransitionRepositorySpySubject.Companion.assertThat as assertThatRepository import com.android.systemui.kosmos.testScope import com.android.systemui.shade.data.repository.FlingInfo import com.android.systemui.shade.data.repository.fakeShadeRepository Loading @@ -48,6 +46,8 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mockito.reset import org.mockito.Mockito.spy import com.android.systemui.keyguard.util.KeyguardTransitionRepositorySpySubject.Companion.assertThat as assertThatRepository @OptIn(ExperimentalCoroutinesApi::class) @SmallTest Loading @@ -55,7 +55,9 @@ import org.mockito.Mockito.reset class FromLockscreenTransitionInteractorTest : SysuiTestCase() { private val kosmos = testKosmos().apply { this.keyguardTransitionRepository = fakeKeyguardTransitionRepositorySpy this.fakeKeyguardTransitionRepository = spy(FakeKeyguardTransitionRepository( testScope = testScope, )) } private val testScope = kosmos.testScope Loading @@ -66,7 +68,7 @@ class FromLockscreenTransitionInteractorTest : SysuiTestCase() { @Before fun setup() { transitionRepository = kosmos.fakeKeyguardTransitionRepositorySpy transitionRepository = kosmos.fakeKeyguardTransitionRepository } @Test Loading Loading @@ -302,4 +304,74 @@ class FromLockscreenTransitionInteractorTest : SysuiTestCase() { to = KeyguardState.LOCKSCREEN, ) } /** * External signals can cause us to transition from PRIMARY_BOUNCER -> * while a manual * transition is in progress. This test was added after a bug that caused the manual transition * ID to get stuck in this scenario, preventing subsequent transitions to PRIMARY_BOUNCER. */ @Test fun testExternalTransitionAwayFromBouncer_transitionIdNotStuck() = testScope.runTest { underTest.start() keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD) keyguardRepository.setKeyguardDismissible(false) shadeRepository.setLegacyShadeTracking(true) keyguardRepository.setKeyguardOccluded(false) runCurrent() reset(transitionRepository) // Disable automatic sending of transition steps so we can send steps through RUNNING // to simulate a cancellation. transitionRepository.sendTransitionStepsOnStartTransition = false shadeRepository.setLegacyShadeExpansion(0.5f) runCurrent() assertThatRepository(transitionRepository) .startedTransition( from = KeyguardState.LOCKSCREEN, to = KeyguardState.PRIMARY_BOUNCER, ) // Partially transition to PRIMARY_BOUNCER. transitionRepository.sendTransitionSteps( from = KeyguardState.LOCKSCREEN, to = KeyguardState.PRIMARY_BOUNCER, throughTransitionState = TransitionState.RUNNING, testScope = testScope, ) // Start a transition to GONE, which will cancel LS -> BOUNCER. transitionRepository.sendTransitionSteps( from = KeyguardState.PRIMARY_BOUNCER, to = KeyguardState.GONE, testScope = testScope, ) // Go to AOD, then LOCKSCREEN. transitionRepository.sendTransitionSteps( from = KeyguardState.GONE, to = KeyguardState.AOD, testScope = testScope, ) transitionRepository.sendTransitionSteps( from = KeyguardState.AOD, to = KeyguardState.LOCKSCREEN, testScope = testScope, ) reset(transitionRepository) // Start a swipe up to the bouncer, and verify that we started a transition to // PRIMARY_BOUNCER, verifying the transition ID did not get stuck. shadeRepository.setLegacyShadeExpansion(0.25f) runCurrent() assertThatRepository(transitionRepository) .startedTransition( from = KeyguardState.LOCKSCREEN, to = KeyguardState.PRIMARY_BOUNCER, ) } } packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt +19 −5 Original line number Diff line number Diff line Loading @@ -19,7 +19,6 @@ package com.android.systemui.keyguard.domain.interactor import android.animation.ValueAnimator import android.util.MathUtils import com.android.app.animation.Interpolators import com.android.app.tracing.coroutines.launchTraced as launch import com.android.systemui.Flags.communalSceneKtfRefactor import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor import com.android.systemui.dagger.SysUISingleton Loading @@ -40,17 +39,19 @@ import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.shade.data.repository.ShadeRepository import com.android.systemui.util.kotlin.sample import java.util.UUID import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.seconds import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onStart import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.seconds import java.util.UUID import javax.inject.Inject import com.android.app.tracing.coroutines.launchTraced as launch @SysUISingleton class FromLockscreenTransitionInteractor Loading Loading @@ -258,6 +259,19 @@ constructor( } } } // Ensure that transitionId is nulled out if external signals cause a PRIMARY_BOUNCER // transition to be canceled. scope.launch { transitionInteractor.transitions .filter { it.transitionState == TransitionState.CANCELED && it.to == KeyguardState.PRIMARY_BOUNCER } .collect { transitionId = null } } } fun dismissKeyguard() { Loading packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt +30 −5 Original line number Diff line number Diff line Loading @@ -52,6 +52,15 @@ import kotlinx.coroutines.test.runCurrent class FakeKeyguardTransitionRepository( private val initInLockscreen: Boolean = true, /** * Initial value for [FakeKeyguardTransitionRepository.sendTransitionStepsOnStartTransition]. * This needs to be configurable in the constructor since some transitions are triggered on * init, before a test has the chance to set sendTransitionStepsOnStartTransition to false. */ private val initiallySendTransitionStepsOnStartTransition: Boolean = true, private val testScope: TestScope, ) : KeyguardTransitionRepository { /** * If true, calls to [startTransition] will automatically emit STARTED, RUNNING, and FINISHED * transition steps from/to the given states. Loading @@ -64,11 +73,9 @@ class FakeKeyguardTransitionRepository( * * If your test needs to make assertions at specific points between STARTED/FINISHED, or if it's * difficult to set up all of the conditions to make the transition interactors actually call * startTransition, then construct a FakeKeyguardTransitionRepository with this value false. * startTransition, set this value to false. */ private val sendTransitionStepsOnStartTransition: Boolean = true, private val testScope: TestScope, ) : KeyguardTransitionRepository { var sendTransitionStepsOnStartTransition = initiallySendTransitionStepsOnStartTransition private val _transitions = MutableSharedFlow<TransitionStep>(replay = 3, onBufferOverflow = BufferOverflow.DROP_OLDEST) Loading @@ -77,7 +84,11 @@ class FakeKeyguardTransitionRepository( @Inject constructor( testScope: TestScope ) : this(initInLockscreen = true, sendTransitionStepsOnStartTransition = true, testScope) ) : this( initInLockscreen = true, initiallySendTransitionStepsOnStartTransition = true, testScope ) private val _currentTransitionInfo: MutableStateFlow<TransitionInfo> = MutableStateFlow( Loading Loading @@ -176,6 +187,20 @@ class FakeKeyguardTransitionRepository( testScheduler: TestCoroutineScheduler, throughTransitionState: TransitionState = TransitionState.FINISHED, ) { val lastStep = _transitions.replayCache.lastOrNull() if (lastStep != null && lastStep.transitionState != TransitionState.FINISHED) { sendTransitionStep( step = TransitionStep( transitionState = TransitionState.CANCELED, from = lastStep.from, to = lastStep.to, value = 0f, ) ) testScheduler.runCurrent() } sendTransitionStep( step = TransitionStep( Loading Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractorTest.kt +1 −1 Original line number Diff line number Diff line Loading @@ -81,7 +81,7 @@ class FromDreamingTransitionInteractorTest(flags: FlagsParameterization?) : Sysu this.fakeKeyguardTransitionRepository = FakeKeyguardTransitionRepository( // This test sends transition steps manually in the test cases. sendTransitionStepsOnStartTransition = false, initiallySendTransitionStepsOnStartTransition = false, testScope = testScope, ) Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorTest.kt +77 −5 Original line number Diff line number Diff line Loading @@ -27,15 +27,13 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectValues import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepositorySpy import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository import com.android.systemui.keyguard.data.repository.keyguardOcclusionRepository import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.StatusBarState import com.android.systemui.keyguard.shared.model.StatusBarState.KEYGUARD import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.keyguard.util.KeyguardTransitionRepositorySpySubject.Companion.assertThat as assertThatRepository import com.android.systemui.kosmos.testScope import com.android.systemui.shade.data.repository.FlingInfo import com.android.systemui.shade.data.repository.fakeShadeRepository Loading @@ -48,6 +46,8 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mockito.reset import org.mockito.Mockito.spy import com.android.systemui.keyguard.util.KeyguardTransitionRepositorySpySubject.Companion.assertThat as assertThatRepository @OptIn(ExperimentalCoroutinesApi::class) @SmallTest Loading @@ -55,7 +55,9 @@ import org.mockito.Mockito.reset class FromLockscreenTransitionInteractorTest : SysuiTestCase() { private val kosmos = testKosmos().apply { this.keyguardTransitionRepository = fakeKeyguardTransitionRepositorySpy this.fakeKeyguardTransitionRepository = spy(FakeKeyguardTransitionRepository( testScope = testScope, )) } private val testScope = kosmos.testScope Loading @@ -66,7 +68,7 @@ class FromLockscreenTransitionInteractorTest : SysuiTestCase() { @Before fun setup() { transitionRepository = kosmos.fakeKeyguardTransitionRepositorySpy transitionRepository = kosmos.fakeKeyguardTransitionRepository } @Test Loading Loading @@ -302,4 +304,74 @@ class FromLockscreenTransitionInteractorTest : SysuiTestCase() { to = KeyguardState.LOCKSCREEN, ) } /** * External signals can cause us to transition from PRIMARY_BOUNCER -> * while a manual * transition is in progress. This test was added after a bug that caused the manual transition * ID to get stuck in this scenario, preventing subsequent transitions to PRIMARY_BOUNCER. */ @Test fun testExternalTransitionAwayFromBouncer_transitionIdNotStuck() = testScope.runTest { underTest.start() keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD) keyguardRepository.setKeyguardDismissible(false) shadeRepository.setLegacyShadeTracking(true) keyguardRepository.setKeyguardOccluded(false) runCurrent() reset(transitionRepository) // Disable automatic sending of transition steps so we can send steps through RUNNING // to simulate a cancellation. transitionRepository.sendTransitionStepsOnStartTransition = false shadeRepository.setLegacyShadeExpansion(0.5f) runCurrent() assertThatRepository(transitionRepository) .startedTransition( from = KeyguardState.LOCKSCREEN, to = KeyguardState.PRIMARY_BOUNCER, ) // Partially transition to PRIMARY_BOUNCER. transitionRepository.sendTransitionSteps( from = KeyguardState.LOCKSCREEN, to = KeyguardState.PRIMARY_BOUNCER, throughTransitionState = TransitionState.RUNNING, testScope = testScope, ) // Start a transition to GONE, which will cancel LS -> BOUNCER. transitionRepository.sendTransitionSteps( from = KeyguardState.PRIMARY_BOUNCER, to = KeyguardState.GONE, testScope = testScope, ) // Go to AOD, then LOCKSCREEN. transitionRepository.sendTransitionSteps( from = KeyguardState.GONE, to = KeyguardState.AOD, testScope = testScope, ) transitionRepository.sendTransitionSteps( from = KeyguardState.AOD, to = KeyguardState.LOCKSCREEN, testScope = testScope, ) reset(transitionRepository) // Start a swipe up to the bouncer, and verify that we started a transition to // PRIMARY_BOUNCER, verifying the transition ID did not get stuck. shadeRepository.setLegacyShadeExpansion(0.25f) runCurrent() assertThatRepository(transitionRepository) .startedTransition( from = KeyguardState.LOCKSCREEN, to = KeyguardState.PRIMARY_BOUNCER, ) } }
packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt +19 −5 Original line number Diff line number Diff line Loading @@ -19,7 +19,6 @@ package com.android.systemui.keyguard.domain.interactor import android.animation.ValueAnimator import android.util.MathUtils import com.android.app.animation.Interpolators import com.android.app.tracing.coroutines.launchTraced as launch import com.android.systemui.Flags.communalSceneKtfRefactor import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor import com.android.systemui.dagger.SysUISingleton Loading @@ -40,17 +39,19 @@ import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.shade.data.repository.ShadeRepository import com.android.systemui.util.kotlin.sample import java.util.UUID import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.seconds import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onStart import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.seconds import java.util.UUID import javax.inject.Inject import com.android.app.tracing.coroutines.launchTraced as launch @SysUISingleton class FromLockscreenTransitionInteractor Loading Loading @@ -258,6 +259,19 @@ constructor( } } } // Ensure that transitionId is nulled out if external signals cause a PRIMARY_BOUNCER // transition to be canceled. scope.launch { transitionInteractor.transitions .filter { it.transitionState == TransitionState.CANCELED && it.to == KeyguardState.PRIMARY_BOUNCER } .collect { transitionId = null } } } fun dismissKeyguard() { Loading
packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt +30 −5 Original line number Diff line number Diff line Loading @@ -52,6 +52,15 @@ import kotlinx.coroutines.test.runCurrent class FakeKeyguardTransitionRepository( private val initInLockscreen: Boolean = true, /** * Initial value for [FakeKeyguardTransitionRepository.sendTransitionStepsOnStartTransition]. * This needs to be configurable in the constructor since some transitions are triggered on * init, before a test has the chance to set sendTransitionStepsOnStartTransition to false. */ private val initiallySendTransitionStepsOnStartTransition: Boolean = true, private val testScope: TestScope, ) : KeyguardTransitionRepository { /** * If true, calls to [startTransition] will automatically emit STARTED, RUNNING, and FINISHED * transition steps from/to the given states. Loading @@ -64,11 +73,9 @@ class FakeKeyguardTransitionRepository( * * If your test needs to make assertions at specific points between STARTED/FINISHED, or if it's * difficult to set up all of the conditions to make the transition interactors actually call * startTransition, then construct a FakeKeyguardTransitionRepository with this value false. * startTransition, set this value to false. */ private val sendTransitionStepsOnStartTransition: Boolean = true, private val testScope: TestScope, ) : KeyguardTransitionRepository { var sendTransitionStepsOnStartTransition = initiallySendTransitionStepsOnStartTransition private val _transitions = MutableSharedFlow<TransitionStep>(replay = 3, onBufferOverflow = BufferOverflow.DROP_OLDEST) Loading @@ -77,7 +84,11 @@ class FakeKeyguardTransitionRepository( @Inject constructor( testScope: TestScope ) : this(initInLockscreen = true, sendTransitionStepsOnStartTransition = true, testScope) ) : this( initInLockscreen = true, initiallySendTransitionStepsOnStartTransition = true, testScope ) private val _currentTransitionInfo: MutableStateFlow<TransitionInfo> = MutableStateFlow( Loading Loading @@ -176,6 +187,20 @@ class FakeKeyguardTransitionRepository( testScheduler: TestCoroutineScheduler, throughTransitionState: TransitionState = TransitionState.FINISHED, ) { val lastStep = _transitions.replayCache.lastOrNull() if (lastStep != null && lastStep.transitionState != TransitionState.FINISHED) { sendTransitionStep( step = TransitionStep( transitionState = TransitionState.CANCELED, from = lastStep.from, to = lastStep.to, value = 0f, ) ) testScheduler.runCurrent() } sendTransitionStep( step = TransitionStep( Loading