• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.Matchers.anyInt;
23 import static org.mockito.Matchers.eq;
24 import static org.mockito.Mockito.never;
25 import static org.mockito.Mockito.times;
26 import static org.mockito.Mockito.verify;
27 import static org.mockito.Mockito.when;
28 
29 import android.app.StatusBarManager;
30 import android.content.Context;
31 import android.content.res.Resources;
32 import android.os.Looper;
33 import android.os.UserHandle;
34 import android.platform.test.annotations.Presubmit;
35 import android.provider.Settings;
36 import android.support.test.InstrumentationRegistry;
37 import android.support.test.filters.SmallTest;
38 import android.support.test.runner.AndroidJUnit4;
39 import android.test.mock.MockContentResolver;
40 import android.view.KeyEvent;
41 import android.util.MutableBoolean;
42 
43 import com.android.internal.logging.MetricsLogger;
44 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
45 import com.android.internal.util.test.FakeSettingsProvider;
46 import com.android.server.LocalServices;
47 import com.android.server.statusbar.StatusBarManagerInternal;
48 
49 import java.util.List;
50 
51 import org.junit.Before;
52 import org.junit.BeforeClass;
53 import org.junit.Test;
54 import org.junit.runner.RunWith;
55 import org.junit.runners.JUnit4;
56 import org.mockito.ArgumentCaptor;
57 import org.mockito.Mock;
58 import org.mockito.MockitoAnnotations;
59 
60 /**
61  * Unit tests for {@link GestureLauncherService}.
62  * runtest frameworks-services -c com.android.server.GestureLauncherServiceTest
63  */
64 @Presubmit
65 @SmallTest
66 @RunWith(AndroidJUnit4.class)
67 public class GestureLauncherServiceTest {
68 
69     private static final int FAKE_USER_ID = 1337;
70     private static final int FAKE_SOURCE = 1982;
71     private static final long INITIAL_EVENT_TIME_MILLIS = 20000L;
72     private static final long IGNORED_DOWN_TIME = 1234L;
73     private static final int IGNORED_ACTION = 13;
74     private static final int IGNORED_CODE = 1999;
75     private static final int IGNORED_REPEAT = 42;
76 
77     private @Mock Context mContext;
78     private @Mock Resources mResources;
79     private @Mock StatusBarManagerInternal mStatusBarManagerInternal;
80     private @Mock MetricsLogger mMetricsLogger;
81     private MockContentResolver mContentResolver;
82     private GestureLauncherService mGestureLauncherService;
83 
84     @BeforeClass
oneTimeInitialization()85     public static void oneTimeInitialization() {
86         if (Looper.myLooper() == null) {
87             Looper.prepare();
88         }
89     }
90 
91     @Before
setup()92     public void setup() {
93         MockitoAnnotations.initMocks(this);
94 
95         LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
96         LocalServices.addService(StatusBarManagerInternal.class, mStatusBarManagerInternal);
97 
98         final Context originalContext = InstrumentationRegistry.getContext();
99         when(mContext.getApplicationInfo()).thenReturn(originalContext.getApplicationInfo());
100         when(mContext.getResources()).thenReturn(mResources);
101         mContentResolver = new MockContentResolver(mContext);
102         mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
103         when(mContext.getContentResolver()).thenReturn(mContentResolver);
104 
105         mGestureLauncherService = new GestureLauncherService(mContext, mMetricsLogger);
106     }
107 
108     @Test
testIsCameraDoubleTapPowerEnabled_configFalse()109     public void testIsCameraDoubleTapPowerEnabled_configFalse() {
110         withCameraDoubleTapPowerEnableConfigValue(false);
111         assertFalse(mGestureLauncherService.isCameraDoubleTapPowerEnabled(mResources));
112     }
113 
114     @Test
testIsCameraDoubleTapPowerEnabled_configTrue()115     public void testIsCameraDoubleTapPowerEnabled_configTrue() {
116         withCameraDoubleTapPowerEnableConfigValue(true);
117         assertTrue(mGestureLauncherService.isCameraDoubleTapPowerEnabled(mResources));
118     }
119 
120     @Test
testIsCameraDoubleTapPowerSettingEnabled_configFalseSettingDisabled()121     public void testIsCameraDoubleTapPowerSettingEnabled_configFalseSettingDisabled() {
122         withCameraDoubleTapPowerEnableConfigValue(false);
123         withCameraDoubleTapPowerDisableSettingValue(1);
124         assertFalse(mGestureLauncherService.isCameraDoubleTapPowerSettingEnabled(
125                 mContext, FAKE_USER_ID));
126     }
127 
128     @Test
testIsCameraDoubleTapPowerSettingEnabled_configFalseSettingEnabled()129     public void testIsCameraDoubleTapPowerSettingEnabled_configFalseSettingEnabled() {
130         withCameraDoubleTapPowerEnableConfigValue(false);
131         withCameraDoubleTapPowerDisableSettingValue(0);
132         assertFalse(mGestureLauncherService.isCameraDoubleTapPowerSettingEnabled(
133                 mContext, FAKE_USER_ID));
134     }
135 
136     @Test
testIsCameraDoubleTapPowerSettingEnabled_configTrueSettingDisabled()137     public void testIsCameraDoubleTapPowerSettingEnabled_configTrueSettingDisabled() {
138         withCameraDoubleTapPowerEnableConfigValue(true);
139         withCameraDoubleTapPowerDisableSettingValue(1);
140         assertFalse(mGestureLauncherService.isCameraDoubleTapPowerSettingEnabled(
141                 mContext, FAKE_USER_ID));
142     }
143 
144     @Test
testIsCameraDoubleTapPowerSettingEnabled_configTrueSettingEnabled()145     public void testIsCameraDoubleTapPowerSettingEnabled_configTrueSettingEnabled() {
146         withCameraDoubleTapPowerEnableConfigValue(true);
147         withCameraDoubleTapPowerDisableSettingValue(0);
148         assertTrue(mGestureLauncherService.isCameraDoubleTapPowerSettingEnabled(
149                 mContext, FAKE_USER_ID));
150     }
151 
152     @Test
testHandleCameraLaunchGesture_userSetupComplete()153     public void testHandleCameraLaunchGesture_userSetupComplete() {
154         withUserSetupCompleteValue(true);
155 
156         boolean useWakeLock = false;
157         assertTrue(mGestureLauncherService.handleCameraGesture(useWakeLock, FAKE_SOURCE));
158         verify(mStatusBarManagerInternal).onCameraLaunchGestureDetected(FAKE_SOURCE);
159     }
160 
161     @Test
testHandleCameraLaunchGesture_userSetupNotComplete()162     public void testHandleCameraLaunchGesture_userSetupNotComplete() {
163         withUserSetupCompleteValue(false);
164 
165         boolean useWakeLock = false;
166         assertFalse(mGestureLauncherService.handleCameraGesture(useWakeLock, FAKE_SOURCE));
167     }
168 
169     @Test
testInterceptPowerKeyDown_firstPowerDownCameraPowerGestureOnInteractive()170     public void testInterceptPowerKeyDown_firstPowerDownCameraPowerGestureOnInteractive() {
171         withCameraDoubleTapPowerEnableConfigValue(true);
172         withCameraDoubleTapPowerDisableSettingValue(0);
173         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
174 
175         long eventTime = INITIAL_EVENT_TIME_MILLIS +
176                 GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
177         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
178                 IGNORED_REPEAT);
179         boolean interactive = true;
180         MutableBoolean outLaunched = new MutableBoolean(true);
181         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
182                 outLaunched);
183         assertFalse(intercepted);
184         assertFalse(outLaunched.value);
185         verify(mMetricsLogger).histogram("power_consecutive_short_tap_count", 1);
186         verify(mMetricsLogger).histogram("power_double_tap_interval", (int) eventTime);
187     }
188 
189     @Test
testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOffInteractive()190     public void testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOffInteractive() {
191         withCameraDoubleTapPowerEnableConfigValue(false);
192         withCameraDoubleTapPowerDisableSettingValue(1);
193         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
194 
195         long eventTime = INITIAL_EVENT_TIME_MILLIS;
196         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
197                 IGNORED_REPEAT);
198         boolean interactive = true;
199         MutableBoolean outLaunched = new MutableBoolean(true);
200         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
201                 outLaunched);
202         assertFalse(intercepted);
203         assertFalse(outLaunched.value);
204 
205         final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
206         eventTime += interval;
207         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
208                 IGNORED_REPEAT);
209         outLaunched.value = true;
210         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
211                 outLaunched);
212         assertFalse(intercepted);
213         assertFalse(outLaunched.value);
214 
215         verify(mMetricsLogger, never())
216             .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
217 
218         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
219         verify(mMetricsLogger, times(2)).histogram(
220                 eq("power_double_tap_interval"), intervalCaptor.capture());
221         List<Integer> intervals = intervalCaptor.getAllValues();
222         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
223         assertEquals((int) interval, intervals.get(1).intValue());
224 
225         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
226         verify(mMetricsLogger, times(2)).histogram(
227                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
228         List<Integer> tapCounts = tapCountCaptor.getAllValues();
229         assertEquals(1, tapCounts.get(0).intValue());
230         assertEquals(2, tapCounts.get(1).intValue());
231     }
232 
233     @Test
testInterceptPowerKeyDown_intervalMidBoundsCameraPowerGestureOffInteractive()234     public void testInterceptPowerKeyDown_intervalMidBoundsCameraPowerGestureOffInteractive() {
235         withCameraDoubleTapPowerEnableConfigValue(false);
236         withCameraDoubleTapPowerDisableSettingValue(1);
237         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
238 
239         long eventTime = INITIAL_EVENT_TIME_MILLIS;
240         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
241                 IGNORED_REPEAT);
242         boolean interactive = true;
243         MutableBoolean outLaunched = new MutableBoolean(true);
244         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
245                 outLaunched);
246         assertFalse(intercepted);
247         assertFalse(outLaunched.value);
248 
249         final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS;
250         eventTime += interval;
251         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
252                 IGNORED_REPEAT);
253         outLaunched.value = true;
254         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
255                 outLaunched);
256         assertFalse(intercepted);
257         assertFalse(outLaunched.value);
258 
259         verify(mMetricsLogger, never())
260             .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
261 
262         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
263         verify(mMetricsLogger, times(2)).histogram(
264                 eq("power_double_tap_interval"), intervalCaptor.capture());
265         List<Integer> intervals = intervalCaptor.getAllValues();
266         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
267         assertEquals((int) interval, intervals.get(1).intValue());
268 
269         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
270         verify(mMetricsLogger, times(2)).histogram(
271                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
272         List<Integer> tapCounts = tapCountCaptor.getAllValues();
273         assertEquals(1, tapCounts.get(0).intValue());
274         // The interval is too long to launch the camera, but short enough to count as a
275         // sequential tap.
276         assertEquals(2, tapCounts.get(1).intValue());
277     }
278 
279     @Test
testInterceptPowerKeyDown_intervalOutOfBoundsCameraPowerGestureOffInteractive()280     public void testInterceptPowerKeyDown_intervalOutOfBoundsCameraPowerGestureOffInteractive() {
281         withCameraDoubleTapPowerEnableConfigValue(false);
282         withCameraDoubleTapPowerDisableSettingValue(1);
283         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
284 
285         long eventTime = INITIAL_EVENT_TIME_MILLIS;
286         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
287                 IGNORED_REPEAT);
288         boolean interactive = true;
289         MutableBoolean outLaunched = new MutableBoolean(true);
290         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
291                 outLaunched);
292         assertFalse(intercepted);
293         assertFalse(outLaunched.value);
294 
295         long interval = GestureLauncherService.POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS;
296         eventTime += interval;
297         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
298                 IGNORED_REPEAT);
299         outLaunched.value = true;
300         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
301                 outLaunched);
302         assertFalse(intercepted);
303         assertFalse(outLaunched.value);
304 
305         verify(mMetricsLogger, never())
306             .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
307 
308         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
309         verify(mMetricsLogger, times(2)).histogram(
310                 eq("power_double_tap_interval"), intervalCaptor.capture());
311         List<Integer> intervals = intervalCaptor.getAllValues();
312         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
313         assertEquals((int) interval, intervals.get(1).intValue());
314 
315         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
316         verify(mMetricsLogger, times(2)).histogram(
317                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
318         List<Integer> tapCounts = tapCountCaptor.getAllValues();
319         assertEquals(1, tapCounts.get(0).intValue());
320         assertEquals(1, tapCounts.get(1).intValue());
321     }
322 
323     @Test
324     public void
testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOnInteractiveSetupComplete()325     testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOnInteractiveSetupComplete() {
326         withCameraDoubleTapPowerEnableConfigValue(true);
327         withCameraDoubleTapPowerDisableSettingValue(0);
328         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
329         withUserSetupCompleteValue(true);
330 
331         long eventTime = INITIAL_EVENT_TIME_MILLIS;
332         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
333                 IGNORED_REPEAT);
334         boolean interactive = true;
335         MutableBoolean outLaunched = new MutableBoolean(true);
336         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
337                 outLaunched);
338         assertFalse(intercepted);
339         assertFalse(outLaunched.value);
340 
341         final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
342         eventTime += interval;
343         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
344                 IGNORED_REPEAT);
345         outLaunched.value = false;
346         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
347                 outLaunched);
348         assertTrue(intercepted);
349         assertTrue(outLaunched.value);
350 
351         verify(mStatusBarManagerInternal).onCameraLaunchGestureDetected(
352                 StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP);
353         verify(mMetricsLogger)
354             .action(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE, (int) interval);
355 
356         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
357         verify(mMetricsLogger, times(2)).histogram(
358                 eq("power_double_tap_interval"), intervalCaptor.capture());
359         List<Integer> intervals = intervalCaptor.getAllValues();
360         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
361         assertEquals((int) interval, intervals.get(1).intValue());
362 
363         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
364         verify(mMetricsLogger, times(2)).histogram(
365                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
366         List<Integer> tapCounts = tapCountCaptor.getAllValues();
367         assertEquals(1, tapCounts.get(0).intValue());
368         assertEquals(2, tapCounts.get(1).intValue());
369     }
370 
371     @Test
372     public void
testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOnInteractiveSetupIncomplete()373     testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOnInteractiveSetupIncomplete() {
374         withCameraDoubleTapPowerEnableConfigValue(true);
375         withCameraDoubleTapPowerDisableSettingValue(0);
376         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
377         withUserSetupCompleteValue(false);
378 
379         long eventTime = INITIAL_EVENT_TIME_MILLIS;
380         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
381                 IGNORED_REPEAT);
382         boolean interactive = true;
383         MutableBoolean outLaunched = new MutableBoolean(true);
384         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
385                 outLaunched);
386         assertFalse(intercepted);
387         assertFalse(outLaunched.value);
388 
389         final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
390         eventTime += interval;
391         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
392                 IGNORED_REPEAT);
393         outLaunched.value = true;
394         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
395                 outLaunched);
396         assertFalse(intercepted);
397         assertFalse(outLaunched.value);
398 
399         verify(mMetricsLogger, never())
400             .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
401 
402         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
403         verify(mMetricsLogger, times(2)).histogram(
404                 eq("power_double_tap_interval"), intervalCaptor.capture());
405         List<Integer> intervals = intervalCaptor.getAllValues();
406         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
407         assertEquals((int) interval, intervals.get(1).intValue());
408 
409         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
410         verify(mMetricsLogger, times(2)).histogram(
411                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
412         List<Integer> tapCounts = tapCountCaptor.getAllValues();
413         assertEquals(1, tapCounts.get(0).intValue());
414         // The interval is too long to launch the camera, but short enough to count as a
415         // sequential tap.
416         assertEquals(2, tapCounts.get(1).intValue());
417     }
418 
419     @Test
testInterceptPowerKeyDown_intervalMidBoundsCameraPowerGestureOnInteractive()420     public void testInterceptPowerKeyDown_intervalMidBoundsCameraPowerGestureOnInteractive() {
421         withCameraDoubleTapPowerEnableConfigValue(true);
422         withCameraDoubleTapPowerDisableSettingValue(0);
423         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
424 
425         long eventTime = INITIAL_EVENT_TIME_MILLIS;
426         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
427                 IGNORED_REPEAT);
428         boolean interactive = true;
429         MutableBoolean outLaunched = new MutableBoolean(true);
430         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
431                 outLaunched);
432         assertFalse(intercepted);
433         assertFalse(outLaunched.value);
434 
435         final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS;
436         eventTime += interval;
437         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
438                 IGNORED_REPEAT);
439         outLaunched.value = true;
440         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
441                 outLaunched);
442         assertFalse(intercepted);
443         assertFalse(outLaunched.value);
444 
445         verify(mMetricsLogger, never())
446             .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
447 
448         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
449         verify(mMetricsLogger, times(2)).histogram(
450                 eq("power_double_tap_interval"), intervalCaptor.capture());
451         List<Integer> intervals = intervalCaptor.getAllValues();
452         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
453         assertEquals((int) interval, intervals.get(1).intValue());
454 
455         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
456         verify(mMetricsLogger, times(2)).histogram(
457                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
458         List<Integer> tapCounts = tapCountCaptor.getAllValues();
459         assertEquals(1, tapCounts.get(0).intValue());
460         // The interval is too long to launch the camera, but short enough to count as a
461         // sequential tap.
462         assertEquals(2, tapCounts.get(1).intValue());
463     }
464 
465     @Test
testInterceptPowerKeyDown_intervalOutOfBoundsCameraPowerGestureOnInteractive()466     public void testInterceptPowerKeyDown_intervalOutOfBoundsCameraPowerGestureOnInteractive() {
467         withCameraDoubleTapPowerEnableConfigValue(true);
468         withCameraDoubleTapPowerDisableSettingValue(0);
469         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
470 
471         long eventTime = INITIAL_EVENT_TIME_MILLIS;
472         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
473                 IGNORED_REPEAT);
474         boolean interactive = true;
475         MutableBoolean outLaunched = new MutableBoolean(true);
476         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
477                 outLaunched);
478         assertFalse(intercepted);
479         assertFalse(outLaunched.value);
480 
481         long interval = GestureLauncherService.POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS;
482         eventTime += interval;
483         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
484                 IGNORED_REPEAT);
485         outLaunched.value = true;
486         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
487                 outLaunched);
488         assertFalse(intercepted);
489         assertFalse(outLaunched.value);
490 
491         verify(mMetricsLogger, never())
492             .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
493 
494         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
495         verify(mMetricsLogger, times(2)).histogram(
496                 eq("power_double_tap_interval"), intervalCaptor.capture());
497         List<Integer> intervals = intervalCaptor.getAllValues();
498         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
499         assertEquals((int) interval, intervals.get(1).intValue());
500 
501         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
502         verify(mMetricsLogger, times(2)).histogram(
503                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
504         List<Integer> tapCounts = tapCountCaptor.getAllValues();
505         assertEquals(1, tapCounts.get(0).intValue());
506         assertEquals(1, tapCounts.get(1).intValue());
507     }
508 
509     @Test
testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOffNotInteractive()510     public void testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOffNotInteractive() {
511         withCameraDoubleTapPowerEnableConfigValue(false);
512         withCameraDoubleTapPowerDisableSettingValue(1);
513         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
514 
515         long eventTime = INITIAL_EVENT_TIME_MILLIS;
516         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
517                 IGNORED_REPEAT);
518         boolean interactive = false;
519         MutableBoolean outLaunched = new MutableBoolean(true);
520         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
521                 outLaunched);
522         assertFalse(intercepted);
523         assertFalse(outLaunched.value);
524 
525         final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
526         eventTime += interval;
527         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
528                 IGNORED_REPEAT);
529         outLaunched.value = true;
530         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
531                 outLaunched);
532         assertFalse(intercepted);
533         assertFalse(outLaunched.value);
534 
535         verify(mMetricsLogger, never())
536             .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
537 
538         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
539         verify(mMetricsLogger, times(2)).histogram(
540                 eq("power_double_tap_interval"), intervalCaptor.capture());
541         List<Integer> intervals = intervalCaptor.getAllValues();
542         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
543         assertEquals((int) interval, intervals.get(1).intValue());
544 
545         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
546         verify(mMetricsLogger, times(2)).histogram(
547                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
548         List<Integer> tapCounts = tapCountCaptor.getAllValues();
549         assertEquals(1, tapCounts.get(0).intValue());
550         assertEquals(2, tapCounts.get(1).intValue());
551     }
552 
553     @Test
testInterceptPowerKeyDown_intervalMidBoundsCameraPowerGestureOffNotInteractive()554     public void testInterceptPowerKeyDown_intervalMidBoundsCameraPowerGestureOffNotInteractive() {
555         withCameraDoubleTapPowerEnableConfigValue(false);
556         withCameraDoubleTapPowerDisableSettingValue(1);
557         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
558 
559         long eventTime = INITIAL_EVENT_TIME_MILLIS;
560         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
561                 IGNORED_REPEAT);
562         boolean interactive = false;
563         MutableBoolean outLaunched = new MutableBoolean(true);
564         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
565                 outLaunched);
566         assertFalse(intercepted);
567         assertFalse(outLaunched.value);
568 
569         final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS;
570         eventTime += interval;
571         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
572                 IGNORED_REPEAT);
573         outLaunched.value = true;
574         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
575                 outLaunched);
576         assertFalse(intercepted);
577         assertFalse(outLaunched.value);
578         verify(mMetricsLogger, never())
579             .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
580 
581         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
582         verify(mMetricsLogger, times(2)).histogram(
583                 eq("power_double_tap_interval"), intervalCaptor.capture());
584         List<Integer> intervals = intervalCaptor.getAllValues();
585         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
586         assertEquals((int) interval, intervals.get(1).intValue());
587 
588         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
589         verify(mMetricsLogger, times(2)).histogram(
590                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
591         List<Integer> tapCounts = tapCountCaptor.getAllValues();
592         assertEquals(1, tapCounts.get(0).intValue());
593         // The interval is too long to launch the camera, but short enough to count as a
594         // sequential tap.
595         assertEquals(2, tapCounts.get(1).intValue());
596     }
597 
598     @Test
testInterceptPowerKeyDown_intervalOutOfBoundsCameraPowerGestureOffNotInteractive()599     public void testInterceptPowerKeyDown_intervalOutOfBoundsCameraPowerGestureOffNotInteractive() {
600         withCameraDoubleTapPowerEnableConfigValue(false);
601         withCameraDoubleTapPowerDisableSettingValue(1);
602         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
603 
604         long eventTime = INITIAL_EVENT_TIME_MILLIS;
605         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
606                 IGNORED_REPEAT);
607         boolean interactive = false;
608         MutableBoolean outLaunched = new MutableBoolean(true);
609         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
610                 outLaunched);
611         assertFalse(intercepted);
612         assertFalse(outLaunched.value);
613 
614         long interval = GestureLauncherService.POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS;
615         eventTime += interval;
616         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
617                 IGNORED_REPEAT);
618         outLaunched.value = true;
619         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
620                 outLaunched);
621         assertFalse(intercepted);
622         assertFalse(outLaunched.value);
623         verify(mMetricsLogger, never())
624             .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
625 
626         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
627         verify(mMetricsLogger, times(2)).histogram(
628                 eq("power_double_tap_interval"), intervalCaptor.capture());
629         List<Integer> intervals = intervalCaptor.getAllValues();
630         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
631         assertEquals((int) interval, intervals.get(1).intValue());
632 
633         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
634         verify(mMetricsLogger, times(2)).histogram(
635                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
636         List<Integer> tapCounts = tapCountCaptor.getAllValues();
637         assertEquals(1, tapCounts.get(0).intValue());
638         assertEquals(1, tapCounts.get(1).intValue());
639     }
640 
641     @Test
642     public void
testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOnNotInteractiveSetupComplete()643     testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOnNotInteractiveSetupComplete() {
644         withCameraDoubleTapPowerEnableConfigValue(true);
645         withCameraDoubleTapPowerDisableSettingValue(0);
646         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
647         withUserSetupCompleteValue(true);
648 
649         long eventTime = INITIAL_EVENT_TIME_MILLIS;
650         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
651                 IGNORED_REPEAT);
652         boolean interactive = false;
653         MutableBoolean outLaunched = new MutableBoolean(true);
654         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
655                 outLaunched);
656         assertFalse(intercepted);
657         assertFalse(outLaunched.value);
658 
659         final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
660         eventTime += interval;
661         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
662                 IGNORED_REPEAT);
663         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
664                 outLaunched);
665         assertFalse(intercepted);
666         assertTrue(outLaunched.value);
667 
668         verify(mStatusBarManagerInternal).onCameraLaunchGestureDetected(
669                 StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP);
670         verify(mMetricsLogger)
671             .action(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE, (int) interval);
672 
673         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
674         verify(mMetricsLogger, times(2)).histogram(
675                 eq("power_double_tap_interval"), intervalCaptor.capture());
676         List<Integer> intervals = intervalCaptor.getAllValues();
677         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
678         assertEquals((int) interval, intervals.get(1).intValue());
679 
680         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
681         verify(mMetricsLogger, times(2)).histogram(
682                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
683         List<Integer> tapCounts = tapCountCaptor.getAllValues();
684         assertEquals(1, tapCounts.get(0).intValue());
685         assertEquals(2, tapCounts.get(1).intValue());
686     }
687 
688     @Test
689     public void
testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOnNotInteractiveSetupIncomplete()690     testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOnNotInteractiveSetupIncomplete() {
691         withCameraDoubleTapPowerEnableConfigValue(true);
692         withCameraDoubleTapPowerDisableSettingValue(0);
693         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
694         withUserSetupCompleteValue(false);
695 
696         long eventTime = INITIAL_EVENT_TIME_MILLIS;
697         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
698                 IGNORED_REPEAT);
699         boolean interactive = false;
700         MutableBoolean outLaunched = new MutableBoolean(true);
701         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
702                 outLaunched);
703         assertFalse(intercepted);
704         assertFalse(outLaunched.value);
705 
706         final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
707         eventTime += interval;
708         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
709                 IGNORED_REPEAT);
710         outLaunched.value = true;
711         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
712                 outLaunched);
713         assertFalse(intercepted);
714         assertFalse(outLaunched.value);
715 
716         verify(mMetricsLogger, never())
717             .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
718 
719         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
720         verify(mMetricsLogger, times(2)).histogram(
721                 eq("power_double_tap_interval"), intervalCaptor.capture());
722         List<Integer> intervals = intervalCaptor.getAllValues();
723         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
724         assertEquals((int) interval, intervals.get(1).intValue());
725 
726         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
727         verify(mMetricsLogger, times(2)).histogram(
728                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
729         List<Integer> tapCounts = tapCountCaptor.getAllValues();
730         assertEquals(1, tapCounts.get(0).intValue());
731         assertEquals(2, tapCounts.get(1).intValue());
732     }
733 
734     @Test
testInterceptPowerKeyDown_intervalMidBoundsCameraPowerGestureOnNotInteractive()735     public void testInterceptPowerKeyDown_intervalMidBoundsCameraPowerGestureOnNotInteractive() {
736         withCameraDoubleTapPowerEnableConfigValue(true);
737         withCameraDoubleTapPowerDisableSettingValue(0);
738         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
739 
740         long eventTime = INITIAL_EVENT_TIME_MILLIS;
741         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
742                 IGNORED_REPEAT);
743         boolean interactive = false;
744         MutableBoolean outLaunched = new MutableBoolean(true);
745         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
746                 outLaunched);
747         assertFalse(intercepted);
748         assertFalse(outLaunched.value);
749 
750         final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS;
751         eventTime += interval;
752         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
753                 IGNORED_REPEAT);
754         outLaunched.value = true;
755         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
756                 outLaunched);
757         assertFalse(intercepted);
758         assertFalse(outLaunched.value);
759 
760         verify(mMetricsLogger, never())
761             .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
762 
763         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
764         verify(mMetricsLogger, times(2)).histogram(
765                 eq("power_double_tap_interval"), intervalCaptor.capture());
766         List<Integer> intervals = intervalCaptor.getAllValues();
767         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
768         assertEquals((int) interval, intervals.get(1).intValue());
769 
770         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
771         verify(mMetricsLogger, times(2)).histogram(
772                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
773         List<Integer> tapCounts = tapCountCaptor.getAllValues();
774         assertEquals(1, tapCounts.get(0).intValue());
775         // The interval is too long to launch the camera, but short enough to count as a
776         // sequential tap.
777         assertEquals(2, tapCounts.get(1).intValue());
778     }
779 
780     @Test
testInterceptPowerKeyDown_intervalOutOfBoundsCameraPowerGestureOnNotInteractive()781     public void testInterceptPowerKeyDown_intervalOutOfBoundsCameraPowerGestureOnNotInteractive() {
782         withCameraDoubleTapPowerEnableConfigValue(true);
783         withCameraDoubleTapPowerDisableSettingValue(0);
784         mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
785 
786         long eventTime = INITIAL_EVENT_TIME_MILLIS;
787         KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
788                 IGNORED_REPEAT);
789         boolean interactive = false;
790         MutableBoolean outLaunched = new MutableBoolean(true);
791         boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
792                 outLaunched);
793         assertFalse(intercepted);
794         assertFalse(outLaunched.value);
795 
796         long interval = GestureLauncherService.POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS;
797         eventTime += interval;
798         keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
799                 IGNORED_REPEAT);
800         outLaunched.value = true;
801         intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
802                 outLaunched);
803         assertFalse(intercepted);
804         assertFalse(outLaunched.value);
805 
806         verify(mMetricsLogger, never())
807             .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
808 
809         final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
810         verify(mMetricsLogger, times(2)).histogram(
811                 eq("power_double_tap_interval"), intervalCaptor.capture());
812         List<Integer> intervals = intervalCaptor.getAllValues();
813         assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
814         assertEquals((int) interval, intervals.get(1).intValue());
815 
816         final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
817         verify(mMetricsLogger, times(2)).histogram(
818                 eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
819         List<Integer> tapCounts = tapCountCaptor.getAllValues();
820         assertEquals(1, tapCounts.get(0).intValue());
821         assertEquals(1, tapCounts.get(1).intValue());
822     }
823 
withCameraDoubleTapPowerEnableConfigValue(boolean enableConfigValue)824     private void withCameraDoubleTapPowerEnableConfigValue(boolean enableConfigValue) {
825         when(mResources.getBoolean(
826                 com.android.internal.R.bool.config_cameraDoubleTapPowerGestureEnabled))
827                 .thenReturn(enableConfigValue);
828     }
829 
withCameraDoubleTapPowerDisableSettingValue(int disableSettingValue)830     private void withCameraDoubleTapPowerDisableSettingValue(int disableSettingValue) {
831         Settings.Secure.putIntForUser(
832                 mContentResolver,
833                 Settings.Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED,
834                 disableSettingValue,
835                 UserHandle.USER_CURRENT);
836     }
837 
withUserSetupCompleteValue(boolean userSetupComplete)838     private void withUserSetupCompleteValue(boolean userSetupComplete) {
839         int userSetupCompleteValue = userSetupComplete ? 1 : 0;
840         Settings.Secure.putIntForUser(
841                 mContentResolver,
842                 Settings.Secure.USER_SETUP_COMPLETE,
843                 userSetupCompleteValue,
844                 UserHandle.USER_CURRENT);
845     }
846 }
847