• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.systemui.statusbar.phone
18 
19 import android.animation.Animator
20 import android.os.Handler
21 import android.os.PowerManager
22 import android.testing.AndroidTestingRunner
23 import android.testing.TestableLooper.RunWithLooper
24 import android.view.View
25 import androidx.test.filters.SmallTest
26 import com.android.internal.jank.InteractionJankMonitor
27 import com.android.systemui.SysuiTestCase
28 import com.android.systemui.keyguard.KeyguardViewMediator
29 import com.android.systemui.keyguard.WakefulnessLifecycle
30 import com.android.systemui.shade.NotificationPanelViewController
31 import com.android.systemui.statusbar.LightRevealScrim
32 import com.android.systemui.statusbar.StatusBarStateControllerImpl
33 import com.android.systemui.statusbar.policy.KeyguardStateController
34 import com.android.systemui.util.settings.GlobalSettings
35 import junit.framework.Assert.assertFalse
36 import org.junit.After
37 import org.junit.Before
38 import org.junit.Test
39 import org.junit.runner.RunWith
40 import org.mockito.ArgumentCaptor
41 import org.mockito.Mock
42 import org.mockito.Mockito
43 import org.mockito.Mockito.anyLong
44 import org.mockito.Mockito.never
45 import org.mockito.Mockito.spy
46 import org.mockito.Mockito.times
47 import org.mockito.Mockito.verify
48 import org.mockito.Mockito.`when`
49 import org.mockito.MockitoAnnotations
50 
51 @SmallTest
52 @RunWith(AndroidTestingRunner::class)
53 @RunWithLooper(setAsMainLooper = true)
54 class UnlockedScreenOffAnimationControllerTest : SysuiTestCase() {
55 
56     private lateinit var controller: UnlockedScreenOffAnimationController
57     @Mock
58     private lateinit var keyguardViewMediator: KeyguardViewMediator
59     @Mock
60     private lateinit var dozeParameters: DozeParameters
61     @Mock
62     private lateinit var keyguardStateController: KeyguardStateController
63     @Mock
64     private lateinit var globalSettings: GlobalSettings
65     @Mock
66     private lateinit var mCentralSurfaces: CentralSurfaces
67     @Mock
68     private lateinit var notificationPanelViewController: NotificationPanelViewController
69     @Mock
70     private lateinit var lightRevealScrim: LightRevealScrim
71     @Mock
72     private lateinit var wakefulnessLifecycle: WakefulnessLifecycle
73     @Mock
74     private lateinit var statusBarStateController: StatusBarStateControllerImpl
75     @Mock
76     private lateinit var interactionJankMonitor: InteractionJankMonitor
77     @Mock
78     private lateinit var powerManager: PowerManager
79     @Mock
80     private lateinit var handler: Handler
81 
82     @Before
setUpnull83     fun setUp() {
84         MockitoAnnotations.initMocks(this)
85 
86         controller = UnlockedScreenOffAnimationController(
87                 context,
88                 wakefulnessLifecycle,
89                 statusBarStateController,
90                 dagger.Lazy<KeyguardViewMediator> { keyguardViewMediator },
91                 keyguardStateController,
92                 dagger.Lazy<DozeParameters> { dozeParameters },
93                 globalSettings,
94                 interactionJankMonitor,
95                 powerManager,
96                 handler = handler
97         )
98         controller.initialize(mCentralSurfaces, lightRevealScrim)
99         `when`(mCentralSurfaces.notificationPanelViewController).thenReturn(
100             notificationPanelViewController)
101 
102         // Screen off does not run if the panel is expanded, so we should say it's collapsed to test
103         // screen off.
104         `when`(notificationPanelViewController.isFullyCollapsed).thenReturn(true)
105     }
106 
107     @After
cleanUpnull108     fun cleanUp() {
109         // Tell the screen off controller to cancel the animations and clean up its state, or
110         // subsequent tests will act unpredictably as the animator continues running.
111         controller.onStartedWakingUp()
112     }
113 
114     @Test
testAnimClearsEndListenernull115     fun testAnimClearsEndListener() {
116         val keyguardView = View(context)
117         val animator = spy(keyguardView.animate())
118         val keyguardSpy = spy(keyguardView)
119         Mockito.`when`(keyguardSpy.animate()).thenReturn(animator)
120         val listener = ArgumentCaptor.forClass(Animator.AnimatorListener::class.java)
121         val endAction = ArgumentCaptor.forClass(Runnable::class.java)
122         controller.animateInKeyguard(keyguardSpy, Runnable {})
123         Mockito.verify(animator).setListener(listener.capture())
124         Mockito.verify(animator).withEndAction(endAction.capture())
125 
126         // Verify that the listener is cleared if we cancel it.
127         listener.value.onAnimationCancel(null)
128         Mockito.verify(animator).setListener(null)
129 
130         // Verify that the listener is also cleared if the end action is triggered.
131         endAction.value.run()
132         verify(animator, times(2)).setListener(null)
133     }
134 
135     /**
136      * The AOD UI is shown during the screen off animation, after a delay to allow the light reveal
137      * animation to start. If the device is woken up during the screen off, we should *never* do
138      * this.
139      *
140      * This test confirms that we do show the AOD UI when the device is not woken up
141      * (PowerManager#isInteractive = false).
142      */
143     @Test
testAodUiShownIfNotInteractivenull144     fun testAodUiShownIfNotInteractive() {
145         `when`(dozeParameters.canControlUnlockedScreenOff()).thenReturn(true)
146         `when`(powerManager.isInteractive).thenReturn(false)
147 
148         val callbackCaptor = ArgumentCaptor.forClass(Runnable::class.java)
149         controller.startAnimation()
150 
151         verify(handler).postDelayed(callbackCaptor.capture(), anyLong())
152 
153         callbackCaptor.value.run()
154 
155         verify(notificationPanelViewController, times(1)).showAodUi()
156     }
157 
158     /**
159      * The AOD UI is shown during the screen off animation, after a delay to allow the light reveal
160      * animation to start. If the device is woken up during the screen off, we should *never* do
161      * this.
162      *
163      * This test confirms that we do not show the AOD UI when the device is woken up during screen
164      * off (PowerManager#isInteractive = true).
165      */
166     @Test
testAodUiNotShownIfInteractivenull167     fun testAodUiNotShownIfInteractive() {
168         `when`(dozeParameters.canControlUnlockedScreenOff()).thenReturn(true)
169         `when`(powerManager.isInteractive).thenReturn(true)
170 
171         val callbackCaptor = ArgumentCaptor.forClass(Runnable::class.java)
172         controller.startAnimation()
173 
174         verify(handler).postDelayed(callbackCaptor.capture(), anyLong())
175         callbackCaptor.value.run()
176 
177         verify(notificationPanelViewController, never()).showAodUi()
178     }
179 
180     @Test
testNoAnimationPlaying_dozeParamsCanNotControlScreenOffnull181     fun testNoAnimationPlaying_dozeParamsCanNotControlScreenOff() {
182         `when`(dozeParameters.canControlUnlockedScreenOff()).thenReturn(false)
183 
184         assertFalse(controller.shouldPlayUnlockedScreenOffAnimation())
185         controller.startAnimation()
186         assertFalse(controller.isAnimationPlaying())
187     }
188 }
189