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

Commit d318c349 authored by Vania Desmonda's avatar Vania Desmonda
Browse files

Add key gesture events for Desktop Windowing task resizing.

Flag: com.android.window.flags.enable_task_resizing_keyboard_shortcuts
Test: atest KeyGestureControllerTests
Bug: 335819608
Change-Id: Id8cb727d6735e48c39b710dac991a52066fbc081
parent 51180047
Loading
Loading
Loading
Loading
+25 −1
Original line number Original line Diff line number Diff line
@@ -113,6 +113,10 @@ public final class KeyGestureEvent {
    public static final int KEY_GESTURE_TYPE_TOGGLE_BOUNCE_KEYS = 65;
    public static final int KEY_GESTURE_TYPE_TOGGLE_BOUNCE_KEYS = 65;
    public static final int KEY_GESTURE_TYPE_TOGGLE_SLOW_KEYS = 66;
    public static final int KEY_GESTURE_TYPE_TOGGLE_SLOW_KEYS = 66;
    public static final int KEY_GESTURE_TYPE_TOGGLE_MOUSE_KEYS = 67;
    public static final int KEY_GESTURE_TYPE_TOGGLE_MOUSE_KEYS = 67;
    public static final int KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW = 68;
    public static final int KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW = 69;
    public static final int KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW = 70;
    public static final int KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE = 71;


    public static final int FLAG_CANCELLED = 1;
    public static final int FLAG_CANCELLED = 1;


@@ -194,7 +198,11 @@ public final class KeyGestureEvent {
            KEY_GESTURE_TYPE_TOGGLE_STICKY_KEYS,
            KEY_GESTURE_TYPE_TOGGLE_STICKY_KEYS,
            KEY_GESTURE_TYPE_TOGGLE_BOUNCE_KEYS,
            KEY_GESTURE_TYPE_TOGGLE_BOUNCE_KEYS,
            KEY_GESTURE_TYPE_TOGGLE_SLOW_KEYS,
            KEY_GESTURE_TYPE_TOGGLE_SLOW_KEYS,
            KEY_GESTURE_TYPE_TOGGLE_MOUSE_KEYS
            KEY_GESTURE_TYPE_TOGGLE_MOUSE_KEYS,
            KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW,
            KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW,
            KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW,
            KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE,
    })
    })
    @Retention(RetentionPolicy.SOURCE)
    @Retention(RetentionPolicy.SOURCE)
    public @interface KeyGestureType {
    public @interface KeyGestureType {
@@ -541,6 +549,14 @@ public final class KeyGestureEvent {
                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__DESKTOP_MODE;
                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__DESKTOP_MODE;
            case KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION:
            case KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION:
                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__MULTI_WINDOW_NAVIGATION;
                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__MULTI_WINDOW_NAVIGATION;
            case KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW:
                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__SNAP_LEFT_FREEFORM_WINDOW;
            case KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW:
                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__SNAP_RIGHT_FREEFORM_WINDOW;
            case KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW:
                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__MAXIMIZE_FREEFORM_WINDOW;
            case KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE:
                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__RESTORE_FREEFORM_WINDOW_SIZE;
            default:
            default:
                return LOG_EVENT_UNSPECIFIED;
                return LOG_EVENT_UNSPECIFIED;
        }
        }
@@ -749,6 +765,14 @@ public final class KeyGestureEvent {
                return "KEY_GESTURE_TYPE_TOGGLE_SLOW_KEYS";
                return "KEY_GESTURE_TYPE_TOGGLE_SLOW_KEYS";
            case KEY_GESTURE_TYPE_TOGGLE_MOUSE_KEYS:
            case KEY_GESTURE_TYPE_TOGGLE_MOUSE_KEYS:
                return "KEY_GESTURE_TYPE_TOGGLE_MOUSE_KEYS";
                return "KEY_GESTURE_TYPE_TOGGLE_MOUSE_KEYS";
            case KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW:
                return "KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW";
            case KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW:
                return "KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW";
            case KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW:
                return "KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW";
            case KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE:
                return "KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE";
            default:
            default:
                return Integer.toHexString(value);
                return Integer.toHexString(value);
        }
        }
+49 −0
Original line number Original line Diff line number Diff line
@@ -25,6 +25,7 @@ import static com.android.hardware.input.Flags.useKeyGestureEventHandler;
import static com.android.hardware.input.Flags.useKeyGestureEventHandlerMultiPressGestures;
import static com.android.hardware.input.Flags.useKeyGestureEventHandlerMultiPressGestures;
import static com.android.server.flags.Flags.newBugreportKeyboardShortcut;
import static com.android.server.flags.Flags.newBugreportKeyboardShortcut;
import static com.android.window.flags.Flags.enableMoveToNextDisplayShortcut;
import static com.android.window.flags.Flags.enableMoveToNextDisplayShortcut;
import static com.android.window.flags.Flags.enableTaskResizingKeyboardShortcuts;


