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
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<Boolean> = repository.isDreamingWithOverlay
|
||||
/** Whether the system is dreaming and the active dream is hosted in lockscreen */
|
||||
val isActiveDreamLockscreenHosted: Flow<Boolean> = repository.isActiveDreamLockscreenHosted
|
||||
val isActiveDreamLockscreenHosted: StateFlow<Boolean> = repository.isActiveDreamLockscreenHosted
|
||||
/** Event for when the camera gesture is detected */
|
||||
val onCameraLaunchDetected: Flow<CameraLaunchSourceModel> = 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) {
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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<TransitionStep> =
|
||||
repository.transition(DREAMING, LOCKSCREEN)
|
||||
|
||||
/** DREAMING_LOCKSCREEN_HOSTED->LOCKSCREEN transition information. */
|
||||
val dreamingLockscreenHostedToLockscreenTransition: Flow<TransitionStep> =
|
||||
repository.transition(DREAMING_LOCKSCREEN_HOSTED, LOCKSCREEN)
|
||||
|
||||
/** GONE->AOD transition information. */
|
||||
val goneToAodTransition: Flow<TransitionStep> = repository.transition(GONE, AOD)
|
||||
|
||||
/** GONE->DREAMING transition information. */
|
||||
val goneToDreamingTransition: Flow<TransitionStep> = repository.transition(GONE, DREAMING)
|
||||
|
||||
/** GONE->DREAMING_LOCKSCREEN_HOSTED transition information. */
|
||||
val goneToDreamingLockscreenHostedTransition: Flow<TransitionStep> =
|
||||
repository.transition(GONE, DREAMING_LOCKSCREEN_HOSTED)
|
||||
|
||||
/** LOCKSCREEN->AOD transition information. */
|
||||
val lockscreenToAodTransition: Flow<TransitionStep> = repository.transition(LOCKSCREEN, AOD)
|
||||
|
||||
@@ -102,6 +111,10 @@ constructor(
|
||||
val lockscreenToDreamingTransition: Flow<TransitionStep> =
|
||||
repository.transition(LOCKSCREEN, DREAMING)
|
||||
|
||||
/** LOCKSCREEN->DREAMING_LOCKSCREEN_HOSTED transition information. */
|
||||
val lockscreenToDreamingLockscreenHostedTransition: Flow<TransitionStep> =
|
||||
repository.transition(LOCKSCREEN, DREAMING_LOCKSCREEN_HOSTED)
|
||||
|
||||
/** LOCKSCREEN->OCCLUDED transition information. */
|
||||
val lockscreenToOccludedTransition: Flow<TransitionStep> =
|
||||
repository.transition(LOCKSCREEN, OCCLUDED)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<Float> =
|
||||
transitionAnimation.createFlow(
|
||||
duration = 1.milliseconds,
|
||||
onStep = { 0f },
|
||||
)
|
||||
}
|
||||
@@ -112,6 +112,7 @@ open class UdfpsLockscreenViewModel(
|
||||
KeyguardState.OFF,
|
||||
KeyguardState.DOZING,
|
||||
KeyguardState.DREAMING,
|
||||
KeyguardState.DREAMING_LOCKSCREEN_HOSTED,
|
||||
KeyguardState.AOD,
|
||||
KeyguardState.PRIMARY_BOUNCER,
|
||||
KeyguardState.GONE,
|
||||
|
||||
@@ -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<TransitionStep> mGoneToDreamingLockscreenHostedTransition =
|
||||
(TransitionStep step) -> {
|
||||
mIsOcclusionTransitionRunning =
|
||||
step.getTransitionState() == TransitionState.RUNNING;
|
||||
mIsGoneToDreamingLockscreenHostedTransitionRunning = mIsOcclusionTransitionRunning;
|
||||
};
|
||||
|
||||
private final Consumer<TransitionStep> mLockscreenToDreamingLockscreenHostedTransition =
|
||||
(TransitionStep step) -> {
|
||||
mIsOcclusionTransitionRunning =
|
||||
step.getTransitionState() == TransitionState.RUNNING;
|
||||
};
|
||||
|
||||
private final Consumer<TransitionStep> mDreamingLockscreenHostedToLockscreenTransition =
|
||||
(TransitionStep step) -> {
|
||||
mIsOcclusionTransitionRunning =
|
||||
step.getTransitionState() == TransitionState.RUNNING;
|
||||
};
|
||||
|
||||
private final Consumer<TransitionStep> 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
|
||||
|
||||
@@ -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<TransitionInfo> {
|
||||
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<TransitionInfo> {
|
||||
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<TransitionInfo> {
|
||||
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<TransitionInfo> {
|
||||
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<TransitionInfo> {
|
||||
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<TransitionInfo> {
|
||||
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<TransitionInfo> {
|
||||
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<TransitionInfo> {
|
||||
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 {
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user