Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3a56d9a1 authored by Vaibhav Devmurari's avatar Vaibhav Devmurari
Browse files

Consume key gesture events after they are handled.

Modify tests to see if keys are consumed when a key shortcut is
pressed. Some exceptions where keys are not to be fully consumed are
cases like multi key combinations, caps lock key.
Bug: 443845653
Test: atest KeyGestureControllerTests
Flag: EXEMPT bugfix

Change-Id: Ife8993700d4e2ee9656654e82cfde4ba50d982e6
parent ab3073a8
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -1138,6 +1138,7 @@ final class KeyGestureController {
                                KeyGestureEvent.KEY_GESTURE_TYPE_LANGUAGE_SWITCH,
                                KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
                                focusedToken, /* flags = */0, /* appLaunchData = */null);
                        return true;
                    }
                }
                break;
@@ -1152,6 +1153,7 @@ final class KeyGestureController {
                            KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT,
                            KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
                            focusedToken, /* flags = */0, /* appLaunchData = */null);
                    return true;
                }
                break;
            case KeyEvent.KEYCODE_SYSRQ:
@@ -1160,6 +1162,7 @@ final class KeyGestureController {
                            KeyGestureEvent.KEY_GESTURE_TYPE_TAKE_SCREENSHOT,
                            KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
                            focusedToken, /* flags = */0, /* appLaunchData = */null);
                    return true;
                }
                break;
            case KeyEvent.KEYCODE_ESCAPE:
@@ -1168,6 +1171,7 @@ final class KeyGestureController {
                            KeyGestureEvent.KEY_GESTURE_TYPE_CLOSE_ALL_DIALOGS,
                            KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
                            focusedToken, /* flags = */0, /* appLaunchData = */null);
                    return true;
                }
                break;
        }
