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

Commit 08fc3ca8 authored by Vaibhav Devmurari's avatar Vaibhav Devmurari Committed by Android (Google) Code Review
Browse files

Merge changes Ife899370,Ic72507fb into main

* changes:
  Consume key gesture events after they are handled.
  Change Assistant shortcut to Meta+Space instead of Meta+A
parents 451d5285 3a56d9a1
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -19,7 +19,6 @@ package com.android.systemui.keyboard.shortcut.data.source
import android.content.res.Resources
import android.hardware.input.InputManager
import android.hardware.input.KeyGlyphMap
import android.view.KeyEvent.KEYCODE_A
import android.view.KeyEvent.KEYCODE_BACK
import android.view.KeyEvent.KEYCODE_DPAD_LEFT
import android.view.KeyEvent.KEYCODE_ESCAPE
@@ -32,6 +31,7 @@ import android.view.KeyEvent.KEYCODE_Q
import android.view.KeyEvent.KEYCODE_RECENT_APPS
import android.view.KeyEvent.KEYCODE_S
import android.view.KeyEvent.KEYCODE_SLASH
import android.view.KeyEvent.KEYCODE_SPACE
import android.view.KeyEvent.KEYCODE_TAB
import android.view.KeyEvent.META_ALT_ON
import android.view.KeyEvent.META_CTRL_ON
@@ -230,9 +230,9 @@ constructor(@Main private val resources: Resources, private val inputManager: In
                command(META_META_ON, KEYCODE_I)
            },
            // Access Assistant:
            //  - Meta + A
            //  - Meta + Space
            shortcutInfo(resources.getString(R.string.group_system_access_google_assistant)) {
                command(META_META_ON, KEYCODE_A)
                command(META_META_ON, KEYCODE_SPACE)
            },
        )
}
+1 −1
Original line number Diff line number Diff line
@@ -104,7 +104,7 @@ final class InputGestureManager {
        // Initialize all system shortcuts
        List<InputGestureData> systemShortcuts = new ArrayList<>(List.of(
                createKeyGesture(
                        KeyEvent.KEYCODE_A,
                        KeyEvent.KEYCODE_SPACE,
                        KeyEvent.META_META_ON,
                        KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_ASSISTANT,
                        /* allowCaptureByFocusedWindow = */true
+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;
        }
+49 −10
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()
    }

@@ -1321,7 +1341,7 @@ class KeyGestureControllerTests {
                /* downTime= */ 0,
                /* eventTime= */ 0,
                KeyEvent.ACTION_DOWN,
                KeyEvent.KEYCODE_SPACE,
                KeyEvent.KEYCODE_MACRO_1, // Random valid keycode
                /* repeat= */ 0,
                KeyEvent.META_META_ON,
            )
@@ -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(
+11 −7
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),
@@ -377,10 +381,10 @@ object KeyGestureTestData {
    val CAPTURABLE_SYSTEM_GESTURES =
        arrayOf(
            KeyGestureData(
                "META + A -> Launch Assistant",
                intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_A),
                "META + Space -> Launch Assistant",
                intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_SPACE),
                KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_ASSISTANT,
                intArrayOf(KeyEvent.KEYCODE_A),
                intArrayOf(KeyEvent.KEYCODE_SPACE),
                KeyEvent.META_META_ON,
                intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE),
            ),