Merge "Transitions: Limit how to LOCKSCREEN can be interrupted" into udc-dev

This commit is contained in:
Matt Pietal
2023-03-27 14:44:57 +00:00
committed by Android (Google) Code Review
2 changed files with 99 additions and 345 deletions

View File

@@ -59,16 +59,23 @@ constructor(
}
private fun listenForLockscreenToDreaming() {
val invalidFromStates = setOf(KeyguardState.AOD, KeyguardState.DOZING)
scope.launch {
keyguardInteractor.isAbleToDream
.sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
.collect { pair ->
val (isAbleToDream, lastStartedTransition) = pair
if (
isAbleToDream &&
lastStartedTransition.to == KeyguardState.LOCKSCREEN &&
lastStartedTransition.from != KeyguardState.AOD
) {
.sample(
combine(
keyguardTransitionInteractor.startedKeyguardTransitionStep,
keyguardTransitionInteractor.finishedKeyguardState,
::Pair
),
::toTriple
)
.collect { (isAbleToDream, lastStartedTransition, finishedKeyguardState) ->
val isOnLockscreen = finishedKeyguardState == KeyguardState.LOCKSCREEN
val isTransitionInterruptible =
lastStartedTransition.to == KeyguardState.LOCKSCREEN &&
!invalidFromStates.contains(lastStartedTransition.from)
if (isAbleToDream && (isOnLockscreen || isTransitionInterruptible)) {
keyguardTransitionRepository.startTransition(
TransitionInfo(
name,

View File

@@ -16,32 +16,31 @@
package com.android.systemui.keyguard.domain.interactor
import android.animation.ValueAnimator
import androidx.test.filters.FlakyTest
import androidx.test.filters.SmallTest
import com.android.keyguard.KeyguardSecurityModel
import com.android.keyguard.KeyguardSecurityModel.SecurityMode.PIN
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.Interpolators
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepositoryImpl
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
import com.android.systemui.keyguard.shared.model.DozeStateModel
import com.android.systemui.keyguard.shared.model.DozeTransitionModel
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionInfo
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.keyguard.shared.model.WakeSleepReason
import com.android.systemui.keyguard.shared.model.WakefulnessModel
import com.android.systemui.keyguard.shared.model.WakefulnessState
import com.android.systemui.keyguard.util.KeyguardTransitionRunner
import com.android.systemui.shade.data.repository.FakeShadeRepository
import com.android.systemui.shade.data.repository.ShadeRepository
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.mockito.withArgCaptor
import com.google.common.truth.Truth.assertThat
@@ -57,6 +56,7 @@ import org.junit.runners.JUnit4
import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@@ -67,17 +67,13 @@ import org.mockito.MockitoAnnotations
*/
@SmallTest
@RunWith(JUnit4::class)
@FlakyTest(bugId = 265303901)
class KeyguardTransitionScenariosTest : SysuiTestCase() {
private lateinit var testScope: TestScope
private lateinit var keyguardRepository: FakeKeyguardRepository
private lateinit var bouncerRepository: FakeKeyguardBouncerRepository
private lateinit var shadeRepository: ShadeRepository
// Used to issue real transition steps for test input
private lateinit var runner: KeyguardTransitionRunner
private lateinit var transitionRepository: KeyguardTransitionRepository
private lateinit var transitionRepository: FakeKeyguardTransitionRepository
// Used to verify transition requests for test output
@Mock private lateinit var mockTransitionRepository: KeyguardTransitionRepository
@@ -103,10 +99,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
keyguardRepository = FakeKeyguardRepository()
bouncerRepository = FakeKeyguardBouncerRepository()
shadeRepository = FakeShadeRepository()
/* Used to issue full transition steps, to better simulate a real device */
transitionRepository = KeyguardTransitionRepositoryImpl()
runner = KeyguardTransitionRunner(transitionRepository)
transitionRepository = FakeKeyguardTransitionRepository()
whenever(keyguardSecurityModel.getSecurityMode(anyInt())).thenReturn(PIN)
@@ -195,21 +188,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
runCurrent()
// GIVEN a prior transition has run to DREAMING
runner.startTransition(
testScope,
TransitionInfo(
ownerName = "",
from = KeyguardState.LOCKSCREEN,
to = KeyguardState.DREAMING,
animator =
ValueAnimator().apply {
duration = 10
interpolator = Interpolators.LINEAR
},
)
)
runCurrent()
reset(mockTransitionRepository)
runTransition(KeyguardState.LOCKSCREEN, KeyguardState.DREAMING)
// WHEN doze is complete
keyguardRepository.setDozeTransitionModel(
@@ -243,20 +222,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
runCurrent()
// GIVEN a prior transition has run to LOCKSCREEN
runner.startTransition(
testScope,
TransitionInfo(
ownerName = "",
from = KeyguardState.OFF,
to = KeyguardState.LOCKSCREEN,
animator =
ValueAnimator().apply {
duration = 10
interpolator = Interpolators.LINEAR
},
)
)
runCurrent()
runTransition(KeyguardState.OFF, KeyguardState.LOCKSCREEN)
// WHEN the primary bouncer is set to show
bouncerRepository.setPrimaryShow(true)
@@ -283,21 +249,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
runCurrent()
// GIVEN a prior transition has run to OCCLUDED
runner.startTransition(
testScope,
TransitionInfo(
ownerName = "",
from = KeyguardState.LOCKSCREEN,
to = KeyguardState.OCCLUDED,
animator =
ValueAnimator().apply {
duration = 10
interpolator = Interpolators.LINEAR
},
)
)
runCurrent()
reset(mockTransitionRepository)
runTransition(KeyguardState.LOCKSCREEN, KeyguardState.OCCLUDED)
// WHEN the device begins to sleep
keyguardRepository.setWakefulnessModel(startingToSleep())
@@ -324,21 +276,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
runCurrent()
// GIVEN a prior transition has run to OCCLUDED
runner.startTransition(
testScope,
TransitionInfo(
ownerName = "",
from = KeyguardState.LOCKSCREEN,
to = KeyguardState.OCCLUDED,
animator =
ValueAnimator().apply {
duration = 10
interpolator = Interpolators.LINEAR
},
)
)
runCurrent()
reset(mockTransitionRepository)
runTransition(KeyguardState.LOCKSCREEN, KeyguardState.OCCLUDED)
// WHEN the device begins to sleep
keyguardRepository.setWakefulnessModel(startingToSleep())
@@ -369,20 +307,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
runCurrent()
// GIVEN a prior transition has run to LOCKSCREEN
runner.startTransition(
testScope,
TransitionInfo(
ownerName = "",
from = KeyguardState.GONE,
to = KeyguardState.LOCKSCREEN,
animator =
ValueAnimator().apply {
duration = 10
interpolator = Interpolators.LINEAR
},
)
)
reset(mockTransitionRepository)
runTransition(KeyguardState.GONE, KeyguardState.LOCKSCREEN)
// WHEN the device begins to dream
keyguardRepository.setDreamingWithOverlay(true)
@@ -409,21 +334,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
runCurrent()
// GIVEN a prior transition has run to LOCKSCREEN
runner.startTransition(
testScope,
TransitionInfo(
ownerName = "",
from = KeyguardState.GONE,
to = KeyguardState.LOCKSCREEN,
animator =
ValueAnimator().apply {
duration = 10
interpolator = Interpolators.LINEAR
},
)
)
runCurrent()
reset(mockTransitionRepository)
runTransition(KeyguardState.GONE, KeyguardState.LOCKSCREEN)
// WHEN the device begins to sleep
keyguardRepository.setWakefulnessModel(startingToSleep())
@@ -450,21 +361,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
runCurrent()
// GIVEN a prior transition has run to LOCKSCREEN
runner.startTransition(
testScope,
TransitionInfo(
ownerName = "",
from = KeyguardState.GONE,
to = KeyguardState.LOCKSCREEN,
animator =
ValueAnimator().apply {
duration = 10
interpolator = Interpolators.LINEAR
},
)
)
runCurrent()
reset(mockTransitionRepository)
runTransition(KeyguardState.GONE, KeyguardState.LOCKSCREEN)
// WHEN the device begins to sleep
keyguardRepository.setWakefulnessModel(startingToSleep())
@@ -487,21 +384,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
fun `DOZING to LOCKSCREEN`() =
testScope.runTest {
// GIVEN a prior transition has run to DOZING
runner.startTransition(
testScope,
TransitionInfo(
ownerName = "",
from = KeyguardState.LOCKSCREEN,
to = KeyguardState.DOZING,
animator =
ValueAnimator().apply {
duration = 10
interpolator = Interpolators.LINEAR
},
)
)
runCurrent()
reset(mockTransitionRepository)
runTransition(KeyguardState.LOCKSCREEN, KeyguardState.DOZING)
// WHEN the device begins to wake
keyguardRepository.setWakefulnessModel(startingToWake())
@@ -521,25 +404,37 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
}
@Test
fun `DOZING to GONE`() =
fun `DOZING to LOCKSCREEN cannot be interruped by DREAMING`() =
testScope.runTest {
// GIVEN a prior transition has run to DOZING
runner.startTransition(
testScope,
TransitionInfo(
ownerName = "",
from = KeyguardState.LOCKSCREEN,
to = KeyguardState.DOZING,
animator =
ValueAnimator().apply {
duration = 10
interpolator = Interpolators.LINEAR
},
// GIVEN a prior transition has started to LOCKSCREEN
transitionRepository.sendTransitionStep(
TransitionStep(
from = KeyguardState.DOZING,
to = KeyguardState.LOCKSCREEN,
value = 0.5f,
transitionState = TransitionState.RUNNING,
ownerName = "KeyguardTransitionScenariosTest",
)
)
runCurrent()
reset(mockTransitionRepository)
// WHEN a signal comes that dreaming is enabled
keyguardRepository.setDreamingWithOverlay(true)
advanceUntilIdle()
// THEN the transition is ignored
verify(mockTransitionRepository, never()).startTransition(any(), anyBoolean())
coroutineContext.cancelChildren()
}
@Test
fun `DOZING to GONE`() =
testScope.runTest {
// GIVEN a prior transition has run to DOZING
runTransition(KeyguardState.LOCKSCREEN, KeyguardState.DOZING)
// WHEN biometrics succeeds with wake and unlock mode
keyguardRepository.setBiometricUnlockState(BiometricUnlockModel.WAKE_AND_UNLOCK)
runCurrent()
@@ -565,21 +460,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
runCurrent()
// GIVEN a prior transition has run to GONE
runner.startTransition(
testScope,
TransitionInfo(
ownerName = "",
from = KeyguardState.LOCKSCREEN,
to = KeyguardState.GONE,
animator =
ValueAnimator().apply {
duration = 10
interpolator = Interpolators.LINEAR
},
)
)
runCurrent()
reset(mockTransitionRepository)
runTransition(KeyguardState.LOCKSCREEN, KeyguardState.GONE)
// WHEN the device begins to sleep
keyguardRepository.setWakefulnessModel(startingToSleep())
@@ -606,21 +487,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
runCurrent()
// GIVEN a prior transition has run to GONE
runner.startTransition(
testScope,
TransitionInfo(
ownerName = "",
from = KeyguardState.LOCKSCREEN,
to = KeyguardState.GONE,
animator =
ValueAnimator().apply {
duration = 10
interpolator = Interpolators.LINEAR
},
)
)
runCurrent()
reset(mockTransitionRepository)
runTransition(KeyguardState.LOCKSCREEN, KeyguardState.GONE)
// WHEN the device begins to sleep
keyguardRepository.setWakefulnessModel(startingToSleep())
@@ -643,21 +510,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
fun `GONE to LOCKSREEN`() =
testScope.runTest {
// GIVEN a prior transition has run to GONE
runner.startTransition(
testScope,
TransitionInfo(
ownerName = "",
from = KeyguardState.LOCKSCREEN,
to = KeyguardState.GONE,
animator =
ValueAnimator().apply {
duration = 10
interpolator = Interpolators.LINEAR
},
)
)
runCurrent()
reset(mockTransitionRepository)
runTransition(KeyguardState.LOCKSCREEN, KeyguardState.GONE)
// WHEN the keyguard starts to show
keyguardRepository.setKeyguardShowing(true)
@@ -688,20 +541,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
runCurrent()
// GIVEN a prior transition has run to GONE
runner.startTransition(
testScope,
TransitionInfo(
ownerName = "",
from = KeyguardState.LOCKSCREEN,
to = KeyguardState.GONE,
animator =
ValueAnimator().apply {
duration = 10
interpolator = Interpolators.LINEAR
},
)
)
reset(mockTransitionRepository)
runTransition(KeyguardState.LOCKSCREEN, KeyguardState.GONE)
// WHEN the device begins to dream
keyguardRepository.setDreamingWithOverlay(true)
@@ -724,21 +564,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
fun `ALTERNATE_BOUNCER to PRIMARY_BOUNCER`() =
testScope.runTest {
// GIVEN a prior transition has run to ALTERNATE_BOUNCER
runner.startTransition(
testScope,
TransitionInfo(
ownerName = "",
from = KeyguardState.LOCKSCREEN,
to = KeyguardState.ALTERNATE_BOUNCER,
animator =
ValueAnimator().apply {
duration = 10
interpolator = Interpolators.LINEAR
},
)
)
runCurrent()
reset(mockTransitionRepository)
runTransition(KeyguardState.LOCKSCREEN, KeyguardState.ALTERNATE_BOUNCER)
// WHEN the alternateBouncer stops showing and then the primary bouncer shows
bouncerRepository.setPrimaryShow(true)
@@ -762,21 +588,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
testScope.runTest {
// GIVEN a prior transition has run to ALTERNATE_BOUNCER
bouncerRepository.setAlternateVisible(true)
runner.startTransition(
testScope,
TransitionInfo(
ownerName = "",
from = KeyguardState.LOCKSCREEN,
to = KeyguardState.ALTERNATE_BOUNCER,
animator =
ValueAnimator().apply {
duration = 10
interpolator = Interpolators.LINEAR
},
)
)
runCurrent()
reset(mockTransitionRepository)
runTransition(KeyguardState.LOCKSCREEN, KeyguardState.ALTERNATE_BOUNCER)
// GIVEN the primary bouncer isn't showing, aod available and starting to sleep
bouncerRepository.setPrimaryShow(false)
@@ -805,21 +617,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
testScope.runTest {
// GIVEN a prior transition has run to ALTERNATE_BOUNCER
bouncerRepository.setAlternateVisible(true)
runner.startTransition(
testScope,
TransitionInfo(
ownerName = "",
from = KeyguardState.LOCKSCREEN,
to = KeyguardState.ALTERNATE_BOUNCER,
animator =
ValueAnimator().apply {
duration = 10
interpolator = Interpolators.LINEAR
},
)
)
runCurrent()
reset(mockTransitionRepository)
runTransition(KeyguardState.LOCKSCREEN, KeyguardState.ALTERNATE_BOUNCER)
// GIVEN the primary bouncer isn't showing, aod not available and starting to sleep
// to sleep
@@ -849,21 +647,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
testScope.runTest {
// GIVEN a prior transition has run to ALTERNATE_BOUNCER
bouncerRepository.setAlternateVisible(true)
runner.startTransition(
testScope,
TransitionInfo(
ownerName = "",
from = KeyguardState.LOCKSCREEN,
to = KeyguardState.ALTERNATE_BOUNCER,
animator =
ValueAnimator().apply {
duration = 10
interpolator = Interpolators.LINEAR
},
)
)
runCurrent()
reset(mockTransitionRepository)
runTransition(KeyguardState.LOCKSCREEN, KeyguardState.ALTERNATE_BOUNCER)
// GIVEN the primary bouncer isn't showing and device not sleeping
bouncerRepository.setPrimaryShow(false)
@@ -891,21 +675,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
testScope.runTest {
// GIVEN a prior transition has run to PRIMARY_BOUNCER
bouncerRepository.setPrimaryShow(true)
runner.startTransition(
testScope,
TransitionInfo(
ownerName = "",
from = KeyguardState.LOCKSCREEN,
to = KeyguardState.PRIMARY_BOUNCER,
animator =
ValueAnimator().apply {
duration = 10
interpolator = Interpolators.LINEAR
},
)
)
runCurrent()
reset(mockTransitionRepository)
runTransition(KeyguardState.LOCKSCREEN, KeyguardState.PRIMARY_BOUNCER)
// GIVEN aod available and starting to sleep
keyguardRepository.setAodAvailable(true)
@@ -933,21 +703,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
testScope.runTest {
// GIVEN a prior transition has run to PRIMARY_BOUNCER
bouncerRepository.setPrimaryShow(true)
runner.startTransition(
testScope,
TransitionInfo(
ownerName = "",
from = KeyguardState.LOCKSCREEN,
to = KeyguardState.PRIMARY_BOUNCER,
animator =
ValueAnimator().apply {
duration = 10
interpolator = Interpolators.LINEAR
},
)
)
runCurrent()
reset(mockTransitionRepository)
runTransition(KeyguardState.LOCKSCREEN, KeyguardState.PRIMARY_BOUNCER)
// GIVEN aod not available and starting to sleep to sleep
keyguardRepository.setAodAvailable(false)
@@ -975,21 +731,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
testScope.runTest {
// GIVEN a prior transition has run to PRIMARY_BOUNCER
bouncerRepository.setPrimaryShow(true)
runner.startTransition(
testScope,
TransitionInfo(
ownerName = "",
from = KeyguardState.LOCKSCREEN,
to = KeyguardState.PRIMARY_BOUNCER,
animator =
ValueAnimator().apply {
duration = 10
interpolator = Interpolators.LINEAR
},
)
)
runCurrent()
reset(mockTransitionRepository)
runTransition(KeyguardState.LOCKSCREEN, KeyguardState.PRIMARY_BOUNCER)
// GIVEN device not sleeping
keyguardRepository.setWakefulnessModel(startingToWake())
@@ -1019,22 +761,9 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
runCurrent()
// GIVEN a prior transition has run to OCCLUDED
runner.startTransition(
testScope,
TransitionInfo(
ownerName = "",
from = KeyguardState.LOCKSCREEN,
to = KeyguardState.OCCLUDED,
animator =
ValueAnimator().apply {
duration = 10
interpolator = Interpolators.LINEAR
},
)
)
runTransition(KeyguardState.LOCKSCREEN, KeyguardState.OCCLUDED)
keyguardRepository.setKeyguardOccluded(true)
runCurrent()
reset(mockTransitionRepository)
// WHEN keyguard goes away
keyguardRepository.setKeyguardShowing(false)
@@ -1063,22 +792,9 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
runCurrent()
// GIVEN a prior transition has run to OCCLUDED
runner.startTransition(
testScope,
TransitionInfo(
ownerName = "",
from = KeyguardState.LOCKSCREEN,
to = KeyguardState.OCCLUDED,
animator =
ValueAnimator().apply {
duration = 10
interpolator = Interpolators.LINEAR
},
)
)
runTransition(KeyguardState.LOCKSCREEN, KeyguardState.OCCLUDED)
keyguardRepository.setKeyguardOccluded(true)
runCurrent()
reset(mockTransitionRepository)
// WHEN occlusion ends
keyguardRepository.setKeyguardOccluded(false)
@@ -1121,4 +837,35 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
bouncerRepository,
)
}
private suspend fun TestScope.runTransition(from: KeyguardState, to: KeyguardState) {
transitionRepository.sendTransitionStep(
TransitionStep(
from = from,
to = to,
value = 0f,
transitionState = TransitionState.STARTED,
)
)
runCurrent()
transitionRepository.sendTransitionStep(
TransitionStep(
from = from,
to = to,
value = 0.5f,
transitionState = TransitionState.RUNNING,
)
)
runCurrent()
transitionRepository.sendTransitionStep(
TransitionStep(
from = from,
to = to,
value = 1f,
transitionState = TransitionState.FINISHED,
)
)
runCurrent()
reset(mockTransitionRepository)
}
}