diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt index 3b09ae7ba8ea5..7134ec0d64f01 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt @@ -21,7 +21,7 @@ import com.android.systemui.animation.Interpolators import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository -import com.android.systemui.keyguard.shared.model.BiometricUnlockModel.Companion.isWakeAndUnlock +import com.android.systemui.keyguard.shared.model.BiometricUnlockModel import com.android.systemui.keyguard.shared.model.DozeStateModel import com.android.systemui.keyguard.shared.model.DozeStateModel.Companion.isDozeOff import com.android.systemui.keyguard.shared.model.KeyguardState @@ -56,7 +56,7 @@ constructor( scope.launch { // Using isDreamingWithOverlay provides an optimized path to LOCKSCREEN state, which // otherwise would have gone through OCCLUDED first - keyguardInteractor.isDreamingWithOverlay + keyguardInteractor.isAbleToDream .sample( combine( keyguardInteractor.dozeTransitionModel, @@ -65,8 +65,7 @@ constructor( ), ::toTriple ) - .collect { triple -> - val (isDreaming, dozeTransitionModel, lastStartedTransition) = triple + .collect { (isDreaming, dozeTransitionModel, lastStartedTransition) -> if ( !isDreaming && isDozeOff(dozeTransitionModel.to) && @@ -96,8 +95,7 @@ constructor( ), ::toTriple ) - .collect { triple -> - val (isDreaming, isOccluded, lastStartedTransition) = triple + .collect { (isDreaming, isOccluded, lastStartedTransition) -> if ( isOccluded && !isDreaming && @@ -123,24 +121,18 @@ constructor( private fun listenForDreamingToGone() { scope.launch { - keyguardInteractor.biometricUnlockState - .sample(keyguardTransitionInteractor.finishedKeyguardState, ::Pair) - .collect { pair -> - val (biometricUnlockState, keyguardState) = pair - if ( - keyguardState == KeyguardState.DREAMING && - isWakeAndUnlock(biometricUnlockState) - ) { - keyguardTransitionRepository.startTransition( - TransitionInfo( - name, - KeyguardState.DREAMING, - KeyguardState.GONE, - getAnimator(), - ) + keyguardInteractor.biometricUnlockState.collect { biometricUnlockState -> + if (biometricUnlockState == BiometricUnlockModel.WAKE_AND_UNLOCK_FROM_DREAM) { + keyguardTransitionRepository.startTransition( + TransitionInfo( + name, + KeyguardState.DREAMING, + KeyguardState.GONE, + getAnimator(), ) - } + ) } + } } } @@ -151,8 +143,7 @@ constructor( keyguardTransitionInteractor.finishedKeyguardState, ::Pair ) - .collect { pair -> - val (dozeTransitionModel, keyguardState) = pair + .collect { (dozeTransitionModel, keyguardState) -> if ( dozeTransitionModel.to == DozeStateModel.DOZE && keyguardState == KeyguardState.DREAMING diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt index 490d22eb08207..4cf56fe2c0310 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt @@ -32,12 +32,15 @@ import com.android.systemui.keyguard.shared.model.StatusBarState import com.android.systemui.keyguard.shared.model.WakefulnessModel import com.android.systemui.statusbar.CommandQueue import com.android.systemui.statusbar.CommandQueue.Callbacks -import com.android.systemui.util.kotlin.sample import javax.inject.Inject import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.merge /** @@ -89,15 +92,23 @@ constructor( /** * Dozing and dreaming have overlapping events. If the doze state remains in FINISH, it means * that doze mode is not running and DREAMING is ok to commence. + * + * Allow a brief moment to prevent rapidly oscillating between true/false signals. */ val isAbleToDream: Flow = merge(isDreaming, isDreamingWithOverlay) - .sample( + .combine( dozeTransitionModel, { isDreaming, dozeTransitionModel -> isDreaming && isDozeOff(dozeTransitionModel.to) } ) + .flatMapLatest { isAbleToDream -> + flow { + delay(50) + emit(isAbleToDream) + } + } .distinctUntilChanged() /** Whether the keyguard is showing or not. */ diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt index e164f5d58b07a..6627865ecc79c 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt @@ -22,10 +22,14 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.domain.interactor.FromDreamingTransitionInteractor.Companion.TO_LOCKSCREEN_DURATION import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.AnimationParams +import com.android.systemui.keyguard.shared.model.TransitionState.CANCELED +import com.android.systemui.keyguard.shared.model.TransitionState.FINISHED import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.merge /** * Breaks down DREAMING->LOCKSCREEN transition into discrete steps for corresponding views to @@ -49,9 +53,15 @@ constructor( /** Lockscreen views y-translation */ fun lockscreenTranslationY(translatePx: Int): Flow { - return flowForAnimation(LOCKSCREEN_TRANSLATION_Y).map { value -> - -translatePx + (EMPHASIZED_DECELERATE.getInterpolation(value) * translatePx) - } + return merge( + flowForAnimation(LOCKSCREEN_TRANSLATION_Y).map { value -> + -translatePx + (EMPHASIZED_DECELERATE.getInterpolation(value) * translatePx) + }, + // On end, reset the translation to 0 + interactor.dreamingToLockscreenTransition + .filter { it.transitionState == FINISHED || it.transitionState == CANCELED } + .map { 0f } + ) } /** Lockscreen views alpha */ diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModel.kt index 45e8f4714f02a..5a4796096eeb9 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModel.kt @@ -21,7 +21,8 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.domain.interactor.FromGoneTransitionInteractor.Companion.TO_DREAMING_DURATION import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.AnimationParams -import com.android.systemui.keyguard.shared.model.TransitionState +import com.android.systemui.keyguard.shared.model.TransitionState.CANCELED +import com.android.systemui.keyguard.shared.model.TransitionState.FINISHED import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds import kotlinx.coroutines.flow.Flow @@ -45,7 +46,7 @@ constructor( }, // On end, reset the translation to 0 interactor.goneToDreamingTransition - .filter { step -> step.transitionState == TransitionState.FINISHED } + .filter { it.transitionState == FINISHED || it.transitionState == CANCELED } .map { 0f } ) } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt index d48f87deaaf49..e05adbdab5838 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt @@ -21,7 +21,8 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor.Companion.TO_DREAMING_DURATION import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.AnimationParams -import com.android.systemui.keyguard.shared.model.TransitionState +import com.android.systemui.keyguard.shared.model.TransitionState.CANCELED +import com.android.systemui.keyguard.shared.model.TransitionState.FINISHED import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds import kotlinx.coroutines.flow.Flow @@ -48,7 +49,7 @@ constructor( }, // On end, reset the translation to 0 interactor.lockscreenToDreamingTransition - .filter { step -> step.transitionState == TransitionState.FINISHED } + .filter { it.transitionState == FINISHED || it.transitionState == CANCELED } .map { 0f } ) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt index e12c363e6f3f1..a1b6d478d7992 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt @@ -38,6 +38,7 @@ import com.android.systemui.util.mockito.withArgCaptor import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.cancelChildren import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.advanceUntilIdle import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Before @@ -177,7 +178,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { keyguardRepository.setDreamingWithOverlay(false) // AND occluded has stopped keyguardRepository.setKeyguardOccluded(false) - runCurrent() + advanceUntilIdle() val info = withArgCaptor { @@ -539,12 +540,11 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { }, ) ) - runCurrent() reset(mockTransitionRepository) // WHEN the device begins to dream keyguardRepository.setDreamingWithOverlay(true) - runCurrent() + advanceUntilIdle() val info = withArgCaptor { diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt index 69b6c63c2312c..7fa204bb980b2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt @@ -92,8 +92,10 @@ class GoneToDreamingTransitionViewModelTest : SysuiTestCase() { repository.sendTransitionStep(step(0.5f)) // ...up to here repository.sendTransitionStep(step(1f)) + // And a final reset event on CANCEL + repository.sendTransitionStep(step(0.8f, TransitionState.CANCELED)) - assertThat(values.size).isEqualTo(3) + assertThat(values.size).isEqualTo(4) assertThat(values[0]) .isEqualTo( EMPHASIZED_ACCELERATE.getInterpolation( @@ -112,6 +114,7 @@ class GoneToDreamingTransitionViewModelTest : SysuiTestCase() { animValue(0.5f, LOCKSCREEN_TRANSLATION_Y) ) * pixels ) + assertThat(values[3]).isEqualTo(0f) job.cancel() } @@ -123,12 +126,15 @@ class GoneToDreamingTransitionViewModelTest : SysuiTestCase() { return (stepValue - startValue) * multiplier } - private fun step(value: Float): TransitionStep { + private fun step( + value: Float, + state: TransitionState = TransitionState.RUNNING + ): TransitionStep { return TransitionStep( from = KeyguardState.GONE, to = KeyguardState.DREAMING, value = value, - transitionState = TransitionState.RUNNING, + transitionState = state, ownerName = "GoneToDreamingTransitionViewModelTest" ) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt index 739059126b04a..539fc2c1548ed 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt @@ -67,8 +67,7 @@ class LockscreenToDreamingTransitionViewModelTest : SysuiTestCase() { repository.sendTransitionStep(step(1f)) // Only three values should be present, since the dream overlay runs for a small - // fraction - // of the overall animation time + // fraction of the overall animation time assertThat(values.size).isEqualTo(3) assertThat(values[0]).isEqualTo(1f - animValue(0f, LOCKSCREEN_ALPHA)) assertThat(values[1]).isEqualTo(1f - animValue(0.1f, LOCKSCREEN_ALPHA)) @@ -92,8 +91,10 @@ class LockscreenToDreamingTransitionViewModelTest : SysuiTestCase() { repository.sendTransitionStep(step(0.5f)) // ...up to here repository.sendTransitionStep(step(1f)) + // And a final reset event on FINISHED + repository.sendTransitionStep(step(1f, TransitionState.FINISHED)) - assertThat(values.size).isEqualTo(3) + assertThat(values.size).isEqualTo(4) assertThat(values[0]) .isEqualTo( EMPHASIZED_ACCELERATE.getInterpolation( @@ -112,6 +113,8 @@ class LockscreenToDreamingTransitionViewModelTest : SysuiTestCase() { animValue(0.5f, LOCKSCREEN_TRANSLATION_Y) ) * pixels ) + assertThat(values[3]).isEqualTo(0f) + job.cancel() } @@ -123,12 +126,15 @@ class LockscreenToDreamingTransitionViewModelTest : SysuiTestCase() { return (stepValue - startValue) * multiplier } - private fun step(value: Float): TransitionStep { + private fun step( + value: Float, + state: TransitionState = TransitionState.RUNNING + ): TransitionStep { return TransitionStep( from = KeyguardState.LOCKSCREEN, to = KeyguardState.DREAMING, value = value, - transitionState = TransitionState.RUNNING, + transitionState = state, ownerName = "LockscreenToDreamingTransitionViewModelTest" ) }