From 4b0a55e4bc90bb936240c0b992f150a688bd088a Mon Sep 17 00:00:00 2001 From: Coco Duan Date: Wed, 12 Jul 2023 06:07:06 +0000 Subject: [PATCH] Add transitions for the lockscreen hosted dream Add a new KeyguardState for the lockscreen hosted dream, as the transition animations to/from lockscreen/gone/bouncer are different from the existing dreaming state. We may also add animations for the lockscreen hosted dream<->lowlight dream transition in later changes. Add Gone->DreamingLockscreenHosted transition ViewModel and set keyguard alpha to 0 immediately and don't animate the clock when updating its position during the transition. When dreaming active, the clock will always be centered. Bug: b/285062308 Test: atest KeyguardTransitionScenariosTest Test: atest NotificationPanelViewControllerTest Change-Id: I6678318b9cbd89d8e47cdd04855c1a592dea5d71 --- ...ingLockscreenHostedTransitionInteractor.kt | 169 ++++++++++++ .../FromDreamingTransitionInteractor.kt | 13 +- .../FromGoneTransitionInteractor.kt | 30 ++- .../FromLockscreenTransitionInteractor.kt | 18 +- .../FromPrimaryBouncerTransitionInteractor.kt | 44 +++- .../domain/interactor/KeyguardInteractor.kt | 15 +- .../KeyguardTransitionCoreStartable.kt | 1 + .../KeyguardTransitionInteractor.kt | 13 + .../interactor/LightRevealScrimInteractor.kt | 1 + .../StartKeyguardTransitionModule.kt | 6 + .../keyguard/shared/model/KeyguardState.kt | 6 + ...mingLockscreenHostedTransitionViewModel.kt | 50 ++++ .../ui/viewmodel/UdfpsLockscreenViewModel.kt | 1 + .../NotificationPanelViewController.java | 62 ++++- .../KeyguardTransitionScenariosTest.kt | 246 ++++++++++++++++++ ...tificationPanelViewControllerBaseTest.java | 19 +- 16 files changed, 672 insertions(+), 22 deletions(-) create mode 100644 packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingLockscreenHostedTransitionInteractor.kt create mode 100644 packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingLockscreenHostedTransitionViewModel.kt diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingLockscreenHostedTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingLockscreenHostedTransitionInteractor.kt new file mode 100644 index 0000000000000..dac6ef5e6082d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingLockscreenHostedTransitionInteractor.kt @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.keyguard.domain.interactor + +import android.animation.ValueAnimator +import com.android.app.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 +import com.android.systemui.keyguard.shared.model.DozeStateModel +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.util.kotlin.Utils.Companion.toTriple +import com.android.systemui.util.kotlin.sample +import javax.inject.Inject +import kotlin.time.Duration.Companion.milliseconds +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.launch + +@SysUISingleton +class FromDreamingLockscreenHostedTransitionInteractor +@Inject +constructor( + override val transitionRepository: KeyguardTransitionRepository, + override val transitionInteractor: KeyguardTransitionInteractor, + @Application private val scope: CoroutineScope, + private val keyguardInteractor: KeyguardInteractor, +) : + TransitionInteractor( + fromState = KeyguardState.DREAMING_LOCKSCREEN_HOSTED, + ) { + + override fun start() { + listenForDreamingLockscreenHostedToLockscreen() + listenForDreamingLockscreenHostedToGone() + listenForDreamingLockscreenHostedToDozing() + listenForDreamingLockscreenHostedToOccluded() + listenForDreamingLockscreenHostedToPrimaryBouncer() + } + + private fun listenForDreamingLockscreenHostedToLockscreen() { + scope.launch { + keyguardInteractor.isActiveDreamLockscreenHosted + // Add a slight delay to prevent transitioning to lockscreen from happening too soon + // as dozing can arrive in a slight gap after the lockscreen hosted dream stops. + .onEach { delay(50) } + .sample( + combine( + keyguardInteractor.dozeTransitionModel, + transitionInteractor.startedKeyguardTransitionStep, + ::Pair + ), + ::toTriple + ) + .collect { + (isActiveDreamLockscreenHosted, dozeTransitionModel, lastStartedTransition) -> + if ( + !isActiveDreamLockscreenHosted && + DozeStateModel.isDozeOff(dozeTransitionModel.to) && + lastStartedTransition.to == KeyguardState.DREAMING_LOCKSCREEN_HOSTED + ) { + startTransitionTo(KeyguardState.LOCKSCREEN) + } + } + } + } + + private fun listenForDreamingLockscreenHostedToOccluded() { + scope.launch { + keyguardInteractor.isActiveDreamLockscreenHosted + .sample( + combine( + keyguardInteractor.isKeyguardOccluded, + transitionInteractor.startedKeyguardTransitionStep, + ::Pair, + ), + ::toTriple + ) + .collect { (isActiveDreamLockscreenHosted, isOccluded, lastStartedTransition) -> + if ( + isOccluded && + !isActiveDreamLockscreenHosted && + lastStartedTransition.to == KeyguardState.DREAMING_LOCKSCREEN_HOSTED + ) { + startTransitionTo(KeyguardState.OCCLUDED) + } + } + } + } + + private fun listenForDreamingLockscreenHostedToPrimaryBouncer() { + scope.launch { + keyguardInteractor.primaryBouncerShowing + .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair) + .collect { (isBouncerShowing, lastStartedTransitionStep) -> + if ( + isBouncerShowing && + lastStartedTransitionStep.to == KeyguardState.DREAMING_LOCKSCREEN_HOSTED + ) { + startTransitionTo(KeyguardState.PRIMARY_BOUNCER) + } + } + } + } + + private fun listenForDreamingLockscreenHostedToGone() { + scope.launch { + keyguardInteractor.biometricUnlockState + .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair) + .collect { (biometricUnlockState, lastStartedTransitionStep) -> + if ( + lastStartedTransitionStep.to == KeyguardState.DREAMING_LOCKSCREEN_HOSTED && + biometricUnlockState == BiometricUnlockModel.WAKE_AND_UNLOCK_FROM_DREAM + ) { + startTransitionTo(KeyguardState.GONE) + } + } + } + } + + private fun listenForDreamingLockscreenHostedToDozing() { + scope.launch { + combine( + keyguardInteractor.dozeTransitionModel, + transitionInteractor.startedKeyguardTransitionStep, + ::Pair + ) + .collect { (dozeTransitionModel, lastStartedTransitionStep) -> + if ( + dozeTransitionModel.to == DozeStateModel.DOZE && + lastStartedTransitionStep.to == KeyguardState.DREAMING_LOCKSCREEN_HOSTED + ) { + startTransitionTo(KeyguardState.DOZING) + } + } + } + } + + override fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator { + return ValueAnimator().apply { + interpolator = Interpolators.LINEAR + duration = + if (toState == KeyguardState.LOCKSCREEN) TO_LOCKSCREEN_DURATION.inWholeMilliseconds + else DEFAULT_DURATION.inWholeMilliseconds + } + } + + companion object { + private val DEFAULT_DURATION = 500.milliseconds + val TO_LOCKSCREEN_DURATION = 1167.milliseconds + } +} 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 98d7434166b4c..954ff6f23561b 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 @@ -94,11 +94,16 @@ constructor( private fun listenForDreamingToGone() { scope.launch { - keyguardInteractor.biometricUnlockState.collect { biometricUnlockState -> - if (biometricUnlockState == BiometricUnlockModel.WAKE_AND_UNLOCK_FROM_DREAM) { - startTransitionTo(KeyguardState.GONE) + keyguardInteractor.biometricUnlockState + .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair) + .collect { (biometricUnlockState, lastStartedTransitionStep) -> + if ( + lastStartedTransitionStep.to == KeyguardState.DREAMING && + biometricUnlockState == BiometricUnlockModel.WAKE_AND_UNLOCK_FROM_DREAM + ) { + startTransitionTo(KeyguardState.GONE) + } } - } } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt index f82633fbba27f..2b08b3d04e19f 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt @@ -48,6 +48,7 @@ constructor( listenForGoneToAodOrDozing() listenForGoneToDreaming() listenForGoneToLockscreen() + listenForGoneToDreamingLockscreenHosted() } // Primarily for when the user chooses to lock down the device @@ -63,12 +64,35 @@ constructor( } } + private fun listenForGoneToDreamingLockscreenHosted() { + scope.launch { + keyguardInteractor.isActiveDreamLockscreenHosted + .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair) + .collect { (isActiveDreamLockscreenHosted, lastStartedStep) -> + if (isActiveDreamLockscreenHosted && lastStartedStep.to == KeyguardState.GONE) { + startTransitionTo(KeyguardState.DREAMING_LOCKSCREEN_HOSTED) + } + } + } + } + private fun listenForGoneToDreaming() { scope.launch { keyguardInteractor.isAbleToDream - .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair) - .collect { (isAbleToDream, lastStartedStep) -> - if (isAbleToDream && lastStartedStep.to == KeyguardState.GONE) { + .sample( + combine( + transitionInteractor.startedKeyguardTransitionStep, + keyguardInteractor.isActiveDreamLockscreenHosted, + ::Pair + ), + ::toTriple + ) + .collect { (isAbleToDream, lastStartedStep, isActiveDreamLockscreenHosted) -> + if ( + isAbleToDream && + lastStartedStep.to == KeyguardState.GONE && + !isActiveDreamLockscreenHosted + ) { startTransitionTo(KeyguardState.DREAMING) } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt index ed1bf3ef27533..6b28b270032e9 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt @@ -70,17 +70,27 @@ constructor( combine( transitionInteractor.startedKeyguardTransitionStep, transitionInteractor.finishedKeyguardState, - ::Pair + keyguardInteractor.isActiveDreamLockscreenHosted, + ::Triple ), - ::toTriple + ::toQuad ) - .collect { (isAbleToDream, lastStartedTransition, finishedKeyguardState) -> + .collect { + ( + isAbleToDream, + lastStartedTransition, + finishedKeyguardState, + isActiveDreamLockscreenHosted) -> val isOnLockscreen = finishedKeyguardState == KeyguardState.LOCKSCREEN val isTransitionInterruptible = lastStartedTransition.to == KeyguardState.LOCKSCREEN && !invalidFromStates.contains(lastStartedTransition.from) if (isAbleToDream && (isOnLockscreen || isTransitionInterruptible)) { - startTransitionTo(KeyguardState.DREAMING) + if (isActiveDreamLockscreenHosted) { + startTransitionTo(KeyguardState.DREAMING_LOCKSCREEN_HOSTED) + } else { + startTransitionTo(KeyguardState.DREAMING) + } } } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt index e1754f55b1dd8..9142d1faa90a1 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt @@ -27,6 +27,8 @@ import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepositor import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.WakefulnessState import com.android.systemui.util.kotlin.Utils.Companion.toQuad +import com.android.systemui.util.kotlin.Utils.Companion.toQuint +import com.android.systemui.util.kotlin.Utils.Companion.toTriple import com.android.systemui.util.kotlin.sample import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds @@ -52,6 +54,7 @@ constructor( listenForPrimaryBouncerToGone() listenForPrimaryBouncerToAodOrDozing() listenForPrimaryBouncerToLockscreenOrOccluded() + listenForPrimaryBouncerToDreamingLockscreenHosted() } private fun listenForPrimaryBouncerToLockscreenOrOccluded() { @@ -62,17 +65,24 @@ constructor( keyguardInteractor.wakefulnessModel, transitionInteractor.startedKeyguardTransitionStep, keyguardInteractor.isKeyguardOccluded, - ::Triple + keyguardInteractor.isActiveDreamLockscreenHosted, + ::toQuad ), - ::toQuad + ::toQuint ) - .collect { (isBouncerShowing, wakefulnessState, lastStartedTransitionStep, occluded) - -> + .collect { + ( + isBouncerShowing, + wakefulnessState, + lastStartedTransitionStep, + occluded, + isActiveDreamLockscreenHosted) -> if ( !isBouncerShowing && lastStartedTransitionStep.to == KeyguardState.PRIMARY_BOUNCER && (wakefulnessState.state == WakefulnessState.AWAKE || - wakefulnessState.state == WakefulnessState.STARTING_TO_WAKE) + wakefulnessState.state == WakefulnessState.STARTING_TO_WAKE) && + !isActiveDreamLockscreenHosted ) { startTransitionTo( if (occluded) KeyguardState.OCCLUDED else KeyguardState.LOCKSCREEN @@ -111,6 +121,30 @@ constructor( } } + private fun listenForPrimaryBouncerToDreamingLockscreenHosted() { + scope.launch { + keyguardInteractor.primaryBouncerShowing + .sample( + combine( + keyguardInteractor.isActiveDreamLockscreenHosted, + transitionInteractor.startedKeyguardTransitionStep, + ::Pair + ), + ::toTriple + ) + .collect { + (isBouncerShowing, isActiveDreamLockscreenHosted, lastStartedTransitionStep) -> + if ( + !isBouncerShowing && + isActiveDreamLockscreenHosted && + lastStartedTransitionStep.to == KeyguardState.PRIMARY_BOUNCER + ) { + startTransitionTo(KeyguardState.DREAMING_LOCKSCREEN_HOSTED) + } + } + } + } + private fun listenForPrimaryBouncerToGone() { scope.launch { keyguardInteractor.isKeyguardGoingAway 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 cc159168009e8..5f849e61b215d 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 @@ -36,7 +36,6 @@ import com.android.systemui.keyguard.shared.model.DozeTransitionModel import com.android.systemui.keyguard.shared.model.KeyguardRootViewVisibilityState import com.android.systemui.keyguard.shared.model.StatusBarState import com.android.systemui.keyguard.shared.model.WakefulnessModel -import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel import com.android.systemui.statusbar.CommandQueue import com.android.systemui.util.kotlin.sample import javax.inject.Inject @@ -100,7 +99,7 @@ constructor( /** Whether the system is dreaming with an overlay active */ val isDreamingWithOverlay: Flow = repository.isDreamingWithOverlay /** Whether the system is dreaming and the active dream is hosted in lockscreen */ - val isActiveDreamLockscreenHosted: Flow = repository.isActiveDreamLockscreenHosted + val isActiveDreamLockscreenHosted: StateFlow = repository.isActiveDreamLockscreenHosted /** Event for when the camera gesture is detected */ val onCameraLaunchDetected: Flow = conflatedCallbackFlow { val callback = @@ -237,8 +236,16 @@ constructor( repository.setQuickSettingsVisible(isVisible) } - fun setKeyguardRootVisibility(statusBarState: Int, goingToFullShade: Boolean, isOcclusionTransitionRunning: Boolean) { - repository.setKeyguardVisibility(statusBarState, goingToFullShade, isOcclusionTransitionRunning) + fun setKeyguardRootVisibility( + statusBarState: Int, + goingToFullShade: Boolean, + isOcclusionTransitionRunning: Boolean + ) { + repository.setKeyguardVisibility( + statusBarState, + goingToFullShade, + isOcclusionTransitionRunning + ) } fun setClockPosition(x: Int, y: Int) { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt index efc1bd0fff04f..ba7b9870103a7 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt @@ -45,6 +45,7 @@ constructor( is FromOccludedTransitionInteractor -> Log.d(TAG, "Started $it") is FromDozingTransitionInteractor -> Log.d(TAG, "Started $it") is FromAlternateBouncerTransitionInteractor -> Log.d(TAG, "Started $it") + is FromDreamingLockscreenHostedTransitionInteractor -> Log.d(TAG, "Started $it") } it.start() } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt index 45bf20d3ec445..8c4c7ae53ce66 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt @@ -24,6 +24,7 @@ import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.KeyguardState.ALTERNATE_BOUNCER import com.android.systemui.keyguard.shared.model.KeyguardState.AOD import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING +import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING_LOCKSCREEN_HOSTED import com.android.systemui.keyguard.shared.model.KeyguardState.GONE import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN import com.android.systemui.keyguard.shared.model.KeyguardState.OCCLUDED @@ -89,12 +90,20 @@ constructor( val dreamingToLockscreenTransition: Flow = repository.transition(DREAMING, LOCKSCREEN) + /** DREAMING_LOCKSCREEN_HOSTED->LOCKSCREEN transition information. */ + val dreamingLockscreenHostedToLockscreenTransition: Flow = + repository.transition(DREAMING_LOCKSCREEN_HOSTED, LOCKSCREEN) + /** GONE->AOD transition information. */ val goneToAodTransition: Flow = repository.transition(GONE, AOD) /** GONE->DREAMING transition information. */ val goneToDreamingTransition: Flow = repository.transition(GONE, DREAMING) + /** GONE->DREAMING_LOCKSCREEN_HOSTED transition information. */ + val goneToDreamingLockscreenHostedTransition: Flow = + repository.transition(GONE, DREAMING_LOCKSCREEN_HOSTED) + /** LOCKSCREEN->AOD transition information. */ val lockscreenToAodTransition: Flow = repository.transition(LOCKSCREEN, AOD) @@ -102,6 +111,10 @@ constructor( val lockscreenToDreamingTransition: Flow = repository.transition(LOCKSCREEN, DREAMING) + /** LOCKSCREEN->DREAMING_LOCKSCREEN_HOSTED transition information. */ + val lockscreenToDreamingLockscreenHostedTransition: Flow = + repository.transition(LOCKSCREEN, DREAMING_LOCKSCREEN_HOSTED) + /** LOCKSCREEN->OCCLUDED transition information. */ val lockscreenToOccludedTransition: Flow = repository.transition(LOCKSCREEN, OCCLUDED) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt index 4244e5565a4b5..6115d90430b36 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt @@ -92,6 +92,7 @@ constructor( KeyguardState.DOZING -> false KeyguardState.AOD -> false KeyguardState.DREAMING -> true + KeyguardState.DREAMING_LOCKSCREEN_HOSTED -> true KeyguardState.ALTERNATE_BOUNCER -> true KeyguardState.PRIMARY_BOUNCER -> true KeyguardState.LOCKSCREEN -> true diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StartKeyguardTransitionModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StartKeyguardTransitionModule.kt index d9690b7e3b380..56f5529614320 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StartKeyguardTransitionModule.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StartKeyguardTransitionModule.kt @@ -48,6 +48,12 @@ abstract class StartKeyguardTransitionModule { @IntoSet abstract fun fromDreaming(impl: FromDreamingTransitionInteractor): TransitionInteractor + @Binds + @IntoSet + abstract fun fromDreamingLockscreenHosted( + impl: FromDreamingLockscreenHostedTransitionInteractor + ): TransitionInteractor + @Binds @IntoSet abstract fun fromOccluded(impl: FromOccludedTransitionInteractor): TransitionInteractor diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt index 87b4321769b51..1e20cdbed9eb3 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt @@ -35,6 +35,12 @@ enum class KeyguardState { * parties to present their own UI over keyguard, like a screensaver. */ DREAMING, + /* + * A device state after the device times out, which can be from both LOCKSCREEN or GONE states. + * It is a special version of DREAMING state but not DOZING. The active dream will be windowless + * and hosted in the lockscreen. + */ + DREAMING_LOCKSCREEN_HOSTED, /** * The device has entered a special low-power mode within SystemUI, also called the Always-on * Display (AOD). A minimal UI is presented to show critical information. If the device is in diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingLockscreenHostedTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingLockscreenHostedTransitionViewModel.kt new file mode 100644 index 0000000000000..113f01c0b122a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingLockscreenHostedTransitionViewModel.kt @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.viewmodel + +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.ui.KeyguardTransitionAnimationFlow +import javax.inject.Inject +import kotlin.time.Duration.Companion.milliseconds +import kotlinx.coroutines.flow.Flow + +/** + * Breaks down GONE->DREAMING_LOCKSCREEN_HOSTED transition into discrete steps for corresponding + * views to consume. + */ +@SysUISingleton +class GoneToDreamingLockscreenHostedTransitionViewModel +@Inject +constructor( + interactor: KeyguardTransitionInteractor, +) { + + private val transitionAnimation = + KeyguardTransitionAnimationFlow( + transitionDuration = TO_DREAMING_DURATION, + transitionFlow = interactor.goneToDreamingLockscreenHostedTransition, + ) + + /** Lockscreen views alpha - hide immediately */ + val lockscreenAlpha: Flow = + transitionAnimation.createFlow( + duration = 1.milliseconds, + onStep = { 0f }, + ) +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsLockscreenViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsLockscreenViewModel.kt index b307f1b43b45c..dd586076be838 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsLockscreenViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/UdfpsLockscreenViewModel.kt @@ -112,6 +112,7 @@ open class UdfpsLockscreenViewModel( KeyguardState.OFF, KeyguardState.DOZING, KeyguardState.DREAMING, + KeyguardState.DREAMING_LOCKSCREEN_HOSTED, KeyguardState.AOD, KeyguardState.PRIMARY_BOUNCER, KeyguardState.GONE, diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java index 773f35e0c6659..1e29dfba08d85 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java @@ -140,6 +140,7 @@ import com.android.systemui.keyguard.shared.model.WakefulnessModel; import com.android.systemui.keyguard.ui.binder.KeyguardLongPressViewBinder; import com.android.systemui.keyguard.ui.view.KeyguardRootView; import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel; +import com.android.systemui.keyguard.ui.viewmodel.GoneToDreamingLockscreenHostedTransitionViewModel; import com.android.systemui.keyguard.ui.viewmodel.GoneToDreamingTransitionViewModel; import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel; import com.android.systemui.keyguard.ui.viewmodel.KeyguardLongPressViewModel; @@ -597,6 +598,9 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump private final OccludedToLockscreenTransitionViewModel mOccludedToLockscreenTransitionViewModel; private final LockscreenToDreamingTransitionViewModel mLockscreenToDreamingTransitionViewModel; private final GoneToDreamingTransitionViewModel mGoneToDreamingTransitionViewModel; + private final GoneToDreamingLockscreenHostedTransitionViewModel + mGoneToDreamingLockscreenHostedTransitionViewModel; + private final LockscreenToOccludedTransitionViewModel mLockscreenToOccludedTransitionViewModel; private final KeyguardTransitionInteractor mKeyguardTransitionInteractor; @@ -605,6 +609,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump private final CoroutineDispatcher mMainDispatcher; private boolean mIsAnyMultiShadeExpanded; private boolean mIsOcclusionTransitionRunning = false; + private boolean mIsGoneToDreamingLockscreenHostedTransitionRunning; private int mDreamingToLockscreenTransitionTranslationY; private int mOccludedToLockscreenTransitionTranslationY; private int mLockscreenToDreamingTransitionTranslationY; @@ -652,6 +657,25 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump step.getTransitionState() == TransitionState.RUNNING; }; + private final Consumer mGoneToDreamingLockscreenHostedTransition = + (TransitionStep step) -> { + mIsOcclusionTransitionRunning = + step.getTransitionState() == TransitionState.RUNNING; + mIsGoneToDreamingLockscreenHostedTransitionRunning = mIsOcclusionTransitionRunning; + }; + + private final Consumer mLockscreenToDreamingLockscreenHostedTransition = + (TransitionStep step) -> { + mIsOcclusionTransitionRunning = + step.getTransitionState() == TransitionState.RUNNING; + }; + + private final Consumer mDreamingLockscreenHostedToLockscreenTransition = + (TransitionStep step) -> { + mIsOcclusionTransitionRunning = + step.getTransitionState() == TransitionState.RUNNING; + }; + private final Consumer mLockscreenToOccludedTransition = (TransitionStep step) -> { mIsOcclusionTransitionRunning = @@ -734,6 +758,8 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump OccludedToLockscreenTransitionViewModel occludedToLockscreenTransitionViewModel, LockscreenToDreamingTransitionViewModel lockscreenToDreamingTransitionViewModel, GoneToDreamingTransitionViewModel goneToDreamingTransitionViewModel, + GoneToDreamingLockscreenHostedTransitionViewModel + goneToDreamingLockscreenHostedTransitionViewModel, LockscreenToOccludedTransitionViewModel lockscreenToOccludedTransitionViewModel, @Main CoroutineDispatcher mainDispatcher, KeyguardTransitionInteractor keyguardTransitionInteractor, @@ -761,6 +787,8 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump mOccludedToLockscreenTransitionViewModel = occludedToLockscreenTransitionViewModel; mLockscreenToDreamingTransitionViewModel = lockscreenToDreamingTransitionViewModel; mGoneToDreamingTransitionViewModel = goneToDreamingTransitionViewModel; + mGoneToDreamingLockscreenHostedTransitionViewModel = + goneToDreamingLockscreenHostedTransitionViewModel; mLockscreenToOccludedTransitionViewModel = lockscreenToOccludedTransitionViewModel; mKeyguardTransitionInteractor = keyguardTransitionInteractor; mKeyguardInteractor = keyguardInteractor; @@ -1091,6 +1119,24 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump mDreamingToLockscreenTransitionTranslationY), setTransitionY(mNotificationStackScrollLayoutController), mMainDispatcher); + // Gone -> Dreaming hosted in lockscreen + collectFlow(mView, mKeyguardTransitionInteractor + .getGoneToDreamingLockscreenHostedTransition(), + mGoneToDreamingLockscreenHostedTransition, mMainDispatcher); + collectFlow(mView, mGoneToDreamingLockscreenHostedTransitionViewModel.getLockscreenAlpha(), + setTransitionAlpha(mNotificationStackScrollLayoutController), + mMainDispatcher); + + // Lockscreen -> Dreaming hosted in lockscreen + collectFlow(mView, mKeyguardTransitionInteractor + .getLockscreenToDreamingLockscreenHostedTransition(), + mLockscreenToDreamingLockscreenHostedTransition, mMainDispatcher); + + // Dreaming hosted in lockscreen -> Lockscreen + collectFlow(mView, mKeyguardTransitionInteractor + .getDreamingLockscreenHostedToLockscreenTransition(), + mDreamingLockscreenHostedToLockscreenTransition, mMainDispatcher); + // Occluded->Lockscreen collectFlow(mView, mKeyguardTransitionInteractor.getOccludedToLockscreenTransition(), mOccludedToLockscreenTransition, mMainDispatcher); @@ -1496,13 +1542,18 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump mAnimateNextPositionUpdate = false; } + private boolean shouldAnimateKeyguardStatusViewAlignment() { + // Do not animate when transitioning from Gone->DreamingLockscreenHosted + return !mIsGoneToDreamingLockscreenHostedTransitionRunning; + } + private void updateClockAppearance() { int userSwitcherPreferredY = mStatusBarHeaderHeightKeyguard; boolean bypassEnabled = mKeyguardBypassController.getBypassEnabled(); boolean shouldAnimateClockChange = mScreenOffAnimationController.shouldAnimateClockChange(); mKeyguardStatusViewController.displayClock(computeDesiredClockSize(), shouldAnimateClockChange); - updateKeyguardStatusViewAlignment(/* animate= */true); + updateKeyguardStatusViewAlignment(/* animate= */shouldAnimateKeyguardStatusViewAlignment()); int userSwitcherHeight = mKeyguardQsUserSwitchController != null ? mKeyguardQsUserSwitchController.getUserIconHeight() : 0; if (mKeyguardUserSwitcherController != null) { @@ -1625,6 +1676,10 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump // overlap. return true; } + if (isActiveDreamLockscreenHosted()) { + // Dreaming hosted in lockscreen, no "visible" notifications. Safe to center the clock. + return true; + } if (mNotificationListContainer.hasPulsingNotifications()) { // Pulsing notification appears on the right. Move clock left to avoid overlap. return false; @@ -1653,6 +1708,11 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump return mDozing && mDozeParameters.getAlwaysOn(); } + + private boolean isActiveDreamLockscreenHosted() { + return mKeyguardInteractor.isActiveDreamLockscreenHosted().getValue(); + } + private boolean hasVisibleNotifications() { return mNotificationStackScrollLayoutController .getVisibleNotificationCount() != 0 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 d01a46e06b9b0..daf5ce691df0d 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 @@ -89,6 +89,8 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { FromAlternateBouncerTransitionInteractor private lateinit var fromPrimaryBouncerTransitionInteractor: FromPrimaryBouncerTransitionInteractor + private lateinit var fromDreamingLockscreenHostedTransitionInteractor: + FromDreamingLockscreenHostedTransitionInteractor @Before fun setUp() { @@ -140,6 +142,15 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { ) .apply { start() } + fromDreamingLockscreenHostedTransitionInteractor = + FromDreamingLockscreenHostedTransitionInteractor( + scope = testScope, + keyguardInteractor = createKeyguardInteractor(), + transitionRepository = transitionRepository, + transitionInteractor = transitionInteractor, + ) + .apply { start() } + fromAodTransitionInteractor = FromAodTransitionInteractor( scope = testScope, @@ -298,6 +309,38 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { coroutineContext.cancelChildren() } + @Test + fun lockscreenToDreamingLockscreenHosted() = + testScope.runTest { + // GIVEN a device that is not dreaming or dozing + keyguardRepository.setDreamingWithOverlay(false) + keyguardRepository.setWakefulnessModel(startingToWake()) + keyguardRepository.setDozeTransitionModel( + DozeTransitionModel(from = DozeStateModel.DOZE, to = DozeStateModel.FINISH) + ) + runCurrent() + + // GIVEN a prior transition has run to LOCKSCREEN + runTransition(KeyguardState.GONE, KeyguardState.LOCKSCREEN) + + // WHEN the device begins to dream and the dream is lockscreen hosted + keyguardRepository.setDreamingWithOverlay(true) + keyguardRepository.setIsActiveDreamLockscreenHosted(true) + advanceUntilIdle() + + val info = + withArgCaptor { + verify(transitionRepository).startTransition(capture(), anyBoolean()) + } + // THEN a transition to DREAMING_LOCKSCREEN_HOSTED should occur + assertThat(info.ownerName).isEqualTo("FromLockscreenTransitionInteractor") + assertThat(info.from).isEqualTo(KeyguardState.LOCKSCREEN) + assertThat(info.to).isEqualTo(KeyguardState.DREAMING_LOCKSCREEN_HOSTED) + assertThat(info.animator).isNotNull() + + coroutineContext.cancelChildren() + } + @Test fun lockscreenToDozing() = testScope.runTest { @@ -352,6 +395,149 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { coroutineContext.cancelChildren() } + @Test + fun dreamingLockscreenHostedToLockscreen() = + testScope.runTest { + // GIVEN a device dreaming with the lockscreen hosted dream and not dozing + keyguardRepository.setIsActiveDreamLockscreenHosted(true) + keyguardRepository.setWakefulnessModel(startingToWake()) + keyguardRepository.setDozeTransitionModel( + DozeTransitionModel(from = DozeStateModel.DOZE, to = DozeStateModel.FINISH) + ) + runCurrent() + + // GIVEN a prior transition has run to DREAMING_LOCKSCREEN_HOSTED + runTransition(KeyguardState.GONE, KeyguardState.DREAMING_LOCKSCREEN_HOSTED) + + // WHEN the lockscreen hosted dream stops + keyguardRepository.setIsActiveDreamLockscreenHosted(false) + advanceUntilIdle() + + val info = + withArgCaptor { + verify(transitionRepository).startTransition(capture(), anyBoolean()) + } + // THEN a transition to Lockscreen should occur + assertThat(info.ownerName).isEqualTo("FromDreamingLockscreenHostedTransitionInteractor") + assertThat(info.from).isEqualTo(KeyguardState.DREAMING_LOCKSCREEN_HOSTED) + assertThat(info.to).isEqualTo(KeyguardState.LOCKSCREEN) + assertThat(info.animator).isNotNull() + + coroutineContext.cancelChildren() + } + + @Test + fun dreamingLockscreenHostedToGone() = + testScope.runTest { + // GIVEN a prior transition has run to DREAMING_LOCKSCREEN_HOSTED + runTransition(KeyguardState.GONE, KeyguardState.DREAMING_LOCKSCREEN_HOSTED) + + // WHEN biometrics succeeds with wake and unlock from dream mode + keyguardRepository.setBiometricUnlockState( + BiometricUnlockModel.WAKE_AND_UNLOCK_FROM_DREAM + ) + runCurrent() + + val info = + withArgCaptor { + verify(transitionRepository).startTransition(capture(), anyBoolean()) + } + // THEN a transition to Gone should occur + assertThat(info.ownerName).isEqualTo("FromDreamingLockscreenHostedTransitionInteractor") + assertThat(info.from).isEqualTo(KeyguardState.DREAMING_LOCKSCREEN_HOSTED) + assertThat(info.to).isEqualTo(KeyguardState.GONE) + assertThat(info.animator).isNotNull() + + coroutineContext.cancelChildren() + } + + @Test + fun dreamingLockscreenHostedToPrimaryBouncer() = + testScope.runTest { + // GIVEN a device dreaming with lockscreen hosted dream and not dozing + keyguardRepository.setIsActiveDreamLockscreenHosted(true) + keyguardRepository.setWakefulnessModel(startingToWake()) + runCurrent() + + // GIVEN a prior transition has run to DREAMING_LOCKSCREEN_HOSTED + runTransition(KeyguardState.GONE, KeyguardState.DREAMING_LOCKSCREEN_HOSTED) + + // WHEN the primary bouncer is set to show + bouncerRepository.setPrimaryShow(true) + runCurrent() + + val info = + withArgCaptor { + verify(transitionRepository).startTransition(capture(), anyBoolean()) + } + // THEN a transition to PRIMARY_BOUNCER should occur + assertThat(info.ownerName).isEqualTo("FromDreamingLockscreenHostedTransitionInteractor") + assertThat(info.from).isEqualTo(KeyguardState.DREAMING_LOCKSCREEN_HOSTED) + assertThat(info.to).isEqualTo(KeyguardState.PRIMARY_BOUNCER) + assertThat(info.animator).isNotNull() + + coroutineContext.cancelChildren() + } + + @Test + fun dreamingLockscreenHostedToDozing() = + testScope.runTest { + // GIVEN a device is dreaming with lockscreen hosted dream + keyguardRepository.setIsActiveDreamLockscreenHosted(true) + runCurrent() + + // GIVEN a prior transition has run to DREAMING_LOCKSCREEN_HOSTED + runTransition(KeyguardState.GONE, KeyguardState.DREAMING_LOCKSCREEN_HOSTED) + + // WHEN the device begins to sleep + keyguardRepository.setIsActiveDreamLockscreenHosted(false) + keyguardRepository.setDozeTransitionModel( + DozeTransitionModel(from = DozeStateModel.INITIALIZED, to = DozeStateModel.DOZE) + ) + runCurrent() + + val info = + withArgCaptor { + verify(transitionRepository).startTransition(capture(), anyBoolean()) + } + // THEN a transition to DOZING should occur + assertThat(info.ownerName).isEqualTo("FromDreamingLockscreenHostedTransitionInteractor") + assertThat(info.from).isEqualTo(KeyguardState.DREAMING_LOCKSCREEN_HOSTED) + assertThat(info.to).isEqualTo(KeyguardState.DOZING) + assertThat(info.animator).isNotNull() + + coroutineContext.cancelChildren() + } + + @Test + fun dreamingLockscreenHostedToOccluded() = + testScope.runTest { + // GIVEN device is dreaming with lockscreen hosted dream and not occluded + keyguardRepository.setIsActiveDreamLockscreenHosted(true) + keyguardRepository.setKeyguardOccluded(false) + runCurrent() + + // GIVEN a prior transition has run to DREAMING_LOCKSCREEN_HOSTED + runTransition(KeyguardState.GONE, KeyguardState.DREAMING_LOCKSCREEN_HOSTED) + + // WHEN the keyguard is occluded and the lockscreen hosted dream stops + keyguardRepository.setIsActiveDreamLockscreenHosted(false) + keyguardRepository.setKeyguardOccluded(true) + runCurrent() + + val info = + withArgCaptor { + verify(transitionRepository).startTransition(capture(), anyBoolean()) + } + // THEN a transition to OCCLUDED should occur + assertThat(info.ownerName).isEqualTo("FromDreamingLockscreenHostedTransitionInteractor") + assertThat(info.from).isEqualTo(KeyguardState.DREAMING_LOCKSCREEN_HOSTED) + assertThat(info.to).isEqualTo(KeyguardState.OCCLUDED) + assertThat(info.animator).isNotNull() + + coroutineContext.cancelChildren() + } + @Test fun dozingToLockscreen() = testScope.runTest { @@ -532,6 +718,38 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { coroutineContext.cancelChildren() } + @Test + fun goneToDreamingLockscreenHosted() = + testScope.runTest { + // GIVEN a device that is not dreaming or dozing + keyguardRepository.setDreamingWithOverlay(false) + keyguardRepository.setWakefulnessModel(startingToWake()) + keyguardRepository.setDozeTransitionModel( + DozeTransitionModel(from = DozeStateModel.DOZE, to = DozeStateModel.FINISH) + ) + runCurrent() + + // GIVEN a prior transition has run to GONE + runTransition(KeyguardState.LOCKSCREEN, KeyguardState.GONE) + + // WHEN the device begins to dream with the lockscreen hosted dream + keyguardRepository.setDreamingWithOverlay(true) + keyguardRepository.setIsActiveDreamLockscreenHosted(true) + advanceUntilIdle() + + val info = + withArgCaptor { + verify(transitionRepository).startTransition(capture(), anyBoolean()) + } + // THEN a transition to DREAMING_LOCKSCREEN_HOSTED should occur + assertThat(info.ownerName).isEqualTo("FromGoneTransitionInteractor") + assertThat(info.from).isEqualTo(KeyguardState.GONE) + assertThat(info.to).isEqualTo(KeyguardState.DREAMING_LOCKSCREEN_HOSTED) + assertThat(info.animator).isNotNull() + + coroutineContext.cancelChildren() + } + @Test fun alternateBouncerToPrimaryBouncer() = testScope.runTest { @@ -725,6 +943,34 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { coroutineContext.cancelChildren() } + @Test + fun primaryBouncerToDreamingLockscreenHosted() = + testScope.runTest { + // GIVEN device dreaming with the lockscreen hosted dream and not dozing + keyguardRepository.setIsActiveDreamLockscreenHosted(true) + keyguardRepository.setWakefulnessModel(startingToWake()) + + // GIVEN a prior transition has run to PRIMARY_BOUNCER + bouncerRepository.setPrimaryShow(true) + runTransition(KeyguardState.DREAMING_LOCKSCREEN_HOSTED, KeyguardState.PRIMARY_BOUNCER) + + // WHEN the primary bouncer stops showing and lockscreen hosted dream still active + bouncerRepository.setPrimaryShow(false) + runCurrent() + + val info = + withArgCaptor { + verify(transitionRepository).startTransition(capture(), anyBoolean()) + } + // THEN a transition back to DREAMING_LOCKSCREEN_HOSTED should occur + assertThat(info.ownerName).isEqualTo("FromPrimaryBouncerTransitionInteractor") + assertThat(info.from).isEqualTo(KeyguardState.PRIMARY_BOUNCER) + assertThat(info.to).isEqualTo(KeyguardState.DREAMING_LOCKSCREEN_HOSTED) + assertThat(info.animator).isNotNull() + + coroutineContext.cancelChildren() + } + @Test fun occludedToGone() = testScope.runTest { diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java index 47ca49d03cc7d..864db578e9304 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java @@ -99,6 +99,7 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor; import com.android.systemui.keyguard.ui.view.KeyguardRootView; import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel; +import com.android.systemui.keyguard.ui.viewmodel.GoneToDreamingLockscreenHostedTransitionViewModel; import com.android.systemui.keyguard.ui.viewmodel.GoneToDreamingTransitionViewModel; import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel; import com.android.systemui.keyguard.ui.viewmodel.KeyguardLongPressViewModel; @@ -297,7 +298,8 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { @Mock protected LockscreenToOccludedTransitionViewModel mLockscreenToOccludedTransitionViewModel; @Mock protected GoneToDreamingTransitionViewModel mGoneToDreamingTransitionViewModel; - + @Mock protected GoneToDreamingLockscreenHostedTransitionViewModel + mGoneToDreamingLockscreenHostedTransitionViewModel; @Mock protected KeyguardTransitionInteractor mKeyguardTransitionInteractor; @Mock protected KeyguardLongPressViewModel mKeyuardLongPressViewModel; @Mock protected AlternateBouncerInteractor mAlternateBouncerInteractor; @@ -477,6 +479,20 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { when(mGoneToDreamingTransitionViewModel.lockscreenTranslationY(anyInt())) .thenReturn(emptyFlow()); + // Gone->Dreaming lockscreen hosted + when(mKeyguardTransitionInteractor.getGoneToDreamingLockscreenHostedTransition()) + .thenReturn(emptyFlow()); + when(mGoneToDreamingLockscreenHostedTransitionViewModel.getLockscreenAlpha()) + .thenReturn(emptyFlow()); + + // Dreaming lockscreen hosted->Lockscreen + when(mKeyguardTransitionInteractor.getDreamingLockscreenHostedToLockscreenTransition()) + .thenReturn(emptyFlow()); + + // Lockscreen->Dreaming lockscreen hosted + when(mKeyguardTransitionInteractor.getLockscreenToDreamingLockscreenHostedTransition()) + .thenReturn(emptyFlow()); + // Lockscreen->Occluded when(mKeyguardTransitionInteractor.getLockscreenToOccludedTransition()) .thenReturn(emptyFlow()); @@ -612,6 +628,7 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { mOccludedToLockscreenTransitionViewModel, mLockscreenToDreamingTransitionViewModel, mGoneToDreamingTransitionViewModel, + mGoneToDreamingLockscreenHostedTransitionViewModel, mLockscreenToOccludedTransitionViewModel, mMainDispatcher, mKeyguardTransitionInteractor,