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.server;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertFalse;
21 import static org.junit.Assert.assertTrue;
22 import static org.mockito.ArgumentMatchers.any;
23 import static org.mockito.Matchers.anyInt;
24 import static org.mockito.Matchers.eq;
25 import static org.mockito.Mockito.never;
26 import static org.mockito.Mockito.times;
27 import static org.mockito.Mockito.verify;
28 import static org.mockito.Mockito.when;
29 
30 import android.app.StatusBarManager;
31 import android.content.Context;
32 import android.content.Intent;
33 import android.content.res.Resources;
34 import android.os.Looper;
35 import android.os.UserHandle;
36 import android.platform.test.annotations.Presubmit;
37 import android.provider.Settings;
38 import android.telecom.TelecomManager;
39 import android.test.mock.MockContentResolver;
40 import android.testing.TestableLooper;
41 import android.util.MutableBoolean;
42 import android.view.KeyEvent;
43 
44 import androidx.test.InstrumentationRegistry;
45 import androidx.test.filters.SmallTest;
46 import androidx.test.runner.AndroidJUnit4;
47 
48 import com.android.internal.logging.MetricsLogger;
49 import com.android.internal.logging.UiEventLogger;
50 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
51 import com.android.internal.util.test.FakeSettingsProvider;
52 import com.android.server.statusbar.StatusBarManagerInternal;
53 
54 import org.junit.Before;
55 import org.junit.BeforeClass;
56 import org.junit.Test;
57 import org.junit.runner.RunWith;
58 import org.mockito.ArgumentCaptor;
59 import org.mockito.Mock;
60 import org.mockito.MockitoAnnotations;
61 
62 import java.util.List;
63 
64 /**
65  * Unit tests for {@link GestureLauncherService}.
66  * runtest frameworks-services -c com.android.server.GestureLauncherServiceTest
67  */
68 @Presubmit
69 @SmallTest
70 @RunWith(AndroidJUnit4.class)
71 @TestableLooper.RunWithLooper(setAsMainLooper = true)
72 public class GestureLauncherServiceTest {
73 
74     private static final int FAKE_USER_ID = 1337;
75     private static final int FAKE_SOURCE = 1982;
76     private static final long INITIAL_EVENT_TIME_MILLIS = 20000L;
77     private static final long IGNORED_DOWN_TIME = 1234L;
78     private static final int IGNORED_ACTION = 13;
79     private static final int IGNORED_CODE = 1999;
80     private static final int IGNORED_REPEAT = 42;
81     private static final int IGNORED_META_STATE = 0;
82     private static final int IGNORED_DEVICE_ID = 0;
83     private static final int IGNORED_SCANCODE = 0;
84 
85     private @Mock Context mContext;
86     private @Mock Resources mResources;
87     private @Mock StatusBarManagerInternal mStatusBarManagerInternal;
88     private @Mock TelecomManager mTelecomManager;
89     private @Mock MetricsLogger mMetricsLogger;
90     @Mock private UiEventLogger mUiEventLogger;
91     private MockContentResolver mContentResolver;
92     private GestureLauncherService mGestureLauncherService;
93 
94     @BeforeClass
oneTimeInitialization()95     public static void oneTimeInitialization() {
96         if (Looper.myLooper() == null) {
97             Looper.prepare();
98         }
99     }
100 
101     @Before
setup()102     public void setup() {
103         MockitoAnnotations.initMocks(this);
104 
105         LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
106         LocalServices.addService(StatusBarManagerInternal.class, mStatusBarManagerInternal);
107 
108         final Context originalContext = InstrumentationRegistry.getContext();
109         when(mContext.getApplicationInfo()).thenReturn(originalContext.getApplicationInfo());
110         when(mContext.getResources()).thenReturn(mResources);
111         mContentResolver = new MockContentResolver(mContext);
112         mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
113         when(mContext.getContentResolver()).thenReturn(mContentResolver);
114         when(mContext.getSystemService(Context.TELECOM_SERVICE)).thenReturn(mTelecomManager);
115         when(mTelecomManager.createLaunchEmergencyDialerIntent(null)).thenReturn(new Intent());
116 
117         mGestureLauncherService = new GestureLauncherService(mContext, mMetricsLogger,
118                 mUiEventLogger);
119     }
120 
121     @Test
testIsCameraDoubleTapPowerEnabled_configFalse()122     public void testIsCameraDoubleTapPowerEnabled_configFalse() {
123         withCameraDoubleTapPowerEnableConfigValue(false);
124         assertFalse(mGestureLauncherService.isCameraDoubleTapPowerEnabled(mResources));
125     }
126 
127     @Test
testIsCameraDoubleTapPowerEnabled_configTrue()128     public void testIsCameraDoubleTapPowerEnabled_configTrue() {
129         withCameraDoubleTapPowerEnableConfigValue(true);
130         assertTrue(mGestureLauncherService.isCameraDoubleTapPowerEnabled(mResources));
131     }
132 
133     @Test
testIsCameraDoubleTapPowerSettingEnabled_configFalseSettingDisabled()134     public void testIsCameraDoubleTapPowerSettingEnabled_configFalseSettingDisabled() {
135         withCameraDoubleTapPowerEnableConfigValue(false);
136         withCameraDoubleTapPowerDisableSettingValue(1);
137         assertFalse(mGestureLauncherService.isCameraDoubleTapPowerSettingEnabled(
138                 mContext, FAKE_USER_ID));
139     }
140 
141     @Test
testIsCameraDoubleTapPowerSettingEnabled_configFalseSettingEnabled()142     public void testIsCameraDoubleTapPowerSettingEnabled_configFalseSettingEnabled() {
143         withCameraDoubleTapPowerEnableConfigValue(false);
144         withCameraDoubleTapPowerDisableSettingValue(0);
145         assertFalse(mGestureLauncherService.isCameraDoubleTapPowerSettingEnabled(
146                 mContext, FAKE_USER_ID));
147     }
148 
149     @Test
testIsCameraDoubleTapPowerSettingEnabled_configTrueSettingDisabled()150     public void testIsCameraDoubleTapPowerSettingEnabled_configTrueSettingDisabled() {
151         withCameraDoubleTapPowerEnableConfigValue(true);
152         withCameraDoubleTapPowerDisableSettingValue(1);
153         assertFalse(mGestureLauncherService.isCameraDoubleTapPowerSettingEnabled(
154                 mContext, FAKE_USER_ID));
155     }
156 
157     @Test
testIsCameraDoubleTapPowerSettingEnabled_configTrueSettingEnabled()158     public void testIsCameraDoubleTapPowerSettingEnabled_configTrueSettingEnabled() {
159         withCameraDoubleTapPowerEnableConfigValue(true);
160         withCameraDoubleTapPowerDisableSettingValue(0);
161         assertTrue(mGestureLauncherService.isCameraDoubleTapPowerSettingEnabled(
162                 mContext, FAKE_USER_ID));
163     }
164 
165     @Test
testIsEmergencyGestureSettingEnabled_settingDisabled()166     public void testIsEmergencyGestureSettingEnabled_settingDisabled() {
167         withEmergencyGestureEnabledConfigValue(true);
168         withEmergencyGestureEnabledSettingValue(false);
169         assertFalse(mGestureLauncherService.isEmergencyGestureSettingEnabled(
170                 mContext, FAKE_USER_ID));
171     }
172 
173     @Test
testIsEmergencyGestureSettingEnabled_settingEnabled()174     public void testIsEmergencyGestureSettingEnabled_settingEnabled() {
175         withEmergencyGestureEnabledConfigValue(true);
176         withEmergencyGestureEnabledSettingValue(true);
177         assertTrue(mGestureLauncherService.isEmergencyGestureSettingEnabled(
178                 mContext, FAKE_USER_ID));
179     }
180 
181     @Test
testIsEmergencyGestureSettingEnabled_supportDisabled()182     public void testIsEmergencyGestureSettingEnabled_supportDisabled() {
183         withEmergencyGestureEnabledConfigValue(false);
184         withEmergencyGestureEnabledSettingValue(true);
185         assertFalse(mGestureLauncherService.isEmergencyGestureSettingEnabled(
186                 mContext, FAKE_USER_ID));
187     }
188 
189     @Test
testHandleCameraLaunchGesture_userSetupComplete()190     public void testHandleCameraLaunchGesture_userSetupComplete() {
191         withUserSetupCompleteValue(true);
192 
193         boolean useWakeLock = false;
194         assertTrue(mGestureLauncherService.handleCameraGesture(useWakeLock, FAKE_SOURCE));
195         verify(mStatusBarManagerInternal).onCameraLaunchGestureDetected(FAKE_SOURCE);
196     }
197 
198     @Test
testHandleEmergencyGesture_userSetupComplete()199     public void testHandleEmergencyGesture_userSetupComplete() {
200         withUserSetupCompleteValue(true);
201 
202         assertTrue(mGestureLauncherService.handleEmergencyGesture());
203     }
204 
205     @Test
testHandleCameraLaunchGesture_userSetupNotComplete()206     public void testHandleCameraLaunchGesture_userSetupNotComplete() {
207         withUserSetupCompleteValue(false);
208 
209         boolean useWakeLock = false;
210         assertFalse(mGestureLauncherService.handleCameraGesture(useWakeLock, FAKE_SOURCE));
211     }
212 
213     @Test
testHandleEmergencyGesture_userSetupNotComplete()214     public void testHandleEmergencyGesture_userSetupNotComplete() {
215         withUserSetupCompleteValue(false);
216 
217         assertFalse(mGestureLauncherService.handleEmergencyGesture());
218     }
219 
220     @Test
testInterceptPowerKeyDown_firstPowerDownCameraPowerGestureOnInteractive()221     public void testInterceptPowerKeyDown_firstPowerDownCameraPowerGestureOnInteractive() {
222         withCameraDoubleTapPowerEnableConfigValue(true);
223         withCameraDoubleTapPowerDisableSettingValue(0);
224         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
225 
226         long eventTime = INITIAL_EVENT_TIME_MILLIS +
227                 GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
228         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
229                 IGNORED_REPEAT);
230         boolean interactive = true;
231         MutableBoolean outLaunched = new MutableBoolean(true);
232         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
233                 outLaunched);
234         assertFalse(intercepted);
235         assertFalse(outLaunched.value);
236         verify(mMetricsLogger).histogram("power_consecutive_short_tap_count", 1);
237         verify(mMetricsLogger).histogram("power_double_tap_interval", (int) eventTime);
238     }
239 
240     @Test
testInterceptPowerKeyDown_firstPowerDown_emergencyGestureNotLaunched()241     public void testInterceptPowerKeyDown_firstPowerDown_emergencyGestureNotLaunched() {
242         withEmergencyGestureEnabledSettingValue(true);
243         mGestureLauncherService.updateEmergencyGestureEnabled();
244 
245         long eventTime = INITIAL_EVENT_TIME_MILLIS
246                 + GestureLauncherService.POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS - 1;
247         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
248                 IGNORED_REPEAT);
249         boolean interactive = true;
250         MutableBoolean outLaunched = new MutableBoolean(true);
251         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
252                 outLaunched);
253 
254         assertFalse(intercepted);
255         assertFalse(outLaunched.value);
256         verify(mMetricsLogger).histogram("power_double_tap_interval", (int) eventTime);
257     }
258 
259     @Test
testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOffInteractive()260     public void testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOffInteractive() {
261         withCameraDoubleTapPowerEnableConfigValue(false);
262         withCameraDoubleTapPowerDisableSettingValue(1);
263         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
264 
265         long eventTime = INITIAL_EVENT_TIME_MILLIS;
266         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
267                 IGNORED_REPEAT);
268         boolean interactive = true;
269         MutableBoolean outLaunched = new MutableBoolean(true);
270         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
271                 outLaunched);
272         assertFalse(intercepted);
273         assertFalse(outLaunched.value);
274 
275         final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
276         eventTime += interval;
277         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
278                 IGNORED_REPEAT);
279         outLaunched.value = true;
280         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
281                 outLaunched);
282         assertFalse(intercepted);
283         assertFalse(outLaunched.value);
284 
285         verify(mMetricsLogger, never())
286             .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
287         verify(mUiEventLogger, never()).log(any());
288 
289         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
290         verify(mMetricsLogger, times(2)).histogram(
291                 eq("power_double_tap_interval"), intervalCaptor.capture());
292         List<Integer> intervals = intervalCaptor.getAllValues();
293         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
294         assertEquals((int) interval, intervals.get(1).intValue());
295 
296         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
297         verify(mMetricsLogger, times(2)).histogram(
298                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
299         List<Integer> tapCounts = tapCountCaptor.getAllValues();
300         assertEquals(1, tapCounts.get(0).intValue());
301         assertEquals(2, tapCounts.get(1).intValue());
302     }
303 
304     @Test
testInterceptPowerKeyDown_intervalMidBoundsCameraPowerGestureOffInteractive()305     public void testInterceptPowerKeyDown_intervalMidBoundsCameraPowerGestureOffInteractive() {
306         withCameraDoubleTapPowerEnableConfigValue(false);
307         withCameraDoubleTapPowerDisableSettingValue(1);
308         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
309 
310         long eventTime = INITIAL_EVENT_TIME_MILLIS;
311         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
312                 IGNORED_REPEAT);
313         boolean interactive = true;
314         MutableBoolean outLaunched = new MutableBoolean(true);
315         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
316                 outLaunched);
317         assertFalse(intercepted);
318         assertFalse(outLaunched.value);
319 
320         final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS;
321         eventTime += interval;
322         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
323                 IGNORED_REPEAT);
324         outLaunched.value = true;
325         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
326                 outLaunched);
327         assertFalse(intercepted);
328         assertFalse(outLaunched.value);
329 
330         verify(mMetricsLogger, never())
331             .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
332         verify(mUiEventLogger, never()).log(any());
333 
334         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
335         verify(mMetricsLogger, times(2)).histogram(
336                 eq("power_double_tap_interval"), intervalCaptor.capture());
337         List<Integer> intervals = intervalCaptor.getAllValues();
338         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
339         assertEquals((int) interval, intervals.get(1).intValue());
340 
341         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
342         verify(mMetricsLogger, times(2)).histogram(
343                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
344         List<Integer> tapCounts = tapCountCaptor.getAllValues();
345         assertEquals(1, tapCounts.get(0).intValue());
346         // The interval is too long to launch the camera, but short enough to count as a
347         // sequential tap.
348         assertEquals(2, tapCounts.get(1).intValue());
349     }
350 
351     @Test
testInterceptPowerKeyDown_intervalOutOfBoundsCameraPowerGestureOffInteractive()352     public void testInterceptPowerKeyDown_intervalOutOfBoundsCameraPowerGestureOffInteractive() {
353         withCameraDoubleTapPowerEnableConfigValue(false);
354         withCameraDoubleTapPowerDisableSettingValue(1);
355         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
356 
357         long eventTime = INITIAL_EVENT_TIME_MILLIS;
358         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
359                 IGNORED_REPEAT);
360         boolean interactive = true;
361         MutableBoolean outLaunched = new MutableBoolean(true);
362         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
363                 outLaunched);
364         assertFalse(intercepted);
365         assertFalse(outLaunched.value);
366 
367         long interval = GestureLauncherService.POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS;
368         eventTime += interval;
369         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
370                 IGNORED_REPEAT);
371         outLaunched.value = true;
372         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
373                 outLaunched);
374         assertFalse(intercepted);
375         assertFalse(outLaunched.value);
376 
377         verify(mMetricsLogger, never())
378             .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
379         verify(mUiEventLogger, never()).log(any());
380 
381         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
382         verify(mMetricsLogger, times(2)).histogram(
383                 eq("power_double_tap_interval"), intervalCaptor.capture());
384         List<Integer> intervals = intervalCaptor.getAllValues();
385         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
386         assertEquals((int) interval, intervals.get(1).intValue());
387 
388         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
389         verify(mMetricsLogger, times(2)).histogram(
390                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
391         List<Integer> tapCounts = tapCountCaptor.getAllValues();
392         assertEquals(1, tapCounts.get(0).intValue());
393         assertEquals(1, tapCounts.get(1).intValue());
394     }
395 
396     @Test
397     public void
testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOnInteractiveSetupComplete()398     testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOnInteractiveSetupComplete() {
399         withCameraDoubleTapPowerEnableConfigValue(true);
400         withCameraDoubleTapPowerDisableSettingValue(0);
401         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
402         withUserSetupCompleteValue(true);
403 
404         long eventTime = INITIAL_EVENT_TIME_MILLIS;
405         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
406                 IGNORED_REPEAT);
407         boolean interactive = true;
408         MutableBoolean outLaunched = new MutableBoolean(true);
409         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
410                 outLaunched);
411         assertFalse(intercepted);
412         assertFalse(outLaunched.value);
413 
414         final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
415         eventTime += interval;
416         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
417                 IGNORED_REPEAT);
418         outLaunched.value = false;
419         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
420                 outLaunched);
421         assertTrue(intercepted);
422         assertTrue(outLaunched.value);
423 
424         verify(mStatusBarManagerInternal).onCameraLaunchGestureDetected(
425                 StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP);
426         verify(mMetricsLogger)
427             .action(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE, (int) interval);
428         verify(mUiEventLogger, times(1))
429                 .log(GestureLauncherService.GestureLauncherEvent.GESTURE_CAMERA_DOUBLE_TAP_POWER);
430 
431         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
432         verify(mMetricsLogger, times(2)).histogram(
433                 eq("power_double_tap_interval"), intervalCaptor.capture());
434         List<Integer> intervals = intervalCaptor.getAllValues();
435         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
436         assertEquals((int) interval, intervals.get(1).intValue());
437 
438         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
439         verify(mMetricsLogger, times(2)).histogram(
440                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
441         List<Integer> tapCounts = tapCountCaptor.getAllValues();
442         assertEquals(1, tapCounts.get(0).intValue());
443         assertEquals(2, tapCounts.get(1).intValue());
444     }
445 
446     @Test
447     public void
testInterceptPowerKeyDown_fiveInboundPresses_cameraAndEmergencyEnabled_bothLaunch()448             testInterceptPowerKeyDown_fiveInboundPresses_cameraAndEmergencyEnabled_bothLaunch() {
449         withCameraDoubleTapPowerEnableConfigValue(true);
450         withCameraDoubleTapPowerDisableSettingValue(0);
451         withEmergencyGestureEnabledConfigValue(true);
452         withEmergencyGestureEnabledSettingValue(true);
453         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
454         mGestureLauncherService.updateEmergencyGestureEnabled();
455         withUserSetupCompleteValue(true);
456 
457         // First button press does nothing
458         long eventTime = INITIAL_EVENT_TIME_MILLIS;
459         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
460                 IGNORED_REPEAT);
461         boolean interactive = true;
462         MutableBoolean outLaunched = new MutableBoolean(true);
463         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
464                 outLaunched);
465         assertFalse(intercepted);
466         assertFalse(outLaunched.value);
467 
468         final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
469 
470         // 2nd button triggers camera
471         eventTime += interval;
472         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
473                 IGNORED_REPEAT);
474         outLaunched.value = false;
475         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
476                 outLaunched);
477         assertTrue(intercepted);
478         assertTrue(outLaunched.value);
479 
480         // Camera checks
481         verify(mStatusBarManagerInternal).onCameraLaunchGestureDetected(
482                 StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP);
483         verify(mMetricsLogger)
484             .action(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE, (int) interval);
485         verify(mUiEventLogger, times(1))
486                 .log(GestureLauncherService.GestureLauncherEvent.GESTURE_CAMERA_DOUBLE_TAP_POWER);
487 
488         final ArgumentCaptor<Integer> cameraIntervalCaptor = ArgumentCaptor.forClass(Integer.class);
489         verify(mMetricsLogger, times(2)).histogram(
490                 eq("power_double_tap_interval"), cameraIntervalCaptor.capture());
491         List<Integer> cameraIntervals = cameraIntervalCaptor.getAllValues();
492         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, cameraIntervals.get(0).intValue());
493         assertEquals((int) interval, cameraIntervals.get(1).intValue());
494 
495         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
496         verify(mMetricsLogger, times(2)).histogram(
497                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
498         List<Integer> tapCounts = tapCountCaptor.getAllValues();
499         assertEquals(1, tapCounts.get(0).intValue());
500         assertEquals(2, tapCounts.get(1).intValue());
501 
502         // Continue the button presses for the emergency gesture.
503 
504         // Presses 3 and 4 should not trigger any gesture
505         for (int i = 0; i < 2; i++) {
506             eventTime += interval;
507             keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
508                     IGNORED_REPEAT);
509             outLaunched.value = false;
510             intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
511                     outLaunched);
512             assertTrue(intercepted);
513             assertFalse(outLaunched.value);
514         }
515 
516         // Fifth button press should trigger the emergency flow
517         eventTime += interval;
518         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
519                 IGNORED_REPEAT);
520         outLaunched.value = false;
521         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
522                 outLaunched);
523         assertTrue(intercepted);
524         assertTrue(outLaunched.value);
525 
526         verify(mUiEventLogger, times(1))
527                 .log(GestureLauncherService.GestureLauncherEvent.GESTURE_EMERGENCY_TAP_POWER);
528         verify(mStatusBarManagerInternal).onEmergencyActionLaunchGestureDetected();
529 
530         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
531         verify(mMetricsLogger, times(5)).histogram(
532                 eq("power_double_tap_interval"), intervalCaptor.capture());
533         List<Integer> intervals = intervalCaptor.getAllValues();
534         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
535         assertEquals((int) interval, intervals.get(1).intValue());
536     }
537 
538     @Test
539     public void
testInterceptPowerKeyDown_fiveInboundPresses_emergencyGestureEnabled_launchesFlow()540             testInterceptPowerKeyDown_fiveInboundPresses_emergencyGestureEnabled_launchesFlow() {
541         withEmergencyGestureEnabledConfigValue(true);
542         withEmergencyGestureEnabledSettingValue(true);
543         mGestureLauncherService.updateEmergencyGestureEnabled();
544         withUserSetupCompleteValue(true);
545 
546         // First button press does nothing
547         long eventTime = INITIAL_EVENT_TIME_MILLIS;
548         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
549                 IGNORED_REPEAT);
550         boolean interactive = true;
551         MutableBoolean outLaunched = new MutableBoolean(true);
552         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
553                 outLaunched);
554         assertFalse(intercepted);
555         assertFalse(outLaunched.value);
556 
557         final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
558         // 3 more button presses which should not trigger any gesture (camera gesture disabled)
559         for (int i = 0; i < 3; i++) {
560             eventTime += interval;
561             keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
562                     IGNORED_REPEAT);
563             outLaunched.value = false;
564             intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
565                     outLaunched);
566             assertTrue(intercepted);
567             assertFalse(outLaunched.value);
568         }
569 
570         // Fifth button press should trigger the emergency flow
571         eventTime += interval;
572         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
573                 IGNORED_REPEAT);
574         outLaunched.value = false;
575         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
576                 outLaunched);
577         assertTrue(outLaunched.value);
578         assertTrue(intercepted);
579 
580         verify(mUiEventLogger, times(1))
581                 .log(GestureLauncherService.GestureLauncherEvent.GESTURE_EMERGENCY_TAP_POWER);
582         verify(mStatusBarManagerInternal).onEmergencyActionLaunchGestureDetected();
583 
584         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
585         verify(mMetricsLogger, times(5)).histogram(
586                 eq("power_double_tap_interval"), intervalCaptor.capture());
587         List<Integer> intervals = intervalCaptor.getAllValues();
588         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
589         assertEquals((int) interval, intervals.get(1).intValue());
590     }
591 
592     @Test
593     public void
testInterceptPowerKeyDown_tenInboundPresses_emergencyGestureEnabled_keyIntercepted()594             testInterceptPowerKeyDown_tenInboundPresses_emergencyGestureEnabled_keyIntercepted() {
595         withEmergencyGestureEnabledConfigValue(true);
596         withEmergencyGestureEnabledSettingValue(true);
597         mGestureLauncherService.updateEmergencyGestureEnabled();
598         withUserSetupCompleteValue(true);
599 
600         // First button press does nothing
601         long eventTime = INITIAL_EVENT_TIME_MILLIS;
602         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
603                 IGNORED_REPEAT);
604         boolean interactive = true;
605         MutableBoolean outLaunched = new MutableBoolean(true);
606         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
607                 outLaunched);
608         assertFalse(intercepted);
609         assertFalse(outLaunched.value);
610 
611         final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
612         // 3 more button presses which should not trigger any gesture, but intercepts action.
613         for (int i = 0; i < 3; i++) {
614             eventTime += interval;
615             keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
616                     IGNORED_REPEAT);
617             outLaunched.value = false;
618             intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
619                     outLaunched);
620             assertTrue(intercepted);
621             assertFalse(outLaunched.value);
622         }
623 
624         // Fifth button press should trigger the emergency flow
625         eventTime += interval;
626         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
627                 IGNORED_REPEAT);
628         outLaunched.value = false;
629         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
630                 outLaunched);
631         assertTrue(outLaunched.value);
632         assertTrue(intercepted);
633 
634         // 5 more button presses which should not trigger any gesture, but intercepts action.
635         for (int i = 0; i < 5; i++) {
636             eventTime += interval;
637             keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
638                     IGNORED_REPEAT);
639             outLaunched.value = false;
640             intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
641                     outLaunched);
642             assertTrue(intercepted);
643             assertFalse(outLaunched.value);
644         }
645     }
646 
647     @Test
testInterceptPowerKeyDown_longpress()648     public void testInterceptPowerKeyDown_longpress() {
649         withCameraDoubleTapPowerEnableConfigValue(true);
650         withCameraDoubleTapPowerDisableSettingValue(0);
651         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
652         withUserSetupCompleteValue(true);
653 
654         long eventTime = INITIAL_EVENT_TIME_MILLIS;
655         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
656                 IGNORED_REPEAT);
657         boolean interactive = true;
658         MutableBoolean outLaunched = new MutableBoolean(true);
659         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
660                 outLaunched);
661         assertFalse(intercepted);
662         assertFalse(outLaunched.value);
663 
664         final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
665         eventTime += interval;
666         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
667                 IGNORED_REPEAT, IGNORED_META_STATE, IGNORED_DEVICE_ID, IGNORED_SCANCODE,
668                 KeyEvent.FLAG_LONG_PRESS);
669         outLaunched.value = false;
670         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
671                 outLaunched);
672         assertFalse(intercepted);
673         assertFalse(outLaunched.value);
674 
675         verify(mMetricsLogger, never())
676                 .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
677         verify(mUiEventLogger, never()).log(any());
678 
679         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
680         verify(mMetricsLogger, times(1)).histogram(
681                 eq("power_double_tap_interval"), intervalCaptor.capture());
682         List<Integer> intervals = intervalCaptor.getAllValues();
683         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
684 
685         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
686         verify(mMetricsLogger, times(1)).histogram(
687                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
688         List<Integer> tapCounts = tapCountCaptor.getAllValues();
689         assertEquals(1, tapCounts.get(0).intValue());
690     }
691 
692     @Test
693     public void
testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOnInteractiveSetupIncomplete()694     testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOnInteractiveSetupIncomplete() {
695         withCameraDoubleTapPowerEnableConfigValue(true);
696         withCameraDoubleTapPowerDisableSettingValue(0);
697         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
698         withUserSetupCompleteValue(false);
699 
700         long eventTime = INITIAL_EVENT_TIME_MILLIS;
701         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
702                 IGNORED_REPEAT);
703         boolean interactive = true;
704         MutableBoolean outLaunched = new MutableBoolean(true);
705         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
706                 outLaunched);
707         assertFalse(intercepted);
708         assertFalse(outLaunched.value);
709 
710         final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
711         eventTime += interval;
712         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
713                 IGNORED_REPEAT);
714         outLaunched.value = true;
715         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
716                 outLaunched);
717         assertFalse(intercepted);
718         assertFalse(outLaunched.value);
719 
720         verify(mMetricsLogger, never())
721             .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
722         verify(mUiEventLogger, never()).log(any());
723 
724         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
725         verify(mMetricsLogger, times(2)).histogram(
726                 eq("power_double_tap_interval"), intervalCaptor.capture());
727         List<Integer> intervals = intervalCaptor.getAllValues();
728         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
729         assertEquals((int) interval, intervals.get(1).intValue());
730 
731         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
732         verify(mMetricsLogger, times(2)).histogram(
733                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
734         List<Integer> tapCounts = tapCountCaptor.getAllValues();
735         assertEquals(1, tapCounts.get(0).intValue());
736         // The interval is too long to launch the camera, but short enough to count as a
737         // sequential tap.
738         assertEquals(2, tapCounts.get(1).intValue());
739     }
740 
741     @Test
testInterceptPowerKeyDown_intervalMidBoundsCameraPowerGestureOnInteractive()742     public void testInterceptPowerKeyDown_intervalMidBoundsCameraPowerGestureOnInteractive() {
743         withCameraDoubleTapPowerEnableConfigValue(true);
744         withCameraDoubleTapPowerDisableSettingValue(0);
745         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
746 
747         long eventTime = INITIAL_EVENT_TIME_MILLIS;
748         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
749                 IGNORED_REPEAT);
750         boolean interactive = true;
751         MutableBoolean outLaunched = new MutableBoolean(true);
752         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
753                 outLaunched);
754         assertFalse(intercepted);
755         assertFalse(outLaunched.value);
756 
757         final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS;
758         eventTime += interval;
759         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
760                 IGNORED_REPEAT);
761         outLaunched.value = true;
762         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
763                 outLaunched);
764         assertFalse(intercepted);
765         assertFalse(outLaunched.value);
766 
767         verify(mMetricsLogger, never())
768             .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
769         verify(mUiEventLogger, never()).log(any());
770 
771         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
772         verify(mMetricsLogger, times(2)).histogram(
773                 eq("power_double_tap_interval"), intervalCaptor.capture());
774         List<Integer> intervals = intervalCaptor.getAllValues();
775         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
776         assertEquals((int) interval, intervals.get(1).intValue());
777 
778         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
779         verify(mMetricsLogger, times(2)).histogram(
780                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
781         List<Integer> tapCounts = tapCountCaptor.getAllValues();
782         assertEquals(1, tapCounts.get(0).intValue());
783         // The interval is too long to launch the camera, but short enough to count as a
784         // sequential tap.
785         assertEquals(2, tapCounts.get(1).intValue());
786     }
787 
788     @Test
testInterceptPowerKeyDown_intervalOutOfBoundsCameraPowerGestureOnInteractive()789     public void testInterceptPowerKeyDown_intervalOutOfBoundsCameraPowerGestureOnInteractive() {
790         withCameraDoubleTapPowerEnableConfigValue(true);
791         withCameraDoubleTapPowerDisableSettingValue(0);
792         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
793 
794         long eventTime = INITIAL_EVENT_TIME_MILLIS;
795         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
796                 IGNORED_REPEAT);
797         boolean interactive = true;
798         MutableBoolean outLaunched = new MutableBoolean(true);
799         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
800                 outLaunched);
801         assertFalse(intercepted);
802         assertFalse(outLaunched.value);
803 
804         long interval = GestureLauncherService.POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS;
805         eventTime += interval;
806         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
807                 IGNORED_REPEAT);
808         outLaunched.value = true;
809         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
810                 outLaunched);
811         assertFalse(intercepted);
812         assertFalse(outLaunched.value);
813 
814         verify(mMetricsLogger, never())
815             .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
816         verify(mUiEventLogger, never()).log(any());
817 
818         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
819         verify(mMetricsLogger, times(2)).histogram(
820                 eq("power_double_tap_interval"), intervalCaptor.capture());
821         List<Integer> intervals = intervalCaptor.getAllValues();
822         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
823         assertEquals((int) interval, intervals.get(1).intValue());
824 
825         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
826         verify(mMetricsLogger, times(2)).histogram(
827                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
828         List<Integer> tapCounts = tapCountCaptor.getAllValues();
829         assertEquals(1, tapCounts.get(0).intValue());
830         assertEquals(1, tapCounts.get(1).intValue());
831     }
832 
833     @Test
testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOffNotInteractive()834     public void testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOffNotInteractive() {
835         withCameraDoubleTapPowerEnableConfigValue(false);
836         withCameraDoubleTapPowerDisableSettingValue(1);
837         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
838 
839         long eventTime = INITIAL_EVENT_TIME_MILLIS;
840         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
841                 IGNORED_REPEAT);
842         boolean interactive = false;
843         MutableBoolean outLaunched = new MutableBoolean(true);
844         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
845                 outLaunched);
846         assertFalse(intercepted);
847         assertFalse(outLaunched.value);
848 
849         final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
850         eventTime += interval;
851         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
852                 IGNORED_REPEAT);
853         outLaunched.value = true;
854         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
855                 outLaunched);
856         assertFalse(intercepted);
857         assertFalse(outLaunched.value);
858 
859         verify(mMetricsLogger, never())
860             .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
861         verify(mUiEventLogger, never()).log(any());
862 
863         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
864         verify(mMetricsLogger, times(2)).histogram(
865                 eq("power_double_tap_interval"), intervalCaptor.capture());
866         List<Integer> intervals = intervalCaptor.getAllValues();
867         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
868         assertEquals((int) interval, intervals.get(1).intValue());
869 
870         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
871         verify(mMetricsLogger, times(2)).histogram(
872                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
873         List<Integer> tapCounts = tapCountCaptor.getAllValues();
874         assertEquals(1, tapCounts.get(0).intValue());
875         assertEquals(2, tapCounts.get(1).intValue());
876     }
877 
878     @Test
testInterceptPowerKeyDown_intervalMidBoundsCameraPowerGestureOffNotInteractive()879     public void testInterceptPowerKeyDown_intervalMidBoundsCameraPowerGestureOffNotInteractive() {
880         withCameraDoubleTapPowerEnableConfigValue(false);
881         withCameraDoubleTapPowerDisableSettingValue(1);
882         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
883 
884         long eventTime = INITIAL_EVENT_TIME_MILLIS;
885         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
886                 IGNORED_REPEAT);
887         boolean interactive = false;
888         MutableBoolean outLaunched = new MutableBoolean(true);
889         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
890                 outLaunched);
891         assertFalse(intercepted);
892         assertFalse(outLaunched.value);
893 
894         final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS;
895         eventTime += interval;
896         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
897                 IGNORED_REPEAT);
898         outLaunched.value = true;
899         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
900                 outLaunched);
901         assertFalse(intercepted);
902         assertFalse(outLaunched.value);
903         verify(mMetricsLogger, never())
904             .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
905         verify(mUiEventLogger, never()).log(any());
906 
907         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
908         verify(mMetricsLogger, times(2)).histogram(
909                 eq("power_double_tap_interval"), intervalCaptor.capture());
910         List<Integer> intervals = intervalCaptor.getAllValues();
911         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
912         assertEquals((int) interval, intervals.get(1).intValue());
913 
914         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
915         verify(mMetricsLogger, times(2)).histogram(
916                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
917         List<Integer> tapCounts = tapCountCaptor.getAllValues();
918         assertEquals(1, tapCounts.get(0).intValue());
919         // The interval is too long to launch the camera, but short enough to count as a
920         // sequential tap.
921         assertEquals(2, tapCounts.get(1).intValue());
922     }
923 
924     @Test
testInterceptPowerKeyDown_intervalOutOfBoundsCameraPowerGestureOffNotInteractive()925     public void testInterceptPowerKeyDown_intervalOutOfBoundsCameraPowerGestureOffNotInteractive() {
926         withCameraDoubleTapPowerEnableConfigValue(false);
927         withCameraDoubleTapPowerDisableSettingValue(1);
928         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
929 
930         long eventTime = INITIAL_EVENT_TIME_MILLIS;
931         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
932                 IGNORED_REPEAT);
933         boolean interactive = false;
934         MutableBoolean outLaunched = new MutableBoolean(true);
935         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
936                 outLaunched);
937         assertFalse(intercepted);
938         assertFalse(outLaunched.value);
939 
940         long interval = GestureLauncherService.POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS;
941         eventTime += interval;
942         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
943                 IGNORED_REPEAT);
944         outLaunched.value = true;
945         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
946                 outLaunched);
947         assertFalse(intercepted);
948         assertFalse(outLaunched.value);
949         verify(mMetricsLogger, never())
950             .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
951         verify(mUiEventLogger, never()).log(any());
952 
953         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
954         verify(mMetricsLogger, times(2)).histogram(
955                 eq("power_double_tap_interval"), intervalCaptor.capture());
956         List<Integer> intervals = intervalCaptor.getAllValues();
957         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
958         assertEquals((int) interval, intervals.get(1).intValue());
959 
960         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
961         verify(mMetricsLogger, times(2)).histogram(
962                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
963         List<Integer> tapCounts = tapCountCaptor.getAllValues();
964         assertEquals(1, tapCounts.get(0).intValue());
965         assertEquals(1, tapCounts.get(1).intValue());
966     }
967 
968     @Test
969     public void
testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOnNotInteractiveSetupComplete()970     testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOnNotInteractiveSetupComplete() {
971         withCameraDoubleTapPowerEnableConfigValue(true);
972         withCameraDoubleTapPowerDisableSettingValue(0);
973         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
974         withUserSetupCompleteValue(true);
975 
976         long eventTime = INITIAL_EVENT_TIME_MILLIS;
977         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
978                 IGNORED_REPEAT);
979         boolean interactive = false;
980         MutableBoolean outLaunched = new MutableBoolean(true);
981         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
982                 outLaunched);
983         assertFalse(intercepted);
984         assertFalse(outLaunched.value);
985 
986         final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
987         eventTime += interval;
988         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
989                 IGNORED_REPEAT);
990         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
991                 outLaunched);
992         assertFalse(intercepted);
993         assertTrue(outLaunched.value);
994 
995         verify(mStatusBarManagerInternal).onCameraLaunchGestureDetected(
996                 StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP);
997         verify(mMetricsLogger)
998             .action(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE, (int) interval);
999         verify(mUiEventLogger, times(1))
1000                 .log(GestureLauncherService.GestureLauncherEvent.GESTURE_CAMERA_DOUBLE_TAP_POWER);
1001 
1002         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
1003         verify(mMetricsLogger, times(2)).histogram(
1004                 eq("power_double_tap_interval"), intervalCaptor.capture());
1005         List<Integer> intervals = intervalCaptor.getAllValues();
1006         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
1007         assertEquals((int) interval, intervals.get(1).intValue());
1008 
1009         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
1010         verify(mMetricsLogger, times(2)).histogram(
1011                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
1012         List<Integer> tapCounts = tapCountCaptor.getAllValues();
1013         assertEquals(1, tapCounts.get(0).intValue());
1014         assertEquals(2, tapCounts.get(1).intValue());
1015     }
1016 
1017     @Test
1018     public void
testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOnNotInteractiveSetupIncomplete()1019     testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOnNotInteractiveSetupIncomplete() {
1020         withCameraDoubleTapPowerEnableConfigValue(true);
1021         withCameraDoubleTapPowerDisableSettingValue(0);
1022         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
1023         withUserSetupCompleteValue(false);
1024 
1025         long eventTime = INITIAL_EVENT_TIME_MILLIS;
1026         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1027                 IGNORED_REPEAT);
1028         boolean interactive = false;
1029         MutableBoolean outLaunched = new MutableBoolean(true);
1030         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1031                 outLaunched);
1032         assertFalse(intercepted);
1033         assertFalse(outLaunched.value);
1034 
1035         final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
1036         eventTime += interval;
1037         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1038                 IGNORED_REPEAT);
1039         outLaunched.value = true;
1040         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1041                 outLaunched);
1042         assertFalse(intercepted);
1043         assertFalse(outLaunched.value);
1044 
1045         verify(mMetricsLogger, never())
1046             .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
1047         verify(mUiEventLogger, never()).log(any());
1048 
1049         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
1050         verify(mMetricsLogger, times(2)).histogram(
1051                 eq("power_double_tap_interval"), intervalCaptor.capture());
1052         List<Integer> intervals = intervalCaptor.getAllValues();
1053         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
1054         assertEquals((int) interval, intervals.get(1).intValue());
1055 
1056         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
1057         verify(mMetricsLogger, times(2)).histogram(
1058                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
1059         List<Integer> tapCounts = tapCountCaptor.getAllValues();
1060         assertEquals(1, tapCounts.get(0).intValue());
1061         assertEquals(2, tapCounts.get(1).intValue());
1062     }
1063 
1064     @Test
testInterceptPowerKeyDown_intervalMidBoundsCameraPowerGestureOnNotInteractive()1065     public void testInterceptPowerKeyDown_intervalMidBoundsCameraPowerGestureOnNotInteractive() {
1066         withCameraDoubleTapPowerEnableConfigValue(true);
1067         withCameraDoubleTapPowerDisableSettingValue(0);
1068         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
1069 
1070         long eventTime = INITIAL_EVENT_TIME_MILLIS;
1071         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1072                 IGNORED_REPEAT);
1073         boolean interactive = false;
1074         MutableBoolean outLaunched = new MutableBoolean(true);
1075         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1076                 outLaunched);
1077         assertFalse(intercepted);
1078         assertFalse(outLaunched.value);
1079 
1080         final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS;
1081         eventTime += interval;
1082         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1083                 IGNORED_REPEAT);
1084         outLaunched.value = true;
1085         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1086                 outLaunched);
1087         assertFalse(intercepted);
1088         assertFalse(outLaunched.value);
1089 
1090         verify(mMetricsLogger, never())
1091             .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
1092         verify(mUiEventLogger, never()).log(any());
1093 
1094         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
1095         verify(mMetricsLogger, times(2)).histogram(
1096                 eq("power_double_tap_interval"), intervalCaptor.capture());
1097         List<Integer> intervals = intervalCaptor.getAllValues();
1098         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
1099         assertEquals((int) interval, intervals.get(1).intValue());
1100 
1101         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
1102         verify(mMetricsLogger, times(2)).histogram(
1103                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
1104         List<Integer> tapCounts = tapCountCaptor.getAllValues();
1105         assertEquals(1, tapCounts.get(0).intValue());
1106         // The interval is too long to launch the camera, but short enough to count as a
1107         // sequential tap.
1108         assertEquals(2, tapCounts.get(1).intValue());
1109     }
1110 
1111     @Test
testInterceptPowerKeyDown_intervalOutOfBoundsCameraPowerGestureOnNotInteractive()1112     public void testInterceptPowerKeyDown_intervalOutOfBoundsCameraPowerGestureOnNotInteractive() {
1113         withCameraDoubleTapPowerEnableConfigValue(true);
1114         withCameraDoubleTapPowerDisableSettingValue(0);
1115         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
1116 
1117         long eventTime = INITIAL_EVENT_TIME_MILLIS;
1118         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1119                 IGNORED_REPEAT);
1120         boolean interactive = false;
1121         MutableBoolean outLaunched = new MutableBoolean(true);
1122         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1123                 outLaunched);
1124         assertFalse(intercepted);
1125         assertFalse(outLaunched.value);
1126 
1127         long interval = GestureLauncherService.POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS;
1128         eventTime += interval;
1129         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1130                 IGNORED_REPEAT);
1131         outLaunched.value = true;
1132         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1133                 outLaunched);
1134         assertFalse(intercepted);
1135         assertFalse(outLaunched.value);
1136 
1137         verify(mMetricsLogger, never())
1138             .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
1139         verify(mUiEventLogger, never()).log(any());
1140 
1141         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
1142         verify(mMetricsLogger, times(2)).histogram(
1143                 eq("power_double_tap_interval"), intervalCaptor.capture());
1144         List<Integer> intervals = intervalCaptor.getAllValues();
1145         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
1146         assertEquals((int) interval, intervals.get(1).intValue());
1147 
1148         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
1149         verify(mMetricsLogger, times(2)).histogram(
1150                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
1151         List<Integer> tapCounts = tapCountCaptor.getAllValues();
1152         assertEquals(1, tapCounts.get(0).intValue());
1153         assertEquals(1, tapCounts.get(1).intValue());
1154     }
1155 
withCameraDoubleTapPowerEnableConfigValue(boolean enableConfigValue)1156     private void withCameraDoubleTapPowerEnableConfigValue(boolean enableConfigValue) {
1157         when(mResources.getBoolean(
1158                 com.android.internal.R.bool.config_cameraDoubleTapPowerGestureEnabled))
1159                 .thenReturn(enableConfigValue);
1160     }
1161 
withEmergencyGestureEnabledConfigValue(boolean enableConfigValue)1162     private void withEmergencyGestureEnabledConfigValue(boolean enableConfigValue) {
1163         when(mResources.getBoolean(
1164                 com.android.internal.R.bool.config_emergencyGestureEnabled))
1165                 .thenReturn(enableConfigValue);
1166     }
1167 
withCameraDoubleTapPowerDisableSettingValue(int disableSettingValue)1168     private void withCameraDoubleTapPowerDisableSettingValue(int disableSettingValue) {
1169         Settings.Secure.putIntForUser(
1170                 mContentResolver,
1171                 Settings.Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED,
1172                 disableSettingValue,
1173                 UserHandle.USER_CURRENT);
1174     }
1175 
withEmergencyGestureEnabledSettingValue(boolean enable)1176     private void withEmergencyGestureEnabledSettingValue(boolean enable) {
1177         Settings.Secure.putIntForUser(
1178                 mContentResolver,
1179                 Settings.Secure.EMERGENCY_GESTURE_ENABLED,
1180                 enable ? 1 : 0,
1181                 UserHandle.USER_CURRENT);
1182     }
1183 
withUserSetupCompleteValue(boolean userSetupComplete)1184     private void withUserSetupCompleteValue(boolean userSetupComplete) {
1185         int userSetupCompleteValue = userSetupComplete ? 1 : 0;
1186         Settings.Secure.putIntForUser(
1187                 mContentResolver,
1188                 Settings.Secure.USER_SETUP_COMPLETE,
1189                 userSetupCompleteValue,
1190                 UserHandle.USER_CURRENT);
1191     }
1192 }
1193