• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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