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