diff options
4 files changed, 455 insertions, 231 deletions
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index ca6051874d78..74891205f3c6 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -3453,8 +3453,16 @@ public class PhoneWindowManager implements WindowManagerPolicy { // NOTE: Please try not to add new Shortcut combinations here and instead use KeyGestureEvents. // Add shortcut trigger logic in {@code KeyGestureController} and add handling logic in // {@link handleKeyGesture()} - @SuppressLint("MissingPermission") private boolean interceptSystemKeysAndShortcuts(IBinder focusedToken, KeyEvent event) { + if (useKeyGestureEventHandler()) { + return interceptSystemKeysAndShortcutsNew(focusedToken, event); + } else { + return interceptSystemKeysAndShortcutsOld(focusedToken, event); + } + } + + @SuppressLint("MissingPermission") + private boolean interceptSystemKeysAndShortcutsOld(IBinder focusedToken, KeyEvent event) { final boolean keyguardOn = keyguardOn(); final int keyCode = event.getKeyCode(); final int repeatCount = event.getRepeatCount(); @@ -3878,6 +3886,59 @@ public class PhoneWindowManager implements WindowManagerPolicy { return (metaState & KeyEvent.META_META_ON) != 0; } + private boolean interceptSystemKeysAndShortcutsNew(IBinder focusedToken, KeyEvent event) { + final int keyCode = event.getKeyCode(); + final int metaState = event.getMetaState(); + final boolean keyguardOn = keyguardOn(); + + if (isUserSetupComplete() && !keyguardOn) { + if (mModifierShortcutManager.interceptKey(event)) { + dismissKeyboardShortcutsMenu(); + return true; + } + } + switch (keyCode) { + case KeyEvent.KEYCODE_HOME: + return handleHomeShortcuts(focusedToken, event); + case KeyEvent.KEYCODE_VOLUME_UP: + case KeyEvent.KEYCODE_VOLUME_DOWN: + case KeyEvent.KEYCODE_VOLUME_MUTE: + if (mUseTvRouting || mHandleVolumeKeysInWM) { + // On TVs or when the configuration is enabled, volume keys never + // go to the foreground app. + dispatchDirectAudioEvent(event); + return true; + } + + // If the device is in VR mode and keys are "internal" (e.g. on the side of the + // device), then drop the volume keys and don't forward it to the + // application/dispatch the audio event. + if (mDefaultDisplayPolicy.isPersistentVrModeEnabled()) { + final InputDevice d = event.getDevice(); + if (d != null && !d.isExternal()) { + return true; + } + } + break; + case KeyEvent.KEYCODE_STEM_PRIMARY: + if (prepareToSendSystemKeyToApplication(focusedToken, event)) { + // Send to app. + return false; + } else { + // Intercepted. + sendSystemKeyToStatusBarAsync(event); + return true; + } + } + if (isValidGlobalKey(keyCode) + && mGlobalKeyManager.handleGlobalKey(mContext, keyCode, event)) { + return true; + } + + // Reserve all the META modifier combos for system behavior + return (metaState & KeyEvent.META_META_ON) != 0; + } + @SuppressLint("MissingPermission") private void initKeyGestures() { if (!useKeyGestureEventHandler()) { 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 3d978e424375..81d63d31e776 100644 --- a/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java +++ b/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java @@ -26,6 +26,7 @@ import static com.android.server.policy.PhoneWindowManager.SETTINGS_KEY_BEHAVIOR import android.hardware.input.KeyGestureEvent; import android.os.RemoteException; +import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.Presubmit; import android.view.KeyEvent; @@ -56,7 +57,117 @@ public class KeyGestureEventTests extends ShortcutKeyTestBase { private static final int CTRL_ON = MODIFIER.get(KeyEvent.KEYCODE_CTRL_LEFT); @Keep - private static Object[][] shortcutTestArguments() { + private static Object[][] shortcutTestArgumentsNotMigratedToKeyGestureController() { + // testName, testKeys, expectedKeyGestureType, expectedKey, expectedModifierState + return new Object[][]{ + {"HOME key -> Open Home", new int[]{KeyEvent.KEYCODE_HOME}, + KeyGestureEvent.KEY_GESTURE_TYPE_HOME, + KeyEvent.KEYCODE_HOME, 0}, + {"BACK key -> Go back", new int[]{KeyEvent.KEYCODE_BACK}, + KeyGestureEvent.KEY_GESTURE_TYPE_BACK, + KeyEvent.KEYCODE_BACK, 0}, + {"VOLUME_UP key -> Increase Volume", new int[]{KeyEvent.KEYCODE_VOLUME_UP}, + KeyGestureEvent.KEY_GESTURE_TYPE_VOLUME_UP, + KeyEvent.KEYCODE_VOLUME_UP, 0}, + {"VOLUME_DOWN key -> Decrease Volume", new int[]{KeyEvent.KEYCODE_VOLUME_DOWN}, + KeyGestureEvent.KEY_GESTURE_TYPE_VOLUME_DOWN, + KeyEvent.KEYCODE_VOLUME_DOWN, 0}, + {"VOLUME_MUTE key -> Mute Volume", new int[]{KeyEvent.KEYCODE_VOLUME_MUTE}, + KeyGestureEvent.KEY_GESTURE_TYPE_VOLUME_MUTE, + KeyEvent.KEYCODE_VOLUME_MUTE, 0}, + {"MUTE key -> Mute System Microphone", new int[]{KeyEvent.KEYCODE_MUTE}, + KeyGestureEvent.KEY_GESTURE_TYPE_SYSTEM_MUTE, KeyEvent.KEYCODE_MUTE, + 0}, + {"POWER key -> Toggle Power", new int[]{KeyEvent.KEYCODE_POWER}, + KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_POWER, KeyEvent.KEYCODE_POWER, + 0}, + {"TV_POWER key -> Toggle Power", new int[]{KeyEvent.KEYCODE_TV_POWER}, + KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_POWER, + KeyEvent.KEYCODE_TV_POWER, 0}, + {"SYSTEM_NAVIGATION_DOWN key -> System Navigation", + new int[]{KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN}, + KeyGestureEvent.KEY_GESTURE_TYPE_SYSTEM_NAVIGATION, + KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN, + 0}, + {"SYSTEM_NAVIGATION_UP key -> System Navigation", + new int[]{KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP}, + KeyGestureEvent.KEY_GESTURE_TYPE_SYSTEM_NAVIGATION, + KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP, + 0}, + {"SYSTEM_NAVIGATION_LEFT key -> System Navigation", + new int[]{KeyEvent.KEYCODE_SYSTEM_NAVIGATION_LEFT}, + KeyGestureEvent.KEY_GESTURE_TYPE_SYSTEM_NAVIGATION, + KeyEvent.KEYCODE_SYSTEM_NAVIGATION_LEFT, + 0}, + {"SYSTEM_NAVIGATION_RIGHT key -> System Navigation", + new int[]{KeyEvent.KEYCODE_SYSTEM_NAVIGATION_RIGHT}, + KeyGestureEvent.KEY_GESTURE_TYPE_SYSTEM_NAVIGATION, + KeyEvent.KEYCODE_SYSTEM_NAVIGATION_RIGHT, 0}, + {"SLEEP key -> System Sleep", new int[]{KeyEvent.KEYCODE_SLEEP}, + KeyGestureEvent.KEY_GESTURE_TYPE_SLEEP, KeyEvent.KEYCODE_SLEEP, 0}, + {"SOFT_SLEEP key -> System Sleep", new int[]{KeyEvent.KEYCODE_SOFT_SLEEP}, + KeyGestureEvent.KEY_GESTURE_TYPE_SLEEP, KeyEvent.KEYCODE_SOFT_SLEEP, + 0}, + {"WAKEUP key -> System Wakeup", new int[]{KeyEvent.KEYCODE_WAKEUP}, + KeyGestureEvent.KEY_GESTURE_TYPE_WAKEUP, KeyEvent.KEYCODE_WAKEUP, 0}, + {"MEDIA_PLAY key -> Media Control", new int[]{KeyEvent.KEYCODE_MEDIA_PLAY}, + KeyGestureEvent.KEY_GESTURE_TYPE_MEDIA_KEY, + KeyEvent.KEYCODE_MEDIA_PLAY, 0}, + {"MEDIA_PAUSE key -> Media Control", new int[]{KeyEvent.KEYCODE_MEDIA_PAUSE}, + KeyGestureEvent.KEY_GESTURE_TYPE_MEDIA_KEY, + KeyEvent.KEYCODE_MEDIA_PAUSE, 0}, + {"MEDIA_PLAY_PAUSE key -> Media Control", + new int[]{KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE}, + KeyGestureEvent.KEY_GESTURE_TYPE_MEDIA_KEY, + KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, 0}, + {"Meta + B -> Launch Default Browser", new int[]{META_KEY, KeyEvent.KEYCODE_B}, + KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER, + KeyEvent.KEYCODE_B, META_ON}, + {"EXPLORER key -> Launch Default Browser", new int[]{KeyEvent.KEYCODE_EXPLORER}, + KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER, + KeyEvent.KEYCODE_EXPLORER, 0}, + {"Meta + C -> Launch Default Contacts", new int[]{META_KEY, KeyEvent.KEYCODE_C}, + KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS, + KeyEvent.KEYCODE_C, META_ON}, + {"CONTACTS key -> Launch Default Contacts", new int[]{KeyEvent.KEYCODE_CONTACTS}, + KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS, + KeyEvent.KEYCODE_CONTACTS, 0}, + {"Meta + E -> Launch Default Email", new int[]{META_KEY, KeyEvent.KEYCODE_E}, + KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL, + KeyEvent.KEYCODE_E, META_ON}, + {"ENVELOPE key -> Launch Default Email", new int[]{KeyEvent.KEYCODE_ENVELOPE}, + KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL, + KeyEvent.KEYCODE_ENVELOPE, 0}, + {"Meta + K -> Launch Default Calendar", new int[]{META_KEY, KeyEvent.KEYCODE_K}, + KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR, + KeyEvent.KEYCODE_K, META_ON}, + {"CALENDAR key -> Launch Default Calendar", new int[]{KeyEvent.KEYCODE_CALENDAR}, + KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR, + KeyEvent.KEYCODE_CALENDAR, 0}, + {"Meta + P -> Launch Default Music", new int[]{META_KEY, KeyEvent.KEYCODE_P}, + KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MUSIC, + KeyEvent.KEYCODE_P, META_ON}, + {"MUSIC key -> Launch Default Music", new int[]{KeyEvent.KEYCODE_MUSIC}, + KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MUSIC, + KeyEvent.KEYCODE_MUSIC, 0}, + {"Meta + U -> Launch Default Calculator", new int[]{META_KEY, KeyEvent.KEYCODE_U}, + KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR, + KeyEvent.KEYCODE_U, META_ON}, + {"CALCULATOR key -> Launch Default Calculator", + new int[]{KeyEvent.KEYCODE_CALCULATOR}, + KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR, + KeyEvent.KEYCODE_CALCULATOR, 0}, + {"Meta + M -> Launch Default Maps", new int[]{META_KEY, KeyEvent.KEYCODE_M}, + KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS, + KeyEvent.KEYCODE_M, META_ON}, + {"Meta + S -> Launch Default Messaging App", + new int[]{META_KEY, KeyEvent.KEYCODE_S}, + KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING, + KeyEvent.KEYCODE_S, META_ON}}; + } + + @Keep + private static Object[][] shortcutTestArgumentsMigratedToKeyGestureController() { // testName, testKeys, expectedKeyGestureType, expectedKey, expectedModifierState return new Object[][]{ {"Meta + H -> Open Home", new int[]{META_KEY, KeyEvent.KEYCODE_H}, @@ -64,9 +175,6 @@ public class KeyGestureEventTests extends ShortcutKeyTestBase { {"Meta + Enter -> Open Home", new int[]{META_KEY, KeyEvent.KEYCODE_ENTER}, KeyGestureEvent.KEY_GESTURE_TYPE_HOME, KeyEvent.KEYCODE_ENTER, META_ON}, - {"HOME key -> Open Home", new int[]{KeyEvent.KEYCODE_HOME}, - KeyGestureEvent.KEY_GESTURE_TYPE_HOME, - KeyEvent.KEYCODE_HOME, 0}, {"RECENT_APPS key -> Open Overview", new int[]{KeyEvent.KEYCODE_RECENT_APPS}, KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS, KeyEvent.KEYCODE_RECENT_APPS, 0}, @@ -76,9 +184,6 @@ public class KeyGestureEventTests extends ShortcutKeyTestBase { {"Alt + Tab -> Open Overview", new int[]{ALT_KEY, KeyEvent.KEYCODE_TAB}, KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS, KeyEvent.KEYCODE_TAB, ALT_ON}, - {"BACK key -> Go back", new int[]{KeyEvent.KEYCODE_BACK}, - KeyGestureEvent.KEY_GESTURE_TYPE_BACK, - KeyEvent.KEYCODE_BACK, 0}, {"Meta + Escape -> Go back", new int[]{META_KEY, KeyEvent.KEYCODE_ESCAPE}, KeyGestureEvent.KEY_GESTURE_TYPE_BACK, KeyEvent.KEYCODE_ESCAPE, META_ON}, @@ -138,15 +243,6 @@ public class KeyGestureEventTests extends ShortcutKeyTestBase { new int[]{KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_TOGGLE}, KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE, KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_TOGGLE, 0}, - {"VOLUME_UP key -> Increase Volume", new int[]{KeyEvent.KEYCODE_VOLUME_UP}, - KeyGestureEvent.KEY_GESTURE_TYPE_VOLUME_UP, - KeyEvent.KEYCODE_VOLUME_UP, 0}, - {"VOLUME_DOWN key -> Decrease Volume", new int[]{KeyEvent.KEYCODE_VOLUME_DOWN}, - KeyGestureEvent.KEY_GESTURE_TYPE_VOLUME_DOWN, - KeyEvent.KEYCODE_VOLUME_DOWN, 0}, - {"VOLUME_MUTE key -> Mute Volume", new int[]{KeyEvent.KEYCODE_VOLUME_MUTE}, - KeyGestureEvent.KEY_GESTURE_TYPE_VOLUME_MUTE, - KeyEvent.KEYCODE_VOLUME_MUTE, 0}, {"ALL_APPS key -> Open App Drawer", new int[]{KeyEvent.KEYCODE_ALL_APPS}, KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS, @@ -170,9 +266,6 @@ public class KeyGestureEventTests extends ShortcutKeyTestBase { {"CAPS_LOCK key -> Toggle CapsLock", new int[]{KeyEvent.KEYCODE_CAPS_LOCK}, KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK, KeyEvent.KEYCODE_CAPS_LOCK, 0}, - {"MUTE key -> Mute System Microphone", new int[]{KeyEvent.KEYCODE_MUTE}, - KeyGestureEvent.KEY_GESTURE_TYPE_SYSTEM_MUTE, KeyEvent.KEYCODE_MUTE, - 0}, {"Meta + Ctrl + DPAD_UP -> Split screen navigation", new int[]{META_KEY, CTRL_KEY, KeyEvent.KEYCODE_DPAD_UP}, KeyGestureEvent.KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION, @@ -194,92 +287,6 @@ public class KeyGestureEventTests extends ShortcutKeyTestBase { {"Meta + Ctrl + N -> Open Notes", new int[]{META_KEY, CTRL_KEY, KeyEvent.KEYCODE_N}, KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_NOTES, KeyEvent.KEYCODE_N, META_ON | CTRL_ON}, - {"POWER key -> Toggle Power", new int[]{KeyEvent.KEYCODE_POWER}, - KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_POWER, KeyEvent.KEYCODE_POWER, - 0}, - {"TV_POWER key -> Toggle Power", new int[]{KeyEvent.KEYCODE_TV_POWER}, - KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_POWER, - KeyEvent.KEYCODE_TV_POWER, 0}, - {"SYSTEM_NAVIGATION_DOWN key -> System Navigation", - new int[]{KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN}, - KeyGestureEvent.KEY_GESTURE_TYPE_SYSTEM_NAVIGATION, - KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN, - 0}, - {"SYSTEM_NAVIGATION_UP key -> System Navigation", - new int[]{KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP}, - KeyGestureEvent.KEY_GESTURE_TYPE_SYSTEM_NAVIGATION, - KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP, - 0}, - {"SYSTEM_NAVIGATION_LEFT key -> System Navigation", - new int[]{KeyEvent.KEYCODE_SYSTEM_NAVIGATION_LEFT}, - KeyGestureEvent.KEY_GESTURE_TYPE_SYSTEM_NAVIGATION, - KeyEvent.KEYCODE_SYSTEM_NAVIGATION_LEFT, - 0}, - {"SYSTEM_NAVIGATION_RIGHT key -> System Navigation", - new int[]{KeyEvent.KEYCODE_SYSTEM_NAVIGATION_RIGHT}, - KeyGestureEvent.KEY_GESTURE_TYPE_SYSTEM_NAVIGATION, - KeyEvent.KEYCODE_SYSTEM_NAVIGATION_RIGHT, 0}, - {"SLEEP key -> System Sleep", new int[]{KeyEvent.KEYCODE_SLEEP}, - KeyGestureEvent.KEY_GESTURE_TYPE_SLEEP, KeyEvent.KEYCODE_SLEEP, 0}, - {"SOFT_SLEEP key -> System Sleep", new int[]{KeyEvent.KEYCODE_SOFT_SLEEP}, - KeyGestureEvent.KEY_GESTURE_TYPE_SLEEP, KeyEvent.KEYCODE_SOFT_SLEEP, - 0}, - {"WAKEUP key -> System Wakeup", new int[]{KeyEvent.KEYCODE_WAKEUP}, - KeyGestureEvent.KEY_GESTURE_TYPE_WAKEUP, KeyEvent.KEYCODE_WAKEUP, 0}, - {"MEDIA_PLAY key -> Media Control", new int[]{KeyEvent.KEYCODE_MEDIA_PLAY}, - KeyGestureEvent.KEY_GESTURE_TYPE_MEDIA_KEY, - KeyEvent.KEYCODE_MEDIA_PLAY, 0}, - {"MEDIA_PAUSE key -> Media Control", new int[]{KeyEvent.KEYCODE_MEDIA_PAUSE}, - KeyGestureEvent.KEY_GESTURE_TYPE_MEDIA_KEY, - KeyEvent.KEYCODE_MEDIA_PAUSE, 0}, - {"MEDIA_PLAY_PAUSE key -> Media Control", - new int[]{KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE}, - KeyGestureEvent.KEY_GESTURE_TYPE_MEDIA_KEY, - KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, 0}, - {"Meta + B -> Launch Default Browser", new int[]{META_KEY, KeyEvent.KEYCODE_B}, - KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER, - KeyEvent.KEYCODE_B, META_ON}, - {"EXPLORER key -> Launch Default Browser", new int[]{KeyEvent.KEYCODE_EXPLORER}, - KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER, - KeyEvent.KEYCODE_EXPLORER, 0}, - {"Meta + C -> Launch Default Contacts", new int[]{META_KEY, KeyEvent.KEYCODE_C}, - KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS, - KeyEvent.KEYCODE_C, META_ON}, - {"CONTACTS key -> Launch Default Contacts", new int[]{KeyEvent.KEYCODE_CONTACTS}, - KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS, - KeyEvent.KEYCODE_CONTACTS, 0}, - {"Meta + E -> Launch Default Email", new int[]{META_KEY, KeyEvent.KEYCODE_E}, - KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL, - KeyEvent.KEYCODE_E, META_ON}, - {"ENVELOPE key -> Launch Default Email", new int[]{KeyEvent.KEYCODE_ENVELOPE}, - KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL, - KeyEvent.KEYCODE_ENVELOPE, 0}, - {"Meta + K -> Launch Default Calendar", new int[]{META_KEY, KeyEvent.KEYCODE_K}, - KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR, - KeyEvent.KEYCODE_K, META_ON}, - {"CALENDAR key -> Launch Default Calendar", new int[]{KeyEvent.KEYCODE_CALENDAR}, - KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR, - KeyEvent.KEYCODE_CALENDAR, 0}, - {"Meta + P -> Launch Default Music", new int[]{META_KEY, KeyEvent.KEYCODE_P}, - KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MUSIC, - KeyEvent.KEYCODE_P, META_ON}, - {"MUSIC key -> Launch Default Music", new int[]{KeyEvent.KEYCODE_MUSIC}, - KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MUSIC, - KeyEvent.KEYCODE_MUSIC, 0}, - {"Meta + U -> Launch Default Calculator", new int[]{META_KEY, KeyEvent.KEYCODE_U}, - KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR, - KeyEvent.KEYCODE_U, META_ON}, - {"CALCULATOR key -> Launch Default Calculator", - new int[]{KeyEvent.KEYCODE_CALCULATOR}, - KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR, - KeyEvent.KEYCODE_CALCULATOR, 0}, - {"Meta + M -> Launch Default Maps", new int[]{META_KEY, KeyEvent.KEYCODE_M}, - KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS, - KeyEvent.KEYCODE_M, META_ON}, - {"Meta + S -> Launch Default Messaging App", - new int[]{META_KEY, KeyEvent.KEYCODE_S}, - KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING, - KeyEvent.KEYCODE_S, META_ON}, {"Meta + Ctrl + DPAD_DOWN -> Enter desktop mode", new int[]{META_KEY, CTRL_KEY, KeyEvent.KEYCODE_DPAD_DOWN}, KeyGestureEvent.KEY_GESTURE_TYPE_DESKTOP_MODE, @@ -296,72 +303,14 @@ public class KeyGestureEventTests extends ShortcutKeyTestBase { new int[]{KeyEvent.KEYCODE_HOME}, LONG_PRESS_HOME_NOTIFICATION_PANEL, KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL, KeyEvent.KEYCODE_HOME, 0}, - {"Long press META + ENTER -> Toggle Notification panel", - new int[]{META_KEY, KeyEvent.KEYCODE_ENTER}, - LONG_PRESS_HOME_NOTIFICATION_PANEL, - KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL, - KeyEvent.KEYCODE_ENTER, - META_ON}, - {"Long press META + H -> Toggle Notification panel", - new int[]{META_KEY, KeyEvent.KEYCODE_H}, LONG_PRESS_HOME_NOTIFICATION_PANEL, - KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL, - KeyEvent.KEYCODE_H, META_ON}, {"Long press HOME key -> Launch assistant", new int[]{KeyEvent.KEYCODE_HOME}, LONG_PRESS_HOME_ASSIST, KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_ASSISTANT, KeyEvent.KEYCODE_HOME, 0}, - {"Long press META + ENTER -> Launch assistant", - new int[]{META_KEY, KeyEvent.KEYCODE_ENTER}, LONG_PRESS_HOME_ASSIST, - KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_ASSISTANT, - KeyEvent.KEYCODE_ENTER, META_ON}, - {"Long press META + H -> Launch assistant", - new int[]{META_KEY, KeyEvent.KEYCODE_H}, LONG_PRESS_HOME_ASSIST, - KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_ASSISTANT, KeyEvent.KEYCODE_H, - META_ON}, {"Long press HOME key -> Open App Drawer", new int[]{KeyEvent.KEYCODE_HOME}, LONG_PRESS_HOME_ALL_APPS, KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS, - KeyEvent.KEYCODE_HOME, 0}, - {"Long press META + ENTER -> Open App Drawer", - new int[]{META_KEY, KeyEvent.KEYCODE_ENTER}, LONG_PRESS_HOME_ALL_APPS, - KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS, - KeyEvent.KEYCODE_ENTER, META_ON}, - {"Long press META + H -> Open App Drawer", - new int[]{META_KEY, KeyEvent.KEYCODE_H}, - LONG_PRESS_HOME_ALL_APPS, - KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS, - KeyEvent.KEYCODE_H, META_ON}}; - } - - @Keep - private static Object[][] doubleTapOnHomeTestArguments() { - // testName, testKeys, doubleTapOnHomeBehavior, expectedKeyGestureType, expectedKey, - // expectedModifierState - return new Object[][]{ - {"Double tap HOME -> Open App switcher", - new int[]{KeyEvent.KEYCODE_HOME}, DOUBLE_TAP_HOME_RECENT_SYSTEM_UI, - KeyGestureEvent.KEY_GESTURE_TYPE_APP_SWITCH, KeyEvent.KEYCODE_HOME, - 0}, - {"Double tap META + ENTER -> Open App switcher", - new int[]{META_KEY, KeyEvent.KEYCODE_ENTER}, - DOUBLE_TAP_HOME_RECENT_SYSTEM_UI, - KeyGestureEvent.KEY_GESTURE_TYPE_APP_SWITCH, - KeyEvent.KEYCODE_ENTER, META_ON}, - {"Double tap META + H -> Open App switcher", - new int[]{META_KEY, KeyEvent.KEYCODE_H}, DOUBLE_TAP_HOME_RECENT_SYSTEM_UI, - KeyGestureEvent.KEY_GESTURE_TYPE_APP_SWITCH, KeyEvent.KEYCODE_H, - META_ON}}; - } - - @Keep - private static Object[][] settingsKeyTestArguments() { - // testName, testKeys, settingsKeyBehavior, expectedKeyGestureType, expectedKey, - // expectedModifierState - return new Object[][]{ - {"SETTINGS key -> Toggle Notification panel", new int[]{KeyEvent.KEYCODE_SETTINGS}, - SETTINGS_KEY_BEHAVIOR_NOTIFICATION_PANEL, - KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL, - KeyEvent.KEYCODE_SETTINGS, 0}}; + KeyEvent.KEYCODE_HOME, 0}}; } @Before @@ -381,8 +330,18 @@ public class KeyGestureEventTests extends ShortcutKeyTestBase { } @Test - @Parameters(method = "shortcutTestArguments") - public void testShortcut(String testName, int[] testKeys, + @Parameters(method = "shortcutTestArgumentsNotMigratedToKeyGestureController") + public void testShortcuts_notMigratedToKeyGestureController(String testName, + int[] testKeys, @KeyGestureEvent.KeyGestureType int expectedKeyGestureType, + int expectedKey, int expectedModifierState) { + testShortcutInternal(testName, testKeys, expectedKeyGestureType, expectedKey, + expectedModifierState); + } + + @Test + @Parameters(method = "shortcutTestArgumentsMigratedToKeyGestureController") + @DisableFlags(com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER) + public void testShortcuts_migratedToKeyGestureController(String testName, int[] testKeys, @KeyGestureEvent.KeyGestureType int expectedKeyGestureType, int expectedKey, int expectedModifierState) { testShortcutInternal(testName, testKeys, expectedKeyGestureType, expectedKey, @@ -402,31 +361,29 @@ public class KeyGestureEventTests extends ShortcutKeyTestBase { } @Test - @Parameters(method = "doubleTapOnHomeTestArguments") - public void testDoubleTapOnHomeBehavior(String testName, int[] testKeys, - int doubleTapOnHomeBehavior, - @KeyGestureEvent.KeyGestureType int expectedKeyGestureType, int expectedKey, - int expectedModifierState) { - mPhoneWindowManager.overriderDoubleTapOnHomeBehavior(doubleTapOnHomeBehavior); - sendKeyCombination(testKeys, 0 /* duration */); - sendKeyCombination(testKeys, 0 /* duration */); + public void testDoubleTapOnHomeBehavior_AppSwitchBehavior() { + mPhoneWindowManager.overriderDoubleTapOnHomeBehavior(DOUBLE_TAP_HOME_RECENT_SYSTEM_UI); + sendKeyCombination(new int[]{KeyEvent.KEYCODE_HOME}, 0 /* duration */); + sendKeyCombination(new int[]{KeyEvent.KEYCODE_HOME}, 0 /* duration */); mPhoneWindowManager.assertKeyGestureCompleted( - new int[]{expectedKey}, expectedModifierState, expectedKeyGestureType, - "Failed while executing " + testName); + new int[]{KeyEvent.KEYCODE_HOME}, /* modifierState = */0, + KeyGestureEvent.KEY_GESTURE_TYPE_APP_SWITCH, + "Failed while executing Double tap HOME -> Open App switcher"); } @Test - @Parameters(method = "settingsKeyTestArguments") - public void testSettingsKey(String testName, int[] testKeys, int settingsKeyBehavior, - @KeyGestureEvent.KeyGestureType int expectedKeyGestureType, int expectedKey, - int expectedModifierState) { - mPhoneWindowManager.overrideSettingsKeyBehavior(settingsKeyBehavior); - testShortcutInternal(testName, testKeys, expectedKeyGestureType, expectedKey, - expectedModifierState); + @DisableFlags(com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER) + public void testSettingsKey_ToggleNotificationBehavior() { + mPhoneWindowManager.overrideSettingsKeyBehavior(SETTINGS_KEY_BEHAVIOR_NOTIFICATION_PANEL); + testShortcutInternal("SETTINGS key -> Toggle Notification panel", + new int[]{KeyEvent.KEYCODE_SETTINGS}, + KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL, + KeyEvent.KEYCODE_SETTINGS, 0); } @Test @EnableFlags(com.android.server.flags.Flags.FLAG_NEW_BUGREPORT_KEYBOARD_SHORTCUT) + @DisableFlags(com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER) public void testBugreportShortcutPress() { testShortcutInternal("Meta + Ctrl + Del -> Trigger bug report", new int[]{META_KEY, CTRL_KEY, KeyEvent.KEYCODE_DEL}, 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 43171f847818..b54e74fb5188 100644 --- a/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutTests.java +++ b/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutTests.java @@ -119,6 +119,7 @@ public class ModifierShortcutTests extends ShortcutKeyTestBase { * ALT + TAB to show recent apps. */ @Test + @DisableFlags(com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER) public void testAltTab() { mPhoneWindowManager.overrideStatusBarManagerInternal(); sendKeyCombination(new int[]{KEYCODE_ALT_LEFT, KEYCODE_TAB}, 0); @@ -158,6 +159,7 @@ public class ModifierShortcutTests extends ShortcutKeyTestBase { * META + CTRL+ S to take screenshot. */ @Test + @DisableFlags(com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER) public void testMetaCtrlS() { sendKeyCombination(new int[]{KEYCODE_META_LEFT, KEYCODE_CTRL_LEFT, KEYCODE_S}, 0); mPhoneWindowManager.assertTakeScreenshotCalled(); @@ -167,6 +169,7 @@ public class ModifierShortcutTests extends ShortcutKeyTestBase { * META + N to expand notification panel. */ @Test + @DisableFlags(com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER) public void testMetaN() throws RemoteException { mPhoneWindowManager.overrideTogglePanel(); sendKeyCombination(new int[]{KEYCODE_META_LEFT, KEYCODE_N}, 0); @@ -177,6 +180,7 @@ public class ModifierShortcutTests extends ShortcutKeyTestBase { * META + SLASH to toggle shortcuts menu. */ @Test + @DisableFlags(com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER) public void testMetaSlash() { mPhoneWindowManager.overrideStatusBarManagerInternal(); sendKeyCombination(new int[]{KEYCODE_META_LEFT, KEYCODE_SLASH}, 0); @@ -187,6 +191,7 @@ public class ModifierShortcutTests extends ShortcutKeyTestBase { * META + ALT to toggle Cap Lock. */ @Test + @DisableFlags(com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER) public void testMetaAlt() { sendKeyCombination(new int[]{KEYCODE_META_LEFT, KEYCODE_ALT_LEFT}, 0); mPhoneWindowManager.assertToggleCapsLock(); @@ -196,6 +201,7 @@ public class ModifierShortcutTests extends ShortcutKeyTestBase { * META + H to go to homescreen */ @Test + @DisableFlags(com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER) public void testMetaH() { mPhoneWindowManager.overrideLaunchHome(); sendKeyCombination(new int[]{KEYCODE_META_LEFT, KEYCODE_H}, 0); @@ -206,6 +212,7 @@ public class ModifierShortcutTests extends ShortcutKeyTestBase { * META + ENTER to go to homescreen */ @Test + @DisableFlags(com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER) public void testMetaEnter() { mPhoneWindowManager.overrideLaunchHome(); sendKeyCombination(new int[]{KEYCODE_META_LEFT, KEYCODE_ENTER}, 0); @@ -216,6 +223,7 @@ public class ModifierShortcutTests extends ShortcutKeyTestBase { * Sends a KEYCODE_BRIGHTNESS_DOWN event and validates the brightness is decreased as expected; */ @Test + @DisableFlags(com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER) public void testKeyCodeBrightnessDown() { float[] currentBrightness = new float[]{0.1f, 0.05f, 0.0f}; float[] newBrightness = new float[]{0.065738f, 0.0275134f, 0.0f}; @@ -231,9 +239,9 @@ public class ModifierShortcutTests extends ShortcutKeyTestBase { * Sends a KEYCODE_SCREENSHOT and validates screenshot is taken if flag is enabled */ @Test + @EnableFlags(com.android.hardware.input.Flags.FLAG_EMOJI_AND_SCREENSHOT_KEYCODES_AVAILABLE) + @DisableFlags(com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER) public void testTakeScreenshot_flagEnabled() { - mSetFlagsRule.enableFlags(com.android.hardware.input.Flags - .FLAG_EMOJI_AND_SCREENSHOT_KEYCODES_AVAILABLE); sendKeyCombination(new int[]{KEYCODE_SCREENSHOT}, 0); mPhoneWindowManager.assertTakeScreenshotCalled(); } @@ -242,9 +250,9 @@ public class ModifierShortcutTests extends ShortcutKeyTestBase { * Sends a KEYCODE_SCREENSHOT and validates screenshot is not taken if flag is disabled */ @Test + @DisableFlags({com.android.hardware.input.Flags.FLAG_EMOJI_AND_SCREENSHOT_KEYCODES_AVAILABLE, + com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER}) public void testTakeScreenshot_flagDisabled() { - mSetFlagsRule.disableFlags(com.android.hardware.input.Flags - .FLAG_EMOJI_AND_SCREENSHOT_KEYCODES_AVAILABLE); sendKeyCombination(new int[]{KEYCODE_SCREENSHOT}, 0); mPhoneWindowManager.assertTakeScreenshotNotCalled(); } @@ -254,6 +262,7 @@ public class ModifierShortcutTests extends ShortcutKeyTestBase { */ @Test @EnableFlags(com.android.server.flags.Flags.FLAG_NEW_BUGREPORT_KEYBOARD_SHORTCUT) + @DisableFlags(com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER) public void testTakeBugReport_flagEnabled() throws RemoteException { sendKeyCombination(new int[]{KEYCODE_META_LEFT, KEYCODE_CTRL_LEFT, KEYCODE_DEL}, 0); mPhoneWindowManager.assertTakeBugreport(true); @@ -263,7 +272,8 @@ public class ModifierShortcutTests extends ShortcutKeyTestBase { * META+CTRL+BACKSPACE for taking a bugreport does nothing when the flag is disabledd. */ @Test - @DisableFlags(com.android.server.flags.Flags.FLAG_NEW_BUGREPORT_KEYBOARD_SHORTCUT) + @DisableFlags({com.android.server.flags.Flags.FLAG_NEW_BUGREPORT_KEYBOARD_SHORTCUT, + com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER}) public void testTakeBugReport_flagDisabled() throws RemoteException { sendKeyCombination(new int[]{KEYCODE_META_LEFT, KEYCODE_CTRL_LEFT, KEYCODE_DEL}, 0); mPhoneWindowManager.assertTakeBugreport(false); diff --git a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt index ba360070abc3..b448c7eb3092 100644 --- a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt +++ b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt @@ -18,6 +18,7 @@ package com.android.server.input import android.content.Context import android.content.ContextWrapper +import android.content.res.Resources import android.hardware.input.IInputManager import android.hardware.input.AidlKeyGestureEvent import android.hardware.input.IKeyGestureEventListener @@ -25,15 +26,18 @@ import android.hardware.input.IKeyGestureHandler import android.hardware.input.InputManager import android.hardware.input.InputManagerGlobal import android.hardware.input.KeyGestureEvent -import android.hardware.input.KeyGestureEvent.KeyGestureType import android.os.IBinder import android.os.Process +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 import android.view.InputDevice -import android.view.KeyCharacterMap import android.view.KeyEvent import androidx.test.core.app.ApplicationProvider +import com.android.internal.R import com.android.internal.annotations.Keep import com.android.internal.util.FrameworkStatsLog import com.android.modules.utils.testing.ExtendedMockitoRule @@ -78,32 +82,43 @@ class KeyGestureControllerTests { KeyEvent.KEYCODE_META_LEFT to (KeyEvent.META_META_LEFT_ON or KeyEvent.META_META_ON), KeyEvent.KEYCODE_META_RIGHT to (KeyEvent.META_META_RIGHT_ON or KeyEvent.META_META_ON), ) + const val SEARCH_KEY_BEHAVIOR_DEFAULT_SEARCH = 0 + const val SEARCH_KEY_BEHAVIOR_TARGET_ACTIVITY = 1 + const val SETTINGS_KEY_BEHAVIOR_SETTINGS_ACTIVITY = 0 + const val SETTINGS_KEY_BEHAVIOR_NOTIFICATION_PANEL = 1 + const val SETTINGS_KEY_BEHAVIOR_NOTHING = 2 } @JvmField @Rule val extendedMockitoRule = ExtendedMockitoRule.Builder(this) - .mockStatic(FrameworkStatsLog::class.java).build()!! + .mockStatic(FrameworkStatsLog::class.java) + .mockStatic(SystemProperties::class.java).build()!! + + @JvmField + @Rule + val rule = SetFlagsRule() @Mock private lateinit var iInputManager: IInputManager + @Mock + private lateinit var resources: Resources + private var currentPid = 0 - private lateinit var keyGestureController: KeyGestureController private lateinit var context: Context private lateinit var inputManagerGlobalSession: InputManagerGlobal.TestSession private lateinit var testLooper: TestLooper private var events = mutableListOf<KeyGestureEvent>() - private var handleEvents = mutableListOf<KeyGestureEvent>() @Before fun setup() { context = Mockito.spy(ContextWrapper(ApplicationProvider.getApplicationContext())) + Mockito.`when`(context.resources).thenReturn(resources) inputManagerGlobalSession = InputManagerGlobal.createTestSession(iInputManager) setupInputDevices() testLooper = TestLooper() currentPid = Process.myPid() - keyGestureController = KeyGestureController(context, testLooper.looper) } private fun setupInputDevices() { @@ -116,7 +131,7 @@ class KeyGestureControllerTests { Mockito.`when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardDevice) } - private fun notifyHomeGestureCompleted() { + private fun notifyHomeGestureCompleted(keyGestureController: KeyGestureController) { keyGestureController.notifyKeyGestureCompleted(DEVICE_ID, intArrayOf(KeyEvent.KEYCODE_H), KeyEvent.META_META_ON or KeyEvent.META_META_LEFT_ON, KeyGestureEvent.KEY_GESTURE_TYPE_HOME) @@ -124,11 +139,12 @@ class KeyGestureControllerTests { @Test fun testKeyGestureEvent_registerUnregisterListener() { + val keyGestureController = KeyGestureController(context, testLooper.looper) val listener = KeyGestureEventListener() // Register key gesture event listener keyGestureController.registerKeyGestureEventListener(listener, 0) - notifyHomeGestureCompleted() + notifyHomeGestureCompleted(keyGestureController) testLooper.dispatchAll() assertEquals( "Listener should get callbacks on key gesture event completed", @@ -144,7 +160,7 @@ class KeyGestureControllerTests { // Unregister listener events.clear() keyGestureController.unregisterKeyGestureEventListener(listener, 0) - notifyHomeGestureCompleted() + notifyHomeGestureCompleted(keyGestureController) testLooper.dispatchAll() assertEquals( "Listener should not get callback after being unregistered", @@ -155,6 +171,8 @@ class KeyGestureControllerTests { @Test fun testKeyGestureEvent_multipleGestureHandlers() { + val keyGestureController = KeyGestureController(context, testLooper.looper) + // Set up two callbacks. var callbackCount1 = 0 var callbackCount2 = 0 @@ -406,6 +424,14 @@ class KeyGestureControllerTests { intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE) ), TestData( + "META + / -> Open Shortcut Helper", + intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_SLASH), + KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER, + intArrayOf(KeyEvent.KEYCODE_SLASH), + KeyEvent.META_META_ON, + intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE) + ), + TestData( "BRIGHTNESS_UP -> Brightness Up", intArrayOf(KeyEvent.KEYCODE_BRIGHTNESS_UP), KeyGestureEvent.KEY_GESTURE_TYPE_BRIGHTNESS_UP, @@ -534,6 +560,188 @@ class KeyGestureControllerTests { @Test @Parameters(method = "keyGestureEventHandlerTestArguments") fun testKeyGestures(test: TestData) { + val keyGestureController = KeyGestureController(context, testLooper.looper) + testKeyGestureInternal(keyGestureController, test) + } + + @Test + fun testKeycodesFullyConsumed_irrespectiveOfHandlers() { + val keyGestureController = KeyGestureController(context, testLooper.looper) + val testKeys = intArrayOf( + KeyEvent.KEYCODE_RECENT_APPS, + KeyEvent.KEYCODE_APP_SWITCH, + KeyEvent.KEYCODE_BRIGHTNESS_UP, + KeyEvent.KEYCODE_BRIGHTNESS_DOWN, + KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_DOWN, + KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_UP, + KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_TOGGLE, + KeyEvent.KEYCODE_ALL_APPS, + KeyEvent.KEYCODE_NOTIFICATION, + KeyEvent.KEYCODE_SETTINGS, + KeyEvent.KEYCODE_LANGUAGE_SWITCH, + KeyEvent.KEYCODE_SCREENSHOT, + KeyEvent.KEYCODE_META_LEFT, + KeyEvent.KEYCODE_META_RIGHT, + KeyEvent.KEYCODE_ASSIST, + KeyEvent.KEYCODE_VOICE_ASSIST, + KeyEvent.KEYCODE_STYLUS_BUTTON_PRIMARY, + KeyEvent.KEYCODE_STYLUS_BUTTON_SECONDARY, + KeyEvent.KEYCODE_STYLUS_BUTTON_TERTIARY, + KeyEvent.KEYCODE_STYLUS_BUTTON_TAIL, + ) + + val handler = KeyGestureHandler { _, _ -> false } + keyGestureController.registerKeyGestureHandler(handler, 0) + + for (key in testKeys) { + sendKeys(keyGestureController, intArrayOf(key), assertAllConsumed = true) + } + } + + @Test + fun testSearchKeyGestures_defaultSearch() { + Mockito.`when`(resources.getInteger(R.integer.config_searchKeyBehavior)) + .thenReturn(SEARCH_KEY_BEHAVIOR_DEFAULT_SEARCH) + val keyGestureController = KeyGestureController(context, testLooper.looper) + testKeyGestureNotProduced( + keyGestureController, + "SEARCH -> Default Search", + intArrayOf(KeyEvent.KEYCODE_SEARCH), + ) + } + + @Test + fun testSearchKeyGestures_searchActivity() { + Mockito.`when`(resources.getInteger(R.integer.config_searchKeyBehavior)) + .thenReturn(SEARCH_KEY_BEHAVIOR_TARGET_ACTIVITY) + val keyGestureController = KeyGestureController(context, testLooper.looper) + testKeyGestureInternal( + keyGestureController, + TestData( + "SEARCH -> Launch Search Activity", + intArrayOf(KeyEvent.KEYCODE_SEARCH), + KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_SEARCH, + intArrayOf(KeyEvent.KEYCODE_SEARCH), + 0, + intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE) + ) + ) + } + + @Test + fun testSettingKeyGestures_doNothing() { + Mockito.`when`(resources.getInteger(R.integer.config_settingsKeyBehavior)) + .thenReturn(SETTINGS_KEY_BEHAVIOR_NOTHING) + val keyGestureController = KeyGestureController(context, testLooper.looper) + testKeyGestureNotProduced( + keyGestureController, + "SETTINGS -> Do Nothing", + intArrayOf(KeyEvent.KEYCODE_SETTINGS), + ) + } + + @Test + fun testSettingKeyGestures_settingsActivity() { + Mockito.`when`(resources.getInteger(R.integer.config_settingsKeyBehavior)) + .thenReturn(SETTINGS_KEY_BEHAVIOR_SETTINGS_ACTIVITY) + val keyGestureController = KeyGestureController(context, testLooper.looper) + testKeyGestureInternal( + keyGestureController, + TestData( + "SETTINGS -> Launch Settings Activity", + intArrayOf(KeyEvent.KEYCODE_SETTINGS), + KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS, + intArrayOf(KeyEvent.KEYCODE_SETTINGS), + 0, + intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE) + ) + ) + } + + @Test + fun testSettingKeyGestures_notificationPanel() { + Mockito.`when`(resources.getInteger(R.integer.config_settingsKeyBehavior)) + .thenReturn(SETTINGS_KEY_BEHAVIOR_NOTIFICATION_PANEL) + val keyGestureController = KeyGestureController(context, testLooper.looper) + testKeyGestureInternal( + keyGestureController, + TestData( + "SETTINGS -> Toggle Notification Panel", + intArrayOf(KeyEvent.KEYCODE_SETTINGS), + KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL, + intArrayOf(KeyEvent.KEYCODE_SETTINGS), + 0, + intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE) + ) + ) + } + + @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 + fun testCapsLockPressNotified() { + val keyGestureController = KeyGestureController(context, testLooper.looper) + val listener = KeyGestureEventListener() + + keyGestureController.registerKeyGestureEventListener(listener, 0) + sendKeys(keyGestureController, intArrayOf(KeyEvent.KEYCODE_CAPS_LOCK)) + testLooper.dispatchAll() + assertEquals( + "Listener should get callbacks on key gesture event completed", + 1, + events.size + ) + assertEquals( + "Listener should get callback for Toggle Caps Lock key gesture complete event", + KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK, + events[0].keyGestureType + ) + } + + private fun testKeyGestureInternal(keyGestureController: KeyGestureController, test: TestData) { + var handleEvents = mutableListOf<KeyGestureEvent>() val handler = KeyGestureHandler { event, _ -> handleEvents.add(KeyGestureEvent(event)) true @@ -541,7 +749,7 @@ class KeyGestureControllerTests { keyGestureController.registerKeyGestureHandler(handler, 0) handleEvents.clear() - sendKeys(test.keys, /* assertAllConsumed = */ false) + sendKeys(keyGestureController, test.keys) assertEquals( "Test: $test doesn't produce correct number of key gesture events", @@ -575,45 +783,33 @@ class KeyGestureControllerTests { keyGestureController.unregisterKeyGestureHandler(handler, 0) } - @Test - fun testKeycodesFullyConsumed_irrespectiveOfHandlers() { - val testKeys = intArrayOf( - KeyEvent.KEYCODE_RECENT_APPS, - KeyEvent.KEYCODE_APP_SWITCH, - KeyEvent.KEYCODE_BRIGHTNESS_UP, - KeyEvent.KEYCODE_BRIGHTNESS_DOWN, - KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_DOWN, - KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_UP, - KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_TOGGLE, - KeyEvent.KEYCODE_ALL_APPS, - KeyEvent.KEYCODE_NOTIFICATION, - KeyEvent.KEYCODE_SETTINGS, - KeyEvent.KEYCODE_LANGUAGE_SWITCH, - KeyEvent.KEYCODE_SCREENSHOT, - KeyEvent.KEYCODE_META_LEFT, - KeyEvent.KEYCODE_META_RIGHT, - KeyEvent.KEYCODE_ASSIST, - KeyEvent.KEYCODE_VOICE_ASSIST, - KeyEvent.KEYCODE_STYLUS_BUTTON_PRIMARY, - KeyEvent.KEYCODE_STYLUS_BUTTON_SECONDARY, - KeyEvent.KEYCODE_STYLUS_BUTTON_TERTIARY, - KeyEvent.KEYCODE_STYLUS_BUTTON_TAIL, - ) - - val handler = KeyGestureHandler { _, _ -> false } + private fun testKeyGestureNotProduced( + keyGestureController: KeyGestureController, + testName: String, + testKeys: IntArray + ) { + var handleEvents = mutableListOf<KeyGestureEvent>() + val handler = KeyGestureHandler { event, _ -> + handleEvents.add(KeyGestureEvent(event)) + true + } keyGestureController.registerKeyGestureHandler(handler, 0) + handleEvents.clear() - for (key in testKeys) { - sendKeys(intArrayOf(key), /* assertAllConsumed = */ true) - } + sendKeys(keyGestureController, testKeys) + assertEquals("Test: $testName should not produce Key gesture", 0, handleEvents.size) } - private fun sendKeys(testKeys: IntArray, assertAllConsumed: Boolean) { + private fun sendKeys( + keyGestureController: KeyGestureController, + testKeys: IntArray, + assertAllConsumed: Boolean = false + ) { var metaState = 0 for (key in testKeys) { val downEvent = KeyEvent( /* downTime = */0, /* eventTime = */ 0, KeyEvent.ACTION_DOWN, key, - 0 /*repeat*/, metaState, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/, + 0 /*repeat*/, metaState, DEVICE_ID, 0 /*scancode*/, 0 /*flags*/, InputDevice.SOURCE_KEYBOARD ) val consumed = @@ -633,7 +829,7 @@ class KeyGestureControllerTests { for (key in testKeys.reversed()) { val upEvent = KeyEvent( /* downTime = */0, /* eventTime = */ 0, KeyEvent.ACTION_UP, key, - 0 /*repeat*/, metaState, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/, + 0 /*repeat*/, metaState, DEVICE_ID, 0 /*scancode*/, 0 /*flags*/, InputDevice.SOURCE_KEYBOARD ) val consumed = |