Loading packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt +16 −6 Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ import android.animation.ValueAnimator import android.content.Context import android.database.ContentObserver import android.os.Handler import android.os.PowerManager import android.provider.Settings import android.view.Surface import android.view.View Loading Loading @@ -50,9 +51,10 @@ class UnlockedScreenOffAnimationController @Inject constructor( private val keyguardViewMediatorLazy: dagger.Lazy<KeyguardViewMediator>, private val keyguardStateController: KeyguardStateController, private val dozeParameters: dagger.Lazy<DozeParameters>, private val globalSettings: GlobalSettings private val globalSettings: GlobalSettings, private val powerManager: PowerManager, private val handler: Handler = Handler() ) : WakefulnessLifecycle.Observer { private val handler = Handler() private lateinit var statusBar: StatusBar private lateinit var lightRevealScrim: LightRevealScrim Loading Loading @@ -205,10 +207,18 @@ class UnlockedScreenOffAnimationController @Inject constructor( lightRevealAnimationPlaying = true lightRevealAnimator.start() handler.postDelayed({ // Only run this callback if the device is sleeping (not interactive). This callback // is removed in onStartedWakingUp, but since that event is asynchronously // dispatched, a race condition could make it possible for this callback to be run // as the device is waking up. That results in the AOD UI being shown while we wake // up, with unpredictable consequences. if (!powerManager.isInteractive) { aodUiAnimationPlaying = true // Show AOD. That'll cause the KeyguardVisibilityHelper to call #animateInKeyguard. // Show AOD. That'll cause the KeyguardVisibilityHelper to call // #animateInKeyguard. statusBar.notificationPanelViewController.showAodUi() } }, (ANIMATE_IN_KEYGUARD_DELAY * animatorDurationScale).toLong()) } else { decidedToAnimateGoingToSleep = false Loading packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt +80 −3 Original line number Diff line number Diff line Loading @@ -17,6 +17,8 @@ package com.android.systemui.statusbar.phone import android.animation.Animator import android.os.Handler import android.os.PowerManager import android.testing.AndroidTestingRunner import android.testing.TestableLooper.RunWithLooper import android.view.View Loading @@ -28,13 +30,20 @@ import com.android.systemui.statusbar.LightRevealScrim import com.android.systemui.statusbar.StatusBarStateControllerImpl import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.settings.GlobalSettings import org.junit.After import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor import org.mockito.Mock import org.mockito.Mockito import org.mockito.Mockito.`when` import org.mockito.Mockito.anyLong import org.mockito.Mockito.mockingDetails import org.mockito.Mockito.never import org.mockito.Mockito.spy import org.mockito.Mockito.times import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations @SmallTest Loading @@ -52,13 +61,19 @@ class UnlockedScreenOffAnimationControllerTest : SysuiTestCase() { @Mock private lateinit var globalSettings: GlobalSettings @Mock private lateinit var statusbar: StatusBar private lateinit var statusBar: StatusBar @Mock private lateinit var notificationPanelViewController: NotificationPanelViewController @Mock private lateinit var lightRevealScrim: LightRevealScrim @Mock private lateinit var wakefulnessLifecycle: WakefulnessLifecycle @Mock private lateinit var statusBarStateController: StatusBarStateControllerImpl @Mock private lateinit var powerManager: PowerManager @Mock private lateinit var handler: Handler @Before fun setUp() { Loading @@ -71,9 +86,24 @@ class UnlockedScreenOffAnimationControllerTest : SysuiTestCase() { dagger.Lazy<KeyguardViewMediator> { keyguardViewMediator }, keyguardStateController, dagger.Lazy<DozeParameters> { dozeParameters }, globalSettings globalSettings, powerManager, handler = handler ) controller.initialize(statusbar, lightRevealScrim) controller.initialize(statusBar, lightRevealScrim) `when`(statusBar.notificationPanelViewController).thenReturn( notificationPanelViewController) // Screen off does not run if the panel is expanded, so we should say it's collapsed to test // screen off. `when`(notificationPanelViewController.isFullyCollapsed).thenReturn(true) } @After fun cleanUp() { // Tell the screen off controller to cancel the animations and clean up its state, or // subsequent tests will act unpredictably as the animator continues running. controller.onStartedWakingUp() } @Test Loading @@ -89,4 +119,51 @@ class UnlockedScreenOffAnimationControllerTest : SysuiTestCase() { listener.value.onAnimationEnd(null) Mockito.verify(animator).setListener(null) } /** * The AOD UI is shown during the screen off animation, after a delay to allow the light reveal * animation to start. If the device is woken up during the screen off, we should *never* do * this. * * This test confirms that we do show the AOD UI when the device is not woken up * (PowerManager#isInteractive = false). */ @Test fun testAodUiShownIfNotInteractive() { `when`(dozeParameters.shouldControlUnlockedScreenOff()).thenReturn(true) `when`(powerManager.isInteractive).thenReturn(false) val callbackCaptor = ArgumentCaptor.forClass(Runnable::class.java) controller.onStartedGoingToSleep() verify(handler).postDelayed(callbackCaptor.capture(), anyLong()) callbackCaptor.value.run() verify(notificationPanelViewController, times(1)).showAodUi() } /** * The AOD UI is shown during the screen off animation, after a delay to allow the light reveal * animation to start. If the device is woken up during the screen off, we should *never* do * this. * * This test confirms that we do not show the AOD UI when the device is woken up during screen * off (PowerManager#isInteractive = true). */ @Test fun testAodUiNotShownIfInteractive() { `when`(dozeParameters.shouldControlUnlockedScreenOff()).thenReturn(true) `when`(powerManager.isInteractive).thenReturn(true) val callbackCaptor = ArgumentCaptor.forClass(Runnable::class.java) controller.onStartedGoingToSleep() mockingDetails(handler).printInvocations() verify(handler).postDelayed(callbackCaptor.capture(), anyLong()) callbackCaptor.value.run() verify(notificationPanelViewController, never()).showAodUi() } } No newline at end of file Loading
packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt +16 −6 Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ import android.animation.ValueAnimator import android.content.Context import android.database.ContentObserver import android.os.Handler import android.os.PowerManager import android.provider.Settings import android.view.Surface import android.view.View Loading Loading @@ -50,9 +51,10 @@ class UnlockedScreenOffAnimationController @Inject constructor( private val keyguardViewMediatorLazy: dagger.Lazy<KeyguardViewMediator>, private val keyguardStateController: KeyguardStateController, private val dozeParameters: dagger.Lazy<DozeParameters>, private val globalSettings: GlobalSettings private val globalSettings: GlobalSettings, private val powerManager: PowerManager, private val handler: Handler = Handler() ) : WakefulnessLifecycle.Observer { private val handler = Handler() private lateinit var statusBar: StatusBar private lateinit var lightRevealScrim: LightRevealScrim Loading Loading @@ -205,10 +207,18 @@ class UnlockedScreenOffAnimationController @Inject constructor( lightRevealAnimationPlaying = true lightRevealAnimator.start() handler.postDelayed({ // Only run this callback if the device is sleeping (not interactive). This callback // is removed in onStartedWakingUp, but since that event is asynchronously // dispatched, a race condition could make it possible for this callback to be run // as the device is waking up. That results in the AOD UI being shown while we wake // up, with unpredictable consequences. if (!powerManager.isInteractive) { aodUiAnimationPlaying = true // Show AOD. That'll cause the KeyguardVisibilityHelper to call #animateInKeyguard. // Show AOD. That'll cause the KeyguardVisibilityHelper to call // #animateInKeyguard. statusBar.notificationPanelViewController.showAodUi() } }, (ANIMATE_IN_KEYGUARD_DELAY * animatorDurationScale).toLong()) } else { decidedToAnimateGoingToSleep = false Loading
packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt +80 −3 Original line number Diff line number Diff line Loading @@ -17,6 +17,8 @@ package com.android.systemui.statusbar.phone import android.animation.Animator import android.os.Handler import android.os.PowerManager import android.testing.AndroidTestingRunner import android.testing.TestableLooper.RunWithLooper import android.view.View Loading @@ -28,13 +30,20 @@ import com.android.systemui.statusbar.LightRevealScrim import com.android.systemui.statusbar.StatusBarStateControllerImpl import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.settings.GlobalSettings import org.junit.After import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor import org.mockito.Mock import org.mockito.Mockito import org.mockito.Mockito.`when` import org.mockito.Mockito.anyLong import org.mockito.Mockito.mockingDetails import org.mockito.Mockito.never import org.mockito.Mockito.spy import org.mockito.Mockito.times import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations @SmallTest Loading @@ -52,13 +61,19 @@ class UnlockedScreenOffAnimationControllerTest : SysuiTestCase() { @Mock private lateinit var globalSettings: GlobalSettings @Mock private lateinit var statusbar: StatusBar private lateinit var statusBar: StatusBar @Mock private lateinit var notificationPanelViewController: NotificationPanelViewController @Mock private lateinit var lightRevealScrim: LightRevealScrim @Mock private lateinit var wakefulnessLifecycle: WakefulnessLifecycle @Mock private lateinit var statusBarStateController: StatusBarStateControllerImpl @Mock private lateinit var powerManager: PowerManager @Mock private lateinit var handler: Handler @Before fun setUp() { Loading @@ -71,9 +86,24 @@ class UnlockedScreenOffAnimationControllerTest : SysuiTestCase() { dagger.Lazy<KeyguardViewMediator> { keyguardViewMediator }, keyguardStateController, dagger.Lazy<DozeParameters> { dozeParameters }, globalSettings globalSettings, powerManager, handler = handler ) controller.initialize(statusbar, lightRevealScrim) controller.initialize(statusBar, lightRevealScrim) `when`(statusBar.notificationPanelViewController).thenReturn( notificationPanelViewController) // Screen off does not run if the panel is expanded, so we should say it's collapsed to test // screen off. `when`(notificationPanelViewController.isFullyCollapsed).thenReturn(true) } @After fun cleanUp() { // Tell the screen off controller to cancel the animations and clean up its state, or // subsequent tests will act unpredictably as the animator continues running. controller.onStartedWakingUp() } @Test Loading @@ -89,4 +119,51 @@ class UnlockedScreenOffAnimationControllerTest : SysuiTestCase() { listener.value.onAnimationEnd(null) Mockito.verify(animator).setListener(null) } /** * The AOD UI is shown during the screen off animation, after a delay to allow the light reveal * animation to start. If the device is woken up during the screen off, we should *never* do * this. * * This test confirms that we do show the AOD UI when the device is not woken up * (PowerManager#isInteractive = false). */ @Test fun testAodUiShownIfNotInteractive() { `when`(dozeParameters.shouldControlUnlockedScreenOff()).thenReturn(true) `when`(powerManager.isInteractive).thenReturn(false) val callbackCaptor = ArgumentCaptor.forClass(Runnable::class.java) controller.onStartedGoingToSleep() verify(handler).postDelayed(callbackCaptor.capture(), anyLong()) callbackCaptor.value.run() verify(notificationPanelViewController, times(1)).showAodUi() } /** * The AOD UI is shown during the screen off animation, after a delay to allow the light reveal * animation to start. If the device is woken up during the screen off, we should *never* do * this. * * This test confirms that we do not show the AOD UI when the device is woken up during screen * off (PowerManager#isInteractive = true). */ @Test fun testAodUiNotShownIfInteractive() { `when`(dozeParameters.shouldControlUnlockedScreenOff()).thenReturn(true) `when`(powerManager.isInteractive).thenReturn(true) val callbackCaptor = ArgumentCaptor.forClass(Runnable::class.java) controller.onStartedGoingToSleep() mockingDetails(handler).printInvocations() verify(handler).postDelayed(callbackCaptor.capture(), anyLong()) callbackCaptor.value.run() verify(notificationPanelViewController, never()).showAodUi() } } No newline at end of file