summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Vaibhav Devmurari <vdevmurari@google.com> 2024-11-04 19:09:05 +0000
committer Vaibhav Devmurari <vdevmurari@google.com> 2024-11-04 19:09:05 +0000
commit3821b8afb6eb9a060eac8f546ae313cafaeb9cd0 (patch)
tree96a060cbcdfe6b26624e4388001551d0ea124932
parent695314eb4f8090f03be042ac6be2f8f79cdd9c50 (diff)
Block addition of custom shortcuts
- If overlapping with system shortcuts - If ovelapping with bookmarks - If no modifierState provided for key based shortcut - If using a system keycode for key based shortcut DD: go/customizable_shortcuts PRD: go/custom-kb-shortcuts Bug: 365064144 Test: atest InputTests Flag: com.android.hardware.input.enable_customizable_input_gestures Change-Id: I69dd162f3318a84123b748d5ee5b9074844d8790
-rw-r--r--services/core/java/com/android/server/input/InputGestureManager.java291
-rw-r--r--services/core/java/com/android/server/input/KeyGestureController.java293
-rw-r--r--tests/Input/src/com/android/server/input/InputGestureManagerTests.kt3
-rw-r--r--tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt730
4 files changed, 648 insertions, 669 deletions
diff --git a/services/core/java/com/android/server/input/InputGestureManager.java b/services/core/java/com/android/server/input/InputGestureManager.java
index f4bd402e63a2..cf1cdaf55e5c 100644
--- a/services/core/java/com/android/server/input/InputGestureManager.java
+++ b/services/core/java/com/android/server/input/InputGestureManager.java
@@ -16,11 +16,21 @@
package com.android.server.input;
+import static android.hardware.input.InputGestureData.createKeyTrigger;
+import static com.android.hardware.input.Flags.keyboardA11yShortcutControl;
+import static com.android.server.flags.Flags.newBugreportKeyboardShortcut;
+import static com.android.window.flags.Flags.enableMoveToNextDisplayShortcut;
+import static com.android.window.flags.Flags.enableTaskResizingKeyboardShortcuts;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.content.Context;
import android.hardware.input.InputGestureData;
import android.hardware.input.InputManager;
+import android.hardware.input.InputSettings;
+import android.hardware.input.KeyGestureEvent;
+import android.os.SystemProperties;
import android.util.IndentingPrintWriter;
import android.util.SparseArray;
import android.view.KeyEvent;
@@ -29,15 +39,17 @@ import com.android.internal.annotations.GuardedBy;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.Set;
/**
* A thread-safe component of {@link InputManagerService} responsible for managing pre-defined input
* gestures and custom gestures defined by other system components using Input APIs.
*
- * TODO(b/365064144): Add implementation to persist data, identify clashes with existing shortcuts.
+ * TODO(b/365064144): Add implementation to persist data.
*
*/
final class InputGestureManager {
@@ -47,13 +59,242 @@ final class InputGestureManager {
KeyEvent.META_CTRL_ON | KeyEvent.META_ALT_ON | KeyEvent.META_SHIFT_ON
| KeyEvent.META_META_ON;
- @GuardedBy("mCustomInputGestures")
+ private final Context mContext;
+
+ private static final Object mGestureLock = new Object();
+ @GuardedBy("mGestureLock")
private final SparseArray<Map<InputGestureData.Trigger, InputGestureData>>
mCustomInputGestures = new SparseArray<>();
+ @GuardedBy("mGestureLock")
+ private final Map<InputGestureData.Trigger, InputGestureData> mSystemShortcuts =
+ new HashMap<>();
+
+ @GuardedBy("mGestureLock")
+ private final Set<InputGestureData.Trigger> mBlockListedTriggers = new HashSet<>(Set.of(
+ createKeyTrigger(KeyEvent.KEYCODE_TAB, KeyEvent.META_ALT_ON),
+ createKeyTrigger(KeyEvent.KEYCODE_TAB, KeyEvent.META_ALT_ON | KeyEvent.META_SHIFT_ON),
+ createKeyTrigger(KeyEvent.KEYCODE_SPACE, KeyEvent.META_CTRL_ON),
+ createKeyTrigger(KeyEvent.KEYCODE_SPACE,
+ KeyEvent.META_CTRL_ON | KeyEvent.META_SHIFT_ON),
+ createKeyTrigger(KeyEvent.KEYCODE_Z,
+ KeyEvent.META_CTRL_ON | KeyEvent.META_ALT_ON),
+ createKeyTrigger(KeyEvent.KEYCODE_A, KeyEvent.META_CTRL_ON),
+ createKeyTrigger(KeyEvent.KEYCODE_C, KeyEvent.META_CTRL_ON),
+ createKeyTrigger(KeyEvent.KEYCODE_V, KeyEvent.META_CTRL_ON),
+ createKeyTrigger(KeyEvent.KEYCODE_X, KeyEvent.META_CTRL_ON),
+ createKeyTrigger(KeyEvent.KEYCODE_Z, KeyEvent.META_CTRL_ON),
+ createKeyTrigger(KeyEvent.KEYCODE_Y, KeyEvent.META_CTRL_ON)
+ ));
+
+ public InputGestureManager(Context context) {
+ mContext = context;
+ }
+
+ public void systemRunning() {
+ initSystemShortcuts();
+ blockListBookmarkedTriggers();
+ }
+
+ private void initSystemShortcuts() {
+ // Initialize all system shortcuts
+ List<InputGestureData> systemShortcuts = new ArrayList<>(List.of(
+ createKeyGesture(
+ KeyEvent.KEYCODE_A,
+ KeyEvent.META_META_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_ASSISTANT
+ ),
+ createKeyGesture(
+ KeyEvent.KEYCODE_H,
+ KeyEvent.META_META_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_HOME
+ ),
+ createKeyGesture(
+ KeyEvent.KEYCODE_ENTER,
+ KeyEvent.META_META_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_HOME
+ ),
+ createKeyGesture(
+ KeyEvent.KEYCODE_I,
+ KeyEvent.META_META_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS
+ ),
+ createKeyGesture(
+ KeyEvent.KEYCODE_L,
+ KeyEvent.META_META_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_LOCK_SCREEN
+ ),
+ createKeyGesture(
+ KeyEvent.KEYCODE_N,
+ KeyEvent.META_META_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL
+ ),
+ createKeyGesture(
+ KeyEvent.KEYCODE_N,
+ KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_NOTES
+ ),
+ createKeyGesture(
+ KeyEvent.KEYCODE_S,
+ KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_TAKE_SCREENSHOT
+ ),
+ createKeyGesture(
+ KeyEvent.KEYCODE_DEL,
+ KeyEvent.META_META_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_BACK
+ ),
+ createKeyGesture(
+ KeyEvent.KEYCODE_ESCAPE,
+ KeyEvent.META_META_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_BACK
+ ),
+ createKeyGesture(
+ KeyEvent.KEYCODE_DPAD_UP,
+ KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION
+ ),
+ createKeyGesture(
+ KeyEvent.KEYCODE_DPAD_DOWN,
+ KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_DESKTOP_MODE
+ ),
+ createKeyGesture(
+ KeyEvent.KEYCODE_DPAD_LEFT,
+ KeyEvent.META_META_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_BACK
+ ),
+ createKeyGesture(
+ KeyEvent.KEYCODE_DPAD_LEFT,
+ KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_LEFT
+ ),
+ createKeyGesture(
+ KeyEvent.KEYCODE_DPAD_LEFT,
+ KeyEvent.META_META_ON | KeyEvent.META_ALT_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_LEFT
+ ),
+ createKeyGesture(
+ KeyEvent.KEYCODE_DPAD_RIGHT,
+ KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_RIGHT
+ ),
+ createKeyGesture(
+ KeyEvent.KEYCODE_DPAD_RIGHT,
+ KeyEvent.META_META_ON | KeyEvent.META_ALT_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_RIGHT
+ ),
+ createKeyGesture(
+ KeyEvent.KEYCODE_SLASH,
+ KeyEvent.META_META_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER
+ ),
+ createKeyGesture(
+ KeyEvent.KEYCODE_TAB,
+ KeyEvent.META_META_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS
+ )
+ ));
+ if (newBugreportKeyboardShortcut() && "1".equals(SystemProperties.get("ro.debuggable"))) {
+ systemShortcuts.add(createKeyGesture(
+ KeyEvent.KEYCODE_DEL,
+ KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT
+ ));
+ }
+ if (enableMoveToNextDisplayShortcut()) {
+ systemShortcuts.add(createKeyGesture(
+ KeyEvent.KEYCODE_D,
+ KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_MOVE_TO_NEXT_DISPLAY
+ ));
+ }
+ if (keyboardA11yShortcutControl()) {
+ systemShortcuts.add(createKeyGesture(
+ KeyEvent.KEYCODE_T,
+ KeyEvent.META_META_ON | KeyEvent.META_ALT_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_TALKBACK
+ ));
+ if (InputSettings.isAccessibilityBounceKeysFeatureEnabled()) {
+ systemShortcuts.add(createKeyGesture(
+ KeyEvent.KEYCODE_3,
+ KeyEvent.META_META_ON | KeyEvent.META_ALT_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_BOUNCE_KEYS
+ ));
+ }
+ if (InputSettings.isAccessibilityMouseKeysFeatureFlagEnabled()) {
+ systemShortcuts.add(createKeyGesture(
+ KeyEvent.KEYCODE_4,
+ KeyEvent.META_META_ON | KeyEvent.META_ALT_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MOUSE_KEYS
+ ));
+ }
+ if (InputSettings.isAccessibilityStickyKeysFeatureEnabled()) {
+ systemShortcuts.add(createKeyGesture(
+ KeyEvent.KEYCODE_5,
+ KeyEvent.META_META_ON | KeyEvent.META_ALT_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_STICKY_KEYS
+ ));
+ }
+ if (InputSettings.isAccessibilitySlowKeysFeatureFlagEnabled()) {
+ systemShortcuts.add(createKeyGesture(
+ KeyEvent.KEYCODE_6,
+ KeyEvent.META_META_ON | KeyEvent.META_ALT_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_SLOW_KEYS
+ ));
+ }
+ if (enableTaskResizingKeyboardShortcuts()) {
+ systemShortcuts.add(createKeyGesture(
+ KeyEvent.KEYCODE_LEFT_BRACKET,
+ KeyEvent.META_ALT_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW
+ ));
+ systemShortcuts.add(createKeyGesture(
+ KeyEvent.KEYCODE_RIGHT_BRACKET,
+ KeyEvent.META_ALT_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW
+ ));
+ systemShortcuts.add(createKeyGesture(
+ KeyEvent.KEYCODE_EQUALS,
+ KeyEvent.META_ALT_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW
+ ));
+ systemShortcuts.add(createKeyGesture(
+ KeyEvent.KEYCODE_MINUS,
+ KeyEvent.META_ALT_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE
+ ));
+ }
+ }
+ synchronized (mGestureLock) {
+ for (InputGestureData systemShortcut : systemShortcuts) {
+ mSystemShortcuts.put(systemShortcut.getTrigger(), systemShortcut);
+ }
+ }
+ }
+
+ private void blockListBookmarkedTriggers() {
+ synchronized (mGestureLock) {
+ InputManager im = Objects.requireNonNull(mContext.getSystemService(InputManager.class));
+ for (InputGestureData bookmark : im.getAppLaunchBookmarks()) {
+ mBlockListedTriggers.add(bookmark.getTrigger());
+ }
+ }
+ }
+
@InputManager.CustomInputGestureResult
public int addCustomInputGesture(int userId, InputGestureData newGesture) {
- synchronized (mCustomInputGestures) {
+ synchronized (mGestureLock) {
+ if (mBlockListedTriggers.contains(newGesture.getTrigger())
+ || mSystemShortcuts.containsKey(newGesture.getTrigger())) {
+ return InputManager.CUSTOM_INPUT_GESTURE_RESULT_ERROR_RESERVED_GESTURE;
+ }
+ if (newGesture.getTrigger() instanceof InputGestureData.KeyTrigger keyTrigger) {
+ if (KeyEvent.isModifierKey(keyTrigger.getKeycode()) ||
+ KeyEvent.isSystemKey(keyTrigger.getKeycode())) {
+ return InputManager.CUSTOM_INPUT_GESTURE_RESULT_ERROR_RESERVED_GESTURE;
+ }
+ }
if (!mCustomInputGestures.contains(userId)) {
mCustomInputGestures.put(userId, new HashMap<>());
}
@@ -69,7 +310,7 @@ final class InputGestureManager {
@InputManager.CustomInputGestureResult
public int removeCustomInputGesture(int userId, InputGestureData data) {
- synchronized (mCustomInputGestures) {
+ synchronized (mGestureLock) {
if (!mCustomInputGestures.contains(userId)) {
return InputManager.CUSTOM_INPUT_GESTURE_RESULT_ERROR_DOES_NOT_EXIST;
}
@@ -88,14 +329,14 @@ final class InputGestureManager {
}
public void removeAllCustomInputGestures(int userId) {
- synchronized (mCustomInputGestures) {
+ synchronized (mGestureLock) {
mCustomInputGestures.remove(userId);
}
}
@NonNull
public List<InputGestureData> getCustomInputGestures(int userId) {
- synchronized (mCustomInputGestures) {
+ synchronized (mGestureLock) {
if (!mCustomInputGestures.contains(userId)) {
return List.of();
}
@@ -109,7 +350,7 @@ final class InputGestureManager {
if (keyCode == KeyEvent.KEYCODE_UNKNOWN) {
return null;
}
- synchronized (mCustomInputGestures) {
+ synchronized (mGestureLock) {
Map<InputGestureData.Trigger, InputGestureData> customGestures =
mCustomInputGestures.get(userId);
if (customGestures == null) {
@@ -120,10 +361,44 @@ final class InputGestureManager {
}
}
+ @Nullable
+ public InputGestureData getSystemShortcutForKeyEvent(KeyEvent event) {
+ final int keyCode = event.getKeyCode();
+ if (keyCode == KeyEvent.KEYCODE_UNKNOWN) {
+ return null;
+ }
+ synchronized (mGestureLock) {
+ int modifierState = event.getMetaState() & KEY_GESTURE_META_MASK;
+ return mSystemShortcuts.get(InputGestureData.createKeyTrigger(keyCode, modifierState));
+ }
+ }
+
+ private static InputGestureData createKeyGesture(int keycode, int modifierState,
+ int keyGestureType) {
+ return new InputGestureData.Builder()
+ .setTrigger(createKeyTrigger(keycode, modifierState))
+ .setKeyGestureType(keyGestureType)
+ .build();
+ }
+
public void dump(IndentingPrintWriter ipw) {
ipw.println("InputGestureManager:");
ipw.increaseIndent();
- synchronized (mCustomInputGestures) {
+ synchronized (mGestureLock) {
+ ipw.println("System Shortcuts:");
+ ipw.increaseIndent();
+ for (InputGestureData systemShortcut : mSystemShortcuts.values()) {
+ ipw.println(systemShortcut);
+ }
+ ipw.decreaseIndent();
+ ipw.println("Blocklisted Triggers:");
+ ipw.increaseIndent();
+ for (InputGestureData.Trigger blocklistedTrigger : mBlockListedTriggers) {
+ ipw.println(blocklistedTrigger);
+ }
+ ipw.decreaseIndent();
+ ipw.println("Custom Gestures:");
+ ipw.increaseIndent();
int size = mCustomInputGestures.size();
for (int i = 0; i < size; i++) {
Map<InputGestureData.Trigger, InputGestureData> customGestures =
diff --git a/services/core/java/com/android/server/input/KeyGestureController.java b/services/core/java/com/android/server/input/KeyGestureController.java
index 5a3707dea1db..bf99fe858a9d 100644
--- a/services/core/java/com/android/server/input/KeyGestureController.java
+++ b/services/core/java/com/android/server/input/KeyGestureController.java
@@ -20,12 +20,8 @@ import static android.content.pm.PackageManager.FEATURE_LEANBACK;
import static android.content.pm.PackageManager.FEATURE_WATCH;
import static android.view.WindowManagerPolicyConstants.FLAG_INTERACTIVE;
-import static com.android.hardware.input.Flags.keyboardA11yShortcutControl;
import static com.android.hardware.input.Flags.useKeyGestureEventHandler;
import static com.android.hardware.input.Flags.useKeyGestureEventHandlerMultiPressGestures;
-import static com.android.server.flags.Flags.newBugreportKeyboardShortcut;
-import static com.android.window.flags.Flags.enableMoveToNextDisplayShortcut;
-import static com.android.window.flags.Flags.enableTaskResizingKeyboardShortcuts;
import android.annotation.BinderThread;
import android.annotation.MainThread;
@@ -121,7 +117,7 @@ final class KeyGestureController {
private final KeyCombinationManager mKeyCombinationManager;
private final SettingsObserver mSettingsObserver;
private final AppLaunchShortcutManager mAppLaunchShortcutManager;
- private final InputGestureManager mInputGestureManager = new InputGestureManager();
+ private final InputGestureManager mInputGestureManager;
private static final Object mUserLock = new Object();
@UserIdInt
@GuardedBy("mUserLock")
@@ -133,7 +129,6 @@ final class KeyGestureController {
private boolean mPendingHideRecentSwitcher;
// Platform behaviors
- private boolean mEnableBugReportKeyboardShortcut;
private boolean mHasFeatureWatch;
private boolean mHasFeatureLeanback;
@@ -181,13 +176,12 @@ final class KeyGestureController {
mKeyCombinationManager = new KeyCombinationManager(mHandler);
mSettingsObserver = new SettingsObserver(mHandler);
mAppLaunchShortcutManager = new AppLaunchShortcutManager(mContext);
+ mInputGestureManager = new InputGestureManager(mContext);
initBehaviors();
initKeyCombinationRules();
}
private void initBehaviors() {
- mEnableBugReportKeyboardShortcut = "1".equals(SystemProperties.get("ro.debuggable"));
-
PackageManager pm = mContext.getPackageManager();
mHasFeatureWatch = pm.hasSystemFeature(FEATURE_WATCH);
mHasFeatureLeanback = pm.hasSystemFeature(FEATURE_LEANBACK);
@@ -441,6 +435,7 @@ final class KeyGestureController {
public void systemRunning() {
mSettingsObserver.observe();
mAppLaunchShortcutManager.systemRunning();
+ mInputGestureManager.systemRunning();
}
public boolean interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
@@ -517,6 +512,7 @@ final class KeyGestureController {
mPendingCapsLockToggle = false;
}
+ // Handle App launch shortcuts
AppLaunchShortcutManager.InterceptKeyResult result = mAppLaunchShortcutManager.interceptKey(
event);
if (result.consumed()) {
@@ -529,15 +525,21 @@ final class KeyGestureController {
focusedToken, /* flags = */0, result.appLaunchData());
}
+ // Handle system shortcuts
+ if (firstDown) {
+ InputGestureData systemShortcut = mInputGestureManager.getSystemShortcutForKeyEvent(
+ event);
+ if (systemShortcut != null) {
+ return handleKeyGesture(deviceId, new int[]{keyCode}, metaState,
+ systemShortcut.getAction().keyGestureType(),
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE,
+ displayId, focusedToken, /* flags = */0,
+ systemShortcut.getAction().appLaunchData());
+ }
+ }
+
+ // Handle system keys
switch (keyCode) {
- case KeyEvent.KEYCODE_A:
- if (firstDown && event.isMetaPressed()) {
- return handleKeyGesture(deviceId, new int[]{keyCode}, KeyEvent.META_META_ON,
- KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_ASSISTANT,
- KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0, /* appLaunchData = */null);
- }
- break;
case KeyEvent.KEYCODE_RECENT_APPS:
if (firstDown) {
handleKeyGesture(deviceId, new int[]{keyCode}, /* modifierState = */0,
@@ -560,257 +562,6 @@ final class KeyGestureController {
/* appLaunchData = */null);
}
return true;
- case KeyEvent.KEYCODE_H:
- case KeyEvent.KEYCODE_ENTER:
- if (firstDown && event.isMetaPressed()) {
- return handleKeyGesture(deviceId, new int[]{keyCode}, KeyEvent.META_META_ON,
- KeyGestureEvent.KEY_GESTURE_TYPE_HOME,
- KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0, /* appLaunchData = */null);
- }
- break;
- case KeyEvent.KEYCODE_I:
- if (firstDown && event.isMetaPressed()) {
- return handleKeyGesture(deviceId, new int[]{keyCode}, KeyEvent.META_META_ON,
- KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS,
- KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0, /* appLaunchData = */null);
- }
- break;
- case KeyEvent.KEYCODE_L:
- if (firstDown && event.isMetaPressed()) {
- return handleKeyGesture(deviceId, new int[]{keyCode}, KeyEvent.META_META_ON,
- KeyGestureEvent.KEY_GESTURE_TYPE_LOCK_SCREEN,
- KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0, /* appLaunchData = */null);
- }
- break;
- case KeyEvent.KEYCODE_N:
- if (firstDown && event.isMetaPressed()) {
- if (event.isCtrlPressed()) {
- return handleKeyGesture(deviceId, new int[]{keyCode},
- KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON,
- KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_NOTES,
- KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0, /* appLaunchData = */null);
- } else {
- return handleKeyGesture(deviceId, new int[]{keyCode},
- KeyEvent.META_META_ON,
- KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL,
- KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0, /* appLaunchData = */null);
- }
- }
- break;
- case KeyEvent.KEYCODE_S:
- if (firstDown && event.isMetaPressed() && event.isCtrlPressed()) {
- return handleKeyGesture(deviceId, new int[]{keyCode},
- KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON,
- KeyGestureEvent.KEY_GESTURE_TYPE_TAKE_SCREENSHOT,
- KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0, /* appLaunchData = */null);
- }
- break;
- case KeyEvent.KEYCODE_T:
- if (keyboardA11yShortcutControl()) {
- if (firstDown && event.isMetaPressed() && event.isAltPressed()) {
- return handleKeyGesture(deviceId, new int[]{keyCode},
- KeyEvent.META_META_ON | KeyEvent.META_ALT_ON,
- KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_TALKBACK,
- KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0, /* appLaunchData = */null);
- }
- }
- break;
- case KeyEvent.KEYCODE_3:
- if (InputSettings.isAccessibilityBounceKeysFeatureEnabled()
- && keyboardA11yShortcutControl()) {
- if (firstDown && event.isMetaPressed() && event.isAltPressed()) {
- return handleKeyGesture(deviceId, new int[]{keyCode},
- KeyEvent.META_META_ON | KeyEvent.META_ALT_ON,
- KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_BOUNCE_KEYS,
- KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0, /* appLaunchData = */null);
- }
- }
- break;
- case KeyEvent.KEYCODE_4:
- if (InputSettings.isAccessibilityMouseKeysFeatureFlagEnabled()
- && keyboardA11yShortcutControl()) {
- if (firstDown && event.isMetaPressed() && event.isAltPressed()) {
- return handleKeyGesture(deviceId, new int[]{keyCode},
- KeyEvent.META_META_ON | KeyEvent.META_ALT_ON,
- KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MOUSE_KEYS,
- KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0, /* appLaunchData = */null);
- }
- }
- break;
- case KeyEvent.KEYCODE_5:
- if (InputSettings.isAccessibilityStickyKeysFeatureEnabled()
- && keyboardA11yShortcutControl()) {
- if (firstDown && event.isMetaPressed() && event.isAltPressed()) {
- return handleKeyGesture(deviceId, new int[]{keyCode},
- KeyEvent.META_META_ON | KeyEvent.META_ALT_ON,
- KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_STICKY_KEYS,
- KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0, /* appLaunchData = */null);
- }
- }
- break;
- case KeyEvent.KEYCODE_6:
- if (InputSettings.isAccessibilitySlowKeysFeatureFlagEnabled()
- && keyboardA11yShortcutControl()) {
- if (firstDown && event.isMetaPressed() && event.isAltPressed()) {
- return handleKeyGesture(deviceId, new int[]{keyCode},
- KeyEvent.META_META_ON | KeyEvent.META_ALT_ON,
- KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_SLOW_KEYS,
- KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0, /* appLaunchData = */null);
- }
- }
- break;
- case KeyEvent.KEYCODE_DEL:
- if (newBugreportKeyboardShortcut()) {
- if (firstDown && mEnableBugReportKeyboardShortcut && event.isMetaPressed()
- && event.isCtrlPressed()) {
- return handleKeyGesture(deviceId, new int[]{keyCode},
- KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON,
- KeyGestureEvent.KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT,
- KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0, /* appLaunchData = */null);
- }
- }
- // fall through
- case KeyEvent.KEYCODE_ESCAPE:
- if (firstDown && event.isMetaPressed()) {
- return handleKeyGesture(deviceId, new int[]{keyCode}, KeyEvent.META_META_ON,
- KeyGestureEvent.KEY_GESTURE_TYPE_BACK,
- KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0, /* appLaunchData = */null);
- }
- break;
- case KeyEvent.KEYCODE_DPAD_UP:
- if (firstDown && event.isMetaPressed() && event.isCtrlPressed()) {
- return handleKeyGesture(deviceId, new int[]{keyCode},
- KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON,
- KeyGestureEvent.KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION,
- KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0, /* appLaunchData = */null);
- }
- break;
- case KeyEvent.KEYCODE_DPAD_DOWN:
- if (firstDown && event.isMetaPressed() && event.isCtrlPressed()) {
- return handleKeyGesture(deviceId, new int[]{keyCode},
- KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON,
- KeyGestureEvent.KEY_GESTURE_TYPE_DESKTOP_MODE,
- KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0, /* appLaunchData = */null);
- }
- break;
- case KeyEvent.KEYCODE_DPAD_LEFT:
- if (firstDown && event.isMetaPressed()) {
- if (event.isCtrlPressed()) {
- return handleKeyGesture(deviceId, new int[]{keyCode},
- KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON,
- KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_LEFT,
- KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0, /* appLaunchData = */null);
- } else if (event.isAltPressed()) {
- return handleKeyGesture(deviceId, new int[]{keyCode},
- KeyEvent.META_META_ON | KeyEvent.META_ALT_ON,
- KeyGestureEvent.KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_LEFT,
- KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0, /* appLaunchData = */null);
- } else {
- return handleKeyGesture(deviceId, new int[]{keyCode},
- KeyEvent.META_META_ON,
- KeyGestureEvent.KEY_GESTURE_TYPE_BACK,
- KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0, /* appLaunchData = */null);
- }
- }
- break;
- case KeyEvent.KEYCODE_DPAD_RIGHT:
- if (firstDown && event.isMetaPressed()) {
- if (event.isCtrlPressed()) {
- return handleKeyGesture(deviceId, new int[]{keyCode},
- KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON,
- KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_RIGHT,
- KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0, /* appLaunchData = */null);
- } else if (event.isAltPressed()) {
- return handleKeyGesture(deviceId, new int[]{keyCode},
- KeyEvent.META_META_ON | KeyEvent.META_ALT_ON,
- KeyGestureEvent.KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_RIGHT,
- KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0, /* appLaunchData = */null);
- }
- }
- break;
- case KeyEvent.KEYCODE_D:
- if (enableMoveToNextDisplayShortcut()) {
- if (firstDown && event.isMetaPressed() && event.isCtrlPressed()) {
- return handleKeyGesture(deviceId, new int[]{keyCode},
- KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON,
- KeyGestureEvent.KEY_GESTURE_TYPE_MOVE_TO_NEXT_DISPLAY,
- KeyGestureEvent.ACTION_GESTURE_COMPLETE,
- displayId, focusedToken, /* flags = */0, /* appLaunchData = */null);
- }
- }
- break;
- case KeyEvent.KEYCODE_LEFT_BRACKET:
- if (enableTaskResizingKeyboardShortcuts()) {
- if (firstDown && event.isAltPressed()) {
- return handleKeyGesture(deviceId, new int[]{keyCode},
- KeyEvent.META_ALT_ON,
- KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW,
- KeyGestureEvent.ACTION_GESTURE_COMPLETE,
- displayId, focusedToken, /* flags = */0, /* appLaunchData = */null);
- }
- }
- break;
- case KeyEvent.KEYCODE_RIGHT_BRACKET:
- if (enableTaskResizingKeyboardShortcuts()) {
- if (firstDown && event.isAltPressed()) {
- return handleKeyGesture(deviceId, new int[]{keyCode},
- KeyEvent.META_ALT_ON,
- KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW,
- KeyGestureEvent.ACTION_GESTURE_COMPLETE,
- displayId, focusedToken, /* flags = */0, /* appLaunchData = */null);
- }
- }
- break;
- case KeyEvent.KEYCODE_EQUALS:
- if (enableTaskResizingKeyboardShortcuts()) {
- if (firstDown && event.isAltPressed()) {
- return handleKeyGesture(deviceId, new int[]{keyCode},
- KeyEvent.META_ALT_ON,
- KeyGestureEvent.KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW,
- KeyGestureEvent.ACTION_GESTURE_COMPLETE,
- displayId, focusedToken, /* flags = */0, /* appLaunchData = */null);
- }
- }
- break;
- case KeyEvent.KEYCODE_MINUS:
- if (enableTaskResizingKeyboardShortcuts()) {
- if (firstDown && event.isAltPressed()) {
- return handleKeyGesture(deviceId, new int[]{keyCode},
- KeyEvent.META_ALT_ON,
- KeyGestureEvent.KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE,
- KeyGestureEvent.ACTION_GESTURE_COMPLETE,
- displayId, focusedToken, /* flags = */0, /* appLaunchData = */null);
- }
- }
- break;
- case KeyEvent.KEYCODE_SLASH:
- if (firstDown && event.isMetaPressed()) {
- return handleKeyGesture(deviceId, new int[]{keyCode}, KeyEvent.META_META_ON,
- KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER,
- KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0, /* appLaunchData = */null);
- }
- break;
case KeyEvent.KEYCODE_BRIGHTNESS_UP:
case KeyEvent.KEYCODE_BRIGHTNESS_DOWN:
if (down) {
@@ -954,12 +705,7 @@ final class KeyGestureController {
return true;
case KeyEvent.KEYCODE_TAB:
if (firstDown) {
- if (event.isMetaPressed()) {
- return handleKeyGesture(deviceId, new int[]{keyCode}, KeyEvent.META_META_ON,
- KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS,
- KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0, /* appLaunchData = */null);
- } else if (!mPendingHideRecentSwitcher) {
+ if (!mPendingHideRecentSwitcher) {
final int shiftlessModifiers =
event.getModifiers() & ~KeyEvent.META_SHIFT_MASK;
if (KeyEvent.metaStateHasModifiers(
@@ -1020,6 +766,7 @@ final class KeyGestureController {
return true;
}
+ // Handle custom shortcuts
if (firstDown) {
InputGestureData customGesture;
synchronized (mUserLock) {
diff --git a/tests/Input/src/com/android/server/input/InputGestureManagerTests.kt b/tests/Input/src/com/android/server/input/InputGestureManagerTests.kt
index 01c56b7148cd..862886ce69d2 100644
--- a/tests/Input/src/com/android/server/input/InputGestureManagerTests.kt
+++ b/tests/Input/src/com/android/server/input/InputGestureManagerTests.kt
@@ -21,6 +21,7 @@ import android.hardware.input.InputManager
import android.hardware.input.KeyGestureEvent
import android.platform.test.annotations.Presubmit
import android.view.KeyEvent
+import androidx.test.core.app.ApplicationProvider
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
@@ -42,7 +43,7 @@ class InputGestureManagerTests {
@Before
fun setup() {
- inputGestureManager = InputGestureManager()
+ inputGestureManager = InputGestureManager(ApplicationProvider.getApplicationContext())
}
@Test
diff --git a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
index fc69a07afcdb..6c9f764bbdee 100644
--- a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
+++ b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
@@ -37,7 +37,6 @@ import android.os.Process
import android.os.SystemClock
import android.os.SystemProperties
import android.os.test.TestLooper
-import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.platform.test.annotations.Presubmit
import android.platform.test.flag.junit.SetFlagsRule
@@ -123,6 +122,7 @@ class KeyGestureControllerTests {
private var currentPid = 0
private lateinit var context: Context
+ private lateinit var keyGestureController: KeyGestureController
private lateinit var inputManagerGlobalSession: InputManagerGlobal.TestSession
private lateinit var testLooper: TestLooper
private var events = mutableListOf<KeyGestureEvent>()
@@ -144,6 +144,7 @@ class KeyGestureControllerTests {
}
private fun setupBehaviors() {
+ Mockito.`when`(SystemProperties.get("ro.debuggable")).thenReturn("1")
Mockito.`when`(resources.getBoolean(R.bool.config_enableScreenshotChord)).thenReturn(true)
val testBookmarks: XmlResourceParser = context.resources.getXml(
com.android.test.input.R.xml.bookmarks
@@ -172,7 +173,14 @@ class KeyGestureControllerTests {
ExtendedMockito.`when`(KeyCharacterMap.load(Mockito.anyInt())).thenReturn(kcm)
}
- private fun notifyHomeGestureCompleted(keyGestureController: KeyGestureController) {
+ private fun setupKeyGestureController() {
+ keyGestureController = KeyGestureController(context, testLooper.looper)
+ Mockito.`when`(iInputManager.getAppLaunchBookmarks())
+ .thenReturn(keyGestureController.appLaunchBookmarks)
+ keyGestureController.systemRunning()
+ }
+
+ private fun notifyHomeGestureCompleted() {
keyGestureController.notifyKeyGestureCompleted(
DEVICE_ID, intArrayOf(KeyEvent.KEYCODE_H),
KeyEvent.META_META_ON or KeyEvent.META_META_LEFT_ON,
@@ -182,12 +190,12 @@ class KeyGestureControllerTests {
@Test
fun testKeyGestureEvent_registerUnregisterListener() {
- val keyGestureController = KeyGestureController(context, testLooper.looper)
+ setupKeyGestureController()
val listener = KeyGestureEventListener()
// Register key gesture event listener
keyGestureController.registerKeyGestureEventListener(listener, 0)
- notifyHomeGestureCompleted(keyGestureController)
+ notifyHomeGestureCompleted()
testLooper.dispatchAll()
assertEquals(
"Listener should get callbacks on key gesture event completed",
@@ -203,7 +211,7 @@ class KeyGestureControllerTests {
// Unregister listener
events.clear()
keyGestureController.unregisterKeyGestureEventListener(listener, 0)
- notifyHomeGestureCompleted(keyGestureController)
+ notifyHomeGestureCompleted()
testLooper.dispatchAll()
assertEquals(
"Listener should not get callback after being unregistered",
@@ -214,7 +222,7 @@ class KeyGestureControllerTests {
@Test
fun testKeyGestureEvent_multipleGestureHandlers() {
- val keyGestureController = KeyGestureController(context, testLooper.looper)
+ setupKeyGestureController()
// Set up two callbacks.
var callbackCount1 = 0
@@ -278,7 +286,7 @@ class KeyGestureControllerTests {
}
@Keep
- private fun keyGestureEventHandlerTestArguments(): Array<TestData> {
+ private fun systemGesturesTestArguments(): Array<TestData> {
return arrayOf(
TestData(
"META + A -> Launch Assistant",
@@ -289,25 +297,6 @@ class KeyGestureControllerTests {
intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
),
TestData(
- "RECENT_APPS -> Show Overview",
- intArrayOf(KeyEvent.KEYCODE_RECENT_APPS),
- KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS,
- intArrayOf(KeyEvent.KEYCODE_RECENT_APPS),
- 0,
- intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
- ),
- TestData(
- "APP_SWITCH -> App Switch",
- intArrayOf(KeyEvent.KEYCODE_APP_SWITCH),
- KeyGestureEvent.KEY_GESTURE_TYPE_APP_SWITCH,
- intArrayOf(KeyEvent.KEYCODE_APP_SWITCH),
- 0,
- intArrayOf(
- KeyGestureEvent.ACTION_GESTURE_START,
- KeyGestureEvent.ACTION_GESTURE_COMPLETE
- )
- ),
- TestData(
"META + H -> Go Home",
intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_H),
KeyGestureEvent.KEY_GESTURE_TYPE_HOME,
@@ -476,94 +465,6 @@ class KeyGestureControllerTests {
intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
),
TestData(
- "BRIGHTNESS_UP -> Brightness Up",
- intArrayOf(KeyEvent.KEYCODE_BRIGHTNESS_UP),
- KeyGestureEvent.KEY_GESTURE_TYPE_BRIGHTNESS_UP,
- intArrayOf(KeyEvent.KEYCODE_BRIGHTNESS_UP),
- 0,
- intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
- ),
- TestData(
- "BRIGHTNESS_DOWN -> Brightness Down",
- intArrayOf(KeyEvent.KEYCODE_BRIGHTNESS_DOWN),
- KeyGestureEvent.KEY_GESTURE_TYPE_BRIGHTNESS_DOWN,
- intArrayOf(KeyEvent.KEYCODE_BRIGHTNESS_DOWN),
- 0,
- intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
- ),
- TestData(
- "KEYBOARD_BACKLIGHT_UP -> Keyboard Backlight Up",
- intArrayOf(KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_UP),
- KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP,
- intArrayOf(KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_UP),
- 0,
- intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
- ),
- TestData(
- "KEYBOARD_BACKLIGHT_DOWN -> Keyboard Backlight Down",
- intArrayOf(KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_DOWN),
- KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN,
- intArrayOf(KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_DOWN),
- 0,
- intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
- ),
- TestData(
- "KEYBOARD_BACKLIGHT_TOGGLE -> Keyboard Backlight Toggle",
- intArrayOf(KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_TOGGLE),
- KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE,
- intArrayOf(KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_TOGGLE),
- 0,
- intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
- ),
- TestData(
- "ALL_APPS -> Open App Drawer",
- intArrayOf(KeyEvent.KEYCODE_ALL_APPS),
- KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS,
- intArrayOf(KeyEvent.KEYCODE_ALL_APPS),
- 0,
- intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
- ),
- TestData(
- "NOTIFICATION -> Toggle Notification Panel",
- intArrayOf(KeyEvent.KEYCODE_NOTIFICATION),
- KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL,
- intArrayOf(KeyEvent.KEYCODE_NOTIFICATION),
- 0,
- intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
- ),
- TestData(
- "LANGUAGE_SWITCH -> Switch Language Forward",
- intArrayOf(KeyEvent.KEYCODE_LANGUAGE_SWITCH),
- KeyGestureEvent.KEY_GESTURE_TYPE_LANGUAGE_SWITCH,
- intArrayOf(KeyEvent.KEYCODE_LANGUAGE_SWITCH),
- 0,
- intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
- ),
- TestData(
- "SHIFT + LANGUAGE_SWITCH -> Switch Language Backward",
- intArrayOf(KeyEvent.KEYCODE_SHIFT_LEFT, KeyEvent.KEYCODE_LANGUAGE_SWITCH),
- KeyGestureEvent.KEY_GESTURE_TYPE_LANGUAGE_SWITCH,
- intArrayOf(KeyEvent.KEYCODE_LANGUAGE_SWITCH),
- KeyEvent.META_SHIFT_ON,
- intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
- ),
- TestData(
- "SCREENSHOT -> Take Screenshot",
- intArrayOf(KeyEvent.KEYCODE_SCREENSHOT),
- KeyGestureEvent.KEY_GESTURE_TYPE_TAKE_SCREENSHOT,
- intArrayOf(KeyEvent.KEYCODE_SCREENSHOT),
- 0,
- intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
- ),
- TestData(
- "META -> Open Apps Drawer",
- intArrayOf(KeyEvent.KEYCODE_META_LEFT),
- KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS,
- intArrayOf(KeyEvent.KEYCODE_META_LEFT),
- 0,
- intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
- ),
- TestData(
"META + ALT -> Toggle Caps Lock",
intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_ALT_LEFT),
KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK,
@@ -631,22 +532,6 @@ class KeyGestureControllerTests {
intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
),
TestData(
- "SYSRQ -> Take screenshot",
- intArrayOf(KeyEvent.KEYCODE_SYSRQ),
- KeyGestureEvent.KEY_GESTURE_TYPE_TAKE_SCREENSHOT,
- intArrayOf(KeyEvent.KEYCODE_SYSRQ),
- 0,
- intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
- ),
- TestData(
- "ESC -> Close All Dialogs",
- intArrayOf(KeyEvent.KEYCODE_ESCAPE),
- KeyGestureEvent.KEY_GESTURE_TYPE_CLOSE_ALL_DIALOGS,
- intArrayOf(KeyEvent.KEYCODE_ESCAPE),
- 0,
- intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
- ),
- TestData(
"META + B -> Launch Default Browser",
intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_B),
KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION,
@@ -758,6 +643,305 @@ class KeyGestureControllerTests {
AppLaunchData.createLaunchDataForComponent("com.test", "com.test.BookmarkTest")
),
TestData(
+ "META + CTRL + DEL -> Trigger Bug Report",
+ intArrayOf(
+ KeyEvent.KEYCODE_META_LEFT,
+ KeyEvent.KEYCODE_CTRL_LEFT,
+ KeyEvent.KEYCODE_DEL
+ ),
+ KeyGestureEvent.KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT,
+ intArrayOf(KeyEvent.KEYCODE_DEL),
+ KeyEvent.META_META_ON or KeyEvent.META_CTRL_ON,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "Meta + Alt + 3 -> Toggle Bounce Keys",
+ intArrayOf(
+ KeyEvent.KEYCODE_META_LEFT,
+ KeyEvent.KEYCODE_ALT_LEFT,
+ KeyEvent.KEYCODE_3
+ ),
+ KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_BOUNCE_KEYS,
+ intArrayOf(KeyEvent.KEYCODE_3),
+ KeyEvent.META_META_ON or KeyEvent.META_ALT_ON,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "Meta + Alt + 4 -> Toggle Mouse Keys",
+ intArrayOf(
+ KeyEvent.KEYCODE_META_LEFT,
+ KeyEvent.KEYCODE_ALT_LEFT,
+ KeyEvent.KEYCODE_4
+ ),
+ KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MOUSE_KEYS,
+ intArrayOf(KeyEvent.KEYCODE_4),
+ KeyEvent.META_META_ON or KeyEvent.META_ALT_ON,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "Meta + Alt + 5 -> Toggle Sticky Keys",
+ intArrayOf(
+ KeyEvent.KEYCODE_META_LEFT,
+ KeyEvent.KEYCODE_ALT_LEFT,
+ KeyEvent.KEYCODE_5
+ ),
+ KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_STICKY_KEYS,
+ intArrayOf(KeyEvent.KEYCODE_5),
+ KeyEvent.META_META_ON or KeyEvent.META_ALT_ON,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "Meta + Alt + 6 -> Toggle Slow Keys",
+ intArrayOf(
+ KeyEvent.KEYCODE_META_LEFT,
+ KeyEvent.KEYCODE_ALT_LEFT,
+ KeyEvent.KEYCODE_6
+ ),
+ KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_SLOW_KEYS,
+ intArrayOf(KeyEvent.KEYCODE_6),
+ KeyEvent.META_META_ON or KeyEvent.META_ALT_ON,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "META + CTRL + D -> Move a task to next display",
+ intArrayOf(
+ KeyEvent.KEYCODE_META_LEFT,
+ KeyEvent.KEYCODE_CTRL_LEFT,
+ KeyEvent.KEYCODE_D
+ ),
+ KeyGestureEvent.KEY_GESTURE_TYPE_MOVE_TO_NEXT_DISPLAY,
+ intArrayOf(KeyEvent.KEYCODE_D),
+ KeyEvent.META_META_ON or KeyEvent.META_CTRL_ON,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "ALT + [ -> Resizes a task to fit the left half of the screen",
+ intArrayOf(
+ KeyEvent.KEYCODE_ALT_LEFT,
+ KeyEvent.KEYCODE_LEFT_BRACKET
+ ),
+ KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW,
+ intArrayOf(KeyEvent.KEYCODE_LEFT_BRACKET),
+ KeyEvent.META_ALT_ON,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "ALT + ] -> Resizes a task to fit the right half of the screen",
+ intArrayOf(
+ KeyEvent.KEYCODE_ALT_LEFT,
+ KeyEvent.KEYCODE_RIGHT_BRACKET
+ ),
+ KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW,
+ intArrayOf(KeyEvent.KEYCODE_RIGHT_BRACKET),
+ KeyEvent.META_ALT_ON,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "ALT + '=' -> Maximizes a task to fit the screen",
+ intArrayOf(
+ KeyEvent.KEYCODE_ALT_LEFT,
+ KeyEvent.KEYCODE_EQUALS
+ ),
+ KeyGestureEvent.KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW,
+ intArrayOf(KeyEvent.KEYCODE_EQUALS),
+ KeyEvent.META_ALT_ON,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "ALT + '-' -> Restores a task size to its previous bounds",
+ intArrayOf(
+ KeyEvent.KEYCODE_ALT_LEFT,
+ KeyEvent.KEYCODE_MINUS
+ ),
+ KeyGestureEvent.KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE,
+ intArrayOf(KeyEvent.KEYCODE_MINUS),
+ KeyEvent.META_ALT_ON,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ )
+ )
+ }
+
+ @Test
+ @Parameters(method = "systemGesturesTestArguments")
+ @EnableFlags(
+ com.android.server.flags.Flags.FLAG_NEW_BUGREPORT_KEYBOARD_SHORTCUT,
+ com.android.hardware.input.Flags.FLAG_KEYBOARD_A11Y_SHORTCUT_CONTROL,
+ com.android.hardware.input.Flags.FLAG_KEYBOARD_A11Y_BOUNCE_KEYS_FLAG,
+ com.android.hardware.input.Flags.FLAG_KEYBOARD_A11Y_SLOW_KEYS_FLAG,
+ com.android.hardware.input.Flags.FLAG_KEYBOARD_A11Y_STICKY_KEYS_FLAG,
+ com.android.hardware.input.Flags.FLAG_KEYBOARD_A11Y_MOUSE_KEYS,
+ com.android.window.flags.Flags.FLAG_ENABLE_MOVE_TO_NEXT_DISPLAY_SHORTCUT,
+ com.android.window.flags.Flags.FLAG_ENABLE_TASK_RESIZING_KEYBOARD_SHORTCUTS
+ )
+ fun testKeyGestures(test: TestData) {
+ setupKeyGestureController()
+ testKeyGestureInternal(test)
+ }
+
+ @Test
+ @Parameters(method = "systemGesturesTestArguments")
+ @EnableFlags(
+ com.android.server.flags.Flags.FLAG_NEW_BUGREPORT_KEYBOARD_SHORTCUT,
+ com.android.hardware.input.Flags.FLAG_KEYBOARD_A11Y_SHORTCUT_CONTROL,
+ com.android.hardware.input.Flags.FLAG_KEYBOARD_A11Y_BOUNCE_KEYS_FLAG,
+ com.android.hardware.input.Flags.FLAG_KEYBOARD_A11Y_SLOW_KEYS_FLAG,
+ com.android.hardware.input.Flags.FLAG_KEYBOARD_A11Y_STICKY_KEYS_FLAG,
+ com.android.hardware.input.Flags.FLAG_KEYBOARD_A11Y_MOUSE_KEYS,
+ com.android.window.flags.Flags.FLAG_ENABLE_MOVE_TO_NEXT_DISPLAY_SHORTCUT,
+ com.android.window.flags.Flags.FLAG_ENABLE_TASK_RESIZING_KEYBOARD_SHORTCUTS
+ )
+ fun testCustomKeyGesturesNotAllowedForSystemGestures(test: TestData) {
+ setupKeyGestureController()
+ // Need to re-init so that bookmarks are correctly blocklisted
+ Mockito.`when`(iInputManager.getAppLaunchBookmarks())
+ .thenReturn(keyGestureController.appLaunchBookmarks)
+ keyGestureController.systemRunning()
+
+ val builder = InputGestureData.Builder()
+ .setKeyGestureType(test.expectedKeyGestureType)
+ .setTrigger(
+ InputGestureData.createKeyTrigger(
+ test.expectedKeys[0],
+ test.expectedModifierState
+ )
+ )
+ if (test.expectedAppLaunchData != null) {
+ builder.setAppLaunchData(test.expectedAppLaunchData)
+ }
+ assertEquals(
+ test.toString(),
+ InputManager.CUSTOM_INPUT_GESTURE_RESULT_ERROR_RESERVED_GESTURE,
+ keyGestureController.addCustomInputGesture(0, builder.build().aidlData)
+ )
+ }
+
+ @Keep
+ private fun systemKeysTestArguments(): Array<TestData> {
+ return arrayOf(
+ TestData(
+ "RECENT_APPS -> Show Overview",
+ intArrayOf(KeyEvent.KEYCODE_RECENT_APPS),
+ KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS,
+ intArrayOf(KeyEvent.KEYCODE_RECENT_APPS),
+ 0,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "APP_SWITCH -> App Switch",
+ intArrayOf(KeyEvent.KEYCODE_APP_SWITCH),
+ KeyGestureEvent.KEY_GESTURE_TYPE_APP_SWITCH,
+ intArrayOf(KeyEvent.KEYCODE_APP_SWITCH),
+ 0,
+ intArrayOf(
+ KeyGestureEvent.ACTION_GESTURE_START,
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE
+ )
+ ),
+ TestData(
+ "BRIGHTNESS_UP -> Brightness Up",
+ intArrayOf(KeyEvent.KEYCODE_BRIGHTNESS_UP),
+ KeyGestureEvent.KEY_GESTURE_TYPE_BRIGHTNESS_UP,
+ intArrayOf(KeyEvent.KEYCODE_BRIGHTNESS_UP),
+ 0,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "BRIGHTNESS_DOWN -> Brightness Down",
+ intArrayOf(KeyEvent.KEYCODE_BRIGHTNESS_DOWN),
+ KeyGestureEvent.KEY_GESTURE_TYPE_BRIGHTNESS_DOWN,
+ intArrayOf(KeyEvent.KEYCODE_BRIGHTNESS_DOWN),
+ 0,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "KEYBOARD_BACKLIGHT_UP -> Keyboard Backlight Up",
+ intArrayOf(KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_UP),
+ KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP,
+ intArrayOf(KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_UP),
+ 0,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "KEYBOARD_BACKLIGHT_DOWN -> Keyboard Backlight Down",
+ intArrayOf(KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_DOWN),
+ KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN,
+ intArrayOf(KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_DOWN),
+ 0,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "KEYBOARD_BACKLIGHT_TOGGLE -> Keyboard Backlight Toggle",
+ intArrayOf(KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_TOGGLE),
+ KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE,
+ intArrayOf(KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_TOGGLE),
+ 0,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "ALL_APPS -> Open App Drawer",
+ intArrayOf(KeyEvent.KEYCODE_ALL_APPS),
+ KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS,
+ intArrayOf(KeyEvent.KEYCODE_ALL_APPS),
+ 0,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "NOTIFICATION -> Toggle Notification Panel",
+ intArrayOf(KeyEvent.KEYCODE_NOTIFICATION),
+ KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL,
+ intArrayOf(KeyEvent.KEYCODE_NOTIFICATION),
+ 0,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "LANGUAGE_SWITCH -> Switch Language Forward",
+ intArrayOf(KeyEvent.KEYCODE_LANGUAGE_SWITCH),
+ KeyGestureEvent.KEY_GESTURE_TYPE_LANGUAGE_SWITCH,
+ intArrayOf(KeyEvent.KEYCODE_LANGUAGE_SWITCH),
+ 0,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "SHIFT + LANGUAGE_SWITCH -> Switch Language Backward",
+ intArrayOf(KeyEvent.KEYCODE_SHIFT_LEFT, KeyEvent.KEYCODE_LANGUAGE_SWITCH),
+ KeyGestureEvent.KEY_GESTURE_TYPE_LANGUAGE_SWITCH,
+ intArrayOf(KeyEvent.KEYCODE_LANGUAGE_SWITCH),
+ KeyEvent.META_SHIFT_ON,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "SCREENSHOT -> Take Screenshot",
+ intArrayOf(KeyEvent.KEYCODE_SCREENSHOT),
+ KeyGestureEvent.KEY_GESTURE_TYPE_TAKE_SCREENSHOT,
+ intArrayOf(KeyEvent.KEYCODE_SCREENSHOT),
+ 0,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "META -> Open Apps Drawer",
+ intArrayOf(KeyEvent.KEYCODE_META_LEFT),
+ KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS,
+ intArrayOf(KeyEvent.KEYCODE_META_LEFT),
+ 0,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "SYSRQ -> Take screenshot",
+ intArrayOf(KeyEvent.KEYCODE_SYSRQ),
+ KeyGestureEvent.KEY_GESTURE_TYPE_TAKE_SCREENSHOT,
+ intArrayOf(KeyEvent.KEYCODE_SYSRQ),
+ 0,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "ESC -> Close All Dialogs",
+ intArrayOf(KeyEvent.KEYCODE_ESCAPE),
+ KeyGestureEvent.KEY_GESTURE_TYPE_CLOSE_ALL_DIALOGS,
+ intArrayOf(KeyEvent.KEYCODE_ESCAPE),
+ 0,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
"EXPLORER -> Launch Default Browser",
intArrayOf(KeyEvent.KEYCODE_EXPLORER),
KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION,
@@ -815,17 +999,15 @@ class KeyGestureControllerTests {
}
@Test
- @Parameters(method = "keyGestureEventHandlerTestArguments")
- fun testKeyGestures(test: TestData) {
- val keyGestureController = KeyGestureController(context, testLooper.looper)
- keyGestureController.systemRunning()
-
- testKeyGestureInternal(keyGestureController, test)
+ @Parameters(method = "systemKeysTestArguments")
+ fun testSystemKeys(test: TestData) {
+ setupKeyGestureController()
+ testKeyGestureInternal(test)
}
@Test
fun testKeycodesFullyConsumed_irrespectiveOfHandlers() {
- val keyGestureController = KeyGestureController(context, testLooper.looper)
+ setupKeyGestureController()
val testKeys = intArrayOf(
KeyEvent.KEYCODE_RECENT_APPS,
KeyEvent.KEYCODE_APP_SWITCH,
@@ -853,7 +1035,7 @@ class KeyGestureControllerTests {
keyGestureController.registerKeyGestureHandler(handler, 0)
for (key in testKeys) {
- sendKeys(keyGestureController, intArrayOf(key), assertNotSentToApps = true)
+ sendKeys(intArrayOf(key), assertNotSentToApps = true)
}
}
@@ -861,9 +1043,8 @@ class KeyGestureControllerTests {
fun testSearchKeyGestures_defaultSearch() {
Mockito.`when`(resources.getInteger(R.integer.config_searchKeyBehavior))
.thenReturn(SEARCH_KEY_BEHAVIOR_DEFAULT_SEARCH)
- val keyGestureController = KeyGestureController(context, testLooper.looper)
+ setupKeyGestureController()
testKeyGestureNotProduced(
- keyGestureController,
"SEARCH -> Default Search",
intArrayOf(KeyEvent.KEYCODE_SEARCH),
)
@@ -873,9 +1054,8 @@ class KeyGestureControllerTests {
fun testSearchKeyGestures_searchActivity() {
Mockito.`when`(resources.getInteger(R.integer.config_searchKeyBehavior))
.thenReturn(SEARCH_KEY_BEHAVIOR_TARGET_ACTIVITY)
- val keyGestureController = KeyGestureController(context, testLooper.looper)
+ setupKeyGestureController()
testKeyGestureInternal(
- keyGestureController,
TestData(
"SEARCH -> Launch Search Activity",
intArrayOf(KeyEvent.KEYCODE_SEARCH),
@@ -891,9 +1071,8 @@ class KeyGestureControllerTests {
fun testSettingKeyGestures_doNothing() {
Mockito.`when`(resources.getInteger(R.integer.config_settingsKeyBehavior))
.thenReturn(SETTINGS_KEY_BEHAVIOR_NOTHING)
- val keyGestureController = KeyGestureController(context, testLooper.looper)
+ setupKeyGestureController()
testKeyGestureNotProduced(
- keyGestureController,
"SETTINGS -> Do Nothing",
intArrayOf(KeyEvent.KEYCODE_SETTINGS),
)
@@ -903,9 +1082,8 @@ class KeyGestureControllerTests {
fun testSettingKeyGestures_settingsActivity() {
Mockito.`when`(resources.getInteger(R.integer.config_settingsKeyBehavior))
.thenReturn(SETTINGS_KEY_BEHAVIOR_SETTINGS_ACTIVITY)
- val keyGestureController = KeyGestureController(context, testLooper.looper)
+ setupKeyGestureController()
testKeyGestureInternal(
- keyGestureController,
TestData(
"SETTINGS -> Launch Settings Activity",
intArrayOf(KeyEvent.KEYCODE_SETTINGS),
@@ -921,9 +1099,8 @@ class KeyGestureControllerTests {
fun testSettingKeyGestures_notificationPanel() {
Mockito.`when`(resources.getInteger(R.integer.config_settingsKeyBehavior))
.thenReturn(SETTINGS_KEY_BEHAVIOR_NOTIFICATION_PANEL)
- val keyGestureController = KeyGestureController(context, testLooper.looper)
+ setupKeyGestureController()
testKeyGestureInternal(
- keyGestureController,
TestData(
"SETTINGS -> Toggle Notification Panel",
intArrayOf(KeyEvent.KEYCODE_SETTINGS),
@@ -936,221 +1113,12 @@ class KeyGestureControllerTests {
}
@Test
- @EnableFlags(com.android.server.flags.Flags.FLAG_NEW_BUGREPORT_KEYBOARD_SHORTCUT)
- fun testTriggerBugReport() {
- Mockito.`when`(SystemProperties.get("ro.debuggable")).thenReturn("1")
- val keyGestureController = KeyGestureController(context, testLooper.looper)
- testKeyGestureInternal(
- keyGestureController,
- TestData(
- "META + CTRL + DEL -> Trigger Bug Report",
- intArrayOf(
- KeyEvent.KEYCODE_META_LEFT,
- KeyEvent.KEYCODE_CTRL_LEFT,
- KeyEvent.KEYCODE_DEL
- ),
- KeyGestureEvent.KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT,
- intArrayOf(KeyEvent.KEYCODE_DEL),
- KeyEvent.META_META_ON or KeyEvent.META_CTRL_ON,
- intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
- )
- )
- }
-
- @Test
- @DisableFlags(com.android.server.flags.Flags.FLAG_NEW_BUGREPORT_KEYBOARD_SHORTCUT)
- fun testTriggerBugReport_flagDisabled() {
- Mockito.`when`(SystemProperties.get("ro.debuggable")).thenReturn("1")
- val keyGestureController = KeyGestureController(context, testLooper.looper)
- testKeyGestureInternal(
- keyGestureController,
- TestData(
- "META + CTRL + DEL -> Not Trigger Bug Report (Fallback to BACK)",
- intArrayOf(
- KeyEvent.KEYCODE_META_LEFT,
- KeyEvent.KEYCODE_CTRL_LEFT,
- KeyEvent.KEYCODE_DEL
- ),
- KeyGestureEvent.KEY_GESTURE_TYPE_BACK,
- intArrayOf(KeyEvent.KEYCODE_DEL),
- KeyEvent.META_META_ON,
- intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
- )
- )
- }
-
- @Test
- @EnableFlags(
- com.android.hardware.input.Flags.FLAG_KEYBOARD_A11Y_SHORTCUT_CONTROL,
- com.android.hardware.input.Flags.FLAG_KEYBOARD_A11Y_BOUNCE_KEYS_FLAG,
- com.android.hardware.input.Flags.FLAG_KEYBOARD_A11Y_SLOW_KEYS_FLAG,
- com.android.hardware.input.Flags.FLAG_KEYBOARD_A11Y_STICKY_KEYS_FLAG,
- com.android.hardware.input.Flags.FLAG_KEYBOARD_A11Y_MOUSE_KEYS
- )
- fun testKeyboardAccessibilityToggleShortcutPress() {
- val keyGestureController = KeyGestureController(context, testLooper.looper)
- testKeyGestureInternal(
- keyGestureController,
- TestData(
- "Meta + Alt + 3 -> Toggle Bounce Keys",
- intArrayOf(
- KeyEvent.KEYCODE_META_LEFT,
- KeyEvent.KEYCODE_ALT_LEFT,
- KeyEvent.KEYCODE_3
- ),
- KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_BOUNCE_KEYS,
- intArrayOf(KeyEvent.KEYCODE_3),
- KeyEvent.META_META_ON or KeyEvent.META_ALT_ON,
- intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)))
- testKeyGestureInternal(
- keyGestureController,
- TestData(
- "Meta + Alt + 4 -> Toggle Mouse Keys",
- intArrayOf(
- KeyEvent.KEYCODE_META_LEFT,
- KeyEvent.KEYCODE_ALT_LEFT,
- KeyEvent.KEYCODE_4
- ),
- KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MOUSE_KEYS,
- intArrayOf(KeyEvent.KEYCODE_4),
- KeyEvent.META_META_ON or KeyEvent.META_ALT_ON,
- intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)))
- testKeyGestureInternal(
- keyGestureController,
- TestData(
- "Meta + Alt + 5 -> Toggle Sticky Keys",
- intArrayOf(
- KeyEvent.KEYCODE_META_LEFT,
- KeyEvent.KEYCODE_ALT_LEFT,
- KeyEvent.KEYCODE_5
- ),
- KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_STICKY_KEYS,
- intArrayOf(KeyEvent.KEYCODE_5),
- KeyEvent.META_META_ON or KeyEvent.META_ALT_ON,
- intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)))
- testKeyGestureInternal(
- keyGestureController,
- TestData(
- "Meta + Alt + 6 -> Toggle Slow Keys",
- intArrayOf(
- KeyEvent.KEYCODE_META_LEFT,
- KeyEvent.KEYCODE_ALT_LEFT,
- KeyEvent.KEYCODE_6
- ),
- KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_SLOW_KEYS,
- intArrayOf(KeyEvent.KEYCODE_6),
- KeyEvent.META_META_ON or KeyEvent.META_ALT_ON,
- intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)))
- }
-
- @Test
- @EnableFlags(com.android.window.flags.Flags.FLAG_ENABLE_MOVE_TO_NEXT_DISPLAY_SHORTCUT)
- fun testMoveToNextDisplay() {
- val keyGestureController = KeyGestureController(context, testLooper.looper)
- testKeyGestureInternal(
- keyGestureController,
- TestData(
- "META + CTRL + D -> Move a task to next display",
- intArrayOf(
- KeyEvent.KEYCODE_META_LEFT,
- KeyEvent.KEYCODE_CTRL_LEFT,
- KeyEvent.KEYCODE_D
- ),
- KeyGestureEvent.KEY_GESTURE_TYPE_MOVE_TO_NEXT_DISPLAY,
- intArrayOf(KeyEvent.KEYCODE_D),
- KeyEvent.META_META_ON or KeyEvent.META_CTRL_ON,
- intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
- )
- )
- }
-
- @Test
- @EnableFlags(com.android.window.flags.Flags.FLAG_ENABLE_TASK_RESIZING_KEYBOARD_SHORTCUTS)
- fun testSnapLeftFreeformTask() {
- val keyGestureController = KeyGestureController(context, testLooper.looper)
- testKeyGestureInternal(
- keyGestureController,
- TestData(
- "ALT + [ -> Resizes a task to fit the left half of the screen",
- intArrayOf(
- KeyEvent.KEYCODE_ALT_LEFT,
- KeyEvent.KEYCODE_LEFT_BRACKET
- ),
- KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW,
- intArrayOf(KeyEvent.KEYCODE_LEFT_BRACKET),
- KeyEvent.META_ALT_ON,
- intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
- )
- )
- }
-
- @Test
- @EnableFlags(com.android.window.flags.Flags.FLAG_ENABLE_TASK_RESIZING_KEYBOARD_SHORTCUTS)
- fun testSnapRightFreeformTask() {
- val keyGestureController = KeyGestureController(context, testLooper.looper)
- testKeyGestureInternal(
- keyGestureController,
- TestData(
- "ALT + ] -> Resizes a task to fit the right half of the screen",
- intArrayOf(
- KeyEvent.KEYCODE_ALT_LEFT,
- KeyEvent.KEYCODE_RIGHT_BRACKET
- ),
- KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW,
- intArrayOf(KeyEvent.KEYCODE_RIGHT_BRACKET),
- KeyEvent.META_ALT_ON,
- intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
- )
- )
- }
-
- @Test
- @EnableFlags(com.android.window.flags.Flags.FLAG_ENABLE_TASK_RESIZING_KEYBOARD_SHORTCUTS)
- fun testMaximizeFreeformTask() {
- val keyGestureController = KeyGestureController(context, testLooper.looper)
- testKeyGestureInternal(
- keyGestureController,
- TestData(
- "ALT + '=' -> Maximizes a task to fit the screen",
- intArrayOf(
- KeyEvent.KEYCODE_ALT_LEFT,
- KeyEvent.KEYCODE_EQUALS
- ),
- KeyGestureEvent.KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW,
- intArrayOf(KeyEvent.KEYCODE_EQUALS),
- KeyEvent.META_ALT_ON,
- intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
- )
- )
- }
-
- @Test
- @EnableFlags(com.android.window.flags.Flags.FLAG_ENABLE_TASK_RESIZING_KEYBOARD_SHORTCUTS)
- fun testRestoreFreeformTask() {
- val keyGestureController = KeyGestureController(context, testLooper.looper)
- testKeyGestureInternal(
- keyGestureController,
- TestData(
- "ALT + '-' -> Restores a task size to its previous bounds",
- intArrayOf(
- KeyEvent.KEYCODE_ALT_LEFT,
- KeyEvent.KEYCODE_MINUS
- ),
- KeyGestureEvent.KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE,
- intArrayOf(KeyEvent.KEYCODE_MINUS),
- KeyEvent.META_ALT_ON,
- intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
- )
- )
- }
-
- @Test
fun testCapsLockPressNotified() {
- val keyGestureController = KeyGestureController(context, testLooper.looper)
+ setupKeyGestureController()
val listener = KeyGestureEventListener()
keyGestureController.registerKeyGestureEventListener(listener, 0)
- sendKeys(keyGestureController, intArrayOf(KeyEvent.KEYCODE_CAPS_LOCK))
+ sendKeys(intArrayOf(KeyEvent.KEYCODE_CAPS_LOCK))
testLooper.dispatchAll()
assertEquals(
"Listener should get callbacks on key gesture event completed",
@@ -1165,7 +1133,7 @@ class KeyGestureControllerTests {
}
@Keep
- private fun keyGestureEventHandlerTestArguments_forKeyCombinations(): Array<TestData> {
+ private fun systemGesturesTestArguments_forKeyCombinations(): Array<TestData> {
return arrayOf(
TestData(
"VOLUME_DOWN + POWER -> Screenshot Chord",
@@ -1226,14 +1194,14 @@ class KeyGestureControllerTests {
}
@Test
- @Parameters(method = "keyGestureEventHandlerTestArguments_forKeyCombinations")
+ @Parameters(method = "systemGesturesTestArguments_forKeyCombinations")
@EnableFlags(
com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER,
com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER_MULTI_PRESS_GESTURES
)
fun testKeyCombinationGestures(test: TestData) {
- val keyGestureController = KeyGestureController(context, testLooper.looper)
- testKeyGestureInternal(keyGestureController, test)
+ setupKeyGestureController()
+ testKeyGestureInternal(test)
}
@Keep
@@ -1274,7 +1242,7 @@ class KeyGestureControllerTests {
@Test
@Parameters(method = "customInputGesturesTestArguments")
fun testCustomKeyGestures(test: TestData) {
- val keyGestureController = KeyGestureController(context, testLooper.looper)
+ setupKeyGestureController()
val builder = InputGestureData.Builder()
.setKeyGestureType(test.expectedKeyGestureType)
.setTrigger(
@@ -1282,17 +1250,17 @@ class KeyGestureControllerTests {
test.expectedKeys[0],
test.expectedModifierState
)
- );
+ )
if (test.expectedAppLaunchData != null) {
builder.setAppLaunchData(test.expectedAppLaunchData)
}
- val inputGestureData = builder.build();
+ val inputGestureData = builder.build()
keyGestureController.addCustomInputGesture(0, inputGestureData.aidlData)
- testKeyGestureInternal(keyGestureController, test)
+ testKeyGestureInternal(test)
}
- private fun testKeyGestureInternal(keyGestureController: KeyGestureController, test: TestData) {
+ private fun testKeyGestureInternal(test: TestData) {
var handleEvents = mutableListOf<KeyGestureEvent>()
val handler = KeyGestureHandler { event, _ ->
handleEvents.add(KeyGestureEvent(event))
@@ -1301,7 +1269,7 @@ class KeyGestureControllerTests {
keyGestureController.registerKeyGestureHandler(handler, 0)
handleEvents.clear()
- sendKeys(keyGestureController, test.keys)
+ sendKeys(test.keys)
assertEquals(
"Test: $test doesn't produce correct number of key gesture events",
@@ -1340,11 +1308,7 @@ class KeyGestureControllerTests {
keyGestureController.unregisterKeyGestureHandler(handler, 0)
}
- private fun testKeyGestureNotProduced(
- keyGestureController: KeyGestureController,
- testName: String,
- testKeys: IntArray
- ) {
+ private fun testKeyGestureNotProduced(testName: String, testKeys: IntArray) {
var handleEvents = mutableListOf<KeyGestureEvent>()
val handler = KeyGestureHandler { event, _ ->
handleEvents.add(KeyGestureEvent(event))
@@ -1353,15 +1317,11 @@ class KeyGestureControllerTests {
keyGestureController.registerKeyGestureHandler(handler, 0)
handleEvents.clear()
- sendKeys(keyGestureController, testKeys)
+ sendKeys(testKeys)
assertEquals("Test: $testName should not produce Key gesture", 0, handleEvents.size)
}
- private fun sendKeys(
- keyGestureController: KeyGestureController,
- testKeys: IntArray,
- assertNotSentToApps: Boolean = false
- ) {
+ private fun sendKeys(testKeys: IntArray, assertNotSentToApps: Boolean = false) {
var metaState = 0
val now = SystemClock.uptimeMillis()
for (key in testKeys) {
@@ -1370,7 +1330,7 @@ class KeyGestureControllerTests {
DEVICE_ID, 0 /*scancode*/, 0 /*flags*/,
InputDevice.SOURCE_KEYBOARD
)
- interceptKey(keyGestureController, downEvent, assertNotSentToApps)
+ interceptKey(downEvent, assertNotSentToApps)
metaState = metaState or MODIFIER.getOrDefault(key, 0)
downEvent.recycle()
@@ -1383,7 +1343,7 @@ class KeyGestureControllerTests {
DEVICE_ID, 0 /*scancode*/, 0 /*flags*/,
InputDevice.SOURCE_KEYBOARD
)
- interceptKey(keyGestureController, upEvent, assertNotSentToApps)
+ interceptKey(upEvent, assertNotSentToApps)
metaState = metaState and MODIFIER.getOrDefault(key, 0).inv()
upEvent.recycle()
@@ -1391,11 +1351,7 @@ class KeyGestureControllerTests {
}
}
- private fun interceptKey(
- keyGestureController: KeyGestureController,
- event: KeyEvent,
- assertNotSentToApps: Boolean
- ) {
+ private fun interceptKey(event: KeyEvent, assertNotSentToApps: Boolean) {
keyGestureController.interceptKeyBeforeQueueing(event, FLAG_INTERACTIVE)
testLooper.dispatchAll()