1 /*
2  * Copyright (C) 2017 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.doze;
18 
19 import static com.android.systemui.doze.DozeMachine.State.DOZE;
20 import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD;
21 import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_DOCKED;
22 import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_PAUSED;
23 import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_PAUSING;
24 import static com.android.systemui.doze.DozeMachine.State.DOZE_PULSE_DONE;
25 import static com.android.systemui.doze.DozeMachine.State.DOZE_PULSING;
26 import static com.android.systemui.doze.DozeMachine.State.DOZE_REQUEST_PULSE;
27 import static com.android.systemui.doze.DozeMachine.State.FINISH;
28 import static com.android.systemui.doze.DozeMachine.State.INITIALIZED;
29 import static com.android.systemui.doze.DozeMachine.State.UNINITIALIZED;
30 import static com.android.systemui.utils.os.FakeHandler.Mode.QUEUEING;
31 
32 import static org.hamcrest.Matchers.is;
33 import static org.junit.Assert.assertEquals;
34 import static org.junit.Assert.assertFalse;
35 import static org.junit.Assert.assertThat;
36 import static org.junit.Assert.assertTrue;
37 import static org.mockito.ArgumentMatchers.eq;
38 import static org.mockito.Matchers.anyObject;
39 import static org.mockito.Mockito.anyInt;
40 import static org.mockito.Mockito.doAnswer;
41 import static org.mockito.Mockito.verify;
42 import static org.mockito.Mockito.when;
43 
44 import android.os.Looper;
45 import android.view.Display;
46 
47 import androidx.test.filters.SmallTest;
48 import androidx.test.runner.AndroidJUnit4;
49 
50 import com.android.systemui.SysuiTestCase;
51 import com.android.systemui.biometrics.AuthController;
52 import com.android.systemui.biometrics.UdfpsController;
53 import com.android.systemui.statusbar.phone.DozeParameters;
54 import com.android.systemui.util.wakelock.WakeLockFake;
55 import com.android.systemui.utils.os.FakeHandler;
56 
57 import org.junit.Before;
58 import org.junit.Test;
59 import org.junit.runner.RunWith;
60 import org.mockito.ArgumentCaptor;
61 import org.mockito.Mock;
62 import org.mockito.MockitoAnnotations;
63 
64 import javax.inject.Provider;
65 
66 @RunWith(AndroidJUnit4.class)
67 @SmallTest
68 public class DozeScreenStateTest extends SysuiTestCase {
69 
70     private DozeServiceFake mServiceFake;
71     private FakeHandler mHandlerFake;
72     @Mock
73     private DozeHost mDozeHost;
74     @Mock
75     private DozeParameters mDozeParameters;
76     private WakeLockFake mWakeLock;
77     private DozeScreenState mScreen;
78     @Mock
79     private Provider<UdfpsController> mUdfpsControllerProvider;
80     @Mock
81     private AuthController mAuthController;
82     @Mock
83     private UdfpsController mUdfpsController;
84     @Mock
85     private DozeLog mDozeLog;
86     @Mock
87     private DozeScreenBrightness mDozeScreenBrightness;
88 
89     @Before
setUp()90     public void setUp() throws Exception {
91         MockitoAnnotations.initMocks(this);
92         when(mDozeParameters.getDisplayNeedsBlanking()).thenReturn(true);
93         when(mDozeParameters.getAlwaysOn()).thenReturn(true);
94         when(mUdfpsControllerProvider.get()).thenReturn(mUdfpsController);
95         when(mAuthController.isUdfpsEnrolled(anyInt())).thenReturn(true);
96         when(mUdfpsController.isFingerDown()).thenReturn(false);
97 
98         mServiceFake = new DozeServiceFake();
99         mHandlerFake = new FakeHandler(Looper.getMainLooper());
100         mWakeLock = new WakeLockFake();
101         mScreen = new DozeScreenState(mServiceFake, mHandlerFake, mDozeHost, mDozeParameters,
102                 mWakeLock, mAuthController, mUdfpsControllerProvider, mDozeLog,
103                 mDozeScreenBrightness);
104     }
105 
106     @Test
testScreen_offInDoze()107     public void testScreen_offInDoze() {
108         mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
109         mScreen.transitionTo(INITIALIZED, DOZE);
110 
111         assertEquals(Display.STATE_OFF, mServiceFake.screenState);
112     }
113 
114     @Test
testScreen_onInAod()115     public void testScreen_onInAod() {
116         mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
117         mScreen.transitionTo(INITIALIZED, DOZE_AOD);
118 
119         assertEquals(Display.STATE_DOZE_SUSPEND, mServiceFake.screenState);
120     }
121 
122     @Test
testScreen_onInPulse()123     public void testScreen_onInPulse() {
124         mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
125         mScreen.transitionTo(INITIALIZED, DOZE);
126 
127         mScreen.transitionTo(DOZE, DOZE_REQUEST_PULSE);
128         mScreen.transitionTo(DOZE_REQUEST_PULSE, DOZE_PULSING);
129 
130         assertEquals(Display.STATE_ON, mServiceFake.screenState);
131     }
132 
133     @Test
testScreen_offInRequestPulseWithoutAoD()134     public void testScreen_offInRequestPulseWithoutAoD() {
135         mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
136         mScreen.transitionTo(INITIALIZED, DOZE);
137 
138         mScreen.transitionTo(DOZE, DOZE_REQUEST_PULSE);
139 
140         assertEquals(Display.STATE_OFF, mServiceFake.screenState);
141     }
142 
143     @Test
testScreen_offInRequestPulseWithAoD()144     public void testScreen_offInRequestPulseWithAoD() {
145         mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
146         mScreen.transitionTo(INITIALIZED, DOZE_AOD);
147 
148         mScreen.transitionTo(DOZE, DOZE_REQUEST_PULSE);
149 
150         assertEquals(Display.STATE_OFF, mServiceFake.screenState);
151     }
152 
153     @Test
testScreen_onInDockedAod()154     public void testScreen_onInDockedAod() {
155         mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
156         mScreen.transitionTo(INITIALIZED, DOZE_AOD_DOCKED);
157 
158         assertEquals(Display.STATE_ON, mServiceFake.screenState);
159     }
160 
161     @Test
test_initialScreenStatePostedToHandler()162     public void test_initialScreenStatePostedToHandler() {
163         mHandlerFake.setMode(QUEUEING);
164 
165         mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
166         mServiceFake.screenStateSet = false;
167         mScreen.transitionTo(INITIALIZED, DOZE_AOD);
168 
169         assertFalse(mServiceFake.screenStateSet);
170 
171         mHandlerFake.dispatchQueuedMessages();
172 
173         assertTrue(mServiceFake.screenStateSet);
174         assertEquals(Display.STATE_DOZE_SUSPEND, mServiceFake.screenState);
175     }
176 
177     @Test
test_noScreenStateSetAfterFinish()178     public void test_noScreenStateSetAfterFinish() {
179         mHandlerFake.setMode(QUEUEING);
180 
181         mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
182         mScreen.transitionTo(INITIALIZED, DOZE_AOD);
183         mScreen.transitionTo(DOZE_AOD, FINISH);
184 
185         mServiceFake.screenStateSet = false;
186 
187         mHandlerFake.dispatchQueuedMessages();
188 
189         assertFalse(mServiceFake.screenStateSet);
190     }
191 
192     @Test
test_holdsWakeLockWhenGoingToLowPowerDelayed()193     public void test_holdsWakeLockWhenGoingToLowPowerDelayed() {
194         // Transition to low power mode will be delayed to let
195         // animations play at 60 fps.
196         when(mDozeParameters.shouldDelayDisplayDozeTransition()).thenReturn(true);
197         mHandlerFake.setMode(QUEUEING);
198 
199         mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
200         mHandlerFake.dispatchQueuedMessages();
201 
202         mScreen.transitionTo(INITIALIZED, DOZE_AOD);
203         assertThat(mWakeLock.isHeld(), is(true));
204 
205         mHandlerFake.dispatchQueuedMessages();
206         assertThat(mWakeLock.isHeld(), is(false));
207     }
208 
209     @Test
test_releasesWakeLock_abortingLowPowerDelayed()210     public void test_releasesWakeLock_abortingLowPowerDelayed() {
211         // Transition to low power mode will be delayed to let
212         // animations play at 60 fps.
213         when(mDozeParameters.shouldDelayDisplayDozeTransition()).thenReturn(true);
214         mHandlerFake.setMode(QUEUEING);
215 
216         mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
217         mHandlerFake.dispatchQueuedMessages();
218 
219         mScreen.transitionTo(INITIALIZED, DOZE_AOD);
220         assertThat(mWakeLock.isHeld(), is(true));
221         mScreen.transitionTo(DOZE_AOD, FINISH);
222 
223         assertThat(mWakeLock.isHeld(), is(false));
224     }
225 
226     @Test
test_animatesPausing()227     public void test_animatesPausing() {
228         ArgumentCaptor<Runnable> captor = ArgumentCaptor.forClass(Runnable.class);
229         doAnswer(invocation -> null).when(mDozeHost).prepareForGentleSleep(captor.capture());
230         mHandlerFake.setMode(QUEUEING);
231 
232         mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
233         mScreen.transitionTo(INITIALIZED, DOZE_AOD_PAUSING);
234         mScreen.transitionTo(DOZE_AOD_PAUSING, DOZE_AOD_PAUSED);
235 
236         mHandlerFake.dispatchQueuedMessages();
237         verify(mDozeHost).prepareForGentleSleep(eq(captor.getValue()));
238         captor.getValue().run();
239         assertEquals(Display.STATE_OFF, mServiceFake.screenState);
240     }
241 
242     @Test
test_animatesOff()243     public void test_animatesOff() {
244         ArgumentCaptor<Runnable> captor = ArgumentCaptor.forClass(Runnable.class);
245         doAnswer(invocation -> null).when(mDozeHost).prepareForGentleSleep(captor.capture());
246         mHandlerFake.setMode(QUEUEING);
247 
248         mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
249         mScreen.transitionTo(INITIALIZED, DOZE_AOD);
250         mScreen.transitionTo(DOZE_AOD, DOZE);
251 
252         mHandlerFake.dispatchQueuedMessages();
253         verify(mDozeHost).prepareForGentleSleep(eq(captor.getValue()));
254         captor.getValue().run();
255         assertEquals(Display.STATE_OFF, mServiceFake.screenState);
256     }
257 
258     @Test
testDelayEnterDozeScreenState_whenUdfpsFingerDown()259     public void testDelayEnterDozeScreenState_whenUdfpsFingerDown() {
260         // GIVEN AOD is initialized
261         when(mDozeParameters.shouldControlScreenOff()).thenReturn(true);
262         mHandlerFake.setMode(QUEUEING);
263         mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
264         mHandlerFake.dispatchQueuedMessages();
265 
266         mScreen.transitionTo(INITIALIZED, DOZE_AOD);
267 
268         // WHEN udfps is activated (fingerDown)
269         when(mUdfpsController.isFingerDown()).thenReturn(true);
270         mHandlerFake.dispatchQueuedMessages();
271 
272         // THEN the display screen state doesn't immediately change
273         assertEquals(Display.STATE_ON, mServiceFake.screenState);
274 
275         // WHEN udfpsController finger is no longer down and the queued messages are run
276         when(mUdfpsController.isFingerDown()).thenReturn(false);
277         mHandlerFake.dispatchQueuedMessages();
278 
279         // THEN the display screen state will change
280         assertEquals(Display.STATE_DOZE_SUSPEND, mServiceFake.screenState);
281     }
282 
283     @Test
testDelayExitPulsingScreenState_whenUdfpsFingerDown()284     public void testDelayExitPulsingScreenState_whenUdfpsFingerDown() {
285         // GIVEN we're pulsing
286         when(mDozeParameters.shouldControlScreenOff()).thenReturn(true);
287         mHandlerFake.setMode(QUEUEING);
288         mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
289         mScreen.transitionTo(INITIALIZED, DOZE_AOD);
290         mScreen.transitionTo(DOZE_AOD, DOZE_REQUEST_PULSE);
291         mScreen.transitionTo(DOZE_REQUEST_PULSE, DOZE_PULSING);
292         mScreen.transitionTo(DOZE_PULSING, DOZE_PULSE_DONE);
293         mHandlerFake.dispatchQueuedMessages();
294 
295         // WHEN udfps is activated while are transitioning back to DOZE_AOD
296         mScreen.transitionTo(DOZE_PULSE_DONE, DOZE_AOD);
297         when(mUdfpsController.isFingerDown()).thenReturn(true);
298         mHandlerFake.dispatchQueuedMessages();
299 
300         // THEN the display screen state doesn't immediately change
301         assertEquals(Display.STATE_ON, mServiceFake.screenState);
302 
303         // WHEN udfpsController finger is no longer down and the queued messages are run
304         when(mUdfpsController.isFingerDown()).thenReturn(false);
305         mHandlerFake.dispatchQueuedMessages();
306 
307         // THEN the display screen state will change
308         assertEquals(Display.STATE_DOZE_SUSPEND, mServiceFake.screenState);
309     }
310 
311     @Test
authCallbackRemovedOnDestroy()312     public void authCallbackRemovedOnDestroy() {
313         mScreen.destroy();
314 
315         verify(mAuthController).removeCallback(anyObject());
316     }
317 }