diff options
14 files changed, 1349 insertions, 527 deletions
diff --git a/core/java/android/hardware/input/AidlKeyGestureEvent.aidl b/core/java/android/hardware/input/AidlKeyGestureEvent.aidl new file mode 100644 index 000000000000..7cf8795085e3 --- /dev/null +++ b/core/java/android/hardware/input/AidlKeyGestureEvent.aidl @@ -0,0 +1,29 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.input; + +/** @hide */ +@JavaDerive(equals=true) +parcelable AidlKeyGestureEvent { + int deviceId; + int[] keycodes; + int modifierState; + int gestureType; + int action; + int displayId; + int flags; +} diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl index 2d96bbaae901..102f56e4672b 100644 --- a/core/java/android/hardware/input/IInputManager.aidl +++ b/core/java/android/hardware/input/IInputManager.aidl @@ -26,6 +26,7 @@ import android.hardware.input.IInputDeviceBatteryState; import android.hardware.input.IKeyboardBacklightListener; import android.hardware.input.IKeyboardBacklightState; import android.hardware.input.IKeyGestureEventListener; +import android.hardware.input.IKeyGestureHandler; import android.hardware.input.IStickyModifierStateListener; import android.hardware.input.ITabletModeChangedListener; import android.hardware.input.KeyboardLayoutSelectionResult; @@ -250,4 +251,14 @@ interface IInputManager { @JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = " + "android.Manifest.permission.MANAGE_KEY_GESTURES)") void unregisterKeyGestureEventListener(IKeyGestureEventListener listener); + + @PermissionManuallyEnforced + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = " + + "android.Manifest.permission.MANAGE_KEY_GESTURES)") + void registerKeyGestureHandler(IKeyGestureHandler handler); + + @PermissionManuallyEnforced + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = " + + "android.Manifest.permission.MANAGE_KEY_GESTURES)") + void unregisterKeyGestureHandler(IKeyGestureHandler handler); } diff --git a/core/java/android/hardware/input/IKeyGestureEventListener.aidl b/core/java/android/hardware/input/IKeyGestureEventListener.aidl index 2c430f1a1c9d..6b5f83758a11 100644 --- a/core/java/android/hardware/input/IKeyGestureEventListener.aidl +++ b/core/java/android/hardware/input/IKeyGestureEventListener.aidl @@ -16,11 +16,13 @@ package android.hardware.input; +import android.hardware.input.AidlKeyGestureEvent; + /** @hide */ oneway interface IKeyGestureEventListener { /** * Called when a key gesture event occurs. */ - void onKeyGestureEvent(int deviceId, in int[] keycodes, int modifierState, int shortcut); + void onKeyGestureEvent(in AidlKeyGestureEvent event); } diff --git a/core/java/android/hardware/input/IKeyGestureHandler.aidl b/core/java/android/hardware/input/IKeyGestureHandler.aidl new file mode 100644 index 000000000000..509b9482154e --- /dev/null +++ b/core/java/android/hardware/input/IKeyGestureHandler.aidl @@ -0,0 +1,42 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.input; + +import android.hardware.input.AidlKeyGestureEvent; +import android.os.IBinder; + +/** @hide */ +interface IKeyGestureHandler { + + /** + * Called when a key gesture starts, ends, or is cancelled. If a handler returns {@code true}, + * it means they intend to handle the full gesture and should handle all the events pertaining + * to that gesture. + */ + boolean handleKeyGesture(in AidlKeyGestureEvent event, in IBinder focusedToken); + + /** + * Called to know if a particular gesture type is supported by the handler. + * + * TODO(b/358569822): Remove this call to reduce the binder calls to single call for + * handleKeyGesture. For this we need to remove dependency of multi-key gestures to identify if + * a key gesture is supported on first relevant key down. + * Also, for now we prioritize handlers in the system server process above external handlers to + * reduce IPC binder calls. + */ + boolean isKeyGestureSupported(int gestureType); +} diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java index 04cfcd880f52..22728f7a5ad3 100644 --- a/core/java/android/hardware/input/InputManager.java +++ b/core/java/android/hardware/input/InputManager.java @@ -1406,6 +1406,33 @@ public final class InputManager { } /** + * Registers a key gesture event handler for {@link KeyGestureEvent} handling. + * + * @param handler the {@link KeyGestureEventHandler} + * @throws IllegalArgumentException if {@code handler} has already been registered previously. + * @throws NullPointerException if {@code handler} or {@code executor} is null. + * @hide + * @see #unregisterKeyGestureEventHandler(KeyGestureEventHandler) + */ + @RequiresPermission(Manifest.permission.MANAGE_KEY_GESTURES) + public void registerKeyGestureEventHandler(@NonNull KeyGestureEventHandler handler) + throws IllegalArgumentException { + mGlobal.registerKeyGestureEventHandler(handler); + } + + /** + * Unregisters a previously added key gesture event handler. + * + * @param handler the {@link KeyGestureEventHandler} + * @hide + * @see #registerKeyGestureEventHandler(KeyGestureEventHandler) + */ + @RequiresPermission(Manifest.permission.MANAGE_KEY_GESTURES) + public void unregisterKeyGestureEventHandler(@NonNull KeyGestureEventHandler handler) { + mGlobal.unregisterKeyGestureEventHandler(handler); + } + + /** * A callback used to be notified about battery state changes for an input device. The * {@link #onBatteryStateChanged(int, long, BatteryState)} method will be called once after the * listener is successfully registered to provide the initial battery state of the device. @@ -1522,4 +1549,35 @@ public final class InputManager { */ void onKeyGestureEvent(@NonNull KeyGestureEvent event); } + + /** + * A callback used to notify about key gesture event start, complete and cancel. Unlike + * {@see KeyGestureEventListener} which is to listen to successfully handled key gestures, this + * interface allows system components to register handler for handling key gestures. + * + * @see #registerKeyGestureEventHandler(KeyGestureEventHandler) + * @see #unregisterKeyGestureEventHandler(KeyGestureEventHandler) + * + * <p> NOTE: All callbacks will occur on system main and input threads, so the caller needs + * to move time-consuming operations to appropriate handler threads. + * @hide + */ + public interface KeyGestureEventHandler { + /** + * Called when a key gesture event starts, is completed, or is cancelled. If a handler + * returns {@code true}, it implies that the handler intends to handle the key gesture and + * only this handler will receive the future events for this key gesture. + * + * @param event the gesture event + */ + boolean handleKeyGestureEvent(@NonNull KeyGestureEvent event, + @Nullable IBinder focusedToken); + + /** + * Called to identify if a particular gesture is of interest to a handler. + * + * NOTE: If no active handler supports certain gestures, the gestures will not be captured. + */ + boolean isKeyGestureSupported(@KeyGestureEvent.KeyGestureType int gestureType); + } } diff --git a/core/java/android/hardware/input/InputManagerGlobal.java b/core/java/android/hardware/input/InputManagerGlobal.java index 2a362381a003..5c11346df1c3 100644 --- a/core/java/android/hardware/input/InputManagerGlobal.java +++ b/core/java/android/hardware/input/InputManagerGlobal.java @@ -25,6 +25,7 @@ import android.hardware.BatteryState; import android.hardware.SensorManager; import android.hardware.input.InputManager.InputDeviceBatteryListener; import android.hardware.input.InputManager.InputDeviceListener; +import android.hardware.input.InputManager.KeyGestureEventHandler; import android.hardware.input.InputManager.KeyGestureEventListener; import android.hardware.input.InputManager.KeyboardBacklightListener; import android.hardware.input.InputManager.OnTabletModeChangedListener; @@ -119,6 +120,14 @@ public final class InputManagerGlobal { @Nullable private IKeyGestureEventListener mKeyGestureEventListener; + private final Object mKeyGestureEventHandlerLock = new Object(); + @GuardedBy("mKeyGestureEventHandlerLock") + @Nullable + private ArrayList<KeyGestureEventHandler> mKeyGestureEventHandlers; + @GuardedBy("mKeyGestureEventHandlerLock") + @Nullable + private IKeyGestureHandler mKeyGestureHandler; + // InputDeviceSensorManager gets notified synchronously from the binder thread when input // devices change, so it must be synchronized with the input device listeners. @GuardedBy("mInputDeviceListeners") @@ -1080,18 +1089,14 @@ public final class InputManagerGlobal { } private class LocalKeyGestureEventListener extends IKeyGestureEventListener.Stub { - @Override - public void onKeyGestureEvent(int deviceId, int[] keycodes, int modifierState, - int gestureType) { + public void onKeyGestureEvent(@NonNull AidlKeyGestureEvent ev) { synchronized (mKeyGestureEventListenerLock) { if (mKeyGestureEventListeners == null) return; final int numListeners = mKeyGestureEventListeners.size(); + final KeyGestureEvent event = new KeyGestureEvent(ev); for (int i = 0; i < numListeners; i++) { - mKeyGestureEventListeners.get(i) - .onKeyGestureEvent( - new KeyGestureEvent(deviceId, keycodes, modifierState, - gestureType)); + mKeyGestureEventListeners.get(i).onKeyGestureEvent(event); } } } @@ -1154,6 +1159,96 @@ public final class InputManagerGlobal { } } + private class LocalKeyGestureHandler extends IKeyGestureHandler.Stub { + @Override + public boolean handleKeyGesture(@NonNull AidlKeyGestureEvent ev, IBinder focusedToken) { + synchronized (mKeyGestureEventHandlerLock) { + if (mKeyGestureEventHandlers == null) { + return false; + } + final int numHandlers = mKeyGestureEventHandlers.size(); + final KeyGestureEvent event = new KeyGestureEvent(ev); + for (int i = 0; i < numHandlers; i++) { + KeyGestureEventHandler handler = mKeyGestureEventHandlers.get(i); + if (handler.handleKeyGestureEvent(event, focusedToken)) { + return true; + } + } + } + return false; + } + + @Override + public boolean isKeyGestureSupported(@KeyGestureEvent.KeyGestureType int gestureType) { + synchronized (mKeyGestureEventHandlerLock) { + if (mKeyGestureEventHandlers == null) { + return false; + } + final int numHandlers = mKeyGestureEventHandlers.size(); + for (int i = 0; i < numHandlers; i++) { + KeyGestureEventHandler handler = mKeyGestureEventHandlers.get(i); + if (handler.isKeyGestureSupported(gestureType)) { + return true; + } + } + } + return false; + } + } + + /** + * @see InputManager#registerKeyGestureEventHandler(KeyGestureEventHandler) + */ + @RequiresPermission(Manifest.permission.MANAGE_KEY_GESTURES) + void registerKeyGestureEventHandler(@NonNull KeyGestureEventHandler handler) + throws IllegalArgumentException { + Objects.requireNonNull(handler, "handler should not be null"); + + synchronized (mKeyGestureEventHandlerLock) { + if (mKeyGestureHandler == null) { + mKeyGestureEventHandlers = new ArrayList<>(); + mKeyGestureHandler = new LocalKeyGestureHandler(); + + try { + mIm.registerKeyGestureHandler(mKeyGestureHandler); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + final int numHandlers = mKeyGestureEventHandlers.size(); + for (int i = 0; i < numHandlers; i++) { + if (mKeyGestureEventHandlers.get(i) == handler) { + throw new IllegalArgumentException("Handler has already been registered!"); + } + } + mKeyGestureEventHandlers.add(handler); + } + } + + /** + * @see InputManager#unregisterKeyGestureEventHandler(KeyGestureEventHandler) + */ + @RequiresPermission(Manifest.permission.MANAGE_KEY_GESTURES) + void unregisterKeyGestureEventHandler(@NonNull KeyGestureEventHandler handler) { + Objects.requireNonNull(handler, "handler should not be null"); + + synchronized (mKeyGestureEventHandlerLock) { + if (mKeyGestureEventHandlers == null) { + return; + } + mKeyGestureEventHandlers.removeIf(existingHandler -> existingHandler == handler); + if (mKeyGestureEventHandlers.isEmpty()) { + try { + mIm.unregisterKeyGestureHandler(mKeyGestureHandler); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + mKeyGestureEventHandlers = null; + mKeyGestureHandler = null; + } + } + } + /** * TODO(b/330517633): Cleanup the unsupported API */ diff --git a/core/java/android/hardware/input/KeyGestureEvent.java b/core/java/android/hardware/input/KeyGestureEvent.java index 7a8dd3395d21..c7ebc63a3d15 100644 --- a/core/java/android/hardware/input/KeyGestureEvent.java +++ b/core/java/android/hardware/input/KeyGestureEvent.java @@ -19,8 +19,11 @@ package android.hardware.input; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.view.Display; +import android.view.KeyCharacterMap; -import com.android.internal.util.DataClass; +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.AnnotationValidations; import com.android.internal.util.FrameworkStatsLog; import java.lang.annotation.Retention; @@ -31,501 +34,511 @@ import java.lang.annotation.RetentionPolicy; * * @hide */ -@DataClass(genToString = true, genEqualsHashCode = true) -public class KeyGestureEvent { +public final class KeyGestureEvent { - private final int mDeviceId; @NonNull - private final int[] mKeycodes; - private final int mModifierState; - @KeyGestureType - private final int mKeyGestureType; - - - public static final int KEY_GESTURE_TYPE_UNSPECIFIED = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__UNSPECIFIED; - public static final int KEY_GESTURE_TYPE_HOME = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__HOME; - public static final int KEY_GESTURE_TYPE_RECENT_APPS = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__RECENT_APPS; - public static final int KEY_GESTURE_TYPE_BACK = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__BACK; - public static final int KEY_GESTURE_TYPE_APP_SWITCH = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__APP_SWITCH; - public static final int KEY_GESTURE_TYPE_LAUNCH_ASSISTANT = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_ASSISTANT; - public static final int KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_VOICE_ASSISTANT; - public static final int KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_SYSTEM_SETTINGS; - public static final int KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__TOGGLE_NOTIFICATION_PANEL; - public static final int KEY_GESTURE_TYPE_TOGGLE_TASKBAR = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__TOGGLE_TASKBAR; - public static final int KEY_GESTURE_TYPE_TAKE_SCREENSHOT = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__TAKE_SCREENSHOT; - public static final int KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__OPEN_SHORTCUT_HELPER; - public static final int KEY_GESTURE_TYPE_BRIGHTNESS_UP = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__BRIGHTNESS_UP; - public static final int KEY_GESTURE_TYPE_BRIGHTNESS_DOWN = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__BRIGHTNESS_DOWN; - public static final int KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__KEYBOARD_BACKLIGHT_UP; - public static final int KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__KEYBOARD_BACKLIGHT_DOWN; - public static final int KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__KEYBOARD_BACKLIGHT_TOGGLE; - public static final int KEY_GESTURE_TYPE_VOLUME_UP = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__VOLUME_UP; - public static final int KEY_GESTURE_TYPE_VOLUME_DOWN = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__VOLUME_DOWN; - public static final int KEY_GESTURE_TYPE_VOLUME_MUTE = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__VOLUME_MUTE; - public static final int KEY_GESTURE_TYPE_ALL_APPS = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__ALL_APPS; - public static final int KEY_GESTURE_TYPE_LAUNCH_SEARCH = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_SEARCH; - public static final int KEY_GESTURE_TYPE_LANGUAGE_SWITCH = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LANGUAGE_SWITCH; - public static final int KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__ACCESSIBILITY_ALL_APPS; - public static final int KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__TOGGLE_CAPS_LOCK; - public static final int KEY_GESTURE_TYPE_SYSTEM_MUTE = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__SYSTEM_MUTE; - public static final int KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__SPLIT_SCREEN_NAVIGATION; - public static final int KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__CHANGE_SPLITSCREEN_FOCUS; - public static final int KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__TRIGGER_BUG_REPORT; - public static final int KEY_GESTURE_TYPE_LOCK_SCREEN = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LOCK_SCREEN; - public static final int KEY_GESTURE_TYPE_OPEN_NOTES = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__OPEN_NOTES; - public static final int KEY_GESTURE_TYPE_TOGGLE_POWER = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__TOGGLE_POWER; - public static final int KEY_GESTURE_TYPE_SYSTEM_NAVIGATION = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__SYSTEM_NAVIGATION; - public static final int KEY_GESTURE_TYPE_SLEEP = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__SLEEP; - public static final int KEY_GESTURE_TYPE_WAKEUP = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__WAKEUP; - public static final int KEY_GESTURE_TYPE_MEDIA_KEY = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__MEDIA_KEY; - public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_BROWSER; - public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_EMAIL; - public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_CONTACTS; - public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_CALENDAR; - public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_CALCULATOR; - public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MUSIC = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_MUSIC; - public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_MAPS; - public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_MESSAGING; - public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_GALLERY = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_GALLERY; - public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FILES = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_FILES; - public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_WEATHER = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_WEATHER; - public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FITNESS = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_FITNESS; - public static final int KEY_GESTURE_TYPE_LAUNCH_APPLICATION_BY_PACKAGE_NAME = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_APPLICATION_BY_PACKAGE_NAME; - public static final int KEY_GESTURE_TYPE_DESKTOP_MODE = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__DESKTOP_MODE; - public static final int KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION = - FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__MULTI_WINDOW_NAVIGATION; - - - - // Code below generated by codegen v1.0.23. - // - // DO NOT MODIFY! - // CHECKSTYLE:OFF Generated code - // - // To regenerate run: - // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/hardware/input/KeyGestureEvent.java - // - // To exclude the generated code from IntelliJ auto-formatting enable (one-time): - // Settings > Editor > Code Style > Formatter Control - //@formatter:off - + private AidlKeyGestureEvent mKeyGestureEvent; + + public static final int KEY_GESTURE_TYPE_UNSPECIFIED = 0; + public static final int KEY_GESTURE_TYPE_HOME = 1; + public static final int KEY_GESTURE_TYPE_RECENT_APPS = 2; + public static final int KEY_GESTURE_TYPE_BACK = 3; + public static final int KEY_GESTURE_TYPE_APP_SWITCH = 4; + public static final int KEY_GESTURE_TYPE_LAUNCH_ASSISTANT = 5; + public static final int KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT = 6; + public static final int KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS = 7; + public static final int KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL = 8; + public static final int KEY_GESTURE_TYPE_TOGGLE_TASKBAR = 9; + public static final int KEY_GESTURE_TYPE_TAKE_SCREENSHOT = 10; + public static final int KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER = 11; + public static final int KEY_GESTURE_TYPE_BRIGHTNESS_UP = 12; + public static final int KEY_GESTURE_TYPE_BRIGHTNESS_DOWN = 13; + public static final int KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP = 14; + public static final int KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN = 15; + public static final int KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE = 16; + public static final int KEY_GESTURE_TYPE_VOLUME_UP = 17; + public static final int KEY_GESTURE_TYPE_VOLUME_DOWN = 18; + public static final int KEY_GESTURE_TYPE_VOLUME_MUTE = 19; + public static final int KEY_GESTURE_TYPE_ALL_APPS = 20; + public static final int KEY_GESTURE_TYPE_LAUNCH_SEARCH = 21; + public static final int KEY_GESTURE_TYPE_LANGUAGE_SWITCH = 22; + public static final int KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS = 23; + public static final int KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK = 24; + public static final int KEY_GESTURE_TYPE_SYSTEM_MUTE = 25; + public static final int KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION = 26; + public static final int KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS = 27; + public static final int KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT = 28; + public static final int KEY_GESTURE_TYPE_LOCK_SCREEN = 29; + public static final int KEY_GESTURE_TYPE_OPEN_NOTES = 30; + public static final int KEY_GESTURE_TYPE_TOGGLE_POWER = 31; + public static final int KEY_GESTURE_TYPE_SYSTEM_NAVIGATION = 32; + public static final int KEY_GESTURE_TYPE_SLEEP = 33; + public static final int KEY_GESTURE_TYPE_WAKEUP = 34; + public static final int KEY_GESTURE_TYPE_MEDIA_KEY = 35; + public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER = 36; + public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL = 37; + public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS = 38; + public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR = 39; + public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR = 40; + public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MUSIC = 41; + public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS = 42; + public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING = 43; + public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_GALLERY = 44; + public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FILES = 45; + public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_WEATHER = 46; + public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FITNESS = 47; + public static final int KEY_GESTURE_TYPE_LAUNCH_APPLICATION_BY_PACKAGE_NAME = 48; + public static final int KEY_GESTURE_TYPE_DESKTOP_MODE = 49; + public static final int KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION = 50; + + public static final int FLAG_CANCELLED = 1; + + // NOTE: Valid KeyGestureEvent streams: + // - GESTURE_START -> GESTURE_CANCEL + // - GESTURE_START -> GESTURE_COMPLETE + // - GESTURE_COMPLETE + + /** Key gesture started (e.g. Key down of the relevant key) */ + public static final int ACTION_GESTURE_START = 1; + /** Key gesture completed (e.g. Key up of the relevant key) */ + public static final int ACTION_GESTURE_COMPLETE = 2; @IntDef(prefix = "KEY_GESTURE_TYPE_", value = { - KEY_GESTURE_TYPE_UNSPECIFIED, - KEY_GESTURE_TYPE_HOME, - KEY_GESTURE_TYPE_RECENT_APPS, - KEY_GESTURE_TYPE_BACK, - KEY_GESTURE_TYPE_APP_SWITCH, - KEY_GESTURE_TYPE_LAUNCH_ASSISTANT, - KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT, - KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS, - KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL, - KEY_GESTURE_TYPE_TOGGLE_TASKBAR, - KEY_GESTURE_TYPE_TAKE_SCREENSHOT, - KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER, - KEY_GESTURE_TYPE_BRIGHTNESS_UP, - KEY_GESTURE_TYPE_BRIGHTNESS_DOWN, - KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP, - KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN, - KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE, - KEY_GESTURE_TYPE_VOLUME_UP, - KEY_GESTURE_TYPE_VOLUME_DOWN, - KEY_GESTURE_TYPE_VOLUME_MUTE, - KEY_GESTURE_TYPE_ALL_APPS, - KEY_GESTURE_TYPE_LAUNCH_SEARCH, - KEY_GESTURE_TYPE_LANGUAGE_SWITCH, - KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS, - KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK, - KEY_GESTURE_TYPE_SYSTEM_MUTE, - KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION, - KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS, - KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT, - KEY_GESTURE_TYPE_LOCK_SCREEN, - KEY_GESTURE_TYPE_OPEN_NOTES, - KEY_GESTURE_TYPE_TOGGLE_POWER, - KEY_GESTURE_TYPE_SYSTEM_NAVIGATION, - KEY_GESTURE_TYPE_SLEEP, - KEY_GESTURE_TYPE_WAKEUP, - KEY_GESTURE_TYPE_MEDIA_KEY, - KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER, - KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL, - KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS, - KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR, - KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR, - KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MUSIC, - KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS, - KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING, - KEY_GESTURE_TYPE_LAUNCH_DEFAULT_GALLERY, - KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FILES, - KEY_GESTURE_TYPE_LAUNCH_DEFAULT_WEATHER, - KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FITNESS, - KEY_GESTURE_TYPE_LAUNCH_APPLICATION_BY_PACKAGE_NAME, - KEY_GESTURE_TYPE_DESKTOP_MODE, - KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION + KEY_GESTURE_TYPE_UNSPECIFIED, + KEY_GESTURE_TYPE_HOME, + KEY_GESTURE_TYPE_RECENT_APPS, + KEY_GESTURE_TYPE_BACK, + KEY_GESTURE_TYPE_APP_SWITCH, + KEY_GESTURE_TYPE_LAUNCH_ASSISTANT, + KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT, + KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS, + KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL, + KEY_GESTURE_TYPE_TOGGLE_TASKBAR, + KEY_GESTURE_TYPE_TAKE_SCREENSHOT, + KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER, + KEY_GESTURE_TYPE_BRIGHTNESS_UP, + KEY_GESTURE_TYPE_BRIGHTNESS_DOWN, + KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP, + KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN, + KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE, + KEY_GESTURE_TYPE_VOLUME_UP, + KEY_GESTURE_TYPE_VOLUME_DOWN, + KEY_GESTURE_TYPE_VOLUME_MUTE, + KEY_GESTURE_TYPE_ALL_APPS, + KEY_GESTURE_TYPE_LAUNCH_SEARCH, + KEY_GESTURE_TYPE_LANGUAGE_SWITCH, + KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS, + KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK, + KEY_GESTURE_TYPE_SYSTEM_MUTE, + KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION, + KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS, + KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT, + KEY_GESTURE_TYPE_LOCK_SCREEN, + KEY_GESTURE_TYPE_OPEN_NOTES, + KEY_GESTURE_TYPE_TOGGLE_POWER, + KEY_GESTURE_TYPE_SYSTEM_NAVIGATION, + KEY_GESTURE_TYPE_SLEEP, + KEY_GESTURE_TYPE_WAKEUP, + KEY_GESTURE_TYPE_MEDIA_KEY, + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER, + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL, + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS, + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR, + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR, + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MUSIC, + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS, + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING, + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_GALLERY, + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FILES, + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_WEATHER, + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FITNESS, + KEY_GESTURE_TYPE_LAUNCH_APPLICATION_BY_PACKAGE_NAME, + KEY_GESTURE_TYPE_DESKTOP_MODE, + KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION, }) @Retention(RetentionPolicy.SOURCE) - @DataClass.Generated.Member - public @interface KeyGestureType {} + public @interface KeyGestureType { + } + + public KeyGestureEvent(@NonNull AidlKeyGestureEvent keyGestureEvent) { + this.mKeyGestureEvent = keyGestureEvent; + } + + /** + * Key gesture event builder used to create a KeyGestureEvent for tests in Java. + * + * @hide + */ + public static class Builder { + private int mDeviceId = KeyCharacterMap.VIRTUAL_KEYBOARD; + private int[] mKeycodes = new int[0]; + private int mModifierState = 0; + @KeyGestureType + private int mKeyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_UNSPECIFIED; + private int mAction = KeyGestureEvent.ACTION_GESTURE_COMPLETE; + private int mDisplayId = Display.DEFAULT_DISPLAY; + private int mFlags = 0; + + /** + * @see KeyGestureEvent#getDeviceId() + */ + public Builder setDeviceId(int deviceId) { + mDeviceId = deviceId; + return this; + } + + /** + * @see KeyGestureEvent#getKeycodes() + */ + public Builder setKeycodes(@NonNull int[] keycodes) { + mKeycodes = keycodes; + return this; + } + + /** + * @see KeyGestureEvent#getModifierState() + */ + public Builder setModifierState(int modifierState) { + mModifierState = modifierState; + return this; + } + + /** + * @see KeyGestureEvent#getKeyGestureType() + */ + public Builder setKeyGestureType(@KeyGestureEvent.KeyGestureType int keyGestureType) { + mKeyGestureType = keyGestureType; + return this; + } + + /** + * @see KeyGestureEvent#getAction() + */ + public Builder setAction(int action) { + mAction = action; + return this; + } + + /** + * @see KeyGestureEvent#getDisplayId() + */ + public Builder setDisplayId(int displayId) { + mDisplayId = displayId; + return this; + } + + /** + * @see KeyGestureEvent#getFlags() + */ + public Builder setFlags(int flags) { + mFlags = flags; + return this; + } + + /** + * Build {@link KeyGestureEvent} + */ + public KeyGestureEvent build() { + AidlKeyGestureEvent event = new AidlKeyGestureEvent(); + event.deviceId = mDeviceId; + event.keycodes = mKeycodes; + event.modifierState = mModifierState; + event.gestureType = mKeyGestureType; + event.action = mAction; + event.displayId = mDisplayId; + event.flags = mFlags; + return new KeyGestureEvent(event); + } + } + + public int getDeviceId() { + return mKeyGestureEvent.deviceId; + } + + public @NonNull int[] getKeycodes() { + return mKeyGestureEvent.keycodes; + } + + public int getModifierState() { + return mKeyGestureEvent.modifierState; + } + + public @KeyGestureType int getKeyGestureType() { + return mKeyGestureEvent.gestureType; + } + + public int getAction() { + return mKeyGestureEvent.action; + } + + public int getDisplayId() { + return mKeyGestureEvent.displayId; + } - @DataClass.Generated.Member - public static String keyGestureTypeToString(@KeyGestureType int value) { + public int getFlags() { + return mKeyGestureEvent.flags; + } + + public boolean isCancelled() { + return (mKeyGestureEvent.flags & FLAG_CANCELLED) != 0; + } + + @Override + public String toString() { + return "KeyGestureEvent { " + + "deviceId = " + mKeyGestureEvent.deviceId + ", " + + "keycodes = " + java.util.Arrays.toString(mKeyGestureEvent.keycodes) + ", " + + "modifierState = " + mKeyGestureEvent.modifierState + ", " + + "keyGestureType = " + keyGestureTypeToString(mKeyGestureEvent.gestureType) + ", " + + "action = " + mKeyGestureEvent.action + ", " + + "displayId = " + mKeyGestureEvent.displayId + ", " + + "flags = " + mKeyGestureEvent.flags + + " }"; + } + + @Override + public boolean equals(@Nullable Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + KeyGestureEvent that = (KeyGestureEvent) o; + return mKeyGestureEvent.deviceId == that.mKeyGestureEvent.deviceId + && java.util.Arrays.equals(mKeyGestureEvent.keycodes, that.mKeyGestureEvent.keycodes) + && mKeyGestureEvent.modifierState == that.mKeyGestureEvent.modifierState + && mKeyGestureEvent.gestureType == that.mKeyGestureEvent.gestureType + && mKeyGestureEvent.action == that.mKeyGestureEvent.action + && mKeyGestureEvent.displayId == that.mKeyGestureEvent.displayId + && mKeyGestureEvent.flags == that.mKeyGestureEvent.flags; + } + + @Override + public int hashCode() { + int _hash = 1; + _hash = 31 * _hash + mKeyGestureEvent.deviceId; + _hash = 31 * _hash + java.util.Arrays.hashCode(mKeyGestureEvent.keycodes); + _hash = 31 * _hash + mKeyGestureEvent.modifierState; + _hash = 31 * _hash + mKeyGestureEvent.gestureType; + _hash = 31 * _hash + mKeyGestureEvent.action; + _hash = 31 * _hash + mKeyGestureEvent.displayId; + _hash = 31 * _hash + mKeyGestureEvent.flags; + return _hash; + } + + /** + * Convert KeyGestureEvent type to corresponding log event got KeyboardSystemsEvent + */ + public static int keyGestureTypeToLogEvent(@KeyGestureType int value) { switch (value) { - case KEY_GESTURE_TYPE_UNSPECIFIED: - return "KEY_GESTURE_TYPE_UNSPECIFIED"; case KEY_GESTURE_TYPE_HOME: - return "KEY_GESTURE_TYPE_HOME"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__HOME; case KEY_GESTURE_TYPE_RECENT_APPS: - return "KEY_GESTURE_TYPE_RECENT_APPS"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__RECENT_APPS; case KEY_GESTURE_TYPE_BACK: - return "KEY_GESTURE_TYPE_BACK"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__BACK; case KEY_GESTURE_TYPE_APP_SWITCH: - return "KEY_GESTURE_TYPE_APP_SWITCH"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__APP_SWITCH; case KEY_GESTURE_TYPE_LAUNCH_ASSISTANT: - return "KEY_GESTURE_TYPE_LAUNCH_ASSISTANT"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_ASSISTANT; case KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT: - return "KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_VOICE_ASSISTANT; case KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS: - return "KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_SYSTEM_SETTINGS; case KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL: - return "KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__TOGGLE_NOTIFICATION_PANEL; case KEY_GESTURE_TYPE_TOGGLE_TASKBAR: - return "KEY_GESTURE_TYPE_TOGGLE_TASKBAR"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__TOGGLE_TASKBAR; case KEY_GESTURE_TYPE_TAKE_SCREENSHOT: - return "KEY_GESTURE_TYPE_TAKE_SCREENSHOT"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__TAKE_SCREENSHOT; case KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER: - return "KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__OPEN_SHORTCUT_HELPER; case KEY_GESTURE_TYPE_BRIGHTNESS_UP: - return "KEY_GESTURE_TYPE_BRIGHTNESS_UP"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__BRIGHTNESS_UP; case KEY_GESTURE_TYPE_BRIGHTNESS_DOWN: - return "KEY_GESTURE_TYPE_BRIGHTNESS_DOWN"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__BRIGHTNESS_DOWN; case KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP: - return "KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__KEYBOARD_BACKLIGHT_UP; case KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN: - return "KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__KEYBOARD_BACKLIGHT_DOWN; case KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE: - return "KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__KEYBOARD_BACKLIGHT_TOGGLE; case KEY_GESTURE_TYPE_VOLUME_UP: - return "KEY_GESTURE_TYPE_VOLUME_UP"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__VOLUME_UP; case KEY_GESTURE_TYPE_VOLUME_DOWN: - return "KEY_GESTURE_TYPE_VOLUME_DOWN"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__VOLUME_DOWN; case KEY_GESTURE_TYPE_VOLUME_MUTE: - return "KEY_GESTURE_TYPE_VOLUME_MUTE"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__VOLUME_MUTE; case KEY_GESTURE_TYPE_ALL_APPS: - return "KEY_GESTURE_TYPE_ALL_APPS"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__ALL_APPS; case KEY_GESTURE_TYPE_LAUNCH_SEARCH: - return "KEY_GESTURE_TYPE_LAUNCH_SEARCH"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_SEARCH; case KEY_GESTURE_TYPE_LANGUAGE_SWITCH: - return "KEY_GESTURE_TYPE_LANGUAGE_SWITCH"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LANGUAGE_SWITCH; case KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS: - return "KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__ACCESSIBILITY_ALL_APPS; case KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK: - return "KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__TOGGLE_CAPS_LOCK; case KEY_GESTURE_TYPE_SYSTEM_MUTE: - return "KEY_GESTURE_TYPE_SYSTEM_MUTE"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__SYSTEM_MUTE; case KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION: - return "KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__SPLIT_SCREEN_NAVIGATION; case KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS: - return "KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__CHANGE_SPLITSCREEN_FOCUS; case KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT: - return "KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__TRIGGER_BUG_REPORT; case KEY_GESTURE_TYPE_LOCK_SCREEN: - return "KEY_GESTURE_TYPE_LOCK_SCREEN"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LOCK_SCREEN; case KEY_GESTURE_TYPE_OPEN_NOTES: - return "KEY_GESTURE_TYPE_OPEN_NOTES"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__OPEN_NOTES; case KEY_GESTURE_TYPE_TOGGLE_POWER: - return "KEY_GESTURE_TYPE_TOGGLE_POWER"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__TOGGLE_POWER; case KEY_GESTURE_TYPE_SYSTEM_NAVIGATION: - return "KEY_GESTURE_TYPE_SYSTEM_NAVIGATION"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__SYSTEM_NAVIGATION; case KEY_GESTURE_TYPE_SLEEP: - return "KEY_GESTURE_TYPE_SLEEP"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__SLEEP; case KEY_GESTURE_TYPE_WAKEUP: - return "KEY_GESTURE_TYPE_WAKEUP"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__WAKEUP; case KEY_GESTURE_TYPE_MEDIA_KEY: - return "KEY_GESTURE_TYPE_MEDIA_KEY"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__MEDIA_KEY; case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER: - return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_BROWSER; case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL: - return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_EMAIL; case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS: - return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_CONTACTS; case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR: - return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_CALENDAR; case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR: - return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_CALCULATOR; case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MUSIC: - return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MUSIC"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_MUSIC; case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS: - return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_MAPS; case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING: - return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_MESSAGING; case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_GALLERY: - return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_GALLERY"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_GALLERY; case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FILES: - return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FILES"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_FILES; case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_WEATHER: - return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_WEATHER"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_WEATHER; case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FITNESS: - return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FITNESS"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_FITNESS; case KEY_GESTURE_TYPE_LAUNCH_APPLICATION_BY_PACKAGE_NAME: - return "KEY_GESTURE_TYPE_LAUNCH_APPLICATION_BY_PACKAGE_NAME"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_APPLICATION_BY_PACKAGE_NAME; case KEY_GESTURE_TYPE_DESKTOP_MODE: - return "KEY_GESTURE_TYPE_DESKTOP_MODE"; + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__DESKTOP_MODE; case KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION: - return "KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION"; - default: return Integer.toHexString(value); + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__MULTI_WINDOW_NAVIGATION; + default: + return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__UNSPECIFIED; } } - @DataClass.Generated.Member - public KeyGestureEvent( - int deviceId, - @NonNull int[] keycodes, - int modifierState, - @KeyGestureType int keyGestureType) { - this.mDeviceId = deviceId; - this.mKeycodes = keycodes; - com.android.internal.util.AnnotationValidations.validate( - NonNull.class, null, mKeycodes); - this.mModifierState = modifierState; - this.mKeyGestureType = keyGestureType; - - if (!(mKeyGestureType == KEY_GESTURE_TYPE_UNSPECIFIED) - && !(mKeyGestureType == KEY_GESTURE_TYPE_HOME) - && !(mKeyGestureType == KEY_GESTURE_TYPE_RECENT_APPS) - && !(mKeyGestureType == KEY_GESTURE_TYPE_BACK) - && !(mKeyGestureType == KEY_GESTURE_TYPE_APP_SWITCH) - && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_ASSISTANT) - && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT) - && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS) - && !(mKeyGestureType == KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL) - && !(mKeyGestureType == KEY_GESTURE_TYPE_TOGGLE_TASKBAR) - && !(mKeyGestureType == KEY_GESTURE_TYPE_TAKE_SCREENSHOT) - && !(mKeyGestureType == KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER) - && !(mKeyGestureType == KEY_GESTURE_TYPE_BRIGHTNESS_UP) - && !(mKeyGestureType == KEY_GESTURE_TYPE_BRIGHTNESS_DOWN) - && !(mKeyGestureType == KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP) - && !(mKeyGestureType == KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN) - && !(mKeyGestureType == KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE) - && !(mKeyGestureType == KEY_GESTURE_TYPE_VOLUME_UP) - && !(mKeyGestureType == KEY_GESTURE_TYPE_VOLUME_DOWN) - && !(mKeyGestureType == KEY_GESTURE_TYPE_VOLUME_MUTE) - && !(mKeyGestureType == KEY_GESTURE_TYPE_ALL_APPS) - && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_SEARCH) - && !(mKeyGestureType == KEY_GESTURE_TYPE_LANGUAGE_SWITCH) - && !(mKeyGestureType == KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS) - && !(mKeyGestureType == KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK) - && !(mKeyGestureType == KEY_GESTURE_TYPE_SYSTEM_MUTE) - && !(mKeyGestureType == KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION) - && !(mKeyGestureType == KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS) - && !(mKeyGestureType == KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT) - && !(mKeyGestureType == KEY_GESTURE_TYPE_LOCK_SCREEN) - && !(mKeyGestureType == KEY_GESTURE_TYPE_OPEN_NOTES) - && !(mKeyGestureType == KEY_GESTURE_TYPE_TOGGLE_POWER) - && !(mKeyGestureType == KEY_GESTURE_TYPE_SYSTEM_NAVIGATION) - && !(mKeyGestureType == KEY_GESTURE_TYPE_SLEEP) - && !(mKeyGestureType == KEY_GESTURE_TYPE_WAKEUP) - && !(mKeyGestureType == KEY_GESTURE_TYPE_MEDIA_KEY) - && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER) - && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL) - && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS) - && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR) - && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR) - && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MUSIC) - && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS) - && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING) - && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_DEFAULT_GALLERY) - && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FILES) - && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_DEFAULT_WEATHER) - && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FITNESS) - && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_APPLICATION_BY_PACKAGE_NAME) - && !(mKeyGestureType == KEY_GESTURE_TYPE_DESKTOP_MODE) - && !(mKeyGestureType == KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION)) { - throw new java.lang.IllegalArgumentException( - "keyGestureType was " + mKeyGestureType + " but must be one of: " - + "KEY_GESTURE_TYPE_UNSPECIFIED(" + KEY_GESTURE_TYPE_UNSPECIFIED + "), " - + "KEY_GESTURE_TYPE_HOME(" + KEY_GESTURE_TYPE_HOME + "), " - + "KEY_GESTURE_TYPE_RECENT_APPS(" + KEY_GESTURE_TYPE_RECENT_APPS + "), " - + "KEY_GESTURE_TYPE_BACK(" + KEY_GESTURE_TYPE_BACK + "), " - + "KEY_GESTURE_TYPE_APP_SWITCH(" + KEY_GESTURE_TYPE_APP_SWITCH + "), " - + "KEY_GESTURE_TYPE_LAUNCH_ASSISTANT(" + KEY_GESTURE_TYPE_LAUNCH_ASSISTANT + "), " - + "KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT(" + KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT + "), " - + "KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS(" + KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS + "), " - + "KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL(" + KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL + "), " - + "KEY_GESTURE_TYPE_TOGGLE_TASKBAR(" + KEY_GESTURE_TYPE_TOGGLE_TASKBAR + "), " - + "KEY_GESTURE_TYPE_TAKE_SCREENSHOT(" + KEY_GESTURE_TYPE_TAKE_SCREENSHOT + "), " - + "KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER(" + KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER + "), " - + "KEY_GESTURE_TYPE_BRIGHTNESS_UP(" + KEY_GESTURE_TYPE_BRIGHTNESS_UP + "), " - + "KEY_GESTURE_TYPE_BRIGHTNESS_DOWN(" + KEY_GESTURE_TYPE_BRIGHTNESS_DOWN + "), " - + "KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP(" + KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP + "), " - + "KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN(" + KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN + "), " - + "KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE(" + KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE + "), " - + "KEY_GESTURE_TYPE_VOLUME_UP(" + KEY_GESTURE_TYPE_VOLUME_UP + "), " - + "KEY_GESTURE_TYPE_VOLUME_DOWN(" + KEY_GESTURE_TYPE_VOLUME_DOWN + "), " - + "KEY_GESTURE_TYPE_VOLUME_MUTE(" + KEY_GESTURE_TYPE_VOLUME_MUTE + "), " - + "KEY_GESTURE_TYPE_ALL_APPS(" + KEY_GESTURE_TYPE_ALL_APPS + "), " - + "KEY_GESTURE_TYPE_LAUNCH_SEARCH(" + KEY_GESTURE_TYPE_LAUNCH_SEARCH + "), " - + "KEY_GESTURE_TYPE_LANGUAGE_SWITCH(" + KEY_GESTURE_TYPE_LANGUAGE_SWITCH + "), " - + "KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS(" + KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS + "), " - + "KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK(" + KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK + "), " - + "KEY_GESTURE_TYPE_SYSTEM_MUTE(" + KEY_GESTURE_TYPE_SYSTEM_MUTE + "), " - + "KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION(" + KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION + "), " - + "KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS(" + KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS + "), " - + "KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT(" + KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT + "), " - + "KEY_GESTURE_TYPE_LOCK_SCREEN(" + KEY_GESTURE_TYPE_LOCK_SCREEN + "), " - + "KEY_GESTURE_TYPE_OPEN_NOTES(" + KEY_GESTURE_TYPE_OPEN_NOTES + "), " - + "KEY_GESTURE_TYPE_TOGGLE_POWER(" + KEY_GESTURE_TYPE_TOGGLE_POWER + "), " - + "KEY_GESTURE_TYPE_SYSTEM_NAVIGATION(" + KEY_GESTURE_TYPE_SYSTEM_NAVIGATION + "), " - + "KEY_GESTURE_TYPE_SLEEP(" + KEY_GESTURE_TYPE_SLEEP + "), " - + "KEY_GESTURE_TYPE_WAKEUP(" + KEY_GESTURE_TYPE_WAKEUP + "), " - + "KEY_GESTURE_TYPE_MEDIA_KEY(" + KEY_GESTURE_TYPE_MEDIA_KEY + "), " - + "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER(" + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER + "), " - + "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL(" + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL + "), " - + "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS(" + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS + "), " - + "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR(" + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR + "), " - + "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR(" + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR + "), " - + "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MUSIC(" + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MUSIC + "), " - + "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS(" + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS + "), " - + "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING(" + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING + "), " - + "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_GALLERY(" + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_GALLERY + "), " - + "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FILES(" + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FILES + "), " - + "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_WEATHER(" + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_WEATHER + "), " - + "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FITNESS(" + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FITNESS + "), " - + "KEY_GESTURE_TYPE_LAUNCH_APPLICATION_BY_PACKAGE_NAME(" + KEY_GESTURE_TYPE_LAUNCH_APPLICATION_BY_PACKAGE_NAME + "), " - + "KEY_GESTURE_TYPE_DESKTOP_MODE(" + KEY_GESTURE_TYPE_DESKTOP_MODE + "), " - + "KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION(" + KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION + ")"); + private static String keyGestureTypeToString(@KeyGestureType int value) { + switch (value) { + case KEY_GESTURE_TYPE_UNSPECIFIED: + return "KEY_GESTURE_TYPE_UNSPECIFIED"; + case KEY_GESTURE_TYPE_HOME: + return "KEY_GESTURE_TYPE_HOME"; + case KEY_GESTURE_TYPE_RECENT_APPS: + return "KEY_GESTURE_TYPE_RECENT_APPS"; + case KEY_GESTURE_TYPE_BACK: + return "KEY_GESTURE_TYPE_BACK"; + case KEY_GESTURE_TYPE_APP_SWITCH: + return "KEY_GESTURE_TYPE_APP_SWITCH"; + case KEY_GESTURE_TYPE_LAUNCH_ASSISTANT: + return "KEY_GESTURE_TYPE_LAUNCH_ASSISTANT"; + case KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT: + return "KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT"; + case KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS: + return "KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS"; + case KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL: + return "KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL"; + case KEY_GESTURE_TYPE_TOGGLE_TASKBAR: + return "KEY_GESTURE_TYPE_TOGGLE_TASKBAR"; + case KEY_GESTURE_TYPE_TAKE_SCREENSHOT: + return "KEY_GESTURE_TYPE_TAKE_SCREENSHOT"; + case KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER: + return "KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER"; + case KEY_GESTURE_TYPE_BRIGHTNESS_UP: + return "KEY_GESTURE_TYPE_BRIGHTNESS_UP"; + case KEY_GESTURE_TYPE_BRIGHTNESS_DOWN: + return "KEY_GESTURE_TYPE_BRIGHTNESS_DOWN"; + case KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP: + return "KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP"; + case KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN: + return "KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN"; + case KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE: + return "KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE"; + case KEY_GESTURE_TYPE_VOLUME_UP: + return "KEY_GESTURE_TYPE_VOLUME_UP"; + case KEY_GESTURE_TYPE_VOLUME_DOWN: + return "KEY_GESTURE_TYPE_VOLUME_DOWN"; + case KEY_GESTURE_TYPE_VOLUME_MUTE: + return "KEY_GESTURE_TYPE_VOLUME_MUTE"; + case KEY_GESTURE_TYPE_ALL_APPS: + return "KEY_GESTURE_TYPE_ALL_APPS"; + case KEY_GESTURE_TYPE_LAUNCH_SEARCH: + return "KEY_GESTURE_TYPE_LAUNCH_SEARCH"; + case KEY_GESTURE_TYPE_LANGUAGE_SWITCH: + return "KEY_GESTURE_TYPE_LANGUAGE_SWITCH"; + case KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS: + return "KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS"; + case KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK: + return "KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK"; + case KEY_GESTURE_TYPE_SYSTEM_MUTE: + return "KEY_GESTURE_TYPE_SYSTEM_MUTE"; + case KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION: + return "KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION"; + case KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS: + return "KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS"; + case KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT: + return "KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT"; + case KEY_GESTURE_TYPE_LOCK_SCREEN: + return "KEY_GESTURE_TYPE_LOCK_SCREEN"; + case KEY_GESTURE_TYPE_OPEN_NOTES: + return "KEY_GESTURE_TYPE_OPEN_NOTES"; + case KEY_GESTURE_TYPE_TOGGLE_POWER: + return "KEY_GESTURE_TYPE_TOGGLE_POWER"; + case KEY_GESTURE_TYPE_SYSTEM_NAVIGATION: + return "KEY_GESTURE_TYPE_SYSTEM_NAVIGATION"; + case KEY_GESTURE_TYPE_SLEEP: + return "KEY_GESTURE_TYPE_SLEEP"; + case KEY_GESTURE_TYPE_WAKEUP: + return "KEY_GESTURE_TYPE_WAKEUP"; + case KEY_GESTURE_TYPE_MEDIA_KEY: + return "KEY_GESTURE_TYPE_MEDIA_KEY"; + case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER: + return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER"; + case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL: + return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL"; + case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS: + return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS"; + case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR: + return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR"; + case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR: + return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR"; + case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MUSIC: + return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MUSIC"; + case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS: + return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS"; + case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING: + return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING"; + case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_GALLERY: + return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_GALLERY"; + case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FILES: + return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FILES"; + case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_WEATHER: + return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_WEATHER"; + case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FITNESS: + return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FITNESS"; + case KEY_GESTURE_TYPE_LAUNCH_APPLICATION_BY_PACKAGE_NAME: + return "KEY_GESTURE_TYPE_LAUNCH_APPLICATION_BY_PACKAGE_NAME"; + case KEY_GESTURE_TYPE_DESKTOP_MODE: + return "KEY_GESTURE_TYPE_DESKTOP_MODE"; + case KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION: + return "KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION"; + default: + return Integer.toHexString(value); } - - - // onConstructed(); // You can define this method to get a callback - } - - @DataClass.Generated.Member - public int getDeviceId() { - return mDeviceId; } - - @DataClass.Generated.Member - public @NonNull int[] getKeycodes() { - return mKeycodes; - } - - @DataClass.Generated.Member - public int getModifierState() { - return mModifierState; - } - - @DataClass.Generated.Member - public @KeyGestureType int getKeyGestureType() { - return mKeyGestureType; - } - - @Override - @DataClass.Generated.Member - public String toString() { - // You can override field toString logic by defining methods like: - // String fieldNameToString() { ... } - - return "KeyGestureEvent { " + - "deviceId = " + mDeviceId + ", " + - "keycodes = " + java.util.Arrays.toString(mKeycodes) + ", " + - "modifierState = " + mModifierState + ", " + - "keyGestureType = " + keyGestureTypeToString(mKeyGestureType) + - " }"; - } - - @Override - @DataClass.Generated.Member - public boolean equals(@Nullable Object o) { - // You can override field equality logic by defining either of the methods like: - // boolean fieldNameEquals(KeyGestureEvent other) { ... } - // boolean fieldNameEquals(FieldType otherValue) { ... } - - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - @SuppressWarnings("unchecked") - KeyGestureEvent that = (KeyGestureEvent) o; - //noinspection PointlessBooleanExpression - return true - && mDeviceId == that.mDeviceId - && java.util.Arrays.equals(mKeycodes, that.mKeycodes) - && mModifierState == that.mModifierState - && mKeyGestureType == that.mKeyGestureType; - } - - @Override - @DataClass.Generated.Member - public int hashCode() { - // You can override field hashCode logic by defining methods like: - // int fieldNameHashCode() { ... } - - int _hash = 1; - _hash = 31 * _hash + mDeviceId; - _hash = 31 * _hash + java.util.Arrays.hashCode(mKeycodes); - _hash = 31 * _hash + mModifierState; - _hash = 31 * _hash + mKeyGestureType; - return _hash; - } - - @DataClass.Generated( - time = 1723409092192L, - codegenVersion = "1.0.23", - sourceFile = "frameworks/base/core/java/android/hardware/input/KeyGestureEvent.java", - inputSignatures = "private final int mDeviceId\nprivate final @android.annotation.NonNull int[] mKeycodes\nprivate final int mModifierState\nprivate final @android.hardware.input.KeyGestureEvent.KeyGestureType int mKeyGestureType\npublic static final int KEY_GESTURE_TYPE_UNSPECIFIED\npublic static final int KEY_GESTURE_TYPE_HOME\npublic static final int KEY_GESTURE_TYPE_RECENT_APPS\npublic static final int KEY_GESTURE_TYPE_BACK\npublic static final int KEY_GESTURE_TYPE_APP_SWITCH\npublic static final int KEY_GESTURE_TYPE_LAUNCH_ASSISTANT\npublic static final int KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT\npublic static final int KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS\npublic static final int KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL\npublic static final int KEY_GESTURE_TYPE_TOGGLE_TASKBAR\npublic static final int KEY_GESTURE_TYPE_TAKE_SCREENSHOT\npublic static final int KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER\npublic static final int KEY_GESTURE_TYPE_BRIGHTNESS_UP\npublic static final int KEY_GESTURE_TYPE_BRIGHTNESS_DOWN\npublic static final int KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP\npublic static final int KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN\npublic static final int KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE\npublic static final int KEY_GESTURE_TYPE_VOLUME_UP\npublic static final int KEY_GESTURE_TYPE_VOLUME_DOWN\npublic static final int KEY_GESTURE_TYPE_VOLUME_MUTE\npublic static final int KEY_GESTURE_TYPE_ALL_APPS\npublic static final int KEY_GESTURE_TYPE_LAUNCH_SEARCH\npublic static final int KEY_GESTURE_TYPE_LANGUAGE_SWITCH\npublic static final int KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS\npublic static final int KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK\npublic static final int KEY_GESTURE_TYPE_SYSTEM_MUTE\npublic static final int KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION\npublic static final int KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS\npublic static final int KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT\npublic static final int KEY_GESTURE_TYPE_LOCK_SCREEN\npublic static final int KEY_GESTURE_TYPE_OPEN_NOTES\npublic static final int KEY_GESTURE_TYPE_TOGGLE_POWER\npublic static final int KEY_GESTURE_TYPE_SYSTEM_NAVIGATION\npublic static final int KEY_GESTURE_TYPE_SLEEP\npublic static final int KEY_GESTURE_TYPE_WAKEUP\npublic static final int KEY_GESTURE_TYPE_MEDIA_KEY\npublic static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER\npublic static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL\npublic static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS\npublic static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR\npublic static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR\npublic static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MUSIC\npublic static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS\npublic static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING\npublic static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_GALLERY\npublic static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FILES\npublic static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_WEATHER\npublic static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FITNESS\npublic static final int KEY_GESTURE_TYPE_LAUNCH_APPLICATION_BY_PACKAGE_NAME\npublic static final int KEY_GESTURE_TYPE_DESKTOP_MODE\npublic static final int KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION\nclass KeyGestureEvent extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genToString=true, genEqualsHashCode=true)") - @Deprecated - private void __metadata() {} - - - //@formatter:on - // End of generated code - } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractorTest.kt index 25c533685ba7..64915fbf551f 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractorTest.kt @@ -261,12 +261,12 @@ class KeyboardTouchpadEduInteractorTest : SysuiTestCase() { .registerKeyGestureEventListener(any(), listenerCaptor.capture()) val allAppsKeyGestureEvent = - KeyGestureEvent( - /* deviceId= */ 1, - IntArray(0), - KeyEvent.META_META_ON, - KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS - ) + KeyGestureEvent.Builder() + .setDeviceId(1) + .setModifierState(KeyEvent.META_META_ON) + .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS) + .setAction(KeyGestureEvent.ACTION_GESTURE_COMPLETE) + .build() listenerCaptor.value.onKeyGestureEvent(allAppsKeyGestureEvent) val model by diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index 1285a61d08f2..5dc1dda3b5ab 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -52,6 +52,7 @@ import android.hardware.input.IInputDevicesChangedListener; import android.hardware.input.IInputManager; import android.hardware.input.IInputSensorEventListener; import android.hardware.input.IKeyGestureEventListener; +import android.hardware.input.IKeyGestureHandler; import android.hardware.input.IKeyboardBacklightListener; import android.hardware.input.IStickyModifierStateListener; import android.hardware.input.ITabletModeChangedListener; @@ -164,7 +165,6 @@ public class InputManagerService extends IInputManager.Stub private static final int MSG_DELIVER_INPUT_DEVICES_CHANGED = 1; private static final int MSG_RELOAD_DEVICE_ALIASES = 2; private static final int MSG_DELIVER_TABLET_MODE_CHANGED = 3; - private static final int MSG_KEY_GESTURE_COMPLETED = 4; private static final int DEFAULT_VIBRATION_MAGNITUDE = 192; private static final AdditionalDisplayInputProperties @@ -476,7 +476,7 @@ public class InputManagerService extends IInputManager.Stub injector.getLooper(), injector.getUEventManager()) : new KeyboardBacklightControllerInterface() {}; mStickyModifierStateController = new StickyModifierStateController(); - mKeyGestureController = new KeyGestureController(); + mKeyGestureController = new KeyGestureController(mContext, injector.getLooper()); mKeyboardLedController = new KeyboardLedController(mContext, injector.getLooper(), mNative); mKeyRemapper = new KeyRemapper(mContext, mNative, mDataStore, injector.getLooper()); @@ -2464,6 +2464,11 @@ public class InputManagerService extends IInputManager.Stub // Native callback. @SuppressWarnings("unused") private long interceptKeyBeforeDispatching(IBinder focus, KeyEvent event, int policyFlags) { + // TODO(b/358569822): Move shortcut trigger logic from PWM to KeyGestureController + long value = mKeyGestureController.interceptKeyBeforeDispatching(focus, event, policyFlags); + if (value != 0) { // If key is consumed (i.e. non-zero value) + return value; + } return mWindowManagerCallbacks.interceptKeyBeforeDispatching(focus, event, policyFlags); } @@ -2769,33 +2774,38 @@ public class InputManagerService extends IInputManager.Stub @Override @PermissionManuallyEnforced - public void registerKeyGestureEventListener( - @NonNull IKeyGestureEventListener listener) { + public void registerKeyGestureEventListener(@NonNull IKeyGestureEventListener listener) { enforceManageKeyGesturePermission(); Objects.requireNonNull(listener); - mKeyGestureController.registerKeyGestureEventListener(listener, - Binder.getCallingPid()); + mKeyGestureController.registerKeyGestureEventListener(listener, Binder.getCallingPid()); } @Override @PermissionManuallyEnforced - public void unregisterKeyGestureEventListener( - @NonNull IKeyGestureEventListener listener) { + public void unregisterKeyGestureEventListener(@NonNull IKeyGestureEventListener listener) { enforceManageKeyGesturePermission(); Objects.requireNonNull(listener); - mKeyGestureController.unregisterKeyGestureEventListener(listener, - Binder.getCallingPid()); + mKeyGestureController.unregisterKeyGestureEventListener(listener, Binder.getCallingPid()); } - private void handleKeyGestureCompleted(KeyGestureEvent event) { - InputDevice device = getInputDevice(event.getDeviceId()); - if (device == null || device.isVirtual()) { - return; - } - KeyboardMetricsCollector.logKeyboardSystemsEventReportedAtom(device, event); - mKeyGestureController.onKeyGestureEvent(event); + @Override + @PermissionManuallyEnforced + public void registerKeyGestureHandler(@NonNull IKeyGestureHandler handler) { + enforceManageKeyGesturePermission(); + + Objects.requireNonNull(handler); + mKeyGestureController.registerKeyGestureHandler(handler, Binder.getCallingPid()); + } + + @Override + @PermissionManuallyEnforced + public void unregisterKeyGestureHandler(@NonNull IKeyGestureHandler handler) { + enforceManageKeyGesturePermission(); + + Objects.requireNonNull(handler); + mKeyGestureController.unregisterKeyGestureHandler(handler, Binder.getCallingPid()); } /** @@ -2966,9 +2976,6 @@ public class InputManagerService extends IInputManager.Stub boolean inTabletMode = (boolean) args.arg1; deliverTabletModeChanged(whenNanos, inTabletMode); break; - case MSG_KEY_GESTURE_COMPLETED: - KeyGestureEvent event = (KeyGestureEvent) msg.obj; - handleKeyGestureCompleted(event); } } } @@ -3298,9 +3305,8 @@ public class InputManagerService extends IInputManager.Stub @Override public void notifyKeyGestureCompleted(int deviceId, int[] keycodes, int modifierState, @KeyGestureEvent.KeyGestureType int gestureType) { - mHandler.obtainMessage(MSG_KEY_GESTURE_COMPLETED, - new KeyGestureEvent(deviceId, keycodes, modifierState, - gestureType)).sendToTarget(); + mKeyGestureController.notifyKeyGestureCompleted(deviceId, keycodes, modifierState, + gestureType); } } diff --git a/services/core/java/com/android/server/input/KeyGestureController.java b/services/core/java/com/android/server/input/KeyGestureController.java index 674d3c448c86..bfdb1c1f4ea9 100644 --- a/services/core/java/com/android/server/input/KeyGestureController.java +++ b/services/core/java/com/android/server/input/KeyGestureController.java @@ -17,15 +17,32 @@ package com.android.server.input; import android.annotation.BinderThread; +import android.annotation.MainThread; +import android.annotation.Nullable; +import android.content.Context; +import android.hardware.input.AidlKeyGestureEvent; import android.hardware.input.IKeyGestureEventListener; +import android.hardware.input.IKeyGestureHandler; +import android.hardware.input.InputManager; import android.hardware.input.KeyGestureEvent; +import android.os.Handler; import android.os.IBinder; +import android.os.Looper; +import android.os.Message; +import android.os.Process; import android.os.RemoteException; import android.util.Log; import android.util.Slog; import android.util.SparseArray; +import android.view.Display; +import android.view.InputDevice; +import android.view.KeyEvent; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; + +import java.util.Objects; +import java.util.TreeMap; /** * A thread-safe component of {@link InputManagerService} responsible for managing callbacks when a @@ -39,12 +56,101 @@ final class KeyGestureController { // 'adb shell setprop log.tag.KeyGestureController DEBUG' (requires restart) private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + private static final int MSG_NOTIFY_KEY_GESTURE_EVENT = 1; + + private final Context mContext; + private final Handler mHandler; + private final int mSystemPid; + // List of currently registered key gesture event listeners keyed by process pid @GuardedBy("mKeyGestureEventListenerRecords") private final SparseArray<KeyGestureEventListenerRecord> mKeyGestureEventListenerRecords = new SparseArray<>(); - public void onKeyGestureEvent(KeyGestureEvent event) { + // List of currently registered key gesture event handler keyed by process pid. The map sorts + // in the order of preference of the handlers, and we prioritize handlers in system server + // over external handlers.. + @GuardedBy("mKeyGestureHandlerRecords") + private final TreeMap<Integer, KeyGestureHandlerRecord> mKeyGestureHandlerRecords; + + KeyGestureController(Context context, Looper looper) { + mContext = context; + mHandler = new Handler(looper, this::handleMessage); + mSystemPid = Process.myPid(); + mKeyGestureHandlerRecords = new TreeMap<>((p1, p2) -> { + if (Objects.equals(p1, p2)) { + return 0; + } + if (p1 == mSystemPid) { + return -1; + } else if (p2 == mSystemPid) { + return 1; + } else { + return Integer.compare(p1, p2); + } + }); + } + + public int interceptKeyBeforeDispatching(IBinder focus, KeyEvent event, int policyFlags) { + // TODO(b/358569822): Handle shortcuts trigger logic here and pass it to appropriate + // KeyGestureHandler (PWM is one of the handlers) + return 0; + } + + @VisibleForTesting + boolean handleKeyGesture(int deviceId, int[] keycodes, int modifierState, + @KeyGestureEvent.KeyGestureType int gestureType, int action, int displayId, + IBinder focusedToken, int flags) { + AidlKeyGestureEvent event = createKeyGestureEvent(deviceId, keycodes, + modifierState, gestureType, action, displayId, flags); + synchronized (mKeyGestureHandlerRecords) { + for (KeyGestureHandlerRecord handler : mKeyGestureHandlerRecords.values()) { + if (handler.handleKeyGesture(event, focusedToken)) { + Message msg = Message.obtain(mHandler, MSG_NOTIFY_KEY_GESTURE_EVENT, event); + mHandler.sendMessage(msg); + return true; + } + } + } + return false; + } + + private boolean isKeyGestureSupported(@KeyGestureEvent.KeyGestureType int gestureType) { + synchronized (mKeyGestureHandlerRecords) { + for (KeyGestureHandlerRecord handler : mKeyGestureHandlerRecords.values()) { + if (handler.isKeyGestureSupported(gestureType)) { + return true; + } + } + } + return false; + } + + public void notifyKeyGestureCompleted(int deviceId, int[] keycodes, int modifierState, + @KeyGestureEvent.KeyGestureType int gestureType) { + // TODO(b/358569822): Once we move the gesture detection logic to IMS, we ideally + // should not rely on PWM to tell us about the gesture start and end. + AidlKeyGestureEvent event = createKeyGestureEvent(deviceId, keycodes, modifierState, + gestureType, KeyGestureEvent.ACTION_GESTURE_COMPLETE, Display.DEFAULT_DISPLAY, 0); + mHandler.obtainMessage(MSG_NOTIFY_KEY_GESTURE_EVENT, event).sendToTarget(); + } + + @MainThread + private void notifyKeyGestureEvent(AidlKeyGestureEvent event) { + InputDevice device = getInputDevice(event.deviceId); + if (device == null || device.isVirtual()) { + return; + } + if (event.action == KeyGestureEvent.ACTION_GESTURE_COMPLETE) { + KeyboardMetricsCollector.logKeyboardSystemsEventReportedAtom(device, event.keycodes, + event.modifierState, + KeyGestureEvent.keyGestureTypeToLogEvent(event.gestureType)); + } + notifyAllListeners(event); + } + + @MainThread + private void notifyAllListeners(AidlKeyGestureEvent event) { if (DEBUG) { Slog.d(TAG, "Key gesture event occurred, event = " + event); } @@ -56,17 +162,26 @@ final class KeyGestureController { } } + @MainThread + private boolean handleMessage(Message msg) { + switch (msg.what) { + case MSG_NOTIFY_KEY_GESTURE_EVENT: + AidlKeyGestureEvent event = (AidlKeyGestureEvent) msg.obj; + notifyKeyGestureEvent(event); + break; + } + return true; + } + /** Register the key gesture event listener for a process. */ @BinderThread - public void registerKeyGestureEventListener(IKeyGestureEventListener listener, - int pid) { + public void registerKeyGestureEventListener(IKeyGestureEventListener listener, int pid) { synchronized (mKeyGestureEventListenerRecords) { if (mKeyGestureEventListenerRecords.get(pid) != null) { throw new IllegalStateException("The calling process has already registered " + "a KeyGestureEventListener."); } - KeyGestureEventListenerRecord record = new KeyGestureEventListenerRecord( - pid, listener); + KeyGestureEventListenerRecord record = new KeyGestureEventListenerRecord(pid, listener); try { listener.asBinder().linkToDeath(record, 0); } catch (RemoteException ex) { @@ -78,8 +193,7 @@ final class KeyGestureController { /** Unregister the key gesture event listener for a process. */ @BinderThread - public void unregisterKeyGestureEventListener(IKeyGestureEventListener listener, - int pid) { + public void unregisterKeyGestureEventListener(IKeyGestureEventListener listener, int pid) { synchronized (mKeyGestureEventListenerRecords) { KeyGestureEventListenerRecord record = mKeyGestureEventListenerRecords.get(pid); @@ -120,10 +234,9 @@ final class KeyGestureController { onKeyGestureEventListenerDied(mPid); } - public void onKeyGestureEvent(KeyGestureEvent event) { + public void onKeyGestureEvent(AidlKeyGestureEvent event) { try { - mListener.onKeyGestureEvent(event.getDeviceId(), event.getKeycodes(), - event.getModifierState(), event.getKeyGestureType()); + mListener.onKeyGestureEvent(event); } catch (RemoteException ex) { Slog.w(TAG, "Failed to notify process " + mPid + " that key gesture event occurred, assuming it died.", ex); @@ -131,4 +244,107 @@ final class KeyGestureController { } } } + + /** Register the key gesture event handler for a process. */ + @BinderThread + public void registerKeyGestureHandler(IKeyGestureHandler handler, int pid) { + synchronized (mKeyGestureHandlerRecords) { + if (mKeyGestureHandlerRecords.get(pid) != null) { + throw new IllegalStateException("The calling process has already registered " + + "a KeyGestureHandler."); + } + KeyGestureHandlerRecord record = new KeyGestureHandlerRecord(pid, handler); + try { + handler.asBinder().linkToDeath(record, 0); + } catch (RemoteException ex) { + throw new RuntimeException(ex); + } + mKeyGestureHandlerRecords.put(pid, record); + } + } + + /** Unregister the key gesture event handler for a process. */ + @BinderThread + public void unregisterKeyGestureHandler(IKeyGestureHandler handler, int pid) { + synchronized (mKeyGestureHandlerRecords) { + KeyGestureHandlerRecord record = mKeyGestureHandlerRecords.get(pid); + if (record == null) { + throw new IllegalStateException("The calling process has no registered " + + "KeyGestureHandler."); + } + if (record.mKeyGestureHandler.asBinder() != handler.asBinder()) { + throw new IllegalStateException("The calling process has a different registered " + + "KeyGestureHandler."); + } + record.mKeyGestureHandler.asBinder().unlinkToDeath(record, 0); + mKeyGestureHandlerRecords.remove(pid); + } + } + + private void onKeyGestureHandlerDied(int pid) { + synchronized (mKeyGestureHandlerRecords) { + mKeyGestureHandlerRecords.remove(pid); + } + } + + // A record of a registered key gesture event listener from one process. + private class KeyGestureHandlerRecord implements IBinder.DeathRecipient { + public final int mPid; + public final IKeyGestureHandler mKeyGestureHandler; + + KeyGestureHandlerRecord(int pid, IKeyGestureHandler keyGestureHandler) { + mPid = pid; + mKeyGestureHandler = keyGestureHandler; + } + + @Override + public void binderDied() { + if (DEBUG) { + Slog.d(TAG, "Key gesture event handler for pid " + mPid + " died."); + } + onKeyGestureHandlerDied(mPid); + } + + public boolean handleKeyGesture(AidlKeyGestureEvent event, IBinder focusedToken) { + try { + return mKeyGestureHandler.handleKeyGesture(event, focusedToken); + } catch (RemoteException ex) { + Slog.w(TAG, "Failed to send key gesture to process " + mPid + + ", assuming it died.", ex); + binderDied(); + } + return false; + } + + public boolean isKeyGestureSupported(@KeyGestureEvent.KeyGestureType int gestureType) { + try { + return mKeyGestureHandler.isKeyGestureSupported(gestureType); + } catch (RemoteException ex) { + Slog.w(TAG, "Failed to identify if key gesture type is supported by the " + + "process " + mPid + ", assuming it died.", ex); + binderDied(); + } + return false; + } + } + + @Nullable + private InputDevice getInputDevice(int deviceId) { + InputManager inputManager = mContext.getSystemService(InputManager.class); + return inputManager != null ? inputManager.getInputDevice(deviceId) : null; + } + + private AidlKeyGestureEvent createKeyGestureEvent(int deviceId, int[] keycodes, + int modifierState, @KeyGestureEvent.KeyGestureType int gestureType, int action, + int displayId, int flags) { + AidlKeyGestureEvent event = new AidlKeyGestureEvent(); + event.deviceId = deviceId; + event.keycodes = keycodes; + event.modifierState = modifierState; + event.gestureType = gestureType; + event.action = action; + event.displayId = displayId; + event.flags = flags; + return event; + } } diff --git a/services/core/java/com/android/server/input/KeyboardMetricsCollector.java b/services/core/java/com/android/server/input/KeyboardMetricsCollector.java index 1daf4db699aa..609164a48687 100644 --- a/services/core/java/com/android/server/input/KeyboardMetricsCollector.java +++ b/services/core/java/com/android/server/input/KeyboardMetricsCollector.java @@ -24,7 +24,6 @@ import static android.hardware.input.KeyboardLayoutSelectionResult.layoutSelecti import android.annotation.NonNull; import android.annotation.Nullable; -import android.hardware.input.KeyGestureEvent; import android.hardware.input.KeyboardLayout; import android.hardware.input.KeyboardLayoutSelectionResult.LayoutSelectionCriteria; import android.icu.util.ULocale; @@ -41,6 +40,7 @@ import com.android.internal.os.KeyboardConfiguredProto.RepeatedKeyboardLayoutCon import com.android.internal.util.FrameworkStatsLog; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Objects; @@ -60,23 +60,26 @@ public final class KeyboardMetricsCollector { @VisibleForTesting public static final String DEFAULT_LANGUAGE_TAG = "None"; + private static final int INVALID_SYSTEMS_EVENT = FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__UNSPECIFIED; + /** * Log keyboard system shortcuts for the proto * {@link com.android.os.input.KeyboardSystemsEventReported} * defined in "stats/atoms/input/input_extension_atoms.proto" */ public static void logKeyboardSystemsEventReportedAtom(@NonNull InputDevice inputDevice, - @NonNull KeyGestureEvent keyGestureEvent) { - if (inputDevice.isVirtual() || !inputDevice.isFullKeyboard()) { + int[] keycodes, int modifierState, int systemsEvent) { + if (systemsEvent == INVALID_SYSTEMS_EVENT || inputDevice.isVirtual() + || !inputDevice.isFullKeyboard()) { return; } FrameworkStatsLog.write(FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED, inputDevice.getVendorId(), inputDevice.getProductId(), - keyGestureEvent.getKeyGestureType(), keyGestureEvent.getKeycodes(), - keyGestureEvent.getModifierState(), inputDevice.getDeviceBus()); + systemsEvent, keycodes, modifierState, inputDevice.getDeviceBus()); if (DEBUG) { - Slog.d(TAG, "Logging Keyboard system event: " + keyGestureEvent); + Slog.d(TAG, "Logging Keyboard system event: " + modifierState + " + " + Arrays.toString( + keycodes) + " -> " + systemsEvent); } } diff --git a/tests/Input/src/android/hardware/input/KeyGestureEventHandlerTest.kt b/tests/Input/src/android/hardware/input/KeyGestureEventHandlerTest.kt new file mode 100644 index 000000000000..072341dcefae --- /dev/null +++ b/tests/Input/src/android/hardware/input/KeyGestureEventHandlerTest.kt @@ -0,0 +1,236 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.input + +import android.content.Context +import android.content.ContextWrapper +import android.os.Handler +import android.os.IBinder +import android.os.test.TestLooper +import android.platform.test.annotations.Presubmit +import android.platform.test.flag.junit.SetFlagsRule +import android.view.KeyEvent +import androidx.test.core.app.ApplicationProvider +import com.android.server.testutils.any +import org.junit.After +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito +import org.mockito.Mockito.doAnswer +import org.mockito.Mockito.`when` +import org.mockito.junit.MockitoJUnitRunner +import kotlin.test.assertEquals +import kotlin.test.assertNotNull +import kotlin.test.assertNull +import kotlin.test.fail + +/** + * Tests for [InputManager.KeyGestureEventHandler]. + * + * Build/Install/Run: + * atest InputTests:KeyGestureEventHandlerTest + */ +@Presubmit +@RunWith(MockitoJUnitRunner::class) +class KeyGestureEventHandlerTest { + + companion object { + const val DEVICE_ID = 1 + val HOME_GESTURE_EVENT = KeyGestureEvent.Builder() + .setDeviceId(DEVICE_ID) + .setKeycodes(intArrayOf(KeyEvent.KEYCODE_H)) + .setModifierState(KeyEvent.META_META_ON or KeyEvent.META_META_LEFT_ON) + .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_HOME) + .build() + val BACK_GESTURE_EVENT = KeyGestureEvent.Builder() + .setDeviceId(DEVICE_ID) + .setKeycodes(intArrayOf(KeyEvent.KEYCODE_DEL)) + .setModifierState(KeyEvent.META_META_ON or KeyEvent.META_META_LEFT_ON) + .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_BACK) + .build() + } + + @get:Rule + val rule = SetFlagsRule() + + private val testLooper = TestLooper() + private var registeredListener: IKeyGestureHandler? = null + private lateinit var context: Context + private lateinit var inputManager: InputManager + private lateinit var inputManagerGlobalSession: InputManagerGlobal.TestSession + + @Mock + private lateinit var iInputManagerMock: IInputManager + + @Before + fun setUp() { + context = Mockito.spy(ContextWrapper(ApplicationProvider.getApplicationContext())) + inputManagerGlobalSession = InputManagerGlobal.createTestSession(iInputManagerMock) + inputManager = InputManager(context) + `when`(context.getSystemService(Mockito.eq(Context.INPUT_SERVICE))) + .thenReturn(inputManager) + + // Handle key gesture handler registration. + doAnswer { + val listener = it.getArgument(0) as IKeyGestureHandler + if (registeredListener != null && + registeredListener!!.asBinder() != listener.asBinder()) { + // There can only be one registered key gesture handler per process. + fail("Trying to register a new listener when one already exists") + } + registeredListener = listener + null + }.`when`(iInputManagerMock).registerKeyGestureHandler(any()) + + // Handle key gesture handler being unregistered. + doAnswer { + val listener = it.getArgument(0) as IKeyGestureHandler + if (registeredListener == null || + registeredListener!!.asBinder() != listener.asBinder()) { + fail("Trying to unregister a listener that is not registered") + } + registeredListener = null + null + }.`when`(iInputManagerMock).unregisterKeyGestureHandler(any()) + } + + @After + fun tearDown() { + if (this::inputManagerGlobalSession.isInitialized) { + inputManagerGlobalSession.close() + } + } + + private fun handleKeyGestureEvent(event: KeyGestureEvent) { + val eventToSend = AidlKeyGestureEvent() + eventToSend.deviceId = event.deviceId + eventToSend.keycodes = event.keycodes + eventToSend.modifierState = event.modifierState + eventToSend.gestureType = event.keyGestureType + eventToSend.action = event.action + eventToSend.displayId = event.displayId + eventToSend.flags = event.flags + registeredListener!!.handleKeyGesture(eventToSend, null) + } + + @Test + fun testHandlerHasCorrectGestureNotified() { + var callbackCount = 0 + + // Add a key gesture event listener + inputManager.registerKeyGestureEventHandler(KeyGestureHandler { event, _ -> + assertEquals(HOME_GESTURE_EVENT, event) + callbackCount++ + true + }) + + // Request handling for key gesture event will notify the handler. + handleKeyGestureEvent(HOME_GESTURE_EVENT) + assertEquals(1, callbackCount) + } + + @Test + fun testAddingHandlersRegistersInternalCallbackHandler() { + // Set up two callbacks. + val callback1 = KeyGestureHandler { _, _ -> false } + val callback2 = KeyGestureHandler { _, _ -> false } + + assertNull(registeredListener) + + // Adding the handler should register the callback with InputManagerService. + inputManager.registerKeyGestureEventHandler(callback1) + assertNotNull(registeredListener) + + // Adding another handler should not register new internal listener. + val currListener = registeredListener + inputManager.registerKeyGestureEventHandler(callback2) + assertEquals(currListener, registeredListener) + } + + @Test + fun testRemovingHandlersUnregistersInternalCallbackHandler() { + // Set up two callbacks. + val callback1 = KeyGestureHandler { _, _ -> false } + val callback2 = KeyGestureHandler { _, _ -> false } + + inputManager.registerKeyGestureEventHandler(callback1) + inputManager.registerKeyGestureEventHandler(callback2) + + // Only removing all handlers should remove the internal callback + inputManager.unregisterKeyGestureEventHandler(callback1) + assertNotNull(registeredListener) + inputManager.unregisterKeyGestureEventHandler(callback2) + assertNull(registeredListener) + } + + @Test + fun testMultipleHandlers() { + // Set up two callbacks. + var callbackCount1 = 0 + var callbackCount2 = 0 + // Handler 1 captures all home gestures + val callback1 = KeyGestureHandler { event, _ -> + callbackCount1++ + event.keyGestureType == KeyGestureEvent.KEY_GESTURE_TYPE_HOME + } + // Handler 2 captures all gestures + val callback2 = KeyGestureHandler { _, _ -> + callbackCount2++ + true + } + + // Add both key gesture event handlers + inputManager.registerKeyGestureEventHandler(callback1) + inputManager.registerKeyGestureEventHandler(callback2) + + // Request handling for key gesture event, should notify callbacks in order. So, only the + // first handler should receive a callback since it captures the event. + handleKeyGestureEvent(HOME_GESTURE_EVENT) + assertEquals(1, callbackCount1) + assertEquals(0, callbackCount2) + + // Second handler should receive the event since the first handler doesn't capture the event + handleKeyGestureEvent(BACK_GESTURE_EVENT) + assertEquals(2, callbackCount1) + assertEquals(1, callbackCount2) + + inputManager.unregisterKeyGestureEventHandler(callback1) + // Request handling for key gesture event, should still trigger callback2 but not callback1. + handleKeyGestureEvent(HOME_GESTURE_EVENT) + assertEquals(2, callbackCount1) + assertEquals(2, callbackCount2) + } + + inner class KeyGestureHandler( + private var handler: (event: KeyGestureEvent, token: IBinder?) -> Boolean + ) : InputManager.KeyGestureEventHandler { + + override fun handleKeyGestureEvent( + event: KeyGestureEvent, + focusedToken: IBinder? + ): Boolean { + return handler(event, focusedToken) + } + + override fun isKeyGestureSupported(gestureType: Int): Boolean { + return true + } + } +} diff --git a/tests/Input/src/android/hardware/input/KeyGestureEventListenerTest.kt b/tests/Input/src/android/hardware/input/KeyGestureEventListenerTest.kt index 14aac6637d4f..ca9de6000a5a 100644 --- a/tests/Input/src/android/hardware/input/KeyGestureEventListenerTest.kt +++ b/tests/Input/src/android/hardware/input/KeyGestureEventListenerTest.kt @@ -53,12 +53,12 @@ class KeyGestureEventListenerTest { companion object { const val DEVICE_ID = 1 - val HOME_GESTURE_EVENT = KeyGestureEvent( - DEVICE_ID, - intArrayOf(KeyEvent.KEYCODE_H), - KeyEvent.META_META_ON or KeyEvent.META_META_LEFT_ON, - KeyGestureEvent.KEY_GESTURE_TYPE_HOME - ) + val HOME_GESTURE_EVENT = KeyGestureEvent.Builder() + .setDeviceId(DEVICE_ID) + .setKeycodes(intArrayOf(KeyEvent.KEYCODE_H)) + .setModifierState(KeyEvent.META_META_ON or KeyEvent.META_META_LEFT_ON) + .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_HOME) + .build() } @get:Rule @@ -114,12 +114,15 @@ class KeyGestureEventListenerTest { } private fun notifyKeyGestureEvent(event: KeyGestureEvent) { - registeredListener!!.onKeyGestureEvent( - event.deviceId, - event.keycodes, - event.modifierState, - event.keyGestureType - ) + val eventToSend = AidlKeyGestureEvent() + eventToSend.deviceId = event.deviceId + eventToSend.keycodes = event.keycodes + eventToSend.modifierState = event.modifierState + eventToSend.gestureType = event.keyGestureType + eventToSend.action = event.action + eventToSend.displayId = event.displayId + eventToSend.flags = event.flags + registeredListener!!.onKeyGestureEvent(eventToSend) } @Test diff --git a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt index 3f611e0ead53..e12679742224 100644 --- a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt +++ b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt @@ -18,18 +18,28 @@ package com.android.server.input import android.content.Context import android.content.ContextWrapper +import android.hardware.input.IInputManager +import android.hardware.input.AidlKeyGestureEvent import android.hardware.input.IKeyGestureEventListener +import android.hardware.input.IKeyGestureHandler +import android.hardware.input.InputManager +import android.hardware.input.InputManagerGlobal import android.hardware.input.KeyGestureEvent +import android.os.IBinder +import android.os.Process +import android.os.test.TestLooper import android.platform.test.annotations.Presubmit +import android.view.InputDevice import android.view.KeyEvent import androidx.test.core.app.ApplicationProvider +import com.android.internal.util.FrameworkStatsLog +import com.android.modules.utils.testing.ExtendedMockitoRule import org.junit.Assert.assertEquals -import org.junit.Assert.assertNull import org.junit.Before import org.junit.Rule import org.junit.Test +import org.mockito.Mock import org.mockito.Mockito -import org.mockito.junit.MockitoJUnit /** * Tests for {@link KeyGestureController}. @@ -41,26 +51,55 @@ import org.mockito.junit.MockitoJUnit class KeyGestureControllerTests { companion object { - val DEVICE_ID = 1 - val HOME_GESTURE_EVENT = KeyGestureEvent( - DEVICE_ID, - intArrayOf(KeyEvent.KEYCODE_H), - KeyEvent.META_META_ON or KeyEvent.META_META_LEFT_ON, - KeyGestureEvent.KEY_GESTURE_TYPE_HOME - ) + const val DEVICE_ID = 1 + val HOME_GESTURE_COMPLETE_EVENT = KeyGestureEvent.Builder() + .setDeviceId(DEVICE_ID) + .setKeycodes(intArrayOf(KeyEvent.KEYCODE_H)) + .setModifierState(KeyEvent.META_META_ON or KeyEvent.META_META_LEFT_ON) + .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_HOME) + .setAction(KeyGestureEvent.ACTION_GESTURE_COMPLETE) + .build() } - @get:Rule - val rule = MockitoJUnit.rule()!! + @JvmField + @Rule + val extendedMockitoRule = ExtendedMockitoRule.Builder(this) + .mockStatic(FrameworkStatsLog::class.java).build()!! + + @Mock + private lateinit var iInputManager: IInputManager + private var currentPid = 0 private lateinit var keyGestureController: KeyGestureController private lateinit var context: Context - private var lastEvent: KeyGestureEvent? = null + private lateinit var inputManagerGlobalSession: InputManagerGlobal.TestSession + private lateinit var testLooper: TestLooper + private var events = mutableListOf<KeyGestureEvent>() @Before fun setup() { context = Mockito.spy(ContextWrapper(ApplicationProvider.getApplicationContext())) - keyGestureController = KeyGestureController() + inputManagerGlobalSession = InputManagerGlobal.createTestSession(iInputManager) + setupInputDevices() + testLooper = TestLooper() + currentPid = Process.myPid() + keyGestureController = KeyGestureController(context, testLooper.looper) + } + + private fun setupInputDevices() { + val inputManager = InputManager(context) + Mockito.`when`(context.getSystemService(Mockito.eq(Context.INPUT_SERVICE))) + .thenReturn(inputManager) + + val keyboardDevice = InputDevice.Builder().setId(DEVICE_ID).build() + Mockito.`when`(iInputManager.inputDeviceIds).thenReturn(intArrayOf(DEVICE_ID)) + Mockito.`when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardDevice) + } + + private fun notifyHomeGestureCompleted() { + keyGestureController.notifyKeyGestureCompleted(DEVICE_ID, intArrayOf(KeyEvent.KEYCODE_H), + KeyEvent.META_META_ON or KeyEvent.META_META_LEFT_ON, + KeyGestureEvent.KEY_GESTURE_TYPE_HOME) } @Test @@ -69,28 +108,97 @@ class KeyGestureControllerTests { // Register key gesture event listener keyGestureController.registerKeyGestureEventListener(listener, 0) - keyGestureController.onKeyGestureEvent(HOME_GESTURE_EVENT) + notifyHomeGestureCompleted() + testLooper.dispatchAll() assertEquals( - "Listener should get callback on key gesture event", - HOME_GESTURE_EVENT, - lastEvent!! + "Listener should get callbacks on key gesture event completed", + 1, + events.size + ) + assertEquals( + "Listener should get callback for key gesture complete event", + HOME_GESTURE_COMPLETE_EVENT, + events[0] ) // Unregister listener - lastEvent = null + events.clear() keyGestureController.unregisterKeyGestureEventListener(listener, 0) - keyGestureController.onKeyGestureEvent(HOME_GESTURE_EVENT) - assertNull("Listener should not get callback after being unregistered", lastEvent) + notifyHomeGestureCompleted() + testLooper.dispatchAll() + assertEquals( + "Listener should not get callback after being unregistered", + 0, + events.size + ) + } + + @Test + fun testKeyGestureEvent_multipleGestureHandlers() { + // Set up two callbacks. + var callbackCount1 = 0 + var callbackCount2 = 0 + var selfCallback = 0 + val externalHandler1 = KeyGestureHandler { _, _ -> + callbackCount1++; + true + } + val externalHandler2 = KeyGestureHandler { _, _ -> + callbackCount2++; + true + } + val selfHandler = KeyGestureHandler { _, _ -> + selfCallback++; + false + } + + // Register key gesture handler: External process (last in priority) + keyGestureController.registerKeyGestureHandler(externalHandler1, currentPid + 1) + + // Register key gesture handler: External process (second in priority) + keyGestureController.registerKeyGestureHandler(externalHandler2, currentPid - 1) + + // Register key gesture handler: Self process (first in priority) + keyGestureController.registerKeyGestureHandler(selfHandler, currentPid) + + keyGestureController.handleKeyGesture(/* deviceId = */ 0, intArrayOf(KeyEvent.KEYCODE_HOME), + /* modifierState = */ 0, KeyGestureEvent.KEY_GESTURE_TYPE_HOME, + KeyGestureEvent.ACTION_GESTURE_COMPLETE, /* displayId */ 0, + /* focusedToken = */ null, /* flags = */ 0 + ) + + assertEquals( + "Self handler should get callbacks first", + 1, + selfCallback + ) + assertEquals( + "Higher priority handler should get callbacks first", + 1, + callbackCount2 + ) + assertEquals( + "Lower priority handler should not get callbacks if already handled", + 0, + callbackCount1 + ) } inner class KeyGestureEventListener : IKeyGestureEventListener.Stub() { - override fun onKeyGestureEvent( - deviceId: Int, - keycodes: IntArray, - modifierState: Int, - gestureType: Int - ) { - lastEvent = KeyGestureEvent(deviceId, keycodes, modifierState, gestureType) + override fun onKeyGestureEvent(event: AidlKeyGestureEvent) { + events.add(KeyGestureEvent(event)) + } + } + + inner class KeyGestureHandler( + private var handler: (event: AidlKeyGestureEvent, token: IBinder?) -> Boolean + ) : IKeyGestureHandler.Stub() { + override fun handleKeyGesture(event: AidlKeyGestureEvent, token: IBinder?): Boolean { + return handler(event, token) + } + + override fun isKeyGestureSupported(gestureType: Int): Boolean { + return true } } }
\ No newline at end of file |