Loading core/java/android/hardware/input/AidlInputGestureData.aidl +17 −4 Original line number Diff line number Diff line Loading @@ -19,13 +19,26 @@ package android.hardware.input; /** @hide */ @JavaDerive(equals=true) parcelable AidlInputGestureData { int keycode; int modifierState; int gestureType; Trigger trigger; // App launch parameters: Only set if gestureType is KEY_GESTURE_TYPE_LAUNCH_APPLICATION int gestureType; // App launch parameters (Only set if gestureType is LAUNCH_APPLICATION) String appLaunchCategory; String appLaunchRole; String appLaunchPackageName; String appLaunchClassName; parcelable KeyTrigger { int keycode; int modifierState; } parcelable TouchpadGestureTrigger { int gestureType; } union Trigger { KeyTrigger key; TouchpadGestureTrigger touchpadGesture; } } core/java/android/hardware/input/InputGestureData.java +76 −26 Original line number Diff line number Diff line Loading @@ -35,20 +35,40 @@ import java.util.Objects; */ public final class InputGestureData { public static final int TOUCHPAD_GESTURE_TYPE_UNKNOWN = 0; public static final int TOUCHPAD_GESTURE_TYPE_THREE_FINGER_TAP = 1; @NonNull private final AidlInputGestureData mInputGestureData; public InputGestureData(AidlInputGestureData inputGestureData) { public InputGestureData(@NonNull AidlInputGestureData inputGestureData) { this.mInputGestureData = inputGestureData; validate(); } /** Returns the trigger information for this input gesture */ public Trigger getTrigger() { if (mInputGestureData.keycode != KeyEvent.KEYCODE_UNKNOWN) { return new KeyTrigger(mInputGestureData.keycode, mInputGestureData.modifierState); switch (mInputGestureData.trigger.getTag()) { case AidlInputGestureData.Trigger.Tag.key: { AidlInputGestureData.KeyTrigger trigger = mInputGestureData.trigger.getKey(); if (trigger == null) { throw new RuntimeException("InputGestureData is corrupted, null key trigger!"); } return createKeyTrigger(trigger.keycode, trigger.modifierState); } case AidlInputGestureData.Trigger.Tag.touchpadGesture: { AidlInputGestureData.TouchpadGestureTrigger trigger = mInputGestureData.trigger.getTouchpadGesture(); if (trigger == null) { throw new RuntimeException( "InputGestureData is corrupted, null touchpad trigger!"); } return createTouchpadTrigger(trigger.gestureType); } default: throw new RuntimeException("InputGestureData is corrupted, invalid trigger type!"); } } /** Returns the action to perform for this input gesture */ Loading Loading @@ -127,9 +147,15 @@ public final class InputGestureData { "No app launch data for system action launch application"); } AidlInputGestureData data = new AidlInputGestureData(); data.trigger = new AidlInputGestureData.Trigger(); if (mTrigger instanceof KeyTrigger keyTrigger) { data.keycode = keyTrigger.getKeycode(); data.modifierState = keyTrigger.getModifierState(); data.trigger.setKey(new AidlInputGestureData.KeyTrigger()); data.trigger.getKey().keycode = keyTrigger.getKeycode(); data.trigger.getKey().modifierState = keyTrigger.getModifierState(); } else if (mTrigger instanceof TouchpadTrigger touchpadTrigger) { data.trigger.setTouchpadGesture(new AidlInputGestureData.TouchpadGestureTrigger()); data.trigger.getTouchpadGesture().gestureType = touchpadTrigger.getTouchpadGestureType(); } else { throw new IllegalArgumentException("Invalid trigger type!"); } Loading Loading @@ -163,30 +189,12 @@ public final class InputGestureData { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; InputGestureData that = (InputGestureData) o; return mInputGestureData.keycode == that.mInputGestureData.keycode && mInputGestureData.modifierState == that.mInputGestureData.modifierState && mInputGestureData.gestureType == that.mInputGestureData.gestureType && Objects.equals(mInputGestureData.appLaunchCategory, that.mInputGestureData.appLaunchCategory) && Objects.equals(mInputGestureData.appLaunchRole, that.mInputGestureData.appLaunchRole) && Objects.equals(mInputGestureData.appLaunchPackageName, that.mInputGestureData.appLaunchPackageName) && Objects.equals(mInputGestureData.appLaunchPackageName, that.mInputGestureData.appLaunchPackageName); return Objects.equals(mInputGestureData, that.mInputGestureData); } @Override public int hashCode() { int _hash = 1; _hash = 31 * _hash + mInputGestureData.keycode; _hash = 31 * _hash + mInputGestureData.modifierState; _hash = 31 * _hash + mInputGestureData.gestureType; _hash = 31 * _hash + (mInputGestureData.appLaunchCategory != null ? mInputGestureData.appLaunchCategory.hashCode() : 0); _hash = 31 * _hash + (mInputGestureData.appLaunchRole != null ? mInputGestureData.appLaunchRole.hashCode() : 0); _hash = 31 * _hash + (mInputGestureData.appLaunchPackageName != null ? mInputGestureData.appLaunchPackageName.hashCode() : 0); _hash = 31 * _hash + (mInputGestureData.appLaunchPackageName != null ? mInputGestureData.appLaunchPackageName.hashCode() : 0); return _hash; return mInputGestureData.hashCode(); } public interface Trigger { Loading @@ -197,6 +205,11 @@ public final class InputGestureData { return new KeyTrigger(keycode, modifierState); } /** Creates a input gesture trigger based on a touchpad gesture */ public static Trigger createTouchpadTrigger(int touchpadGestureType) { return new TouchpadTrigger(touchpadGestureType); } /** Key based input gesture trigger */ public static class KeyTrigger implements Trigger { private static final int SHORTCUT_META_MASK = Loading Loading @@ -242,6 +255,43 @@ public final class InputGestureData { } } /** Touchpad based input gesture trigger */ public static class TouchpadTrigger implements Trigger { private final int mTouchpadGestureType; private TouchpadTrigger(int touchpadGestureType) { if (touchpadGestureType != TOUCHPAD_GESTURE_TYPE_THREE_FINGER_TAP) { throw new IllegalArgumentException( "Invalid touchpadGestureType = " + touchpadGestureType); } mTouchpadGestureType = touchpadGestureType; } public int getTouchpadGestureType() { return mTouchpadGestureType; } @Override public String toString() { return "TouchpadTrigger{" + "mTouchpadGestureType=" + mTouchpadGestureType + '}'; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; TouchpadTrigger that = (TouchpadTrigger) o; return mTouchpadGestureType == that.mTouchpadGestureType; } @Override public int hashCode() { return Objects.hashCode(mTouchpadGestureType); } } /** Data for action to perform when input gesture is triggered */ public record Action(@KeyGestureEvent.KeyGestureType int keyGestureType, @Nullable AppLaunchData appLaunchData) { Loading services/core/java/com/android/server/input/InputGestureManager.java +16 −0 Original line number Diff line number Diff line Loading @@ -361,6 +361,22 @@ final class InputGestureManager { } } @Nullable public InputGestureData getCustomGestureForTouchpadGesture(@UserIdInt int userId, int touchpadGestureType) { if (touchpadGestureType == InputGestureData.TOUCHPAD_GESTURE_TYPE_UNKNOWN) { return null; } synchronized (mGestureLock) { Map<InputGestureData.Trigger, InputGestureData> customGestures = mCustomInputGestures.get(userId); if (customGestures == null) { return null; } return customGestures.get(InputGestureData.createTouchpadTrigger(touchpadGestureType)); } } @Nullable public InputGestureData getSystemShortcutForKeyEvent(KeyEvent event) { final int keyCode = event.getKeyCode(); Loading services/core/java/com/android/server/input/InputManagerService.java +3 −1 Original line number Diff line number Diff line Loading @@ -64,6 +64,7 @@ import android.hardware.input.IKeyboardBacklightListener; import android.hardware.input.IStickyModifierStateListener; import android.hardware.input.ITabletModeChangedListener; import android.hardware.input.InputDeviceIdentifier; import android.hardware.input.InputGestureData; import android.hardware.input.InputManager; import android.hardware.input.InputSensorInfo; import android.hardware.input.InputSettings; Loading Loading @@ -2314,7 +2315,8 @@ public class InputManagerService extends IInputManager.Stub // Native callback. @SuppressWarnings("unused") private void notifyTouchpadThreeFingerTap() { mKeyGestureController.handleTouchpadThreeFingerTap(); mKeyGestureController.handleTouchpadGesture( InputGestureData.TOUCHPAD_GESTURE_TYPE_THREE_FINGER_TAP); } // Native callback. Loading services/core/java/com/android/server/input/KeyGestureController.java +19 −4 Original line number Diff line number Diff line Loading @@ -847,6 +847,13 @@ final class KeyGestureController { /* appLaunchData = */null); } private void handleTouchpadGesture(@KeyGestureEvent.KeyGestureType int keyGestureType, @Nullable AppLaunchData appLaunchData) { handleKeyGesture(KeyCharacterMap.VIRTUAL_KEYBOARD, new int[0], /* modifierState= */0, keyGestureType, KeyGestureEvent.ACTION_GESTURE_COMPLETE, Display.DEFAULT_DISPLAY, /* focusedToken = */null, /* flags = */0, appLaunchData); } @VisibleForTesting boolean handleKeyGesture(int deviceId, int[] keycodes, int modifierState, @KeyGestureEvent.KeyGestureType int gestureType, int action, int displayId, Loading Loading @@ -897,11 +904,18 @@ final class KeyGestureController { handleKeyGesture(event, null /*focusedToken*/); } public void handleTouchpadThreeFingerTap() { // TODO(b/365063048): trigger a custom shortcut based on the three-finger tap. if (DEBUG) { Slog.d(TAG, "Three-finger touchpad tap occurred"); public void handleTouchpadGesture(int touchpadGestureType) { // Handle custom shortcuts InputGestureData customGesture; synchronized (mUserLock) { customGesture = mInputGestureManager.getCustomGestureForTouchpadGesture(mCurrentUserId, touchpadGestureType); } if (customGesture == null) { return; } handleTouchpadGesture(customGesture.getAction().keyGestureType(), customGesture.getAction().appLaunchData()); } @MainThread Loading Loading @@ -1214,6 +1228,7 @@ final class KeyGestureController { public void dump(IndentingPrintWriter ipw) { ipw.println("KeyGestureController:"); ipw.increaseIndent(); ipw.println("mCurrentUserId = " + mCurrentUserId); ipw.println("mSystemPid = " + mSystemPid); ipw.println("mPendingMetaAction = " + mPendingMetaAction); ipw.println("mPendingCapsLockToggle = " + mPendingCapsLockToggle); Loading Loading
core/java/android/hardware/input/AidlInputGestureData.aidl +17 −4 Original line number Diff line number Diff line Loading @@ -19,13 +19,26 @@ package android.hardware.input; /** @hide */ @JavaDerive(equals=true) parcelable AidlInputGestureData { int keycode; int modifierState; int gestureType; Trigger trigger; // App launch parameters: Only set if gestureType is KEY_GESTURE_TYPE_LAUNCH_APPLICATION int gestureType; // App launch parameters (Only set if gestureType is LAUNCH_APPLICATION) String appLaunchCategory; String appLaunchRole; String appLaunchPackageName; String appLaunchClassName; parcelable KeyTrigger { int keycode; int modifierState; } parcelable TouchpadGestureTrigger { int gestureType; } union Trigger { KeyTrigger key; TouchpadGestureTrigger touchpadGesture; } }
core/java/android/hardware/input/InputGestureData.java +76 −26 Original line number Diff line number Diff line Loading @@ -35,20 +35,40 @@ import java.util.Objects; */ public final class InputGestureData { public static final int TOUCHPAD_GESTURE_TYPE_UNKNOWN = 0; public static final int TOUCHPAD_GESTURE_TYPE_THREE_FINGER_TAP = 1; @NonNull private final AidlInputGestureData mInputGestureData; public InputGestureData(AidlInputGestureData inputGestureData) { public InputGestureData(@NonNull AidlInputGestureData inputGestureData) { this.mInputGestureData = inputGestureData; validate(); } /** Returns the trigger information for this input gesture */ public Trigger getTrigger() { if (mInputGestureData.keycode != KeyEvent.KEYCODE_UNKNOWN) { return new KeyTrigger(mInputGestureData.keycode, mInputGestureData.modifierState); switch (mInputGestureData.trigger.getTag()) { case AidlInputGestureData.Trigger.Tag.key: { AidlInputGestureData.KeyTrigger trigger = mInputGestureData.trigger.getKey(); if (trigger == null) { throw new RuntimeException("InputGestureData is corrupted, null key trigger!"); } return createKeyTrigger(trigger.keycode, trigger.modifierState); } case AidlInputGestureData.Trigger.Tag.touchpadGesture: { AidlInputGestureData.TouchpadGestureTrigger trigger = mInputGestureData.trigger.getTouchpadGesture(); if (trigger == null) { throw new RuntimeException( "InputGestureData is corrupted, null touchpad trigger!"); } return createTouchpadTrigger(trigger.gestureType); } default: throw new RuntimeException("InputGestureData is corrupted, invalid trigger type!"); } } /** Returns the action to perform for this input gesture */ Loading Loading @@ -127,9 +147,15 @@ public final class InputGestureData { "No app launch data for system action launch application"); } AidlInputGestureData data = new AidlInputGestureData(); data.trigger = new AidlInputGestureData.Trigger(); if (mTrigger instanceof KeyTrigger keyTrigger) { data.keycode = keyTrigger.getKeycode(); data.modifierState = keyTrigger.getModifierState(); data.trigger.setKey(new AidlInputGestureData.KeyTrigger()); data.trigger.getKey().keycode = keyTrigger.getKeycode(); data.trigger.getKey().modifierState = keyTrigger.getModifierState(); } else if (mTrigger instanceof TouchpadTrigger touchpadTrigger) { data.trigger.setTouchpadGesture(new AidlInputGestureData.TouchpadGestureTrigger()); data.trigger.getTouchpadGesture().gestureType = touchpadTrigger.getTouchpadGestureType(); } else { throw new IllegalArgumentException("Invalid trigger type!"); } Loading Loading @@ -163,30 +189,12 @@ public final class InputGestureData { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; InputGestureData that = (InputGestureData) o; return mInputGestureData.keycode == that.mInputGestureData.keycode && mInputGestureData.modifierState == that.mInputGestureData.modifierState && mInputGestureData.gestureType == that.mInputGestureData.gestureType && Objects.equals(mInputGestureData.appLaunchCategory, that.mInputGestureData.appLaunchCategory) && Objects.equals(mInputGestureData.appLaunchRole, that.mInputGestureData.appLaunchRole) && Objects.equals(mInputGestureData.appLaunchPackageName, that.mInputGestureData.appLaunchPackageName) && Objects.equals(mInputGestureData.appLaunchPackageName, that.mInputGestureData.appLaunchPackageName); return Objects.equals(mInputGestureData, that.mInputGestureData); } @Override public int hashCode() { int _hash = 1; _hash = 31 * _hash + mInputGestureData.keycode; _hash = 31 * _hash + mInputGestureData.modifierState; _hash = 31 * _hash + mInputGestureData.gestureType; _hash = 31 * _hash + (mInputGestureData.appLaunchCategory != null ? mInputGestureData.appLaunchCategory.hashCode() : 0); _hash = 31 * _hash + (mInputGestureData.appLaunchRole != null ? mInputGestureData.appLaunchRole.hashCode() : 0); _hash = 31 * _hash + (mInputGestureData.appLaunchPackageName != null ? mInputGestureData.appLaunchPackageName.hashCode() : 0); _hash = 31 * _hash + (mInputGestureData.appLaunchPackageName != null ? mInputGestureData.appLaunchPackageName.hashCode() : 0); return _hash; return mInputGestureData.hashCode(); } public interface Trigger { Loading @@ -197,6 +205,11 @@ public final class InputGestureData { return new KeyTrigger(keycode, modifierState); } /** Creates a input gesture trigger based on a touchpad gesture */ public static Trigger createTouchpadTrigger(int touchpadGestureType) { return new TouchpadTrigger(touchpadGestureType); } /** Key based input gesture trigger */ public static class KeyTrigger implements Trigger { private static final int SHORTCUT_META_MASK = Loading Loading @@ -242,6 +255,43 @@ public final class InputGestureData { } } /** Touchpad based input gesture trigger */ public static class TouchpadTrigger implements Trigger { private final int mTouchpadGestureType; private TouchpadTrigger(int touchpadGestureType) { if (touchpadGestureType != TOUCHPAD_GESTURE_TYPE_THREE_FINGER_TAP) { throw new IllegalArgumentException( "Invalid touchpadGestureType = " + touchpadGestureType); } mTouchpadGestureType = touchpadGestureType; } public int getTouchpadGestureType() { return mTouchpadGestureType; } @Override public String toString() { return "TouchpadTrigger{" + "mTouchpadGestureType=" + mTouchpadGestureType + '}'; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; TouchpadTrigger that = (TouchpadTrigger) o; return mTouchpadGestureType == that.mTouchpadGestureType; } @Override public int hashCode() { return Objects.hashCode(mTouchpadGestureType); } } /** Data for action to perform when input gesture is triggered */ public record Action(@KeyGestureEvent.KeyGestureType int keyGestureType, @Nullable AppLaunchData appLaunchData) { Loading
services/core/java/com/android/server/input/InputGestureManager.java +16 −0 Original line number Diff line number Diff line Loading @@ -361,6 +361,22 @@ final class InputGestureManager { } } @Nullable public InputGestureData getCustomGestureForTouchpadGesture(@UserIdInt int userId, int touchpadGestureType) { if (touchpadGestureType == InputGestureData.TOUCHPAD_GESTURE_TYPE_UNKNOWN) { return null; } synchronized (mGestureLock) { Map<InputGestureData.Trigger, InputGestureData> customGestures = mCustomInputGestures.get(userId); if (customGestures == null) { return null; } return customGestures.get(InputGestureData.createTouchpadTrigger(touchpadGestureType)); } } @Nullable public InputGestureData getSystemShortcutForKeyEvent(KeyEvent event) { final int keyCode = event.getKeyCode(); Loading
services/core/java/com/android/server/input/InputManagerService.java +3 −1 Original line number Diff line number Diff line Loading @@ -64,6 +64,7 @@ import android.hardware.input.IKeyboardBacklightListener; import android.hardware.input.IStickyModifierStateListener; import android.hardware.input.ITabletModeChangedListener; import android.hardware.input.InputDeviceIdentifier; import android.hardware.input.InputGestureData; import android.hardware.input.InputManager; import android.hardware.input.InputSensorInfo; import android.hardware.input.InputSettings; Loading Loading @@ -2314,7 +2315,8 @@ public class InputManagerService extends IInputManager.Stub // Native callback. @SuppressWarnings("unused") private void notifyTouchpadThreeFingerTap() { mKeyGestureController.handleTouchpadThreeFingerTap(); mKeyGestureController.handleTouchpadGesture( InputGestureData.TOUCHPAD_GESTURE_TYPE_THREE_FINGER_TAP); } // Native callback. Loading
services/core/java/com/android/server/input/KeyGestureController.java +19 −4 Original line number Diff line number Diff line Loading @@ -847,6 +847,13 @@ final class KeyGestureController { /* appLaunchData = */null); } private void handleTouchpadGesture(@KeyGestureEvent.KeyGestureType int keyGestureType, @Nullable AppLaunchData appLaunchData) { handleKeyGesture(KeyCharacterMap.VIRTUAL_KEYBOARD, new int[0], /* modifierState= */0, keyGestureType, KeyGestureEvent.ACTION_GESTURE_COMPLETE, Display.DEFAULT_DISPLAY, /* focusedToken = */null, /* flags = */0, appLaunchData); } @VisibleForTesting boolean handleKeyGesture(int deviceId, int[] keycodes, int modifierState, @KeyGestureEvent.KeyGestureType int gestureType, int action, int displayId, Loading Loading @@ -897,11 +904,18 @@ final class KeyGestureController { handleKeyGesture(event, null /*focusedToken*/); } public void handleTouchpadThreeFingerTap() { // TODO(b/365063048): trigger a custom shortcut based on the three-finger tap. if (DEBUG) { Slog.d(TAG, "Three-finger touchpad tap occurred"); public void handleTouchpadGesture(int touchpadGestureType) { // Handle custom shortcuts InputGestureData customGesture; synchronized (mUserLock) { customGesture = mInputGestureManager.getCustomGestureForTouchpadGesture(mCurrentUserId, touchpadGestureType); } if (customGesture == null) { return; } handleTouchpadGesture(customGesture.getAction().keyGestureType(), customGesture.getAction().appLaunchData()); } @MainThread Loading Loading @@ -1214,6 +1228,7 @@ final class KeyGestureController { public void dump(IndentingPrintWriter ipw) { ipw.println("KeyGestureController:"); ipw.increaseIndent(); ipw.println("mCurrentUserId = " + mCurrentUserId); ipw.println("mSystemPid = " + mSystemPid); ipw.println("mPendingMetaAction = " + mPendingMetaAction); ipw.println("mPendingCapsLockToggle = " + mPendingCapsLockToggle); Loading