1 /* 2 * Copyright 2024 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.input; 18 19 import static android.content.pm.PackageManager.FEATURE_LEANBACK; 20 import static android.content.pm.PackageManager.FEATURE_WATCH; 21 import static android.os.UserManager.isVisibleBackgroundUsersEnabled; 22 import static android.view.Display.DEFAULT_DISPLAY; 23 import static android.view.WindowManagerPolicyConstants.FLAG_INTERACTIVE; 24 25 import static com.android.hardware.input.Flags.enableNew25q2Keycodes; 26 27 import android.annotation.BinderThread; 28 import android.annotation.MainThread; 29 import android.annotation.NonNull; 30 import android.annotation.Nullable; 31 import android.annotation.SuppressLint; 32 import android.annotation.UserIdInt; 33 import android.content.ContentResolver; 34 import android.content.Context; 35 import android.content.pm.PackageManager; 36 import android.content.res.Resources; 37 import android.database.ContentObserver; 38 import android.hardware.display.DisplayManager; 39 import android.hardware.input.AidlInputGestureData; 40 import android.hardware.input.AidlKeyGestureEvent; 41 import android.hardware.input.AppLaunchData; 42 import android.hardware.input.IKeyGestureEventListener; 43 import android.hardware.input.IKeyGestureHandler; 44 import android.hardware.input.InputGestureData; 45 import android.hardware.input.InputManager; 46 import android.hardware.input.InputSettings; 47 import android.hardware.input.KeyGestureEvent; 48 import android.os.Handler; 49 import android.os.IBinder; 50 import android.os.Looper; 51 import android.os.Message; 52 import android.os.Process; 53 import android.os.RemoteException; 54 import android.os.SystemClock; 55 import android.os.UserHandle; 56 import android.provider.Settings; 57 import android.util.IndentingPrintWriter; 58 import android.util.Log; 59 import android.util.Slog; 60 import android.util.SparseArray; 61 import android.util.SparseIntArray; 62 import android.view.Display; 63 import android.view.InputDevice; 64 import android.view.KeyCharacterMap; 65 import android.view.KeyEvent; 66 import android.view.ViewConfiguration; 67 68 import com.android.internal.R; 69 import com.android.internal.accessibility.AccessibilityShortcutController; 70 import com.android.internal.annotations.GuardedBy; 71 import com.android.internal.annotations.VisibleForTesting; 72 import com.android.internal.policy.IShortcutService; 73 import com.android.server.LocalServices; 74 import com.android.server.pm.UserManagerInternal; 75 import com.android.server.policy.KeyCombinationManager; 76 77 import org.xmlpull.v1.XmlPullParserException; 78 79 import java.io.ByteArrayInputStream; 80 import java.io.ByteArrayOutputStream; 81 import java.io.IOException; 82 import java.util.ArrayDeque; 83 import java.util.Arrays; 84 import java.util.HashSet; 85 import java.util.List; 86 import java.util.Objects; 87 import java.util.Set; 88 89 /** 90 * A thread-safe component of {@link InputManagerService} responsible for managing callbacks when a 91 * key gesture event occurs. 92 */ 93 final class KeyGestureController { 94 95 private static final String TAG = "KeyGestureController"; 96 97 // To enable these logs, run: 98 // 'adb shell setprop log.tag.KeyGestureController DEBUG' (requires restart) 99 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 100 101 // Maximum key gesture events that are tracked and will be available in input dump. 102 private static final int MAX_TRACKED_EVENTS = 10; 103 private static final int SHORTCUT_META_MASK = 104 KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON | KeyEvent.META_ALT_ON 105 | KeyEvent.META_SHIFT_ON; 106 107 private static final int MSG_NOTIFY_KEY_GESTURE_EVENT = 1; 108 private static final int MSG_PERSIST_CUSTOM_GESTURES = 2; 109 private static final int MSG_LOAD_CUSTOM_GESTURES = 3; 110 private static final int MSG_ACCESSIBILITY_SHORTCUT = 4; 111 112 // must match: config_settingsKeyBehavior in config.xml 113 private static final int SETTINGS_KEY_BEHAVIOR_SETTINGS_ACTIVITY = 0; 114 private static final int SETTINGS_KEY_BEHAVIOR_NOTIFICATION_PANEL = 1; 115 private static final int SETTINGS_KEY_BEHAVIOR_NOTHING = 2; 116 private static final int LAST_SETTINGS_KEY_BEHAVIOR = SETTINGS_KEY_BEHAVIOR_NOTHING; 117 118 // Must match: config_searchKeyBehavior in config.xml 119 private static final int SEARCH_KEY_BEHAVIOR_DEFAULT_SEARCH = 0; 120 private static final int SEARCH_KEY_BEHAVIOR_TARGET_ACTIVITY = 1; 121 private static final int LAST_SEARCH_KEY_BEHAVIOR = SEARCH_KEY_BEHAVIOR_TARGET_ACTIVITY; 122 123 // must match: config_keyChordPowerVolumeUp in config.xml 124 static final int POWER_VOLUME_UP_BEHAVIOR_NOTHING = 0; 125 static final int POWER_VOLUME_UP_BEHAVIOR_MUTE = 1; 126 static final int POWER_VOLUME_UP_BEHAVIOR_GLOBAL_ACTIONS = 2; 127 128 private final Context mContext; 129 private InputManagerService.WindowManagerCallbacks mWindowManagerCallbacks; 130 private final Handler mHandler; 131 private final Handler mIoHandler; 132 private final int mSystemPid; 133 private final KeyCombinationManager mKeyCombinationManager; 134 private final SettingsObserver mSettingsObserver; 135 private final AppLaunchShortcutManager mAppLaunchShortcutManager; 136 @VisibleForTesting 137 final AccessibilityShortcutController mAccessibilityShortcutController; 138 private final InputGestureManager mInputGestureManager; 139 private final DisplayManager mDisplayManager; 140 @GuardedBy("mInputDataStore") 141 private final InputDataStore mInputDataStore; 142 private static final Object mUserLock = new Object(); 143 @UserIdInt 144 @GuardedBy("mUserLock") 145 private int mCurrentUserId = UserHandle.USER_SYSTEM; 146 147 // Pending actions 148 private boolean mPendingMetaAction; 149 private boolean mPendingCapsLockToggle; 150 private boolean mPendingHideRecentSwitcher; 151 152 // Platform behaviors 153 private boolean mHasFeatureWatch; 154 private boolean mHasFeatureLeanback; 155 156 // Key behaviors 157 private int mSearchKeyBehavior; 158 private int mSettingsKeyBehavior; 159 160 // Settings behaviors 161 private int mRingerToggleChord = Settings.Secure.VOLUME_HUSH_OFF; 162 private int mPowerVolUpBehavior; 163 164 165 // List of currently registered key gesture event listeners keyed by process pid 166 @GuardedBy("mKeyGestureEventListenerRecords") 167 private final SparseArray<KeyGestureEventListenerRecord> 168 mKeyGestureEventListenerRecords = new SparseArray<>(); 169 170 // Map of currently registered key gesture event handlers keyed by pid. 171 @GuardedBy("mKeyGestureHandlerRecords") 172 private final SparseArray<KeyGestureHandlerRecord> mKeyGestureHandlerRecords = 173 new SparseArray<>(); 174 175 // Currently supported key gestures mapped to pid that registered the corresponding handler. 176 @GuardedBy("mKeyGestureHandlerRecords") 177 private final SparseIntArray mSupportedKeyGestureToPidMap = new SparseIntArray(); 178 179 private final ArrayDeque<KeyGestureEvent> mLastHandledEvents = new ArrayDeque<>(); 180 181 /** Currently fully consumed key codes per device */ 182 private final SparseArray<Set<Integer>> mConsumedKeysForDevice = new SparseArray<>(); 183 184 private final UserManagerInternal mUserManagerInternal; 185 186 private final boolean mVisibleBackgroundUsersEnabled = isVisibleBackgroundUsersEnabled(); 187 KeyGestureController(Context context, Looper looper, Looper ioLooper, InputDataStore inputDataStore)188 public KeyGestureController(Context context, Looper looper, Looper ioLooper, 189 InputDataStore inputDataStore) { 190 this(context, looper, ioLooper, inputDataStore, new Injector()); 191 } 192 193 @VisibleForTesting KeyGestureController(Context context, Looper looper, Looper ioLooper, InputDataStore inputDataStore, Injector injector)194 KeyGestureController(Context context, Looper looper, Looper ioLooper, 195 InputDataStore inputDataStore, Injector injector) { 196 mContext = context; 197 mHandler = new Handler(looper, this::handleMessage); 198 mIoHandler = new Handler(ioLooper, this::handleIoMessage); 199 mSystemPid = Process.myPid(); 200 mKeyCombinationManager = new KeyCombinationManager(mHandler); 201 mSettingsObserver = new SettingsObserver(mHandler); 202 mAppLaunchShortcutManager = new AppLaunchShortcutManager(mContext); 203 mInputGestureManager = new InputGestureManager(mContext); 204 mAccessibilityShortcutController = injector.getAccessibilityShortcutController(mContext, 205 mHandler); 206 mDisplayManager = Objects.requireNonNull(mContext.getSystemService(DisplayManager.class)); 207 mInputDataStore = inputDataStore; 208 mUserManagerInternal = LocalServices.getService(UserManagerInternal.class); 209 initBehaviors(); 210 initKeyCombinationRules(); 211 } 212 initBehaviors()213 private void initBehaviors() { 214 PackageManager pm = mContext.getPackageManager(); 215 mHasFeatureWatch = pm.hasSystemFeature(FEATURE_WATCH); 216 mHasFeatureLeanback = pm.hasSystemFeature(FEATURE_LEANBACK); 217 218 Resources res = mContext.getResources(); 219 mSearchKeyBehavior = res.getInteger(R.integer.config_searchKeyBehavior); 220 if (mSearchKeyBehavior < SEARCH_KEY_BEHAVIOR_DEFAULT_SEARCH 221 || mSearchKeyBehavior > LAST_SEARCH_KEY_BEHAVIOR) { 222 mSearchKeyBehavior = SEARCH_KEY_BEHAVIOR_DEFAULT_SEARCH; 223 } 224 mSettingsKeyBehavior = res.getInteger(R.integer.config_settingsKeyBehavior); 225 if (mSettingsKeyBehavior < SETTINGS_KEY_BEHAVIOR_SETTINGS_ACTIVITY 226 || mSettingsKeyBehavior > LAST_SETTINGS_KEY_BEHAVIOR) { 227 mSettingsKeyBehavior = SETTINGS_KEY_BEHAVIOR_SETTINGS_ACTIVITY; 228 } 229 230 mHandler.post(this::initBehaviorsFromSettings); 231 } 232 initBehaviorsFromSettings()233 private void initBehaviorsFromSettings() { 234 ContentResolver resolver = mContext.getContentResolver(); 235 mRingerToggleChord = Settings.Secure.getIntForUser(resolver, 236 Settings.Secure.VOLUME_HUSH_GESTURE, Settings.Secure.VOLUME_HUSH_OFF, 237 UserHandle.USER_CURRENT); 238 239 mPowerVolUpBehavior = Settings.Global.getInt(resolver, 240 Settings.Global.KEY_CHORD_POWER_VOLUME_UP, 241 mContext.getResources().getInteger( 242 com.android.internal.R.integer.config_keyChordPowerVolumeUp)); 243 } 244 initKeyCombinationRules()245 private void initKeyCombinationRules() { 246 if (!InputSettings.doesKeyGestureEventHandlerSupportMultiKeyGestures()) { 247 return; 248 } 249 // TODO(b/358569822): Handle Power, Back key properly since key combination gesture is 250 // captured here and rest of the Power, Back key behaviors are handled in PWM 251 final boolean screenshotChordEnabled = mContext.getResources().getBoolean( 252 com.android.internal.R.bool.config_enableScreenshotChord); 253 254 if (screenshotChordEnabled) { 255 mKeyCombinationManager.addRule( 256 new KeyCombinationManager.TwoKeysCombinationRule(KeyEvent.KEYCODE_VOLUME_DOWN, 257 KeyEvent.KEYCODE_POWER) { 258 @Override 259 public void execute() { 260 handleMultiKeyGesture( 261 new int[]{KeyEvent.KEYCODE_VOLUME_DOWN, KeyEvent.KEYCODE_POWER}, 262 KeyGestureEvent.KEY_GESTURE_TYPE_SCREENSHOT_CHORD, 263 KeyGestureEvent.ACTION_GESTURE_START, 0); 264 } 265 266 @Override 267 public void cancel() { 268 handleMultiKeyGesture( 269 new int[]{KeyEvent.KEYCODE_VOLUME_DOWN, KeyEvent.KEYCODE_POWER}, 270 KeyGestureEvent.KEY_GESTURE_TYPE_SCREENSHOT_CHORD, 271 KeyGestureEvent.ACTION_GESTURE_COMPLETE, 272 KeyGestureEvent.FLAG_CANCELLED); 273 } 274 }); 275 276 if (mHasFeatureWatch) { 277 mKeyCombinationManager.addRule( 278 new KeyCombinationManager.TwoKeysCombinationRule(KeyEvent.KEYCODE_POWER, 279 KeyEvent.KEYCODE_STEM_PRIMARY) { 280 @Override 281 public void execute() { 282 handleMultiKeyGesture(new int[]{KeyEvent.KEYCODE_POWER, 283 KeyEvent.KEYCODE_STEM_PRIMARY}, 284 KeyGestureEvent.KEY_GESTURE_TYPE_SCREENSHOT_CHORD, 285 KeyGestureEvent.ACTION_GESTURE_START, 0); 286 } 287 @Override 288 public void cancel() { 289 handleMultiKeyGesture(new int[]{KeyEvent.KEYCODE_POWER, 290 KeyEvent.KEYCODE_STEM_PRIMARY}, 291 KeyGestureEvent.KEY_GESTURE_TYPE_SCREENSHOT_CHORD, 292 KeyGestureEvent.ACTION_GESTURE_COMPLETE, 293 KeyGestureEvent.FLAG_CANCELLED); 294 } 295 }); 296 } 297 } 298 299 mKeyCombinationManager.addRule( 300 new KeyCombinationManager.TwoKeysCombinationRule(KeyEvent.KEYCODE_VOLUME_DOWN, 301 KeyEvent.KEYCODE_VOLUME_UP) { 302 @Override 303 public boolean preCondition() { 304 return mAccessibilityShortcutController.isAccessibilityShortcutAvailable( 305 mWindowManagerCallbacks.isKeyguardLocked(DEFAULT_DISPLAY)); 306 } 307 308 @Override 309 public void execute() { 310 handleMultiKeyGesture( 311 new int[]{KeyEvent.KEYCODE_VOLUME_DOWN, KeyEvent.KEYCODE_VOLUME_UP}, 312 KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT_CHORD, 313 KeyGestureEvent.ACTION_GESTURE_START, 0); 314 } 315 316 @Override 317 public void cancel() { 318 handleMultiKeyGesture( 319 new int[]{KeyEvent.KEYCODE_VOLUME_DOWN, KeyEvent.KEYCODE_VOLUME_UP}, 320 KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT_CHORD, 321 KeyGestureEvent.ACTION_GESTURE_COMPLETE, 322 KeyGestureEvent.FLAG_CANCELLED); 323 } 324 }); 325 326 // Volume up + power can either be the "ringer toggle chord" or as another way to 327 // launch GlobalActions. This behavior can change at runtime so we must check behavior 328 // inside the TwoKeysCombinationRule. 329 mKeyCombinationManager.addRule( 330 new KeyCombinationManager.TwoKeysCombinationRule(KeyEvent.KEYCODE_VOLUME_UP, 331 KeyEvent.KEYCODE_POWER) { 332 @Override 333 public boolean preCondition() { 334 switch (mPowerVolUpBehavior) { 335 case POWER_VOLUME_UP_BEHAVIOR_MUTE: 336 return mRingerToggleChord != Settings.Secure.VOLUME_HUSH_OFF; 337 default: 338 return true; 339 } 340 } 341 @Override 342 public void execute() { 343 int gestureType = getGestureType(); 344 if (gestureType == KeyGestureEvent.KEY_GESTURE_TYPE_UNSPECIFIED) { 345 return; 346 } 347 handleMultiKeyGesture( 348 new int[]{KeyEvent.KEYCODE_VOLUME_UP, KeyEvent.KEYCODE_POWER}, 349 gestureType, KeyGestureEvent.ACTION_GESTURE_START, 0); 350 } 351 @Override 352 public void cancel() { 353 int gestureType = getGestureType(); 354 if (gestureType == KeyGestureEvent.KEY_GESTURE_TYPE_UNSPECIFIED) { 355 return; 356 } 357 handleMultiKeyGesture( 358 new int[]{KeyEvent.KEYCODE_VOLUME_UP, KeyEvent.KEYCODE_POWER}, 359 gestureType, KeyGestureEvent.ACTION_GESTURE_COMPLETE, 360 KeyGestureEvent.FLAG_CANCELLED); 361 } 362 363 @KeyGestureEvent.KeyGestureType 364 private int getGestureType() { 365 switch (mPowerVolUpBehavior) { 366 case POWER_VOLUME_UP_BEHAVIOR_MUTE -> { 367 return KeyGestureEvent.KEY_GESTURE_TYPE_RINGER_TOGGLE_CHORD; 368 } 369 case POWER_VOLUME_UP_BEHAVIOR_GLOBAL_ACTIONS -> { 370 return KeyGestureEvent.KEY_GESTURE_TYPE_GLOBAL_ACTIONS; 371 } 372 default -> { 373 return KeyGestureEvent.KEY_GESTURE_TYPE_UNSPECIFIED; 374 } 375 } 376 } 377 }); 378 379 if (mHasFeatureLeanback) { 380 mKeyCombinationManager.addRule( 381 new KeyCombinationManager.TwoKeysCombinationRule(KeyEvent.KEYCODE_BACK, 382 KeyEvent.KEYCODE_DPAD_DOWN) { 383 @Override 384 public boolean preCondition() { 385 return mAccessibilityShortcutController 386 .isAccessibilityShortcutAvailable(false); 387 } 388 389 @Override 390 public void execute() { 391 handleMultiKeyGesture( 392 new int[]{KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_DPAD_DOWN}, 393 KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT_CHORD, 394 KeyGestureEvent.ACTION_GESTURE_START, 0); 395 } 396 397 @Override 398 public void cancel() { 399 handleMultiKeyGesture( 400 new int[]{KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_DPAD_DOWN}, 401 KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT_CHORD, 402 KeyGestureEvent.ACTION_GESTURE_COMPLETE, 403 KeyGestureEvent.FLAG_CANCELLED); 404 } 405 @Override 406 public long getKeyInterceptDelayMs() { 407 // Use a timeout of 0 to prevent additional latency in processing of 408 // this key. This will potentially cause some unwanted UI actions if the 409 // user does end up triggering the key combination later, but in most 410 // cases, the user will simply hit a single key, and this will allow us 411 // to process it without first waiting to see if the combination is 412 // going to be triggered. 413 return 0; 414 } 415 }); 416 417 mKeyCombinationManager.addRule( 418 new KeyCombinationManager.TwoKeysCombinationRule(KeyEvent.KEYCODE_BACK, 419 KeyEvent.KEYCODE_DPAD_CENTER) { 420 @Override 421 public void execute() { 422 handleMultiKeyGesture( 423 new int[]{KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_DPAD_CENTER}, 424 KeyGestureEvent.KEY_GESTURE_TYPE_TV_TRIGGER_BUG_REPORT, 425 KeyGestureEvent.ACTION_GESTURE_START, 0); 426 } 427 @Override 428 public void cancel() { 429 handleMultiKeyGesture( 430 new int[]{KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_DPAD_CENTER}, 431 KeyGestureEvent.KEY_GESTURE_TYPE_TV_TRIGGER_BUG_REPORT, 432 KeyGestureEvent.ACTION_GESTURE_COMPLETE, 433 KeyGestureEvent.FLAG_CANCELLED); 434 } 435 @Override 436 public long getKeyInterceptDelayMs() { 437 return 0; 438 } 439 }); 440 } 441 } 442 systemRunning()443 public void systemRunning() { 444 mSettingsObserver.observe(); 445 mAppLaunchShortcutManager.init(); 446 mInputGestureManager.init(mAppLaunchShortcutManager.getBookmarks()); 447 initKeyGestures(); 448 449 int userId; 450 synchronized (mUserLock) { 451 userId = mCurrentUserId; 452 } 453 // Load the system user's input gestures. 454 mIoHandler.obtainMessage(MSG_LOAD_CUSTOM_GESTURES, userId).sendToTarget(); 455 } 456 457 @SuppressLint("MissingPermission") initKeyGestures()458 private void initKeyGestures() { 459 InputManager im = Objects.requireNonNull(mContext.getSystemService(InputManager.class)); 460 im.registerKeyGestureEventHandler( 461 List.of(KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT_CHORD), 462 (event, focusedToken) -> { 463 if (event.getKeyGestureType() 464 == KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT_CHORD) { 465 if (event.getAction() == KeyGestureEvent.ACTION_GESTURE_START) { 466 mHandler.removeMessages(MSG_ACCESSIBILITY_SHORTCUT); 467 mHandler.sendMessageDelayed( 468 mHandler.obtainMessage(MSG_ACCESSIBILITY_SHORTCUT), 469 getAccessibilityShortcutTimeout()); 470 } else { 471 mHandler.removeMessages(MSG_ACCESSIBILITY_SHORTCUT); 472 } 473 } else { 474 Log.w(TAG, "Received a key gesture " + event 475 + " that was not registered by this handler"); 476 } 477 }); 478 } 479 interceptKeyBeforeQueueing(KeyEvent event, int policyFlags)480 public boolean interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) { 481 if (mVisibleBackgroundUsersEnabled && shouldIgnoreKeyEventForVisibleBackgroundUser(event)) { 482 return false; 483 } 484 if (InputSettings.doesKeyGestureEventHandlerSupportMultiKeyGestures() 485 && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) { 486 final boolean interactive = (policyFlags & FLAG_INTERACTIVE) != 0; 487 final boolean isDefaultDisplayOn = isDefaultDisplayOn(); 488 return mKeyCombinationManager.interceptKey(event, interactive && isDefaultDisplayOn); 489 } 490 return false; 491 } 492 shouldIgnoreKeyEventForVisibleBackgroundUser(KeyEvent event)493 private boolean shouldIgnoreKeyEventForVisibleBackgroundUser(KeyEvent event) { 494 final int displayAssignedUserId = mUserManagerInternal.getUserAssignedToDisplay( 495 event.getDisplayId()); 496 final int currentUserId; 497 synchronized (mUserLock) { 498 currentUserId = mCurrentUserId; 499 } 500 if (currentUserId != displayAssignedUserId 501 && !KeyEvent.isVisibleBackgroundUserAllowedKey(event.getKeyCode())) { 502 if (DEBUG) { 503 Slog.w(TAG, "Ignored key event [" + event + "] for visible background user [" 504 + displayAssignedUserId + "]"); 505 } 506 return true; 507 } 508 return false; 509 } 510 interceptKeyBeforeDispatching(IBinder focusedToken, KeyEvent event, int policyFlags)511 public long interceptKeyBeforeDispatching(IBinder focusedToken, KeyEvent event, 512 int policyFlags) { 513 // TODO(b/358569822): Handle shortcuts trigger logic here and pass it to appropriate 514 // KeyGestureHandler (PWM is one of the handlers) 515 final int keyCode = event.getKeyCode(); 516 final int deviceId = event.getDeviceId(); 517 final int flags = event.getFlags(); 518 final long keyConsumed = -1; 519 final long keyNotConsumed = 0; 520 521 if (InputSettings.doesKeyGestureEventHandlerSupportMultiKeyGestures()) { 522 if (mKeyCombinationManager.isKeyConsumed(event)) { 523 return keyConsumed; 524 } 525 526 if ((flags & KeyEvent.FLAG_FALLBACK) == 0) { 527 final long now = SystemClock.uptimeMillis(); 528 final long interceptTimeout = mKeyCombinationManager.getKeyInterceptTimeout( 529 keyCode); 530 if (now < interceptTimeout) { 531 return interceptTimeout - now; 532 } 533 } 534 } 535 536 Set<Integer> consumedKeys = mConsumedKeysForDevice.get(deviceId); 537 if (consumedKeys == null) { 538 consumedKeys = new HashSet<>(); 539 mConsumedKeysForDevice.put(deviceId, consumedKeys); 540 } 541 542 if (interceptSystemKeysAndShortcuts(focusedToken, event) 543 && event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) { 544 consumedKeys.add(keyCode); 545 return keyConsumed; 546 } 547 548 boolean needToConsumeKey = consumedKeys.contains(keyCode); 549 if (event.getAction() == KeyEvent.ACTION_UP || event.isCanceled()) { 550 consumedKeys.remove(keyCode); 551 if (consumedKeys.isEmpty()) { 552 mConsumedKeysForDevice.remove(deviceId); 553 } 554 } 555 556 return needToConsumeKey ? keyConsumed : keyNotConsumed; 557 } 558 559 @SuppressLint("MissingPermission") interceptSystemKeysAndShortcuts(IBinder focusedToken, KeyEvent event)560 private boolean interceptSystemKeysAndShortcuts(IBinder focusedToken, KeyEvent event) { 561 final int keyCode = event.getKeyCode(); 562 final int repeatCount = event.getRepeatCount(); 563 final int metaState = event.getMetaState() & SHORTCUT_META_MASK; 564 final boolean down = event.getAction() == KeyEvent.ACTION_DOWN; 565 final boolean canceled = event.isCanceled(); 566 final int displayId = event.getDisplayId(); 567 final int deviceId = event.getDeviceId(); 568 final boolean firstDown = down && repeatCount == 0; 569 570 // Cancel any pending meta actions if we see any other keys being pressed between the 571 // down of the meta key and its corresponding up. 572 if (mPendingMetaAction && !KeyEvent.isMetaKey(keyCode)) { 573 mPendingMetaAction = false; 574 } 575 // Any key that is not Alt or Meta cancels Caps Lock combo tracking. 576 if (mPendingCapsLockToggle && !KeyEvent.isMetaKey(keyCode) && !KeyEvent.isAltKey(keyCode)) { 577 mPendingCapsLockToggle = false; 578 } 579 580 // Handle App launch shortcuts 581 AppLaunchShortcutManager.InterceptKeyResult result = mAppLaunchShortcutManager.interceptKey( 582 event); 583 if (result.consumed()) { 584 return true; 585 } 586 if (result.appLaunchData() != null) { 587 handleKeyGesture(deviceId, new int[]{keyCode}, metaState, 588 KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION, 589 KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId, focusedToken, /* flags = */ 590 0, result.appLaunchData()); 591 return true; 592 } 593 594 // Handle system shortcuts 595 if (firstDown) { 596 InputGestureData systemShortcut = mInputGestureManager.getSystemShortcutForKeyEvent( 597 event); 598 if (systemShortcut != null) { 599 handleKeyGesture(deviceId, new int[]{keyCode}, metaState, 600 systemShortcut.getAction().keyGestureType(), 601 KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId, 602 focusedToken, /* flags = */0, systemShortcut.getAction().appLaunchData()); 603 return true; 604 } 605 } 606 607 // Handle system keys 608 switch (keyCode) { 609 case KeyEvent.KEYCODE_RECENT_APPS: 610 if (firstDown) { 611 handleKeyGesture(deviceId, new int[]{keyCode}, /* modifierState = */0, 612 KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS, 613 KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId, 614 focusedToken, /* flags = */0, /* appLaunchData = */null); 615 } 616 return true; 617 case KeyEvent.KEYCODE_APP_SWITCH: 618 if (firstDown) { 619 handleKeyGesture(deviceId, new int[]{keyCode}, /* modifierState = */0, 620 KeyGestureEvent.KEY_GESTURE_TYPE_APP_SWITCH, 621 KeyGestureEvent.ACTION_GESTURE_START, displayId, 622 focusedToken, /* flags = */0, /* appLaunchData = */null); 623 } else if (!down) { 624 handleKeyGesture(deviceId, new int[]{keyCode}, /* modifierState = */0, 625 KeyGestureEvent.KEY_GESTURE_TYPE_APP_SWITCH, 626 KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId, 627 focusedToken, canceled ? KeyGestureEvent.FLAG_CANCELLED : 0, 628 /* appLaunchData = */null); 629 } 630 return true; 631 case KeyEvent.KEYCODE_BRIGHTNESS_UP: 632 case KeyEvent.KEYCODE_BRIGHTNESS_DOWN: 633 if (down) { 634 handleKeyGesture(deviceId, new int[]{keyCode}, /* modifierState = */0, 635 keyCode == KeyEvent.KEYCODE_BRIGHTNESS_UP 636 ? KeyGestureEvent.KEY_GESTURE_TYPE_BRIGHTNESS_UP 637 : KeyGestureEvent.KEY_GESTURE_TYPE_BRIGHTNESS_DOWN, 638 KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId, 639 focusedToken, /* flags = */0, /* appLaunchData = */null); 640 } 641 return true; 642 case KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_DOWN: 643 if (down) { 644 handleKeyGesture(deviceId, new int[]{keyCode}, /* modifierState = */0, 645 KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN, 646 KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId, 647 focusedToken, /* flags = */0, /* appLaunchData = */null); 648 } 649 return true; 650 case KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_UP: 651 if (down) { 652 handleKeyGesture(deviceId, new int[]{keyCode}, /* modifierState = */0, 653 KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP, 654 KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId, 655 focusedToken, /* flags = */0, /* appLaunchData = */null); 656 } 657 return true; 658 case KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_TOGGLE: 659 // TODO: Add logic 660 if (!down) { 661 handleKeyGesture(deviceId, new int[]{keyCode}, /* modifierState = */0, 662 KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE, 663 KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId, 664 focusedToken, /* flags = */0, /* appLaunchData = */null); 665 } 666 return true; 667 case KeyEvent.KEYCODE_ALL_APPS: 668 if (firstDown) { 669 handleKeyGesture(deviceId, new int[]{keyCode}, /* modifierState = */0, 670 KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS, 671 KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId, 672 focusedToken, /* flags = */0, /* appLaunchData = */null); 673 } 674 return true; 675 case KeyEvent.KEYCODE_NOTIFICATION: 676 if (!down) { 677 handleKeyGesture(deviceId, new int[]{keyCode}, /* modifierState = */0, 678 KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL, 679 KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId, 680 focusedToken, /* flags = */0, /* appLaunchData = */null); 681 } 682 return true; 683 case KeyEvent.KEYCODE_SEARCH: 684 if (firstDown && mSearchKeyBehavior == SEARCH_KEY_BEHAVIOR_TARGET_ACTIVITY) { 685 handleKeyGesture(deviceId, new int[]{keyCode}, /* modifierState = */0, 686 KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_SEARCH, 687 KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId, 688 focusedToken, /* flags = */0, /* appLaunchData = */null); 689 return true; 690 } 691 break; 692 case KeyEvent.KEYCODE_SETTINGS: 693 if (firstDown) { 694 if (mSettingsKeyBehavior == SETTINGS_KEY_BEHAVIOR_SETTINGS_ACTIVITY) { 695 handleKeyGesture(deviceId, 696 new int[]{keyCode}, /* modifierState = */0, 697 KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS, 698 KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId, 699 focusedToken, /* flags = */0, /* appLaunchData = */null); 700 } else if (mSettingsKeyBehavior == SETTINGS_KEY_BEHAVIOR_NOTIFICATION_PANEL) { 701 handleKeyGesture(deviceId, 702 new int[]{keyCode}, /* modifierState = */0, 703 KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL, 704 KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId, 705 focusedToken, /* flags = */0, /* appLaunchData = */null); 706 } 707 } 708 return true; 709 case KeyEvent.KEYCODE_LANGUAGE_SWITCH: 710 if (firstDown) { 711 handleKeyGesture(deviceId, new int[]{keyCode}, 712 event.isShiftPressed() ? KeyEvent.META_SHIFT_ON : 0, 713 KeyGestureEvent.KEY_GESTURE_TYPE_LANGUAGE_SWITCH, 714 KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId, 715 focusedToken, /* flags = */0, /* appLaunchData = */null); 716 } 717 return true; 718 case KeyEvent.KEYCODE_CAPS_LOCK: 719 // Just logging/notifying purposes 720 // Caps lock is already handled in inputflinger native 721 if (!down) { 722 AidlKeyGestureEvent eventToNotify = createKeyGestureEvent(deviceId, 723 new int[]{keyCode}, metaState, 724 KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK, 725 KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId, /* flags = */0, 726 /* appLaunchData = */null); 727 Message msg = Message.obtain(mHandler, MSG_NOTIFY_KEY_GESTURE_EVENT, 728 eventToNotify); 729 mHandler.sendMessage(msg); 730 } 731 break; 732 case KeyEvent.KEYCODE_SCREENSHOT: 733 if (firstDown) { 734 handleKeyGesture(deviceId, new int[]{keyCode}, /* modifierState = */0, 735 KeyGestureEvent.KEY_GESTURE_TYPE_TAKE_SCREENSHOT, 736 KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId, 737 focusedToken, /* flags = */0, /* appLaunchData = */null); 738 } 739 return true; 740 case KeyEvent.KEYCODE_META_LEFT: 741 case KeyEvent.KEYCODE_META_RIGHT: 742 if (down) { 743 if (event.isAltPressed()) { 744 mPendingCapsLockToggle = true; 745 mPendingMetaAction = false; 746 } else { 747 mPendingCapsLockToggle = false; 748 mPendingMetaAction = true; 749 } 750 } else { 751 // Toggle Caps Lock on META-ALT. 752 if (mPendingCapsLockToggle) { 753 mPendingCapsLockToggle = false; 754 handleKeyGesture(deviceId, new int[]{KeyEvent.KEYCODE_META_LEFT, 755 KeyEvent.KEYCODE_ALT_LEFT}, /* modifierState = */0, 756 KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK, 757 KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId, 758 focusedToken, /* flags = */0, /* appLaunchData = */null); 759 760 } else if (mPendingMetaAction) { 761 mPendingMetaAction = false; 762 if (!canceled) { 763 handleKeyGesture(deviceId, new int[]{keyCode}, 764 /* modifierState = */0, 765 KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS, 766 KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId, 767 focusedToken, /* flags = */0, /* appLaunchData = */null); 768 } 769 } 770 } 771 return true; 772 case KeyEvent.KEYCODE_TAB: 773 if (firstDown) { 774 if (!mPendingHideRecentSwitcher) { 775 final int shiftlessModifiers = 776 event.getModifiers() & ~KeyEvent.META_SHIFT_MASK; 777 if (KeyEvent.metaStateHasModifiers( 778 shiftlessModifiers, KeyEvent.META_ALT_ON)) { 779 mPendingHideRecentSwitcher = true; 780 handleKeyGesture(deviceId, new int[]{keyCode}, 781 KeyEvent.META_ALT_ON, 782 KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS_SWITCHER, 783 KeyGestureEvent.ACTION_GESTURE_START, displayId, 784 focusedToken, /* flags = */0, /* appLaunchData = */null); 785 return true; 786 } 787 } 788 } 789 break; 790 case KeyEvent.KEYCODE_ALT_LEFT: 791 case KeyEvent.KEYCODE_ALT_RIGHT: 792 if (down) { 793 if (event.isMetaPressed()) { 794 mPendingCapsLockToggle = true; 795 mPendingMetaAction = false; 796 } else { 797 mPendingCapsLockToggle = false; 798 } 799 } else { 800 if (mPendingHideRecentSwitcher) { 801 mPendingHideRecentSwitcher = false; 802 handleKeyGesture(deviceId, new int[]{KeyEvent.KEYCODE_TAB}, 803 KeyEvent.META_ALT_ON, 804 KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS_SWITCHER, 805 KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId, 806 focusedToken, /* flags = */0, /* appLaunchData = */null); 807 return true; 808 } 809 810 // Toggle Caps Lock on META-ALT. 811 if (mPendingCapsLockToggle) { 812 mPendingCapsLockToggle = false; 813 handleKeyGesture(deviceId, new int[]{KeyEvent.KEYCODE_META_LEFT, 814 KeyEvent.KEYCODE_ALT_LEFT}, /* modifierState = */0, 815 KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK, 816 KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId, 817 focusedToken, /* flags = */0, /* appLaunchData = */null); 818 return true; 819 } 820 } 821 break; 822 case KeyEvent.KEYCODE_LOCK: 823 if (enableNew25q2Keycodes()) { 824 if (firstDown) { 825 handleKeyGesture(deviceId, new int[]{KeyEvent.KEYCODE_LOCK}, 826 /* modifierState = */0, 827 KeyGestureEvent.KEY_GESTURE_TYPE_LOCK_SCREEN, 828 KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId, focusedToken, 829 /* flags = */0, /* appLaunchData = */null); 830 } 831 } 832 return true; 833 case KeyEvent.KEYCODE_FULLSCREEN: 834 if (enableNew25q2Keycodes()) { 835 if (firstDown) { 836 handleKeyGesture(deviceId, new int[]{KeyEvent.KEYCODE_FULLSCREEN}, 837 /* modifierState = */0, 838 KeyGestureEvent.KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION, 839 KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId, focusedToken, 840 /* flags = */0, /* appLaunchData = */null); 841 } 842 } 843 return true; 844 case KeyEvent.KEYCODE_ASSIST: 845 Slog.wtf(TAG, "KEYCODE_ASSIST should be handled in interceptKeyBeforeQueueing"); 846 return true; 847 case KeyEvent.KEYCODE_VOICE_ASSIST: 848 Slog.wtf(TAG, "KEYCODE_VOICE_ASSIST should be handled in" 849 + " interceptKeyBeforeQueueing"); 850 return true; 851 case KeyEvent.KEYCODE_STYLUS_BUTTON_PRIMARY: 852 case KeyEvent.KEYCODE_STYLUS_BUTTON_SECONDARY: 853 case KeyEvent.KEYCODE_STYLUS_BUTTON_TERTIARY: 854 case KeyEvent.KEYCODE_STYLUS_BUTTON_TAIL: 855 Slog.wtf(TAG, "KEYCODE_STYLUS_BUTTON_* should be handled in" 856 + " interceptKeyBeforeQueueing"); 857 return true; 858 case KeyEvent.KEYCODE_DO_NOT_DISTURB: 859 if (enableNew25q2Keycodes()) { 860 if (firstDown) { 861 handleKeyGesture(deviceId, new int[]{KeyEvent.KEYCODE_DO_NOT_DISTURB}, 862 /* modifierState = */0, 863 KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_DO_NOT_DISTURB, 864 KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId, focusedToken, 865 /* flags = */0, /* appLaunchData = */null); 866 } 867 } 868 return true; 869 } 870 871 // Handle shortcuts through shortcut services 872 if (mAppLaunchShortcutManager.handleShortcutService(event)) { 873 return true; 874 } 875 876 // Handle custom shortcuts 877 if (firstDown) { 878 InputGestureData customGesture; 879 synchronized (mUserLock) { 880 customGesture = mInputGestureManager.getCustomGestureForKeyEvent(mCurrentUserId, 881 event); 882 } 883 if (customGesture == null) { 884 return false; 885 } 886 handleKeyGesture(deviceId, new int[]{keyCode}, metaState, 887 customGesture.getAction().keyGestureType(), 888 KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId, focusedToken, 889 /* flags = */0, customGesture.getAction().appLaunchData()); 890 return true; 891 } 892 return false; 893 } 894 interceptUnhandledKey(KeyEvent event, IBinder focusedToken)895 boolean interceptUnhandledKey(KeyEvent event, IBinder focusedToken) { 896 final int keyCode = event.getKeyCode(); 897 final int repeatCount = event.getRepeatCount(); 898 final boolean down = event.getAction() == KeyEvent.ACTION_DOWN; 899 final int metaState = event.getModifiers(); 900 final int deviceId = event.getDeviceId(); 901 final int displayId = event.getDisplayId(); 902 903 switch(keyCode) { 904 case KeyEvent.KEYCODE_SPACE: 905 if (down && repeatCount == 0) { 906 // Handle keyboard layout switching. (CTRL + SPACE) 907 if (KeyEvent.metaStateHasModifiers(metaState & ~KeyEvent.META_SHIFT_MASK, 908 KeyEvent.META_CTRL_ON)) { 909 handleKeyGesture(deviceId, new int[]{keyCode}, 910 KeyEvent.META_CTRL_ON | (event.isShiftPressed() 911 ? KeyEvent.META_SHIFT_ON : 0), 912 KeyGestureEvent.KEY_GESTURE_TYPE_LANGUAGE_SWITCH, 913 KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId, 914 focusedToken, /* flags = */0, /* appLaunchData = */null); 915 } 916 } 917 break; 918 case KeyEvent.KEYCODE_Z: 919 if (down && KeyEvent.metaStateHasModifiers(metaState, 920 KeyEvent.META_CTRL_ON | KeyEvent.META_ALT_ON)) { 921 // Intercept the Accessibility keychord (CTRL + ALT + Z) for keyboard users. 922 handleKeyGesture(deviceId, new int[]{keyCode}, 923 KeyEvent.META_CTRL_ON | KeyEvent.META_ALT_ON, 924 KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT, 925 KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId, 926 focusedToken, /* flags = */0, /* appLaunchData = */null); 927 } 928 break; 929 case KeyEvent.KEYCODE_SYSRQ: 930 if (down && repeatCount == 0) { 931 handleKeyGesture(deviceId, new int[]{keyCode}, /* modifierState = */0, 932 KeyGestureEvent.KEY_GESTURE_TYPE_TAKE_SCREENSHOT, 933 KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId, 934 focusedToken, /* flags = */0, /* appLaunchData = */null); 935 } 936 break; 937 case KeyEvent.KEYCODE_ESCAPE: 938 if (down && KeyEvent.metaStateHasNoModifiers(metaState) && repeatCount == 0) { 939 handleKeyGesture(deviceId, new int[]{keyCode}, /* modifierState = */0, 940 KeyGestureEvent.KEY_GESTURE_TYPE_CLOSE_ALL_DIALOGS, 941 KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId, 942 focusedToken, /* flags = */0, /* appLaunchData = */null); 943 } 944 break; 945 } 946 947 return false; 948 } 949 handleMultiKeyGesture(int[] keycodes, @KeyGestureEvent.KeyGestureType int gestureType, int action, int flags)950 private void handleMultiKeyGesture(int[] keycodes, 951 @KeyGestureEvent.KeyGestureType int gestureType, int action, int flags) { 952 handleKeyGesture(KeyCharacterMap.VIRTUAL_KEYBOARD, keycodes, /* modifierState= */0, 953 gestureType, action, DEFAULT_DISPLAY, /* focusedToken = */null, flags, 954 /* appLaunchData = */null); 955 } 956 handleTouchpadGesture(@eyGestureEvent.KeyGestureType int keyGestureType, @Nullable AppLaunchData appLaunchData)957 private void handleTouchpadGesture(@KeyGestureEvent.KeyGestureType int keyGestureType, 958 @Nullable AppLaunchData appLaunchData) { 959 handleKeyGesture(KeyCharacterMap.VIRTUAL_KEYBOARD, new int[0], /* modifierState= */0, 960 keyGestureType, KeyGestureEvent.ACTION_GESTURE_COMPLETE, 961 DEFAULT_DISPLAY, /* focusedToken = */null, /* flags = */0, appLaunchData); 962 } 963 964 @VisibleForTesting handleKeyGesture(int deviceId, int[] keycodes, int modifierState, @KeyGestureEvent.KeyGestureType int gestureType, int action, int displayId, @Nullable IBinder focusedToken, int flags, @Nullable AppLaunchData appLaunchData)965 void handleKeyGesture(int deviceId, int[] keycodes, int modifierState, 966 @KeyGestureEvent.KeyGestureType int gestureType, int action, int displayId, 967 @Nullable IBinder focusedToken, int flags, @Nullable AppLaunchData appLaunchData) { 968 handleKeyGesture( 969 createKeyGestureEvent(deviceId, keycodes, modifierState, gestureType, action, 970 displayId, flags, appLaunchData), focusedToken); 971 } 972 handleKeyGesture(AidlKeyGestureEvent event, @Nullable IBinder focusedToken)973 private void handleKeyGesture(AidlKeyGestureEvent event, @Nullable IBinder focusedToken) { 974 if (mVisibleBackgroundUsersEnabled && event.displayId != DEFAULT_DISPLAY 975 && shouldIgnoreGestureEventForVisibleBackgroundUser(event.gestureType, 976 event.displayId)) { 977 return; 978 } 979 synchronized (mKeyGestureHandlerRecords) { 980 int index = mSupportedKeyGestureToPidMap.indexOfKey(event.gestureType); 981 if (index < 0) { 982 Log.i(TAG, "Key gesture: " + event.gestureType + " is not supported"); 983 return; 984 } 985 int pid = mSupportedKeyGestureToPidMap.valueAt(index); 986 mKeyGestureHandlerRecords.get(pid).handleKeyGesture(event, focusedToken); 987 Message msg = Message.obtain(mHandler, MSG_NOTIFY_KEY_GESTURE_EVENT, event); 988 mHandler.sendMessage(msg); 989 } 990 } 991 shouldIgnoreGestureEventForVisibleBackgroundUser( @eyGestureEvent.KeyGestureType int gestureType, int displayId)992 private boolean shouldIgnoreGestureEventForVisibleBackgroundUser( 993 @KeyGestureEvent.KeyGestureType int gestureType, int displayId) { 994 final int displayAssignedUserId = mUserManagerInternal.getUserAssignedToDisplay(displayId); 995 final int currentUserId; 996 synchronized (mUserLock) { 997 currentUserId = mCurrentUserId; 998 } 999 if (currentUserId != displayAssignedUserId 1000 && !KeyGestureEvent.isVisibleBackgrounduserAllowedGesture(gestureType)) { 1001 if (DEBUG) { 1002 Slog.w(TAG, "Ignored gesture event [" + gestureType 1003 + "] for visible background user [" + displayAssignedUserId + "]"); 1004 } 1005 return true; 1006 } 1007 return false; 1008 } 1009 notifyKeyGestureCompleted(int deviceId, int[] keycodes, int modifierState, @KeyGestureEvent.KeyGestureType int gestureType)1010 public void notifyKeyGestureCompleted(int deviceId, int[] keycodes, int modifierState, 1011 @KeyGestureEvent.KeyGestureType int gestureType) { 1012 // TODO(b/358569822): Once we move the gesture detection logic to IMS, we ideally 1013 // should not rely on PWM to tell us about the gesture start and end. 1014 AidlKeyGestureEvent event = createKeyGestureEvent(deviceId, keycodes, modifierState, 1015 gestureType, KeyGestureEvent.ACTION_GESTURE_COMPLETE, DEFAULT_DISPLAY, 1016 /* flags = */0, /* appLaunchData = */null); 1017 mHandler.obtainMessage(MSG_NOTIFY_KEY_GESTURE_EVENT, event).sendToTarget(); 1018 } 1019 handleKeyGesture(int deviceId, int[] keycodes, int modifierState, @KeyGestureEvent.KeyGestureType int gestureType)1020 public void handleKeyGesture(int deviceId, int[] keycodes, int modifierState, 1021 @KeyGestureEvent.KeyGestureType int gestureType) { 1022 AidlKeyGestureEvent event = createKeyGestureEvent(deviceId, keycodes, modifierState, 1023 gestureType, KeyGestureEvent.ACTION_GESTURE_COMPLETE, DEFAULT_DISPLAY, 1024 /* flags = */0, /* appLaunchData = */null); 1025 handleKeyGesture(event, null /*focusedToken*/); 1026 } 1027 handleTouchpadGesture(int touchpadGestureType)1028 public void handleTouchpadGesture(int touchpadGestureType) { 1029 // Handle custom shortcuts 1030 InputGestureData customGesture; 1031 synchronized (mUserLock) { 1032 customGesture = mInputGestureManager.getCustomGestureForTouchpadGesture(mCurrentUserId, 1033 touchpadGestureType); 1034 } 1035 if (customGesture == null) { 1036 return; 1037 } 1038 handleTouchpadGesture(customGesture.getAction().keyGestureType(), 1039 customGesture.getAction().appLaunchData()); 1040 } 1041 1042 @MainThread setCurrentUserId(@serIdInt int userId)1043 public void setCurrentUserId(@UserIdInt int userId) { 1044 synchronized (mUserLock) { 1045 mCurrentUserId = userId; 1046 } 1047 mAccessibilityShortcutController.setCurrentUser(userId); 1048 mIoHandler.obtainMessage(MSG_LOAD_CUSTOM_GESTURES, userId).sendToTarget(); 1049 } 1050 1051 setWindowManagerCallbacks( @onNull InputManagerService.WindowManagerCallbacks callbacks)1052 public void setWindowManagerCallbacks( 1053 @NonNull InputManagerService.WindowManagerCallbacks callbacks) { 1054 mWindowManagerCallbacks = callbacks; 1055 } 1056 isDefaultDisplayOn()1057 private boolean isDefaultDisplayOn() { 1058 Display defaultDisplay = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY); 1059 if (defaultDisplay == null) { 1060 return false; 1061 } 1062 return Display.isOnState(defaultDisplay.getState()); 1063 } 1064 1065 @MainThread notifyKeyGestureEvent(AidlKeyGestureEvent event)1066 private void notifyKeyGestureEvent(AidlKeyGestureEvent event) { 1067 InputDevice device = getInputDevice(event.deviceId); 1068 if (device == null) { 1069 return; 1070 } 1071 KeyGestureEvent keyGestureEvent = new KeyGestureEvent(event); 1072 if (event.action == KeyGestureEvent.ACTION_GESTURE_COMPLETE) { 1073 KeyboardMetricsCollector.logKeyboardSystemsEventReportedAtom(device, event.keycodes, 1074 event.modifierState, keyGestureEvent.getLogEvent()); 1075 } 1076 notifyAllListeners(event); 1077 while (mLastHandledEvents.size() >= MAX_TRACKED_EVENTS) { 1078 mLastHandledEvents.removeFirst(); 1079 } 1080 mLastHandledEvents.addLast(keyGestureEvent); 1081 } 1082 1083 @MainThread notifyAllListeners(AidlKeyGestureEvent event)1084 private void notifyAllListeners(AidlKeyGestureEvent event) { 1085 if (DEBUG) { 1086 Slog.d(TAG, "Key gesture event occurred, event = " + event); 1087 } 1088 1089 synchronized (mKeyGestureEventListenerRecords) { 1090 for (int i = 0; i < mKeyGestureEventListenerRecords.size(); i++) { 1091 mKeyGestureEventListenerRecords.valueAt(i).onKeyGestureEvent(event); 1092 } 1093 } 1094 } 1095 1096 @MainThread handleMessage(Message msg)1097 private boolean handleMessage(Message msg) { 1098 switch (msg.what) { 1099 case MSG_NOTIFY_KEY_GESTURE_EVENT: 1100 AidlKeyGestureEvent event = (AidlKeyGestureEvent) msg.obj; 1101 notifyKeyGestureEvent(event); 1102 break; 1103 case MSG_ACCESSIBILITY_SHORTCUT: 1104 mAccessibilityShortcutController.performAccessibilityShortcut(); 1105 break; 1106 } 1107 return true; 1108 } 1109 handleIoMessage(Message msg)1110 private boolean handleIoMessage(Message msg) { 1111 switch (msg.what) { 1112 case MSG_PERSIST_CUSTOM_GESTURES: { 1113 final int userId = (Integer) msg.obj; 1114 persistInputGestures(userId); 1115 break; 1116 } 1117 case MSG_LOAD_CUSTOM_GESTURES: { 1118 final int userId = (Integer) msg.obj; 1119 loadInputGestures(userId); 1120 break; 1121 } 1122 } 1123 return true; 1124 } 1125 1126 /** Register the key gesture event listener for a process. */ 1127 @BinderThread registerKeyGestureEventListener(IKeyGestureEventListener listener, int pid)1128 public void registerKeyGestureEventListener(IKeyGestureEventListener listener, int pid) { 1129 synchronized (mKeyGestureEventListenerRecords) { 1130 if (mKeyGestureEventListenerRecords.get(pid) != null) { 1131 throw new IllegalStateException("The calling process has already registered " 1132 + "a KeyGestureEventListener."); 1133 } 1134 KeyGestureEventListenerRecord record = new KeyGestureEventListenerRecord(pid, listener); 1135 try { 1136 listener.asBinder().linkToDeath(record, 0); 1137 } catch (RemoteException ex) { 1138 throw new RuntimeException(ex); 1139 } 1140 mKeyGestureEventListenerRecords.put(pid, record); 1141 } 1142 } 1143 1144 /** Unregister the key gesture event listener for a process. */ 1145 @BinderThread unregisterKeyGestureEventListener(IKeyGestureEventListener listener, int pid)1146 public void unregisterKeyGestureEventListener(IKeyGestureEventListener listener, int pid) { 1147 synchronized (mKeyGestureEventListenerRecords) { 1148 KeyGestureEventListenerRecord record = 1149 mKeyGestureEventListenerRecords.get(pid); 1150 if (record == null) { 1151 throw new IllegalStateException("The calling process has no registered " 1152 + "KeyGestureEventListener."); 1153 } 1154 if (record.mListener.asBinder() != listener.asBinder()) { 1155 throw new IllegalStateException("The calling process has a different registered " 1156 + "KeyGestureEventListener."); 1157 } 1158 record.mListener.asBinder().unlinkToDeath(record, 0); 1159 mKeyGestureEventListenerRecords.remove(pid); 1160 } 1161 } 1162 1163 @BinderThread 1164 @Nullable getInputGesture(@serIdInt int userId, @NonNull AidlInputGestureData.Trigger trigger)1165 public AidlInputGestureData getInputGesture(@UserIdInt int userId, 1166 @NonNull AidlInputGestureData.Trigger trigger) { 1167 InputGestureData gestureData = mInputGestureManager.getInputGesture(userId, 1168 InputGestureData.createTriggerFromAidlTrigger(trigger)); 1169 if (gestureData == null) { 1170 return null; 1171 } 1172 return gestureData.getAidlData(); 1173 } 1174 1175 @BinderThread 1176 @InputManager.CustomInputGestureResult addCustomInputGesture(@serIdInt int userId, @NonNull AidlInputGestureData inputGestureData)1177 public int addCustomInputGesture(@UserIdInt int userId, 1178 @NonNull AidlInputGestureData inputGestureData) { 1179 final int result = mInputGestureManager.addCustomInputGesture(userId, 1180 new InputGestureData(inputGestureData)); 1181 if (result == InputManager.CUSTOM_INPUT_GESTURE_RESULT_SUCCESS) { 1182 mIoHandler.obtainMessage(MSG_PERSIST_CUSTOM_GESTURES, userId).sendToTarget(); 1183 } 1184 return result; 1185 } 1186 1187 @BinderThread 1188 @InputManager.CustomInputGestureResult removeCustomInputGesture(@serIdInt int userId, @NonNull AidlInputGestureData inputGestureData)1189 public int removeCustomInputGesture(@UserIdInt int userId, 1190 @NonNull AidlInputGestureData inputGestureData) { 1191 final int result = mInputGestureManager.removeCustomInputGesture(userId, 1192 new InputGestureData(inputGestureData)); 1193 if (result == InputManager.CUSTOM_INPUT_GESTURE_RESULT_SUCCESS) { 1194 mIoHandler.obtainMessage(MSG_PERSIST_CUSTOM_GESTURES, userId).sendToTarget(); 1195 } 1196 return result; 1197 } 1198 1199 @BinderThread removeAllCustomInputGestures(@serIdInt int userId, @Nullable InputGestureData.Filter filter)1200 public void removeAllCustomInputGestures(@UserIdInt int userId, 1201 @Nullable InputGestureData.Filter filter) { 1202 mInputGestureManager.removeAllCustomInputGestures(userId, filter); 1203 mIoHandler.obtainMessage(MSG_PERSIST_CUSTOM_GESTURES, userId).sendToTarget(); 1204 } 1205 1206 @BinderThread getCustomInputGestures(@serIdInt int userId, @Nullable InputGestureData.Filter filter)1207 public AidlInputGestureData[] getCustomInputGestures(@UserIdInt int userId, 1208 @Nullable InputGestureData.Filter filter) { 1209 List<InputGestureData> customGestures = mInputGestureManager.getCustomInputGestures(userId, 1210 filter); 1211 AidlInputGestureData[] result = new AidlInputGestureData[customGestures.size()]; 1212 for (int i = 0; i < customGestures.size(); i++) { 1213 result[i] = customGestures.get(i).getAidlData(); 1214 } 1215 return result; 1216 } 1217 1218 @BinderThread getAppLaunchBookmarks()1219 public AidlInputGestureData[] getAppLaunchBookmarks() { 1220 List<InputGestureData> bookmarks = mAppLaunchShortcutManager.getBookmarks(); 1221 AidlInputGestureData[] result = new AidlInputGestureData[bookmarks.size()]; 1222 for (int i = 0; i < bookmarks.size(); i++) { 1223 result[i] = bookmarks.get(i).getAidlData(); 1224 } 1225 return result; 1226 } 1227 onKeyGestureEventListenerDied(int pid)1228 private void onKeyGestureEventListenerDied(int pid) { 1229 synchronized (mKeyGestureEventListenerRecords) { 1230 mKeyGestureEventListenerRecords.remove(pid); 1231 } 1232 } 1233 getInputGestureBackupPayload(int userId)1234 byte[] getInputGestureBackupPayload(int userId) throws IOException { 1235 final List<InputGestureData> inputGestureDataList = 1236 mInputGestureManager.getCustomInputGestures(userId, null); 1237 ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 1238 synchronized (mInputDataStore) { 1239 mInputDataStore.writeInputGestureXml(byteArrayOutputStream, true, inputGestureDataList); 1240 } 1241 return byteArrayOutputStream.toByteArray(); 1242 } 1243 applyInputGesturesBackupPayload(byte[] payload, int userId)1244 void applyInputGesturesBackupPayload(byte[] payload, int userId) 1245 throws XmlPullParserException, IOException { 1246 final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(payload); 1247 List<InputGestureData> inputGestureDataList; 1248 synchronized (mInputDataStore) { 1249 inputGestureDataList = mInputDataStore.readInputGesturesXml(byteArrayInputStream, true); 1250 } 1251 for (final InputGestureData inputGestureData : inputGestureDataList) { 1252 mInputGestureManager.addCustomInputGesture(userId, inputGestureData); 1253 } 1254 mHandler.obtainMessage(MSG_PERSIST_CUSTOM_GESTURES, userId).sendToTarget(); 1255 } 1256 1257 // A record of a registered key gesture event listener from one process. 1258 private class KeyGestureEventListenerRecord implements IBinder.DeathRecipient { 1259 public final int mPid; 1260 public final IKeyGestureEventListener mListener; 1261 KeyGestureEventListenerRecord(int pid, IKeyGestureEventListener listener)1262 KeyGestureEventListenerRecord(int pid, IKeyGestureEventListener listener) { 1263 mPid = pid; 1264 mListener = listener; 1265 } 1266 1267 @Override binderDied()1268 public void binderDied() { 1269 if (DEBUG) { 1270 Slog.d(TAG, "Key gesture event listener for pid " + mPid + " died."); 1271 } 1272 onKeyGestureEventListenerDied(mPid); 1273 } 1274 onKeyGestureEvent(AidlKeyGestureEvent event)1275 public void onKeyGestureEvent(AidlKeyGestureEvent event) { 1276 try { 1277 mListener.onKeyGestureEvent(event); 1278 } catch (RemoteException ex) { 1279 Slog.w(TAG, "Failed to notify process " + mPid 1280 + " that key gesture event occurred, assuming it died.", ex); 1281 binderDied(); 1282 } 1283 } 1284 } 1285 1286 /** Register the key gesture event handler for a process. */ 1287 @BinderThread registerKeyGestureHandler(int[] keyGesturesToHandle, IKeyGestureHandler handler, int pid)1288 public void registerKeyGestureHandler(int[] keyGesturesToHandle, IKeyGestureHandler handler, 1289 int pid) { 1290 synchronized (mKeyGestureHandlerRecords) { 1291 if (mKeyGestureHandlerRecords.get(pid) != null) { 1292 throw new IllegalStateException("The calling process has already registered " 1293 + "a KeyGestureHandler."); 1294 } 1295 if (keyGesturesToHandle.length == 0) { 1296 throw new IllegalArgumentException("No key gestures provided for pid = " + pid); 1297 } 1298 for (int gestureType : keyGesturesToHandle) { 1299 if (mSupportedKeyGestureToPidMap.indexOfKey(gestureType) >= 0) { 1300 throw new IllegalArgumentException( 1301 "Key gesture " + gestureType + " is already registered by pid = " 1302 + mSupportedKeyGestureToPidMap.get(gestureType)); 1303 } 1304 } 1305 KeyGestureHandlerRecord record = new KeyGestureHandlerRecord(pid, handler); 1306 try { 1307 handler.asBinder().linkToDeath(record, 0); 1308 } catch (RemoteException ex) { 1309 throw new RuntimeException(ex); 1310 } 1311 mKeyGestureHandlerRecords.put(pid, record); 1312 for (int gestureType : keyGesturesToHandle) { 1313 mSupportedKeyGestureToPidMap.put(gestureType, pid); 1314 } 1315 } 1316 } 1317 1318 /** Unregister the key gesture event handler for a process. */ 1319 @BinderThread unregisterKeyGestureHandler(IKeyGestureHandler handler, int pid)1320 public void unregisterKeyGestureHandler(IKeyGestureHandler handler, int pid) { 1321 synchronized (mKeyGestureHandlerRecords) { 1322 KeyGestureHandlerRecord record = mKeyGestureHandlerRecords.get(pid); 1323 if (record == null) { 1324 throw new IllegalStateException("The calling process has no registered " 1325 + "KeyGestureHandler."); 1326 } 1327 if (record.mKeyGestureHandler.asBinder() != handler.asBinder()) { 1328 throw new IllegalStateException("The calling process has a different registered " 1329 + "KeyGestureHandler."); 1330 } 1331 record.mKeyGestureHandler.asBinder().unlinkToDeath(record, 0); 1332 onKeyGestureHandlerRemoved(pid); 1333 } 1334 } 1335 registerShortcutKey(long shortcutCode, IShortcutService shortcutKeyReceiver)1336 public void registerShortcutKey(long shortcutCode, IShortcutService shortcutKeyReceiver) 1337 throws RemoteException { 1338 mAppLaunchShortcutManager.registerShortcutKey(shortcutCode, shortcutKeyReceiver); 1339 } 1340 getBookmarks()1341 public List<InputGestureData> getBookmarks() { 1342 return mAppLaunchShortcutManager.getBookmarks(); 1343 } 1344 onKeyGestureHandlerRemoved(int pid)1345 private void onKeyGestureHandlerRemoved(int pid) { 1346 synchronized (mKeyGestureHandlerRecords) { 1347 mKeyGestureHandlerRecords.remove(pid); 1348 for (int i = mSupportedKeyGestureToPidMap.size() - 1; i >= 0; i--) { 1349 if (mSupportedKeyGestureToPidMap.valueAt(i) == pid) { 1350 mSupportedKeyGestureToPidMap.removeAt(i); 1351 } 1352 } 1353 } 1354 } 1355 persistInputGestures(int userId)1356 private void persistInputGestures(int userId) { 1357 synchronized (mInputDataStore) { 1358 final List<InputGestureData> inputGestureDataList = 1359 mInputGestureManager.getCustomInputGestures(userId, 1360 null); 1361 mInputDataStore.saveInputGestures(userId, inputGestureDataList); 1362 } 1363 } 1364 loadInputGestures(int userId)1365 private void loadInputGestures(int userId) { 1366 synchronized (mInputDataStore) { 1367 mInputGestureManager.removeAllCustomInputGestures(userId, null); 1368 final List<InputGestureData> inputGestureDataList = mInputDataStore.loadInputGestures( 1369 userId); 1370 for (final InputGestureData inputGestureData : inputGestureDataList) { 1371 mInputGestureManager.addCustomInputGesture(userId, inputGestureData); 1372 } 1373 } 1374 } 1375 1376 // A record of a registered key gesture event listener from one process. 1377 private class KeyGestureHandlerRecord implements IBinder.DeathRecipient { 1378 public final int mPid; 1379 public final IKeyGestureHandler mKeyGestureHandler; 1380 KeyGestureHandlerRecord(int pid, IKeyGestureHandler keyGestureHandler)1381 KeyGestureHandlerRecord(int pid, IKeyGestureHandler keyGestureHandler) { 1382 mPid = pid; 1383 mKeyGestureHandler = keyGestureHandler; 1384 } 1385 1386 @Override binderDied()1387 public void binderDied() { 1388 if (DEBUG) { 1389 Slog.d(TAG, "Key gesture event handler for pid " + mPid + " died."); 1390 } 1391 onKeyGestureHandlerRemoved(mPid); 1392 } 1393 handleKeyGesture(AidlKeyGestureEvent event, IBinder focusedToken)1394 public void handleKeyGesture(AidlKeyGestureEvent event, IBinder focusedToken) { 1395 try { 1396 mKeyGestureHandler.handleKeyGesture(event, focusedToken); 1397 } catch (RemoteException ex) { 1398 Slog.w(TAG, "Failed to send key gesture to process " + mPid 1399 + ", assuming it died.", ex); 1400 binderDied(); 1401 } 1402 } 1403 } 1404 1405 private class SettingsObserver extends ContentObserver { SettingsObserver(Handler handler)1406 private SettingsObserver(Handler handler) { 1407 super(handler); 1408 } 1409 observe()1410 private void observe() { 1411 ContentResolver resolver = mContext.getContentResolver(); 1412 resolver.registerContentObserver(Settings.Secure.getUriFor( 1413 Settings.Secure.VOLUME_HUSH_GESTURE), false, this, 1414 UserHandle.USER_ALL); 1415 resolver.registerContentObserver(Settings.Global.getUriFor( 1416 Settings.Global.KEY_CHORD_POWER_VOLUME_UP), false, this, 1417 UserHandle.USER_ALL); 1418 } 1419 1420 @Override onChange(boolean selfChange)1421 public void onChange(boolean selfChange) { 1422 initBehaviorsFromSettings(); 1423 } 1424 } 1425 1426 @Nullable getInputDevice(int deviceId)1427 private InputDevice getInputDevice(int deviceId) { 1428 InputManager inputManager = mContext.getSystemService(InputManager.class); 1429 return inputManager != null ? inputManager.getInputDevice(deviceId) : null; 1430 } 1431 createKeyGestureEvent(int deviceId, int[] keycodes, int modifierState, @KeyGestureEvent.KeyGestureType int gestureType, int action, int displayId, int flags, @Nullable AppLaunchData appLaunchData)1432 private AidlKeyGestureEvent createKeyGestureEvent(int deviceId, int[] keycodes, 1433 int modifierState, @KeyGestureEvent.KeyGestureType int gestureType, int action, 1434 int displayId, int flags, @Nullable AppLaunchData appLaunchData) { 1435 AidlKeyGestureEvent event = new AidlKeyGestureEvent(); 1436 event.deviceId = deviceId; 1437 event.keycodes = keycodes; 1438 event.modifierState = modifierState; 1439 event.gestureType = gestureType; 1440 event.action = action; 1441 event.displayId = displayId; 1442 event.flags = flags; 1443 if (appLaunchData != null) { 1444 if (appLaunchData instanceof AppLaunchData.CategoryData categoryData) { 1445 event.appLaunchCategory = categoryData.getCategory(); 1446 } else if (appLaunchData instanceof AppLaunchData.RoleData roleData) { 1447 event.appLaunchRole = roleData.getRole(); 1448 } else if (appLaunchData instanceof AppLaunchData.ComponentData componentData) { 1449 event.appLaunchPackageName = componentData.getPackageName(); 1450 event.appLaunchClassName = componentData.getClassName(); 1451 } else { 1452 throw new IllegalArgumentException("AppLaunchData type is invalid!"); 1453 } 1454 } 1455 return event; 1456 } 1457 getAccessibilityShortcutTimeout()1458 private long getAccessibilityShortcutTimeout() { 1459 synchronized (mUserLock) { 1460 final ViewConfiguration config = ViewConfiguration.get(mContext); 1461 final boolean hasDialogShown = Settings.Secure.getIntForUser( 1462 mContext.getContentResolver(), 1463 Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0, mCurrentUserId) != 0; 1464 final boolean skipTimeoutRestriction = 1465 Settings.Secure.getIntForUser(mContext.getContentResolver(), 1466 Settings.Secure.SKIP_ACCESSIBILITY_SHORTCUT_DIALOG_TIMEOUT_RESTRICTION, 1467 0, mCurrentUserId) != 0; 1468 1469 // If users manually set the volume key shortcut for any accessibility service, the 1470 // system would bypass the timeout restriction of the shortcut dialog. 1471 return hasDialogShown || skipTimeoutRestriction 1472 ? config.getAccessibilityShortcutKeyTimeoutAfterConfirmation() 1473 : config.getAccessibilityShortcutKeyTimeout(); 1474 } 1475 } 1476 dump(IndentingPrintWriter ipw)1477 public void dump(IndentingPrintWriter ipw) { 1478 ipw.println("KeyGestureController:"); 1479 ipw.increaseIndent(); 1480 ipw.println("mCurrentUserId = " + mCurrentUserId); 1481 ipw.println("mSystemPid = " + mSystemPid); 1482 ipw.println("mPendingMetaAction = " + mPendingMetaAction); 1483 ipw.println("mPendingCapsLockToggle = " + mPendingCapsLockToggle); 1484 ipw.println("mPendingHideRecentSwitcher = " + mPendingHideRecentSwitcher); 1485 ipw.println("mSearchKeyBehavior = " + mSearchKeyBehavior); 1486 ipw.println("mSettingsKeyBehavior = " + mSettingsKeyBehavior); 1487 ipw.println("mRingerToggleChord = " + mRingerToggleChord); 1488 ipw.println("mPowerVolUpBehavior = " + mPowerVolUpBehavior); 1489 ipw.print("mKeyGestureEventListenerRecords = {"); 1490 synchronized (mKeyGestureEventListenerRecords) { 1491 int size = mKeyGestureEventListenerRecords.size(); 1492 for (int i = 0; i < size; i++) { 1493 ipw.print(mKeyGestureEventListenerRecords.keyAt(i)); 1494 if (i < size - 1) { 1495 ipw.print(", "); 1496 } 1497 } 1498 } 1499 ipw.println("}"); 1500 synchronized (mKeyGestureHandlerRecords) { 1501 ipw.print("mKeyGestureHandlerRecords = {"); 1502 int size = mKeyGestureHandlerRecords.size(); 1503 for (int i = 0; i < size; i++) { 1504 int pid = mKeyGestureHandlerRecords.keyAt(i); 1505 ipw.print(pid); 1506 if (i < size - 1) { 1507 ipw.print(", "); 1508 } 1509 } 1510 ipw.println("}"); 1511 ipw.println("mSupportedKeyGestures = " + Arrays.toString( 1512 mSupportedKeyGestureToPidMap.copyKeys())); 1513 } 1514 1515 ipw.decreaseIndent(); 1516 ipw.println("Last handled KeyGestureEvents: "); 1517 ipw.increaseIndent(); 1518 for (KeyGestureEvent ev : mLastHandledEvents) { 1519 ipw.println(ev); 1520 } 1521 ipw.decreaseIndent(); 1522 mKeyCombinationManager.dump("", ipw); 1523 mAppLaunchShortcutManager.dump(ipw); 1524 mInputGestureManager.dump(ipw); 1525 } 1526 1527 @VisibleForTesting 1528 static class Injector { getAccessibilityShortcutController(Context context, Handler handler)1529 AccessibilityShortcutController getAccessibilityShortcutController(Context context, 1530 Handler handler) { 1531 return new AccessibilityShortcutController(context, handler, UserHandle.USER_SYSTEM); 1532 } 1533 } 1534 } 1535