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