Home | History | Annotate | Download | only in server
      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
     85     public static void oneTimeInitialization() {
     86         if (Looper.myLooper() == null) {
     87             Looper.prepare();
     88         }
     89     }
     90 
     91     @Before
     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
    109     public void testIsCameraDoubleTapPowerEnabled_configFalse() {
    110         withCameraDoubleTapPowerEnableConfigValue(false);
    111         assertFalse(mGestureLauncherService.isCameraDoubleTapPowerEnabled(mResources));
    112     }
    113 
    114     @Test
    115     public void testIsCameraDoubleTapPowerEnabled_configTrue() {
    116         withCameraDoubleTapPowerEnableConfigValue(true);
    117         assertTrue(mGestureLauncherService.isCameraDoubleTapPowerEnabled(mResources));
    118     }
    119 
    120     @Test
    121     public void testIsCameraDoubleTapPowerSettingEnabled_configFalseSettingDisabled() {
    122         withCameraDoubleTapPowerEnableConfigValue(false);
    123         withCameraDoubleTapPowerDisableSettingValue(1);
    124         assertFalse(mGestureLauncherService.isCameraDoubleTapPowerSettingEnabled(
    125                 mContext, FAKE_USER_ID));
    126     }
    127 
    128     @Test
    129     public void testIsCameraDoubleTapPowerSettingEnabled_configFalseSettingEnabled() {
    130         withCameraDoubleTapPowerEnableConfigValue(false);
    131         withCameraDoubleTapPowerDisableSettingValue(0);
    132         assertFalse(mGestureLauncherService.isCameraDoubleTapPowerSettingEnabled(
    133                 mContext, FAKE_USER_ID));
    134     }
    135 
    136     @Test
    137     public void testIsCameraDoubleTapPowerSettingEnabled_configTrueSettingDisabled() {
    138         withCameraDoubleTapPowerEnableConfigValue(true);
    139         withCameraDoubleTapPowerDisableSettingValue(1);
    140         assertFalse(mGestureLauncherService.isCameraDoubleTapPowerSettingEnabled(
    141                 mContext, FAKE_USER_ID));
    142     }
    143 
    144     @Test
    145     public void testIsCameraDoubleTapPowerSettingEnabled_configTrueSettingEnabled() {
    146         withCameraDoubleTapPowerEnableConfigValue(true);
    147         withCameraDoubleTapPowerDisableSettingValue(0);
    148         assertTrue(mGestureLauncherService.isCameraDoubleTapPowerSettingEnabled(
    149                 mContext, FAKE_USER_ID));
    150     }
    151 
    152     @Test
    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
    162     public void testHandleCameraLaunchGesture_userSetupNotComplete() {
    163         withUserSetupCompleteValue(false);
    164 
    165         boolean useWakeLock = false;
    166         assertFalse(mGestureLauncherService.handleCameraGesture(useWakeLock, FAKE_SOURCE));
    167     }
    168 
    169     @Test
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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 
    824     private void withCameraDoubleTapPowerEnableConfigValue(boolean enableConfigValue) {
    825         when(mResources.getBoolean(
    826                 com.android.internal.R.bool.config_cameraDoubleTapPowerGestureEnabled))
    827                 .thenReturn(enableConfigValue);
    828     }
    829 
    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 
    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