+48 −9
Original line number Diff line number Diff line
@@ -373,6 +373,18 @@ class KeyGestureControllerTests {
        testKeyGestureProduced(test, PASS_THROUGH_APP)
    }

    @Keep
    private fun multiKeyGestureArguments(): Array<KeyGestureData> {
        return KeyGestureTestData.MULTI_KEY_SYSTEM_GESTURES
    }

    @Test
    @Parameters(method = "multiKeyGestureArguments")
    fun testMultiKeyGestures(test: KeyGestureData) {
        setupKeyGestureController()
        testKeyGestureProduced(test, BLOCKING_APP)
    }

    @Test
    @EnableFlags(com.android.window.flags.Flags.FLAG_TOGGLE_FULLSCREEN_STATE_VIA_FULLSCREEN_KEY)
    fun testCustomKeyGesturesNotAllowedForSystemGestures() {
@@ -604,7 +616,7 @@ class KeyGestureControllerTests {
        val listener = KeyGestureEventListener { event -> events.add(KeyGestureEvent(event)) }

        keyGestureController.registerKeyGestureEventListener(listener, 0)
        sendKeys(intArrayOf(KeyEvent.KEYCODE_CAPS_LOCK))
        sendKeys(intArrayOf(KeyEvent.KEYCODE_CAPS_LOCK), assertKeysFullyConsumed = false)
        testLooper.dispatchAll()
        assertEquals("Listener should get callbacks on key gesture event completed", 1, events.size)
        assertEquals(
@@ -961,7 +973,11 @@ class KeyGestureControllerTests {
    fun testAccessibilityTvShortcutChordPressed() {
        setupKeyGestureController()

        sendKeys(intArrayOf(KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_DPAD_DOWN), timeDelayMs = 10000)
        sendKeys(
            intArrayOf(KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_DPAD_DOWN),
            timeDelayMs = 10000,
            assertKeysFullyConsumed = false,
        )
        Mockito.verify(accessibilityShortcutController, times(1)).performAccessibilityShortcut()
    }

@@ -980,7 +996,11 @@ class KeyGestureControllerTests {
    fun testAccessibilityTvShortcutChordPressedForLessThanTimeout() {
        setupKeyGestureController()

        sendKeys(intArrayOf(KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_DPAD_DOWN), timeDelayMs = 0)
        sendKeys(
            intArrayOf(KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_DPAD_DOWN),
            timeDelayMs = 0,
            assertKeysFullyConsumed = false,
        )
        Mockito.verify(accessibilityShortcutController, never()).performAccessibilityShortcut()
    }

@@ -1363,6 +1383,7 @@ class KeyGestureControllerTests {
        sendKeys(
            intArrayOf(KeyEvent.KEYCODE_ESCAPE),
            timeDelayMs = 2 * LONG_PRESS_DELAY_FOR_ESCAPE_MILLIS,
            appDelegate = BLOCKING_APP,
        )
        keyGestureController.unregisterKeyGestureHandler(handler, TEST_PID)
        assertEquals(2, events.size)
@@ -1383,6 +1404,7 @@ class KeyGestureControllerTests {
        sendKeys(
            intArrayOf(KeyEvent.KEYCODE_ESCAPE),
            timeDelayMs = 2 * LONG_PRESS_DELAY_FOR_ESCAPE_MILLIS,
            appDelegate = BLOCKING_APP,
        )
        keyGestureController.unregisterKeyGestureHandler(handler, TEST_PID)
        assertEquals(0, events.size)
@@ -1402,6 +1424,7 @@ class KeyGestureControllerTests {
        sendKeys(
            intArrayOf(KeyEvent.KEYCODE_ESCAPE),
            timeDelayMs = LONG_PRESS_DELAY_FOR_ESCAPE_MILLIS / 2,
            appDelegate = BLOCKING_APP,
        )
        keyGestureController.unregisterKeyGestureHandler(handler, TEST_PID)
        assertEquals(2, events.size)
@@ -1512,6 +1535,7 @@ class KeyGestureControllerTests {
        appDelegate: AppDelegate = PASS_THROUGH_APP,
        timeDelayMs: Long = 0,
        displayId: Int = DEFAULT_DISPLAY,
        assertKeysFullyConsumed: Boolean = true,
    ) {
        var metaState = 0
        val now = SystemClock.uptimeMillis()
@@ -1531,7 +1555,10 @@ class KeyGestureControllerTests {
                    displayId,
                    /* characters= */ "",
                )
            interceptKey(downEvent, appDelegate)
            val consumed = interceptKey(downEvent, appDelegate)
            if (assertKeysFullyConsumed) {
                assertTrue("Key $downEvent should be consumed", consumed)
            }
            metaState = metaState or MODIFIER.getOrDefault(key, 0)

            downEvent.recycle()
@@ -1559,7 +1586,10 @@ class KeyGestureControllerTests {
                    displayId,
                    /* characters= */ "",
                )
            interceptKey(upEvent, appDelegate)
            val consumed = interceptKey(upEvent, appDelegate)
            if (assertKeysFullyConsumed) {
                assertTrue("Key $upEvent should be consumed", consumed)
            }
            metaState = metaState and MODIFIER.getOrDefault(key, 0).inv()

            upEvent.recycle()
@@ -1567,14 +1597,23 @@ class KeyGestureControllerTests {
        }
    }

    private fun interceptKey(event: KeyEvent, appDelegate: AppDelegate) {
    private fun interceptKey(event: KeyEvent, appDelegate: AppDelegate): Boolean {
        keyGestureController.interceptKeyBeforeQueueing(event, FLAG_INTERACTIVE)
        testLooper.dispatchAll()

        val consumed = keyGestureController.interceptKeyBeforeDispatching(null, event, 0) == -1L
        if (!consumed && !appDelegate.consumeKey(event)) {
            keyGestureController.interceptUnhandledKey(event, null)
        if (keyGestureController.interceptKeyBeforeDispatching(null, event, 0) != 0L) {
            return true
        }
        if (appDelegate.consumeKey(event)) {
            return true
        }
        if (keyGestureController.interceptUnhandledKey(event, null)) {
            return true
        }
        if (KeyEvent.isModifierKey(event.keyCode)) {
            return true
        }
        return false
    }

    fun overrideSendActionKeyEventsToFocusedWindow(
+8 −4
Original line number Diff line number Diff line
@@ -25,10 +25,7 @@ import android.view.KeyEvent
/** Test data for Key gestures tests in {@link KeyGestureControllerTests} */
object KeyGestureTestData {

    // All Key gestures that should always happen regardless of whether focused window captures the
    // keys should go in this list.
    // (i.e. Shortcuts and keys handled in INTERCEPT_SHORTCUTS_BEFORE_KEY_CAPTURE stage)
    val NON_CAPTURABLE_SYSTEM_GESTURES =
    val MULTI_KEY_SYSTEM_GESTURES =
        arrayOf(
            KeyGestureData(
                "VOLUME_DOWN + POWER -> Screenshot Chord",
@@ -89,6 +86,13 @@ object KeyGestureTestData {
                    KeyGestureEvent.ACTION_GESTURE_COMPLETE,
                ),
            ),
        )

    // All Key gestures that should always happen regardless of whether focused window captures the
    // keys should go in this list.
    // (i.e. Shortcuts and keys handled in INTERCEPT_SHORTCUTS_BEFORE_KEY_CAPTURE stage)
    val NON_CAPTURABLE_SYSTEM_GESTURES =
        arrayOf(
            KeyGestureData(
                "META + H -> Go Home",
                intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_H),