1 /*
2  * Copyright (C) 2020 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.util.sensors;
18 
19 import static android.hardware.Sensor.TYPE_ALL;
20 
21 import static org.junit.Assert.assertEquals;
22 import static org.junit.Assert.assertFalse;
23 import static org.junit.Assert.assertTrue;
24 import static org.mockito.Mockito.mock;
25 import static org.mockito.Mockito.when;
26 
27 import android.hardware.Sensor;
28 import android.testing.AndroidTestingRunner;
29 
30 import androidx.test.filters.SmallTest;
31 
32 import com.android.systemui.SysuiTestCase;
33 import com.android.systemui.util.concurrency.FakeExecution;
34 import com.android.systemui.util.concurrency.FakeExecutor;
35 import com.android.systemui.util.concurrency.FakeThreadFactory;
36 import com.android.systemui.util.time.FakeSystemClock;
37 
38 import org.junit.Before;
39 import org.junit.Test;
40 import org.junit.runner.RunWith;
41 
42 import java.util.List;
43 
44 @SmallTest
45 @RunWith(AndroidTestingRunner.class)
46 public class ThresholdSensorImplTest extends SysuiTestCase {
47 
48     private ThresholdSensorImpl mThresholdSensor;
49     private FakeSensorManager mSensorManager;
50     private AsyncSensorManager mAsyncSensorManager;
51     private FakeSensorManager.FakeProximitySensor mFakeProximitySensor;
52     private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
53 
54     @Before
setUp()55     public void setUp() throws Exception {
56         mSensorManager = new FakeSensorManager(getContext());
57 
58         mAsyncSensorManager = new AsyncSensorManager(
59                 mSensorManager, new FakeThreadFactory(mFakeExecutor), null);
60 
61         mFakeProximitySensor = mSensorManager.getFakeProximitySensor();
62         ThresholdSensorImpl.Builder thresholdSensorBuilder = new ThresholdSensorImpl.Builder(
63                 null, mAsyncSensorManager, new FakeExecution());
64         mThresholdSensor = (ThresholdSensorImpl) thresholdSensorBuilder
65                 .setSensor(mFakeProximitySensor.getSensor())
66                 .setThresholdValue(mFakeProximitySensor.getSensor().getMaximumRange())
67                 .build();
68     }
69 
70     @Test
testRegistersWakeUpProxSensor_givenWakeUpExistsAfterNonWakeup()71     public void testRegistersWakeUpProxSensor_givenWakeUpExistsAfterNonWakeup() {
72         // GIVEN sensor manager with two prox sensors (one non-wakeup, one wakeup)
73         final String sensorTypeProx = "prox";
74         AsyncSensorManager mockSensorManager = mock(AsyncSensorManager.class);
75 
76         Sensor mockNonWakeupProx = mock(Sensor.class);
77         when(mockNonWakeupProx.isWakeUpSensor()).thenReturn(false);
78         when(mockNonWakeupProx.getStringType()).thenReturn(sensorTypeProx);
79 
80         Sensor mockWakeupProx = mock(Sensor.class);
81         when(mockWakeupProx.isWakeUpSensor()).thenReturn(true);
82         when(mockWakeupProx.getStringType()).thenReturn(sensorTypeProx);
83 
84         when(mockSensorManager.getSensorList(TYPE_ALL)).thenReturn(
85                 List.of(mockNonWakeupProx, mockWakeupProx));
86 
87         // WHEN we build a threshold sensor by type
88         ThresholdSensorImpl.Builder thresholdSensorBuilder = new ThresholdSensorImpl.Builder(
89                 null, mockSensorManager, new FakeExecution());
90         Sensor proxSensor = thresholdSensorBuilder.findSensorByType(sensorTypeProx, true);
91 
92         // THEN the prox sensor used is the wakeup sensor
93         assertEquals(mockWakeupProx, proxSensor);
94     }
95 
96     @Test
testRegistersWakeUpProxSensor_givenNonWakeUpExistsAfterWakeup()97     public void testRegistersWakeUpProxSensor_givenNonWakeUpExistsAfterWakeup() {
98         // GIVEN sensor manager with two prox sensors (one wakeup, one non-wakeup)
99         final String sensorTypeProx = "prox";
100         AsyncSensorManager mockSensorManager = mock(AsyncSensorManager.class);
101 
102         Sensor mockNonWakeupProx = mock(Sensor.class);
103         when(mockNonWakeupProx.isWakeUpSensor()).thenReturn(false);
104         when(mockNonWakeupProx.getStringType()).thenReturn(sensorTypeProx);
105 
106         Sensor mockWakeupProx = mock(Sensor.class);
107         when(mockWakeupProx.isWakeUpSensor()).thenReturn(true);
108         when(mockWakeupProx.getStringType()).thenReturn(sensorTypeProx);
109 
110         when(mockSensorManager.getSensorList(TYPE_ALL)).thenReturn(
111                 List.of(mockWakeupProx, mockNonWakeupProx));
112 
113         // WHEN we build a threshold sensor by type
114         ThresholdSensorImpl.Builder thresholdSensorBuilder = new ThresholdSensorImpl.Builder(
115                 null, mockSensorManager, new FakeExecution());
116         Sensor proxSensor = thresholdSensorBuilder.findSensorByType(sensorTypeProx, true);
117 
118         // THEN the prox sensor used is the wakeup sensor
119         assertEquals(mockWakeupProx, proxSensor);
120     }
121 
122     @Test
testRegistersNonWakeUpProxSensor_givenNonWakeUpOnly()123     public void testRegistersNonWakeUpProxSensor_givenNonWakeUpOnly() {
124         // GIVEN sensor manager with one non-wakeup prox sensor
125         final String sensorTypeProx = "prox";
126         AsyncSensorManager mockSensorManager = mock(AsyncSensorManager.class);
127 
128         Sensor mockNonWakeupProx = mock(Sensor.class);
129         when(mockNonWakeupProx.isWakeUpSensor()).thenReturn(false);
130         when(mockNonWakeupProx.getStringType()).thenReturn(sensorTypeProx);
131 
132         when(mockSensorManager.getSensorList(TYPE_ALL)).thenReturn(List.of(mockNonWakeupProx));
133 
134         // WHEN we build a threshold sensor by type
135         ThresholdSensorImpl.Builder thresholdSensorBuilder = new ThresholdSensorImpl.Builder(
136                 null, mockSensorManager, new FakeExecution());
137         Sensor proxSensor = thresholdSensorBuilder.findSensorByType(sensorTypeProx, true);
138 
139         // THEN the prox sensor used is the one available (non-wakeup)
140         assertEquals(mockNonWakeupProx, proxSensor);
141     }
142 
143     @Test
testSingleListener()144     public void testSingleListener() {
145         TestableListener listener = new TestableListener();
146 
147         assertFalse(mThresholdSensor.isRegistered());
148         mThresholdSensor.register(listener);
149         waitForSensorManager();
150         assertTrue(mThresholdSensor.isRegistered());
151         assertEquals(0, listener.mCallCount);
152 
153         mFakeProximitySensor.sendProximityResult(true);
154         assertFalse(listener.mBelow);
155         assertEquals(1, listener.mCallCount);
156         mFakeProximitySensor.sendProximityResult(false);
157         assertTrue(listener.mBelow);
158         assertEquals(2, listener.mCallCount);
159 
160         mThresholdSensor.unregister(listener);
161         waitForSensorManager();
162     }
163 
164     @Test
testMultiListener()165     public void testMultiListener() {
166         TestableListener listenerA = new TestableListener();
167         TestableListener listenerB = new TestableListener();
168 
169         assertFalse(mThresholdSensor.isRegistered());
170 
171         mThresholdSensor.register(listenerA);
172         waitForSensorManager();
173         assertTrue(mThresholdSensor.isRegistered());
174         mThresholdSensor.register(listenerB);
175         waitForSensorManager();
176         assertTrue(mThresholdSensor.isRegistered());
177         assertEquals(0, listenerA.mCallCount);
178         assertEquals(0, listenerB.mCallCount);
179 
180 
181         mFakeProximitySensor.sendProximityResult(true);
182         assertFalse(listenerA.mBelow);
183         assertFalse(listenerB.mBelow);
184         assertEquals(1, listenerA.mCallCount);
185         assertEquals(1, listenerB.mCallCount);
186         mFakeProximitySensor.sendProximityResult(false);
187         assertTrue(listenerA.mBelow);
188         assertTrue(listenerB.mBelow);
189         assertEquals(2, listenerA.mCallCount);
190         assertEquals(2, listenerB.mCallCount);
191 
192         mThresholdSensor.unregister(listenerA);
193         mThresholdSensor.unregister(listenerB);
194         waitForSensorManager();
195     }
196 
197     @Test
testDuplicateListener()198     public void testDuplicateListener() {
199         TestableListener listenerA = new TestableListener();
200 
201         assertFalse(mThresholdSensor.isRegistered());
202 
203         mThresholdSensor.register(listenerA);
204         waitForSensorManager();
205         assertTrue(mThresholdSensor.isRegistered());
206         mThresholdSensor.register(listenerA);
207         waitForSensorManager();
208         assertTrue(mThresholdSensor.isRegistered());
209         assertEquals(0, listenerA.mCallCount);
210 
211         mFakeProximitySensor.sendProximityResult(true);
212         assertFalse(listenerA.mBelow);
213         assertEquals(1, listenerA.mCallCount);
214         mFakeProximitySensor.sendProximityResult(false);
215         assertTrue(listenerA.mBelow);
216         assertEquals(2, listenerA.mCallCount);
217 
218         mThresholdSensor.unregister(listenerA);
219         waitForSensorManager();
220     }
221     @Test
testUnregister()222     public void testUnregister() {
223         TestableListener listener = new TestableListener();
224 
225         assertFalse(mThresholdSensor.isRegistered());
226         mThresholdSensor.register(listener);
227         waitForSensorManager();
228         assertTrue(mThresholdSensor.isRegistered());
229         assertEquals(0, listener.mCallCount);
230 
231         mFakeProximitySensor.sendProximityResult(true);
232         assertFalse(listener.mBelow);
233         assertEquals(1, listener.mCallCount);
234 
235         mThresholdSensor.unregister(listener);
236         waitForSensorManager();
237         assertFalse(mThresholdSensor.isRegistered());
238     }
239 
240     @Test
testPauseAndResume()241     public void testPauseAndResume() {
242         TestableListener listener = new TestableListener();
243 
244         assertFalse(mThresholdSensor.isRegistered());
245         mThresholdSensor.register(listener);
246         waitForSensorManager();
247         assertTrue(mThresholdSensor.isRegistered());
248         assertEquals(0, listener.mCallCount);
249 
250         mFakeProximitySensor.sendProximityResult(true);
251         assertFalse(listener.mBelow);
252         assertEquals(1, listener.mCallCount);
253 
254         mThresholdSensor.pause();
255         waitForSensorManager();
256         assertFalse(mThresholdSensor.isRegistered());
257 
258         // More events do nothing when paused.
259         mFakeProximitySensor.sendProximityResult(true);
260         assertFalse(listener.mBelow);
261         assertEquals(1, listener.mCallCount);
262         mFakeProximitySensor.sendProximityResult(false);
263         assertFalse(listener.mBelow);
264         assertEquals(1, listener.mCallCount);
265 
266         mThresholdSensor.resume();
267         waitForSensorManager();
268         assertTrue(mThresholdSensor.isRegistered());
269         // Still matches our previous call
270         assertFalse(listener.mBelow);
271         assertEquals(1, listener.mCallCount);
272 
273         mFakeProximitySensor.sendProximityResult(false);
274         assertTrue(listener.mBelow);
275         assertEquals(2, listener.mCallCount);
276 
277         mThresholdSensor.unregister(listener);
278         waitForSensorManager();
279         assertFalse(mThresholdSensor.isRegistered());
280     }
281 
282     @Test
testAlertListeners()283     public void testAlertListeners() {
284         TestableListener listenerA = new TestableListener();
285         TestableListener listenerB = new TestableListener();
286 
287         assertFalse(mThresholdSensor.isRegistered());
288 
289         mThresholdSensor.register(listenerA);
290         mThresholdSensor.register(listenerB);
291         waitForSensorManager();
292         assertTrue(mThresholdSensor.isRegistered());
293         assertEquals(0, listenerA.mCallCount);
294         assertEquals(0, listenerB.mCallCount);
295 
296         mFakeProximitySensor.sendProximityResult(true);
297         assertFalse(listenerA.mBelow);
298         assertEquals(1, listenerA.mCallCount);
299         assertFalse(listenerB.mBelow);
300         assertEquals(1, listenerB.mCallCount);
301 
302         mFakeProximitySensor.sendProximityResult(false);
303         assertTrue(listenerA.mBelow);
304         assertEquals(2, listenerA.mCallCount);
305         assertTrue(listenerB.mBelow);
306         assertEquals(2, listenerB.mCallCount);
307 
308         mThresholdSensor.unregister(listenerA);
309         mThresholdSensor.unregister(listenerB);
310         waitForSensorManager();
311     }
312 
313     @Test
testHysteresis()314     public void testHysteresis() {
315         float lowValue = 10f;
316         float highValue = 100f;
317         FakeSensorManager.FakeGenericSensor sensor = mSensorManager.getFakeLightSensor();
318         ThresholdSensorImpl.Builder thresholdSensorBuilder = new ThresholdSensorImpl.Builder(
319                 null, mAsyncSensorManager, new FakeExecution());
320         ThresholdSensorImpl thresholdSensor = (ThresholdSensorImpl) thresholdSensorBuilder
321                 .setSensor(sensor.getSensor())
322                 .setThresholdValue(lowValue)
323                 .setThresholdLatchValue(highValue)
324                 .build();
325 
326         TestableListener listener = new TestableListener();
327 
328         assertFalse(thresholdSensor.isRegistered());
329         thresholdSensor.register(listener);
330         waitForSensorManager();
331         assertTrue(thresholdSensor.isRegistered());
332         assertEquals(0, listener.mCallCount);
333 
334         sensor.sendSensorEvent(lowValue - 1);
335 
336         assertTrue(listener.mBelow);
337         assertEquals(1, listener.mCallCount);
338 
339         sensor.sendSensorEvent(lowValue + 1);
340 
341         assertTrue(listener.mBelow);
342         assertEquals(1, listener.mCallCount);
343 
344         sensor.sendSensorEvent(highValue);
345 
346         assertFalse(listener.mBelow);
347         assertEquals(2, listener.mCallCount);
348 
349         sensor.sendSensorEvent(highValue - 1);
350 
351         assertFalse(listener.mBelow);
352         assertEquals(2, listener.mCallCount);
353 
354 
355         sensor.sendSensorEvent(lowValue - 1);
356 
357         assertTrue(listener.mBelow);
358         assertEquals(3, listener.mCallCount);
359     }
360 
361     @Test
testAlertAfterPause()362     public void testAlertAfterPause() {
363         TestableListener listener = new TestableListener();
364 
365         mThresholdSensor.register(listener);
366         waitForSensorManager();
367         mFakeProximitySensor.sendProximityResult(false);
368         assertTrue(listener.mBelow);
369         assertEquals(1, listener.mCallCount);
370 
371         mThresholdSensor.pause();
372 
373         mFakeProximitySensor.sendProximityResult(false);
374         assertTrue(listener.mBelow);
375         assertEquals(1, listener.mCallCount);
376     }
377 
378     static class TestableListener implements ThresholdSensor.Listener {
379         boolean mBelow;
380         long mTimestampNs;
381         int mCallCount;
382 
383         @Override
onThresholdCrossed(ThresholdSensorEvent event)384         public void onThresholdCrossed(ThresholdSensorEvent event) {
385             mBelow = event.getBelow();
386             mTimestampNs = event.getTimestampNs();
387             mCallCount++;
388         }
389     }
390 
waitForSensorManager()391     private void waitForSensorManager() {
392         mFakeExecutor.runAllReady();
393     }
394 
395 }
396