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

Commit ffce4018 authored by Vaibhav Devmurari's avatar Vaibhav Devmurari
Browse files

Cleanup: Shift input shortcuts out of PWM

With new key gesture event handler APIs, different components
can define and reach to different shortcuts, so trying to shift
shortcut handling code to place that makes sense, instead of
putting it in PWM.

Bug: 358569822
Test: atest InputManagerServiceTests
Flag: EXEMPT pure refactor
Change-Id: I78c7f765bac7ec6a866730fdf3e94cf0a444569d
parent 84f5f8ff
Loading
Loading
Loading
Loading
+74 −26
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.PermissionManuallyEnforced;
import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.annotation.UserIdInt;
import android.app.ActivityManagerInternal;
import android.bluetooth.BluetoothAdapter;
@@ -2625,12 +2626,39 @@ public class InputManagerService extends IInputManager.Stub
        return mWindowManagerCallbacks.interceptUnhandledKey(event, focus);
    }

    @SuppressLint("MissingPermission")
    private void initKeyGestures() {
        InputManager im = Objects.requireNonNull(mContext.getSystemService(InputManager.class));
        im.registerKeyGestureEventHandler(new InputManager.KeyGestureEventHandler() {
            @Override
            public boolean handleKeyGestureEvent(@NonNull KeyGestureEvent event,
                    @Nullable IBinder focussedToken) {
                return InputManagerService.this.handleKeyGestureEvent(event);
            }

            @Override
            public boolean isKeyGestureSupported(int gestureType) {
                switch (gestureType) {
                    case KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP:
                    case KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN:
                    case KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE:
                    case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK:
                    case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_SLOW_KEYS:
                    case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_BOUNCE_KEYS:
                    case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MOUSE_KEYS:
                    case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_STICKY_KEYS:
                        return true;
                    default:
                        return false;

                }
            }
        });
    }

    @SuppressLint("MissingPermission")
    @VisibleForTesting
    boolean handleKeyGestureEvent(@NonNull KeyGestureEvent event) {
        int deviceId = event.getDeviceId();
        boolean complete = event.getAction() == KeyGestureEvent.ACTION_GESTURE_COMPLETE
                && !event.isCancelled();
@@ -2653,26 +2681,46 @@ public class InputManagerService extends IInputManager.Stub
                    mNative.toggleCapsLock(deviceId);
                }
                return true;
                    default:
                        return false;

            case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_BOUNCE_KEYS:
                if (complete && InputSettings.isAccessibilityBounceKeysFeatureEnabled()) {
                    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 (complete && InputSettings.isAccessibilityMouseKeysFeatureFlagEnabled()) {
                    final boolean mouseKeysEnabled = InputSettings.isAccessibilityMouseKeysEnabled(
                            mContext);
                    InputSettings.setAccessibilityMouseKeysEnabled(mContext, !mouseKeysEnabled);
                    return true;
                }

            @Override
            public boolean isKeyGestureSupported(int gestureType) {
                switch (gestureType) {
                    case KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP:
                    case KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN:
                    case KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE:
                    case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK:
                break;
            case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_STICKY_KEYS:
                if (complete && InputSettings.isAccessibilityStickyKeysFeatureEnabled()) {
                    final boolean stickyKeysEnabled =
                            InputSettings.isAccessibilityStickyKeysEnabled(mContext);
                    InputSettings.setAccessibilityStickyKeysEnabled(mContext, !stickyKeysEnabled);
                    return true;
                }
                break;
            case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_SLOW_KEYS:
                if (complete && InputSettings.isAccessibilitySlowKeysFeatureFlagEnabled()) {
                    final boolean slowKeysEnabled =
                            InputSettings.isAccessibilitySlowKeysEnabled(mContext);
                    InputSettings.setAccessibilitySlowKeysThreshold(mContext,
                            slowKeysEnabled ? 0 : InputSettings.DEFAULT_SLOW_KEYS_THRESHOLD_MILLIS);
                    return true;
                }
                break;
            default:
                return false;

        }
            }
        });
        return false;
    }

    // Native callback.
+0 −64
Original line number Diff line number Diff line
@@ -4120,18 +4120,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                                .isAccessibilityShortcutAvailable(false);
                    case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_TALKBACK:
                        return enableTalkbackAndMagnifierKeyGestures();
                    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;
                }
@@ -4368,58 +4356,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                    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;
        }
        return false;
    }
+0 −53
Original line number Diff line number Diff line
@@ -26,7 +26,6 @@ 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;
@@ -756,56 +755,4 @@ 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));
    }
}
+91 −38
Original line number Diff line number Diff line
@@ -28,10 +28,11 @@ import android.hardware.display.DisplayViewport
import android.hardware.display.VirtualDisplay
import android.hardware.input.InputManager
import android.hardware.input.InputManagerGlobal
import android.hardware.input.InputSettings
import android.hardware.input.KeyGestureEvent
import android.os.InputEventInjectionSync
import android.os.SystemClock
import android.os.test.TestLooper
import android.platform.test.annotations.EnableFlags
import android.platform.test.annotations.Presubmit
import android.platform.test.flag.junit.SetFlagsRule
import android.provider.Settings
@@ -99,6 +100,7 @@ class InputManagerServiceTests {
            .mockStatic(LocalServices::class.java)
            .mockStatic(PermissionChecker::class.java)
            .mockStatic(KeyCharacterMap::class.java)
            .mockStatic(InputSettings::class.java)
            .build()!!

    @get:Rule
@@ -481,32 +483,102 @@ class InputManagerServiceTests {
    }

    @Test
    @EnableFlags(com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER)
    fun handleKeyGestures_keyboardBacklight() {
        service.systemRunning()

        val backlightDownEvent = createKeyEvent(KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_DOWN)
        service.interceptKeyBeforeDispatching(null, backlightDownEvent, /* policyFlags = */0)
        val backlightDownEvent =
            KeyGestureEvent.Builder()
                .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN)
                .setAction(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
                .build()
        service.handleKeyGestureEvent(backlightDownEvent)
        verify(kbdController).decrementKeyboardBacklight(anyInt())

        val backlightUpEvent = createKeyEvent(KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_UP)
        service.interceptKeyBeforeDispatching(null, backlightUpEvent, /* policyFlags = */0)
        val backlightUpEvent =
            KeyGestureEvent.Builder()
                .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP)
                .setAction(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
                .build()
        service.handleKeyGestureEvent(backlightUpEvent)
        verify(kbdController).incrementKeyboardBacklight(anyInt())
    }

    @Test
    @EnableFlags(com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER)
    fun handleKeyGestures_toggleCapsLock() {
        service.systemRunning()
    fun handleKeyGestures_a11yBounceKeysShortcut() {
        ExtendedMockito.doReturn(true).`when` {
            InputSettings.isAccessibilityBounceKeysFeatureEnabled()
        }
        val toggleBounceKeysEvent =
            KeyGestureEvent.Builder()
                .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_BOUNCE_KEYS)
                .setAction(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
                .build()
        service.handleKeyGestureEvent(toggleBounceKeysEvent)
        ExtendedMockito.verify {
            InputSettings.setAccessibilityBounceKeysThreshold(
                any(),
                eq(InputSettings.DEFAULT_BOUNCE_KEYS_THRESHOLD_MILLIS)
            )
        }
    }

    @Test
    fun handleKeyGestures_a11yMouseKeysShortcut() {
        ExtendedMockito.doReturn(true).`when` {
            InputSettings.isAccessibilityMouseKeysFeatureFlagEnabled()
        }
        val toggleMouseKeysEvent =
            KeyGestureEvent.Builder()
                .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MOUSE_KEYS)
                .setAction(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
                .build()
        service.handleKeyGestureEvent(toggleMouseKeysEvent)
        ExtendedMockito.verify {
            InputSettings.setAccessibilityMouseKeysEnabled(any(), eq(true))
        }
    }

    @Test
    fun handleKeyGestures_a11yStickyKeysShortcut() {
        ExtendedMockito.doReturn(true).`when` {
            InputSettings.isAccessibilityStickyKeysFeatureEnabled()
        }
        val toggleStickyKeysEvent =
            KeyGestureEvent.Builder()
                .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_STICKY_KEYS)
                .setAction(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
                .build()
        service.handleKeyGestureEvent(toggleStickyKeysEvent)
        ExtendedMockito.verify {
            InputSettings.setAccessibilityStickyKeysEnabled(any(), eq(true))
        }
    }

    @Test
    fun handleKeyGestures_a11ySlowKeysShortcut() {
        ExtendedMockito.doReturn(true).`when` {
            InputSettings.isAccessibilitySlowKeysFeatureFlagEnabled()
        }
        val toggleSlowKeysEvent =
            KeyGestureEvent.Builder()
                .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_SLOW_KEYS)
                .setAction(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
                .build()
        service.handleKeyGestureEvent(toggleSlowKeysEvent)
        ExtendedMockito.verify {
            InputSettings.setAccessibilitySlowKeysThreshold(
                any(),
                eq(InputSettings.DEFAULT_SLOW_KEYS_THRESHOLD_MILLIS)
            )
        }
    }

        val metaDownEvent = createKeyEvent(KeyEvent.KEYCODE_META_LEFT)
        service.interceptKeyBeforeDispatching(null, metaDownEvent, /* policyFlags = */0)
        val altDownEvent =
            createKeyEvent(KeyEvent.KEYCODE_ALT_LEFT, KeyEvent.META_META_ON, KeyEvent.ACTION_DOWN)
        service.interceptKeyBeforeDispatching(null, altDownEvent, /* policyFlags = */0)
        val altUpEvent =
            createKeyEvent(KeyEvent.KEYCODE_ALT_LEFT, KeyEvent.META_META_ON, KeyEvent.ACTION_UP)
        service.interceptKeyBeforeDispatching(null, altUpEvent, /* policyFlags = */0)
    @Test
    fun handleKeyGestures_toggleCapsLock() {
        val toggleCapsLockEvent =
            KeyGestureEvent.Builder()
                .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK)
                .setAction(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
                .build()
        service.handleKeyGestureEvent(toggleCapsLockEvent)

        verify(native).toggleCapsLock(anyInt())
    }
@@ -545,25 +617,6 @@ class InputManagerServiceTests {
        )
        whenever(windowManagerInternal.getKeyInterceptionInfoFromToken(any())).thenReturn(info)
    }

    private fun createKeyEvent(
        keycode: Int,
        modifierState: Int = 0,
        action: Int = KeyEvent.ACTION_DOWN
    ): KeyEvent {
        return KeyEvent(
            /* downTime = */0,
            /* eventTime = */0,
            action,
            keycode,
            /* repeat = */0,
            modifierState,
            KeyCharacterMap.VIRTUAL_KEYBOARD,
            /* scancode = */0,
            /* flags = */0,
            InputDevice.SOURCE_KEYBOARD
        )
    }
}

private fun <T> whenever(methodCall: T): OngoingStubbing<T> = `when`(methodCall)