summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/hardware/input/IKeyGestureHandler.aidl11
-rw-r--r--core/java/android/hardware/input/InputManager.java7
-rw-r--r--core/java/android/hardware/input/InputManagerGlobal.java17
-rw-r--r--core/java/android/hardware/input/KeyGestureEvent.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandler.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt8
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java9
-rw-r--r--services/core/java/com/android/server/input/InputManagerService.java24
-rw-r--r--services/core/java/com/android/server/input/KeyGestureController.java109
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java81
-rw-r--r--services/core/java/com/android/server/wm/InputManagerCallback.java7
-rw-r--r--services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java46
-rw-r--r--services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java5
-rw-r--r--tests/Input/src/android/hardware/input/KeyGestureEventHandlerTest.kt4
-rw-r--r--tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt110
15 files changed, 198 insertions, 260 deletions
diff --git a/core/java/android/hardware/input/IKeyGestureHandler.aidl b/core/java/android/hardware/input/IKeyGestureHandler.aidl
index 509b9482154e..4da991ee85b1 100644
--- a/core/java/android/hardware/input/IKeyGestureHandler.aidl
+++ b/core/java/android/hardware/input/IKeyGestureHandler.aidl
@@ -28,15 +28,4 @@ interface IKeyGestureHandler {
* to that gesture.
*/
boolean handleKeyGesture(in AidlKeyGestureEvent event, in IBinder focusedToken);
-
- /**
- * Called to know if a particular gesture type is supported by the handler.
- *
- * TODO(b/358569822): Remove this call to reduce the binder calls to single call for
- * handleKeyGesture. For this we need to remove dependency of multi-key gestures to identify if
- * a key gesture is supported on first relevant key down.
- * Also, for now we prioritize handlers in the system server process above external handlers to
- * reduce IPC binder calls.
- */
- boolean isKeyGestureSupported(int gestureType);
}
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 49db54d81e65..d6419afb2a5a 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -1758,13 +1758,6 @@ public final class InputManager {
*/
boolean handleKeyGestureEvent(@NonNull KeyGestureEvent event,
@Nullable IBinder focusedToken);
-
- /**
- * Called to identify if a particular gesture is of interest to a handler.
- *
- * NOTE: If no active handler supports certain gestures, the gestures will not be captured.
- */
- boolean isKeyGestureSupported(@KeyGestureEvent.KeyGestureType int gestureType);
}
/** @hide */
diff --git a/core/java/android/hardware/input/InputManagerGlobal.java b/core/java/android/hardware/input/InputManagerGlobal.java
index a9a45ae45ec3..c4b4831ba76e 100644
--- a/core/java/android/hardware/input/InputManagerGlobal.java
+++ b/core/java/android/hardware/input/InputManagerGlobal.java
@@ -1193,23 +1193,6 @@ public final class InputManagerGlobal {
}
return false;
}
-
- @Override
- public boolean isKeyGestureSupported(@KeyGestureEvent.KeyGestureType int gestureType) {
- synchronized (mKeyGestureEventHandlerLock) {
- if (mKeyGestureEventHandlers == null) {
- return false;
- }
- final int numHandlers = mKeyGestureEventHandlers.size();
- for (int i = 0; i < numHandlers; i++) {
- KeyGestureEventHandler handler = mKeyGestureEventHandlers.get(i);
- if (handler.isKeyGestureSupported(gestureType)) {
- return true;
- }
- }
- }
- return false;
- }
}
/**
diff --git a/core/java/android/hardware/input/KeyGestureEvent.java b/core/java/android/hardware/input/KeyGestureEvent.java
index 1a712d2b3f31..9dd1fed4a85a 100644
--- a/core/java/android/hardware/input/KeyGestureEvent.java
+++ b/core/java/android/hardware/input/KeyGestureEvent.java
@@ -108,7 +108,8 @@ public final class KeyGestureEvent {
public static final int KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT_CHORD = 55;
public static final int KEY_GESTURE_TYPE_RINGER_TOGGLE_CHORD = 56;
public static final int KEY_GESTURE_TYPE_GLOBAL_ACTIONS = 57;
- public static final int KEY_GESTURE_TYPE_TV_ACCESSIBILITY_SHORTCUT_CHORD = 58;
+ @Deprecated
+ public static final int DEPRECATED_KEY_GESTURE_TYPE_TV_ACCESSIBILITY_SHORTCUT_CHORD = 58;
public static final int KEY_GESTURE_TYPE_TV_TRIGGER_BUG_REPORT = 59;
public static final int KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT = 60;
public static final int KEY_GESTURE_TYPE_CLOSE_ALL_DIALOGS = 61;
@@ -200,7 +201,6 @@ public final class KeyGestureEvent {
KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT_CHORD,
KEY_GESTURE_TYPE_RINGER_TOGGLE_CHORD,
KEY_GESTURE_TYPE_GLOBAL_ACTIONS,
- KEY_GESTURE_TYPE_TV_ACCESSIBILITY_SHORTCUT_CHORD,
KEY_GESTURE_TYPE_TV_TRIGGER_BUG_REPORT,
KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT,
KEY_GESTURE_TYPE_CLOSE_ALL_DIALOGS,
@@ -777,8 +777,6 @@ public final class KeyGestureEvent {
return "KEY_GESTURE_TYPE_RINGER_TOGGLE_CHORD";
case KEY_GESTURE_TYPE_GLOBAL_ACTIONS:
return "KEY_GESTURE_TYPE_GLOBAL_ACTIONS";
- case KEY_GESTURE_TYPE_TV_ACCESSIBILITY_SHORTCUT_CHORD:
- return "KEY_GESTURE_TYPE_TV_ACCESSIBILITY_SHORTCUT_CHORD";
case KEY_GESTURE_TYPE_TV_TRIGGER_BUG_REPORT:
return "KEY_GESTURE_TYPE_TV_TRIGGER_BUG_REPORT";
case KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT:
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandler.kt
index 5269318943d9..1ea545f3ab67 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandler.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandler.kt
@@ -56,7 +56,6 @@ class DesktopModeKeyGestureHandler(
override fun handleKeyGestureEvent(event: KeyGestureEvent, focusedToken: IBinder?): Boolean {
if (
- !isKeyGestureSupported(event.keyGestureType) ||
!desktopTasksController.isPresent ||
!desktopModeWindowDecorViewModel.isPresent
) {
@@ -136,19 +135,6 @@ class DesktopModeKeyGestureHandler(
}
}
- override fun isKeyGestureSupported(gestureType: Int): Boolean =
- when (gestureType) {
- KeyGestureEvent.KEY_GESTURE_TYPE_MOVE_TO_NEXT_DISPLAY ->
- enableMoveToNextDisplayShortcut()
- KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW,
- KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW,
- KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MAXIMIZE_FREEFORM_WINDOW,
- KeyGestureEvent.KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW ->
- DesktopModeFlags.ENABLE_TASK_RESIZING_KEYBOARD_SHORTCUTS.isTrue &&
- manageKeyGestures()
- else -> false
- }
-
// TODO: b/364154795 - wait for the completion of moveToNextDisplay transition, otherwise it
// will pick a wrong task when a user quickly perform other actions with keyboard shortcuts
// after moveToNextDisplay, and move this to FocusTransitionObserver class.
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt
index d8fc52bcc55a..8dc27bf4ac3e 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt
@@ -162,10 +162,6 @@ constructor(
): Boolean {
return this@NoteTaskInitializer.handleKeyGestureEvent(event)
}
-
- override fun isKeyGestureSupported(gestureType: Int): Boolean {
- return this@NoteTaskInitializer.isKeyGestureSupported(gestureType)
- }
}
/**
@@ -225,10 +221,6 @@ constructor(
return true
}
- private fun isKeyGestureSupported(gestureType: Int): Boolean {
- return gestureType == KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_NOTES
- }
-
companion object {
val MULTI_PRESS_TIMEOUT = ViewConfiguration.getMultiPressTimeout().toLong()
val LONG_PRESS_TIMEOUT = ViewConfiguration.getLongPressTimeout().toLong()
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index c49151dd5e30..573c591cb504 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -521,15 +521,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
@Nullable IBinder focusedToken) {
return AccessibilityManagerService.this.handleKeyGestureEvent(event);
}
-
- @Override
- public boolean isKeyGestureSupported(int gestureType) {
- return switch (gestureType) {
- case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MAGNIFICATION,
- KeyGestureEvent.KEY_GESTURE_TYPE_ACTIVATE_SELECT_TO_SPEAK -> true;
- default -> false;
- };
- }
};
@VisibleForTesting
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index c2fecf283a34..d9db178e0dc2 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -568,6 +568,7 @@ public class InputManagerService extends IInputManager.Stub
}
mWindowManagerCallbacks = callbacks;
registerLidSwitchCallbackInternal(mWindowManagerCallbacks);
+ mKeyGestureController.setWindowManagerCallbacks(callbacks);
}
public void setWiredAccessoryCallbacks(WiredAccessoryCallbacks callbacks) {
@@ -2756,24 +2757,6 @@ public class InputManagerService extends IInputManager.Stub
@Nullable IBinder focussedToken) {
return InputManagerService.this.handleKeyGestureEvent(event);
}
-
- @Override
- public boolean isKeyGestureSupported(int gestureType) {
- switch (gestureType) {
- case KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP:
- case KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN:
- case KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE:
- case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK:
- case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_SLOW_KEYS:
- case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_BOUNCE_KEYS:
- case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MOUSE_KEYS:
- case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_STICKY_KEYS:
- return true;
- default:
- return false;
-
- }
- }
});
}
@@ -3371,6 +3354,11 @@ public class InputManagerService extends IInputManager.Stub
*/
@Nullable
SurfaceControl createSurfaceForGestureMonitor(String name, int displayId);
+
+ /**
+ * Provide information on whether the keyguard is currently locked or not.
+ */
+ boolean isKeyguardLocked(int displayId);
}
/**
diff --git a/services/core/java/com/android/server/input/KeyGestureController.java b/services/core/java/com/android/server/input/KeyGestureController.java
index ef5babf19d83..395c77322c04 100644
--- a/services/core/java/com/android/server/input/KeyGestureController.java
+++ b/services/core/java/com/android/server/input/KeyGestureController.java
@@ -62,8 +62,10 @@ import android.view.Display;
import android.view.InputDevice;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
+import android.view.ViewConfiguration;
import com.android.internal.R;
+import com.android.internal.accessibility.AccessibilityShortcutController;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.IShortcutService;
@@ -104,6 +106,7 @@ final class KeyGestureController {
private static final int MSG_NOTIFY_KEY_GESTURE_EVENT = 1;
private static final int MSG_PERSIST_CUSTOM_GESTURES = 2;
private static final int MSG_LOAD_CUSTOM_GESTURES = 3;
+ private static final int MSG_ACCESSIBILITY_SHORTCUT = 4;
// must match: config_settingsKeyBehavior in config.xml
private static final int SETTINGS_KEY_BEHAVIOR_SETTINGS_ACTIVITY = 0;
@@ -122,12 +125,15 @@ final class KeyGestureController {
static final int POWER_VOLUME_UP_BEHAVIOR_GLOBAL_ACTIONS = 2;
private final Context mContext;
+ private InputManagerService.WindowManagerCallbacks mWindowManagerCallbacks;
private final Handler mHandler;
private final Handler mIoHandler;
private final int mSystemPid;
private final KeyCombinationManager mKeyCombinationManager;
private final SettingsObserver mSettingsObserver;
private final AppLaunchShortcutManager mAppLaunchShortcutManager;
+ @VisibleForTesting
+ final AccessibilityShortcutController mAccessibilityShortcutController;
private final InputGestureManager mInputGestureManager;
private final DisplayManager mDisplayManager;
@GuardedBy("mInputDataStore")
@@ -175,8 +181,14 @@ final class KeyGestureController {
private final boolean mVisibleBackgroundUsersEnabled = isVisibleBackgroundUsersEnabled();
- KeyGestureController(Context context, Looper looper, Looper ioLooper,
+ public KeyGestureController(Context context, Looper looper, Looper ioLooper,
InputDataStore inputDataStore) {
+ this(context, looper, ioLooper, inputDataStore, new Injector());
+ }
+
+ @VisibleForTesting
+ KeyGestureController(Context context, Looper looper, Looper ioLooper,
+ InputDataStore inputDataStore, Injector injector) {
mContext = context;
mHandler = new Handler(looper, this::handleMessage);
mIoHandler = new Handler(ioLooper, this::handleIoMessage);
@@ -197,6 +209,8 @@ final class KeyGestureController {
mSettingsObserver = new SettingsObserver(mHandler);
mAppLaunchShortcutManager = new AppLaunchShortcutManager(mContext);
mInputGestureManager = new InputGestureManager(mContext);
+ mAccessibilityShortcutController = injector.getAccessibilityShortcutController(mContext,
+ mHandler);
mDisplayManager = Objects.requireNonNull(mContext.getSystemService(DisplayManager.class));
mInputDataStore = inputDataStore;
mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
@@ -295,8 +309,8 @@ final class KeyGestureController {
KeyEvent.KEYCODE_VOLUME_UP) {
@Override
public boolean preCondition() {
- return isKeyGestureSupported(
- KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT_CHORD);
+ return mAccessibilityShortcutController.isAccessibilityShortcutAvailable(
+ mWindowManagerCallbacks.isKeyguardLocked(DEFAULT_DISPLAY));
}
@Override
@@ -376,15 +390,15 @@ final class KeyGestureController {
KeyEvent.KEYCODE_DPAD_DOWN) {
@Override
public boolean preCondition() {
- return isKeyGestureSupported(
- KeyGestureEvent.KEY_GESTURE_TYPE_TV_ACCESSIBILITY_SHORTCUT_CHORD);
+ return mAccessibilityShortcutController
+ .isAccessibilityShortcutAvailable(false);
}
@Override
public void execute() {
handleMultiKeyGesture(
new int[]{KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_DPAD_DOWN},
- KeyGestureEvent.KEY_GESTURE_TYPE_TV_ACCESSIBILITY_SHORTCUT_CHORD,
+ KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT_CHORD,
KeyGestureEvent.ACTION_GESTURE_START, 0);
}
@@ -392,7 +406,7 @@ final class KeyGestureController {
public void cancel() {
handleMultiKeyGesture(
new int[]{KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_DPAD_DOWN},
- KeyGestureEvent.KEY_GESTURE_TYPE_TV_ACCESSIBILITY_SHORTCUT_CHORD,
+ KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT_CHORD,
KeyGestureEvent.ACTION_GESTURE_COMPLETE,
KeyGestureEvent.FLAG_CANCELLED);
}
@@ -438,6 +452,7 @@ final class KeyGestureController {
mSettingsObserver.observe();
mAppLaunchShortcutManager.systemRunning();
mInputGestureManager.systemRunning();
+ initKeyGestures();
int userId;
synchronized (mUserLock) {
@@ -447,6 +462,27 @@ final class KeyGestureController {
mIoHandler.obtainMessage(MSG_LOAD_CUSTOM_GESTURES, userId).sendToTarget();
}
+ @SuppressLint("MissingPermission")
+ private void initKeyGestures() {
+ InputManager im = Objects.requireNonNull(mContext.getSystemService(InputManager.class));
+ im.registerKeyGestureEventHandler((event, focusedToken) -> {
+ switch (event.getKeyGestureType()) {
+ case KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT_CHORD:
+ if (event.getAction() == KeyGestureEvent.ACTION_GESTURE_START) {
+ mHandler.removeMessages(MSG_ACCESSIBILITY_SHORTCUT);
+ mHandler.sendMessageDelayed(
+ mHandler.obtainMessage(MSG_ACCESSIBILITY_SHORTCUT),
+ getAccessibilityShortcutTimeout());
+ } else {
+ mHandler.removeMessages(MSG_ACCESSIBILITY_SHORTCUT);
+ }
+ return true;
+ default:
+ return false;
+ }
+ });
+ }
+
public boolean interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
if (mVisibleBackgroundUsersEnabled && shouldIgnoreKeyEventForVisibleBackgroundUser(event)) {
return false;
@@ -971,17 +1007,6 @@ final class KeyGestureController {
return false;
}
- private boolean isKeyGestureSupported(@KeyGestureEvent.KeyGestureType int gestureType) {
- synchronized (mKeyGestureHandlerRecords) {
- for (KeyGestureHandlerRecord handler : mKeyGestureHandlerRecords.values()) {
- if (handler.isKeyGestureSupported(gestureType)) {
- return true;
- }
- }
- }
- return false;
- }
-
public void notifyKeyGestureCompleted(int deviceId, int[] keycodes, int modifierState,
@KeyGestureEvent.KeyGestureType int gestureType) {
// TODO(b/358569822): Once we move the gesture detection logic to IMS, we ideally
@@ -1019,9 +1044,16 @@ final class KeyGestureController {
synchronized (mUserLock) {
mCurrentUserId = userId;
}
+ mAccessibilityShortcutController.setCurrentUser(userId);
mIoHandler.obtainMessage(MSG_LOAD_CUSTOM_GESTURES, userId).sendToTarget();
}
+
+ public void setWindowManagerCallbacks(
+ @NonNull InputManagerService.WindowManagerCallbacks callbacks) {
+ mWindowManagerCallbacks = callbacks;
+ }
+
private boolean isDefaultDisplayOn() {
Display defaultDisplay = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
if (defaultDisplay == null) {
@@ -1068,6 +1100,9 @@ final class KeyGestureController {
AidlKeyGestureEvent event = (AidlKeyGestureEvent) msg.obj;
notifyKeyGestureEvent(event);
break;
+ case MSG_ACCESSIBILITY_SHORTCUT:
+ mAccessibilityShortcutController.performAccessibilityShortcut();
+ break;
}
return true;
}
@@ -1347,17 +1382,6 @@ final class KeyGestureController {
}
return false;
}
-
- public boolean isKeyGestureSupported(@KeyGestureEvent.KeyGestureType int gestureType) {
- try {
- return mKeyGestureHandler.isKeyGestureSupported(gestureType);
- } catch (RemoteException ex) {
- Slog.w(TAG, "Failed to identify if key gesture type is supported by the "
- + "process " + mPid + ", assuming it died.", ex);
- binderDied();
- }
- return false;
- }
}
private class SettingsObserver extends ContentObserver {
@@ -1413,6 +1437,25 @@ final class KeyGestureController {
return event;
}
+ private long getAccessibilityShortcutTimeout() {
+ synchronized (mUserLock) {
+ final ViewConfiguration config = ViewConfiguration.get(mContext);
+ final boolean hasDialogShown = Settings.Secure.getIntForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0, mCurrentUserId) != 0;
+ final boolean skipTimeoutRestriction =
+ Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.SKIP_ACCESSIBILITY_SHORTCUT_DIALOG_TIMEOUT_RESTRICTION,
+ 0, mCurrentUserId) != 0;
+
+ // If users manually set the volume key shortcut for any accessibility service, the
+ // system would bypass the timeout restriction of the shortcut dialog.
+ return hasDialogShown || skipTimeoutRestriction
+ ? config.getAccessibilityShortcutKeyTimeoutAfterConfirmation()
+ : config.getAccessibilityShortcutKeyTimeout();
+ }
+ }
+
public void dump(IndentingPrintWriter ipw) {
ipw.println("KeyGestureController:");
ipw.increaseIndent();
@@ -1459,4 +1502,12 @@ final class KeyGestureController {
mAppLaunchShortcutManager.dump(ipw);
mInputGestureManager.dump(ipw);
}
+
+ @VisibleForTesting
+ static class Injector {
+ AccessibilityShortcutController getAccessibilityShortcutController(Context context,
+ Handler handler) {
+ return new AccessibilityShortcutController(context, handler, UserHandle.USER_SYSTEM);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 46dc75817a36..3230e891db55 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -4240,66 +4240,14 @@ public class PhoneWindowManager implements WindowManagerPolicy {
if (!useKeyGestureEventHandler()) {
return;
}
- mInputManager.registerKeyGestureEventHandler(new InputManager.KeyGestureEventHandler() {
- @Override
- public boolean handleKeyGestureEvent(@NonNull KeyGestureEvent event,
- @Nullable IBinder focusedToken) {
- boolean handled = PhoneWindowManager.this.handleKeyGestureEvent(event,
- focusedToken);
- if (handled && !event.isCancelled() && Arrays.stream(event.getKeycodes()).anyMatch(
- (keycode) -> keycode == KeyEvent.KEYCODE_POWER)) {
- mPowerKeyHandled = true;
- }
- return handled;
- }
-
- @Override
- public boolean isKeyGestureSupported(int gestureType) {
- switch (gestureType) {
- case KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS:
- case KeyGestureEvent.KEY_GESTURE_TYPE_APP_SWITCH:
- case KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_ASSISTANT:
- case KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT:
- case KeyGestureEvent.KEY_GESTURE_TYPE_HOME:
- case KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS:
- case KeyGestureEvent.KEY_GESTURE_TYPE_LOCK_SCREEN:
- case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL:
- case KeyGestureEvent.KEY_GESTURE_TYPE_TAKE_SCREENSHOT:
- case KeyGestureEvent.KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT:
- case KeyGestureEvent.KEY_GESTURE_TYPE_BACK:
- case KeyGestureEvent.KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION:
- case KeyGestureEvent.KEY_GESTURE_TYPE_DESKTOP_MODE:
- case KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_LEFT:
- case KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_RIGHT:
- case KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER:
- case KeyGestureEvent.KEY_GESTURE_TYPE_BRIGHTNESS_UP:
- case KeyGestureEvent.KEY_GESTURE_TYPE_BRIGHTNESS_DOWN:
- case KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS_SWITCHER:
- case KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS:
- case KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS:
- case KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_SEARCH:
- case KeyGestureEvent.KEY_GESTURE_TYPE_LANGUAGE_SWITCH:
- case KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT:
- case KeyGestureEvent.KEY_GESTURE_TYPE_CLOSE_ALL_DIALOGS:
- case KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION:
- case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_DO_NOT_DISTURB:
- case KeyGestureEvent.KEY_GESTURE_TYPE_SCREENSHOT_CHORD:
- case KeyGestureEvent.KEY_GESTURE_TYPE_RINGER_TOGGLE_CHORD:
- case KeyGestureEvent.KEY_GESTURE_TYPE_GLOBAL_ACTIONS:
- case KeyGestureEvent.KEY_GESTURE_TYPE_TV_TRIGGER_BUG_REPORT:
- case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_TALKBACK:
- case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_VOICE_ACCESS:
- return true;
- case KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT_CHORD:
- return mAccessibilityShortcutController.isAccessibilityShortcutAvailable(
- isKeyguardLocked());
- case KeyGestureEvent.KEY_GESTURE_TYPE_TV_ACCESSIBILITY_SHORTCUT_CHORD:
- return mAccessibilityShortcutController.isAccessibilityShortcutAvailable(
- false);
- default:
- return false;
- }
+ mInputManager.registerKeyGestureEventHandler((event, focusedToken) -> {
+ boolean handled = PhoneWindowManager.this.handleKeyGestureEvent(event,
+ focusedToken);
+ if (handled && !event.isCancelled() && Arrays.stream(event.getKeycodes()).anyMatch(
+ (keycode) -> keycode == KeyEvent.KEYCODE_POWER)) {
+ mPowerKeyHandled = true;
}
+ return handled;
});
}
@@ -4457,13 +4405,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
cancelPendingScreenshotChordAction();
}
return true;
- case KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT_CHORD:
- if (start) {
- interceptAccessibilityShortcutChord();
- } else {
- cancelPendingAccessibilityShortcutAction();
- }
- return true;
case KeyGestureEvent.KEY_GESTURE_TYPE_RINGER_TOGGLE_CHORD:
if (start) {
interceptRingerToggleChord();
@@ -4481,14 +4422,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
cancelGlobalActionsAction();
}
return true;
- // TODO (b/358569822): Consolidate TV and non-TV gestures into same KeyGestureEvent
- case KeyGestureEvent.KEY_GESTURE_TYPE_TV_ACCESSIBILITY_SHORTCUT_CHORD:
- if (start) {
- interceptAccessibilityGestureTv();
- } else {
- cancelAccessibilityGestureTv();
- }
- return true;
case KeyGestureEvent.KEY_GESTURE_TYPE_TV_TRIGGER_BUG_REPORT:
if (start) {
interceptBugreportGestureTv();
diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java
index 7751ac3f9fc6..a4bc5cbcb5d3 100644
--- a/services/core/java/com/android/server/wm/InputManagerCallback.java
+++ b/services/core/java/com/android/server/wm/InputManagerCallback.java
@@ -343,6 +343,13 @@ final class InputManagerCallback implements InputManagerService.WindowManagerCal
}
}
+ @Override
+ public boolean isKeyguardLocked(int displayId) {
+ synchronized (mService.mGlobalLock) {
+ return mService.mAtmService.mKeyguardController.isKeyguardLocked(displayId);
+ }
+ }
+
/** Waits until the built-in input devices have been configured. */
public boolean waitForInputDevicesReady(long timeoutMillis) {
synchronized (mInputDevicesReadyMonitor) {
diff --git a/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java b/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java
index 3ca019728c2b..fcdf88f16550 100644
--- a/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java
@@ -605,29 +605,6 @@ public class KeyGestureEventTests extends ShortcutKeyTestBase {
}
@Test
- public void testKeyGestureAccessibilityShortcutChord() {
- Assert.assertTrue(
- sendKeyGestureEventStart(
- KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT_CHORD));
- mPhoneWindowManager.moveTimeForward(5000);
- Assert.assertTrue(
- sendKeyGestureEventCancel(
- KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT_CHORD));
- mPhoneWindowManager.assertAccessibilityKeychordCalled();
- }
-
- @Test
- public void testKeyGestureAccessibilityShortcutChordCancelled() {
- Assert.assertTrue(
- sendKeyGestureEventStart(
- KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT_CHORD));
- Assert.assertTrue(
- sendKeyGestureEventCancel(
- KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT_CHORD));
- mPhoneWindowManager.assertAccessibilityKeychordNotCalled();
- }
-
- @Test
public void testKeyGestureRingerToggleChord() {
mPhoneWindowManager.overridePowerVolumeUp(POWER_VOLUME_UP_BEHAVIOR_MUTE);
Assert.assertTrue(
@@ -670,29 +647,6 @@ public class KeyGestureEventTests extends ShortcutKeyTestBase {
}
@Test
- public void testKeyGestureAccessibilityTvShortcutChord() {
- Assert.assertTrue(
- sendKeyGestureEventStart(
- KeyGestureEvent.KEY_GESTURE_TYPE_TV_ACCESSIBILITY_SHORTCUT_CHORD));
- mPhoneWindowManager.moveTimeForward(5000);
- Assert.assertTrue(
- sendKeyGestureEventCancel(
- KeyGestureEvent.KEY_GESTURE_TYPE_TV_ACCESSIBILITY_SHORTCUT_CHORD));
- mPhoneWindowManager.assertAccessibilityKeychordCalled();
- }
-
- @Test
- public void testKeyGestureAccessibilityTvShortcutChordCancelled() {
- Assert.assertTrue(
- sendKeyGestureEventStart(
- KeyGestureEvent.KEY_GESTURE_TYPE_TV_ACCESSIBILITY_SHORTCUT_CHORD));
- Assert.assertTrue(
- sendKeyGestureEventCancel(
- KeyGestureEvent.KEY_GESTURE_TYPE_TV_ACCESSIBILITY_SHORTCUT_CHORD));
- mPhoneWindowManager.assertAccessibilityKeychordNotCalled();
- }
-
- @Test
public void testKeyGestureTvTriggerBugReport() {
Assert.assertTrue(
sendKeyGestureEventStart(KeyGestureEvent.KEY_GESTURE_TYPE_TV_TRIGGER_BUG_REPORT));
diff --git a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
index f88492477487..e56fd3c6272d 100644
--- a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
+++ b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
@@ -750,11 +750,6 @@ class TestPhoneWindowManager {
verify(mAccessibilityShortcutController).performAccessibilityShortcut();
}
- void assertAccessibilityKeychordNotCalled() {
- mTestLooper.dispatchAll();
- verify(mAccessibilityShortcutController, never()).performAccessibilityShortcut();
- }
-
void assertCloseAllDialogs() {
verify(mContext).closeSystemDialogs();
}
diff --git a/tests/Input/src/android/hardware/input/KeyGestureEventHandlerTest.kt b/tests/Input/src/android/hardware/input/KeyGestureEventHandlerTest.kt
index e99c81493394..794fd0255726 100644
--- a/tests/Input/src/android/hardware/input/KeyGestureEventHandlerTest.kt
+++ b/tests/Input/src/android/hardware/input/KeyGestureEventHandlerTest.kt
@@ -214,9 +214,5 @@ class KeyGestureEventHandlerTest {
): Boolean {
return handler(event, focusedToken)
}
-
- override fun isKeyGestureSupported(gestureType: Int): Boolean {
- return true
- }
}
}
diff --git a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
index 2799f6c79215..4f1fb6487b19 100644
--- a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
+++ b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
@@ -32,6 +32,7 @@ import android.hardware.input.InputGestureData
import android.hardware.input.InputManager
import android.hardware.input.InputManagerGlobal
import android.hardware.input.KeyGestureEvent
+import android.os.Handler
import android.os.IBinder
import android.os.Process
import android.os.SystemClock
@@ -48,9 +49,11 @@ import android.view.WindowManagerPolicyConstants.FLAG_INTERACTIVE
import androidx.test.core.app.ApplicationProvider
import com.android.dx.mockito.inline.extended.ExtendedMockito
import com.android.internal.R
+import com.android.internal.accessibility.AccessibilityShortcutController
import com.android.internal.annotations.Keep
import com.android.internal.util.FrameworkStatsLog
import com.android.modules.utils.testing.ExtendedMockitoRule
+import com.android.server.input.InputManagerService.WindowManagerCallbacks
import java.io.File
import java.io.FileOutputStream
import java.io.InputStream
@@ -67,6 +70,8 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito
+import org.mockito.kotlin.never
+import org.mockito.kotlin.times
/**
* Tests for {@link KeyGestureController}.
@@ -102,6 +107,7 @@ class KeyGestureControllerTests {
const val SETTINGS_KEY_BEHAVIOR_SETTINGS_ACTIVITY = 0
const val SETTINGS_KEY_BEHAVIOR_NOTIFICATION_PANEL = 1
const val SETTINGS_KEY_BEHAVIOR_NOTHING = 2
+ const val TEST_PID = 10
}
@JvmField
@@ -116,11 +122,10 @@ class KeyGestureControllerTests {
@Rule
val rule = SetFlagsRule()
- @Mock
- private lateinit var iInputManager: IInputManager
-
- @Mock
- private lateinit var packageManager: PackageManager
+ @Mock private lateinit var iInputManager: IInputManager
+ @Mock private lateinit var packageManager: PackageManager
+ @Mock private lateinit var wmCallbacks: WindowManagerCallbacks
+ @Mock private lateinit var accessibilityShortcutController: AccessibilityShortcutController
private var currentPid = 0
private lateinit var context: Context
@@ -207,8 +212,34 @@ class KeyGestureControllerTests {
private fun setupKeyGestureController() {
keyGestureController =
- KeyGestureController(context, testLooper.looper, testLooper.looper, inputDataStore)
- Mockito.`when`(iInputManager.getAppLaunchBookmarks())
+ KeyGestureController(
+ context,
+ testLooper.looper,
+ testLooper.looper,
+ inputDataStore,
+ object : KeyGestureController.Injector() {
+ override fun getAccessibilityShortcutController(
+ context: Context?,
+ handler: Handler?
+ ): AccessibilityShortcutController {
+ return accessibilityShortcutController
+ }
+ })
+ Mockito.`when`(iInputManager.registerKeyGestureHandler(Mockito.any()))
+ .thenAnswer {
+ val args = it.arguments
+ if (args[0] != null) {
+ keyGestureController.registerKeyGestureHandler(
+ args[0] as IKeyGestureHandler,
+ TEST_PID
+ )
+ }
+ }
+ keyGestureController.setWindowManagerCallbacks(wmCallbacks)
+ Mockito.`when`(wmCallbacks.isKeyguardLocked(Mockito.anyInt())).thenReturn(false)
+ Mockito.`when`(accessibilityShortcutController
+ .isAccessibilityShortcutAvailable(Mockito.anyBoolean())).thenReturn(true)
+ Mockito.`when`(iInputManager.appLaunchBookmarks)
.thenReturn(keyGestureController.appLaunchBookmarks)
keyGestureController.systemRunning()
testLooper.dispatchAll()
@@ -1270,9 +1301,9 @@ class KeyGestureControllerTests {
)
),
TestData(
- "BACK + DPAD_DOWN -> TV Accessibility Chord",
+ "BACK + DPAD_DOWN -> Accessibility Chord(for TV)",
intArrayOf(KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_DPAD_DOWN),
- KeyGestureEvent.KEY_GESTURE_TYPE_TV_ACCESSIBILITY_SHORTCUT_CHORD,
+ KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT_CHORD,
intArrayOf(KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_DPAD_DOWN),
0,
intArrayOf(
@@ -1622,6 +1653,52 @@ class KeyGestureControllerTests {
)
}
+ @Test
+ fun testAccessibilityShortcutChordPressed() {
+ setupKeyGestureController()
+
+ sendKeys(
+ intArrayOf(KeyEvent.KEYCODE_VOLUME_UP, KeyEvent.KEYCODE_VOLUME_DOWN),
+ // Assuming this value is always greater than the accessibility shortcut timeout, which
+ // currently defaults to 3000ms
+ timeDelayMs = 10000
+ )
+ Mockito.verify(accessibilityShortcutController, times(1)).performAccessibilityShortcut()
+ }
+
+ @Test
+ fun testAccessibilityTvShortcutChordPressed() {
+ setupKeyGestureController()
+
+ sendKeys(
+ intArrayOf(KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_DPAD_DOWN),
+ timeDelayMs = 10000
+ )
+ Mockito.verify(accessibilityShortcutController, times(1)).performAccessibilityShortcut()
+ }
+
+ @Test
+ fun testAccessibilityShortcutChordPressedForLessThanTimeout() {
+ setupKeyGestureController()
+
+ sendKeys(
+ intArrayOf(KeyEvent.KEYCODE_VOLUME_UP, KeyEvent.KEYCODE_VOLUME_DOWN),
+ timeDelayMs = 0
+ )
+ Mockito.verify(accessibilityShortcutController, never()).performAccessibilityShortcut()
+ }
+
+ @Test
+ fun testAccessibilityTvShortcutChordPressedForLessThanTimeout() {
+ setupKeyGestureController()
+
+ sendKeys(
+ intArrayOf(KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_DPAD_DOWN),
+ timeDelayMs = 0
+ )
+ Mockito.verify(accessibilityShortcutController, never()).performAccessibilityShortcut()
+ }
+
private fun testKeyGestureInternal(test: TestData) {
val handledEvents = mutableListOf<KeyGestureEvent>()
val handler = KeyGestureHandler { event, _ ->
@@ -1683,7 +1760,11 @@ class KeyGestureControllerTests {
assertEquals("Test: $testName should not produce Key gesture", 0, handledEvents.size)
}
- private fun sendKeys(testKeys: IntArray, assertNotSentToApps: Boolean = false) {
+ private fun sendKeys(
+ testKeys: IntArray,
+ assertNotSentToApps: Boolean = false,
+ timeDelayMs: Long = 0
+ ) {
var metaState = 0
val now = SystemClock.uptimeMillis()
for (key in testKeys) {
@@ -1699,6 +1780,11 @@ class KeyGestureControllerTests {
testLooper.dispatchAll()
}
+ if (timeDelayMs > 0) {
+ testLooper.moveTimeForward(timeDelayMs)
+ testLooper.dispatchAll()
+ }
+
for (key in testKeys.reversed()) {
val upEvent = KeyEvent(
now, now, KeyEvent.ACTION_UP, key, 0 /*repeat*/, metaState,
@@ -1742,9 +1828,5 @@ class KeyGestureControllerTests {
override fun handleKeyGesture(event: AidlKeyGestureEvent, token: IBinder?): Boolean {
return handler(event, token)
}
-
- override fun isKeyGestureSupported(gestureType: Int): Boolean {
- return true
- }
}
}