Transitions - Better dozing/aod support
Add callbacks to BatteryController in order to feed AOD availability into the KeyguardRepository. This allows for better decisions when transitioning to both DOZING and AOD states. Remove released lockscreen animations flag Fixes: 254512713 Bug: 195430376 Test: atest KeyguardRepositoryImplTest KeyguardTransitionScenariosTest DozeParametersTest Change-Id: I2ab4c15e1b0289acb9e3505ca3ef4475c2f143ae
This commit is contained in:
@@ -114,8 +114,6 @@ object Flags {
|
||||
// ** Flag retired **
|
||||
// public static final BooleanFlag KEYGUARD_LAYOUT =
|
||||
// new BooleanFlag(200, true);
|
||||
// TODO(b/254512713): Tracking Bug
|
||||
@JvmField val LOCKSCREEN_ANIMATIONS = releasedFlag(201, "lockscreen_animations")
|
||||
|
||||
// TODO(b/254512750): Tracking Bug
|
||||
val NEW_UNLOCK_SWIPE_ANIMATION = releasedFlag(202, "new_unlock_swipe_animation")
|
||||
|
||||
@@ -40,6 +40,7 @@ import com.android.systemui.keyguard.shared.model.WakefulnessModel
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController
|
||||
import com.android.systemui.statusbar.phone.BiometricUnlockController
|
||||
import com.android.systemui.statusbar.phone.BiometricUnlockController.WakeAndUnlockMode
|
||||
import com.android.systemui.statusbar.phone.DozeParameters
|
||||
import com.android.systemui.statusbar.policy.KeyguardStateController
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.channels.awaitClose
|
||||
@@ -88,6 +89,9 @@ interface KeyguardRepository {
|
||||
/** Observable for whether the bouncer is showing. */
|
||||
val isBouncerShowing: Flow<Boolean>
|
||||
|
||||
/** Is the always-on display available to be used? */
|
||||
val isAodAvailable: Flow<Boolean>
|
||||
|
||||
/**
|
||||
* Observable for whether we are in doze state.
|
||||
*
|
||||
@@ -182,6 +186,7 @@ constructor(
|
||||
private val keyguardStateController: KeyguardStateController,
|
||||
private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
|
||||
private val dozeTransitionListener: DozeTransitionListener,
|
||||
private val dozeParameters: DozeParameters,
|
||||
private val authController: AuthController,
|
||||
private val dreamOverlayCallbackController: DreamOverlayCallbackController,
|
||||
) : KeyguardRepository {
|
||||
@@ -220,6 +225,31 @@ constructor(
|
||||
}
|
||||
.distinctUntilChanged()
|
||||
|
||||
override val isAodAvailable: Flow<Boolean> =
|
||||
conflatedCallbackFlow {
|
||||
val callback =
|
||||
object : DozeParameters.Callback {
|
||||
override fun onAlwaysOnChange() {
|
||||
trySendWithFailureLogging(
|
||||
dozeParameters.getAlwaysOn(),
|
||||
TAG,
|
||||
"updated isAodAvailable"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
dozeParameters.addCallback(callback)
|
||||
// Adding the callback does not send an initial update.
|
||||
trySendWithFailureLogging(
|
||||
dozeParameters.getAlwaysOn(),
|
||||
TAG,
|
||||
"initial isAodAvailable"
|
||||
)
|
||||
|
||||
awaitClose { dozeParameters.removeCallback(callback) }
|
||||
}
|
||||
.distinctUntilChanged()
|
||||
|
||||
override val isKeyguardOccluded: Flow<Boolean> =
|
||||
conflatedCallbackFlow {
|
||||
val callback =
|
||||
|
||||
@@ -21,9 +21,9 @@ import com.android.systemui.animation.Interpolators
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.dagger.qualifiers.Application
|
||||
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
|
||||
import com.android.systemui.keyguard.shared.model.DozeStateModel.Companion.isDozeOff
|
||||
import com.android.systemui.keyguard.shared.model.KeyguardState
|
||||
import com.android.systemui.keyguard.shared.model.TransitionInfo
|
||||
import com.android.systemui.keyguard.shared.model.WakefulnessModel.Companion.isWakingOrStartingToWake
|
||||
import com.android.systemui.util.kotlin.sample
|
||||
import javax.inject.Inject
|
||||
import kotlin.time.Duration
|
||||
@@ -48,12 +48,11 @@ constructor(
|
||||
|
||||
private fun listenForDozingToLockscreen() {
|
||||
scope.launch {
|
||||
keyguardInteractor.dozeTransitionModel
|
||||
keyguardInteractor.wakefulnessModel
|
||||
.sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
|
||||
.collect { pair ->
|
||||
val (dozeTransitionModel, lastStartedTransition) = pair
|
||||
.collect { (wakefulnessModel, lastStartedTransition) ->
|
||||
if (
|
||||
isDozeOff(dozeTransitionModel.to) &&
|
||||
isWakingOrStartingToWake(wakefulnessModel) &&
|
||||
lastStartedTransition.to == KeyguardState.DOZING
|
||||
) {
|
||||
keyguardTransitionRepository.startTransition(
|
||||
|
||||
@@ -26,7 +26,10 @@ import com.android.systemui.keyguard.shared.model.TransitionInfo
|
||||
import com.android.systemui.keyguard.shared.model.WakefulnessState
|
||||
import com.android.systemui.util.kotlin.sample
|
||||
import javax.inject.Inject
|
||||
import kotlin.time.Duration
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@SysUISingleton
|
||||
@@ -40,7 +43,7 @@ constructor(
|
||||
) : TransitionInteractor(FromGoneTransitionInteractor::class.simpleName!!) {
|
||||
|
||||
override fun start() {
|
||||
listenForGoneToAod()
|
||||
listenForGoneToAodOrDozing()
|
||||
listenForGoneToDreaming()
|
||||
}
|
||||
|
||||
@@ -56,7 +59,7 @@ constructor(
|
||||
name,
|
||||
KeyguardState.GONE,
|
||||
KeyguardState.DREAMING,
|
||||
getAnimator(),
|
||||
getAnimator(TO_DREAMING_DURATION),
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -64,12 +67,18 @@ constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun listenForGoneToAod() {
|
||||
private fun listenForGoneToAodOrDozing() {
|
||||
scope.launch {
|
||||
keyguardInteractor.wakefulnessModel
|
||||
.sample(keyguardTransitionInteractor.finishedKeyguardState, ::Pair)
|
||||
.collect { pair ->
|
||||
val (wakefulnessState, keyguardState) = pair
|
||||
.sample(
|
||||
combine(
|
||||
keyguardTransitionInteractor.finishedKeyguardState,
|
||||
keyguardInteractor.isAodAvailable,
|
||||
::Pair
|
||||
),
|
||||
::toTriple
|
||||
)
|
||||
.collect { (wakefulnessState, keyguardState, isAodAvailable) ->
|
||||
if (
|
||||
keyguardState == KeyguardState.GONE &&
|
||||
wakefulnessState.state == WakefulnessState.STARTING_TO_SLEEP
|
||||
@@ -78,7 +87,11 @@ constructor(
|
||||
TransitionInfo(
|
||||
name,
|
||||
KeyguardState.GONE,
|
||||
KeyguardState.AOD,
|
||||
if (isAodAvailable) {
|
||||
KeyguardState.AOD
|
||||
} else {
|
||||
KeyguardState.DOZING
|
||||
},
|
||||
getAnimator(),
|
||||
)
|
||||
)
|
||||
@@ -87,14 +100,15 @@ constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun getAnimator(): ValueAnimator {
|
||||
private fun getAnimator(duration: Duration = DEFAULT_DURATION): ValueAnimator {
|
||||
return ValueAnimator().apply {
|
||||
setInterpolator(Interpolators.LINEAR)
|
||||
setDuration(TRANSITION_DURATION_MS)
|
||||
setDuration(duration.inWholeMilliseconds)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TRANSITION_DURATION_MS = 500L
|
||||
private val DEFAULT_DURATION = 500.milliseconds
|
||||
val TO_DREAMING_DURATION = 933.milliseconds
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,11 +21,11 @@ import com.android.systemui.animation.Interpolators
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.dagger.qualifiers.Application
|
||||
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
|
||||
import com.android.systemui.keyguard.shared.model.DozeStateModel
|
||||
import com.android.systemui.keyguard.shared.model.KeyguardState
|
||||
import com.android.systemui.keyguard.shared.model.StatusBarState.KEYGUARD
|
||||
import com.android.systemui.keyguard.shared.model.TransitionInfo
|
||||
import com.android.systemui.keyguard.shared.model.TransitionState
|
||||
import com.android.systemui.keyguard.shared.model.WakefulnessState
|
||||
import com.android.systemui.shade.data.repository.ShadeRepository
|
||||
import com.android.systemui.util.kotlin.sample
|
||||
import java.util.UUID
|
||||
@@ -54,7 +54,7 @@ constructor(
|
||||
listenForLockscreenToGone()
|
||||
listenForLockscreenToOccluded()
|
||||
listenForLockscreenToCamera()
|
||||
listenForLockscreenToAod()
|
||||
listenForLockscreenToAodOrDozing()
|
||||
listenForLockscreenToBouncer()
|
||||
listenForLockscreenToDreaming()
|
||||
listenForLockscreenToBouncerDragging()
|
||||
@@ -230,19 +230,31 @@ constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun listenForLockscreenToAod() {
|
||||
private fun listenForLockscreenToAodOrDozing() {
|
||||
scope.launch {
|
||||
keyguardInteractor
|
||||
.dozeTransitionTo(DozeStateModel.DOZE_AOD)
|
||||
.sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
|
||||
.collect { pair ->
|
||||
val (dozeToAod, lastStartedStep) = pair
|
||||
if (lastStartedStep.to == KeyguardState.LOCKSCREEN) {
|
||||
keyguardInteractor.wakefulnessModel
|
||||
.sample(
|
||||
combine(
|
||||
keyguardTransitionInteractor.startedKeyguardTransitionStep,
|
||||
keyguardInteractor.isAodAvailable,
|
||||
::Pair
|
||||
),
|
||||
::toTriple
|
||||
)
|
||||
.collect { (wakefulnessState, lastStartedStep, isAodAvailable) ->
|
||||
if (
|
||||
lastStartedStep.to == KeyguardState.LOCKSCREEN &&
|
||||
wakefulnessState.state == WakefulnessState.STARTING_TO_SLEEP
|
||||
) {
|
||||
keyguardTransitionRepository.startTransition(
|
||||
TransitionInfo(
|
||||
name,
|
||||
KeyguardState.LOCKSCREEN,
|
||||
KeyguardState.AOD,
|
||||
if (isAodAvailable) {
|
||||
KeyguardState.AOD
|
||||
} else {
|
||||
KeyguardState.DOZING
|
||||
},
|
||||
getAnimator(),
|
||||
)
|
||||
)
|
||||
|
||||
@@ -23,12 +23,14 @@ import com.android.systemui.dagger.qualifiers.Application
|
||||
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
|
||||
import com.android.systemui.keyguard.shared.model.KeyguardState
|
||||
import com.android.systemui.keyguard.shared.model.TransitionInfo
|
||||
import com.android.systemui.keyguard.shared.model.WakefulnessState
|
||||
import com.android.systemui.util.kotlin.sample
|
||||
import javax.inject.Inject
|
||||
import kotlin.time.Duration
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@SysUISingleton
|
||||
@@ -44,6 +46,7 @@ constructor(
|
||||
override fun start() {
|
||||
listenForOccludedToLockscreen()
|
||||
listenForOccludedToDreaming()
|
||||
listenForOccludedToAodOrDozing()
|
||||
}
|
||||
|
||||
private fun listenForOccludedToDreaming() {
|
||||
@@ -70,8 +73,7 @@ constructor(
|
||||
scope.launch {
|
||||
keyguardInteractor.isKeyguardOccluded
|
||||
.sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
|
||||
.collect { pair ->
|
||||
val (isOccluded, lastStartedKeyguardState) = pair
|
||||
.collect { (isOccluded, lastStartedKeyguardState) ->
|
||||
// Occlusion signals come from the framework, and should interrupt any
|
||||
// existing transition
|
||||
if (!isOccluded && lastStartedKeyguardState.to == KeyguardState.OCCLUDED) {
|
||||
@@ -88,6 +90,39 @@ constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun listenForOccludedToAodOrDozing() {
|
||||
scope.launch {
|
||||
keyguardInteractor.wakefulnessModel
|
||||
.sample(
|
||||
combine(
|
||||
keyguardTransitionInteractor.startedKeyguardTransitionStep,
|
||||
keyguardInteractor.isAodAvailable,
|
||||
::Pair
|
||||
),
|
||||
::toTriple
|
||||
)
|
||||
.collect { (wakefulnessState, lastStartedStep, isAodAvailable) ->
|
||||
if (
|
||||
lastStartedStep.to == KeyguardState.OCCLUDED &&
|
||||
wakefulnessState.state == WakefulnessState.STARTING_TO_SLEEP
|
||||
) {
|
||||
keyguardTransitionRepository.startTransition(
|
||||
TransitionInfo(
|
||||
name,
|
||||
KeyguardState.OCCLUDED,
|
||||
if (isAodAvailable) {
|
||||
KeyguardState.AOD
|
||||
} else {
|
||||
KeyguardState.DOZING
|
||||
},
|
||||
getAnimator(),
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getAnimator(duration: Duration = DEFAULT_DURATION): ValueAnimator {
|
||||
return ValueAnimator().apply {
|
||||
setInterpolator(Interpolators.LINEAR)
|
||||
|
||||
@@ -57,6 +57,8 @@ constructor(
|
||||
val dozeAmount: Flow<Float> = repository.linearDozeAmount
|
||||
/** Whether the system is in doze mode. */
|
||||
val isDozing: Flow<Boolean> = repository.isDozing
|
||||
/** Whether Always-on Display mode is available. */
|
||||
val isAodAvailable: Flow<Boolean> = repository.isAodAvailable
|
||||
/** Doze transition information. */
|
||||
val dozeTransitionModel: Flow<DozeTransitionModel> = repository.dozeTransitionModel
|
||||
/**
|
||||
|
||||
@@ -4262,8 +4262,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
|
||||
|
||||
@Override
|
||||
public void onDozeAmountChanged(float linear, float eased) {
|
||||
if (mFeatureFlags.isEnabled(Flags.LOCKSCREEN_ANIMATIONS)
|
||||
&& !mFeatureFlags.isEnabled(Flags.LIGHT_REVEAL_MIGRATION)
|
||||
if (!mFeatureFlags.isEnabled(Flags.LIGHT_REVEAL_MIGRATION)
|
||||
&& !(mLightRevealScrim.getRevealEffect() instanceof CircleReveal)) {
|
||||
mLightRevealScrim.setRevealAmount(1f - linear);
|
||||
}
|
||||
|
||||
@@ -44,10 +44,9 @@ import com.android.systemui.dagger.qualifiers.Main;
|
||||
import com.android.systemui.doze.AlwaysOnDisplayPolicy;
|
||||
import com.android.systemui.doze.DozeScreenState;
|
||||
import com.android.systemui.dump.DumpManager;
|
||||
import com.android.systemui.flags.FeatureFlags;
|
||||
import com.android.systemui.flags.Flags;
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||
import com.android.systemui.statusbar.policy.BatteryController;
|
||||
import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
|
||||
import com.android.systemui.statusbar.policy.ConfigurationController;
|
||||
import com.android.systemui.statusbar.policy.DevicePostureController;
|
||||
import com.android.systemui.tuner.TunerService;
|
||||
@@ -82,7 +81,6 @@ public class DozeParameters implements
|
||||
private final AlwaysOnDisplayPolicy mAlwaysOnPolicy;
|
||||
private final Resources mResources;
|
||||
private final BatteryController mBatteryController;
|
||||
private final FeatureFlags mFeatureFlags;
|
||||
private final ScreenOffAnimationController mScreenOffAnimationController;
|
||||
private final FoldAodAnimationController mFoldAodAnimationController;
|
||||
private final UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
|
||||
@@ -125,7 +123,6 @@ public class DozeParameters implements
|
||||
BatteryController batteryController,
|
||||
TunerService tunerService,
|
||||
DumpManager dumpManager,
|
||||
FeatureFlags featureFlags,
|
||||
ScreenOffAnimationController screenOffAnimationController,
|
||||
Optional<SysUIUnfoldComponent> sysUiUnfoldComponent,
|
||||
UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
|
||||
@@ -141,7 +138,6 @@ public class DozeParameters implements
|
||||
mControlScreenOffAnimation = !getDisplayNeedsBlanking();
|
||||
mPowerManager = powerManager;
|
||||
mPowerManager.setDozeAfterScreenOff(!mControlScreenOffAnimation);
|
||||
mFeatureFlags = featureFlags;
|
||||
mScreenOffAnimationController = screenOffAnimationController;
|
||||
mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController;
|
||||
|
||||
@@ -162,6 +158,13 @@ public class DozeParameters implements
|
||||
|
||||
SettingsObserver quickPickupSettingsObserver = new SettingsObserver(context, handler);
|
||||
quickPickupSettingsObserver.observe();
|
||||
|
||||
batteryController.addCallback(new BatteryStateChangeCallback() {
|
||||
@Override
|
||||
public void onPowerSaveChanged(boolean isPowerSave) {
|
||||
dispatchAlwaysOnEvent();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void updateQuickPickupEnabled() {
|
||||
@@ -300,13 +303,10 @@ public class DozeParameters implements
|
||||
|
||||
/**
|
||||
* Whether we're capable of controlling the screen off animation if we want to. This isn't
|
||||
* possible if AOD isn't even enabled or if the flag is disabled, or if the display needs
|
||||
* blanking.
|
||||
* possible if AOD isn't even enabled or if the display needs blanking.
|
||||
*/
|
||||
public boolean canControlUnlockedScreenOff() {
|
||||
return getAlwaysOn()
|
||||
&& mFeatureFlags.isEnabled(Flags.LOCKSCREEN_ANIMATIONS)
|
||||
&& !getDisplayNeedsBlanking();
|
||||
return getAlwaysOn() && !getDisplayNeedsBlanking();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -424,9 +424,7 @@ public class DozeParameters implements
|
||||
updateControlScreenOff();
|
||||
}
|
||||
|
||||
for (Callback callback : mCallbacks) {
|
||||
callback.onAlwaysOnChange();
|
||||
}
|
||||
dispatchAlwaysOnEvent();
|
||||
mScreenOffAnimationController.onAlwaysOnChanged(getAlwaysOn());
|
||||
}
|
||||
|
||||
@@ -463,6 +461,12 @@ public class DozeParameters implements
|
||||
pw.print("isQuickPickupEnabled(): "); pw.println(isQuickPickupEnabled());
|
||||
}
|
||||
|
||||
private void dispatchAlwaysOnEvent() {
|
||||
for (Callback callback : mCallbacks) {
|
||||
callback.onAlwaysOnChange();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean getPostureSpecificBool(
|
||||
int[] postureMapping,
|
||||
boolean defaultSensorBool,
|
||||
@@ -477,7 +481,8 @@ public class DozeParameters implements
|
||||
return bool;
|
||||
}
|
||||
|
||||
interface Callback {
|
||||
/** Callbacks for doze parameter related information */
|
||||
public interface Callback {
|
||||
/**
|
||||
* Invoked when the value of getAlwaysOn may have changed.
|
||||
*/
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.android.keyguard.KeyguardUpdateMonitorCallback
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.biometrics.AuthController
|
||||
import com.android.systemui.common.shared.model.Position
|
||||
import com.android.systemui.coroutines.collectLastValue
|
||||
import com.android.systemui.doze.DozeHost
|
||||
import com.android.systemui.doze.DozeMachine
|
||||
import com.android.systemui.doze.DozeTransitionCallback
|
||||
@@ -38,14 +39,17 @@ import com.android.systemui.keyguard.shared.model.WakefulnessModel
|
||||
import com.android.systemui.keyguard.shared.model.WakefulnessState
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController
|
||||
import com.android.systemui.statusbar.phone.BiometricUnlockController
|
||||
import com.android.systemui.statusbar.phone.DozeParameters
|
||||
import com.android.systemui.statusbar.policy.KeyguardStateController
|
||||
import com.android.systemui.util.mockito.argumentCaptor
|
||||
import com.android.systemui.util.mockito.whenever
|
||||
import com.android.systemui.util.mockito.withArgCaptor
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onCompletion
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
||||
import kotlinx.coroutines.test.runCurrent
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
@@ -68,6 +72,7 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
|
||||
@Mock private lateinit var authController: AuthController
|
||||
@Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
|
||||
@Mock private lateinit var dreamOverlayCallbackController: DreamOverlayCallbackController
|
||||
@Mock private lateinit var dozeParameters: DozeParameters
|
||||
|
||||
private lateinit var underTest: KeyguardRepositoryImpl
|
||||
|
||||
@@ -84,6 +89,7 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
|
||||
keyguardStateController,
|
||||
keyguardUpdateMonitor,
|
||||
dozeTransitionListener,
|
||||
dozeParameters,
|
||||
authController,
|
||||
dreamOverlayCallbackController,
|
||||
)
|
||||
@@ -169,6 +175,26 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isAodAvailable() = runTest {
|
||||
val flow = underTest.isAodAvailable
|
||||
var isAodAvailable = collectLastValue(flow)
|
||||
runCurrent()
|
||||
|
||||
val callback =
|
||||
withArgCaptor<DozeParameters.Callback> { verify(dozeParameters).addCallback(capture()) }
|
||||
|
||||
whenever(dozeParameters.getAlwaysOn()).thenReturn(false)
|
||||
callback.onAlwaysOnChange()
|
||||
assertThat(isAodAvailable()).isEqualTo(false)
|
||||
|
||||
whenever(dozeParameters.getAlwaysOn()).thenReturn(true)
|
||||
callback.onAlwaysOnChange()
|
||||
assertThat(isAodAvailable()).isEqualTo(true)
|
||||
|
||||
flow.onCompletion { verify(dozeParameters).removeCallback(callback) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isKeyguardOccluded() =
|
||||
runTest(UnconfinedTestDispatcher()) {
|
||||
|
||||
@@ -71,6 +71,10 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
|
||||
|
||||
private lateinit var fromLockscreenTransitionInteractor: FromLockscreenTransitionInteractor
|
||||
private lateinit var fromDreamingTransitionInteractor: FromDreamingTransitionInteractor
|
||||
private lateinit var fromDozingTransitionInteractor: FromDozingTransitionInteractor
|
||||
private lateinit var fromOccludedTransitionInteractor: FromOccludedTransitionInteractor
|
||||
private lateinit var fromGoneTransitionInteractor: FromGoneTransitionInteractor
|
||||
private lateinit var fromAodTransitionInteractor: FromAodTransitionInteractor
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
@@ -102,6 +106,42 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
|
||||
keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
|
||||
)
|
||||
fromDreamingTransitionInteractor.start()
|
||||
|
||||
fromAodTransitionInteractor =
|
||||
FromAodTransitionInteractor(
|
||||
scope = testScope,
|
||||
keyguardInteractor = KeyguardInteractor(keyguardRepository, commandQueue),
|
||||
keyguardTransitionRepository = mockTransitionRepository,
|
||||
keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
|
||||
)
|
||||
fromAodTransitionInteractor.start()
|
||||
|
||||
fromGoneTransitionInteractor =
|
||||
FromGoneTransitionInteractor(
|
||||
scope = testScope,
|
||||
keyguardInteractor = KeyguardInteractor(keyguardRepository, commandQueue),
|
||||
keyguardTransitionRepository = mockTransitionRepository,
|
||||
keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
|
||||
)
|
||||
fromGoneTransitionInteractor.start()
|
||||
|
||||
fromDozingTransitionInteractor =
|
||||
FromDozingTransitionInteractor(
|
||||
scope = testScope,
|
||||
keyguardInteractor = KeyguardInteractor(keyguardRepository, commandQueue),
|
||||
keyguardTransitionRepository = mockTransitionRepository,
|
||||
keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
|
||||
)
|
||||
fromDozingTransitionInteractor.start()
|
||||
|
||||
fromOccludedTransitionInteractor =
|
||||
FromOccludedTransitionInteractor(
|
||||
scope = testScope,
|
||||
keyguardInteractor = KeyguardInteractor(keyguardRepository, commandQueue),
|
||||
keyguardTransitionRepository = mockTransitionRepository,
|
||||
keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
|
||||
)
|
||||
fromOccludedTransitionInteractor.start()
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -192,6 +232,289 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
|
||||
coroutineContext.cancelChildren()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `OCCLUDED to DOZING`() =
|
||||
testScope.runTest {
|
||||
// GIVEN a device with AOD not available
|
||||
keyguardRepository.setAodAvailable(false)
|
||||
runCurrent()
|
||||
|
||||
// GIVEN a prior transition has run to OCCLUDED
|
||||
runner.startTransition(
|
||||
testScope,
|
||||
TransitionInfo(
|
||||
ownerName = "",
|
||||
from = KeyguardState.LOCKSCREEN,
|
||||
to = KeyguardState.OCCLUDED,
|
||||
animator =
|
||||
ValueAnimator().apply {
|
||||
duration = 10
|
||||
interpolator = Interpolators.LINEAR
|
||||
},
|
||||
)
|
||||
)
|
||||
runCurrent()
|
||||
reset(mockTransitionRepository)
|
||||
|
||||
// WHEN the device begins to sleep
|
||||
keyguardRepository.setWakefulnessModel(startingToSleep())
|
||||
runCurrent()
|
||||
|
||||
val info =
|
||||
withArgCaptor<TransitionInfo> {
|
||||
verify(mockTransitionRepository).startTransition(capture())
|
||||
}
|
||||
// THEN a transition to DOZING should occur
|
||||
assertThat(info.ownerName).isEqualTo("FromOccludedTransitionInteractor")
|
||||
assertThat(info.from).isEqualTo(KeyguardState.OCCLUDED)
|
||||
assertThat(info.to).isEqualTo(KeyguardState.DOZING)
|
||||
assertThat(info.animator).isNotNull()
|
||||
|
||||
coroutineContext.cancelChildren()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `OCCLUDED to AOD`() =
|
||||
testScope.runTest {
|
||||
// GIVEN a device with AOD available
|
||||
keyguardRepository.setAodAvailable(true)
|
||||
runCurrent()
|
||||
|
||||
// GIVEN a prior transition has run to OCCLUDED
|
||||
runner.startTransition(
|
||||
testScope,
|
||||
TransitionInfo(
|
||||
ownerName = "",
|
||||
from = KeyguardState.LOCKSCREEN,
|
||||
to = KeyguardState.OCCLUDED,
|
||||
animator =
|
||||
ValueAnimator().apply {
|
||||
duration = 10
|
||||
interpolator = Interpolators.LINEAR
|
||||
},
|
||||
)
|
||||
)
|
||||
runCurrent()
|
||||
reset(mockTransitionRepository)
|
||||
|
||||
// WHEN the device begins to sleep
|
||||
keyguardRepository.setWakefulnessModel(startingToSleep())
|
||||
runCurrent()
|
||||
|
||||
val info =
|
||||
withArgCaptor<TransitionInfo> {
|
||||
verify(mockTransitionRepository).startTransition(capture())
|
||||
}
|
||||
// THEN a transition to DOZING should occur
|
||||
assertThat(info.ownerName).isEqualTo("FromOccludedTransitionInteractor")
|
||||
assertThat(info.from).isEqualTo(KeyguardState.OCCLUDED)
|
||||
assertThat(info.to).isEqualTo(KeyguardState.AOD)
|
||||
assertThat(info.animator).isNotNull()
|
||||
|
||||
coroutineContext.cancelChildren()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `LOCKSCREEN to DOZING`() =
|
||||
testScope.runTest {
|
||||
// GIVEN a device with AOD not available
|
||||
keyguardRepository.setAodAvailable(false)
|
||||
runCurrent()
|
||||
|
||||
// GIVEN a prior transition has run to LOCKSCREEN
|
||||
runner.startTransition(
|
||||
testScope,
|
||||
TransitionInfo(
|
||||
ownerName = "",
|
||||
from = KeyguardState.GONE,
|
||||
to = KeyguardState.LOCKSCREEN,
|
||||
animator =
|
||||
ValueAnimator().apply {
|
||||
duration = 10
|
||||
interpolator = Interpolators.LINEAR
|
||||
},
|
||||
)
|
||||
)
|
||||
runCurrent()
|
||||
reset(mockTransitionRepository)
|
||||
|
||||
// WHEN the device begins to sleep
|
||||
keyguardRepository.setWakefulnessModel(startingToSleep())
|
||||
runCurrent()
|
||||
|
||||
val info =
|
||||
withArgCaptor<TransitionInfo> {
|
||||
verify(mockTransitionRepository).startTransition(capture())
|
||||
}
|
||||
// THEN a transition to DOZING should occur
|
||||
assertThat(info.ownerName).isEqualTo("FromLockscreenTransitionInteractor")
|
||||
assertThat(info.from).isEqualTo(KeyguardState.LOCKSCREEN)
|
||||
assertThat(info.to).isEqualTo(KeyguardState.DOZING)
|
||||
assertThat(info.animator).isNotNull()
|
||||
|
||||
coroutineContext.cancelChildren()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `LOCKSCREEN to AOD`() =
|
||||
testScope.runTest {
|
||||
// GIVEN a device with AOD available
|
||||
keyguardRepository.setAodAvailable(true)
|
||||
runCurrent()
|
||||
|
||||
// GIVEN a prior transition has run to LOCKSCREEN
|
||||
runner.startTransition(
|
||||
testScope,
|
||||
TransitionInfo(
|
||||
ownerName = "",
|
||||
from = KeyguardState.GONE,
|
||||
to = KeyguardState.LOCKSCREEN,
|
||||
animator =
|
||||
ValueAnimator().apply {
|
||||
duration = 10
|
||||
interpolator = Interpolators.LINEAR
|
||||
},
|
||||
)
|
||||
)
|
||||
runCurrent()
|
||||
reset(mockTransitionRepository)
|
||||
|
||||
// WHEN the device begins to sleep
|
||||
keyguardRepository.setWakefulnessModel(startingToSleep())
|
||||
runCurrent()
|
||||
|
||||
val info =
|
||||
withArgCaptor<TransitionInfo> {
|
||||
verify(mockTransitionRepository).startTransition(capture())
|
||||
}
|
||||
// THEN a transition to DOZING should occur
|
||||
assertThat(info.ownerName).isEqualTo("FromLockscreenTransitionInteractor")
|
||||
assertThat(info.from).isEqualTo(KeyguardState.LOCKSCREEN)
|
||||
assertThat(info.to).isEqualTo(KeyguardState.AOD)
|
||||
assertThat(info.animator).isNotNull()
|
||||
|
||||
coroutineContext.cancelChildren()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `DOZING to LOCKSCREEN`() =
|
||||
testScope.runTest {
|
||||
// GIVEN a prior transition has run to DOZING
|
||||
runner.startTransition(
|
||||
testScope,
|
||||
TransitionInfo(
|
||||
ownerName = "",
|
||||
from = KeyguardState.LOCKSCREEN,
|
||||
to = KeyguardState.DOZING,
|
||||
animator =
|
||||
ValueAnimator().apply {
|
||||
duration = 10
|
||||
interpolator = Interpolators.LINEAR
|
||||
},
|
||||
)
|
||||
)
|
||||
runCurrent()
|
||||
reset(mockTransitionRepository)
|
||||
|
||||
// WHEN the device begins to wake
|
||||
keyguardRepository.setWakefulnessModel(startingToWake())
|
||||
runCurrent()
|
||||
|
||||
val info =
|
||||
withArgCaptor<TransitionInfo> {
|
||||
verify(mockTransitionRepository).startTransition(capture())
|
||||
}
|
||||
// THEN a transition to DOZING should occur
|
||||
assertThat(info.ownerName).isEqualTo("FromDozingTransitionInteractor")
|
||||
assertThat(info.from).isEqualTo(KeyguardState.DOZING)
|
||||
assertThat(info.to).isEqualTo(KeyguardState.LOCKSCREEN)
|
||||
assertThat(info.animator).isNotNull()
|
||||
|
||||
coroutineContext.cancelChildren()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GONE to DOZING`() =
|
||||
testScope.runTest {
|
||||
// GIVEN a device with AOD not available
|
||||
keyguardRepository.setAodAvailable(false)
|
||||
runCurrent()
|
||||
|
||||
// GIVEN a prior transition has run to GONE
|
||||
runner.startTransition(
|
||||
testScope,
|
||||
TransitionInfo(
|
||||
ownerName = "",
|
||||
from = KeyguardState.LOCKSCREEN,
|
||||
to = KeyguardState.GONE,
|
||||
animator =
|
||||
ValueAnimator().apply {
|
||||
duration = 10
|
||||
interpolator = Interpolators.LINEAR
|
||||
},
|
||||
)
|
||||
)
|
||||
runCurrent()
|
||||
reset(mockTransitionRepository)
|
||||
|
||||
// WHEN the device begins to sleep
|
||||
keyguardRepository.setWakefulnessModel(startingToSleep())
|
||||
runCurrent()
|
||||
|
||||
val info =
|
||||
withArgCaptor<TransitionInfo> {
|
||||
verify(mockTransitionRepository).startTransition(capture())
|
||||
}
|
||||
// THEN a transition to DOZING should occur
|
||||
assertThat(info.ownerName).isEqualTo("FromGoneTransitionInteractor")
|
||||
assertThat(info.from).isEqualTo(KeyguardState.GONE)
|
||||
assertThat(info.to).isEqualTo(KeyguardState.DOZING)
|
||||
assertThat(info.animator).isNotNull()
|
||||
|
||||
coroutineContext.cancelChildren()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GONE to AOD`() =
|
||||
testScope.runTest {
|
||||
// GIVEN a device with AOD available
|
||||
keyguardRepository.setAodAvailable(true)
|
||||
runCurrent()
|
||||
|
||||
// GIVEN a prior transition has run to GONE
|
||||
runner.startTransition(
|
||||
testScope,
|
||||
TransitionInfo(
|
||||
ownerName = "",
|
||||
from = KeyguardState.LOCKSCREEN,
|
||||
to = KeyguardState.GONE,
|
||||
animator =
|
||||
ValueAnimator().apply {
|
||||
duration = 10
|
||||
interpolator = Interpolators.LINEAR
|
||||
},
|
||||
)
|
||||
)
|
||||
runCurrent()
|
||||
reset(mockTransitionRepository)
|
||||
|
||||
// WHEN the device begins to sleep
|
||||
keyguardRepository.setWakefulnessModel(startingToSleep())
|
||||
runCurrent()
|
||||
|
||||
val info =
|
||||
withArgCaptor<TransitionInfo> {
|
||||
verify(mockTransitionRepository).startTransition(capture())
|
||||
}
|
||||
// THEN a transition to DOZING should occur
|
||||
assertThat(info.ownerName).isEqualTo("FromGoneTransitionInteractor")
|
||||
assertThat(info.from).isEqualTo(KeyguardState.GONE)
|
||||
assertThat(info.to).isEqualTo(KeyguardState.AOD)
|
||||
assertThat(info.animator).isNotNull()
|
||||
|
||||
coroutineContext.cancelChildren()
|
||||
}
|
||||
|
||||
private fun startingToWake() =
|
||||
WakefulnessModel(
|
||||
WakefulnessState.STARTING_TO_WAKE,
|
||||
@@ -199,4 +522,12 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
|
||||
WakeSleepReason.OTHER,
|
||||
WakeSleepReason.OTHER
|
||||
)
|
||||
|
||||
private fun startingToSleep() =
|
||||
WakefulnessModel(
|
||||
WakefulnessState.STARTING_TO_SLEEP,
|
||||
true,
|
||||
WakeSleepReason.OTHER,
|
||||
WakeSleepReason.OTHER
|
||||
)
|
||||
}
|
||||
|
||||
@@ -23,6 +23,10 @@ import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.reset;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.res.Resources;
|
||||
@@ -39,10 +43,9 @@ import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.doze.AlwaysOnDisplayPolicy;
|
||||
import com.android.systemui.doze.DozeScreenState;
|
||||
import com.android.systemui.dump.DumpManager;
|
||||
import com.android.systemui.flags.FeatureFlags;
|
||||
import com.android.systemui.flags.Flags;
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||
import com.android.systemui.statusbar.policy.BatteryController;
|
||||
import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
|
||||
import com.android.systemui.statusbar.policy.ConfigurationController;
|
||||
import com.android.systemui.tuner.TunerService;
|
||||
import com.android.systemui.unfold.FoldAodAnimationController;
|
||||
@@ -52,6 +55,8 @@ import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Captor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@@ -69,7 +74,6 @@ public class DozeParametersTest extends SysuiTestCase {
|
||||
@Mock private PowerManager mPowerManager;
|
||||
@Mock private TunerService mTunerService;
|
||||
@Mock private BatteryController mBatteryController;
|
||||
@Mock private FeatureFlags mFeatureFlags;
|
||||
@Mock private DumpManager mDumpManager;
|
||||
@Mock private ScreenOffAnimationController mScreenOffAnimationController;
|
||||
@Mock private FoldAodAnimationController mFoldAodAnimationController;
|
||||
@@ -78,6 +82,7 @@ public class DozeParametersTest extends SysuiTestCase {
|
||||
@Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
|
||||
@Mock private StatusBarStateController mStatusBarStateController;
|
||||
@Mock private ConfigurationController mConfigurationController;
|
||||
@Captor private ArgumentCaptor<BatteryStateChangeCallback> mBatteryStateChangeCallback;
|
||||
|
||||
/**
|
||||
* The current value of PowerManager's dozeAfterScreenOff property.
|
||||
@@ -113,7 +118,6 @@ public class DozeParametersTest extends SysuiTestCase {
|
||||
mBatteryController,
|
||||
mTunerService,
|
||||
mDumpManager,
|
||||
mFeatureFlags,
|
||||
mScreenOffAnimationController,
|
||||
Optional.of(mSysUIUnfoldComponent),
|
||||
mUnlockedScreenOffAnimationController,
|
||||
@@ -122,7 +126,8 @@ public class DozeParametersTest extends SysuiTestCase {
|
||||
mStatusBarStateController
|
||||
);
|
||||
|
||||
when(mFeatureFlags.isEnabled(Flags.LOCKSCREEN_ANIMATIONS)).thenReturn(true);
|
||||
verify(mBatteryController).addCallback(mBatteryStateChangeCallback.capture());
|
||||
|
||||
setAodEnabledForTest(true);
|
||||
setShouldControlUnlockedScreenOffForTest(true);
|
||||
setDisplayNeedsBlankingForTest(false);
|
||||
@@ -173,6 +178,29 @@ public class DozeParametersTest extends SysuiTestCase {
|
||||
assertThat(mDozeParameters.getAlwaysOn()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAlwaysOn_whenBatterySaverCallback() {
|
||||
DozeParameters.Callback callback = mock(DozeParameters.Callback.class);
|
||||
mDozeParameters.addCallback(callback);
|
||||
|
||||
when(mAmbientDisplayConfiguration.alwaysOnEnabled(anyInt())).thenReturn(true);
|
||||
when(mBatteryController.isAodPowerSave()).thenReturn(true);
|
||||
|
||||
// Both lines should trigger an event
|
||||
mDozeParameters.onTuningChanged(Settings.Secure.DOZE_ALWAYS_ON, "1");
|
||||
mBatteryStateChangeCallback.getValue().onPowerSaveChanged(true);
|
||||
|
||||
verify(callback, times(2)).onAlwaysOnChange();
|
||||
assertThat(mDozeParameters.getAlwaysOn()).isFalse();
|
||||
|
||||
reset(callback);
|
||||
when(mBatteryController.isAodPowerSave()).thenReturn(false);
|
||||
mBatteryStateChangeCallback.getValue().onPowerSaveChanged(true);
|
||||
|
||||
verify(callback).onAlwaysOnChange();
|
||||
assertThat(mDozeParameters.getAlwaysOn()).isTrue();
|
||||
}
|
||||
|
||||
/**
|
||||
* PowerManager.setDozeAfterScreenOff(true) means we are not controlling screen off, and calling
|
||||
* it with false means we are. Confusing, but sure - make sure that we call PowerManager with
|
||||
@@ -195,17 +223,6 @@ public class DozeParametersTest extends SysuiTestCase {
|
||||
assertFalse(mPowerManagerDozeAfterScreenOff);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testControlUnlockedScreenOffAnimationDisabled_dozeAfterScreenOff() {
|
||||
when(mFeatureFlags.isEnabled(Flags.LOCKSCREEN_ANIMATIONS)).thenReturn(false);
|
||||
|
||||
assertFalse(mDozeParameters.shouldControlUnlockedScreenOff());
|
||||
|
||||
// Trigger the setter for the current value.
|
||||
mDozeParameters.setControlScreenOffAnimation(mDozeParameters.shouldControlScreenOff());
|
||||
assertFalse(mDozeParameters.shouldControlScreenOff());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void propagatesAnimateScreenOff_noAlwaysOn() {
|
||||
setAodEnabledForTest(false);
|
||||
|
||||
@@ -52,6 +52,9 @@ class FakeKeyguardRepository : KeyguardRepository {
|
||||
private val _isDozing = MutableStateFlow(false)
|
||||
override val isDozing: Flow<Boolean> = _isDozing
|
||||
|
||||
private val _isAodAvailable = MutableStateFlow(false)
|
||||
override val isAodAvailable: Flow<Boolean> = _isAodAvailable
|
||||
|
||||
private val _isDreaming = MutableStateFlow(false)
|
||||
override val isDreaming: Flow<Boolean> = _isDreaming
|
||||
|
||||
@@ -126,6 +129,10 @@ class FakeKeyguardRepository : KeyguardRepository {
|
||||
_isDozing.value = isDozing
|
||||
}
|
||||
|
||||
fun setAodAvailable(isAodAvailable: Boolean) {
|
||||
_isAodAvailable.value = isAodAvailable
|
||||
}
|
||||
|
||||
fun setDreamingWithOverlay(isDreaming: Boolean) {
|
||||
_isDreamingWithOverlay.value = isDreaming
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user