1 /* 2 * Copyright (C) 2015 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 android.app.ActivityManager; 20 import android.app.StatusBarManager; 21 import android.content.BroadcastReceiver; 22 import android.content.ComponentName; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.content.IntentFilter; 26 import android.content.pm.PackageManager; 27 import android.content.pm.ResolveInfo; 28 import android.content.res.Resources; 29 import android.database.ContentObserver; 30 import android.hardware.Sensor; 31 import android.hardware.SensorEvent; 32 import android.hardware.SensorEventListener; 33 import android.hardware.SensorManager; 34 import android.hardware.TriggerEvent; 35 import android.hardware.TriggerEventListener; 36 import android.os.Handler; 37 import android.os.PowerManager; 38 import android.os.PowerManager.WakeLock; 39 import android.os.SystemClock; 40 import android.os.SystemProperties; 41 import android.os.Trace; 42 import android.os.UserHandle; 43 import android.os.VibrationEffect; 44 import android.os.Vibrator; 45 import android.provider.Settings; 46 import android.util.MutableBoolean; 47 import android.util.Slog; 48 import android.view.KeyEvent; 49 50 import com.android.internal.annotations.VisibleForTesting; 51 import com.android.internal.logging.MetricsLogger; 52 import com.android.internal.logging.UiEvent; 53 import com.android.internal.logging.UiEventLogger; 54 import com.android.internal.logging.UiEventLoggerImpl; 55 import com.android.internal.logging.nano.MetricsProto.MetricsEvent; 56 import com.android.server.statusbar.StatusBarManagerInternal; 57 import com.android.server.wm.WindowManagerInternal; 58 59 /** 60 * The service that listens for gestures detected in sensor firmware and starts the intent 61 * accordingly. 62 * <p>For now, only camera launch gesture is supported, and in the future, more gestures can be 63 * added.</p> 64 * @hide 65 */ 66 public class GestureLauncherService extends SystemService { 67 private static final boolean DBG = false; 68 private static final boolean DBG_CAMERA_LIFT = false; 69 private static final String TAG = "GestureLauncherService"; 70 71 /** 72 * Time in milliseconds in which the power button must be pressed twice so it will be considered 73 * as a camera launch. 74 */ 75 @VisibleForTesting static final long CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS = 300; 76 77 /** 78 * Min time in milliseconds to complete the emergency gesture for it count. If the gesture is 79 * completed faster than this, we assume it's not performed by human and the 80 * event gets ignored. 81 */ 82 @VisibleForTesting static final int EMERGENCY_GESTURE_TAP_DETECTION_MIN_TIME_MS = 200; 83 84 /** 85 * Interval in milliseconds in which the power button must be depressed in succession to be 86 * considered part of an extended sequence of taps. Note that this is a looser threshold than 87 * the camera launch gesture, because the purpose of this threshold is to measure the 88 * frequency of consecutive taps, for evaluation for future gestures. 89 */ 90 @VisibleForTesting static final long POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS = 500; 91 92 /** 93 * Number of taps required to launch emergency gesture ui. 94 */ 95 private static final int EMERGENCY_GESTURE_POWER_TAP_COUNT_THRESHOLD = 5; 96 97 /** 98 * Default value of the power button "cooldown" period after the Emergency gesture is triggered. 99 * See {@link Settings.Global#EMERGENCY_GESTURE_POWER_BUTTON_COOLDOWN_PERIOD_MS} 100 */ 101 private static final int EMERGENCY_GESTURE_POWER_BUTTON_COOLDOWN_PERIOD_MS_DEFAULT = 3000; 102 103 /** 104 * Maximum value of the power button "cooldown" period after the Emergency gesture is triggered. 105 * The value read from {@link Settings.Global#EMERGENCY_GESTURE_POWER_BUTTON_COOLDOWN_PERIOD_MS} 106 * is capped at this maximum. 107 */ 108 @VisibleForTesting 109 static final int EMERGENCY_GESTURE_POWER_BUTTON_COOLDOWN_PERIOD_MS_MAX = 5000; 110 111 /** 112 * Number of taps required to launch camera shortcut. 113 */ 114 private static final int CAMERA_POWER_TAP_COUNT_THRESHOLD = 2; 115 116 /** Action for starting emergency alerts on Wear OS. */ 117 private static final String WEAR_LAUNCH_EMERGENCY_ACTION = 118 "com.android.systemui.action.LAUNCH_EMERGENCY"; 119 120 /** Action for starting emergency alerts in retail mode on Wear OS. */ 121 private static final String WEAR_LAUNCH_EMERGENCY_RETAIL_ACTION = 122 "com.android.systemui.action.LAUNCH_EMERGENCY_RETAIL"; 123 124 /** 125 * Boolean extra for distinguishing intents coming from power button gesture. 126 */ 127 private static final String EXTRA_LAUNCH_EMERGENCY_VIA_GESTURE = "launch_emergency_via_gesture"; 128 129 /** The listener that receives the gesture event. */ 130 private final GestureEventListener mGestureListener = new GestureEventListener(); 131 private final CameraLiftTriggerEventListener mCameraLiftTriggerListener = 132 new CameraLiftTriggerEventListener(); 133 134 private Sensor mCameraLaunchSensor; 135 private Sensor mCameraLiftTriggerSensor; 136 private Context mContext; 137 private final MetricsLogger mMetricsLogger; 138 private PowerManager mPowerManager; 139 private WindowManagerInternal mWindowManagerInternal; 140 141 /** The wake lock held when a gesture is detected. */ 142 private WakeLock mWakeLock; 143 private boolean mCameraLaunchRegistered; 144 private boolean mCameraLiftRegistered; 145 private int mUserId; 146 147 // Below are fields used for event logging only. 148 /** Elapsed real time when the camera gesture is turned on. */ 149 private long mCameraGestureOnTimeMs = 0L; 150 151 /** Elapsed real time when the last camera gesture was detected. */ 152 private long mCameraGestureLastEventTime = 0L; 153 154 /** 155 * How long the sensor 1 has been turned on since camera launch sensor was 156 * subscribed to and when the last camera launch gesture was detected. 157 * <p>Sensor 1 is the main sensor used to detect camera launch gesture.</p> 158 */ 159 private long mCameraGestureSensor1LastOnTimeMs = 0L; 160 161 /** 162 * If applicable, how long the sensor 2 has been turned on since camera 163 * launch sensor was subscribed to and when the last camera launch 164 * gesture was detected. 165 * <p>Sensor 2 is the secondary sensor used to detect camera launch gesture. 166 * This is optional and if only sensor 1 is used for detect camera launch 167 * gesture, this value would always be 0.</p> 168 */ 169 private long mCameraGestureSensor2LastOnTimeMs = 0L; 170 171 /** 172 * Extra information about the event when the last camera launch gesture 173 * was detected. 174 */ 175 private int mCameraLaunchLastEventExtra = 0; 176 177 /** 178 * Whether camera double tap power button gesture is currently enabled; 179 */ 180 private boolean mCameraDoubleTapPowerEnabled; 181 182 /** 183 * Whether emergency gesture is currently enabled 184 */ 185 private boolean mEmergencyGestureEnabled; 186 187 /** 188 * Power button cooldown period in milliseconds, after emergency gesture is triggered. A zero 189 * value means the cooldown period is disabled. 190 */ 191 private int mEmergencyGesturePowerButtonCooldownPeriodMs; 192 193 private long mLastPowerDown; 194 private long mFirstPowerDown; 195 private long mLastEmergencyGestureTriggered; 196 private int mPowerButtonConsecutiveTaps; 197 private int mPowerButtonSlowConsecutiveTaps; 198 private final UiEventLogger mUiEventLogger; 199 200 private boolean mHasFeatureWatch; 201 private long mVibrateMilliSecondsForPanicGesture; 202 203 @VisibleForTesting 204 public enum GestureLauncherEvent implements UiEventLogger.UiEventEnum { 205 @UiEvent(doc = "The user lifted the device just the right way to launch the camera.") 206 GESTURE_CAMERA_LIFT(658), 207 208 @UiEvent(doc = "The user wiggled the device just the right way to launch the camera.") 209 GESTURE_CAMERA_WIGGLE(659), 210 211 @UiEvent(doc = "The user double-tapped power quickly enough to launch the camera.") 212 GESTURE_CAMERA_DOUBLE_TAP_POWER(660), 213 214 @UiEvent(doc = "The user multi-tapped power quickly enough to signal an emergency.") 215 GESTURE_EMERGENCY_TAP_POWER(661); 216 217 private final int mId; 218 GestureLauncherEvent(int id)219 GestureLauncherEvent(int id) { 220 mId = id; 221 } 222 223 @Override getId()224 public int getId() { 225 return mId; 226 } 227 } GestureLauncherService(Context context)228 public GestureLauncherService(Context context) { 229 this(context, new MetricsLogger(), new UiEventLoggerImpl()); 230 } 231 232 @VisibleForTesting GestureLauncherService(Context context, MetricsLogger metricsLogger, UiEventLogger uiEventLogger)233 GestureLauncherService(Context context, MetricsLogger metricsLogger, 234 UiEventLogger uiEventLogger) { 235 super(context); 236 mContext = context; 237 mMetricsLogger = metricsLogger; 238 mUiEventLogger = uiEventLogger; 239 } 240 241 @Override onStart()242 public void onStart() { 243 LocalServices.addService(GestureLauncherService.class, this); 244 } 245 246 @Override onBootPhase(int phase)247 public void onBootPhase(int phase) { 248 if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) { 249 Resources resources = mContext.getResources(); 250 if (!isGestureLauncherEnabled(resources)) { 251 if (DBG) Slog.d(TAG, "Gesture launcher is disabled in system properties."); 252 return; 253 } 254 255 mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class); 256 mPowerManager = (PowerManager) mContext.getSystemService( 257 Context.POWER_SERVICE); 258 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, 259 "GestureLauncherService"); 260 updateCameraRegistered(); 261 updateCameraDoubleTapPowerEnabled(); 262 updateEmergencyGestureEnabled(); 263 updateEmergencyGesturePowerButtonCooldownPeriodMs(); 264 265 mUserId = ActivityManager.getCurrentUser(); 266 mContext.registerReceiver(mUserReceiver, new IntentFilter(Intent.ACTION_USER_SWITCHED)); 267 registerContentObservers(); 268 269 mHasFeatureWatch = 270 mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH); 271 mVibrateMilliSecondsForPanicGesture = 272 resources.getInteger( 273 com.android 274 .internal 275 .R 276 .integer 277 .config_mashPressVibrateTimeOnPowerButton); 278 } 279 } 280 registerContentObservers()281 private void registerContentObservers() { 282 mContext.getContentResolver().registerContentObserver( 283 Settings.Secure.getUriFor(Settings.Secure.CAMERA_GESTURE_DISABLED), 284 false, mSettingObserver, mUserId); 285 mContext.getContentResolver().registerContentObserver( 286 Settings.Secure.getUriFor(Settings.Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED), 287 false, mSettingObserver, mUserId); 288 mContext.getContentResolver().registerContentObserver( 289 Settings.Secure.getUriFor(Settings.Secure.CAMERA_LIFT_TRIGGER_ENABLED), 290 false, mSettingObserver, mUserId); 291 mContext.getContentResolver().registerContentObserver( 292 Settings.Secure.getUriFor(Settings.Secure.EMERGENCY_GESTURE_ENABLED), 293 false, mSettingObserver, mUserId); 294 mContext.getContentResolver().registerContentObserver( 295 Settings.Global.getUriFor( 296 Settings.Global.EMERGENCY_GESTURE_POWER_BUTTON_COOLDOWN_PERIOD_MS), 297 false, mSettingObserver, mUserId); 298 } 299 updateCameraRegistered()300 private void updateCameraRegistered() { 301 Resources resources = mContext.getResources(); 302 if (isCameraLaunchSettingEnabled(mContext, mUserId)) { 303 registerCameraLaunchGesture(resources); 304 } else { 305 unregisterCameraLaunchGesture(); 306 } 307 308 if (isCameraLiftTriggerSettingEnabled(mContext, mUserId)) { 309 registerCameraLiftTrigger(resources); 310 } else { 311 unregisterCameraLiftTrigger(); 312 } 313 } 314 315 @VisibleForTesting updateCameraDoubleTapPowerEnabled()316 void updateCameraDoubleTapPowerEnabled() { 317 boolean enabled = isCameraDoubleTapPowerSettingEnabled(mContext, mUserId); 318 synchronized (this) { 319 mCameraDoubleTapPowerEnabled = enabled; 320 } 321 } 322 323 @VisibleForTesting updateEmergencyGestureEnabled()324 void updateEmergencyGestureEnabled() { 325 boolean enabled = isEmergencyGestureSettingEnabled(mContext, mUserId); 326 synchronized (this) { 327 mEmergencyGestureEnabled = enabled; 328 } 329 } 330 331 @VisibleForTesting updateEmergencyGesturePowerButtonCooldownPeriodMs()332 void updateEmergencyGesturePowerButtonCooldownPeriodMs() { 333 int cooldownPeriodMs = getEmergencyGesturePowerButtonCooldownPeriodMs(mContext, mUserId); 334 synchronized (this) { 335 mEmergencyGesturePowerButtonCooldownPeriodMs = cooldownPeriodMs; 336 } 337 } 338 unregisterCameraLaunchGesture()339 private void unregisterCameraLaunchGesture() { 340 if (mCameraLaunchRegistered) { 341 mCameraLaunchRegistered = false; 342 mCameraGestureOnTimeMs = 0L; 343 mCameraGestureLastEventTime = 0L; 344 mCameraGestureSensor1LastOnTimeMs = 0; 345 mCameraGestureSensor2LastOnTimeMs = 0; 346 mCameraLaunchLastEventExtra = 0; 347 348 SensorManager sensorManager = (SensorManager) mContext.getSystemService( 349 Context.SENSOR_SERVICE); 350 sensorManager.unregisterListener(mGestureListener); 351 } 352 } 353 354 /** 355 * Registers for the camera launch gesture. 356 */ registerCameraLaunchGesture(Resources resources)357 private void registerCameraLaunchGesture(Resources resources) { 358 if (mCameraLaunchRegistered) { 359 return; 360 } 361 mCameraGestureOnTimeMs = SystemClock.elapsedRealtime(); 362 mCameraGestureLastEventTime = mCameraGestureOnTimeMs; 363 SensorManager sensorManager = (SensorManager) mContext.getSystemService( 364 Context.SENSOR_SERVICE); 365 int cameraLaunchGestureId = resources.getInteger( 366 com.android.internal.R.integer.config_cameraLaunchGestureSensorType); 367 if (cameraLaunchGestureId != -1) { 368 mCameraLaunchRegistered = false; 369 String sensorName = resources.getString( 370 com.android.internal.R.string.config_cameraLaunchGestureSensorStringType); 371 mCameraLaunchSensor = sensorManager.getDefaultSensor( 372 cameraLaunchGestureId, 373 true /*wakeUp*/); 374 375 // Compare the camera gesture string type to that in the resource file to make 376 // sure we are registering the correct sensor. This is redundant check, it 377 // makes the code more robust. 378 if (mCameraLaunchSensor != null) { 379 if (sensorName.equals(mCameraLaunchSensor.getStringType())) { 380 mCameraLaunchRegistered = sensorManager.registerListener(mGestureListener, 381 mCameraLaunchSensor, 0); 382 } else { 383 String message = String.format("Wrong configuration. Sensor type and sensor " 384 + "string type don't match: %s in resources, %s in the sensor.", 385 sensorName, mCameraLaunchSensor.getStringType()); 386 throw new RuntimeException(message); 387 } 388 } 389 if (DBG) Slog.d(TAG, "Camera launch sensor registered: " + mCameraLaunchRegistered); 390 } else { 391 if (DBG) Slog.d(TAG, "Camera launch sensor is not specified."); 392 } 393 } 394 unregisterCameraLiftTrigger()395 private void unregisterCameraLiftTrigger() { 396 if (mCameraLiftRegistered) { 397 mCameraLiftRegistered = false; 398 399 SensorManager sensorManager = (SensorManager) mContext.getSystemService( 400 Context.SENSOR_SERVICE); 401 sensorManager.cancelTriggerSensor(mCameraLiftTriggerListener, mCameraLiftTriggerSensor); 402 } 403 } 404 405 /** 406 * Registers for the camera lift trigger. 407 */ registerCameraLiftTrigger(Resources resources)408 private void registerCameraLiftTrigger(Resources resources) { 409 if (mCameraLiftRegistered) { 410 return; 411 } 412 SensorManager sensorManager = (SensorManager) mContext.getSystemService( 413 Context.SENSOR_SERVICE); 414 int cameraLiftTriggerId = resources.getInteger( 415 com.android.internal.R.integer.config_cameraLiftTriggerSensorType); 416 if (cameraLiftTriggerId != -1) { 417 mCameraLiftRegistered = false; 418 String sensorName = resources.getString( 419 com.android.internal.R.string.config_cameraLiftTriggerSensorStringType); 420 mCameraLiftTriggerSensor = sensorManager.getDefaultSensor( 421 cameraLiftTriggerId, 422 true /*wakeUp*/); 423 424 // Compare the camera lift trigger string type to that in the resource file to make 425 // sure we are registering the correct sensor. This is redundant check, it 426 // makes the code more robust. 427 if (mCameraLiftTriggerSensor != null) { 428 if (sensorName.equals(mCameraLiftTriggerSensor.getStringType())) { 429 mCameraLiftRegistered = sensorManager.requestTriggerSensor(mCameraLiftTriggerListener, 430 mCameraLiftTriggerSensor); 431 } else { 432 String message = String.format("Wrong configuration. Sensor type and sensor " 433 + "string type don't match: %s in resources, %s in the sensor.", 434 sensorName, mCameraLiftTriggerSensor.getStringType()); 435 throw new RuntimeException(message); 436 } 437 } 438 if (DBG) Slog.d(TAG, "Camera lift trigger sensor registered: " + mCameraLiftRegistered); 439 } else { 440 if (DBG) Slog.d(TAG, "Camera lift trigger sensor is not specified."); 441 } 442 } 443 isCameraLaunchSettingEnabled(Context context, int userId)444 public static boolean isCameraLaunchSettingEnabled(Context context, int userId) { 445 return isCameraLaunchEnabled(context.getResources()) 446 && (Settings.Secure.getIntForUser(context.getContentResolver(), 447 Settings.Secure.CAMERA_GESTURE_DISABLED, 0, userId) == 0); 448 } 449 isCameraDoubleTapPowerSettingEnabled(Context context, int userId)450 public static boolean isCameraDoubleTapPowerSettingEnabled(Context context, int userId) { 451 return isCameraDoubleTapPowerEnabled(context.getResources()) 452 && (Settings.Secure.getIntForUser(context.getContentResolver(), 453 Settings.Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED, 0, userId) == 0); 454 } 455 isCameraLiftTriggerSettingEnabled(Context context, int userId)456 public static boolean isCameraLiftTriggerSettingEnabled(Context context, int userId) { 457 return isCameraLiftTriggerEnabled(context.getResources()) 458 && (Settings.Secure.getIntForUser(context.getContentResolver(), 459 Settings.Secure.CAMERA_LIFT_TRIGGER_ENABLED, 460 Settings.Secure.CAMERA_LIFT_TRIGGER_ENABLED_DEFAULT, userId) != 0); 461 } 462 463 /** 464 * Whether to enable emergency gesture. 465 */ isEmergencyGestureSettingEnabled(Context context, int userId)466 public static boolean isEmergencyGestureSettingEnabled(Context context, int userId) { 467 return isEmergencyGestureEnabled(context.getResources()) 468 && Settings.Secure.getIntForUser(context.getContentResolver(), 469 Settings.Secure.EMERGENCY_GESTURE_ENABLED, 470 isDefaultEmergencyGestureEnabled(context.getResources()) ? 1 : 0, userId) != 0; 471 } 472 473 /** 474 * Gets power button cooldown period in milliseconds after emergency gesture is triggered. The 475 * value is capped at a maximum 476 * {@link GestureLauncherService#EMERGENCY_GESTURE_POWER_BUTTON_COOLDOWN_PERIOD_MS_MAX}. If the 477 * value is zero, it means the cooldown period is disabled. 478 */ 479 @VisibleForTesting getEmergencyGesturePowerButtonCooldownPeriodMs(Context context, int userId)480 static int getEmergencyGesturePowerButtonCooldownPeriodMs(Context context, int userId) { 481 int cooldown = Settings.Global.getInt(context.getContentResolver(), 482 Settings.Global.EMERGENCY_GESTURE_POWER_BUTTON_COOLDOWN_PERIOD_MS, 483 EMERGENCY_GESTURE_POWER_BUTTON_COOLDOWN_PERIOD_MS_DEFAULT); 484 485 return Math.min(cooldown, EMERGENCY_GESTURE_POWER_BUTTON_COOLDOWN_PERIOD_MS_MAX); 486 } 487 488 /** 489 * Whether to enable the camera launch gesture. 490 */ isCameraLaunchEnabled(Resources resources)491 private static boolean isCameraLaunchEnabled(Resources resources) { 492 boolean configSet = resources.getInteger( 493 com.android.internal.R.integer.config_cameraLaunchGestureSensorType) != -1; 494 return configSet && 495 !SystemProperties.getBoolean("gesture.disable_camera_launch", false); 496 } 497 498 @VisibleForTesting isCameraDoubleTapPowerEnabled(Resources resources)499 static boolean isCameraDoubleTapPowerEnabled(Resources resources) { 500 return resources.getBoolean( 501 com.android.internal.R.bool.config_cameraDoubleTapPowerGestureEnabled); 502 } 503 isCameraLiftTriggerEnabled(Resources resources)504 private static boolean isCameraLiftTriggerEnabled(Resources resources) { 505 boolean configSet = resources.getInteger( 506 com.android.internal.R.integer.config_cameraLiftTriggerSensorType) != -1; 507 return configSet; 508 } 509 510 /** 511 * Whether or not the emergency gesture feature is enabled by platform 512 */ isEmergencyGestureEnabled(Resources resources)513 private static boolean isEmergencyGestureEnabled(Resources resources) { 514 return resources.getBoolean(com.android.internal.R.bool.config_emergencyGestureEnabled); 515 } 516 isDefaultEmergencyGestureEnabled(Resources resources)517 private static boolean isDefaultEmergencyGestureEnabled(Resources resources) { 518 return resources.getBoolean( 519 com.android.internal.R.bool.config_defaultEmergencyGestureEnabled); 520 } 521 522 /** 523 * Whether GestureLauncherService should be enabled according to system properties. 524 */ isGestureLauncherEnabled(Resources resources)525 public static boolean isGestureLauncherEnabled(Resources resources) { 526 return isCameraLaunchEnabled(resources) 527 || isCameraDoubleTapPowerEnabled(resources) 528 || isCameraLiftTriggerEnabled(resources) 529 || isEmergencyGestureEnabled(resources); 530 } 531 532 /** 533 * Attempts to intercept power key down event by detecting certain gesture patterns 534 * 535 * @param interactive true if the event's policy contains {@code FLAG_INTERACTIVE} 536 * @param outLaunched true if some action is taken as part of the key intercept (eg, app launch) 537 * @return true if the key down event is intercepted 538 */ interceptPowerKeyDown(KeyEvent event, boolean interactive, MutableBoolean outLaunched)539 public boolean interceptPowerKeyDown(KeyEvent event, boolean interactive, 540 MutableBoolean outLaunched) { 541 if (mEmergencyGestureEnabled && mEmergencyGesturePowerButtonCooldownPeriodMs >= 0 542 && event.getEventTime() - mLastEmergencyGestureTriggered 543 < mEmergencyGesturePowerButtonCooldownPeriodMs) { 544 Slog.i(TAG, String.format( 545 "Suppressing power button: within %dms cooldown period after Emergency " 546 + "Gesture. Begin=%dms, end=%dms.", 547 mEmergencyGesturePowerButtonCooldownPeriodMs, 548 mLastEmergencyGestureTriggered, 549 mLastEmergencyGestureTriggered + mEmergencyGesturePowerButtonCooldownPeriodMs)); 550 outLaunched.value = false; 551 return true; 552 } 553 554 if (event.isLongPress()) { 555 // Long presses are sent as a second key down. If the long press threshold is set lower 556 // than the double tap of sequence interval thresholds, this could cause false double 557 // taps or consecutive taps, so we want to ignore the long press event. 558 outLaunched.value = false; 559 return false; 560 } 561 boolean launchCamera = false; 562 boolean launchEmergencyGesture = false; 563 boolean intercept = false; 564 long powerTapInterval; 565 synchronized (this) { 566 powerTapInterval = event.getEventTime() - mLastPowerDown; 567 mLastPowerDown = event.getEventTime(); 568 if (powerTapInterval >= POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS) { 569 // Tap too slow, reset consecutive tap counts. 570 mFirstPowerDown = event.getEventTime(); 571 mPowerButtonConsecutiveTaps = 1; 572 mPowerButtonSlowConsecutiveTaps = 1; 573 } else if (powerTapInterval >= CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS) { 574 // Tap too slow for shortcuts 575 mFirstPowerDown = event.getEventTime(); 576 mPowerButtonConsecutiveTaps = 1; 577 mPowerButtonSlowConsecutiveTaps++; 578 } else { 579 // Fast consecutive tap 580 mPowerButtonConsecutiveTaps++; 581 mPowerButtonSlowConsecutiveTaps++; 582 } 583 // Check if we need to launch camera or emergency gesture flows 584 if (mEmergencyGestureEnabled) { 585 // Commit to intercepting the powerkey event after the second "quick" tap to avoid 586 // lockscreen changes between launching camera and the emergency gesture flow. 587 // Since watch doesn't have camera gesture, only intercept power key event after 588 // emergency gesture tap count. 589 if (mPowerButtonConsecutiveTaps 590 > (mHasFeatureWatch ? EMERGENCY_GESTURE_POWER_TAP_COUNT_THRESHOLD : 1)) { 591 intercept = interactive; 592 } 593 if (mPowerButtonConsecutiveTaps == EMERGENCY_GESTURE_POWER_TAP_COUNT_THRESHOLD) { 594 long emergencyGestureSpentTime = event.getEventTime() - mFirstPowerDown; 595 long emergencyGestureTapDetectionMinTimeMs = Settings.Global.getInt( 596 mContext.getContentResolver(), 597 Settings.Global.EMERGENCY_GESTURE_TAP_DETECTION_MIN_TIME_MS, 598 EMERGENCY_GESTURE_TAP_DETECTION_MIN_TIME_MS); 599 if (emergencyGestureSpentTime <= emergencyGestureTapDetectionMinTimeMs) { 600 Slog.i(TAG, "Emergency gesture detected but it's too fast. Gesture time: " 601 + emergencyGestureSpentTime + " ms"); 602 // Reset consecutive tap counts. 603 mFirstPowerDown = event.getEventTime(); 604 mPowerButtonConsecutiveTaps = 1; 605 mPowerButtonSlowConsecutiveTaps = 1; 606 } else { 607 Slog.i(TAG, "Emergency gesture detected. Gesture time: " 608 + emergencyGestureSpentTime + " ms"); 609 launchEmergencyGesture = true; 610 mMetricsLogger.histogram("emergency_gesture_spent_time", 611 (int) emergencyGestureSpentTime); 612 613 } 614 } 615 } 616 if (mCameraDoubleTapPowerEnabled 617 && powerTapInterval < CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS 618 && mPowerButtonConsecutiveTaps == CAMERA_POWER_TAP_COUNT_THRESHOLD) { 619 launchCamera = true; 620 intercept = interactive; 621 } 622 } 623 if (mPowerButtonConsecutiveTaps > 1 || mPowerButtonSlowConsecutiveTaps > 1) { 624 Slog.i(TAG, Long.valueOf(mPowerButtonConsecutiveTaps) 625 + " consecutive power button taps detected, " 626 + Long.valueOf(mPowerButtonSlowConsecutiveTaps) 627 + " consecutive slow power button taps detected"); 628 } 629 if (launchCamera) { 630 Slog.i(TAG, "Power button double tap gesture detected, launching camera. Interval=" 631 + powerTapInterval + "ms"); 632 launchCamera = handleCameraGesture(false /* useWakelock */, 633 StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP); 634 if (launchCamera) { 635 mMetricsLogger.action(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE, 636 (int) powerTapInterval); 637 mUiEventLogger.log(GestureLauncherEvent.GESTURE_CAMERA_DOUBLE_TAP_POWER); 638 } 639 } else if (launchEmergencyGesture) { 640 Slog.i(TAG, "Emergency gesture detected, launching."); 641 launchEmergencyGesture = handleEmergencyGesture(); 642 mUiEventLogger.log(GestureLauncherEvent.GESTURE_EMERGENCY_TAP_POWER); 643 // Record emergency trigger time if emergency UI was launched 644 if (launchEmergencyGesture) { 645 synchronized (this) { 646 mLastEmergencyGestureTriggered = event.getEventTime(); 647 } 648 } 649 } 650 mMetricsLogger.histogram("power_consecutive_short_tap_count", 651 mPowerButtonSlowConsecutiveTaps); 652 mMetricsLogger.histogram("power_double_tap_interval", (int) powerTapInterval); 653 654 outLaunched.value = launchCamera || launchEmergencyGesture; 655 // Intercept power key event if the press is part of a gesture (camera, eGesture) and the 656 // user has completed setup. 657 return intercept && isUserSetupComplete(); 658 } 659 /** 660 * @return true if camera was launched, false otherwise. 661 */ 662 @VisibleForTesting handleCameraGesture(boolean useWakelock, int source)663 boolean handleCameraGesture(boolean useWakelock, int source) { 664 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "GestureLauncher:handleCameraGesture"); 665 try { 666 boolean userSetupComplete = isUserSetupComplete(); 667 if (!userSetupComplete) { 668 if (DBG) { 669 Slog.d(TAG, String.format( 670 "userSetupComplete = %s, ignoring camera gesture.", 671 userSetupComplete)); 672 } 673 return false; 674 } 675 if (DBG) { 676 Slog.d(TAG, String.format( 677 "userSetupComplete = %s, performing camera gesture.", 678 userSetupComplete)); 679 } 680 681 if (useWakelock) { 682 // Make sure we don't sleep too early 683 mWakeLock.acquire(500L); 684 } 685 StatusBarManagerInternal service = LocalServices.getService( 686 StatusBarManagerInternal.class); 687 service.onCameraLaunchGestureDetected(source); 688 return true; 689 } finally { 690 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); 691 } 692 } 693 694 /** 695 * @return true if emergency gesture UI was launched, false otherwise. 696 */ 697 @VisibleForTesting handleEmergencyGesture()698 boolean handleEmergencyGesture() { 699 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, 700 "GestureLauncher:handleEmergencyGesture"); 701 try { 702 boolean userSetupComplete = isUserSetupComplete(); 703 if (!userSetupComplete) { 704 if (DBG) { 705 Slog.d(TAG, String.format( 706 "userSetupComplete = %s, ignoring emergency gesture.", 707 userSetupComplete)); 708 } 709 return false; 710 } 711 if (DBG) { 712 Slog.d(TAG, String.format( 713 "userSetupComplete = %s, performing emergency gesture.", 714 userSetupComplete)); 715 } 716 717 if (mHasFeatureWatch) { 718 onEmergencyGestureDetectedOnWatch(); 719 return true; 720 } 721 722 StatusBarManagerInternal service = LocalServices.getService( 723 StatusBarManagerInternal.class); 724 service.onEmergencyActionLaunchGestureDetected(); 725 return true; 726 } finally { 727 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); 728 } 729 } 730 onEmergencyGestureDetectedOnWatch()731 private void onEmergencyGestureDetectedOnWatch() { 732 Intent emergencyIntent = 733 new Intent( 734 isInRetailMode() 735 ? WEAR_LAUNCH_EMERGENCY_RETAIL_ACTION 736 : WEAR_LAUNCH_EMERGENCY_ACTION); 737 PackageManager pm = mContext.getPackageManager(); 738 ResolveInfo resolveInfo = pm.resolveActivity(emergencyIntent, /*flags=*/0); 739 if (resolveInfo == null) { 740 Slog.w(TAG, "Couldn't find an app to process the emergency intent " 741 + emergencyIntent.getAction()); 742 return; 743 } 744 745 Vibrator vibrator = mContext.getSystemService(Vibrator.class); 746 vibrator.vibrate(VibrationEffect.createOneShot(mVibrateMilliSecondsForPanicGesture, 747 VibrationEffect.DEFAULT_AMPLITUDE)); 748 749 emergencyIntent.setComponent( 750 new ComponentName( 751 resolveInfo.activityInfo.packageName, resolveInfo.activityInfo.name)); 752 emergencyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 753 emergencyIntent.putExtra(EXTRA_LAUNCH_EMERGENCY_VIA_GESTURE, true); 754 mContext.startActivityAsUser(emergencyIntent, new UserHandle(mUserId)); 755 } 756 isInRetailMode()757 private boolean isInRetailMode() { 758 return Settings.Global.getInt(mContext.getContentResolver(), 759 Settings.Global.DEVICE_DEMO_MODE, 0) == 1; 760 } 761 isUserSetupComplete()762 private boolean isUserSetupComplete() { 763 return Settings.Secure.getIntForUser(mContext.getContentResolver(), 764 Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0; 765 } 766 767 private final BroadcastReceiver mUserReceiver = new BroadcastReceiver() { 768 @Override 769 public void onReceive(Context context, Intent intent) { 770 if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) { 771 mUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0); 772 mContext.getContentResolver().unregisterContentObserver(mSettingObserver); 773 registerContentObservers(); 774 updateCameraRegistered(); 775 updateCameraDoubleTapPowerEnabled(); 776 updateEmergencyGestureEnabled(); 777 updateEmergencyGesturePowerButtonCooldownPeriodMs(); 778 } 779 } 780 }; 781 782 private final ContentObserver mSettingObserver = new ContentObserver(new Handler()) { 783 public void onChange(boolean selfChange, android.net.Uri uri, int userId) { 784 if (userId == mUserId) { 785 updateCameraRegistered(); 786 updateCameraDoubleTapPowerEnabled(); 787 updateEmergencyGestureEnabled(); 788 updateEmergencyGesturePowerButtonCooldownPeriodMs(); 789 } 790 } 791 }; 792 793 private final class GestureEventListener implements SensorEventListener { 794 @Override onSensorChanged(SensorEvent event)795 public void onSensorChanged(SensorEvent event) { 796 if (!mCameraLaunchRegistered) { 797 if (DBG) Slog.d(TAG, "Ignoring gesture event because it's unregistered."); 798 return; 799 } 800 if (event.sensor == mCameraLaunchSensor) { 801 if (DBG) { 802 float[] values = event.values; 803 Slog.d(TAG, String.format("Received a camera launch event: " + 804 "values=[%.4f, %.4f, %.4f].", values[0], values[1], values[2])); 805 } 806 if (handleCameraGesture(true /* useWakelock */, 807 StatusBarManager.CAMERA_LAUNCH_SOURCE_WIGGLE)) { 808 mMetricsLogger.action(MetricsEvent.ACTION_WIGGLE_CAMERA_GESTURE); 809 mUiEventLogger.log(GestureLauncherEvent.GESTURE_CAMERA_WIGGLE); 810 trackCameraLaunchEvent(event); 811 } 812 return; 813 } 814 } 815 816 @Override onAccuracyChanged(Sensor sensor, int accuracy)817 public void onAccuracyChanged(Sensor sensor, int accuracy) { 818 // Ignored. 819 } 820 trackCameraLaunchEvent(SensorEvent event)821 private void trackCameraLaunchEvent(SensorEvent event) { 822 long now = SystemClock.elapsedRealtime(); 823 long totalDuration = now - mCameraGestureOnTimeMs; 824 // values[0]: ratio between total time duration when accel is turned on and time 825 // duration since camera launch gesture is subscribed. 826 // values[1]: ratio between total time duration when gyro is turned on and time duration 827 // since camera launch gesture is subscribed. 828 // values[2]: extra information 829 float[] values = event.values; 830 831 long sensor1OnTime = (long) (totalDuration * (double) values[0]); 832 long sensor2OnTime = (long) (totalDuration * (double) values[1]); 833 int extra = (int) values[2]; 834 835 // We only log the difference in the event log to make aggregation easier. 836 long gestureOnTimeDiff = now - mCameraGestureLastEventTime; 837 long sensor1OnTimeDiff = sensor1OnTime - mCameraGestureSensor1LastOnTimeMs; 838 long sensor2OnTimeDiff = sensor2OnTime - mCameraGestureSensor2LastOnTimeMs; 839 int extraDiff = extra - mCameraLaunchLastEventExtra; 840 841 // Gating against negative time difference. This doesn't usually happen, but it may 842 // happen because of numeric errors. 843 if (gestureOnTimeDiff < 0 || sensor1OnTimeDiff < 0 || sensor2OnTimeDiff < 0) { 844 if (DBG) Slog.d(TAG, "Skipped event logging because negative numbers."); 845 return; 846 } 847 848 if (DBG) Slog.d(TAG, String.format("totalDuration: %d, sensor1OnTime: %s, " + 849 "sensor2OnTime: %d, extra: %d", 850 gestureOnTimeDiff, 851 sensor1OnTimeDiff, 852 sensor2OnTimeDiff, 853 extraDiff)); 854 EventLogTags.writeCameraGestureTriggered( 855 gestureOnTimeDiff, 856 sensor1OnTimeDiff, 857 sensor2OnTimeDiff, 858 extraDiff); 859 860 mCameraGestureLastEventTime = now; 861 mCameraGestureSensor1LastOnTimeMs = sensor1OnTime; 862 mCameraGestureSensor2LastOnTimeMs = sensor2OnTime; 863 mCameraLaunchLastEventExtra = extra; 864 } 865 } 866 867 private final class CameraLiftTriggerEventListener extends TriggerEventListener { 868 @Override onTrigger(TriggerEvent event)869 public void onTrigger(TriggerEvent event) { 870 if (DBG_CAMERA_LIFT) Slog.d(TAG, String.format("onTrigger event - time: %d, name: %s", 871 event.timestamp, event.sensor.getName())); 872 if (!mCameraLiftRegistered) { 873 if (DBG_CAMERA_LIFT) Slog.d(TAG, "Ignoring camera lift event because it's " + 874 "unregistered."); 875 return; 876 } 877 if (event.sensor == mCameraLiftTriggerSensor) { 878 Resources resources = mContext.getResources(); 879 SensorManager sensorManager = (SensorManager) mContext.getSystemService( 880 Context.SENSOR_SERVICE); 881 boolean keyguardShowingAndNotOccluded = 882 mWindowManagerInternal.isKeyguardShowingAndNotOccluded(); 883 boolean interactive = mPowerManager.isInteractive(); 884 if (DBG_CAMERA_LIFT) { 885 float[] values = event.values; 886 Slog.d(TAG, String.format("Received a camera lift trigger " + 887 "event: values=[%.4f], keyguard showing: %b, interactive: %b", values[0], 888 keyguardShowingAndNotOccluded, interactive)); 889 } 890 if (keyguardShowingAndNotOccluded || !interactive) { 891 if (handleCameraGesture(true /* useWakelock */, 892 StatusBarManager.CAMERA_LAUNCH_SOURCE_LIFT_TRIGGER)) { 893 MetricsLogger.action(mContext, MetricsEvent.ACTION_CAMERA_LIFT_TRIGGER); 894 mUiEventLogger.log(GestureLauncherEvent.GESTURE_CAMERA_LIFT); 895 } 896 } else { 897 if (DBG_CAMERA_LIFT) Slog.d(TAG, "Ignoring lift event"); 898 } 899 900 mCameraLiftRegistered = sensorManager.requestTriggerSensor( 901 mCameraLiftTriggerListener, mCameraLiftTriggerSensor); 902 903 if (DBG_CAMERA_LIFT) Slog.d(TAG, "Camera lift trigger sensor re-registered: " + 904 mCameraLiftRegistered); 905 return; 906 } 907 } 908 } 909 } 910