Skip to content
Snippets Groups Projects
Commit 4cc8c0e4 authored by Josh Tsuji's avatar Josh Tsuji Committed by Android (Google) Code Review
Browse files

Merge "Use currentKeyguardState for lockscreenVisibility." into main

parents be108573 5f7dc9a2
No related branches found
No related tags found
No related merge requests found
......@@ -35,6 +35,7 @@ import com.android.systemui.keyguard.shared.model.KeyguardState.OFF
import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.util.kotlin.pairwise
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
......@@ -46,6 +47,7 @@ import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.flow.stateIn
/** Encapsulates business-logic related to the keyguard transitions. */
@OptIn(ExperimentalCoroutinesApi::class)
......@@ -205,6 +207,21 @@ constructor(
.map { step -> step.to }
.shareIn(scope, SharingStarted.Eagerly, replay = 1)
/**
* A pair of the most recent STARTED step, and the transition step immediately preceding it. The
* transition framework enforces that the previous step is either a CANCELED or FINISHED step,
* and that the previous step was *to* the state the STARTED step is *from*.
*
* This flow can be used to access the previous step to determine whether it was CANCELED or
* FINISHED. In the case of a CANCELED step, we can also figure out which state we were coming
* from when we were canceled.
*/
val startedStepWithPrecedingStep =
transitions
.pairwise()
.filter { it.newValue.transitionState == TransitionState.STARTED }
.stateIn(scope, SharingStarted.Eagerly, null)
/**
* The last [KeyguardState] to which we [TransitionState.FINISHED] a transition.
*
......
......@@ -19,7 +19,9 @@ package com.android.systemui.keyguard.domain.interactor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.statusbar.notification.domain.interactor.NotificationLaunchAnimationInteractor
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
......@@ -121,19 +123,27 @@ constructor(
* want to know if the AOD/clock/notifs/etc. are visible.
*/
val lockscreenVisibility: Flow<Boolean> =
combine(
transitionInteractor.startedKeyguardTransitionStep,
transitionInteractor.finishedKeyguardState,
) { startedStep, finishedState ->
// If we finished the transition, use the finished state. If we're running a
// transition, use the state we're transitioning FROM. This can be different from
// the last finished state if a transition is interrupted. For example, if we were
// transitioning from GONE to AOD and then started AOD -> LOCKSCREEN mid-transition,
// we want to immediately use the visibility for AOD (lockscreenVisibility=true)
// even though the lastFinishedState is still GONE (lockscreenVisibility=false).
if (finishedState == startedStep.to) finishedState else startedStep.from
transitionInteractor.currentKeyguardState
.sample(transitionInteractor.startedStepWithPrecedingStep, ::Pair)
.map { (currentState, startedWithPrev) ->
val startedFromStep = startedWithPrev?.previousValue
val startedStep = startedWithPrev?.newValue
val returningToGoneAfterCancellation =
startedStep?.to == KeyguardState.GONE &&
startedFromStep?.transitionState == TransitionState.CANCELED &&
startedFromStep.from == KeyguardState.GONE
if (!returningToGoneAfterCancellation) {
// By default, apply the lockscreen visibility of the current state.
KeyguardState.lockscreenVisibleInState(currentState)
} else {
// If we're transitioning to GONE after a prior canceled transition from GONE,
// then this is the camera launch transition from an asleep state back to GONE.
// We don't want to show the lockscreen since we're aborting the lock and going
// back to GONE.
KeyguardState.lockscreenVisibleInState(KeyguardState.GONE)
}
}
.map(KeyguardState::lockscreenVisibleInState)
.distinctUntilChanged()
/**
......
......@@ -375,4 +375,323 @@ class WindowManagerLockscreenVisibilityInteractorTest : SysuiTestCase() {
values
)
}
@Test
fun testLockscreenVisibility_usesFromState_ifCanceled() =
testScope.runTest {
val values by collectValues(underTest.lockscreenVisibility)
transitionRepository.sendTransitionSteps(
from = KeyguardState.LOCKSCREEN,
to = KeyguardState.GONE,
testScope
)
runCurrent()
assertEquals(
listOf(
// Initially should be true, as we start in LOCKSCREEN.
true,
// Then, false, since we finish in GONE.
false,
),
values
)
transitionRepository.sendTransitionStep(
TransitionStep(
transitionState = TransitionState.STARTED,
from = KeyguardState.GONE,
to = KeyguardState.AOD,
)
)
transitionRepository.sendTransitionStep(
TransitionStep(
transitionState = TransitionState.RUNNING,
from = KeyguardState.GONE,
to = KeyguardState.AOD,
)
)
runCurrent()
assertEquals(
listOf(
true,
// Should remain false as we transition from GONE.
false,
),
values
)
transitionRepository.sendTransitionStep(
TransitionStep(
transitionState = TransitionState.CANCELED,
from = KeyguardState.GONE,
to = KeyguardState.AOD,
)
)
transitionRepository.sendTransitionStep(
TransitionStep(
transitionState = TransitionState.STARTED,
from = KeyguardState.AOD,
to = KeyguardState.LOCKSCREEN,
)
)
runCurrent()
assertEquals(
listOf(
true,
false,
// If we cancel and then go from LS -> GONE, we should immediately flip to the
// visibility of the from state (LS).
true,
),
values
)
transitionRepository.sendTransitionStep(
TransitionStep(
transitionState = TransitionState.FINISHED,
from = KeyguardState.AOD,
to = KeyguardState.LOCKSCREEN,
)
)
runCurrent()
assertEquals(
listOf(
true,
false,
true,
),
values
)
}
/**
* Tests the special case for insecure camera launch. CANCELING a transition from GONE and then
* STARTING a transition back to GONE should never show the lockscreen, even though the current
* state during the AOD/isAsleep -> GONE transition is AOD (where lockscreen visibility = true).
*/
@Test
fun testLockscreenVisibility_falseDuringTransitionToGone_fromCanceledGone() =
testScope.runTest {
val values by collectValues(underTest.lockscreenVisibility)
transitionRepository.sendTransitionSteps(
from = KeyguardState.LOCKSCREEN,
to = KeyguardState.GONE,
testScope
)
runCurrent()
assertEquals(
listOf(
true,
// Not visible since we're GONE.
false,
),
values
)
transitionRepository.sendTransitionStep(
TransitionStep(
transitionState = TransitionState.STARTED,
from = KeyguardState.GONE,
to = KeyguardState.AOD,
)
)
runCurrent()
transitionRepository.sendTransitionStep(
TransitionStep(
transitionState = TransitionState.RUNNING,
from = KeyguardState.GONE,
to = KeyguardState.AOD,
)
)
runCurrent()
transitionRepository.sendTransitionStep(
TransitionStep(
transitionState = TransitionState.CANCELED,
from = KeyguardState.GONE,
to = KeyguardState.AOD,
)
)
runCurrent()
transitionRepository.sendTransitionStep(
TransitionStep(
transitionState = TransitionState.STARTED,
from = KeyguardState.AOD,
to = KeyguardState.GONE,
)
)
runCurrent()
transitionRepository.sendTransitionStep(
TransitionStep(
transitionState = TransitionState.RUNNING,
from = KeyguardState.AOD,
to = KeyguardState.GONE,
)
)
runCurrent()
transitionRepository.sendTransitionStep(
TransitionStep(
transitionState = TransitionState.FINISHED,
from = KeyguardState.AOD,
to = KeyguardState.GONE,
)
)
runCurrent()
assertEquals(
listOf(
true,
// Remains not visible from GONE -> AOD (canceled) -> AOD since we never
// FINISHED in AOD, and special-case handling for the insecure camera launch
// ensures that we use the lockscreen visibility for GONE (false) if we're
// STARTED to GONE after a CANCELED from GONE.
false,
),
values
)
transitionRepository.sendTransitionSteps(
from = KeyguardState.GONE,
to = KeyguardState.LOCKSCREEN,
testScope,
)
assertEquals(
listOf(
true,
false,
// Make sure there's no stuck overrides or something - we should make lockscreen
// visible again once we're finished in LOCKSCREEN.
true,
),
values
)
}
/** */
@Test
fun testLockscreenVisibility_trueDuringTransitionToGone_fromNotCanceledGone() =
testScope.runTest {
val values by collectValues(underTest.lockscreenVisibility)
transitionRepository.sendTransitionSteps(
from = KeyguardState.LOCKSCREEN,
to = KeyguardState.GONE,
testScope
)
runCurrent()
assertEquals(
listOf(
true,
// Not visible when finished in GONE.
false,
),
values
)
transitionRepository.sendTransitionStep(
TransitionStep(
transitionState = TransitionState.STARTED,
from = KeyguardState.GONE,
to = KeyguardState.AOD,
)
)
runCurrent()
transitionRepository.sendTransitionStep(
TransitionStep(
transitionState = TransitionState.RUNNING,
from = KeyguardState.GONE,
to = KeyguardState.AOD,
)
)
runCurrent()
assertEquals(
listOf(
true,
// Still not visible during GONE -> AOD.
false,
),
values
)
transitionRepository.sendTransitionStep(
TransitionStep(
transitionState = TransitionState.FINISHED,
from = KeyguardState.GONE,
to = KeyguardState.AOD,
)
)
runCurrent()
assertEquals(
listOf(
true,
false,
// Visible now that we're FINISHED in AOD.
true
),
values
)
transitionRepository.sendTransitionStep(
TransitionStep(
transitionState = TransitionState.STARTED,
from = KeyguardState.AOD,
to = KeyguardState.GONE,
)
)
runCurrent()
transitionRepository.sendTransitionStep(
TransitionStep(
transitionState = TransitionState.RUNNING,
from = KeyguardState.AOD,
to = KeyguardState.GONE,
)
)
runCurrent()
assertEquals(
listOf(
true,
false,
// Remains visible from AOD during transition.
true
),
values
)
transitionRepository.sendTransitionStep(
TransitionStep(
transitionState = TransitionState.FINISHED,
from = KeyguardState.AOD,
to = KeyguardState.GONE,
)
)
runCurrent()
assertEquals(
listOf(
true,
false,
true,
// Until we're finished in GONE again.
false
),
values
)
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment