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

Commit a42d5f4a authored by David Padlipsky's avatar David Padlipsky Committed by Android (Google) Code Review
Browse files

Merge "Implement shortcut controls for a11y keyboard features" into main

parents f39495b5 2d89f6e7
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -71,6 +71,20 @@ public class InputSettings {
    @SuppressLint("UnflaggedApi") // TestApi without associated feature.
    public static final int DEFAULT_POINTER_SPEED = 0;

    /**
     * Bounce Keys Threshold: The default value of the threshold (500 ms).
     *
     * @hide
     */
    public static final int DEFAULT_BOUNCE_KEYS_THRESHOLD_MILLIS = 500;

    /**
     * Slow Keys Threshold: The default value of the threshold (500 ms).
     *
     * @hide
     */
    public static final int DEFAULT_SLOW_KEYS_THRESHOLD_MILLIS = 500;

    /**
     * The maximum allowed obscuring opacity by UID to propagate touches (0 <= x <= 1).
     * @hide
+16 −0
Original line number Diff line number Diff line
@@ -109,6 +109,10 @@ public final class KeyGestureEvent {
    public static final int KEY_GESTURE_TYPE_CLOSE_ALL_DIALOGS = 61;
    public static final int KEY_GESTURE_TYPE_MOVE_TO_NEXT_DISPLAY = 62;
    public static final int KEY_GESTURE_TYPE_TOGGLE_TALKBACK = 63;
    public static final int KEY_GESTURE_TYPE_TOGGLE_STICKY_KEYS = 64;
    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_MOUSE_KEYS = 67;

    public static final int FLAG_CANCELLED = 1;

@@ -187,6 +191,10 @@ public final class KeyGestureEvent {
            KEY_GESTURE_TYPE_CLOSE_ALL_DIALOGS,
            KEY_GESTURE_TYPE_MOVE_TO_NEXT_DISPLAY,
            KEY_GESTURE_TYPE_TOGGLE_TALKBACK,
            KEY_GESTURE_TYPE_TOGGLE_STICKY_KEYS,
            KEY_GESTURE_TYPE_TOGGLE_BOUNCE_KEYS,
            KEY_GESTURE_TYPE_TOGGLE_SLOW_KEYS,
            KEY_GESTURE_TYPE_TOGGLE_MOUSE_KEYS
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface KeyGestureType {
@@ -733,6 +741,14 @@ public final class KeyGestureEvent {
                return "KEY_GESTURE_TYPE_CLOSE_ALL_DIALOGS";
            case KEY_GESTURE_TYPE_TOGGLE_TALKBACK:
                return "KEY_GESTURE_TYPE_TOGGLE_TALKBACK";
            case KEY_GESTURE_TYPE_TOGGLE_STICKY_KEYS:
                return "KEY_GESTURE_TYPE_TOGGLE_STICKY_KEYS";
            case KEY_GESTURE_TYPE_TOGGLE_BOUNCE_KEYS:
                return "KEY_GESTURE_TYPE_TOGGLE_BOUNCE_KEYS";
            case KEY_GESTURE_TYPE_TOGGLE_SLOW_KEYS:
                return "KEY_GESTURE_TYPE_TOGGLE_SLOW_KEYS";
            case KEY_GESTURE_TYPE_TOGGLE_MOUSE_KEYS:
                return "KEY_GESTURE_TYPE_TOGGLE_MOUSE_KEYS";
            default:
                return Integer.toHexString(value);
        }
+49 −0
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ import android.hardware.input.AidlKeyGestureEvent;
import android.hardware.input.IKeyGestureEventListener;
import android.hardware.input.IKeyGestureHandler;
import android.hardware.input.InputManager;
import android.hardware.input.InputSettings;
import android.hardware.input.KeyGestureEvent;
import android.os.Handler;
import android.os.IBinder;
@@ -589,6 +590,54 @@ final class KeyGestureController {
                    }
                }
                break;
            case KeyEvent.KEYCODE_3:
                if (InputSettings.isAccessibilityBounceKeysFeatureEnabled()
                        && keyboardA11yShortcutControl()) {
                    if (firstDown && event.isMetaPressed() && event.isAltPressed()) {
                        return handleKeyGesture(deviceId, new int[]{keyCode},
                                KeyEvent.META_META_ON | KeyEvent.META_ALT_ON,
                                KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_BOUNCE_KEYS,
                                KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
                                focusedToken, /* flags = */0);
                    }
                }
                break;
            case KeyEvent.KEYCODE_4:
                if (InputSettings.isAccessibilityMouseKeysFeatureFlagEnabled()
                        && keyboardA11yShortcutControl()) {
                    if (firstDown && event.isMetaPressed() && event.isAltPressed()) {
                        return handleKeyGesture(deviceId, new int[]{keyCode},
                                KeyEvent.META_META_ON | KeyEvent.META_ALT_ON,
                                KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MOUSE_KEYS,
                                KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
                                focusedToken, /* flags = */0);
                    }
                }
                break;
            case KeyEvent.KEYCODE_5:
                if (InputSettings.isAccessibilityStickyKeysFeatureEnabled()
                        && keyboardA11yShortcutControl()) {
                    if (firstDown && event.isMetaPressed() && event.isAltPressed()) {
                        return handleKeyGesture(deviceId, new int[]{keyCode},
                                KeyEvent.META_META_ON | KeyEvent.META_ALT_ON,
                                KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_STICKY_KEYS,
                                KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
                                focusedToken, /* flags = */0);
                    }
                }
                break;
            case KeyEvent.KEYCODE_6:
                if (InputSettings.isAccessibilitySlowKeysFeatureFlagEnabled()
                        && keyboardA11yShortcutControl()) {
                    if (firstDown && event.isMetaPressed() && event.isAltPressed()) {
                        return handleKeyGesture(deviceId, new int[]{keyCode},
                                KeyEvent.META_META_ON | KeyEvent.META_ALT_ON,
                                KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_SLOW_KEYS,
                                KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
                                focusedToken, /* flags = */0);
                    }
                }
                break;
            case KeyEvent.KEYCODE_DEL:
                if (newBugreportKeyboardShortcut()) {
                    if (firstDown && mEnableBugReportKeyboardShortcut && event.isMetaPressed()
+126 −0
Original line number Diff line number Diff line
@@ -151,6 +151,7 @@ import android.hardware.hdmi.HdmiPlaybackClient;
import android.hardware.hdmi.HdmiPlaybackClient.OneTouchPlayCallback;
import android.hardware.input.AppLaunchData;
import android.hardware.input.InputManager;
import android.hardware.input.InputSettings;
import android.hardware.input.KeyGestureEvent;
import android.media.AudioManager;
import android.media.AudioManagerInternal;
@@ -3617,6 +3618,68 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                    }
                }
                break;
            case KeyEvent.KEYCODE_3:
                if (InputSettings.isAccessibilityBounceKeysFeatureEnabled()
                        && keyboardA11yShortcutControl()) {
                    if (firstDown && event.isMetaPressed()
                            && event.isAltPressed()) {
                        final boolean bounceKeysEnabled =
                                InputSettings.isAccessibilityBounceKeysEnabled(
                                        mContext);
                        InputSettings.setAccessibilityBounceKeysThreshold(mContext,
                                bounceKeysEnabled ? 0
                                        : InputSettings.DEFAULT_BOUNCE_KEYS_THRESHOLD_MILLIS);
                        notifyKeyGestureCompleted(event,
                                KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_BOUNCE_KEYS);
                        return true;
                    }
                }
                break;
            case KeyEvent.KEYCODE_4:
                if (InputSettings.isAccessibilityMouseKeysFeatureFlagEnabled()
                        && keyboardA11yShortcutControl()) {
                    if (firstDown && event.isMetaPressed() && event.isAltPressed()) {
                        final boolean mouseKeysEnabled =
                                InputSettings.isAccessibilityMouseKeysEnabled(
                                        mContext);
                        InputSettings.setAccessibilityMouseKeysEnabled(mContext,
                                !mouseKeysEnabled);
                        notifyKeyGestureCompleted(event,
                                KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MOUSE_KEYS);
                        return true;
                    }
                }
                break;
            case KeyEvent.KEYCODE_5:
                if (InputSettings.isAccessibilityStickyKeysFeatureEnabled()
                        && keyboardA11yShortcutControl()) {
                    if (firstDown && event.isMetaPressed() && event.isAltPressed()) {
                        final boolean stickyKeysEnabled =
                                InputSettings.isAccessibilityStickyKeysEnabled(
                                        mContext);
                        InputSettings.setAccessibilityStickyKeysEnabled(mContext,
                                !stickyKeysEnabled);
                        notifyKeyGestureCompleted(event,
                                KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_STICKY_KEYS);
                        return true;
                    }
                }
                break;
            case KeyEvent.KEYCODE_6:
                if (InputSettings.isAccessibilitySlowKeysFeatureFlagEnabled()
                        && keyboardA11yShortcutControl()) {
                    if (firstDown && event.isMetaPressed() && event.isAltPressed()) {
                        final boolean slowKeysEnabled =
                                InputSettings.isAccessibilitySlowKeysEnabled(mContext);
                        InputSettings.setAccessibilitySlowKeysThreshold(mContext,
                                slowKeysEnabled ? 0
                                        : InputSettings.DEFAULT_SLOW_KEYS_THRESHOLD_MILLIS);
                        notifyKeyGestureCompleted(event,
                                KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_SLOW_KEYS);
                        return true;
                    }
                }
                break;
            case KeyEvent.KEYCODE_DEL:
                if (newBugreportKeyboardShortcut()) {
                    if (mEnableBugReportKeyboardShortcut && firstDown
@@ -4053,6 +4116,18 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                                .isAccessibilityShortcutAvailable(false);
                    case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_TALKBACK:
                        return keyboardA11yShortcutControl();
                    case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_SLOW_KEYS:
                        return InputSettings.isAccessibilitySlowKeysFeatureFlagEnabled()
                                && keyboardA11yShortcutControl();
                    case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_BOUNCE_KEYS:
                        return InputSettings.isAccessibilityBounceKeysFeatureEnabled()
                                && keyboardA11yShortcutControl();
                    case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MOUSE_KEYS:
                        return InputSettings.isAccessibilityMouseKeysFeatureFlagEnabled()
                                && keyboardA11yShortcutControl();
                    case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_STICKY_KEYS:
                        return InputSettings.isAccessibilityStickyKeysFeatureEnabled()
                                && keyboardA11yShortcutControl();
                    default:
                        return false;
                }
@@ -4286,6 +4361,57 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                if (complete && isUserSetupComplete() && !keyguardOn
                        && data != null && mModifierShortcutManager.launchApplication(data)) {
                    dismissKeyboardShortcutsMenu();
                }
                return true;
            case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_BOUNCE_KEYS:
                if (InputSettings.isAccessibilityBounceKeysFeatureEnabled()
                        && keyboardA11yShortcutControl()) {
                    if (complete) {
                        final boolean bounceKeysEnabled =
                                InputSettings.isAccessibilityBounceKeysEnabled(
                                        mContext);
                        InputSettings.setAccessibilityBounceKeysThreshold(mContext,
                                bounceKeysEnabled ? 0
                                        : InputSettings.DEFAULT_BOUNCE_KEYS_THRESHOLD_MILLIS);
                    }
                    return true;
                }
                break;
            case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MOUSE_KEYS:
                if (InputSettings.isAccessibilityMouseKeysFeatureFlagEnabled()
                        && keyboardA11yShortcutControl()) {
                    if (complete) {
                        final boolean mouseKeysEnabled =
                                InputSettings.isAccessibilityMouseKeysEnabled(
                                        mContext);
                        InputSettings.setAccessibilityMouseKeysEnabled(mContext,
                                !mouseKeysEnabled);
                    }
                    return true;
                }
                break;
            case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_STICKY_KEYS:
                if (InputSettings.isAccessibilityStickyKeysFeatureEnabled()
                        && keyboardA11yShortcutControl()) {
                    if (complete) {
                        final boolean stickyKeysEnabled =
                                InputSettings.isAccessibilityStickyKeysEnabled(mContext);
                        InputSettings.setAccessibilityStickyKeysEnabled(mContext,
                                !stickyKeysEnabled);
                    }
                    return true;
                }
                break;
            case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_SLOW_KEYS:
                if (InputSettings.isAccessibilitySlowKeysFeatureFlagEnabled()
                        && keyboardA11yShortcutControl()) {
                    if (complete) {
                        final boolean slowKeysEnabled =
                                InputSettings.isAccessibilitySlowKeysEnabled(mContext);
                        InputSettings.setAccessibilitySlowKeysThreshold(mContext,
                                slowKeysEnabled ? 0
                                        : InputSettings.DEFAULT_SLOW_KEYS_THRESHOLD_MILLIS);
                    }
                    return true;
                }
                break;
+83 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import static com.android.server.policy.PhoneWindowManager.POWER_VOLUME_UP_BEHAV
import static com.android.server.policy.PhoneWindowManager.POWER_VOLUME_UP_BEHAVIOR_MUTE;
import static com.android.server.policy.PhoneWindowManager.SETTINGS_KEY_BEHAVIOR_NOTIFICATION_PANEL;

import android.hardware.input.InputSettings;
import android.hardware.input.KeyGestureEvent;
import android.os.RemoteException;
import android.platform.test.annotations.DisableFlags;
@@ -405,6 +406,36 @@ public class KeyGestureEventTests extends ShortcutKeyTestBase {
                META_ON | ALT_ON);
    }

    @Test
    @EnableFlags({com.android.hardware.input.Flags.FLAG_KEYBOARD_A11Y_SHORTCUT_CONTROL,
            com.android.hardware.input.Flags.FLAG_KEYBOARD_A11Y_BOUNCE_KEYS_FLAG,
            com.android.hardware.input.Flags.FLAG_KEYBOARD_A11Y_SLOW_KEYS_FLAG,
            com.android.hardware.input.Flags.FLAG_KEYBOARD_A11Y_STICKY_KEYS_FLAG,
            com.android.hardware.input.Flags.FLAG_KEYBOARD_A11Y_MOUSE_KEYS})
    @DisableFlags(com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER)
    public void testKeyboardAccessibilityToggleShortcutPress() {
        testShortcutInternal("Meta + Alt + 3 -> Toggle Bounce Keys",
                new int[]{META_KEY, ALT_KEY, KeyEvent.KEYCODE_3},
                KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_BOUNCE_KEYS,
                KeyEvent.KEYCODE_3,
                META_ON | ALT_ON);
        testShortcutInternal("Meta + Alt + 4 -> Toggle Mouse Keys",
                new int[]{META_KEY, ALT_KEY, KeyEvent.KEYCODE_4},
                KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MOUSE_KEYS,
                KeyEvent.KEYCODE_4,
                META_ON | ALT_ON);
        testShortcutInternal("Meta + Alt + 5 -> Toggle Sticky Keys",
                new int[]{META_KEY, ALT_KEY, KeyEvent.KEYCODE_5},
                KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_STICKY_KEYS,
                KeyEvent.KEYCODE_5,
                META_ON | ALT_ON);
        testShortcutInternal("Meta + Alt + 6 -> Toggle Slow Keys",
                new int[]{META_KEY, ALT_KEY, KeyEvent.KEYCODE_6},
                KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_SLOW_KEYS,
                KeyEvent.KEYCODE_6,
                META_ON | ALT_ON);
    }

    private void testShortcutInternal(String testName, int[] testKeys,
            @KeyGestureEvent.KeyGestureType int expectedKeyGestureType, int expectedKey,
            int expectedModifierState) {
@@ -723,4 +754,56 @@ public class KeyGestureEventTests extends ShortcutKeyTestBase {
                sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_TALKBACK));
        mPhoneWindowManager.assertTalkBack(false);
    }

    @Test
    @EnableFlags({com.android.hardware.input.Flags.FLAG_KEYBOARD_A11Y_SHORTCUT_CONTROL,
            com.android.hardware.input.Flags.FLAG_KEYBOARD_A11Y_STICKY_KEYS_FLAG})
    public void testKeyGestureToggleStickyKeys() {
        Assert.assertTrue(
                sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_STICKY_KEYS));
        Assert.assertTrue(InputSettings.isAccessibilityStickyKeysEnabled(mContext));

        Assert.assertTrue(
                sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_STICKY_KEYS));
        Assert.assertFalse(InputSettings.isAccessibilityStickyKeysEnabled(mContext));
    }

    @Test
    @EnableFlags({com.android.hardware.input.Flags.FLAG_KEYBOARD_A11Y_SHORTCUT_CONTROL,
            com.android.hardware.input.Flags.FLAG_KEYBOARD_A11Y_SLOW_KEYS_FLAG})
    public void testKeyGestureToggleSlowKeys() {
        Assert.assertTrue(
                sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_SLOW_KEYS));
        Assert.assertTrue(InputSettings.isAccessibilitySlowKeysEnabled(mContext));

        Assert.assertTrue(
                sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_SLOW_KEYS));
        Assert.assertFalse(InputSettings.isAccessibilitySlowKeysEnabled(mContext));
    }

    @Test
    @EnableFlags({com.android.hardware.input.Flags.FLAG_KEYBOARD_A11Y_SHORTCUT_CONTROL,
            com.android.hardware.input.Flags.FLAG_KEYBOARD_A11Y_MOUSE_KEYS})
    public void testKeyGestureToggleMouseKeys() {
        Assert.assertTrue(
                sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MOUSE_KEYS));
        Assert.assertTrue(InputSettings.isAccessibilityMouseKeysEnabled(mContext));

        Assert.assertTrue(
                sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MOUSE_KEYS));
        Assert.assertFalse(InputSettings.isAccessibilityMouseKeysEnabled(mContext));
    }

    @Test
    @EnableFlags({com.android.hardware.input.Flags.FLAG_KEYBOARD_A11Y_SHORTCUT_CONTROL,
            com.android.hardware.input.Flags.FLAG_KEYBOARD_A11Y_BOUNCE_KEYS_FLAG})
    public void testKeyGestureToggleBounceKeys() {
        Assert.assertTrue(
                sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_BOUNCE_KEYS));
        Assert.assertTrue(InputSettings.isAccessibilityBounceKeysEnabled(mContext));

        Assert.assertTrue(
                sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_BOUNCE_KEYS));
        Assert.assertFalse(InputSettings.isAccessibilityBounceKeysEnabled(mContext));
    }
}
Loading