1/*
2 * Copyright (C) 2016 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
17package com.android.systemui.doze;
18
19import static com.android.systemui.doze.DozeMachine.State.DOZE;
20import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD;
21import static com.android.systemui.doze.DozeMachine.State.DOZE_PULSE_DONE;
22import static com.android.systemui.doze.DozeMachine.State.DOZE_PULSING;
23import static com.android.systemui.doze.DozeMachine.State.DOZE_REQUEST_PULSE;
24import static com.android.systemui.doze.DozeMachine.State.FINISH;
25import static com.android.systemui.doze.DozeMachine.State.INITIALIZED;
26import static com.android.systemui.doze.DozeMachine.State.UNINITIALIZED;
27
28import static org.junit.Assert.assertEquals;
29import static org.junit.Assert.assertFalse;
30import static org.junit.Assert.assertTrue;
31import static org.mockito.ArgumentMatchers.anyInt;
32import static org.mockito.ArgumentMatchers.any;
33import static org.mockito.ArgumentMatchers.eq;
34import static org.mockito.Mockito.doAnswer;
35import static org.mockito.Mockito.mock;
36import static org.mockito.Mockito.never;
37import static org.mockito.Mockito.reset;
38import static org.mockito.Mockito.verify;
39import static org.mockito.Mockito.when;
40
41import android.support.test.filters.SmallTest;
42import android.testing.AndroidTestingRunner;
43import android.view.Display;
44
45import com.android.internal.hardware.AmbientDisplayConfiguration;
46import com.android.systemui.SysuiTestCase;
47import com.android.systemui.util.wakelock.WakeLockFake;
48
49import android.testing.UiThreadTest;
50
51import org.junit.Before;
52import org.junit.Test;
53import org.junit.runner.RunWith;
54
55@SmallTest
56@RunWith(AndroidTestingRunner.class)
57@UiThreadTest
58public class DozeMachineTest extends SysuiTestCase {
59
60    DozeMachine mMachine;
61
62    private DozeServiceFake mServiceFake;
63    private WakeLockFake mWakeLockFake;
64    private AmbientDisplayConfiguration mConfigMock;
65    private DozeMachine.Part mPartMock;
66
67    @Before
68    public void setUp() {
69        mServiceFake = new DozeServiceFake();
70        mWakeLockFake = new WakeLockFake();
71        mConfigMock = mock(AmbientDisplayConfiguration.class);
72        mPartMock = mock(DozeMachine.Part.class);
73
74        mMachine = new DozeMachine(mServiceFake, mConfigMock, mWakeLockFake);
75
76        mMachine.setParts(new DozeMachine.Part[]{mPartMock});
77    }
78
79    @Test
80    public void testInitialize_initializesParts() {
81        mMachine.requestState(INITIALIZED);
82
83        verify(mPartMock).transitionTo(UNINITIALIZED, INITIALIZED);
84    }
85
86    @Test
87    public void testInitialize_goesToDoze() {
88        when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(false);
89
90        mMachine.requestState(INITIALIZED);
91
92        verify(mPartMock).transitionTo(INITIALIZED, DOZE);
93        assertEquals(DOZE, mMachine.getState());
94    }
95
96    @Test
97    public void testInitialize_goesToAod() {
98        when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(true);
99
100        mMachine.requestState(INITIALIZED);
101
102        verify(mPartMock).transitionTo(INITIALIZED, DOZE_AOD);
103        assertEquals(DOZE_AOD, mMachine.getState());
104    }
105
106    @Test
107    public void testPulseDone_goesToDoze() {
108        when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(false);
109        mMachine.requestState(INITIALIZED);
110        mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
111        mMachine.requestState(DOZE_PULSING);
112
113        mMachine.requestState(DOZE_PULSE_DONE);
114
115        verify(mPartMock).transitionTo(DOZE_PULSE_DONE, DOZE);
116        assertEquals(DOZE, mMachine.getState());
117    }
118
119    @Test
120    public void testPulseDone_goesToAoD() {
121        when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(true);
122        mMachine.requestState(INITIALIZED);
123        mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
124        mMachine.requestState(DOZE_PULSING);
125
126        mMachine.requestState(DOZE_PULSE_DONE);
127
128        verify(mPartMock).transitionTo(DOZE_PULSE_DONE, DOZE_AOD);
129        assertEquals(DOZE_AOD, mMachine.getState());
130    }
131
132    @Test
133    public void testFinished_staysFinished() {
134        mMachine.requestState(INITIALIZED);
135        mMachine.requestState(FINISH);
136        reset(mPartMock);
137
138        mMachine.requestState(DOZE);
139
140        verify(mPartMock, never()).transitionTo(any(), any());
141        assertEquals(FINISH, mMachine.getState());
142    }
143
144    @Test
145    public void testFinish_finishesService() {
146        mMachine.requestState(INITIALIZED);
147
148        mMachine.requestState(FINISH);
149
150        assertTrue(mServiceFake.finished);
151    }
152
153    @Test
154    public void testWakeLock_heldInTransition() {
155        doAnswer((inv) -> {
156            assertTrue(mWakeLockFake.isHeld());
157            return null;
158        }).when(mPartMock).transitionTo(any(), any());
159
160        mMachine.requestState(INITIALIZED);
161    }
162
163    @Test
164    public void testWakeLock_heldInPulseStates() {
165        mMachine.requestState(INITIALIZED);
166
167        mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
168        assertTrue(mWakeLockFake.isHeld());
169
170        mMachine.requestState(DOZE_PULSING);
171        assertTrue(mWakeLockFake.isHeld());
172    }
173
174    @Test
175    public void testWakeLock_notHeldInDozeStates() {
176        mMachine.requestState(INITIALIZED);
177
178        mMachine.requestState(DOZE);
179        assertFalse(mWakeLockFake.isHeld());
180
181        mMachine.requestState(DOZE_AOD);
182        assertFalse(mWakeLockFake.isHeld());
183    }
184
185    @Test
186    public void testWakeLock_releasedAfterPulse() {
187        mMachine.requestState(INITIALIZED);
188
189        mMachine.requestState(DOZE);
190        mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
191        mMachine.requestState(DOZE_PULSING);
192        mMachine.requestState(DOZE_PULSE_DONE);
193
194        assertFalse(mWakeLockFake.isHeld());
195    }
196
197    @Test
198    public void testPulseDuringPulse_doesntCrash() {
199        mMachine.requestState(INITIALIZED);
200
201        mMachine.requestState(DOZE);
202        mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
203        mMachine.requestState(DOZE_PULSING);
204        mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
205        mMachine.requestState(DOZE_PULSE_DONE);
206    }
207
208    @Test
209    public void testSuppressingPulse_doesntCrash() {
210        mMachine.requestState(INITIALIZED);
211
212        mMachine.requestState(DOZE);
213        mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
214        mMachine.requestState(DOZE_PULSE_DONE);
215    }
216
217    @Test
218    public void testTransitions_canRequestTransitions() {
219        mMachine.requestState(INITIALIZED);
220        mMachine.requestState(DOZE);
221        doAnswer(inv -> {
222            mMachine.requestState(DOZE_PULSING);
223            return null;
224        }).when(mPartMock).transitionTo(any(), eq(DOZE_REQUEST_PULSE));
225
226        mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
227
228        assertEquals(DOZE_PULSING, mMachine.getState());
229    }
230
231    @Test
232    public void testPulseReason_getMatchesRequest() {
233        mMachine.requestState(INITIALIZED);
234        mMachine.requestState(DOZE);
235        mMachine.requestPulse(DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP);
236
237        assertEquals(DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP, mMachine.getPulseReason());
238    }
239
240    @Test
241    public void testPulseReason_getFromTransition() {
242        mMachine.requestState(INITIALIZED);
243        mMachine.requestState(DOZE);
244        doAnswer(inv -> {
245            DozeMachine.State newState = inv.getArgument(1);
246            if (newState == DOZE_REQUEST_PULSE
247                    || newState == DOZE_PULSING
248                    || newState == DOZE_PULSE_DONE) {
249                assertEquals(DozeLog.PULSE_REASON_NOTIFICATION, mMachine.getPulseReason());
250            } else {
251                assertTrue("unexpected state " + newState,
252                        newState == DOZE || newState == DOZE_AOD);
253            }
254            return null;
255        }).when(mPartMock).transitionTo(any(), any());
256
257        mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
258        mMachine.requestState(DOZE_PULSING);
259        mMachine.requestState(DOZE_PULSE_DONE);
260    }
261
262    @Test
263    public void testWakeUp_wakesUp() {
264        mMachine.wakeUp();
265
266        assertTrue(mServiceFake.requestedWakeup);
267    }
268}
269