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 com.android.server.GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS;
20 import static com.android.server.GestureLauncherService.EMERGENCY_GESTURE_TAP_DETECTION_MIN_TIME_MS;
21 
22 import static org.junit.Assert.assertEquals;
23 import static org.junit.Assert.assertFalse;
24 import static org.junit.Assert.assertTrue;
25 import static org.mockito.ArgumentMatchers.any;
26 import static org.mockito.Matchers.anyInt;
27 import static org.mockito.Matchers.eq;
28 import static org.mockito.Mockito.never;
29 import static org.mockito.Mockito.times;
30 import static org.mockito.Mockito.verify;
31 import static org.mockito.Mockito.when;
32 
33 import android.app.StatusBarManager;
34 import android.content.Context;
35 import android.content.Intent;
36 import android.content.res.Resources;
37 import android.os.Looper;
38 import android.os.UserHandle;
39 import android.platform.test.annotations.Presubmit;
40 import android.provider.Settings;
41 import android.telecom.TelecomManager;
42 import android.test.mock.MockContentResolver;
43 import android.testing.TestableLooper;
44 import android.util.MutableBoolean;
45 import android.view.KeyEvent;
46 
47 import androidx.test.InstrumentationRegistry;
48 import androidx.test.filters.SmallTest;
49 import androidx.test.runner.AndroidJUnit4;
50 
51 import com.android.internal.logging.MetricsLogger;
52 import com.android.internal.logging.UiEventLogger;
53 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
54 import com.android.internal.util.test.FakeSettingsProvider;
55 import com.android.server.statusbar.StatusBarManagerInternal;
56 
57 import org.junit.Before;
58 import org.junit.BeforeClass;
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 java.util.List;
66 
67 /**
68  * Unit tests for {@link GestureLauncherService}.
69  * runtest frameworks-services -c com.android.server.GestureLauncherServiceTest
70  */
71 @Presubmit
72 @SmallTest
73 @RunWith(AndroidJUnit4.class)
74 @TestableLooper.RunWithLooper(setAsMainLooper = true)
75 public class GestureLauncherServiceTest {
76 
77     private static final int FAKE_USER_ID = 1337;
78     private static final int FAKE_SOURCE = 1982;
79     private static final long INITIAL_EVENT_TIME_MILLIS = 20000L;
80     private static final long IGNORED_DOWN_TIME = 1234L;
81     private static final int IGNORED_ACTION = 13;
82     private static final int IGNORED_CODE = 1999;
83     private static final int IGNORED_REPEAT = 42;
84     private static final int IGNORED_META_STATE = 0;
85     private static final int IGNORED_DEVICE_ID = 0;
86     private static final int IGNORED_SCANCODE = 0;
87 
88     private @Mock Context mContext;
89     private @Mock Resources mResources;
90     private @Mock StatusBarManagerInternal mStatusBarManagerInternal;
91     private @Mock TelecomManager mTelecomManager;
92     private @Mock MetricsLogger mMetricsLogger;
93     @Mock private UiEventLogger mUiEventLogger;
94     private MockContentResolver mContentResolver;
95     private GestureLauncherService mGestureLauncherService;
96 
97     @BeforeClass
oneTimeInitialization()98     public static void oneTimeInitialization() {
99         if (Looper.myLooper() == null) {
100             Looper.prepare();
101         }
102     }
103 
104     @Before
setup()105     public void setup() {
106         MockitoAnnotations.initMocks(this);
107 
108         LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
109         LocalServices.addService(StatusBarManagerInternal.class, mStatusBarManagerInternal);
110 
111         final Context originalContext = InstrumentationRegistry.getContext();
112         when(mContext.getApplicationInfo()).thenReturn(originalContext.getApplicationInfo());
113         when(mContext.getResources()).thenReturn(mResources);
114         mContentResolver = new MockContentResolver(mContext);
115         mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
116         when(mContext.getContentResolver()).thenReturn(mContentResolver);
117         when(mContext.getSystemService(Context.TELECOM_SERVICE)).thenReturn(mTelecomManager);
118         when(mTelecomManager.createLaunchEmergencyDialerIntent(null)).thenReturn(new Intent());
119 
120         mGestureLauncherService = new GestureLauncherService(mContext, mMetricsLogger,
121                 mUiEventLogger);
122     }
123 
124     @Test
testIsCameraDoubleTapPowerEnabled_configFalse()125     public void testIsCameraDoubleTapPowerEnabled_configFalse() {
126         withCameraDoubleTapPowerEnableConfigValue(false);
127         assertFalse(mGestureLauncherService.isCameraDoubleTapPowerEnabled(mResources));
128     }
129 
130     @Test
testIsCameraDoubleTapPowerEnabled_configTrue()131     public void testIsCameraDoubleTapPowerEnabled_configTrue() {
132         withCameraDoubleTapPowerEnableConfigValue(true);
133         assertTrue(mGestureLauncherService.isCameraDoubleTapPowerEnabled(mResources));
134     }
135 
136     @Test
testIsCameraDoubleTapPowerSettingEnabled_configFalseSettingDisabled()137     public void testIsCameraDoubleTapPowerSettingEnabled_configFalseSettingDisabled() {
138         withCameraDoubleTapPowerEnableConfigValue(false);
139         withCameraDoubleTapPowerDisableSettingValue(1);
140         assertFalse(mGestureLauncherService.isCameraDoubleTapPowerSettingEnabled(
141                 mContext, FAKE_USER_ID));
142     }
143 
144     @Test
testIsCameraDoubleTapPowerSettingEnabled_configFalseSettingEnabled()145     public void testIsCameraDoubleTapPowerSettingEnabled_configFalseSettingEnabled() {
146         withCameraDoubleTapPowerEnableConfigValue(false);
147         withCameraDoubleTapPowerDisableSettingValue(0);
148         assertFalse(mGestureLauncherService.isCameraDoubleTapPowerSettingEnabled(
149                 mContext, FAKE_USER_ID));
150     }
151 
152     @Test
testIsCameraDoubleTapPowerSettingEnabled_configTrueSettingDisabled()153     public void testIsCameraDoubleTapPowerSettingEnabled_configTrueSettingDisabled() {
154         withCameraDoubleTapPowerEnableConfigValue(true);
155         withCameraDoubleTapPowerDisableSettingValue(1);
156         assertFalse(mGestureLauncherService.isCameraDoubleTapPowerSettingEnabled(
157                 mContext, FAKE_USER_ID));
158     }
159 
160     @Test
testIsCameraDoubleTapPowerSettingEnabled_configTrueSettingEnabled()161     public void testIsCameraDoubleTapPowerSettingEnabled_configTrueSettingEnabled() {
162         withCameraDoubleTapPowerEnableConfigValue(true);
163         withCameraDoubleTapPowerDisableSettingValue(0);
164         assertTrue(mGestureLauncherService.isCameraDoubleTapPowerSettingEnabled(
165                 mContext, FAKE_USER_ID));
166     }
167 
168     @Test
testIsEmergencyGestureSettingEnabled_settingDisabled()169     public void testIsEmergencyGestureSettingEnabled_settingDisabled() {
170         withEmergencyGestureEnabledConfigValue(true);
171         withEmergencyGestureEnabledSettingValue(false);
172         assertFalse(mGestureLauncherService.isEmergencyGestureSettingEnabled(
173                 mContext, FAKE_USER_ID));
174     }
175 
176     @Test
testIsEmergencyGestureSettingEnabled_settingEnabled()177     public void testIsEmergencyGestureSettingEnabled_settingEnabled() {
178         withEmergencyGestureEnabledConfigValue(true);
179         withEmergencyGestureEnabledSettingValue(true);
180         assertTrue(mGestureLauncherService.isEmergencyGestureSettingEnabled(
181                 mContext, FAKE_USER_ID));
182     }
183 
184     @Test
testIsEmergencyGestureSettingEnabled_supportDisabled()185     public void testIsEmergencyGestureSettingEnabled_supportDisabled() {
186         withEmergencyGestureEnabledConfigValue(false);
187         withEmergencyGestureEnabledSettingValue(true);
188         assertFalse(mGestureLauncherService.isEmergencyGestureSettingEnabled(
189                 mContext, FAKE_USER_ID));
190     }
191 
192     @Test
testGetEmergencyGesturePowerButtonCooldownPeriodMs_enabled()193     public void testGetEmergencyGesturePowerButtonCooldownPeriodMs_enabled() {
194         withEmergencyGesturePowerButtonCooldownPeriodMsValue(4000);
195         assertEquals(4000,
196                 mGestureLauncherService.getEmergencyGesturePowerButtonCooldownPeriodMs(mContext,
197                         FAKE_USER_ID));
198     }
199 
200     @Test
testGetEmergencyGesturePowerButtonCooldownPeriodMs_disabled()201     public void testGetEmergencyGesturePowerButtonCooldownPeriodMs_disabled() {
202         withEmergencyGesturePowerButtonCooldownPeriodMsValue(0);
203         assertEquals(0,
204                 mGestureLauncherService.getEmergencyGesturePowerButtonCooldownPeriodMs(mContext,
205                         FAKE_USER_ID));
206     }
207 
208     @Test
testGetEmergencyGesturePowerButtonCooldownPeriodMs_cappedAtMaximum()209     public void testGetEmergencyGesturePowerButtonCooldownPeriodMs_cappedAtMaximum() {
210         withEmergencyGesturePowerButtonCooldownPeriodMsValue(10000);
211         assertEquals(GestureLauncherService.EMERGENCY_GESTURE_POWER_BUTTON_COOLDOWN_PERIOD_MS_MAX,
212                 mGestureLauncherService.getEmergencyGesturePowerButtonCooldownPeriodMs(mContext,
213                         FAKE_USER_ID));
214     }
215 
216     @Test
testHandleCameraLaunchGesture_userSetupComplete()217     public void testHandleCameraLaunchGesture_userSetupComplete() {
218         withUserSetupCompleteValue(true);
219 
220         boolean useWakeLock = false;
221         assertTrue(mGestureLauncherService.handleCameraGesture(useWakeLock, FAKE_SOURCE));
222         verify(mStatusBarManagerInternal).onCameraLaunchGestureDetected(FAKE_SOURCE);
223     }
224 
225     @Test
testHandleEmergencyGesture_userSetupComplete()226     public void testHandleEmergencyGesture_userSetupComplete() {
227         withUserSetupCompleteValue(true);
228 
229         assertTrue(mGestureLauncherService.handleEmergencyGesture());
230     }
231 
232     @Test
testHandleCameraLaunchGesture_userSetupNotComplete()233     public void testHandleCameraLaunchGesture_userSetupNotComplete() {
234         withUserSetupCompleteValue(false);
235 
236         boolean useWakeLock = false;
237         assertFalse(mGestureLauncherService.handleCameraGesture(useWakeLock, FAKE_SOURCE));
238     }
239 
240     @Test
testHandleEmergencyGesture_userSetupNotComplete()241     public void testHandleEmergencyGesture_userSetupNotComplete() {
242         withUserSetupCompleteValue(false);
243 
244         assertFalse(mGestureLauncherService.handleEmergencyGesture());
245     }
246 
247     @Test
testInterceptPowerKeyDown_firstPowerDownCameraPowerGestureOnInteractive()248     public void testInterceptPowerKeyDown_firstPowerDownCameraPowerGestureOnInteractive() {
249         withCameraDoubleTapPowerEnableConfigValue(true);
250         withCameraDoubleTapPowerDisableSettingValue(0);
251         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
252 
253         long eventTime = INITIAL_EVENT_TIME_MILLIS +
254                 CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
255         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
256                 IGNORED_REPEAT);
257         boolean interactive = true;
258         MutableBoolean outLaunched = new MutableBoolean(true);
259         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
260                 outLaunched);
261         assertFalse(intercepted);
262         assertFalse(outLaunched.value);
263         verify(mMetricsLogger).histogram("power_consecutive_short_tap_count", 1);
264         verify(mMetricsLogger).histogram("power_double_tap_interval", (int) eventTime);
265     }
266 
267     @Test
testInterceptPowerKeyDown_firstPowerDown_emergencyGestureNotLaunched()268     public void testInterceptPowerKeyDown_firstPowerDown_emergencyGestureNotLaunched() {
269         withEmergencyGestureEnabledSettingValue(true);
270         mGestureLauncherService.updateEmergencyGestureEnabled();
271 
272         long eventTime = INITIAL_EVENT_TIME_MILLIS
273                 + GestureLauncherService.POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS - 1;
274         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
275                 IGNORED_REPEAT);
276         boolean interactive = true;
277         MutableBoolean outLaunched = new MutableBoolean(true);
278         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
279                 outLaunched);
280 
281         assertFalse(intercepted);
282         assertFalse(outLaunched.value);
283         verify(mMetricsLogger).histogram("power_double_tap_interval", (int) eventTime);
284     }
285 
286     @Test
testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOffInteractive()287     public void testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOffInteractive() {
288         withCameraDoubleTapPowerEnableConfigValue(false);
289         withCameraDoubleTapPowerDisableSettingValue(1);
290         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
291 
292         long eventTime = INITIAL_EVENT_TIME_MILLIS;
293         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
294                 IGNORED_REPEAT);
295         boolean interactive = true;
296         MutableBoolean outLaunched = new MutableBoolean(true);
297         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
298                 outLaunched);
299         assertFalse(intercepted);
300         assertFalse(outLaunched.value);
301 
302         final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
303         eventTime += interval;
304         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
305                 IGNORED_REPEAT);
306         outLaunched.value = true;
307         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
308                 outLaunched);
309         assertFalse(intercepted);
310         assertFalse(outLaunched.value);
311 
312         verify(mMetricsLogger, never())
313             .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
314         verify(mUiEventLogger, never()).log(any());
315 
316         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
317         verify(mMetricsLogger, times(2)).histogram(
318                 eq("power_double_tap_interval"), intervalCaptor.capture());
319         List<Integer> intervals = intervalCaptor.getAllValues();
320         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
321         assertEquals((int) interval, intervals.get(1).intValue());
322 
323         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
324         verify(mMetricsLogger, times(2)).histogram(
325                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
326         List<Integer> tapCounts = tapCountCaptor.getAllValues();
327         assertEquals(1, tapCounts.get(0).intValue());
328         assertEquals(2, tapCounts.get(1).intValue());
329     }
330 
331     @Test
testInterceptPowerKeyDown_intervalMidBoundsCameraPowerGestureOffInteractive()332     public void testInterceptPowerKeyDown_intervalMidBoundsCameraPowerGestureOffInteractive() {
333         withCameraDoubleTapPowerEnableConfigValue(false);
334         withCameraDoubleTapPowerDisableSettingValue(1);
335         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
336 
337         long eventTime = INITIAL_EVENT_TIME_MILLIS;
338         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
339                 IGNORED_REPEAT);
340         boolean interactive = true;
341         MutableBoolean outLaunched = new MutableBoolean(true);
342         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
343                 outLaunched);
344         assertFalse(intercepted);
345         assertFalse(outLaunched.value);
346 
347         final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS;
348         eventTime += interval;
349         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
350                 IGNORED_REPEAT);
351         outLaunched.value = true;
352         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
353                 outLaunched);
354         assertFalse(intercepted);
355         assertFalse(outLaunched.value);
356 
357         verify(mMetricsLogger, never())
358             .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
359         verify(mUiEventLogger, never()).log(any());
360 
361         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
362         verify(mMetricsLogger, times(2)).histogram(
363                 eq("power_double_tap_interval"), intervalCaptor.capture());
364         List<Integer> intervals = intervalCaptor.getAllValues();
365         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
366         assertEquals((int) interval, intervals.get(1).intValue());
367 
368         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
369         verify(mMetricsLogger, times(2)).histogram(
370                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
371         List<Integer> tapCounts = tapCountCaptor.getAllValues();
372         assertEquals(1, tapCounts.get(0).intValue());
373         // The interval is too long to launch the camera, but short enough to count as a
374         // sequential tap.
375         assertEquals(2, tapCounts.get(1).intValue());
376     }
377 
378     @Test
testInterceptPowerKeyDown_intervalOutOfBoundsCameraPowerGestureOffInteractive()379     public void testInterceptPowerKeyDown_intervalOutOfBoundsCameraPowerGestureOffInteractive() {
380         withCameraDoubleTapPowerEnableConfigValue(false);
381         withCameraDoubleTapPowerDisableSettingValue(1);
382         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
383 
384         long eventTime = INITIAL_EVENT_TIME_MILLIS;
385         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
386                 IGNORED_REPEAT);
387         boolean interactive = true;
388         MutableBoolean outLaunched = new MutableBoolean(true);
389         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
390                 outLaunched);
391         assertFalse(intercepted);
392         assertFalse(outLaunched.value);
393 
394         long interval = GestureLauncherService.POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS;
395         eventTime += interval;
396         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
397                 IGNORED_REPEAT);
398         outLaunched.value = true;
399         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
400                 outLaunched);
401         assertFalse(intercepted);
402         assertFalse(outLaunched.value);
403 
404         verify(mMetricsLogger, never())
405             .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
406         verify(mUiEventLogger, never()).log(any());
407 
408         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
409         verify(mMetricsLogger, times(2)).histogram(
410                 eq("power_double_tap_interval"), intervalCaptor.capture());
411         List<Integer> intervals = intervalCaptor.getAllValues();
412         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
413         assertEquals((int) interval, intervals.get(1).intValue());
414 
415         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
416         verify(mMetricsLogger, times(2)).histogram(
417                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
418         List<Integer> tapCounts = tapCountCaptor.getAllValues();
419         assertEquals(1, tapCounts.get(0).intValue());
420         assertEquals(1, tapCounts.get(1).intValue());
421     }
422 
423     @Test
424     public void
testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOnInteractiveSetupComplete()425     testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOnInteractiveSetupComplete() {
426         withCameraDoubleTapPowerEnableConfigValue(true);
427         withCameraDoubleTapPowerDisableSettingValue(0);
428         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
429         withUserSetupCompleteValue(true);
430 
431         long eventTime = INITIAL_EVENT_TIME_MILLIS;
432         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
433                 IGNORED_REPEAT);
434         boolean interactive = true;
435         MutableBoolean outLaunched = new MutableBoolean(true);
436         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
437                 outLaunched);
438         assertFalse(intercepted);
439         assertFalse(outLaunched.value);
440 
441         final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
442         eventTime += interval;
443         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
444                 IGNORED_REPEAT);
445         outLaunched.value = false;
446         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
447                 outLaunched);
448         assertTrue(intercepted);
449         assertTrue(outLaunched.value);
450 
451         verify(mStatusBarManagerInternal).onCameraLaunchGestureDetected(
452                 StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP);
453         verify(mMetricsLogger)
454             .action(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE, (int) interval);
455         verify(mUiEventLogger, times(1))
456                 .log(GestureLauncherService.GestureLauncherEvent.GESTURE_CAMERA_DOUBLE_TAP_POWER);
457 
458         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
459         verify(mMetricsLogger, times(2)).histogram(
460                 eq("power_double_tap_interval"), intervalCaptor.capture());
461         List<Integer> intervals = intervalCaptor.getAllValues();
462         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
463         assertEquals((int) interval, intervals.get(1).intValue());
464 
465         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
466         verify(mMetricsLogger, times(2)).histogram(
467                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
468         List<Integer> tapCounts = tapCountCaptor.getAllValues();
469         assertEquals(1, tapCounts.get(0).intValue());
470         assertEquals(2, tapCounts.get(1).intValue());
471     }
472 
473     @Test
474     public void
testInterceptPowerKeyDown_fiveInboundPresses_cameraAndEmergencyEnabled_bothLaunch()475             testInterceptPowerKeyDown_fiveInboundPresses_cameraAndEmergencyEnabled_bothLaunch() {
476         withCameraDoubleTapPowerEnableConfigValue(true);
477         withCameraDoubleTapPowerDisableSettingValue(0);
478         withEmergencyGestureEnabledConfigValue(true);
479         withEmergencyGestureEnabledSettingValue(true);
480         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
481         mGestureLauncherService.updateEmergencyGestureEnabled();
482         withUserSetupCompleteValue(true);
483 
484         // First button press does nothing
485         long eventTime = INITIAL_EVENT_TIME_MILLIS;
486         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
487                 IGNORED_REPEAT);
488         boolean interactive = true;
489         MutableBoolean outLaunched = new MutableBoolean(true);
490         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
491                 outLaunched);
492         assertFalse(intercepted);
493         assertFalse(outLaunched.value);
494 
495         final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
496 
497         // 2nd button triggers camera
498         eventTime += interval;
499         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
500                 IGNORED_REPEAT);
501         outLaunched.value = false;
502         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
503                 outLaunched);
504         assertTrue(intercepted);
505         assertTrue(outLaunched.value);
506 
507         // Camera checks
508         verify(mStatusBarManagerInternal).onCameraLaunchGestureDetected(
509                 StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP);
510         verify(mMetricsLogger)
511             .action(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE, (int) interval);
512         verify(mUiEventLogger, times(1))
513                 .log(GestureLauncherService.GestureLauncherEvent.GESTURE_CAMERA_DOUBLE_TAP_POWER);
514 
515         final ArgumentCaptor<Integer> cameraIntervalCaptor = ArgumentCaptor.forClass(Integer.class);
516         verify(mMetricsLogger, times(2)).histogram(
517                 eq("power_double_tap_interval"), cameraIntervalCaptor.capture());
518         List<Integer> cameraIntervals = cameraIntervalCaptor.getAllValues();
519         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, cameraIntervals.get(0).intValue());
520         assertEquals((int) interval, cameraIntervals.get(1).intValue());
521 
522         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
523         verify(mMetricsLogger, times(2)).histogram(
524                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
525         List<Integer> tapCounts = tapCountCaptor.getAllValues();
526         assertEquals(1, tapCounts.get(0).intValue());
527         assertEquals(2, tapCounts.get(1).intValue());
528 
529         // Continue the button presses for the emergency gesture.
530 
531         // Presses 3 and 4 should not trigger any gesture
532         for (int i = 0; i < 2; i++) {
533             eventTime += interval;
534             keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
535                     IGNORED_REPEAT);
536             outLaunched.value = false;
537             intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
538                     outLaunched);
539             assertTrue(intercepted);
540             assertFalse(outLaunched.value);
541         }
542 
543         // Fifth button press should trigger the emergency flow
544         eventTime += interval;
545         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
546                 IGNORED_REPEAT);
547         outLaunched.value = false;
548         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
549                 outLaunched);
550         assertTrue(intercepted);
551         assertTrue(outLaunched.value);
552 
553         verify(mUiEventLogger, times(1))
554                 .log(GestureLauncherService.GestureLauncherEvent.GESTURE_EMERGENCY_TAP_POWER);
555         verify(mStatusBarManagerInternal).onEmergencyActionLaunchGestureDetected();
556 
557         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
558         verify(mMetricsLogger, times(5)).histogram(
559                 eq("power_double_tap_interval"), intervalCaptor.capture());
560         List<Integer> intervals = intervalCaptor.getAllValues();
561         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
562         assertEquals((int) interval, intervals.get(1).intValue());
563     }
564 
565     @Test
566     public void
testInterceptPowerKeyDown_fiveInboundPresses_emergencyGestureEnabled_launchesFlow()567             testInterceptPowerKeyDown_fiveInboundPresses_emergencyGestureEnabled_launchesFlow() {
568         withEmergencyGestureEnabledConfigValue(true);
569         withEmergencyGestureEnabledSettingValue(true);
570         mGestureLauncherService.updateEmergencyGestureEnabled();
571         withUserSetupCompleteValue(true);
572 
573         // First button press does nothing
574         long eventTime = INITIAL_EVENT_TIME_MILLIS;
575         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
576                 IGNORED_REPEAT);
577         boolean interactive = true;
578         MutableBoolean outLaunched = new MutableBoolean(true);
579         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
580                 outLaunched);
581         assertFalse(intercepted);
582         assertFalse(outLaunched.value);
583 
584         final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
585         // 3 more button presses which should not trigger any gesture (camera gesture disabled)
586         for (int i = 0; i < 3; i++) {
587             eventTime += interval;
588             keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
589                     IGNORED_REPEAT);
590             outLaunched.value = false;
591             intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
592                     outLaunched);
593             assertTrue(intercepted);
594             assertFalse(outLaunched.value);
595         }
596 
597         // Fifth button press should trigger the emergency flow
598         eventTime += interval;
599         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
600                 IGNORED_REPEAT);
601         outLaunched.value = false;
602         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
603                 outLaunched);
604         assertTrue(outLaunched.value);
605         assertTrue(intercepted);
606 
607         verify(mUiEventLogger, times(1))
608                 .log(GestureLauncherService.GestureLauncherEvent.GESTURE_EMERGENCY_TAP_POWER);
609         verify(mStatusBarManagerInternal).onEmergencyActionLaunchGestureDetected();
610 
611         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
612         verify(mMetricsLogger, times(5)).histogram(
613                 eq("power_double_tap_interval"), intervalCaptor.capture());
614         List<Integer> intervals = intervalCaptor.getAllValues();
615         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
616         assertEquals((int) interval, intervals.get(1).intValue());
617     }
618 
619     @Test
620     public void
testInterceptPowerKeyDown_tenInboundPresses_emergencyGestureEnabled_keyIntercepted()621             testInterceptPowerKeyDown_tenInboundPresses_emergencyGestureEnabled_keyIntercepted() {
622         withEmergencyGestureEnabledConfigValue(true);
623         withEmergencyGestureEnabledSettingValue(true);
624         mGestureLauncherService.updateEmergencyGestureEnabled();
625         withUserSetupCompleteValue(true);
626 
627         // First button press does nothing
628         long eventTime = INITIAL_EVENT_TIME_MILLIS;
629         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
630                 IGNORED_REPEAT);
631         boolean interactive = true;
632         MutableBoolean outLaunched = new MutableBoolean(true);
633         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
634                 outLaunched);
635         assertFalse(intercepted);
636         assertFalse(outLaunched.value);
637 
638         final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
639         // 3 more button presses which should not trigger any gesture, but intercepts action.
640         for (int i = 0; i < 3; i++) {
641             eventTime += interval;
642             keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
643                     IGNORED_REPEAT);
644             outLaunched.value = false;
645             intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
646                     outLaunched);
647             assertTrue(intercepted);
648             assertFalse(outLaunched.value);
649         }
650 
651         // Fifth button press should trigger the emergency flow
652         eventTime += interval;
653         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
654                 IGNORED_REPEAT);
655         outLaunched.value = false;
656         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
657                 outLaunched);
658         assertTrue(outLaunched.value);
659         assertTrue(intercepted);
660 
661         // 5 more button presses which should not trigger any gesture, but intercepts action.
662         for (int i = 0; i < 5; i++) {
663             eventTime += interval;
664             keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
665                     IGNORED_REPEAT);
666             outLaunched.value = false;
667             intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
668                     outLaunched);
669             assertTrue(intercepted);
670             assertFalse(outLaunched.value);
671         }
672     }
673 
674     @Test
testInterceptPowerKeyDown_triggerEmergency_singleTaps_cooldownTriggered()675     public void testInterceptPowerKeyDown_triggerEmergency_singleTaps_cooldownTriggered() {
676         // Enable power button cooldown
677         withEmergencyGesturePowerButtonCooldownPeriodMsValue(3000);
678         mGestureLauncherService.updateEmergencyGesturePowerButtonCooldownPeriodMs();
679 
680         // Trigger emergency by tapping button 5 times
681         long eventTime = triggerEmergencyGesture();
682 
683         // Add enough interval to reset consecutive tap count
684         long interval = GestureLauncherService.POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS + 1;
685         eventTime += interval;
686 
687         // Subsequent single tap is intercepted, but should not trigger any gesture
688         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
689                 IGNORED_REPEAT);
690         boolean interactive = true;
691         MutableBoolean outLaunched = new MutableBoolean(true);
692         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
693                 outLaunched);
694         assertTrue(intercepted);
695         assertFalse(outLaunched.value);
696 
697         // Add enough interval to reset consecutive tap count
698         interval = GestureLauncherService.POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS + 1;
699         eventTime += interval;
700 
701         // Another single tap should be the same (intercepted but should not trigger gesture)
702         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
703                 IGNORED_REPEAT);
704         interactive = true;
705         outLaunched = new MutableBoolean(true);
706         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
707                 outLaunched);
708         assertTrue(intercepted);
709         assertFalse(outLaunched.value);
710     }
711 
712     @Test
713     public void
testInterceptPowerKeyDown_triggerEmergency_cameraGestureEnabled_doubleTap_cooldownTriggered()714     testInterceptPowerKeyDown_triggerEmergency_cameraGestureEnabled_doubleTap_cooldownTriggered() {
715         // Enable camera double tap gesture
716         withCameraDoubleTapPowerEnableConfigValue(true);
717         withCameraDoubleTapPowerDisableSettingValue(0);
718         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
719 
720         // Enable power button cooldown
721         withEmergencyGesturePowerButtonCooldownPeriodMsValue(3000);
722         mGestureLauncherService.updateEmergencyGesturePowerButtonCooldownPeriodMs();
723 
724         // Trigger emergency by tapping button 5 times
725         long eventTime = triggerEmergencyGesture();
726 
727         // Add enough interval to reset consecutive tap count
728         long interval = GestureLauncherService.POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS + 1;
729         eventTime += interval;
730 
731         // Subsequent double tap is intercepted, but should not trigger any gesture
732         for (int i = 0; i < 2; i++) {
733             KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION,
734                     IGNORED_CODE, IGNORED_REPEAT);
735             boolean interactive = true;
736             MutableBoolean outLaunched = new MutableBoolean(true);
737             boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent,
738                     interactive, outLaunched);
739             assertTrue(intercepted);
740             assertFalse(outLaunched.value);
741             interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
742             eventTime += interval;
743         }
744     }
745 
746     @Test
testInterceptPowerKeyDown_triggerEmergency_fiveTaps_cooldownTriggered()747     public void testInterceptPowerKeyDown_triggerEmergency_fiveTaps_cooldownTriggered() {
748         // Enable power button cooldown
749         withEmergencyGesturePowerButtonCooldownPeriodMsValue(3000);
750         mGestureLauncherService.updateEmergencyGesturePowerButtonCooldownPeriodMs();
751 
752         // Trigger emergency by tapping button 5 times
753         long eventTime = triggerEmergencyGesture();
754 
755         // Add enough interval to reset consecutive tap count
756         long interval = GestureLauncherService.POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS + 1;
757         eventTime += interval;
758 
759         // Subsequent 5 taps are intercepted, but should not trigger any gesture
760         for (int i = 0; i < 5; i++) {
761             KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION,
762                     IGNORED_CODE, IGNORED_REPEAT);
763             boolean interactive = true;
764             MutableBoolean outLaunched = new MutableBoolean(true);
765             boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent,
766                     interactive, outLaunched);
767             assertTrue(intercepted);
768             assertFalse(outLaunched.value);
769             interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
770             eventTime += interval;
771         }
772     }
773 
774     @Test
testInterceptPowerKeyDown_triggerEmergency_fiveFastTaps_gestureIgnored()775     public void testInterceptPowerKeyDown_triggerEmergency_fiveFastTaps_gestureIgnored() {
776         // Trigger emergency by tapping button 5 times
777         long eventTime = triggerEmergencyGesture(/* tapIntervalMs= */ 1);
778 
779         // Add 1 more millisecond and send the event again.
780         eventTime += 1;
781 
782         // Subsequent long press is intercepted, but should not trigger any gesture
783         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
784                 IGNORED_REPEAT, IGNORED_META_STATE, IGNORED_DEVICE_ID, IGNORED_SCANCODE,
785                 KeyEvent.FLAG_LONG_PRESS);
786         MutableBoolean outLaunched = new MutableBoolean(true);
787         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(
788                 keyEvent,
789                 /* interactive= */ true,
790                 outLaunched);
791         assertFalse(intercepted);
792         assertFalse(outLaunched.value);
793     }
794 
795     @Test
testInterceptPowerKeyDown_triggerEmergency_longPress_cooldownTriggered()796     public void testInterceptPowerKeyDown_triggerEmergency_longPress_cooldownTriggered() {
797         // Enable power button cooldown
798         withEmergencyGesturePowerButtonCooldownPeriodMsValue(3000);
799         mGestureLauncherService.updateEmergencyGesturePowerButtonCooldownPeriodMs();
800 
801         // Trigger emergency by tapping button 5 times
802         long eventTime = triggerEmergencyGesture();
803 
804         // Add enough interval to reset consecutive tap count
805         long interval = GestureLauncherService.POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS + 1;
806         eventTime += interval;
807 
808         // Subsequent long press is intercepted, but should not trigger any gesture
809         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
810                 IGNORED_REPEAT, IGNORED_META_STATE, IGNORED_DEVICE_ID, IGNORED_SCANCODE,
811                 KeyEvent.FLAG_LONG_PRESS);
812 
813         boolean interactive = true;
814         MutableBoolean outLaunched = new MutableBoolean(true);
815         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
816                 outLaunched);
817         assertTrue(intercepted);
818         assertFalse(outLaunched.value);
819     }
820 
821     @Test
testInterceptPowerKeyDown_triggerEmergency_cooldownDisabled_cooldownNotTriggered()822     public void testInterceptPowerKeyDown_triggerEmergency_cooldownDisabled_cooldownNotTriggered() {
823         // Disable power button cooldown by setting cooldown period to 0
824         withEmergencyGesturePowerButtonCooldownPeriodMsValue(0);
825         mGestureLauncherService.updateEmergencyGesturePowerButtonCooldownPeriodMs();
826 
827         // Trigger emergency by tapping button 5 times
828         long eventTime = triggerEmergencyGesture();
829 
830         // Add enough interval to reset consecutive tap count
831         long interval = GestureLauncherService.POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS + 1;
832         eventTime += interval;
833 
834         // Subsequent single tap is NOT intercepted
835         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
836                 IGNORED_REPEAT);
837         boolean interactive = true;
838         MutableBoolean outLaunched = new MutableBoolean(true);
839         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
840                 outLaunched);
841         assertFalse(intercepted);
842         assertFalse(outLaunched.value);
843 
844         // Add enough interval to reset consecutive tap count
845         interval = GestureLauncherService.POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS + 1;
846         eventTime += interval;
847 
848         // Long press also NOT intercepted
849         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
850                 IGNORED_REPEAT, IGNORED_META_STATE, IGNORED_DEVICE_ID, IGNORED_SCANCODE,
851                 KeyEvent.FLAG_LONG_PRESS);
852         interactive = true;
853         outLaunched = new MutableBoolean(true);
854         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
855                 outLaunched);
856         assertFalse(intercepted);
857         assertFalse(outLaunched.value);
858     }
859 
860     @Test
861     public void
testInterceptPowerKeyDown_triggerEmergency_outsideCooldownPeriod_cooldownNotTriggered()862     testInterceptPowerKeyDown_triggerEmergency_outsideCooldownPeriod_cooldownNotTriggered() {
863         // Enable power button cooldown
864         withEmergencyGesturePowerButtonCooldownPeriodMsValue(5000);
865         mGestureLauncherService.updateEmergencyGesturePowerButtonCooldownPeriodMs();
866 
867         // Trigger emergency by tapping button 5 times
868         long eventTime = triggerEmergencyGesture();
869 
870         // Add enough interval to be outside of cooldown period
871         long interval = 5001;
872         eventTime += interval;
873 
874         // Subsequent single tap is NOT intercepted
875         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
876                 IGNORED_REPEAT);
877         boolean interactive = true;
878         MutableBoolean outLaunched = new MutableBoolean(true);
879         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
880                 outLaunched);
881         assertFalse(intercepted);
882         assertFalse(outLaunched.value);
883 
884         // Add enough interval to reset consecutive tap count
885         interval = GestureLauncherService.POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS + 1;
886         eventTime += interval;
887 
888         // Long press also NOT intercepted
889         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
890                 IGNORED_REPEAT, IGNORED_META_STATE, IGNORED_DEVICE_ID, IGNORED_SCANCODE,
891                 KeyEvent.FLAG_LONG_PRESS);
892         interactive = true;
893         outLaunched = new MutableBoolean(true);
894         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
895                 outLaunched);
896         assertFalse(intercepted);
897         assertFalse(outLaunched.value);
898     }
899 
900     @Test
testInterceptPowerKeyDown_longpress()901     public void testInterceptPowerKeyDown_longpress() {
902         withCameraDoubleTapPowerEnableConfigValue(true);
903         withCameraDoubleTapPowerDisableSettingValue(0);
904         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
905         withUserSetupCompleteValue(true);
906 
907         long eventTime = INITIAL_EVENT_TIME_MILLIS;
908         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
909                 IGNORED_REPEAT);
910         boolean interactive = true;
911         MutableBoolean outLaunched = new MutableBoolean(true);
912         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
913                 outLaunched);
914         assertFalse(intercepted);
915         assertFalse(outLaunched.value);
916 
917         final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
918         eventTime += interval;
919         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
920                 IGNORED_REPEAT, IGNORED_META_STATE, IGNORED_DEVICE_ID, IGNORED_SCANCODE,
921                 KeyEvent.FLAG_LONG_PRESS);
922         outLaunched.value = false;
923         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
924                 outLaunched);
925         assertFalse(intercepted);
926         assertFalse(outLaunched.value);
927 
928         verify(mMetricsLogger, never())
929                 .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
930         verify(mUiEventLogger, never()).log(any());
931 
932         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
933         verify(mMetricsLogger, times(1)).histogram(
934                 eq("power_double_tap_interval"), intervalCaptor.capture());
935         List<Integer> intervals = intervalCaptor.getAllValues();
936         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
937 
938         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
939         verify(mMetricsLogger, times(1)).histogram(
940                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
941         List<Integer> tapCounts = tapCountCaptor.getAllValues();
942         assertEquals(1, tapCounts.get(0).intValue());
943     }
944 
945     @Test
946     public void
testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOnInteractiveSetupIncomplete()947     testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOnInteractiveSetupIncomplete() {
948         withCameraDoubleTapPowerEnableConfigValue(true);
949         withCameraDoubleTapPowerDisableSettingValue(0);
950         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
951         withUserSetupCompleteValue(false);
952 
953         long eventTime = INITIAL_EVENT_TIME_MILLIS;
954         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
955                 IGNORED_REPEAT);
956         boolean interactive = true;
957         MutableBoolean outLaunched = new MutableBoolean(true);
958         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
959                 outLaunched);
960         assertFalse(intercepted);
961         assertFalse(outLaunched.value);
962 
963         final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
964         eventTime += interval;
965         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
966                 IGNORED_REPEAT);
967         outLaunched.value = true;
968         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
969                 outLaunched);
970         assertFalse(intercepted);
971         assertFalse(outLaunched.value);
972 
973         verify(mMetricsLogger, never())
974             .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
975         verify(mUiEventLogger, never()).log(any());
976 
977         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
978         verify(mMetricsLogger, times(2)).histogram(
979                 eq("power_double_tap_interval"), intervalCaptor.capture());
980         List<Integer> intervals = intervalCaptor.getAllValues();
981         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
982         assertEquals((int) interval, intervals.get(1).intValue());
983 
984         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
985         verify(mMetricsLogger, times(2)).histogram(
986                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
987         List<Integer> tapCounts = tapCountCaptor.getAllValues();
988         assertEquals(1, tapCounts.get(0).intValue());
989         // The interval is too long to launch the camera, but short enough to count as a
990         // sequential tap.
991         assertEquals(2, tapCounts.get(1).intValue());
992     }
993 
994     @Test
testInterceptPowerKeyDown_intervalMidBoundsCameraPowerGestureOnInteractive()995     public void testInterceptPowerKeyDown_intervalMidBoundsCameraPowerGestureOnInteractive() {
996         withCameraDoubleTapPowerEnableConfigValue(true);
997         withCameraDoubleTapPowerDisableSettingValue(0);
998         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
999 
1000         long eventTime = INITIAL_EVENT_TIME_MILLIS;
1001         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1002                 IGNORED_REPEAT);
1003         boolean interactive = true;
1004         MutableBoolean outLaunched = new MutableBoolean(true);
1005         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1006                 outLaunched);
1007         assertFalse(intercepted);
1008         assertFalse(outLaunched.value);
1009 
1010         final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS;
1011         eventTime += interval;
1012         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1013                 IGNORED_REPEAT);
1014         outLaunched.value = true;
1015         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1016                 outLaunched);
1017         assertFalse(intercepted);
1018         assertFalse(outLaunched.value);
1019 
1020         verify(mMetricsLogger, never())
1021             .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
1022         verify(mUiEventLogger, never()).log(any());
1023 
1024         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
1025         verify(mMetricsLogger, times(2)).histogram(
1026                 eq("power_double_tap_interval"), intervalCaptor.capture());
1027         List<Integer> intervals = intervalCaptor.getAllValues();
1028         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
1029         assertEquals((int) interval, intervals.get(1).intValue());
1030 
1031         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
1032         verify(mMetricsLogger, times(2)).histogram(
1033                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
1034         List<Integer> tapCounts = tapCountCaptor.getAllValues();
1035         assertEquals(1, tapCounts.get(0).intValue());
1036         // The interval is too long to launch the camera, but short enough to count as a
1037         // sequential tap.
1038         assertEquals(2, tapCounts.get(1).intValue());
1039     }
1040 
1041     @Test
testInterceptPowerKeyDown_intervalOutOfBoundsCameraPowerGestureOnInteractive()1042     public void testInterceptPowerKeyDown_intervalOutOfBoundsCameraPowerGestureOnInteractive() {
1043         withCameraDoubleTapPowerEnableConfigValue(true);
1044         withCameraDoubleTapPowerDisableSettingValue(0);
1045         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
1046 
1047         long eventTime = INITIAL_EVENT_TIME_MILLIS;
1048         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1049                 IGNORED_REPEAT);
1050         boolean interactive = true;
1051         MutableBoolean outLaunched = new MutableBoolean(true);
1052         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1053                 outLaunched);
1054         assertFalse(intercepted);
1055         assertFalse(outLaunched.value);
1056 
1057         long interval = GestureLauncherService.POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS;
1058         eventTime += interval;
1059         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1060                 IGNORED_REPEAT);
1061         outLaunched.value = true;
1062         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1063                 outLaunched);
1064         assertFalse(intercepted);
1065         assertFalse(outLaunched.value);
1066 
1067         verify(mMetricsLogger, never())
1068             .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
1069         verify(mUiEventLogger, never()).log(any());
1070 
1071         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
1072         verify(mMetricsLogger, times(2)).histogram(
1073                 eq("power_double_tap_interval"), intervalCaptor.capture());
1074         List<Integer> intervals = intervalCaptor.getAllValues();
1075         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
1076         assertEquals((int) interval, intervals.get(1).intValue());
1077 
1078         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
1079         verify(mMetricsLogger, times(2)).histogram(
1080                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
1081         List<Integer> tapCounts = tapCountCaptor.getAllValues();
1082         assertEquals(1, tapCounts.get(0).intValue());
1083         assertEquals(1, tapCounts.get(1).intValue());
1084     }
1085 
1086     @Test
testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOffNotInteractive()1087     public void testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOffNotInteractive() {
1088         withCameraDoubleTapPowerEnableConfigValue(false);
1089         withCameraDoubleTapPowerDisableSettingValue(1);
1090         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
1091 
1092         long eventTime = INITIAL_EVENT_TIME_MILLIS;
1093         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1094                 IGNORED_REPEAT);
1095         boolean interactive = false;
1096         MutableBoolean outLaunched = new MutableBoolean(true);
1097         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1098                 outLaunched);
1099         assertFalse(intercepted);
1100         assertFalse(outLaunched.value);
1101 
1102         final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
1103         eventTime += interval;
1104         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1105                 IGNORED_REPEAT);
1106         outLaunched.value = true;
1107         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1108                 outLaunched);
1109         assertFalse(intercepted);
1110         assertFalse(outLaunched.value);
1111 
1112         verify(mMetricsLogger, never())
1113             .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
1114         verify(mUiEventLogger, never()).log(any());
1115 
1116         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
1117         verify(mMetricsLogger, times(2)).histogram(
1118                 eq("power_double_tap_interval"), intervalCaptor.capture());
1119         List<Integer> intervals = intervalCaptor.getAllValues();
1120         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
1121         assertEquals((int) interval, intervals.get(1).intValue());
1122 
1123         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
1124         verify(mMetricsLogger, times(2)).histogram(
1125                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
1126         List<Integer> tapCounts = tapCountCaptor.getAllValues();
1127         assertEquals(1, tapCounts.get(0).intValue());
1128         assertEquals(2, tapCounts.get(1).intValue());
1129     }
1130 
1131     @Test
testInterceptPowerKeyDown_intervalMidBoundsCameraPowerGestureOffNotInteractive()1132     public void testInterceptPowerKeyDown_intervalMidBoundsCameraPowerGestureOffNotInteractive() {
1133         withCameraDoubleTapPowerEnableConfigValue(false);
1134         withCameraDoubleTapPowerDisableSettingValue(1);
1135         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
1136 
1137         long eventTime = INITIAL_EVENT_TIME_MILLIS;
1138         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1139                 IGNORED_REPEAT);
1140         boolean interactive = false;
1141         MutableBoolean outLaunched = new MutableBoolean(true);
1142         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1143                 outLaunched);
1144         assertFalse(intercepted);
1145         assertFalse(outLaunched.value);
1146 
1147         final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS;
1148         eventTime += interval;
1149         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1150                 IGNORED_REPEAT);
1151         outLaunched.value = true;
1152         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1153                 outLaunched);
1154         assertFalse(intercepted);
1155         assertFalse(outLaunched.value);
1156         verify(mMetricsLogger, never())
1157             .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
1158         verify(mUiEventLogger, never()).log(any());
1159 
1160         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
1161         verify(mMetricsLogger, times(2)).histogram(
1162                 eq("power_double_tap_interval"), intervalCaptor.capture());
1163         List<Integer> intervals = intervalCaptor.getAllValues();
1164         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
1165         assertEquals((int) interval, intervals.get(1).intValue());
1166 
1167         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
1168         verify(mMetricsLogger, times(2)).histogram(
1169                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
1170         List<Integer> tapCounts = tapCountCaptor.getAllValues();
1171         assertEquals(1, tapCounts.get(0).intValue());
1172         // The interval is too long to launch the camera, but short enough to count as a
1173         // sequential tap.
1174         assertEquals(2, tapCounts.get(1).intValue());
1175     }
1176 
1177     @Test
testInterceptPowerKeyDown_intervalOutOfBoundsCameraPowerGestureOffNotInteractive()1178     public void testInterceptPowerKeyDown_intervalOutOfBoundsCameraPowerGestureOffNotInteractive() {
1179         withCameraDoubleTapPowerEnableConfigValue(false);
1180         withCameraDoubleTapPowerDisableSettingValue(1);
1181         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
1182 
1183         long eventTime = INITIAL_EVENT_TIME_MILLIS;
1184         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1185                 IGNORED_REPEAT);
1186         boolean interactive = false;
1187         MutableBoolean outLaunched = new MutableBoolean(true);
1188         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1189                 outLaunched);
1190         assertFalse(intercepted);
1191         assertFalse(outLaunched.value);
1192 
1193         long interval = GestureLauncherService.POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS;
1194         eventTime += interval;
1195         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1196                 IGNORED_REPEAT);
1197         outLaunched.value = true;
1198         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1199                 outLaunched);
1200         assertFalse(intercepted);
1201         assertFalse(outLaunched.value);
1202         verify(mMetricsLogger, never())
1203             .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
1204         verify(mUiEventLogger, never()).log(any());
1205 
1206         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
1207         verify(mMetricsLogger, times(2)).histogram(
1208                 eq("power_double_tap_interval"), intervalCaptor.capture());
1209         List<Integer> intervals = intervalCaptor.getAllValues();
1210         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
1211         assertEquals((int) interval, intervals.get(1).intValue());
1212 
1213         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
1214         verify(mMetricsLogger, times(2)).histogram(
1215                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
1216         List<Integer> tapCounts = tapCountCaptor.getAllValues();
1217         assertEquals(1, tapCounts.get(0).intValue());
1218         assertEquals(1, tapCounts.get(1).intValue());
1219     }
1220 
1221     @Test
1222     public void
testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOnNotInteractiveSetupComplete()1223     testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOnNotInteractiveSetupComplete() {
1224         withCameraDoubleTapPowerEnableConfigValue(true);
1225         withCameraDoubleTapPowerDisableSettingValue(0);
1226         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
1227         withUserSetupCompleteValue(true);
1228 
1229         long eventTime = INITIAL_EVENT_TIME_MILLIS;
1230         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1231                 IGNORED_REPEAT);
1232         boolean interactive = false;
1233         MutableBoolean outLaunched = new MutableBoolean(true);
1234         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1235                 outLaunched);
1236         assertFalse(intercepted);
1237         assertFalse(outLaunched.value);
1238 
1239         final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
1240         eventTime += interval;
1241         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1242                 IGNORED_REPEAT);
1243         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1244                 outLaunched);
1245         assertFalse(intercepted);
1246         assertTrue(outLaunched.value);
1247 
1248         verify(mStatusBarManagerInternal).onCameraLaunchGestureDetected(
1249                 StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP);
1250         verify(mMetricsLogger)
1251             .action(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE, (int) interval);
1252         verify(mUiEventLogger, times(1))
1253                 .log(GestureLauncherService.GestureLauncherEvent.GESTURE_CAMERA_DOUBLE_TAP_POWER);
1254 
1255         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
1256         verify(mMetricsLogger, times(2)).histogram(
1257                 eq("power_double_tap_interval"), intervalCaptor.capture());
1258         List<Integer> intervals = intervalCaptor.getAllValues();
1259         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
1260         assertEquals((int) interval, intervals.get(1).intValue());
1261 
1262         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
1263         verify(mMetricsLogger, times(2)).histogram(
1264                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
1265         List<Integer> tapCounts = tapCountCaptor.getAllValues();
1266         assertEquals(1, tapCounts.get(0).intValue());
1267         assertEquals(2, tapCounts.get(1).intValue());
1268     }
1269 
1270     @Test
1271     public void
testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOnNotInteractiveSetupIncomplete()1272     testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOnNotInteractiveSetupIncomplete() {
1273         withCameraDoubleTapPowerEnableConfigValue(true);
1274         withCameraDoubleTapPowerDisableSettingValue(0);
1275         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
1276         withUserSetupCompleteValue(false);
1277 
1278         long eventTime = INITIAL_EVENT_TIME_MILLIS;
1279         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1280                 IGNORED_REPEAT);
1281         boolean interactive = false;
1282         MutableBoolean outLaunched = new MutableBoolean(true);
1283         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1284                 outLaunched);
1285         assertFalse(intercepted);
1286         assertFalse(outLaunched.value);
1287 
1288         final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
1289         eventTime += interval;
1290         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1291                 IGNORED_REPEAT);
1292         outLaunched.value = true;
1293         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1294                 outLaunched);
1295         assertFalse(intercepted);
1296         assertFalse(outLaunched.value);
1297 
1298         verify(mMetricsLogger, never())
1299             .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
1300         verify(mUiEventLogger, never()).log(any());
1301 
1302         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
1303         verify(mMetricsLogger, times(2)).histogram(
1304                 eq("power_double_tap_interval"), intervalCaptor.capture());
1305         List<Integer> intervals = intervalCaptor.getAllValues();
1306         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
1307         assertEquals((int) interval, intervals.get(1).intValue());
1308 
1309         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
1310         verify(mMetricsLogger, times(2)).histogram(
1311                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
1312         List<Integer> tapCounts = tapCountCaptor.getAllValues();
1313         assertEquals(1, tapCounts.get(0).intValue());
1314         assertEquals(2, tapCounts.get(1).intValue());
1315     }
1316 
1317     @Test
testInterceptPowerKeyDown_intervalMidBoundsCameraPowerGestureOnNotInteractive()1318     public void testInterceptPowerKeyDown_intervalMidBoundsCameraPowerGestureOnNotInteractive() {
1319         withCameraDoubleTapPowerEnableConfigValue(true);
1320         withCameraDoubleTapPowerDisableSettingValue(0);
1321         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
1322 
1323         long eventTime = INITIAL_EVENT_TIME_MILLIS;
1324         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1325                 IGNORED_REPEAT);
1326         boolean interactive = false;
1327         MutableBoolean outLaunched = new MutableBoolean(true);
1328         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1329                 outLaunched);
1330         assertFalse(intercepted);
1331         assertFalse(outLaunched.value);
1332 
1333         final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS;
1334         eventTime += interval;
1335         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1336                 IGNORED_REPEAT);
1337         outLaunched.value = true;
1338         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1339                 outLaunched);
1340         assertFalse(intercepted);
1341         assertFalse(outLaunched.value);
1342 
1343         verify(mMetricsLogger, never())
1344             .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
1345         verify(mUiEventLogger, never()).log(any());
1346 
1347         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
1348         verify(mMetricsLogger, times(2)).histogram(
1349                 eq("power_double_tap_interval"), intervalCaptor.capture());
1350         List<Integer> intervals = intervalCaptor.getAllValues();
1351         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
1352         assertEquals((int) interval, intervals.get(1).intValue());
1353 
1354         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
1355         verify(mMetricsLogger, times(2)).histogram(
1356                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
1357         List<Integer> tapCounts = tapCountCaptor.getAllValues();
1358         assertEquals(1, tapCounts.get(0).intValue());
1359         // The interval is too long to launch the camera, but short enough to count as a
1360         // sequential tap.
1361         assertEquals(2, tapCounts.get(1).intValue());
1362     }
1363 
1364     @Test
testInterceptPowerKeyDown_intervalOutOfBoundsCameraPowerGestureOnNotInteractive()1365     public void testInterceptPowerKeyDown_intervalOutOfBoundsCameraPowerGestureOnNotInteractive() {
1366         withCameraDoubleTapPowerEnableConfigValue(true);
1367         withCameraDoubleTapPowerDisableSettingValue(0);
1368         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
1369 
1370         long eventTime = INITIAL_EVENT_TIME_MILLIS;
1371         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1372                 IGNORED_REPEAT);
1373         boolean interactive = false;
1374         MutableBoolean outLaunched = new MutableBoolean(true);
1375         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1376                 outLaunched);
1377         assertFalse(intercepted);
1378         assertFalse(outLaunched.value);
1379 
1380         long interval = GestureLauncherService.POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS;
1381         eventTime += interval;
1382         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1383                 IGNORED_REPEAT);
1384         outLaunched.value = true;
1385         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1386                 outLaunched);
1387         assertFalse(intercepted);
1388         assertFalse(outLaunched.value);
1389 
1390         verify(mMetricsLogger, never())
1391             .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
1392         verify(mUiEventLogger, never()).log(any());
1393 
1394         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
1395         verify(mMetricsLogger, times(2)).histogram(
1396                 eq("power_double_tap_interval"), intervalCaptor.capture());
1397         List<Integer> intervals = intervalCaptor.getAllValues();
1398         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
1399         assertEquals((int) interval, intervals.get(1).intValue());
1400 
1401         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
1402         verify(mMetricsLogger, times(2)).histogram(
1403                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
1404         List<Integer> tapCounts = tapCountCaptor.getAllValues();
1405         assertEquals(1, tapCounts.get(0).intValue());
1406         assertEquals(1, tapCounts.get(1).intValue());
1407     }
1408 
1409     /**
1410      * Helper method to trigger emergency gesture by pressing button for 5 times.
1411      *
1412      * @return last event time.
1413      */
triggerEmergencyGesture()1414     private long triggerEmergencyGesture() {
1415         return triggerEmergencyGesture(CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1);
1416     }
1417 
1418     /**
1419      * Helper method to trigger emergency gesture by pressing button for 5 times with
1420      * specified interval between each tap
1421      *
1422      * @return last event time.
1423      */
triggerEmergencyGesture(long tapIntervalMs)1424     private long triggerEmergencyGesture(long tapIntervalMs) {
1425         // Enable emergency power gesture
1426         withEmergencyGestureEnabledConfigValue(true);
1427         withEmergencyGestureEnabledSettingValue(true);
1428         mGestureLauncherService.updateEmergencyGestureEnabled();
1429         withUserSetupCompleteValue(true);
1430 
1431         // 4 button presses
1432         long eventTime = INITIAL_EVENT_TIME_MILLIS;
1433         boolean interactive = true;
1434         KeyEvent keyEvent;
1435         MutableBoolean outLaunched = new MutableBoolean(false);
1436         for (int i = 0; i < 4; i++) {
1437             keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1438                     IGNORED_REPEAT);
1439             mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive, outLaunched);
1440             eventTime += tapIntervalMs;
1441         }
1442 
1443         // 5th button press should trigger the emergency flow
1444         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
1445                 IGNORED_REPEAT);
1446         outLaunched.value = false;
1447         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
1448                 outLaunched);
1449         long emergencyGestureTapDetectionMinTimeMs = Settings.Global.getInt(
1450                 mContext.getContentResolver(),
1451                 Settings.Global.EMERGENCY_GESTURE_TAP_DETECTION_MIN_TIME_MS,
1452                 EMERGENCY_GESTURE_TAP_DETECTION_MIN_TIME_MS);
1453         assertTrue(intercepted);
1454         if (tapIntervalMs * 4 > emergencyGestureTapDetectionMinTimeMs) {
1455             assertTrue(outLaunched.value);
1456             verify(mUiEventLogger, times(1))
1457                     .log(GestureLauncherService.GestureLauncherEvent.GESTURE_EMERGENCY_TAP_POWER);
1458             verify(mStatusBarManagerInternal).onEmergencyActionLaunchGestureDetected();
1459         } else {
1460             assertFalse(outLaunched.value);
1461             verify(mUiEventLogger, never())
1462                     .log(GestureLauncherService.GestureLauncherEvent.GESTURE_EMERGENCY_TAP_POWER);
1463             verify(mStatusBarManagerInternal, never()).onEmergencyActionLaunchGestureDetected();
1464         }
1465         return eventTime;
1466     }
1467 
withCameraDoubleTapPowerEnableConfigValue(boolean enableConfigValue)1468     private void withCameraDoubleTapPowerEnableConfigValue(boolean enableConfigValue) {
1469         when(mResources.getBoolean(
1470                 com.android.internal.R.bool.config_cameraDoubleTapPowerGestureEnabled))
1471                 .thenReturn(enableConfigValue);
1472     }
1473 
withEmergencyGestureEnabledConfigValue(boolean enableConfigValue)1474     private void withEmergencyGestureEnabledConfigValue(boolean enableConfigValue) {
1475         when(mResources.getBoolean(
1476                 com.android.internal.R.bool.config_emergencyGestureEnabled))
1477                 .thenReturn(enableConfigValue);
1478     }
1479 
withCameraDoubleTapPowerDisableSettingValue(int disableSettingValue)1480     private void withCameraDoubleTapPowerDisableSettingValue(int disableSettingValue) {
1481         Settings.Secure.putIntForUser(
1482                 mContentResolver,
1483                 Settings.Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED,
1484                 disableSettingValue,
1485                 UserHandle.USER_CURRENT);
1486     }
1487 
withEmergencyGestureEnabledSettingValue(boolean enable)1488     private void withEmergencyGestureEnabledSettingValue(boolean enable) {
1489         Settings.Secure.putIntForUser(
1490                 mContentResolver,
1491                 Settings.Secure.EMERGENCY_GESTURE_ENABLED,
1492                 enable ? 1 : 0,
1493                 UserHandle.USER_CURRENT);
1494     }
1495 
withEmergencyGesturePowerButtonCooldownPeriodMsValue(int period)1496     private void withEmergencyGesturePowerButtonCooldownPeriodMsValue(int period) {
1497         Settings.Global.putInt(
1498                 mContentResolver,
1499                 Settings.Global.EMERGENCY_GESTURE_POWER_BUTTON_COOLDOWN_PERIOD_MS,
1500                 period);
1501     }
1502 
withUserSetupCompleteValue(boolean userSetupComplete)1503     private void withUserSetupCompleteValue(boolean userSetupComplete) {
1504         int userSetupCompleteValue = userSetupComplete ? 1 : 0;
1505         Settings.Secure.putIntForUser(
1506                 mContentResolver,
1507                 Settings.Secure.USER_SETUP_COMPLETE,
1508                 userSetupCompleteValue,
1509                 UserHandle.USER_CURRENT);
1510     }
1511 }
1512