summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/hardware/input/KeyGestureEvent.java11
-rw-r--r--services/core/java/com/android/server/input/InputManagerService.java82
-rw-r--r--services/core/java/com/android/server/input/KeyGestureController.java55
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java112
-rw-r--r--services/core/java/com/android/server/policy/WindowManagerPolicy.java6
-rw-r--r--services/core/java/com/android/server/wm/InputManagerCallback.java5
-rw-r--r--services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java15
-rw-r--r--services/tests/wmtests/src/com/android/server/policy/ModifierShortcutTests.java3
-rw-r--r--services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java8
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java4
-rw-r--r--tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt105
12 files changed, 274 insertions, 134 deletions
diff --git a/core/java/android/hardware/input/KeyGestureEvent.java b/core/java/android/hardware/input/KeyGestureEvent.java
index ef0bb98b5a26..5ee61bcd436a 100644
--- a/core/java/android/hardware/input/KeyGestureEvent.java
+++ b/core/java/android/hardware/input/KeyGestureEvent.java
@@ -97,6 +97,8 @@ public final class KeyGestureEvent {
public static final int KEY_GESTURE_TYPE_GLOBAL_ACTIONS = 57;
public static final int 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;
public static final int FLAG_CANCELLED = 1;
@@ -170,7 +172,10 @@ public final class KeyGestureEvent {
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_TV_TRIGGER_BUG_REPORT,
+ KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT,
+ KEY_GESTURE_TYPE_CLOSE_ALL_DIALOGS,
+
})
@Retention(RetentionPolicy.SOURCE)
public @interface KeyGestureType {
@@ -583,6 +588,10 @@ public final class KeyGestureEvent {
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:
+ return "KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT";
+ case KEY_GESTURE_TYPE_CLOSE_ALL_DIALOGS:
+ return "KEY_GESTURE_TYPE_CLOSE_ALL_DIALOGS";
default:
return Integer.toHexString(value);
}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 631663ac7dea..909c47bc9359 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -25,6 +25,7 @@ import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_M
import static com.android.hardware.input.Flags.touchpadVisualizer;
import static com.android.hardware.input.Flags.useKeyGestureEventHandler;
+import static com.android.server.policy.WindowManagerPolicy.ACTION_PASS_TO_USER;
import android.Manifest;
import android.annotation.EnforcePermission;
@@ -326,6 +327,9 @@ public class InputManagerService extends IInputManager.Stub
// Manages Sticky modifier state
private final StickyModifierStateController mStickyModifierStateController;
private final KeyGestureController mKeyGestureController;
+ /** Fallback actions by key code */
+ private final SparseArray<KeyCharacterMap.FallbackAction> mFallbackActions =
+ new SparseArray<>();
// Manages Keyboard microphone mute led
private final KeyboardLedController mKeyboardLedController;
@@ -2521,6 +2525,74 @@ public class InputManagerService extends IInputManager.Stub
null, null, null) == PERMISSION_GRANTED;
}
+ // Native callback.
+ @SuppressWarnings("unused")
+ private KeyEvent dispatchUnhandledKey(IBinder focus, KeyEvent event, int policyFlags) {
+ if (interceptUnhandledKey(event, focus)) {
+ return null;
+ }
+ // TODO(b/358569822): Move fallback logic to KeyGestureController
+ if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) != 0) {
+ return null;
+ }
+ final KeyCharacterMap kcm = event.getKeyCharacterMap();
+ final int keyCode = event.getKeyCode();
+ final int metaState = event.getMetaState();
+ final boolean initialDown = event.getAction() == KeyEvent.ACTION_DOWN
+ && event.getRepeatCount() == 0;
+
+ // Check for fallback actions specified by the key character map.
+ final KeyCharacterMap.FallbackAction fallbackAction;
+ if (initialDown) {
+ fallbackAction = kcm.getFallbackAction(keyCode, metaState);
+ } else {
+ fallbackAction = mFallbackActions.get(keyCode);
+ }
+
+ if (fallbackAction == null) {
+ return null;
+ }
+ KeyEvent fallbackEvent = null;
+ final int flags = event.getFlags() | KeyEvent.FLAG_FALLBACK;
+ fallbackEvent = KeyEvent.obtain(
+ event.getDownTime(), event.getEventTime(),
+ event.getAction(), fallbackAction.keyCode,
+ event.getRepeatCount(), fallbackAction.metaState,
+ event.getDeviceId(), event.getScanCode(),
+ flags, event.getSource(), event.getDisplayId(), null);
+
+ if (!interceptFallback(focus, fallbackEvent, policyFlags)) {
+ fallbackEvent.recycle();
+ fallbackEvent = null;
+ }
+
+ if (initialDown) {
+ mFallbackActions.put(keyCode, fallbackAction);
+ } else if (event.getAction() == KeyEvent.ACTION_UP) {
+ mFallbackActions.remove(keyCode);
+ fallbackAction.recycle();
+ }
+ return fallbackEvent;
+ }
+
+ private boolean interceptFallback(IBinder focusedToken, KeyEvent fallbackEvent,
+ int policyFlags) {
+ int actions = interceptKeyBeforeQueueing(fallbackEvent, policyFlags);
+ if ((actions & ACTION_PASS_TO_USER) == 0) {
+ return false;
+ }
+ long delayMillis = interceptKeyBeforeDispatching(focusedToken, fallbackEvent, policyFlags);
+ return delayMillis == 0 && !interceptUnhandledKey(fallbackEvent, focusedToken);
+ }
+
+ private boolean interceptUnhandledKey(KeyEvent event, IBinder focus) {
+ if (useKeyGestureEventHandler() && mKeyGestureController.interceptUnhandledKey(event,
+ focus)) {
+ return true;
+ }
+ return mWindowManagerCallbacks.interceptUnhandledKey(event, focus);
+ }
+
private void initKeyGestures() {
if (!useKeyGestureEventHandler()) {
return;
@@ -2576,12 +2648,6 @@ public class InputManagerService extends IInputManager.Stub
// Native callback.
@SuppressWarnings("unused")
- private KeyEvent dispatchUnhandledKey(IBinder focus, KeyEvent event, int policyFlags) {
- return mWindowManagerCallbacks.dispatchUnhandledKey(focus, event, policyFlags);
- }
-
- // Native callback.
- @SuppressWarnings("unused")
private void onPointerDownOutsideFocus(IBinder touchedToken) {
mWindowManagerCallbacks.onPointerDownOutsideFocus(touchedToken);
}
@@ -2996,9 +3062,9 @@ public class InputManagerService extends IInputManager.Stub
long interceptKeyBeforeDispatching(IBinder token, KeyEvent event, int policyFlags);
/**
- * Dispatch unhandled key
+ * Intercept unhandled key
*/
- KeyEvent dispatchUnhandledKey(IBinder token, KeyEvent event, int policyFlags);
+ boolean interceptUnhandledKey(KeyEvent event, IBinder token);
int getPointerLayer();
diff --git a/services/core/java/com/android/server/input/KeyGestureController.java b/services/core/java/com/android/server/input/KeyGestureController.java
index 5def0857bc17..b488db533d12 100644
--- a/services/core/java/com/android/server/input/KeyGestureController.java
+++ b/services/core/java/com/android/server/input/KeyGestureController.java
@@ -872,6 +872,61 @@ final class KeyGestureController {
return false;
}
+ boolean interceptUnhandledKey(KeyEvent event, IBinder focusedToken) {
+ final int keyCode = event.getKeyCode();
+ final int repeatCount = event.getRepeatCount();
+ final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
+ final int metaState = event.getModifiers();
+ final int deviceId = event.getDeviceId();
+ final int displayId = event.getDisplayId();
+
+ switch(keyCode) {
+ case KeyEvent.KEYCODE_SPACE:
+ if (down && repeatCount == 0) {
+ // Handle keyboard layout switching. (CTRL + SPACE)
+ if (KeyEvent.metaStateHasModifiers(metaState & ~KeyEvent.META_SHIFT_MASK,
+ KeyEvent.META_CTRL_ON)) {
+ return handleKeyGesture(deviceId, new int[]{keyCode},
+ KeyEvent.META_CTRL_ON | (event.isShiftPressed()
+ ? KeyEvent.META_SHIFT_ON : 0),
+ KeyGestureEvent.KEY_GESTURE_TYPE_LANGUAGE_SWITCH,
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
+ focusedToken, /* flags = */0);
+ }
+ }
+ break;
+ case KeyEvent.KEYCODE_Z:
+ if (down && KeyEvent.metaStateHasModifiers(metaState,
+ KeyEvent.META_CTRL_ON | KeyEvent.META_ALT_ON)) {
+ // Intercept the Accessibility keychord (CTRL + ALT + Z) for keyboard users.
+ return handleKeyGesture(deviceId, new int[]{keyCode},
+ KeyEvent.META_CTRL_ON | KeyEvent.META_ALT_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT,
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
+ focusedToken, /* flags = */0);
+ }
+ break;
+ case KeyEvent.KEYCODE_SYSRQ:
+ if (down && repeatCount == 0) {
+ return handleKeyGesture(deviceId, new int[]{keyCode}, /* modifierState = */0,
+ KeyGestureEvent.KEY_GESTURE_TYPE_TAKE_SCREENSHOT,
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
+ focusedToken, /* flags = */0);
+ }
+ break;
+ case KeyEvent.KEYCODE_ESCAPE:
+ if (down && KeyEvent.metaStateHasNoModifiers(metaState) && repeatCount == 0) {
+ return handleKeyGesture(deviceId, new int[]{keyCode}, /* modifierState = */0,
+ KeyGestureEvent.KEY_GESTURE_TYPE_CLOSE_ALL_DIALOGS,
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
+ focusedToken, /* flags = */0);
+ }
+ break;
+ }
+
+ return false;
+ }
+
private boolean handleKeyGesture(int[] keycodes,
@KeyGestureEvent.KeyGestureType int gestureType, int action, int flags) {
return handleKeyGesture(KeyCharacterMap.VIRTUAL_KEYBOARD, keycodes, /* modifierState= */0,
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 29d00ca2b2e0..228405074dbb 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -199,7 +199,6 @@ import android.view.HapticFeedbackConstants;
import android.view.IDisplayFoldListener;
import android.view.InputDevice;
import android.view.KeyCharacterMap;
-import android.view.KeyCharacterMap.FallbackAction;
import android.view.KeyEvent;
import android.view.KeyboardShortcutGroup;
import android.view.MotionEvent;
@@ -699,10 +698,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// Maps global key codes to the components that will handle them.
private GlobalKeyManager mGlobalKeyManager;
- // Fallback actions by key code.
- private final SparseArray<KeyCharacterMap.FallbackAction> mFallbackActions =
- new SparseArray<KeyCharacterMap.FallbackAction>();
-
private final com.android.internal.policy.LogDecelerateInterpolator mLogDecelerateInterpolator
= new LogDecelerateInterpolator(100, 0);
private final DeferredKeyActionExecutor mDeferredKeyActionExecutor =
@@ -3993,6 +3988,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
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:
return true;
case KeyGestureEvent.KEY_GESTURE_TYPE_SCREENSHOT_CHORD:
case KeyGestureEvent.KEY_GESTURE_TYPE_RINGER_TOGGLE_CHORD:
@@ -4211,6 +4208,17 @@ public class PhoneWindowManager implements WindowManagerPolicy {
cancelBugreportGestureTv();
}
return true;
+ case KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT:
+ if (complete && mAccessibilityShortcutController.isAccessibilityShortcutAvailable(
+ isKeyguardLocked())) {
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_ACCESSIBILITY_SHORTCUT));
+ }
+ return true;
+ case KeyGestureEvent.KEY_GESTURE_TYPE_CLOSE_ALL_DIALOGS:
+ if (complete) {
+ mContext.closeSystemDialogs();
+ }
+ return true;
}
return false;
}
@@ -4396,7 +4404,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// TODO(b/117479243): handle it in InputPolicy
/** {@inheritDoc} */
@Override
- public KeyEvent dispatchUnhandledKey(IBinder focusedToken, KeyEvent event, int policyFlags) {
+ public boolean interceptUnhandledKey(KeyEvent event, IBinder focusedToken) {
// Note: This method is only called if the initial down was unhandled.
if (DEBUG_INPUT) {
final KeyInterceptionInfo info =
@@ -4409,75 +4417,26 @@ public class PhoneWindowManager implements WindowManagerPolicy {
+ ", keyCode=" + event.getKeyCode()
+ ", scanCode=" + event.getScanCode()
+ ", metaState=" + event.getMetaState()
- + ", repeatCount=" + event.getRepeatCount()
- + ", policyFlags=" + policyFlags);
- }
-
- if (interceptUnhandledKey(event, focusedToken)) {
- return null;
- }
-
- KeyEvent fallbackEvent = null;
- if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
- final KeyCharacterMap kcm = event.getKeyCharacterMap();
- final int keyCode = event.getKeyCode();
- final int metaState = event.getMetaState();
- final boolean initialDown = event.getAction() == KeyEvent.ACTION_DOWN
- && event.getRepeatCount() == 0;
-
- // Check for fallback actions specified by the key character map.
- final FallbackAction fallbackAction;
- if (initialDown) {
- fallbackAction = kcm.getFallbackAction(keyCode, metaState);
- } else {
- fallbackAction = mFallbackActions.get(keyCode);
- }
-
- if (fallbackAction != null) {
- if (DEBUG_INPUT) {
- Slog.d(TAG, "Fallback: keyCode=" + fallbackAction.keyCode
- + " metaState=" + Integer.toHexString(fallbackAction.metaState));
- }
-
- final int flags = event.getFlags() | KeyEvent.FLAG_FALLBACK;
- fallbackEvent = KeyEvent.obtain(
- event.getDownTime(), event.getEventTime(),
- event.getAction(), fallbackAction.keyCode,
- event.getRepeatCount(), fallbackAction.metaState,
- event.getDeviceId(), event.getScanCode(),
- flags, event.getSource(), event.getDisplayId(), null);
-
- if (!interceptFallback(focusedToken, fallbackEvent, policyFlags)) {
- fallbackEvent.recycle();
- fallbackEvent = null;
- }
-
- if (initialDown) {
- mFallbackActions.put(keyCode, fallbackAction);
- } else if (event.getAction() == KeyEvent.ACTION_UP) {
- mFallbackActions.remove(keyCode);
- fallbackAction.recycle();
- }
- }
+ + ", repeatCount=" + event.getRepeatCount());
}
- if (DEBUG_INPUT) {
- if (fallbackEvent == null) {
- Slog.d(TAG, "No fallback.");
- } else {
- Slog.d(TAG, "Performing fallback: " + fallbackEvent);
- }
- }
- return fallbackEvent;
- }
-
- private boolean interceptUnhandledKey(KeyEvent event, IBinder focusedToken) {
final int keyCode = event.getKeyCode();
final int repeatCount = event.getRepeatCount();
final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
final int metaState = event.getModifiers();
- switch(keyCode) {
+ // TODO(b/358569822): Shift to KeyGestureEvent based handling
+ if (keyCode == KeyEvent.KEYCODE_STEM_PRIMARY) {
+ handleUnhandledSystemKey(event);
+ sendSystemKeyToStatusBarAsync(event);
+ return true;
+ }
+
+ if (useKeyGestureEventHandler()) {
+ return false;
+ }
+
+ switch (keyCode) {
case KeyEvent.KEYCODE_SPACE:
if (down && repeatCount == 0) {
// Handle keyboard layout switching. (CTRL + SPACE)
@@ -4514,10 +4473,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return true;
}
break;
- case KeyEvent.KEYCODE_STEM_PRIMARY:
- handleUnhandledSystemKey(event);
- sendSystemKeyToStatusBarAsync(event);
- return true;
}
return false;
@@ -4556,19 +4511,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
targetWindowToken);
}
- private boolean interceptFallback(IBinder focusedToken, KeyEvent fallbackEvent,
- int policyFlags) {
- int actions = interceptKeyBeforeQueueing(fallbackEvent, policyFlags);
- if ((actions & ACTION_PASS_TO_USER) != 0) {
- long delayMillis = interceptKeyBeforeDispatching(
- focusedToken, fallbackEvent, policyFlags);
- if (delayMillis == 0 && !interceptUnhandledKey(fallbackEvent, focusedToken)) {
- return true;
- }
- }
- return false;
- }
-
@Override
public void setTopFocusedDisplay(int displayId) {
mTopFocusedDisplayId = displayId;
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 892af6bec534..ad116578ae41 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -754,11 +754,9 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
* @param focusedToken Client window token that currently has focus. This is where the key
* event will normally go.
* @param event The key event.
- * @param policyFlags The policy flags associated with the key.
- * @return Returns an alternate key event to redispatch as a fallback, or null to give up.
- * The caller is responsible for recycling the key event.
+ * @return true if the unhandled key is intercepted by the policy.
*/
- KeyEvent dispatchUnhandledKey(IBinder focusedToken, KeyEvent event, int policyFlags);
+ boolean interceptUnhandledKey(KeyEvent event, IBinder focusedToken);
/**
* Called when the top focused display is changed.
diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java
index 232c3b62bcef..dcf031953610 100644
--- a/services/core/java/com/android/server/wm/InputManagerCallback.java
+++ b/services/core/java/com/android/server/wm/InputManagerCallback.java
@@ -188,9 +188,8 @@ final class InputManagerCallback implements InputManagerService.WindowManagerCal
* the application did not handle.
*/
@Override
- public KeyEvent dispatchUnhandledKey(
- IBinder focusedToken, KeyEvent event, int policyFlags) {
- return mService.mPolicy.dispatchUnhandledKey(focusedToken, event, policyFlags);
+ public boolean interceptUnhandledKey(KeyEvent event, IBinder focusedToken) {
+ return mService.mPolicy.interceptUnhandledKey(event, focusedToken);
}
/** Callback to get pointer layer. */
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 fbdc78b78810..cdb45423c11a 100644
--- a/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java
@@ -684,4 +684,19 @@ public class KeyGestureEventTests extends ShortcutKeyTestBase {
sendKeyGestureEventCancel(KeyGestureEvent.KEY_GESTURE_TYPE_TV_TRIGGER_BUG_REPORT));
mPhoneWindowManager.assertBugReportNotTakenForTv();
}
+
+ @Test
+ public void testKeyGestureAccessibilityShortcut() {
+ Assert.assertTrue(
+ sendKeyGestureEventComplete(
+ KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT));
+ mPhoneWindowManager.assertAccessibilityKeychordCalled();
+ }
+
+ @Test
+ public void testKeyGestureCloseAllDialogs() {
+ Assert.assertTrue(
+ sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_CLOSE_ALL_DIALOGS));
+ mPhoneWindowManager.assertCloseAllDialogs();
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutTests.java b/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutTests.java
index b54e74fb5188..c186a0355588 100644
--- a/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutTests.java
@@ -130,6 +130,7 @@ public class ModifierShortcutTests extends ShortcutKeyTestBase {
* CTRL + SPACE to switch keyboard layout.
*/
@Test
+ @DisableFlags(com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER)
public void testCtrlSpace() {
sendKeyCombination(new int[]{KEYCODE_CTRL_LEFT, KEYCODE_SPACE}, /* duration= */ 0,
ANY_DISPLAY_ID);
@@ -140,6 +141,7 @@ public class ModifierShortcutTests extends ShortcutKeyTestBase {
* CTRL + SHIFT + SPACE to switch keyboard layout backwards.
*/
@Test
+ @DisableFlags(com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER)
public void testCtrlShiftSpace() {
sendKeyCombination(new int[]{KEYCODE_CTRL_LEFT, KEYCODE_SHIFT_LEFT, KEYCODE_SPACE},
/* duration= */ 0, ANY_DISPLAY_ID);
@@ -150,6 +152,7 @@ public class ModifierShortcutTests extends ShortcutKeyTestBase {
* CTRL + ALT + Z to enable accessibility service.
*/
@Test
+ @DisableFlags(com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER)
public void testCtrlAltZ() {
sendKeyCombination(new int[]{KEYCODE_CTRL_LEFT, KEYCODE_ALT_LEFT, KEYCODE_Z}, 0);
mPhoneWindowManager.assertAccessibilityKeychordCalled();
diff --git a/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java b/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java
index 2aed30a5108c..9e47a008592c 100644
--- a/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java
+++ b/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java
@@ -283,7 +283,7 @@ class ShortcutKeyTestBase {
if ((actions & ACTION_PASS_TO_USER) != 0) {
if (0 == mPhoneWindowManager.interceptKeyBeforeDispatching(keyEvent)) {
if (!mDispatchedKeyHandler.onKeyDispatched(keyEvent)) {
- mPhoneWindowManager.dispatchUnhandledKey(keyEvent);
+ mPhoneWindowManager.interceptUnhandledKey(keyEvent);
}
}
}
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 0d8c05903d2c..1aa908792c0e 100644
--- a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
+++ b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
@@ -418,8 +418,8 @@ class TestPhoneWindowManager {
mKeyEventPolicyFlags);
}
- void dispatchUnhandledKey(KeyEvent event) {
- mPhoneWindowManager.dispatchUnhandledKey(mInputToken, event, FLAG_INTERACTIVE);
+ void interceptUnhandledKey(KeyEvent event) {
+ mPhoneWindowManager.interceptUnhandledKey(event, mInputToken);
}
boolean sendKeyGestureEvent(KeyGestureEvent event) {
@@ -683,6 +683,10 @@ class TestPhoneWindowManager {
verify(mAccessibilityShortcutController, never()).performAccessibilityShortcut();
}
+ void assertCloseAllDialogs() {
+ verify(mContext).closeSystemDialogs();
+ }
+
void assertDreamRequest() {
mTestLooper.dispatchAll();
verify(mDreamManagerInternal).requestDream();
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
index eebb487d16cd..9e9874b32893 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -103,8 +103,8 @@ class TestWindowManagerPolicy implements WindowManagerPolicy {
}
@Override
- public KeyEvent dispatchUnhandledKey(IBinder focusedToken, KeyEvent event, int policyFlags) {
- return null;
+ public boolean interceptUnhandledKey(KeyEvent event, IBinder focusedToken) {
+ return false;
}
@Override
diff --git a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
index f4bebb566cba..4ae06a4f9812 100644
--- a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
+++ b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
@@ -152,9 +152,11 @@ class KeyGestureControllerTests {
}
private fun notifyHomeGestureCompleted(keyGestureController: KeyGestureController) {
- keyGestureController.notifyKeyGestureCompleted(DEVICE_ID, intArrayOf(KeyEvent.KEYCODE_H),
+ keyGestureController.notifyKeyGestureCompleted(
+ DEVICE_ID, intArrayOf(KeyEvent.KEYCODE_H),
KeyEvent.META_META_ON or KeyEvent.META_META_LEFT_ON,
- KeyGestureEvent.KEY_GESTURE_TYPE_HOME)
+ KeyGestureEvent.KEY_GESTURE_TYPE_HOME
+ )
}
@Test
@@ -574,6 +576,54 @@ class KeyGestureControllerTests {
KeyGestureEvent.ACTION_GESTURE_COMPLETE
)
),
+ TestData(
+ "CTRL + SPACE -> Switch Language Forward",
+ intArrayOf(KeyEvent.KEYCODE_CTRL_LEFT, KeyEvent.KEYCODE_SPACE),
+ KeyGestureEvent.KEY_GESTURE_TYPE_LANGUAGE_SWITCH,
+ intArrayOf(KeyEvent.KEYCODE_SPACE),
+ KeyEvent.META_CTRL_ON,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "CTRL + SHIFT + SPACE -> Switch Language Backward",
+ intArrayOf(
+ KeyEvent.KEYCODE_CTRL_LEFT,
+ KeyEvent.KEYCODE_SHIFT_LEFT,
+ KeyEvent.KEYCODE_SPACE
+ ),
+ KeyGestureEvent.KEY_GESTURE_TYPE_LANGUAGE_SWITCH,
+ intArrayOf(KeyEvent.KEYCODE_SPACE),
+ KeyEvent.META_CTRL_ON or KeyEvent.META_SHIFT_ON,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "CTRL + ALT + Z -> Accessibility Shortcut",
+ intArrayOf(
+ KeyEvent.KEYCODE_CTRL_LEFT,
+ KeyEvent.KEYCODE_ALT_LEFT,
+ KeyEvent.KEYCODE_Z
+ ),
+ KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT,
+ intArrayOf(KeyEvent.KEYCODE_Z),
+ KeyEvent.META_CTRL_ON or KeyEvent.META_ALT_ON,
+ 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)
+ ),
)
}
@@ -614,7 +664,7 @@ class KeyGestureControllerTests {
keyGestureController.registerKeyGestureHandler(handler, 0)
for (key in testKeys) {
- sendKeys(keyGestureController, intArrayOf(key), assertAllConsumed = true)
+ sendKeys(keyGestureController, intArrayOf(key), assertNotSentToApps = true)
}
}
@@ -895,7 +945,7 @@ class KeyGestureControllerTests {
private fun sendKeys(
keyGestureController: KeyGestureController,
testKeys: IntArray,
- assertAllConsumed: Boolean = false
+ assertNotSentToApps: Boolean = false
) {
var metaState = 0
val now = SystemClock.uptimeMillis()
@@ -905,18 +955,7 @@ class KeyGestureControllerTests {
DEVICE_ID, 0 /*scancode*/, 0 /*flags*/,
InputDevice.SOURCE_KEYBOARD
)
-
- keyGestureController.interceptKeyBeforeQueueing(downEvent, FLAG_INTERACTIVE)
- testLooper.dispatchAll()
-
- val consumed =
- keyGestureController.interceptKeyBeforeDispatching(null, downEvent, 0) == -1L
- if (assertAllConsumed) {
- assertTrue(
- "interceptKeyBeforeDispatching should consume all events $downEvent",
- consumed
- )
- }
+ interceptKey(keyGestureController, downEvent, assertNotSentToApps)
metaState = metaState or MODIFIER.getOrDefault(key, 0)
downEvent.recycle()
@@ -929,18 +968,7 @@ class KeyGestureControllerTests {
DEVICE_ID, 0 /*scancode*/, 0 /*flags*/,
InputDevice.SOURCE_KEYBOARD
)
-
- keyGestureController.interceptKeyBeforeQueueing(upEvent, FLAG_INTERACTIVE)
- testLooper.dispatchAll()
-
- val consumed =
- keyGestureController.interceptKeyBeforeDispatching(null, upEvent, 0) == -1L
- if (assertAllConsumed) {
- assertTrue(
- "interceptKeyBeforeDispatching should consume all events $upEvent",
- consumed
- )
- }
+ interceptKey(keyGestureController, upEvent, assertNotSentToApps)
metaState = metaState and MODIFIER.getOrDefault(key, 0).inv()
upEvent.recycle()
@@ -948,6 +976,27 @@ class KeyGestureControllerTests {
}
}
+ private fun interceptKey(
+ keyGestureController: KeyGestureController,
+ event: KeyEvent,
+ assertNotSentToApps: Boolean
+ ) {
+ keyGestureController.interceptKeyBeforeQueueing(event, FLAG_INTERACTIVE)
+ testLooper.dispatchAll()
+
+ val consumed =
+ keyGestureController.interceptKeyBeforeDispatching(null, event, 0) == -1L
+ if (assertNotSentToApps) {
+ assertTrue(
+ "interceptKeyBeforeDispatching should consume all events $event",
+ consumed
+ )
+ }
+ if (!consumed) {
+ keyGestureController.interceptUnhandledKey(event, null)
+ }
+ }
+
inner class KeyGestureEventListener : IKeyGestureEventListener.Stub() {
override fun onKeyGestureEvent(event: AidlKeyGestureEvent) {
events.add(KeyGestureEvent(event))