import android.annotation.BinderThread;
import android.annotation.BinderThread;
import android.annotation.MainThread;
import android.annotation.MainThread;
@@ -728,6 +729,54 @@ final class KeyGestureController {
                    }
                    }
                }
                }
                break;
                break;
            case KeyEvent.KEYCODE_LEFT_BRACKET:
                if (enableTaskResizingKeyboardShortcuts()) {
                    if (firstDown && event.isAltPressed()) {
                        return handleKeyGesture(deviceId, new int[]{keyCode},
                                KeyEvent.META_ALT_ON,
                                KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW,
                                KeyGestureEvent.ACTION_GESTURE_COMPLETE,
                                displayId,
                                focusedToken, /* flags = */0);
                    }
                }
                break;
            case KeyEvent.KEYCODE_RIGHT_BRACKET:
                if (enableTaskResizingKeyboardShortcuts()) {
                    if (firstDown && event.isAltPressed()) {
                        return handleKeyGesture(deviceId, new int[]{keyCode},
                                KeyEvent.META_ALT_ON,
                                KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW,
                                KeyGestureEvent.ACTION_GESTURE_COMPLETE,
                                displayId,
                                focusedToken, /* flags = */0);
                    }
                }
                break;
            case KeyEvent.KEYCODE_EQUALS:
                if (enableTaskResizingKeyboardShortcuts()) {
                    if (firstDown && event.isAltPressed()) {
                        return handleKeyGesture(deviceId, new int[]{keyCode},
                                KeyEvent.META_ALT_ON,
                                KeyGestureEvent.KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW,
                                KeyGestureEvent.ACTION_GESTURE_COMPLETE,
                                displayId,
                                focusedToken, /* flags = */0);
                    }
                }
                break;
            case KeyEvent.KEYCODE_MINUS:
                if (enableTaskResizingKeyboardShortcuts()) {
                    if (firstDown && event.isAltPressed()) {
                        return handleKeyGesture(deviceId, new int[]{keyCode},
                                KeyEvent.META_ALT_ON,
                                KeyGestureEvent.KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE,
                                KeyGestureEvent.ACTION_GESTURE_COMPLETE,
                                displayId,
                                focusedToken, /* flags = */0);
                    }
                }
                break;
            case KeyEvent.KEYCODE_SLASH:
            case KeyEvent.KEYCODE_SLASH:
                if (firstDown && event.isMetaPressed()) {
                if (firstDown && event.isMetaPressed()) {
                    return handleKeyGesture(deviceId, new int[]{keyCode}, KeyEvent.META_META_ON,
                    return handleKeyGesture(deviceId, new int[]{keyCode}, KeyEvent.META_META_ON,
+80 −0
Original line number Original line Diff line number Diff line
@@ -883,6 +883,86 @@ class KeyGestureControllerTests {
        )
        )
    }
    }


    @Test
    @EnableFlags(com.android.window.flags.Flags.FLAG_ENABLE_TASK_RESIZING_KEYBOARD_SHORTCUTS)
    fun testSnapLeftFreeformTask() {
        val keyGestureController = KeyGestureController(context, testLooper.looper)
        testKeyGestureInternal(
            keyGestureController,
            TestData(
                "ALT + [ -> Resizes a task to fit the left half of the screen",
                intArrayOf(
                    KeyEvent.KEYCODE_ALT_LEFT,
                    KeyEvent.KEYCODE_LEFT_BRACKET
                ),
                KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW,
                intArrayOf(KeyEvent.KEYCODE_LEFT_BRACKET),
                KeyEvent.META_ALT_ON,
                intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
            )
        )
    }

    @Test
    @EnableFlags(com.android.window.flags.Flags.FLAG_ENABLE_TASK_RESIZING_KEYBOARD_SHORTCUTS)
    fun testSnapRightFreeformTask() {
        val keyGestureController = KeyGestureController(context, testLooper.looper)
        testKeyGestureInternal(
            keyGestureController,
            TestData(
                "ALT + ] -> Resizes a task to fit the right half of the screen",
                intArrayOf(
                    KeyEvent.KEYCODE_ALT_LEFT,
                    KeyEvent.KEYCODE_RIGHT_BRACKET
                ),
                KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW,
                intArrayOf(KeyEvent.KEYCODE_RIGHT_BRACKET),
                KeyEvent.META_ALT_ON,
                intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
            )
        )
    }

    @Test
    @EnableFlags(com.android.window.flags.Flags.FLAG_ENABLE_TASK_RESIZING_KEYBOARD_SHORTCUTS)
    fun testMaximizeFreeformTask() {
        val keyGestureController = KeyGestureController(context, testLooper.looper)
        testKeyGestureInternal(
            keyGestureController,
            TestData(
                "ALT + '=' -> Maximizes a task to fit the screen",
                intArrayOf(
                    KeyEvent.KEYCODE_ALT_LEFT,
                    KeyEvent.KEYCODE_EQUALS
                ),
                KeyGestureEvent.KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW,
                intArrayOf(KeyEvent.KEYCODE_EQUALS),
                KeyEvent.META_ALT_ON,
                intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
            )
        )
    }

    @Test
    @EnableFlags(com.android.window.flags.Flags.FLAG_ENABLE_TASK_RESIZING_KEYBOARD_SHORTCUTS)
    fun testRestoreFreeformTask() {
        val keyGestureController = KeyGestureController(context, testLooper.looper)
        testKeyGestureInternal(
            keyGestureController,
            TestData(
                "ALT + '-' -> Restores a task size to its previous bounds",
                intArrayOf(
                    KeyEvent.KEYCODE_ALT_LEFT,
                    KeyEvent.KEYCODE_MINUS
                ),
                KeyGestureEvent.KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE,
                intArrayOf(KeyEvent.KEYCODE_MINUS),
                KeyEvent.META_ALT_ON,
                intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
            )
        )
    }

    @Test
    @Test
    fun testCapsLockPressNotified() {
    fun testCapsLockPressNotified() {
        val keyGestureController = KeyGestureController(context, testLooper.looper)
        val keyGestureController = KeyGestureController(context, testLooper.looper)