diff options
| author | 2023-01-11 15:07:11 +0000 | |
|---|---|---|
| committer | 2023-01-11 15:07:11 +0000 | |
| commit | c36131f6f3f479e324b2e10927898b8d14ce677c (patch) | |
| tree | 6894e7712921ffb5f0bbbb4325bbbeb1b76229e9 | |
| parent | 52388f923068d6391cda0b8f3d3a7aef73c60582 (diff) | |
| parent | fef981cbb7f067ec62ca30c91872fea4cfc01488 (diff) | |
Merge "Transitions - Better dozing/aod support" into tm-qpr-dev
13 files changed, 536 insertions, 61 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt index d015b1580385..0c0d5a66890c 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt @@ -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") diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt index a4fd087a24b1..d99af90ab6dc 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt @@ -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 = diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt index fd2d271e40f9..ce61f2fec92f 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt @@ -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( diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt index 553fafeb92c3..9203a9b924a7 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt @@ -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 } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt index 20c6531d580b..64028ceb2fbe 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt @@ -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(), ) ) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt index 88789019b10f..2dc8fee25379 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt @@ -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) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt index ac2d230ee605..490d22eb0820 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt @@ -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 /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java index 8f2704521d95..f1e1f426b467 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java @@ -4266,8 +4266,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); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java index de7b152adaab..0446cefb10dc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java @@ -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. */ diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt index be712f699b7b..f997d18a57a5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt @@ -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, ) @@ -170,6 +176,26 @@ class KeyguardRepositoryImplTest : SysuiTestCase() { } @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()) { whenever(keyguardStateController.isOccluded).thenReturn(false) diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt index 754adfdc48b3..b3cee2273012 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt @@ -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 + ) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java index 077b41a0aa90..c8438501b3e6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java @@ -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 @@ -196,17 +224,6 @@ public class DozeParametersTest extends SysuiTestCase { } @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); setDisplayNeedsBlankingForTest(false); diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt index 39d2ecaef51a..15b473640de7 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt @@ -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 } |