Merge "Transitions - Better dozing/aod support" into tm-qpr-dev

This commit is contained in:
Matt Pietal
2023-01-11 15:07:11 +00:00
committed by Android (Google) Code Review
13 changed files with 536 additions and 61 deletions

View File

@@ -114,8 +114,6 @@ object Flags {
// ** Flag retired ** // ** Flag retired **
// public static final BooleanFlag KEYGUARD_LAYOUT = // public static final BooleanFlag KEYGUARD_LAYOUT =
// new BooleanFlag(200, true); // new BooleanFlag(200, true);
// TODO(b/254512713): Tracking Bug
@JvmField val LOCKSCREEN_ANIMATIONS = releasedFlag(201, "lockscreen_animations")
// TODO(b/254512750): Tracking Bug // TODO(b/254512750): Tracking Bug
val NEW_UNLOCK_SWIPE_ANIMATION = releasedFlag(202, "new_unlock_swipe_animation") val NEW_UNLOCK_SWIPE_ANIMATION = releasedFlag(202, "new_unlock_swipe_animation")

View File

@@ -40,6 +40,7 @@ import com.android.systemui.keyguard.shared.model.WakefulnessModel
import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.phone.BiometricUnlockController import com.android.systemui.statusbar.phone.BiometricUnlockController
import com.android.systemui.statusbar.phone.BiometricUnlockController.WakeAndUnlockMode import com.android.systemui.statusbar.phone.BiometricUnlockController.WakeAndUnlockMode
import com.android.systemui.statusbar.phone.DozeParameters
import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.statusbar.policy.KeyguardStateController
import javax.inject.Inject import javax.inject.Inject
import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.channels.awaitClose
@@ -88,6 +89,9 @@ interface KeyguardRepository {
/** Observable for whether the bouncer is showing. */ /** Observable for whether the bouncer is showing. */
val isBouncerShowing: Flow<Boolean> 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. * Observable for whether we are in doze state.
* *
@@ -182,6 +186,7 @@ constructor(
private val keyguardStateController: KeyguardStateController, private val keyguardStateController: KeyguardStateController,
private val keyguardUpdateMonitor: KeyguardUpdateMonitor, private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
private val dozeTransitionListener: DozeTransitionListener, private val dozeTransitionListener: DozeTransitionListener,
private val dozeParameters: DozeParameters,
private val authController: AuthController, private val authController: AuthController,
private val dreamOverlayCallbackController: DreamOverlayCallbackController, private val dreamOverlayCallbackController: DreamOverlayCallbackController,
) : KeyguardRepository { ) : KeyguardRepository {
@@ -220,6 +225,31 @@ constructor(
} }
.distinctUntilChanged() .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> = override val isKeyguardOccluded: Flow<Boolean> =
conflatedCallbackFlow { conflatedCallbackFlow {
val callback = val callback =

View File

@@ -21,9 +21,9 @@ import com.android.systemui.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository 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.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionInfo 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 com.android.systemui.util.kotlin.sample
import javax.inject.Inject import javax.inject.Inject
import kotlin.time.Duration import kotlin.time.Duration
@@ -48,12 +48,11 @@ constructor(
private fun listenForDozingToLockscreen() { private fun listenForDozingToLockscreen() {
scope.launch { scope.launch {
keyguardInteractor.dozeTransitionModel keyguardInteractor.wakefulnessModel
.sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair) .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
.collect { pair -> .collect { (wakefulnessModel, lastStartedTransition) ->
val (dozeTransitionModel, lastStartedTransition) = pair
if ( if (
isDozeOff(dozeTransitionModel.to) && isWakingOrStartingToWake(wakefulnessModel) &&
lastStartedTransition.to == KeyguardState.DOZING lastStartedTransition.to == KeyguardState.DOZING
) { ) {
keyguardTransitionRepository.startTransition( keyguardTransitionRepository.startTransition(

View File

@@ -26,7 +26,10 @@ import com.android.systemui.keyguard.shared.model.TransitionInfo
import com.android.systemui.keyguard.shared.model.WakefulnessState import com.android.systemui.keyguard.shared.model.WakefulnessState
import com.android.systemui.util.kotlin.sample import com.android.systemui.util.kotlin.sample
import javax.inject.Inject import javax.inject.Inject
import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@SysUISingleton @SysUISingleton
@@ -40,7 +43,7 @@ constructor(
) : TransitionInteractor(FromGoneTransitionInteractor::class.simpleName!!) { ) : TransitionInteractor(FromGoneTransitionInteractor::class.simpleName!!) {
override fun start() { override fun start() {
listenForGoneToAod() listenForGoneToAodOrDozing()
listenForGoneToDreaming() listenForGoneToDreaming()
} }
@@ -56,7 +59,7 @@ constructor(
name, name,
KeyguardState.GONE, KeyguardState.GONE,
KeyguardState.DREAMING, KeyguardState.DREAMING,
getAnimator(), getAnimator(TO_DREAMING_DURATION),
) )
) )
} }
@@ -64,12 +67,18 @@ constructor(
} }
} }
private fun listenForGoneToAod() { private fun listenForGoneToAodOrDozing() {
scope.launch { scope.launch {
keyguardInteractor.wakefulnessModel keyguardInteractor.wakefulnessModel
.sample(keyguardTransitionInteractor.finishedKeyguardState, ::Pair) .sample(
.collect { pair -> combine(
val (wakefulnessState, keyguardState) = pair keyguardTransitionInteractor.finishedKeyguardState,
keyguardInteractor.isAodAvailable,
::Pair
),
::toTriple
)
.collect { (wakefulnessState, keyguardState, isAodAvailable) ->
if ( if (
keyguardState == KeyguardState.GONE && keyguardState == KeyguardState.GONE &&
wakefulnessState.state == WakefulnessState.STARTING_TO_SLEEP wakefulnessState.state == WakefulnessState.STARTING_TO_SLEEP
@@ -78,7 +87,11 @@ constructor(
TransitionInfo( TransitionInfo(
name, name,
KeyguardState.GONE, KeyguardState.GONE,
KeyguardState.AOD, if (isAodAvailable) {
KeyguardState.AOD
} else {
KeyguardState.DOZING
},
getAnimator(), getAnimator(),
) )
) )
@@ -87,14 +100,15 @@ constructor(
} }
} }
private fun getAnimator(): ValueAnimator { private fun getAnimator(duration: Duration = DEFAULT_DURATION): ValueAnimator {
return ValueAnimator().apply { return ValueAnimator().apply {
setInterpolator(Interpolators.LINEAR) setInterpolator(Interpolators.LINEAR)
setDuration(TRANSITION_DURATION_MS) setDuration(duration.inWholeMilliseconds)
} }
} }
companion object { companion object {
private const val TRANSITION_DURATION_MS = 500L private val DEFAULT_DURATION = 500.milliseconds
val TO_DREAMING_DURATION = 933.milliseconds
} }
} }

View File

@@ -21,11 +21,11 @@ import com.android.systemui.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository 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.KeyguardState
import com.android.systemui.keyguard.shared.model.StatusBarState.KEYGUARD import com.android.systemui.keyguard.shared.model.StatusBarState.KEYGUARD
import com.android.systemui.keyguard.shared.model.TransitionInfo import com.android.systemui.keyguard.shared.model.TransitionInfo
import com.android.systemui.keyguard.shared.model.TransitionState 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.shade.data.repository.ShadeRepository
import com.android.systemui.util.kotlin.sample import com.android.systemui.util.kotlin.sample
import java.util.UUID import java.util.UUID
@@ -54,7 +54,7 @@ constructor(
listenForLockscreenToGone() listenForLockscreenToGone()
listenForLockscreenToOccluded() listenForLockscreenToOccluded()
listenForLockscreenToCamera() listenForLockscreenToCamera()
listenForLockscreenToAod() listenForLockscreenToAodOrDozing()
listenForLockscreenToBouncer() listenForLockscreenToBouncer()
listenForLockscreenToDreaming() listenForLockscreenToDreaming()
listenForLockscreenToBouncerDragging() listenForLockscreenToBouncerDragging()
@@ -230,19 +230,31 @@ constructor(
} }
} }
private fun listenForLockscreenToAod() { private fun listenForLockscreenToAodOrDozing() {
scope.launch { scope.launch {
keyguardInteractor keyguardInteractor.wakefulnessModel
.dozeTransitionTo(DozeStateModel.DOZE_AOD) .sample(
.sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair) combine(
.collect { pair -> keyguardTransitionInteractor.startedKeyguardTransitionStep,
val (dozeToAod, lastStartedStep) = pair keyguardInteractor.isAodAvailable,
if (lastStartedStep.to == KeyguardState.LOCKSCREEN) { ::Pair
),
::toTriple
)
.collect { (wakefulnessState, lastStartedStep, isAodAvailable) ->
if (
lastStartedStep.to == KeyguardState.LOCKSCREEN &&
wakefulnessState.state == WakefulnessState.STARTING_TO_SLEEP
) {
keyguardTransitionRepository.startTransition( keyguardTransitionRepository.startTransition(
TransitionInfo( TransitionInfo(
name, name,
KeyguardState.LOCKSCREEN, KeyguardState.LOCKSCREEN,
KeyguardState.AOD, if (isAodAvailable) {
KeyguardState.AOD
} else {
KeyguardState.DOZING
},
getAnimator(), getAnimator(),
) )
) )

View File

@@ -23,12 +23,14 @@ import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionInfo import com.android.systemui.keyguard.shared.model.TransitionInfo
import com.android.systemui.keyguard.shared.model.WakefulnessState
import com.android.systemui.util.kotlin.sample import com.android.systemui.util.kotlin.sample
import javax.inject.Inject import javax.inject.Inject
import kotlin.time.Duration import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@SysUISingleton @SysUISingleton
@@ -44,6 +46,7 @@ constructor(
override fun start() { override fun start() {
listenForOccludedToLockscreen() listenForOccludedToLockscreen()
listenForOccludedToDreaming() listenForOccludedToDreaming()
listenForOccludedToAodOrDozing()
} }
private fun listenForOccludedToDreaming() { private fun listenForOccludedToDreaming() {
@@ -70,8 +73,7 @@ constructor(
scope.launch { scope.launch {
keyguardInteractor.isKeyguardOccluded keyguardInteractor.isKeyguardOccluded
.sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair) .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
.collect { pair -> .collect { (isOccluded, lastStartedKeyguardState) ->
val (isOccluded, lastStartedKeyguardState) = pair
// Occlusion signals come from the framework, and should interrupt any // Occlusion signals come from the framework, and should interrupt any
// existing transition // existing transition
if (!isOccluded && lastStartedKeyguardState.to == KeyguardState.OCCLUDED) { 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 { private fun getAnimator(duration: Duration = DEFAULT_DURATION): ValueAnimator {
return ValueAnimator().apply { return ValueAnimator().apply {
setInterpolator(Interpolators.LINEAR) setInterpolator(Interpolators.LINEAR)

View File

@@ -57,6 +57,8 @@ constructor(
val dozeAmount: Flow<Float> = repository.linearDozeAmount val dozeAmount: Flow<Float> = repository.linearDozeAmount
/** Whether the system is in doze mode. */ /** Whether the system is in doze mode. */
val isDozing: Flow<Boolean> = repository.isDozing val isDozing: Flow<Boolean> = repository.isDozing
/** Whether Always-on Display mode is available. */
val isAodAvailable: Flow<Boolean> = repository.isAodAvailable
/** Doze transition information. */ /** Doze transition information. */
val dozeTransitionModel: Flow<DozeTransitionModel> = repository.dozeTransitionModel val dozeTransitionModel: Flow<DozeTransitionModel> = repository.dozeTransitionModel
/** /**

View File

@@ -4266,8 +4266,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
@Override @Override
public void onDozeAmountChanged(float linear, float eased) { public void onDozeAmountChanged(float linear, float eased) {
if (mFeatureFlags.isEnabled(Flags.LOCKSCREEN_ANIMATIONS) if (!mFeatureFlags.isEnabled(Flags.LIGHT_REVEAL_MIGRATION)
&& !mFeatureFlags.isEnabled(Flags.LIGHT_REVEAL_MIGRATION)
&& !(mLightRevealScrim.getRevealEffect() instanceof CircleReveal)) { && !(mLightRevealScrim.getRevealEffect() instanceof CircleReveal)) {
mLightRevealScrim.setRevealAmount(1f - linear); mLightRevealScrim.setRevealAmount(1f - linear);
} }

View File

@@ -44,10 +44,9 @@ import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.doze.AlwaysOnDisplayPolicy; import com.android.systemui.doze.AlwaysOnDisplayPolicy;
import com.android.systemui.doze.DozeScreenState; import com.android.systemui.doze.DozeScreenState;
import com.android.systemui.dump.DumpManager; 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.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.policy.BatteryController; 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.ConfigurationController;
import com.android.systemui.statusbar.policy.DevicePostureController; import com.android.systemui.statusbar.policy.DevicePostureController;
import com.android.systemui.tuner.TunerService; import com.android.systemui.tuner.TunerService;
@@ -82,7 +81,6 @@ public class DozeParameters implements
private final AlwaysOnDisplayPolicy mAlwaysOnPolicy; private final AlwaysOnDisplayPolicy mAlwaysOnPolicy;
private final Resources mResources; private final Resources mResources;
private final BatteryController mBatteryController; private final BatteryController mBatteryController;
private final FeatureFlags mFeatureFlags;
private final ScreenOffAnimationController mScreenOffAnimationController; private final ScreenOffAnimationController mScreenOffAnimationController;
private final FoldAodAnimationController mFoldAodAnimationController; private final FoldAodAnimationController mFoldAodAnimationController;
private final UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController; private final UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
@@ -125,7 +123,6 @@ public class DozeParameters implements
BatteryController batteryController, BatteryController batteryController,
TunerService tunerService, TunerService tunerService,
DumpManager dumpManager, DumpManager dumpManager,
FeatureFlags featureFlags,
ScreenOffAnimationController screenOffAnimationController, ScreenOffAnimationController screenOffAnimationController,
Optional<SysUIUnfoldComponent> sysUiUnfoldComponent, Optional<SysUIUnfoldComponent> sysUiUnfoldComponent,
UnlockedScreenOffAnimationController unlockedScreenOffAnimationController, UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
@@ -141,7 +138,6 @@ public class DozeParameters implements
mControlScreenOffAnimation = !getDisplayNeedsBlanking(); mControlScreenOffAnimation = !getDisplayNeedsBlanking();
mPowerManager = powerManager; mPowerManager = powerManager;
mPowerManager.setDozeAfterScreenOff(!mControlScreenOffAnimation); mPowerManager.setDozeAfterScreenOff(!mControlScreenOffAnimation);
mFeatureFlags = featureFlags;
mScreenOffAnimationController = screenOffAnimationController; mScreenOffAnimationController = screenOffAnimationController;
mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController; mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController;
@@ -162,6 +158,13 @@ public class DozeParameters implements
SettingsObserver quickPickupSettingsObserver = new SettingsObserver(context, handler); SettingsObserver quickPickupSettingsObserver = new SettingsObserver(context, handler);
quickPickupSettingsObserver.observe(); quickPickupSettingsObserver.observe();
batteryController.addCallback(new BatteryStateChangeCallback() {
@Override
public void onPowerSaveChanged(boolean isPowerSave) {
dispatchAlwaysOnEvent();
}
});
} }
private void updateQuickPickupEnabled() { 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 * 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 * possible if AOD isn't even enabled or if the display needs blanking.
* blanking.
*/ */
public boolean canControlUnlockedScreenOff() { public boolean canControlUnlockedScreenOff() {
return getAlwaysOn() return getAlwaysOn() && !getDisplayNeedsBlanking();
&& mFeatureFlags.isEnabled(Flags.LOCKSCREEN_ANIMATIONS)
&& !getDisplayNeedsBlanking();
} }
/** /**
@@ -424,9 +424,7 @@ public class DozeParameters implements
updateControlScreenOff(); updateControlScreenOff();
} }
for (Callback callback : mCallbacks) { dispatchAlwaysOnEvent();
callback.onAlwaysOnChange();
}
mScreenOffAnimationController.onAlwaysOnChanged(getAlwaysOn()); mScreenOffAnimationController.onAlwaysOnChanged(getAlwaysOn());
} }
@@ -463,6 +461,12 @@ public class DozeParameters implements
pw.print("isQuickPickupEnabled(): "); pw.println(isQuickPickupEnabled()); pw.print("isQuickPickupEnabled(): "); pw.println(isQuickPickupEnabled());
} }
private void dispatchAlwaysOnEvent() {
for (Callback callback : mCallbacks) {
callback.onAlwaysOnChange();
}
}
private boolean getPostureSpecificBool( private boolean getPostureSpecificBool(
int[] postureMapping, int[] postureMapping,
boolean defaultSensorBool, boolean defaultSensorBool,
@@ -477,7 +481,8 @@ public class DozeParameters implements
return bool; return bool;
} }
interface Callback { /** Callbacks for doze parameter related information */
public interface Callback {
/** /**
* Invoked when the value of getAlwaysOn may have changed. * Invoked when the value of getAlwaysOn may have changed.
*/ */

View File

@@ -24,6 +24,7 @@ import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.systemui.SysuiTestCase import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.AuthController import com.android.systemui.biometrics.AuthController
import com.android.systemui.common.shared.model.Position 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.DozeHost
import com.android.systemui.doze.DozeMachine import com.android.systemui.doze.DozeMachine
import com.android.systemui.doze.DozeTransitionCallback 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.keyguard.shared.model.WakefulnessState
import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.phone.BiometricUnlockController 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.statusbar.policy.KeyguardStateController
import com.android.systemui.util.mockito.argumentCaptor import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.whenever import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.mockito.withArgCaptor import com.android.systemui.util.mockito.withArgCaptor
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
@@ -68,6 +72,7 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
@Mock private lateinit var authController: AuthController @Mock private lateinit var authController: AuthController
@Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
@Mock private lateinit var dreamOverlayCallbackController: DreamOverlayCallbackController @Mock private lateinit var dreamOverlayCallbackController: DreamOverlayCallbackController
@Mock private lateinit var dozeParameters: DozeParameters
private lateinit var underTest: KeyguardRepositoryImpl private lateinit var underTest: KeyguardRepositoryImpl
@@ -84,6 +89,7 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
keyguardStateController, keyguardStateController,
keyguardUpdateMonitor, keyguardUpdateMonitor,
dozeTransitionListener, dozeTransitionListener,
dozeParameters,
authController, authController,
dreamOverlayCallbackController, dreamOverlayCallbackController,
) )
@@ -169,6 +175,26 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
job.cancel() 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 @Test
fun isKeyguardOccluded() = fun isKeyguardOccluded() =
runTest(UnconfinedTestDispatcher()) { runTest(UnconfinedTestDispatcher()) {

View File

@@ -71,6 +71,10 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
private lateinit var fromLockscreenTransitionInteractor: FromLockscreenTransitionInteractor private lateinit var fromLockscreenTransitionInteractor: FromLockscreenTransitionInteractor
private lateinit var fromDreamingTransitionInteractor: FromDreamingTransitionInteractor 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 @Before
fun setUp() { fun setUp() {
@@ -102,6 +106,42 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository), keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
) )
fromDreamingTransitionInteractor.start() 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 @Test
@@ -192,6 +232,289 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
coroutineContext.cancelChildren() 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() = private fun startingToWake() =
WakefulnessModel( WakefulnessModel(
WakefulnessState.STARTING_TO_WAKE, WakefulnessState.STARTING_TO_WAKE,
@@ -199,4 +522,12 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
WakeSleepReason.OTHER, WakeSleepReason.OTHER,
WakeSleepReason.OTHER WakeSleepReason.OTHER
) )
private fun startingToSleep() =
WakefulnessModel(
WakefulnessState.STARTING_TO_SLEEP,
true,
WakeSleepReason.OTHER,
WakeSleepReason.OTHER
)
} }

View File

@@ -23,6 +23,10 @@ import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doAnswer; 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 static org.mockito.Mockito.when;
import android.content.res.Resources; 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.AlwaysOnDisplayPolicy;
import com.android.systemui.doze.DozeScreenState; import com.android.systemui.doze.DozeScreenState;
import com.android.systemui.dump.DumpManager; 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.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.policy.BatteryController; 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.ConfigurationController;
import com.android.systemui.tuner.TunerService; import com.android.systemui.tuner.TunerService;
import com.android.systemui.unfold.FoldAodAnimationController; import com.android.systemui.unfold.FoldAodAnimationController;
@@ -52,6 +55,8 @@ import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
@@ -69,7 +74,6 @@ public class DozeParametersTest extends SysuiTestCase {
@Mock private PowerManager mPowerManager; @Mock private PowerManager mPowerManager;
@Mock private TunerService mTunerService; @Mock private TunerService mTunerService;
@Mock private BatteryController mBatteryController; @Mock private BatteryController mBatteryController;
@Mock private FeatureFlags mFeatureFlags;
@Mock private DumpManager mDumpManager; @Mock private DumpManager mDumpManager;
@Mock private ScreenOffAnimationController mScreenOffAnimationController; @Mock private ScreenOffAnimationController mScreenOffAnimationController;
@Mock private FoldAodAnimationController mFoldAodAnimationController; @Mock private FoldAodAnimationController mFoldAodAnimationController;
@@ -78,6 +82,7 @@ public class DozeParametersTest extends SysuiTestCase {
@Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor; @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Mock private StatusBarStateController mStatusBarStateController; @Mock private StatusBarStateController mStatusBarStateController;
@Mock private ConfigurationController mConfigurationController; @Mock private ConfigurationController mConfigurationController;
@Captor private ArgumentCaptor<BatteryStateChangeCallback> mBatteryStateChangeCallback;
/** /**
* The current value of PowerManager's dozeAfterScreenOff property. * The current value of PowerManager's dozeAfterScreenOff property.
@@ -113,7 +118,6 @@ public class DozeParametersTest extends SysuiTestCase {
mBatteryController, mBatteryController,
mTunerService, mTunerService,
mDumpManager, mDumpManager,
mFeatureFlags,
mScreenOffAnimationController, mScreenOffAnimationController,
Optional.of(mSysUIUnfoldComponent), Optional.of(mSysUIUnfoldComponent),
mUnlockedScreenOffAnimationController, mUnlockedScreenOffAnimationController,
@@ -122,7 +126,8 @@ public class DozeParametersTest extends SysuiTestCase {
mStatusBarStateController mStatusBarStateController
); );
when(mFeatureFlags.isEnabled(Flags.LOCKSCREEN_ANIMATIONS)).thenReturn(true); verify(mBatteryController).addCallback(mBatteryStateChangeCallback.capture());
setAodEnabledForTest(true); setAodEnabledForTest(true);
setShouldControlUnlockedScreenOffForTest(true); setShouldControlUnlockedScreenOffForTest(true);
setDisplayNeedsBlankingForTest(false); setDisplayNeedsBlankingForTest(false);
@@ -173,6 +178,29 @@ public class DozeParametersTest extends SysuiTestCase {
assertThat(mDozeParameters.getAlwaysOn()).isFalse(); 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 * 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 * 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); 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 @Test
public void propagatesAnimateScreenOff_noAlwaysOn() { public void propagatesAnimateScreenOff_noAlwaysOn() {
setAodEnabledForTest(false); setAodEnabledForTest(false);

View File

@@ -52,6 +52,9 @@ class FakeKeyguardRepository : KeyguardRepository {
private val _isDozing = MutableStateFlow(false) private val _isDozing = MutableStateFlow(false)
override val isDozing: Flow<Boolean> = _isDozing override val isDozing: Flow<Boolean> = _isDozing
private val _isAodAvailable = MutableStateFlow(false)
override val isAodAvailable: Flow<Boolean> = _isAodAvailable
private val _isDreaming = MutableStateFlow(false) private val _isDreaming = MutableStateFlow(false)
override val isDreaming: Flow<Boolean> = _isDreaming override val isDreaming: Flow<Boolean> = _isDreaming
@@ -126,6 +129,10 @@ class FakeKeyguardRepository : KeyguardRepository {
_isDozing.value = isDozing _isDozing.value = isDozing
} }
fun setAodAvailable(isAodAvailable: Boolean) {
_isAodAvailable.value = isAodAvailable
}
fun setDreamingWithOverlay(isDreaming: Boolean) { fun setDreamingWithOverlay(isDreaming: Boolean) {
_isDreamingWithOverlay.value = isDreaming _isDreamingWithOverlay.value = isDreaming
} }