summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Vaibhav Devmurari <vdevmurari@google.com> 2025-03-07 19:05:55 +0000
committer Vaibhav Devmurari <vdevmurari@google.com> 2025-03-14 04:01:42 -0700
commitb1d338f1074bf7137ad03e94ade1b167c3ca97ae (patch)
treeb76f897633686bdb1b8cfdc134f5ddf39fed0193
parent20380db5b2dc017041c522539a5b6facdd8ae4c4 (diff)
(4/n) Shift to oneway binder call for register key handler
handleKeyGestureEvent() is synchronous API that makes system server dependent on handler and can cause ANR if handlers misbehave. As a replacement, handlers should provide list of gesture they want to listen to. For consistency, we only allow single handler per gesture. Test: atest InputTests Test: atest WmTests Test: Presubmit Bug: 358569822 Bug: 383602794 Flag: EXEMPT refactor Change-Id: Iea0f6ba3360ed241e19f0265d6ab28fd7889aafa
-rw-r--r--core/java/android/hardware/input/IInputManager.aidl2
-rw-r--r--core/java/android/hardware/input/IKeyGestureHandler.aidl10
-rw-r--r--core/java/android/hardware/input/InputManager.java21
-rw-r--r--core/java/android/hardware/input/InputManagerGlobal.java103
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandler.kt29
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandlerTest.kt20
-rw-r--r--packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt24
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInitializerTest.kt39
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java33
-rw-r--r--services/core/java/com/android/server/input/AppLaunchShortcutManager.java2
-rw-r--r--services/core/java/com/android/server/input/InputGestureManager.java9
-rw-r--r--services/core/java/com/android/server/input/InputManagerService.java46
-rw-r--r--services/core/java/com/android/server/input/KeyGestureController.java179
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java135
-rw-r--r--services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java148
-rw-r--r--services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java3
-rw-r--r--services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java20
-rw-r--r--services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java7
-rw-r--r--tests/Input/src/android/hardware/input/KeyGestureEventHandlerTest.kt115
-rw-r--r--tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt234
20 files changed, 635 insertions, 544 deletions
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index 1c2150f3c09f..5537135f7bfa 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -273,7 +273,7 @@ interface IInputManager {
@PermissionManuallyEnforced
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = "
+ "android.Manifest.permission.MANAGE_KEY_GESTURES)")
- void registerKeyGestureHandler(IKeyGestureHandler handler);
+ void registerKeyGestureHandler(in int[] keyGesturesToHandle, IKeyGestureHandler handler);
@PermissionManuallyEnforced
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = "
diff --git a/core/java/android/hardware/input/IKeyGestureHandler.aidl b/core/java/android/hardware/input/IKeyGestureHandler.aidl
index 4da991ee85b1..08b015892710 100644
--- a/core/java/android/hardware/input/IKeyGestureHandler.aidl
+++ b/core/java/android/hardware/input/IKeyGestureHandler.aidl
@@ -20,12 +20,12 @@ import android.hardware.input.AidlKeyGestureEvent;
import android.os.IBinder;
/** @hide */
-interface IKeyGestureHandler {
+oneway 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.
+ * Called when a key gesture starts, ends, or is cancelled. It is only sent to the handler that
+ * registered the callback for that particular gesture type.
+ * {@see IInputManager#registerKeyGestureHandler(int[], IKeyGestureHandler)}
*/
- boolean handleKeyGesture(in AidlKeyGestureEvent event, in IBinder focusedToken);
+ void handleKeyGesture(in AidlKeyGestureEvent event, in IBinder focusedToken);
}
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index d6419afb2a5a..a66ac76d7597 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -1446,16 +1446,18 @@ public final class InputManager {
/**
* Registers a key gesture event handler for {@link KeyGestureEvent} handling.
*
+ * @param keyGesturesToHandle list of KeyGestureTypes to listen to
* @param handler the {@link KeyGestureEventHandler}
- * @throws IllegalArgumentException if {@code handler} has already been registered previously.
+ * @throws IllegalArgumentException if {@code handler} has already been registered previously
+ * or key gestures provided are already registered by some other gesture handler.
* @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);
+ public void registerKeyGestureEventHandler(List<Integer> keyGesturesToHandle,
+ @NonNull KeyGestureEventHandler handler) throws IllegalArgumentException {
+ mGlobal.registerKeyGestureEventHandler(keyGesturesToHandle, handler);
}
/**
@@ -1463,7 +1465,7 @@ public final class InputManager {
*
* @param handler the {@link KeyGestureEventHandler}
* @hide
- * @see #registerKeyGestureEventHandler(KeyGestureEventHandler)
+ * @see #registerKeyGestureEventHandler(List, KeyGestureEventHandler)
*/
@RequiresPermission(Manifest.permission.MANAGE_KEY_GESTURES)
public void unregisterKeyGestureEventHandler(@NonNull KeyGestureEventHandler handler) {
@@ -1741,7 +1743,7 @@ public final class InputManager {
* {@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 #registerKeyGestureEventHandler(List, KeyGestureEventHandler)
* @see #unregisterKeyGestureEventHandler(KeyGestureEventHandler)
*
* <p> NOTE: All callbacks will occur on system main and input threads, so the caller needs
@@ -1750,14 +1752,11 @@ public final class InputManager {
*/
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.
+ * Called when a key gesture event starts, is completed, or is cancelled.
*
* @param event the gesture event
*/
- boolean handleKeyGestureEvent(@NonNull KeyGestureEvent event,
- @Nullable IBinder focusedToken);
+ void handleKeyGestureEvent(@NonNull KeyGestureEvent event, @Nullable IBinder focusedToken);
}
/** @hide */
diff --git a/core/java/android/hardware/input/InputManagerGlobal.java b/core/java/android/hardware/input/InputManagerGlobal.java
index c4b4831ba76e..754182ce3d11 100644
--- a/core/java/android/hardware/input/InputManagerGlobal.java
+++ b/core/java/android/hardware/input/InputManagerGlobal.java
@@ -25,8 +25,8 @@ 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.KeyEventActivityListener;
+import android.hardware.input.InputManager.KeyGestureEventHandler;
import android.hardware.input.InputManager.KeyGestureEventListener;
import android.hardware.input.InputManager.KeyboardBacklightListener;
import android.hardware.input.InputManager.OnTabletModeChangedListener;
@@ -49,6 +49,7 @@ import android.os.ServiceManager;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.os.VibratorManager;
+import android.util.IntArray;
import android.util.Log;
import android.util.SparseArray;
import android.view.Display;
@@ -132,13 +133,13 @@ public final class InputManagerGlobal {
@Nullable
private IKeyEventActivityListener mKeyEventActivityListener;
- private final Object mKeyGestureEventHandlerLock = new Object();
- @GuardedBy("mKeyGestureEventHandlerLock")
- @Nullable
- private ArrayList<KeyGestureEventHandler> mKeyGestureEventHandlers;
- @GuardedBy("mKeyGestureEventHandlerLock")
+ @GuardedBy("mKeyGesturesToHandlerMap")
@Nullable
private IKeyGestureHandler mKeyGestureHandler;
+ @GuardedBy("mKeyGesturesToHandlerMap")
+ private final SparseArray<KeyGestureEventHandler> mKeyGesturesToHandlerMap =
+ new SparseArray<>();
+
// InputDeviceSensorManager gets notified synchronously from the binder thread when input
// devices change, so it must be synchronized with the input device listeners.
@@ -1177,50 +1178,69 @@ 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;
- }
+ public void handleKeyGesture(@NonNull AidlKeyGestureEvent ev, IBinder focusedToken) {
+ synchronized (mKeyGesturesToHandlerMap) {
+ KeyGestureEventHandler handler = mKeyGesturesToHandlerMap.get(ev.gestureType);
+ if (handler == null) {
+ Log.w(TAG, "Key gesture event " + ev.gestureType
+ + " occurred without a registered handler!");
+ return;
}
+ handler.handleKeyGestureEvent(new KeyGestureEvent(ev), focusedToken);
}
- return false;
}
}
/**
- * @see InputManager#registerKeyGestureEventHandler(KeyGestureEventHandler)
+ * @see InputManager#registerKeyGestureEventHandler(List, KeyGestureEventHandler)
*/
@RequiresPermission(Manifest.permission.MANAGE_KEY_GESTURES)
- void registerKeyGestureEventHandler(@NonNull KeyGestureEventHandler handler)
- throws IllegalArgumentException {
+ void registerKeyGestureEventHandler(List<Integer> keyGesturesToHandle,
+ @NonNull KeyGestureEventHandler handler) throws IllegalArgumentException {
+ Objects.requireNonNull(keyGesturesToHandle, "List of gestures should not be null");
Objects.requireNonNull(handler, "handler should not be null");
- synchronized (mKeyGestureEventHandlerLock) {
- if (mKeyGestureHandler == null) {
- mKeyGestureEventHandlers = new ArrayList<>();
- mKeyGestureHandler = new LocalKeyGestureHandler();
+ if (keyGesturesToHandle.isEmpty()) {
+ throw new IllegalArgumentException("No key gestures provided!");
+ }
- try {
- mIm.registerKeyGestureHandler(mKeyGestureHandler);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ synchronized (mKeyGesturesToHandlerMap) {
+ IntArray newKeyGestures = new IntArray(
+ keyGesturesToHandle.size() + mKeyGesturesToHandlerMap.size());
+
+ // Check if the handler already exists
+ for (int i = 0; i < mKeyGesturesToHandlerMap.size(); i++) {
+ KeyGestureEventHandler h = mKeyGesturesToHandlerMap.valueAt(i);
+ if (h == handler) {
+ throw new IllegalArgumentException("Handler has already been registered!");
}
+ newKeyGestures.add(mKeyGesturesToHandlerMap.keyAt(i));
}
- 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!");
+
+ // Check if any of the key gestures are already handled by existing handlers
+ for (int gesture : keyGesturesToHandle) {
+ if (mKeyGesturesToHandlerMap.contains(gesture)) {
+ throw new IllegalArgumentException("Key gesture " + gesture
+ + " is already registered by another handler!");
+ }
+ newKeyGestures.add(gesture);
+ }
+
+ try {
+ // If handler was already registered for this process, we need to unregister and
+ // re-register it for the new set of gestures
+ if (mKeyGestureHandler != null) {
+ mIm.unregisterKeyGestureHandler(mKeyGestureHandler);
+ } else {
+ mKeyGestureHandler = new LocalKeyGestureHandler();
+ }
+ mIm.registerKeyGestureHandler(newKeyGestures.toArray(), mKeyGestureHandler);
+ for (int gesture : keyGesturesToHandle) {
+ mKeyGesturesToHandlerMap.put(gesture, handler);
}
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- mKeyGestureEventHandlers.add(handler);
}
}
@@ -1231,18 +1251,21 @@ public final class InputManagerGlobal {
void unregisterKeyGestureEventHandler(@NonNull KeyGestureEventHandler handler) {
Objects.requireNonNull(handler, "handler should not be null");
- synchronized (mKeyGestureEventHandlerLock) {
- if (mKeyGestureEventHandlers == null) {
+ synchronized (mKeyGesturesToHandlerMap) {
+ if (mKeyGestureHandler == null) {
return;
}
- mKeyGestureEventHandlers.removeIf(existingHandler -> existingHandler == handler);
- if (mKeyGestureEventHandlers.isEmpty()) {
+ for (int i = mKeyGesturesToHandlerMap.size() - 1; i >= 0; i--) {
+ if (mKeyGesturesToHandlerMap.valueAt(i) == handler) {
+ mKeyGesturesToHandlerMap.removeAt(i);
+ }
+ }
+ if (mKeyGesturesToHandlerMap.size() == 0) {
try {
mIm.unregisterKeyGestureHandler(mKeyGestureHandler);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
- mKeyGestureEventHandlers = null;
mKeyGestureHandler = null;
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandler.kt
index 1ea545f3ab67..19507c17bc95 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandler.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandler.kt
@@ -23,10 +23,7 @@ import android.hardware.input.InputManager
import android.hardware.input.InputManager.KeyGestureEventHandler
import android.hardware.input.KeyGestureEvent
import android.os.IBinder
-import android.window.DesktopModeFlags
-import com.android.hardware.input.Flags.manageKeyGestures
import com.android.internal.protolog.ProtoLog
-import com.android.window.flags.Flags.enableMoveToNextDisplayShortcut
import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.common.DisplayController
import com.android.wm.shell.common.ShellExecutor
@@ -51,16 +48,20 @@ class DesktopModeKeyGestureHandler(
) : KeyGestureEventHandler {
init {
- inputManager.registerKeyGestureEventHandler(this)
+ if (desktopTasksController.isPresent && desktopModeWindowDecorViewModel.isPresent) {
+ val supportedGestures =
+ listOf(
+ KeyGestureEvent.KEY_GESTURE_TYPE_MOVE_TO_NEXT_DISPLAY,
+ KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW,
+ KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW,
+ KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MAXIMIZE_FREEFORM_WINDOW,
+ KeyGestureEvent.KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW,
+ )
+ inputManager.registerKeyGestureEventHandler(supportedGestures, this)
+ }
}
- override fun handleKeyGestureEvent(event: KeyGestureEvent, focusedToken: IBinder?): Boolean {
- if (
- !desktopTasksController.isPresent ||
- !desktopModeWindowDecorViewModel.isPresent
- ) {
- return false
- }
+ override fun handleKeyGestureEvent(event: KeyGestureEvent, focusedToken: IBinder?) {
when (event.keyGestureType) {
KeyGestureEvent.KEY_GESTURE_TYPE_MOVE_TO_NEXT_DISPLAY -> {
logV("Key gesture MOVE_TO_NEXT_DISPLAY is handled")
@@ -69,7 +70,6 @@ class DesktopModeKeyGestureHandler(
desktopTasksController.get().moveToNextDisplay(it.taskId)
}
}
- return true
}
KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW -> {
logV("Key gesture SNAP_LEFT_FREEFORM_WINDOW is handled")
@@ -85,7 +85,6 @@ class DesktopModeKeyGestureHandler(
)
}
}
- return true
}
KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW -> {
logV("Key gesture SNAP_RIGHT_FREEFORM_WINDOW is handled")
@@ -101,7 +100,6 @@ class DesktopModeKeyGestureHandler(
)
}
}
- return true
}
KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MAXIMIZE_FREEFORM_WINDOW -> {
logV("Key gesture TOGGLE_MAXIMIZE_FREEFORM_WINDOW is handled")
@@ -120,7 +118,6 @@ class DesktopModeKeyGestureHandler(
)
}
}
- return true
}
KeyGestureEvent.KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW -> {
logV("Key gesture MINIMIZE_FREEFORM_WINDOW is handled")
@@ -129,9 +126,7 @@ class DesktopModeKeyGestureHandler(
desktopTasksController.get().minimizeTask(it, MinimizeReason.KEY_GESTURE)
}
}
- return true
}
- else -> return false
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandlerTest.kt
index d510570e8839..e40da5e8498d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandlerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandlerTest.kt
@@ -50,7 +50,6 @@ import com.android.wm.shell.desktopmode.common.ToggleTaskSizeInteraction
import com.android.wm.shell.sysui.ShellInit
import com.android.wm.shell.transition.FocusTransitionObserver
import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel
-import com.google.common.truth.Truth.assertThat
import java.util.Optional
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -120,11 +119,11 @@ class DesktopModeKeyGestureHandlerTest : ShellTestCase() {
whenever(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY)).thenReturn(tda)
doAnswer {
- keyGestureEventHandler = (it.arguments[0] as KeyGestureEventHandler)
+ keyGestureEventHandler = (it.arguments[1] as KeyGestureEventHandler)
null
}
.whenever(inputManager)
- .registerKeyGestureEventHandler(any())
+ .registerKeyGestureEventHandler(any(), any())
shellInit.init()
desktopModeKeyGestureHandler =
@@ -176,10 +175,9 @@ class DesktopModeKeyGestureHandlerTest : ShellTestCase() {
.setKeycodes(intArrayOf(KeyEvent.KEYCODE_D))
.setModifierState(KeyEvent.META_META_ON or KeyEvent.META_CTRL_ON)
.build()
- val result = keyGestureEventHandler.handleKeyGestureEvent(event, null)
+ keyGestureEventHandler.handleKeyGestureEvent(event, null)
testExecutor.flushAll()
- assertThat(result).isTrue()
verify(desktopTasksController).moveToNextDisplay(task.taskId)
}
@@ -197,10 +195,9 @@ class DesktopModeKeyGestureHandlerTest : ShellTestCase() {
.setKeycodes(intArrayOf(KeyEvent.KEYCODE_LEFT_BRACKET))
.setModifierState(KeyEvent.META_META_ON)
.build()
- val result = keyGestureEventHandler.handleKeyGestureEvent(event, null)
+ keyGestureEventHandler.handleKeyGestureEvent(event, null)
testExecutor.flushAll()
- assertThat(result).isTrue()
verify(desktopModeWindowDecorViewModel)
.onSnapResize(
task.taskId,
@@ -224,10 +221,9 @@ class DesktopModeKeyGestureHandlerTest : ShellTestCase() {
.setKeycodes(intArrayOf(KeyEvent.KEYCODE_RIGHT_BRACKET))
.setModifierState(KeyEvent.META_META_ON)
.build()
- val result = keyGestureEventHandler.handleKeyGestureEvent(event, null)
+ keyGestureEventHandler.handleKeyGestureEvent(event, null)
testExecutor.flushAll()
- assertThat(result).isTrue()
verify(desktopModeWindowDecorViewModel)
.onSnapResize(
task.taskId,
@@ -251,10 +247,9 @@ class DesktopModeKeyGestureHandlerTest : ShellTestCase() {
.setKeycodes(intArrayOf(KeyEvent.KEYCODE_EQUALS))
.setModifierState(KeyEvent.META_META_ON)
.build()
- val result = keyGestureEventHandler.handleKeyGestureEvent(event, null)
+ keyGestureEventHandler.handleKeyGestureEvent(event, null)
testExecutor.flushAll()
- assertThat(result).isTrue()
verify(desktopTasksController)
.toggleDesktopTaskSize(
task,
@@ -280,10 +275,9 @@ class DesktopModeKeyGestureHandlerTest : ShellTestCase() {
.setKeycodes(intArrayOf(KeyEvent.KEYCODE_MINUS))
.setModifierState(KeyEvent.META_META_ON)
.build()
- val result = keyGestureEventHandler.handleKeyGestureEvent(event, null)
+ keyGestureEventHandler.handleKeyGestureEvent(event, null)
testExecutor.flushAll()
- assertThat(result).isTrue()
verify(desktopTasksController).minimizeTask(task, MinimizeReason.KEY_GESTURE)
}
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt
index 8dc27bf4ac3e..080940169e46 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt
@@ -86,7 +86,10 @@ constructor(
*/
private fun initializeKeyGestureEventHandler() {
if (useKeyGestureEventHandler()) {
- inputManager.registerKeyGestureEventHandler(callbacks)
+ inputManager.registerKeyGestureEventHandler(
+ listOf(KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_NOTES),
+ callbacks,
+ )
}
}
@@ -156,11 +159,8 @@ constructor(
controller.updateNoteTaskForCurrentUserAndManagedProfiles()
}
- override fun handleKeyGestureEvent(
- event: KeyGestureEvent,
- focusedToken: IBinder?,
- ): Boolean {
- return this@NoteTaskInitializer.handleKeyGestureEvent(event)
+ override fun handleKeyGestureEvent(event: KeyGestureEvent, focusedToken: IBinder?) {
+ this@NoteTaskInitializer.handleKeyGestureEvent(event)
}
}
@@ -202,23 +202,19 @@ constructor(
return !isMultiPress && !isLongPress
}
- private fun handleKeyGestureEvent(event: KeyGestureEvent): Boolean {
- // This method is on input hot path and should be kept lightweight. Shift all complex
- // processing onto background executor wherever possible.
+ private fun handleKeyGestureEvent(event: KeyGestureEvent) {
if (event.keyGestureType != KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_NOTES) {
- return false
+ return
}
debugLog {
"handleKeyGestureEvent: Received OPEN_NOTES gesture event from keycodes: " +
event.keycodes.contentToString()
}
if (event.keycodes.size == 1 && event.keycodes[0] == KEYCODE_STYLUS_BUTTON_TAIL) {
- debugLog { "Note task triggered by stylus tail button" }
backgroundExecutor.execute { controller.showNoteTask(TAIL_BUTTON) }
- return true
+ } else {
+ backgroundExecutor.execute { controller.showNoteTask(KEYBOARD_SHORTCUT) }
}
- backgroundExecutor.execute { controller.showNoteTask(KEYBOARD_SHORTCUT) }
- return true
}
companion object {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInitializerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInitializerTest.kt
index 8a4f1ad13b78..5596cc7ee7da 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInitializerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInitializerTest.kt
@@ -38,8 +38,6 @@ import com.android.systemui.notetask.NoteTaskEntryPoint.TAIL_BUTTON
import com.android.systemui.settings.FakeUserTracker
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.util.concurrency.FakeExecutor
-import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.mockito.withArgCaptor
@@ -52,11 +50,14 @@ import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
+import org.mockito.Mockito.anyList
import org.mockito.Mockito.never
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.MockitoAnnotations.initMocks
+import org.mockito.kotlin.any
+import org.mockito.kotlin.eq
/** atest SystemUITests:NoteTaskInitializerTest */
@OptIn(InternalNoteTaskApi::class)
@@ -180,6 +181,18 @@ internal class NoteTaskInitializerTest : SysuiTestCase() {
@Test
@EnableFlags(com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER)
+ fun initialize_keyGestureTypeOpenNotes_isRegistered() {
+ val underTest = createUnderTest(isEnabled = true, bubbles = bubbles)
+ underTest.initialize()
+ verify(inputManager)
+ .registerKeyGestureEventHandler(
+ eq(listOf(KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_NOTES)),
+ any(),
+ )
+ }
+
+ @Test
+ @EnableFlags(com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER)
fun handlesShortcut_keyGestureTypeOpenNotes() {
val gestureEvent =
KeyGestureEvent.Builder()
@@ -189,12 +202,12 @@ internal class NoteTaskInitializerTest : SysuiTestCase() {
val underTest = createUnderTest(isEnabled = true, bubbles = bubbles)
underTest.initialize()
val callback = withArgCaptor {
- verify(inputManager).registerKeyGestureEventHandler(capture())
+ verify(inputManager).registerKeyGestureEventHandler(anyList(), capture())
}
- assertThat(callback.handleKeyGestureEvent(gestureEvent, null)).isTrue()
-
+ callback.handleKeyGestureEvent(gestureEvent, null)
executor.runAllReady()
+
verify(controller).showNoteTask(eq(KEYBOARD_SHORTCUT))
}
@@ -203,19 +216,19 @@ internal class NoteTaskInitializerTest : SysuiTestCase() {
fun handlesShortcut_stylusTailButton() {
val gestureEvent =
KeyGestureEvent.Builder()
- .setKeycodes(intArrayOf(KeyEvent.KEYCODE_STYLUS_BUTTON_TAIL))
+ .setKeycodes(intArrayOf(KEYCODE_STYLUS_BUTTON_TAIL))
.setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_NOTES)
.setAction(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
.build()
val underTest = createUnderTest(isEnabled = true, bubbles = bubbles)
underTest.initialize()
val callback = withArgCaptor {
- verify(inputManager).registerKeyGestureEventHandler(capture())
+ verify(inputManager).registerKeyGestureEventHandler(anyList(), capture())
}
- assertThat(callback.handleKeyGestureEvent(gestureEvent, null)).isTrue()
-
+ callback.handleKeyGestureEvent(gestureEvent, null)
executor.runAllReady()
+
verify(controller).showNoteTask(eq(TAIL_BUTTON))
}
@@ -224,19 +237,19 @@ internal class NoteTaskInitializerTest : SysuiTestCase() {
fun ignoresUnrelatedShortcuts() {
val gestureEvent =
KeyGestureEvent.Builder()
- .setKeycodes(intArrayOf(KeyEvent.KEYCODE_STYLUS_BUTTON_TAIL))
+ .setKeycodes(intArrayOf(KEYCODE_STYLUS_BUTTON_TAIL))
.setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_HOME)
.setAction(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
.build()
val underTest = createUnderTest(isEnabled = true, bubbles = bubbles)
underTest.initialize()
val callback = withArgCaptor {
- verify(inputManager).registerKeyGestureEventHandler(capture())
+ verify(inputManager).registerKeyGestureEventHandler(anyList(), capture())
}
- assertThat(callback.handleKeyGestureEvent(gestureEvent, null)).isFalse()
-
+ callback.handleKeyGestureEvent(gestureEvent, null)
executor.runAllReady()
+
verify(controller, never()).showNoteTask(any())
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 703e37fad5ad..45f83c500d48 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -514,14 +514,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
private InputManager.KeyGestureEventHandler mKeyGestureEventHandler =
- new InputManager.KeyGestureEventHandler() {
- @Override
- public boolean handleKeyGestureEvent(
- @NonNull KeyGestureEvent event,
- @Nullable IBinder focusedToken) {
- return AccessibilityManagerService.this.handleKeyGestureEvent(event);
- }
- };
+ (event, focusedToken) -> AccessibilityManagerService.this.handleKeyGestureEvent(event);
@VisibleForTesting
AccessibilityManagerService(
@@ -637,7 +630,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
new AccessibilityContentObserver(mMainHandler).register(
mContext.getContentResolver());
if (enableTalkbackAndMagnifierKeyGestures()) {
- mInputManager.registerKeyGestureEventHandler(mKeyGestureEventHandler);
+ List<Integer> supportedGestures = List.of(
+ KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MAGNIFICATION,
+ KeyGestureEvent.KEY_GESTURE_TYPE_ACTIVATE_SELECT_TO_SPEAK);
+ mInputManager.registerKeyGestureEventHandler(supportedGestures,
+ mKeyGestureEventHandler);
}
if (com.android.settingslib.flags.Flags.hearingDevicesInputRoutingControl()) {
if (mHearingDeviceNotificationController != null) {
@@ -686,13 +683,13 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
@VisibleForTesting
- boolean handleKeyGestureEvent(KeyGestureEvent event) {
+ void handleKeyGestureEvent(KeyGestureEvent event) {
final boolean complete =
event.getAction() == KeyGestureEvent.ACTION_GESTURE_COMPLETE
&& !event.isCancelled();
final int gestureType = event.getKeyGestureType();
if (!complete) {
- return false;
+ return;
}
String targetName;
@@ -703,7 +700,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
case KeyGestureEvent.KEY_GESTURE_TYPE_ACTIVATE_SELECT_TO_SPEAK:
targetName = mContext.getString(R.string.config_defaultSelectToSpeakService);
if (targetName.isEmpty()) {
- return false;
+ return;
}
final ComponentName targetServiceComponent = TextUtils.isEmpty(targetName)
@@ -715,7 +712,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
userState.getInstalledServiceInfoLocked(targetServiceComponent);
}
if (accessibilityServiceInfo == null) {
- return false;
+ return;
}
// Skip enabling if a warning dialog is required for the feature.
@@ -725,11 +722,13 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
Slog.w(LOG_TAG,
"Accessibility warning is required before this service can be "
+ "activated automatically via KEY_GESTURE shortcut.");
- return false;
+ return;
}
break;
default:
- return false;
+ Slog.w(LOG_TAG, "Received a key gesture " + event
+ + " that was not registered by this handler");
+ return;
}
List<String> shortcutTargets = getAccessibilityShortcutTargets(
@@ -748,14 +747,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
// this will be a separate dialog that appears that requires the user to confirm
// which will resolve this race condition. For now, just require two presses the
// first time it is activated.
- return true;
+ return;
}
final int displayId = event.getDisplayId() != INVALID_DISPLAY
? event.getDisplayId() : getLastNonProxyTopFocusedDisplayId();
performAccessibilityShortcutInternal(displayId, KEY_GESTURE, targetName);
-
- return true;
}
@Override
diff --git a/services/core/java/com/android/server/input/AppLaunchShortcutManager.java b/services/core/java/com/android/server/input/AppLaunchShortcutManager.java
index 8c028bc92841..eb102294ac32 100644
--- a/services/core/java/com/android/server/input/AppLaunchShortcutManager.java
+++ b/services/core/java/com/android/server/input/AppLaunchShortcutManager.java
@@ -111,7 +111,7 @@ final class AppLaunchShortcutManager {
mContext = context;
}
- public void systemRunning() {
+ public void init() {
loadShortcuts();
}
diff --git a/services/core/java/com/android/server/input/InputGestureManager.java b/services/core/java/com/android/server/input/InputGestureManager.java
index 67e1ccc6a850..e6d71900f106 100644
--- a/services/core/java/com/android/server/input/InputGestureManager.java
+++ b/services/core/java/com/android/server/input/InputGestureManager.java
@@ -94,9 +94,9 @@ final class InputGestureManager {
mContext = context;
}
- public void systemRunning() {
+ public void init(List<InputGestureData> bookmarks) {
initSystemShortcuts();
- blockListBookmarkedTriggers();
+ blockListBookmarkedTriggers(bookmarks);
}
private void initSystemShortcuts() {
@@ -263,10 +263,9 @@ final class InputGestureManager {
}
}
- private void blockListBookmarkedTriggers() {
+ private void blockListBookmarkedTriggers(List<InputGestureData> bookmarks) {
synchronized (mGestureLock) {
- InputManager im = Objects.requireNonNull(mContext.getSystemService(InputManager.class));
- for (InputGestureData bookmark : im.getAppLaunchBookmarks()) {
+ for (InputGestureData bookmark : bookmarks) {
mBlockListedTriggers.add(bookmark.getTrigger());
}
}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 6e6d00d62819..29e04e744759 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -2751,18 +2751,23 @@ public class InputManagerService extends IInputManager.Stub
@SuppressLint("MissingPermission")
private void initKeyGestures() {
InputManager im = Objects.requireNonNull(mContext.getSystemService(InputManager.class));
- im.registerKeyGestureEventHandler(new InputManager.KeyGestureEventHandler() {
- @Override
- public boolean handleKeyGestureEvent(@NonNull KeyGestureEvent event,
- @Nullable IBinder focussedToken) {
- return InputManagerService.this.handleKeyGestureEvent(event);
- }
- });
+ List<Integer> supportedGestures = List.of(
+ KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP,
+ KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN,
+ KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE,
+ KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK,
+ KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_BOUNCE_KEYS,
+ KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MOUSE_KEYS,
+ KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_STICKY_KEYS,
+ KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_SLOW_KEYS
+ );
+ im.registerKeyGestureEventHandler(supportedGestures,
+ (event, focusedToken) -> InputManagerService.this.handleKeyGestureEvent(event));
}
@SuppressLint("MissingPermission")
@VisibleForTesting
- boolean handleKeyGestureEvent(@NonNull KeyGestureEvent event) {
+ void handleKeyGestureEvent(@NonNull KeyGestureEvent event) {
int deviceId = event.getDeviceId();
boolean complete = event.getAction() == KeyGestureEvent.ACTION_GESTURE_COMPLETE
&& !event.isCancelled();
@@ -2771,20 +2776,20 @@ public class InputManagerService extends IInputManager.Stub
if (complete) {
mKeyboardBacklightController.incrementKeyboardBacklight(deviceId);
}
- return true;
+ break;
case KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN:
if (complete) {
mKeyboardBacklightController.decrementKeyboardBacklight(deviceId);
}
- return true;
+ break;
case KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE:
// TODO(b/367748270): Add functionality to turn keyboard backlight on/off.
- return true;
+ break;
case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK:
if (complete) {
mNative.toggleCapsLock(deviceId);
}
- return true;
+ break;
case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_BOUNCE_KEYS:
if (complete) {
final boolean bounceKeysEnabled =
@@ -2792,7 +2797,6 @@ public class InputManagerService extends IInputManager.Stub
InputSettings.setAccessibilityBounceKeysThreshold(mContext,
bounceKeysEnabled ? 0
: InputSettings.DEFAULT_BOUNCE_KEYS_THRESHOLD_MILLIS);
- return true;
}
break;
case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MOUSE_KEYS:
@@ -2800,7 +2804,6 @@ public class InputManagerService extends IInputManager.Stub
final boolean mouseKeysEnabled = InputSettings.isAccessibilityMouseKeysEnabled(
mContext);
InputSettings.setAccessibilityMouseKeysEnabled(mContext, !mouseKeysEnabled);
- return true;
}
break;
case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_STICKY_KEYS:
@@ -2808,7 +2811,6 @@ public class InputManagerService extends IInputManager.Stub
final boolean stickyKeysEnabled =
InputSettings.isAccessibilityStickyKeysEnabled(mContext);
InputSettings.setAccessibilityStickyKeysEnabled(mContext, !stickyKeysEnabled);
- return true;
}
break;
case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_SLOW_KEYS:
@@ -2817,14 +2819,13 @@ public class InputManagerService extends IInputManager.Stub
InputSettings.isAccessibilitySlowKeysEnabled(mContext);
InputSettings.setAccessibilitySlowKeysThreshold(mContext,
slowKeysEnabled ? 0 : InputSettings.DEFAULT_SLOW_KEYS_THRESHOLD_MILLIS);
- return true;
}
break;
default:
- return false;
-
+ Log.w(TAG, "Received a key gesture " + event
+ + " that was not registered by this handler");
+ break;
}
- return false;
}
// Native callback.
@@ -3147,11 +3148,14 @@ public class InputManagerService extends IInputManager.Stub
@Override
@PermissionManuallyEnforced
- public void registerKeyGestureHandler(@NonNull IKeyGestureHandler handler) {
+ public void registerKeyGestureHandler(int[] keyGesturesToHandle,
+ @NonNull IKeyGestureHandler handler) {
enforceManageKeyGesturePermission();
Objects.requireNonNull(handler);
- mKeyGestureController.registerKeyGestureHandler(handler, Binder.getCallingPid());
+ Objects.requireNonNull(keyGesturesToHandle);
+ mKeyGestureController.registerKeyGestureHandler(keyGesturesToHandle, handler,
+ Binder.getCallingPid());
}
@Override
diff --git a/services/core/java/com/android/server/input/KeyGestureController.java b/services/core/java/com/android/server/input/KeyGestureController.java
index 395c77322c04..5de432e5849b 100644
--- a/services/core/java/com/android/server/input/KeyGestureController.java
+++ b/services/core/java/com/android/server/input/KeyGestureController.java
@@ -58,6 +58,7 @@ import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SparseIntArray;
import android.view.Display;
import android.view.InputDevice;
import android.view.KeyCharacterMap;
@@ -79,11 +80,11 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayDeque;
+import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
-import java.util.TreeMap;
/**
* A thread-safe component of {@link InputManagerService} responsible for managing callbacks when a
@@ -166,11 +167,14 @@ final class KeyGestureController {
private final SparseArray<KeyGestureEventListenerRecord>
mKeyGestureEventListenerRecords = new SparseArray<>();
- // 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..
+ // Map of currently registered key gesture event handlers keyed by pid.
@GuardedBy("mKeyGestureHandlerRecords")
- private final TreeMap<Integer, KeyGestureHandlerRecord> mKeyGestureHandlerRecords;
+ private final SparseArray<KeyGestureHandlerRecord> mKeyGestureHandlerRecords =
+ new SparseArray<>();
+
+ // Currently supported key gestures mapped to pid that registered the corresponding handler.
+ @GuardedBy("mKeyGestureHandlerRecords")
+ private final SparseIntArray mSupportedKeyGestureToPidMap = new SparseIntArray();
private final ArrayDeque<KeyGestureEvent> mLastHandledEvents = new ArrayDeque<>();
@@ -193,18 +197,6 @@ final class KeyGestureController {
mHandler = new Handler(looper, this::handleMessage);
mIoHandler = new Handler(ioLooper, this::handleIoMessage);
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);
- }
- });
mKeyCombinationManager = new KeyCombinationManager(mHandler);
mSettingsObserver = new SettingsObserver(mHandler);
mAppLaunchShortcutManager = new AppLaunchShortcutManager(mContext);
@@ -450,8 +442,8 @@ final class KeyGestureController {
public void systemRunning() {
mSettingsObserver.observe();
- mAppLaunchShortcutManager.systemRunning();
- mInputGestureManager.systemRunning();
+ mAppLaunchShortcutManager.init();
+ mInputGestureManager.init(mAppLaunchShortcutManager.getBookmarks());
initKeyGestures();
int userId;
@@ -465,22 +457,24 @@ final class KeyGestureController {
@SuppressLint("MissingPermission")
private void initKeyGestures() {
InputManager im = Objects.requireNonNull(mContext.getSystemService(InputManager.class));
- im.registerKeyGestureEventHandler((event, focusedToken) -> {
- switch (event.getKeyGestureType()) {
- case KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT_CHORD:
- if (event.getAction() == KeyGestureEvent.ACTION_GESTURE_START) {
- mHandler.removeMessages(MSG_ACCESSIBILITY_SHORTCUT);
- mHandler.sendMessageDelayed(
- mHandler.obtainMessage(MSG_ACCESSIBILITY_SHORTCUT),
- getAccessibilityShortcutTimeout());
+ im.registerKeyGestureEventHandler(
+ List.of(KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT_CHORD),
+ (event, focusedToken) -> {
+ if (event.getKeyGestureType()
+ == KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT_CHORD) {
+ if (event.getAction() == KeyGestureEvent.ACTION_GESTURE_START) {
+ mHandler.removeMessages(MSG_ACCESSIBILITY_SHORTCUT);
+ mHandler.sendMessageDelayed(
+ mHandler.obtainMessage(MSG_ACCESSIBILITY_SHORTCUT),
+ getAccessibilityShortcutTimeout());
+ } else {
+ mHandler.removeMessages(MSG_ACCESSIBILITY_SHORTCUT);
+ }
} else {
- mHandler.removeMessages(MSG_ACCESSIBILITY_SHORTCUT);
+ Log.w(TAG, "Received a key gesture " + event
+ + " that was not registered by this handler");
}
- return true;
- default:
- return false;
- }
- });
+ });
}
public boolean interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
@@ -590,10 +584,11 @@ final class KeyGestureController {
return true;
}
if (result.appLaunchData() != null) {
- return handleKeyGesture(deviceId, new int[]{keyCode}, metaState,
+ handleKeyGesture(deviceId, new int[]{keyCode}, metaState,
KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION,
- KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
- focusedToken, /* flags = */0, result.appLaunchData());
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId, focusedToken, /* flags = */
+ 0, result.appLaunchData());
+ return true;
}
// Handle system shortcuts
@@ -601,11 +596,11 @@ final class KeyGestureController {
InputGestureData systemShortcut = mInputGestureManager.getSystemShortcutForKeyEvent(
event);
if (systemShortcut != null) {
- return handleKeyGesture(deviceId, new int[]{keyCode}, metaState,
+ handleKeyGesture(deviceId, new int[]{keyCode}, metaState,
systemShortcut.getAction().keyGestureType(),
- KeyGestureEvent.ACTION_GESTURE_COMPLETE,
- displayId, focusedToken, /* flags = */0,
- systemShortcut.getAction().appLaunchData());
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
+ focusedToken, /* flags = */0, systemShortcut.getAction().appLaunchData());
+ return true;
}
}
@@ -687,11 +682,11 @@ final class KeyGestureController {
return true;
case KeyEvent.KEYCODE_SEARCH:
if (firstDown && mSearchKeyBehavior == SEARCH_KEY_BEHAVIOR_TARGET_ACTIVITY) {
- return handleKeyGesture(deviceId, new int[]{keyCode}, /* modifierState = */0,
+ handleKeyGesture(deviceId, new int[]{keyCode}, /* modifierState = */0,
KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_SEARCH,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
focusedToken, /* flags = */0, /* appLaunchData = */null);
-
+ return true;
}
break;
case KeyEvent.KEYCODE_SETTINGS:
@@ -782,11 +777,12 @@ final class KeyGestureController {
if (KeyEvent.metaStateHasModifiers(
shiftlessModifiers, KeyEvent.META_ALT_ON)) {
mPendingHideRecentSwitcher = true;
- return handleKeyGesture(deviceId, new int[]{keyCode},
+ handleKeyGesture(deviceId, new int[]{keyCode},
KeyEvent.META_ALT_ON,
KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS_SWITCHER,
KeyGestureEvent.ACTION_GESTURE_START, displayId,
focusedToken, /* flags = */0, /* appLaunchData = */null);
+ return true;
}
}
}
@@ -803,21 +799,23 @@ final class KeyGestureController {
} else {
if (mPendingHideRecentSwitcher) {
mPendingHideRecentSwitcher = false;
- return handleKeyGesture(deviceId, new int[]{KeyEvent.KEYCODE_TAB},
+ handleKeyGesture(deviceId, new int[]{KeyEvent.KEYCODE_TAB},
KeyEvent.META_ALT_ON,
KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS_SWITCHER,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
focusedToken, /* flags = */0, /* appLaunchData = */null);
+ return true;
}
// Toggle Caps Lock on META-ALT.
if (mPendingCapsLockToggle) {
mPendingCapsLockToggle = false;
- return handleKeyGesture(deviceId, new int[]{KeyEvent.KEYCODE_META_LEFT,
+ handleKeyGesture(deviceId, new int[]{KeyEvent.KEYCODE_META_LEFT,
KeyEvent.KEYCODE_ALT_LEFT}, /* modifierState = */0,
KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
focusedToken, /* flags = */0, /* appLaunchData = */null);
+ return true;
}
}
break;
@@ -885,11 +883,11 @@ final class KeyGestureController {
if (customGesture == null) {
return false;
}
- return handleKeyGesture(deviceId, new int[]{keyCode}, metaState,
+ handleKeyGesture(deviceId, new int[]{keyCode}, metaState,
customGesture.getAction().keyGestureType(),
- KeyGestureEvent.ACTION_GESTURE_COMPLETE,
- displayId, focusedToken, /* flags = */0,
- customGesture.getAction().appLaunchData());
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId, focusedToken,
+ /* flags = */0, customGesture.getAction().appLaunchData());
+ return true;
}
return false;
}
@@ -908,7 +906,7 @@ final class KeyGestureController {
// Handle keyboard layout switching. (CTRL + SPACE)
if (KeyEvent.metaStateHasModifiers(metaState & ~KeyEvent.META_SHIFT_MASK,
KeyEvent.META_CTRL_ON)) {
- return handleKeyGesture(deviceId, new int[]{keyCode},
+ handleKeyGesture(deviceId, new int[]{keyCode},
KeyEvent.META_CTRL_ON | (event.isShiftPressed()
? KeyEvent.META_SHIFT_ON : 0),
KeyGestureEvent.KEY_GESTURE_TYPE_LANGUAGE_SWITCH,
@@ -921,7 +919,7 @@ final class KeyGestureController {
if (down && KeyEvent.metaStateHasModifiers(metaState,
KeyEvent.META_CTRL_ON | KeyEvent.META_ALT_ON)) {
// Intercept the Accessibility keychord (CTRL + ALT + Z) for keyboard users.
- return handleKeyGesture(deviceId, new int[]{keyCode},
+ handleKeyGesture(deviceId, new int[]{keyCode},
KeyEvent.META_CTRL_ON | KeyEvent.META_ALT_ON,
KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
@@ -930,7 +928,7 @@ final class KeyGestureController {
break;
case KeyEvent.KEYCODE_SYSRQ:
if (down && repeatCount == 0) {
- return handleKeyGesture(deviceId, new int[]{keyCode}, /* modifierState = */0,
+ handleKeyGesture(deviceId, new int[]{keyCode}, /* modifierState = */0,
KeyGestureEvent.KEY_GESTURE_TYPE_TAKE_SCREENSHOT,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
focusedToken, /* flags = */0, /* appLaunchData = */null);
@@ -938,7 +936,7 @@ final class KeyGestureController {
break;
case KeyEvent.KEYCODE_ESCAPE:
if (down && KeyEvent.metaStateHasNoModifiers(metaState) && repeatCount == 0) {
- return handleKeyGesture(deviceId, new int[]{keyCode}, /* modifierState = */0,
+ handleKeyGesture(deviceId, new int[]{keyCode}, /* modifierState = */0,
KeyGestureEvent.KEY_GESTURE_TYPE_CLOSE_ALL_DIALOGS,
KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
focusedToken, /* flags = */0, /* appLaunchData = */null);
@@ -964,29 +962,31 @@ final class KeyGestureController {
}
@VisibleForTesting
- boolean handleKeyGesture(int deviceId, int[] keycodes, int modifierState,
+ void handleKeyGesture(int deviceId, int[] keycodes, int modifierState,
@KeyGestureEvent.KeyGestureType int gestureType, int action, int displayId,
@Nullable IBinder focusedToken, int flags, @Nullable AppLaunchData appLaunchData) {
- return handleKeyGesture(createKeyGestureEvent(deviceId, keycodes,
- modifierState, gestureType, action, displayId, flags, appLaunchData), focusedToken);
+ handleKeyGesture(
+ createKeyGestureEvent(deviceId, keycodes, modifierState, gestureType, action,
+ displayId, flags, appLaunchData), focusedToken);
}
- private boolean handleKeyGesture(AidlKeyGestureEvent event, @Nullable IBinder focusedToken) {
+ private void handleKeyGesture(AidlKeyGestureEvent event, @Nullable IBinder focusedToken) {
if (mVisibleBackgroundUsersEnabled && event.displayId != DEFAULT_DISPLAY
&& shouldIgnoreGestureEventForVisibleBackgroundUser(event.gestureType,
event.displayId)) {
- return false;
+ return;
}
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;
- }
+ int index = mSupportedKeyGestureToPidMap.indexOfKey(event.gestureType);
+ if (index < 0) {
+ Log.i(TAG, "Key gesture: " + event.gestureType + " is not supported");
+ return;
}
+ int pid = mSupportedKeyGestureToPidMap.valueAt(index);
+ mKeyGestureHandlerRecords.get(pid).handleKeyGesture(event, focusedToken);
+ Message msg = Message.obtain(mHandler, MSG_NOTIFY_KEY_GESTURE_EVENT, event);
+ mHandler.sendMessage(msg);
}
- return false;
}
private boolean shouldIgnoreGestureEventForVisibleBackgroundUser(
@@ -1285,12 +1285,23 @@ final class KeyGestureController {
/** Register the key gesture event handler for a process. */
@BinderThread
- public void registerKeyGestureHandler(IKeyGestureHandler handler, int pid) {
+ public void registerKeyGestureHandler(int[] keyGesturesToHandle, IKeyGestureHandler handler,
+ int pid) {
synchronized (mKeyGestureHandlerRecords) {
if (mKeyGestureHandlerRecords.get(pid) != null) {
throw new IllegalStateException("The calling process has already registered "
+ "a KeyGestureHandler.");
}
+ if (keyGesturesToHandle.length == 0) {
+ throw new IllegalArgumentException("No key gestures provided for pid = " + pid);
+ }
+ for (int gestureType : keyGesturesToHandle) {
+ if (mSupportedKeyGestureToPidMap.indexOfKey(gestureType) >= 0) {
+ throw new IllegalArgumentException(
+ "Key gesture " + gestureType + " is already registered by pid = "
+ + mSupportedKeyGestureToPidMap.get(gestureType));
+ }
+ }
KeyGestureHandlerRecord record = new KeyGestureHandlerRecord(pid, handler);
try {
handler.asBinder().linkToDeath(record, 0);
@@ -1298,6 +1309,9 @@ final class KeyGestureController {
throw new RuntimeException(ex);
}
mKeyGestureHandlerRecords.put(pid, record);
+ for (int gestureType : keyGesturesToHandle) {
+ mSupportedKeyGestureToPidMap.put(gestureType, pid);
+ }
}
}
@@ -1315,7 +1329,7 @@ final class KeyGestureController {
+ "KeyGestureHandler.");
}
record.mKeyGestureHandler.asBinder().unlinkToDeath(record, 0);
- mKeyGestureHandlerRecords.remove(pid);
+ onKeyGestureHandlerRemoved(pid);
}
}
@@ -1328,9 +1342,14 @@ final class KeyGestureController {
return mAppLaunchShortcutManager.getBookmarks();
}
- private void onKeyGestureHandlerDied(int pid) {
+ private void onKeyGestureHandlerRemoved(int pid) {
synchronized (mKeyGestureHandlerRecords) {
mKeyGestureHandlerRecords.remove(pid);
+ for (int i = mSupportedKeyGestureToPidMap.size() - 1; i >= 0; i--) {
+ if (mSupportedKeyGestureToPidMap.valueAt(i) == pid) {
+ mSupportedKeyGestureToPidMap.removeAt(i);
+ }
+ }
}
}
@@ -1369,18 +1388,17 @@ final class KeyGestureController {
if (DEBUG) {
Slog.d(TAG, "Key gesture event handler for pid " + mPid + " died.");
}
- onKeyGestureHandlerDied(mPid);
+ onKeyGestureHandlerRemoved(mPid);
}
- public boolean handleKeyGesture(AidlKeyGestureEvent event, IBinder focusedToken) {
+ public void handleKeyGesture(AidlKeyGestureEvent event, IBinder focusedToken) {
try {
- return mKeyGestureHandler.handleKeyGesture(event, focusedToken);
+ 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;
}
}
@@ -1479,18 +1497,21 @@ final class KeyGestureController {
}
}
ipw.println("}");
- ipw.print("mKeyGestureHandlerRecords = {");
synchronized (mKeyGestureHandlerRecords) {
- int i = mKeyGestureHandlerRecords.size() - 1;
- for (int processId : mKeyGestureHandlerRecords.keySet()) {
- ipw.print(processId);
- if (i > 0) {
+ ipw.print("mKeyGestureHandlerRecords = {");
+ int size = mKeyGestureHandlerRecords.size();
+ for (int i = 0; i < size; i++) {
+ int pid = mKeyGestureHandlerRecords.keyAt(i);
+ ipw.print(pid);
+ if (i < size - 1) {
ipw.print(", ");
}
- i--;
}
+ ipw.println("}");
+ ipw.println("mSupportedKeyGestures = " + Arrays.toString(
+ mSupportedKeyGestureToPidMap.copyKeys()));
}
- ipw.println("}");
+
ipw.decreaseIndent();
ipw.println("Last handled KeyGestureEvents: ");
ipw.increaseIndent();
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 38d458767015..fcd1452b8702 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -115,7 +115,6 @@ import static com.android.server.wm.WindowManagerPolicyProto.SCREEN_ON_FULLY;
import static com.android.server.wm.WindowManagerPolicyProto.WINDOW_MANAGER_DRAW_COMPLETE;
import android.accessibilityservice.AccessibilityService;
-import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.app.ActivityManager;
@@ -268,6 +267,7 @@ import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
@@ -4240,19 +4240,51 @@ public class PhoneWindowManager implements WindowManagerPolicy {
if (!useKeyGestureEventHandler()) {
return;
}
- mInputManager.registerKeyGestureEventHandler((event, focusedToken) -> {
- boolean handled = PhoneWindowManager.this.handleKeyGestureEvent(event,
- focusedToken);
- if (handled && !event.isCancelled() && Arrays.stream(event.getKeycodes()).anyMatch(
- (keycode) -> keycode == KeyEvent.KEYCODE_POWER)) {
- mPowerKeyHandled = true;
- }
- return handled;
- });
+ List<Integer> supportedGestures = new ArrayList<>(List.of(
+ KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS,
+ KeyGestureEvent.KEY_GESTURE_TYPE_APP_SWITCH,
+ KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_ASSISTANT,
+ KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT,
+ KeyGestureEvent.KEY_GESTURE_TYPE_HOME,
+ KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS,
+ KeyGestureEvent.KEY_GESTURE_TYPE_LOCK_SCREEN,
+ KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL,
+ KeyGestureEvent.KEY_GESTURE_TYPE_TAKE_SCREENSHOT,
+ KeyGestureEvent.KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT,
+ KeyGestureEvent.KEY_GESTURE_TYPE_BACK,
+ KeyGestureEvent.KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION,
+ KeyGestureEvent.KEY_GESTURE_TYPE_DESKTOP_MODE,
+ KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_LEFT,
+ KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_RIGHT,
+ KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER,
+ KeyGestureEvent.KEY_GESTURE_TYPE_BRIGHTNESS_UP,
+ KeyGestureEvent.KEY_GESTURE_TYPE_BRIGHTNESS_DOWN,
+ KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS_SWITCHER,
+ KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS,
+ KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS,
+ KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_SEARCH,
+ KeyGestureEvent.KEY_GESTURE_TYPE_LANGUAGE_SWITCH,
+ KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT,
+ KeyGestureEvent.KEY_GESTURE_TYPE_CLOSE_ALL_DIALOGS,
+ KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION,
+ KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_DO_NOT_DISTURB,
+ KeyGestureEvent.KEY_GESTURE_TYPE_SCREENSHOT_CHORD,
+ KeyGestureEvent.KEY_GESTURE_TYPE_RINGER_TOGGLE_CHORD,
+ KeyGestureEvent.KEY_GESTURE_TYPE_GLOBAL_ACTIONS,
+ KeyGestureEvent.KEY_GESTURE_TYPE_TV_TRIGGER_BUG_REPORT
+ ));
+ if (enableTalkbackAndMagnifierKeyGestures()) {
+ supportedGestures.add(KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_TALKBACK);
+ }
+ if (enableVoiceAccessKeyGestures()) {
+ supportedGestures.add(KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_VOICE_ACCESS);
+ }
+ mInputManager.registerKeyGestureEventHandler(supportedGestures,
+ PhoneWindowManager.this::handleKeyGestureEvent);
}
@VisibleForTesting
- boolean handleKeyGestureEvent(KeyGestureEvent event, IBinder focusedToken) {
+ void handleKeyGestureEvent(KeyGestureEvent event, IBinder focusedToken) {
boolean start = event.getAction() == KeyGestureEvent.ACTION_GESTURE_START;
boolean complete = event.getAction() == KeyGestureEvent.ACTION_GESTURE_COMPLETE
&& !event.isCancelled();
@@ -4262,12 +4294,16 @@ public class PhoneWindowManager implements WindowManagerPolicy {
int modifierState = event.getModifierState();
boolean keyguardOn = keyguardOn();
boolean canLaunchApp = isUserSetupComplete() && !keyguardOn;
+ if (!event.isCancelled() && Arrays.stream(event.getKeycodes()).anyMatch(
+ (keycode) -> keycode == KeyEvent.KEYCODE_POWER)) {
+ mPowerKeyHandled = true;
+ }
switch (gestureType) {
case KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS:
if (complete) {
showRecentApps(false);
}
- return true;
+ break;
case KeyGestureEvent.KEY_GESTURE_TYPE_APP_SWITCH:
if (!keyguardOn) {
if (start) {
@@ -4276,7 +4312,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
toggleRecentApps();
}
}
- return true;
+ break;
case KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_ASSISTANT:
case KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT:
if (complete && canLaunchApp) {
@@ -4284,33 +4320,33 @@ public class PhoneWindowManager implements WindowManagerPolicy {
deviceId, SystemClock.uptimeMillis(),
AssistUtils.INVOCATION_TYPE_UNKNOWN);
}
- return true;
+ break;
case KeyGestureEvent.KEY_GESTURE_TYPE_HOME:
if (complete) {
// Post to main thread to avoid blocking input pipeline.
mHandler.post(() -> handleShortPressOnHome(displayId));
}
- return true;
+ break;
case KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS:
if (complete && canLaunchApp) {
showSystemSettings();
}
- return true;
+ break;
case KeyGestureEvent.KEY_GESTURE_TYPE_LOCK_SCREEN:
if (complete) {
lockNow(null /* options */);
}
- return true;
+ break;
case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL:
if (complete) {
toggleNotificationPanel();
}
- return true;
+ break;
case KeyGestureEvent.KEY_GESTURE_TYPE_TAKE_SCREENSHOT:
if (complete) {
interceptScreenshotChord(SCREENSHOT_KEY_OTHER, 0 /*pressDelay*/);
}
- return true;
+ break;
case KeyGestureEvent.KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT:
if (complete && mEnableBugReportKeyboardShortcut) {
try {
@@ -4321,12 +4357,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
Slog.d(TAG, "Error taking bugreport", e);
}
}
- return true;
+ break;
case KeyGestureEvent.KEY_GESTURE_TYPE_BACK:
if (complete) {
injectBackGesture(SystemClock.uptimeMillis());
}
- return true;
+ break;
case KeyGestureEvent.KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION:
if (complete) {
StatusBarManagerInternal statusbar = getStatusBarManagerInternal();
@@ -4335,7 +4371,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
getTargetDisplayIdForKeyGestureEvent(event));
}
}
- return true;
+ break;
case KeyGestureEvent.KEY_GESTURE_TYPE_DESKTOP_MODE:
if (complete) {
StatusBarManagerInternal statusbar = getStatusBarManagerInternal();
@@ -4344,24 +4380,24 @@ public class PhoneWindowManager implements WindowManagerPolicy {
getTargetDisplayIdForKeyGestureEvent(event));
}
}
- return true;
+ break;
case KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_LEFT:
if (complete) {
moveFocusedTaskToStageSplit(getTargetDisplayIdForKeyGestureEvent(event),
true /* leftOrTop */);
}
- return true;
+ break;
case KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_RIGHT:
if (complete) {
moveFocusedTaskToStageSplit(getTargetDisplayIdForKeyGestureEvent(event),
false /* leftOrTop */);
}
- return true;
+ break;
case KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER:
if (complete) {
toggleKeyboardShortcutsMenu(deviceId);
}
- return true;
+ break;
case KeyGestureEvent.KEY_GESTURE_TYPE_BRIGHTNESS_UP:
case KeyGestureEvent.KEY_GESTURE_TYPE_BRIGHTNESS_DOWN:
if (complete) {
@@ -4369,32 +4405,32 @@ public class PhoneWindowManager implements WindowManagerPolicy {
gestureType == KeyGestureEvent.KEY_GESTURE_TYPE_BRIGHTNESS_UP ? 1 : -1;
changeDisplayBrightnessValue(displayId, direction);
}
- return true;
+ break;
case KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS_SWITCHER:
if (start) {
showRecentApps(true);
} else {
hideRecentApps(true, false);
}
- return true;
+ break;
case KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS:
case KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS:
if (complete && isKeyEventForCurrentUser(event.getDisplayId(),
event.getKeycodes()[0], "launchAllAppsViaA11y")) {
launchAllAppsAction();
}
- return true;
+ break;
case KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_SEARCH:
if (complete && canLaunchApp) {
launchTargetSearchActivity();
}
- return true;
+ break;
case KeyGestureEvent.KEY_GESTURE_TYPE_LANGUAGE_SWITCH:
if (complete) {
int direction = (modifierState & KeyEvent.META_SHIFT_MASK) != 0 ? -1 : 1;
sendSwitchKeyboardLayout(displayId, focusedToken, direction);
}
- return true;
+ break;
case KeyGestureEvent.KEY_GESTURE_TYPE_SCREENSHOT_CHORD:
if (start) {
// Screenshot chord is pressed: Wait for long press delay before taking
@@ -4404,14 +4440,14 @@ public class PhoneWindowManager implements WindowManagerPolicy {
} else {
cancelPendingScreenshotChordAction();
}
- return true;
+ break;
case KeyGestureEvent.KEY_GESTURE_TYPE_RINGER_TOGGLE_CHORD:
if (start) {
interceptRingerToggleChord();
} else {
cancelPendingRingerToggleChordAction();
}
- return true;
+ break;
case KeyGestureEvent.KEY_GESTURE_TYPE_GLOBAL_ACTIONS:
if (start) {
performHapticFeedback(
@@ -4421,40 +4457,34 @@ public class PhoneWindowManager implements WindowManagerPolicy {
} else {
cancelGlobalActionsAction();
}
- return true;
+ break;
case KeyGestureEvent.KEY_GESTURE_TYPE_TV_TRIGGER_BUG_REPORT:
if (start) {
interceptBugreportGestureTv();
} else {
cancelBugreportGestureTv();
}
- return true;
+ break;
case KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT:
if (complete && mAccessibilityShortcutController.isAccessibilityShortcutAvailable(
isKeyguardLocked())) {
mHandler.sendMessage(mHandler.obtainMessage(MSG_ACCESSIBILITY_SHORTCUT));
}
- return true;
+ break;
case KeyGestureEvent.KEY_GESTURE_TYPE_CLOSE_ALL_DIALOGS:
if (complete) {
mContext.closeSystemDialogs();
}
- return true;
+ break;
case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_TALKBACK:
- if (enableTalkbackAndMagnifierKeyGestures()) {
- if (complete) {
- mTalkbackShortcutController.toggleTalkback(mCurrentUserId,
- TalkbackShortcutController.ShortcutSource.KEYBOARD);
- }
- return true;
+ if (complete) {
+ mTalkbackShortcutController.toggleTalkback(mCurrentUserId,
+ TalkbackShortcutController.ShortcutSource.KEYBOARD);
}
break;
case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_VOICE_ACCESS:
- if (enableVoiceAccessKeyGestures()) {
- if (complete) {
- mVoiceAccessShortcutController.toggleVoiceAccess(mCurrentUserId);
- }
- return true;
+ if (complete) {
+ mVoiceAccessShortcutController.toggleVoiceAccess(mCurrentUserId);
}
break;
case KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION:
@@ -4463,7 +4493,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
&& mModifierShortcutManager.launchApplication(data)) {
dismissKeyboardShortcutsMenu();
}
- return true;
+ break;
case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_DO_NOT_DISTURB:
NotificationManager nm = getNotificationService();
if (nm != null) {
@@ -4472,9 +4502,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
: Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, null,
"Key gesture DND", true);
}
- return true;
+ break;
+ default:
+ Log.w(TAG, "Received a key gesture " + event
+ + " that was not registered by this handler");
+ break;
}
- return false;
}
private void changeDisplayBrightnessValue(int displayId, int direction) {
diff --git a/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java b/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java
index fcdf88f16550..0495e967c0e3 100644
--- a/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java
@@ -39,8 +39,6 @@ import androidx.test.filters.MediumTest;
import com.android.hardware.input.Flags;
import com.android.internal.annotations.Keep;
-import junit.framework.Assert;
-
import junitparams.JUnitParamsRunner;
import junitparams.Parameters;
@@ -433,112 +431,94 @@ public class KeyGestureEventTests extends ShortcutKeyTestBase {
@Test
public void testKeyGestureRecentApps() {
- Assert.assertTrue(
- sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS));
+ sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS);
mPhoneWindowManager.assertShowRecentApps();
}
@Test
public void testKeyGestureAppSwitch() {
- Assert.assertTrue(
- sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_APP_SWITCH));
+ sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_APP_SWITCH);
mPhoneWindowManager.assertToggleRecentApps();
}
@Test
public void testKeyGestureLaunchAssistant() {
- Assert.assertTrue(
- sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_ASSISTANT));
+ sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_ASSISTANT);
mPhoneWindowManager.assertSearchManagerLaunchAssist();
}
@Test
public void testKeyGestureLaunchVoiceAssistant() {
- Assert.assertTrue(
- sendKeyGestureEventComplete(
- KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT));
+ sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT);
mPhoneWindowManager.assertSearchManagerLaunchAssist();
}
@Test
public void testKeyGestureGoHome() {
- Assert.assertTrue(
- sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_HOME));
+ sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_HOME);
mPhoneWindowManager.assertGoToHomescreen();
}
@Test
public void testKeyGestureLaunchSystemSettings() {
- Assert.assertTrue(
- sendKeyGestureEventComplete(
- KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS));
+ sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS);
mPhoneWindowManager.assertLaunchSystemSettings();
}
@Test
public void testKeyGestureLock() {
- Assert.assertTrue(
- sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_LOCK_SCREEN));
+ sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_LOCK_SCREEN);
mPhoneWindowManager.assertLockedAfterAppTransitionFinished();
}
@Test
public void testKeyGestureToggleNotificationPanel() throws RemoteException {
- Assert.assertTrue(
- sendKeyGestureEventComplete(
- KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL));
+ sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL);
mPhoneWindowManager.assertTogglePanel();
}
@Test
public void testKeyGestureScreenshot() {
- Assert.assertTrue(
- sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_TAKE_SCREENSHOT));
+ sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_TAKE_SCREENSHOT);
mPhoneWindowManager.assertTakeScreenshotCalled();
}
@Test
public void testKeyGestureTriggerBugReport() throws RemoteException {
- Assert.assertTrue(
- sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT));
+ sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT);
mPhoneWindowManager.assertTakeBugreport(true);
}
@Test
public void testKeyGestureBack() {
- Assert.assertTrue(sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_BACK));
+ sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_BACK);
mPhoneWindowManager.assertBackEventInjected();
}
@Test
public void testKeyGestureMultiWindowNavigation() {
- Assert.assertTrue(sendKeyGestureEventComplete(
- KeyGestureEvent.KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION));
+ sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION);
mPhoneWindowManager.assertMoveFocusedTaskToFullscreen();
}
@Test
public void testKeyGestureDesktopMode() {
- Assert.assertTrue(
- sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_DESKTOP_MODE));
+ sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_DESKTOP_MODE);
mPhoneWindowManager.assertMoveFocusedTaskToDesktop();
}
@Test
public void testKeyGestureSplitscreenNavigation() {
- Assert.assertTrue(sendKeyGestureEventComplete(
- KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_LEFT));
+ sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_LEFT);
mPhoneWindowManager.assertMoveFocusedTaskToStageSplit(true);
- Assert.assertTrue(sendKeyGestureEventComplete(
- KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_RIGHT));
+ sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_RIGHT);
mPhoneWindowManager.assertMoveFocusedTaskToStageSplit(false);
}
@Test
public void testKeyGestureShortcutHelper() {
- Assert.assertTrue(sendKeyGestureEventComplete(
- KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER));
+ sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER);
mPhoneWindowManager.assertToggleShortcutsMenu();
}
@@ -549,173 +529,139 @@ public class KeyGestureEventTests extends ShortcutKeyTestBase {
for (int i = 0; i < currentBrightness.length; i++) {
mPhoneWindowManager.prepareBrightnessDecrease(currentBrightness[i]);
- Assert.assertTrue(
- sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_BRIGHTNESS_DOWN));
+ sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_BRIGHTNESS_DOWN);
mPhoneWindowManager.verifyNewBrightness(newBrightness[i]);
}
}
@Test
public void testKeyGestureRecentAppSwitcher() {
- Assert.assertTrue(sendKeyGestureEventStart(
- KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS_SWITCHER));
+ sendKeyGestureEventStart(KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS_SWITCHER);
mPhoneWindowManager.assertShowRecentApps();
-
- Assert.assertTrue(sendKeyGestureEventComplete(
- KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS_SWITCHER));
+ sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS_SWITCHER);
mPhoneWindowManager.assertHideRecentApps();
}
@Test
public void testKeyGestureLanguageSwitch() {
- Assert.assertTrue(
- sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_LANGUAGE_SWITCH));
+ sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_LANGUAGE_SWITCH);
mPhoneWindowManager.assertSwitchKeyboardLayout(1, DEFAULT_DISPLAY);
- Assert.assertTrue(
- sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_LANGUAGE_SWITCH,
- KeyEvent.META_SHIFT_ON));
+ sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_LANGUAGE_SWITCH,
+ KeyEvent.META_SHIFT_ON);
mPhoneWindowManager.assertSwitchKeyboardLayout(-1, DEFAULT_DISPLAY);
}
@Test
public void testKeyGestureLaunchSearch() {
- Assert.assertTrue(
- sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_SEARCH));
+ sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_SEARCH);
mPhoneWindowManager.assertLaunchSearch();
}
@Test
public void testKeyGestureScreenshotChord() {
- Assert.assertTrue(
- sendKeyGestureEventStart(KeyGestureEvent.KEY_GESTURE_TYPE_SCREENSHOT_CHORD));
+ sendKeyGestureEventStart(KeyGestureEvent.KEY_GESTURE_TYPE_SCREENSHOT_CHORD);
mPhoneWindowManager.moveTimeForward(500);
- Assert.assertTrue(
- sendKeyGestureEventCancel(KeyGestureEvent.KEY_GESTURE_TYPE_SCREENSHOT_CHORD));
+ sendKeyGestureEventCancel(KeyGestureEvent.KEY_GESTURE_TYPE_SCREENSHOT_CHORD);
mPhoneWindowManager.assertTakeScreenshotCalled();
}
@Test
public void testKeyGestureScreenshotChordCancelled() {
- Assert.assertTrue(
- sendKeyGestureEventStart(KeyGestureEvent.KEY_GESTURE_TYPE_SCREENSHOT_CHORD));
- Assert.assertTrue(
- sendKeyGestureEventCancel(KeyGestureEvent.KEY_GESTURE_TYPE_SCREENSHOT_CHORD));
+ sendKeyGestureEventStart(KeyGestureEvent.KEY_GESTURE_TYPE_SCREENSHOT_CHORD);
+ sendKeyGestureEventCancel(KeyGestureEvent.KEY_GESTURE_TYPE_SCREENSHOT_CHORD);
mPhoneWindowManager.assertTakeScreenshotNotCalled();
}
@Test
public void testKeyGestureRingerToggleChord() {
mPhoneWindowManager.overridePowerVolumeUp(POWER_VOLUME_UP_BEHAVIOR_MUTE);
- Assert.assertTrue(
- sendKeyGestureEventStart(KeyGestureEvent.KEY_GESTURE_TYPE_RINGER_TOGGLE_CHORD));
+ sendKeyGestureEventStart(KeyGestureEvent.KEY_GESTURE_TYPE_RINGER_TOGGLE_CHORD);
mPhoneWindowManager.moveTimeForward(500);
- Assert.assertTrue(
- sendKeyGestureEventCancel(KeyGestureEvent.KEY_GESTURE_TYPE_RINGER_TOGGLE_CHORD));
+ sendKeyGestureEventCancel(KeyGestureEvent.KEY_GESTURE_TYPE_RINGER_TOGGLE_CHORD);
mPhoneWindowManager.assertVolumeMute();
}
@Test
public void testKeyGestureRingerToggleChordCancelled() {
mPhoneWindowManager.overridePowerVolumeUp(POWER_VOLUME_UP_BEHAVIOR_MUTE);
- Assert.assertTrue(
- sendKeyGestureEventStart(KeyGestureEvent.KEY_GESTURE_TYPE_RINGER_TOGGLE_CHORD));
- Assert.assertTrue(
- sendKeyGestureEventCancel(KeyGestureEvent.KEY_GESTURE_TYPE_RINGER_TOGGLE_CHORD));
+ sendKeyGestureEventStart(KeyGestureEvent.KEY_GESTURE_TYPE_RINGER_TOGGLE_CHORD);
+ sendKeyGestureEventCancel(KeyGestureEvent.KEY_GESTURE_TYPE_RINGER_TOGGLE_CHORD);
mPhoneWindowManager.assertVolumeNotMuted();
}
@Test
public void testKeyGestureGlobalAction() {
mPhoneWindowManager.overridePowerVolumeUp(POWER_VOLUME_UP_BEHAVIOR_GLOBAL_ACTIONS);
- Assert.assertTrue(
- sendKeyGestureEventStart(KeyGestureEvent.KEY_GESTURE_TYPE_GLOBAL_ACTIONS));
+ sendKeyGestureEventStart(KeyGestureEvent.KEY_GESTURE_TYPE_GLOBAL_ACTIONS);
mPhoneWindowManager.moveTimeForward(500);
- Assert.assertTrue(
- sendKeyGestureEventCancel(KeyGestureEvent.KEY_GESTURE_TYPE_GLOBAL_ACTIONS));
+ sendKeyGestureEventCancel(KeyGestureEvent.KEY_GESTURE_TYPE_GLOBAL_ACTIONS);
mPhoneWindowManager.assertShowGlobalActionsCalled();
}
@Test
public void testKeyGestureGlobalActionCancelled() {
mPhoneWindowManager.overridePowerVolumeUp(POWER_VOLUME_UP_BEHAVIOR_GLOBAL_ACTIONS);
- Assert.assertTrue(
- sendKeyGestureEventStart(KeyGestureEvent.KEY_GESTURE_TYPE_GLOBAL_ACTIONS));
- Assert.assertTrue(
- sendKeyGestureEventCancel(KeyGestureEvent.KEY_GESTURE_TYPE_GLOBAL_ACTIONS));
+ sendKeyGestureEventStart(KeyGestureEvent.KEY_GESTURE_TYPE_GLOBAL_ACTIONS);
+ sendKeyGestureEventCancel(KeyGestureEvent.KEY_GESTURE_TYPE_GLOBAL_ACTIONS);
mPhoneWindowManager.assertShowGlobalActionsNotCalled();
}
@Test
public void testKeyGestureTvTriggerBugReport() {
- Assert.assertTrue(
- sendKeyGestureEventStart(KeyGestureEvent.KEY_GESTURE_TYPE_TV_TRIGGER_BUG_REPORT));
+ sendKeyGestureEventStart(KeyGestureEvent.KEY_GESTURE_TYPE_TV_TRIGGER_BUG_REPORT);
mPhoneWindowManager.moveTimeForward(1000);
- Assert.assertTrue(
- sendKeyGestureEventCancel(KeyGestureEvent.KEY_GESTURE_TYPE_TV_TRIGGER_BUG_REPORT));
+ sendKeyGestureEventCancel(KeyGestureEvent.KEY_GESTURE_TYPE_TV_TRIGGER_BUG_REPORT);
mPhoneWindowManager.assertBugReportTakenForTv();
}
@Test
public void testKeyGestureTvTriggerBugReportCancelled() {
- Assert.assertTrue(
- sendKeyGestureEventStart(KeyGestureEvent.KEY_GESTURE_TYPE_TV_TRIGGER_BUG_REPORT));
- Assert.assertTrue(
- sendKeyGestureEventCancel(KeyGestureEvent.KEY_GESTURE_TYPE_TV_TRIGGER_BUG_REPORT));
+ sendKeyGestureEventStart(KeyGestureEvent.KEY_GESTURE_TYPE_TV_TRIGGER_BUG_REPORT);
+ sendKeyGestureEventCancel(KeyGestureEvent.KEY_GESTURE_TYPE_TV_TRIGGER_BUG_REPORT);
mPhoneWindowManager.assertBugReportNotTakenForTv();
}
@Test
public void testKeyGestureAccessibilityShortcut() {
- Assert.assertTrue(
- sendKeyGestureEventComplete(
- KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT));
+ sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT);
mPhoneWindowManager.assertAccessibilityKeychordCalled();
}
@Test
public void testKeyGestureCloseAllDialogs() {
- Assert.assertTrue(
- sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_CLOSE_ALL_DIALOGS));
+ sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_CLOSE_ALL_DIALOGS);
mPhoneWindowManager.assertCloseAllDialogs();
}
@Test
@EnableFlags(com.android.hardware.input.Flags.FLAG_ENABLE_TALKBACK_AND_MAGNIFIER_KEY_GESTURES)
public void testKeyGestureToggleTalkback() {
- Assert.assertTrue(
- sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_TALKBACK));
+ sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_TALKBACK);
mPhoneWindowManager.assertTalkBack(true);
- Assert.assertTrue(
- sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_TALKBACK));
+ sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_TALKBACK);
mPhoneWindowManager.assertTalkBack(false);
}
@Test
@EnableFlags(com.android.hardware.input.Flags.FLAG_ENABLE_VOICE_ACCESS_KEY_GESTURES)
public void testKeyGestureToggleVoiceAccess() {
- Assert.assertTrue(
- sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_VOICE_ACCESS));
+ sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_VOICE_ACCESS);
mPhoneWindowManager.assertVoiceAccess(true);
- Assert.assertTrue(
- sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_VOICE_ACCESS));
+ sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_VOICE_ACCESS);
mPhoneWindowManager.assertVoiceAccess(false);
}
@Test
public void testKeyGestureToggleDoNotDisturb() {
mPhoneWindowManager.overrideZenMode(Settings.Global.ZEN_MODE_OFF);
- Assert.assertTrue(
- sendKeyGestureEventComplete(
- KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_DO_NOT_DISTURB));
+ sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_DO_NOT_DISTURB);
mPhoneWindowManager.assertZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
mPhoneWindowManager.overrideZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
- Assert.assertTrue(
- sendKeyGestureEventComplete(
- KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_DO_NOT_DISTURB));
+ sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_DO_NOT_DISTURB);
mPhoneWindowManager.assertZenMode(Settings.Global.ZEN_MODE_OFF);
}
diff --git a/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java b/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java
index 32a3b7f2c9cc..68229688c238 100644
--- a/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java
@@ -43,6 +43,7 @@ import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
@@ -146,7 +147,7 @@ public class PhoneWindowManagerTests {
mPhoneWindowManager.mKeyguardDelegate = mKeyguardServiceDelegate;
final InputManager im = mock(InputManager.class);
- doNothing().when(im).registerKeyGestureEventHandler(any());
+ doNothing().when(im).registerKeyGestureEventHandler(anyList(), any());
doReturn(im).when(mContext).getSystemService(eq(Context.INPUT_SERVICE));
}
diff --git a/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java b/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java
index c57adfd69b06..f89c6f638384 100644
--- a/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java
+++ b/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java
@@ -238,33 +238,33 @@ class ShortcutKeyTestBase {
sendKeyCombination(new int[]{keyCode}, durationMillis, false, DEFAULT_DISPLAY);
}
- boolean sendKeyGestureEventStart(int gestureType) {
- return mPhoneWindowManager.sendKeyGestureEvent(
+ void sendKeyGestureEventStart(int gestureType) {
+ mPhoneWindowManager.sendKeyGestureEvent(
new KeyGestureEvent.Builder().setKeyGestureType(gestureType).setAction(
KeyGestureEvent.ACTION_GESTURE_START).build());
}
- boolean sendKeyGestureEventComplete(int gestureType) {
- return mPhoneWindowManager.sendKeyGestureEvent(
+ void sendKeyGestureEventComplete(int gestureType) {
+ mPhoneWindowManager.sendKeyGestureEvent(
new KeyGestureEvent.Builder().setKeyGestureType(gestureType).setAction(
KeyGestureEvent.ACTION_GESTURE_COMPLETE).build());
}
- boolean sendKeyGestureEventCancel(int gestureType) {
- return mPhoneWindowManager.sendKeyGestureEvent(
+ void sendKeyGestureEventCancel(int gestureType) {
+ mPhoneWindowManager.sendKeyGestureEvent(
new KeyGestureEvent.Builder().setKeyGestureType(gestureType).setAction(
KeyGestureEvent.ACTION_GESTURE_COMPLETE).setFlags(
KeyGestureEvent.FLAG_CANCELLED).build());
}
- boolean sendKeyGestureEventComplete(int gestureType, int modifierState) {
- return mPhoneWindowManager.sendKeyGestureEvent(
+ void sendKeyGestureEventComplete(int gestureType, int modifierState) {
+ mPhoneWindowManager.sendKeyGestureEvent(
new KeyGestureEvent.Builder().setModifierState(modifierState).setKeyGestureType(
gestureType).setAction(KeyGestureEvent.ACTION_GESTURE_COMPLETE).build());
}
- boolean sendKeyGestureEventComplete(int keycode, int modifierState, int gestureType) {
- return mPhoneWindowManager.sendKeyGestureEvent(
+ void sendKeyGestureEventComplete(int keycode, int modifierState, int gestureType) {
+ mPhoneWindowManager.sendKeyGestureEvent(
new KeyGestureEvent.Builder().setKeycodes(new int[]{keycode}).setModifierState(
modifierState).setKeyGestureType(gestureType).setAction(
KeyGestureEvent.ACTION_GESTURE_COMPLETE).build());
diff --git a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
index e56fd3c6272d..7b6d361c55d4 100644
--- a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
+++ b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
@@ -49,6 +49,7 @@ import static com.android.server.policy.PhoneWindowManager.POWER_VOLUME_UP_BEHAV
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.CALLS_REAL_METHODS;
import static org.mockito.Mockito.after;
@@ -353,7 +354,7 @@ class TestPhoneWindowManager {
doReturn(mAppOpsManager).when(mContext).getSystemService(eq(AppOpsManager.class));
doReturn(mDisplayManager).when(mContext).getSystemService(eq(DisplayManager.class));
doReturn(mInputManager).when(mContext).getSystemService(eq(InputManager.class));
- doNothing().when(mInputManager).registerKeyGestureEventHandler(any());
+ doNothing().when(mInputManager).registerKeyGestureEventHandler(anyList(), any());
doNothing().when(mInputManager).unregisterKeyGestureEventHandler(any());
doReturn(mPackageManager).when(mContext).getPackageManager();
doReturn(mSensorPrivacyManager).when(mContext).getSystemService(
@@ -476,8 +477,8 @@ class TestPhoneWindowManager {
mPhoneWindowManager.interceptUnhandledKey(event, mInputToken);
}
- boolean sendKeyGestureEvent(KeyGestureEvent event) {
- return mPhoneWindowManager.handleKeyGestureEvent(event, mInputToken);
+ void sendKeyGestureEvent(KeyGestureEvent event) {
+ mPhoneWindowManager.handleKeyGestureEvent(event, mInputToken);
}
/**
diff --git a/tests/Input/src/android/hardware/input/KeyGestureEventHandlerTest.kt b/tests/Input/src/android/hardware/input/KeyGestureEventHandlerTest.kt
index 794fd0255726..c62bd0b72584 100644
--- a/tests/Input/src/android/hardware/input/KeyGestureEventHandlerTest.kt
+++ b/tests/Input/src/android/hardware/input/KeyGestureEventHandlerTest.kt
@@ -18,12 +18,10 @@ package android.hardware.input
import android.content.Context
import android.content.ContextWrapper
-import android.os.IBinder
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 com.android.test.input.MockInputManagerRule
import org.junit.Before
import org.junit.Rule
@@ -37,6 +35,7 @@ import kotlin.test.assertEquals
import kotlin.test.assertNotNull
import kotlin.test.assertNull
import kotlin.test.fail
+import org.junit.Assert.assertThrows
/**
* Tests for [InputManager.KeyGestureEventHandler].
@@ -82,7 +81,7 @@ class KeyGestureEventHandlerTest {
// Handle key gesture handler registration.
doAnswer {
- val listener = it.getArgument(0) as IKeyGestureHandler
+ val listener = it.getArgument(1) as IKeyGestureHandler
if (registeredListener != null &&
registeredListener!!.asBinder() != listener.asBinder()) {
// There can only be one registered key gesture handler per process.
@@ -90,7 +89,7 @@ class KeyGestureEventHandlerTest {
}
registeredListener = listener
null
- }.`when`(inputManagerRule.mock).registerKeyGestureHandler(any())
+ }.`when`(inputManagerRule.mock).registerKeyGestureHandler(Mockito.any(), Mockito.any())
// Handle key gesture handler being unregistered.
doAnswer {
@@ -101,7 +100,7 @@ class KeyGestureEventHandlerTest {
}
registeredListener = null
null
- }.`when`(inputManagerRule.mock).unregisterKeyGestureHandler(any())
+ }.`when`(inputManagerRule.mock).unregisterKeyGestureHandler(Mockito.any())
}
private fun handleKeyGestureEvent(event: KeyGestureEvent) {
@@ -121,11 +120,12 @@ class KeyGestureEventHandlerTest {
var callbackCount = 0
// Add a key gesture event listener
- inputManager.registerKeyGestureEventHandler(KeyGestureHandler { event, _ ->
+ inputManager.registerKeyGestureEventHandler(
+ listOf(KeyGestureEvent.KEY_GESTURE_TYPE_HOME)
+ ) { event, _ ->
assertEquals(HOME_GESTURE_EVENT, event)
callbackCount++
- true
- })
+ }
// Request handling for key gesture event will notify the handler.
handleKeyGestureEvent(HOME_GESTURE_EVENT)
@@ -135,29 +135,41 @@ class KeyGestureEventHandlerTest {
@Test
fun testAddingHandlersRegistersInternalCallbackHandler() {
// Set up two callbacks.
- val callback1 = KeyGestureHandler { _, _ -> false }
- val callback2 = KeyGestureHandler { _, _ -> false }
+ val callback1 = InputManager.KeyGestureEventHandler { _, _ -> }
+ val callback2 = InputManager.KeyGestureEventHandler { _, _ -> }
assertNull(registeredListener)
// Adding the handler should register the callback with InputManagerService.
- inputManager.registerKeyGestureEventHandler(callback1)
+ inputManager.registerKeyGestureEventHandler(
+ listOf(KeyGestureEvent.KEY_GESTURE_TYPE_HOME),
+ callback1
+ )
assertNotNull(registeredListener)
// Adding another handler should not register new internal listener.
val currListener = registeredListener
- inputManager.registerKeyGestureEventHandler(callback2)
+ inputManager.registerKeyGestureEventHandler(
+ listOf(KeyGestureEvent.KEY_GESTURE_TYPE_BACK),
+ callback2
+ )
assertEquals(currListener, registeredListener)
}
@Test
fun testRemovingHandlersUnregistersInternalCallbackHandler() {
// Set up two callbacks.
- val callback1 = KeyGestureHandler { _, _ -> false }
- val callback2 = KeyGestureHandler { _, _ -> false }
+ val callback1 = InputManager.KeyGestureEventHandler { _, _ -> }
+ val callback2 = InputManager.KeyGestureEventHandler { _, _ -> }
- inputManager.registerKeyGestureEventHandler(callback1)
- inputManager.registerKeyGestureEventHandler(callback2)
+ inputManager.registerKeyGestureEventHandler(
+ listOf(KeyGestureEvent.KEY_GESTURE_TYPE_HOME),
+ callback1
+ )
+ inputManager.registerKeyGestureEventHandler(
+ listOf(KeyGestureEvent.KEY_GESTURE_TYPE_BACK),
+ callback2
+ )
// Only removing all handlers should remove the internal callback
inputManager.unregisterKeyGestureEventHandler(callback1)
@@ -172,47 +184,74 @@ class KeyGestureEventHandlerTest {
var callbackCount1 = 0
var callbackCount2 = 0
// Handler 1 captures all home gestures
- val callback1 = KeyGestureHandler { event, _ ->
+ val callback1 = InputManager.KeyGestureEventHandler { event, _ ->
callbackCount1++
- event.keyGestureType == KeyGestureEvent.KEY_GESTURE_TYPE_HOME
+ assertEquals(KeyGestureEvent.KEY_GESTURE_TYPE_HOME, event.keyGestureType)
}
- // Handler 2 captures all gestures
- val callback2 = KeyGestureHandler { _, _ ->
+ // Handler 2 captures all back gestures
+ val callback2 = InputManager.KeyGestureEventHandler { event, _ ->
callbackCount2++
- true
+ assertEquals(KeyGestureEvent.KEY_GESTURE_TYPE_BACK, event.keyGestureType)
}
// Add both key gesture event handlers
- inputManager.registerKeyGestureEventHandler(callback1)
- inputManager.registerKeyGestureEventHandler(callback2)
+ inputManager.registerKeyGestureEventHandler(
+ listOf(KeyGestureEvent.KEY_GESTURE_TYPE_HOME),
+ callback1
+ )
+ inputManager.registerKeyGestureEventHandler(
+ listOf(KeyGestureEvent.KEY_GESTURE_TYPE_BACK),
+ 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.
+ // Request handling for home key gesture event, should notify only callback1
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
+ // Request handling for back key gesture event, should notify only callback2
handleKeyGestureEvent(BACK_GESTURE_EVENT)
- assertEquals(2, callbackCount1)
+ assertEquals(1, callbackCount1)
assertEquals(1, callbackCount2)
inputManager.unregisterKeyGestureEventHandler(callback1)
- // Request handling for key gesture event, should still trigger callback2 but not callback1.
+
+ // Request handling for home key gesture event, should not trigger callback2
handleKeyGestureEvent(HOME_GESTURE_EVENT)
- assertEquals(2, callbackCount1)
- assertEquals(2, callbackCount2)
+ assertEquals(1, callbackCount1)
+ assertEquals(1, callbackCount2)
+ }
+
+ @Test
+ fun testUnableToRegisterSameHandlerTwice() {
+ val handler = InputManager.KeyGestureEventHandler { _, _ -> }
+
+ inputManager.registerKeyGestureEventHandler(
+ listOf(KeyGestureEvent.KEY_GESTURE_TYPE_HOME),
+ handler
+ )
+
+ assertThrows(IllegalArgumentException::class.java) {
+ inputManager.registerKeyGestureEventHandler(
+ listOf(KeyGestureEvent.KEY_GESTURE_TYPE_BACK), handler
+ )
+ }
}
- inner class KeyGestureHandler(
- private var handler: (event: KeyGestureEvent, token: IBinder?) -> Boolean
- ) : InputManager.KeyGestureEventHandler {
+ @Test
+ fun testUnableToRegisterSameGestureTwice() {
+ val handler1 = InputManager.KeyGestureEventHandler { _, _ -> }
+ val handler2 = InputManager.KeyGestureEventHandler { _, _ -> }
+
+ inputManager.registerKeyGestureEventHandler(
+ listOf(KeyGestureEvent.KEY_GESTURE_TYPE_HOME),
+ handler1
+ )
- override fun handleKeyGestureEvent(
- event: KeyGestureEvent,
- focusedToken: IBinder?
- ): Boolean {
- return handler(event, focusedToken)
+ assertThrows(IllegalArgumentException::class.java) {
+ inputManager.registerKeyGestureEventHandler(
+ listOf(KeyGestureEvent.KEY_GESTURE_TYPE_HOME), handler2
+ )
}
}
}
diff --git a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
index 4f1fb6487b19..163dda84a71c 100644
--- a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
+++ b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
@@ -63,6 +63,7 @@ import org.junit.After
import org.junit.Assert.assertArrayEquals
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull
+import org.junit.Assert.assertThrows
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Rule
@@ -107,7 +108,10 @@ class KeyGestureControllerTests {
const val SETTINGS_KEY_BEHAVIOR_SETTINGS_ACTIVITY = 0
const val SETTINGS_KEY_BEHAVIOR_NOTIFICATION_PANEL = 1
const val SETTINGS_KEY_BEHAVIOR_NOTHING = 2
+ const val SYSTEM_PID = 0
const val TEST_PID = 10
+ const val RANDOM_PID1 = 11
+ const val RANDOM_PID2 = 12
}
@JvmField
@@ -170,6 +174,7 @@ class KeyGestureControllerTests {
return atomicFile
}
})
+ startNewInputGlobalTestSession()
}
@After
@@ -199,17 +204,22 @@ class KeyGestureControllerTests {
val correctIm = context.getSystemService(InputManager::class.java)!!
val virtualDevice = correctIm.getInputDevice(KeyCharacterMap.VIRTUAL_KEYBOARD)!!
val kcm = virtualDevice.keyCharacterMap!!
- inputManagerGlobalSession = InputManagerGlobal.createTestSession(iInputManager)
- 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)
ExtendedMockito.`when`(KeyCharacterMap.load(Mockito.anyInt())).thenReturn(kcm)
}
+ private fun startNewInputGlobalTestSession() {
+ if (this::inputManagerGlobalSession.isInitialized) {
+ inputManagerGlobalSession.close()
+ }
+ inputManagerGlobalSession = InputManagerGlobal.createTestSession(iInputManager)
+ val inputManager = InputManager(context)
+ Mockito.`when`(context.getSystemService(Mockito.eq(Context.INPUT_SERVICE)))
+ .thenReturn(inputManager)
+ }
+
private fun setupKeyGestureController() {
keyGestureController =
KeyGestureController(
@@ -225,13 +235,14 @@ class KeyGestureControllerTests {
return accessibilityShortcutController
}
})
- Mockito.`when`(iInputManager.registerKeyGestureHandler(Mockito.any()))
+ Mockito.`when`(iInputManager.registerKeyGestureHandler(Mockito.any(), Mockito.any()))
.thenAnswer {
val args = it.arguments
if (args[0] != null) {
keyGestureController.registerKeyGestureHandler(
- args[0] as IKeyGestureHandler,
- TEST_PID
+ args[0] as IntArray,
+ args[1] as IKeyGestureHandler,
+ SYSTEM_PID
)
}
}
@@ -285,59 +296,6 @@ class KeyGestureControllerTests {
)
}
- @Test
- fun testKeyGestureEvent_multipleGestureHandlers() {
- setupKeyGestureController()
-
- // 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, /* appLaunchData = */null
- )
-
- 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
- )
- }
-
class TestData(
val name: String,
val keys: IntArray,
@@ -789,10 +747,6 @@ class KeyGestureControllerTests {
)
fun testCustomKeyGesturesNotAllowedForSystemGestures(test: TestData) {
setupKeyGestureController()
- // Need to re-init so that bookmarks are correctly blocklisted
- Mockito.`when`(iInputManager.getAppLaunchBookmarks())
- .thenReturn(keyGestureController.appLaunchBookmarks)
- keyGestureController.systemRunning()
val builder = InputGestureData.Builder()
.setKeyGestureType(test.expectedKeyGestureType)
@@ -1163,9 +1117,6 @@ class KeyGestureControllerTests {
KeyEvent.KEYCODE_FULLSCREEN
)
- val handler = KeyGestureHandler { _, _ -> false }
- keyGestureController.registerKeyGestureHandler(handler, 0)
-
for (key in testKeys) {
sendKeys(intArrayOf(key), assertNotSentToApps = true)
}
@@ -1179,6 +1130,7 @@ class KeyGestureControllerTests {
testKeyGestureNotProduced(
"SEARCH -> Default Search",
intArrayOf(KeyEvent.KEYCODE_SEARCH),
+ intArrayOf(KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_SEARCH)
)
}
@@ -1207,6 +1159,10 @@ class KeyGestureControllerTests {
testKeyGestureNotProduced(
"SETTINGS -> Do Nothing",
intArrayOf(KeyEvent.KEYCODE_SETTINGS),
+ intArrayOf(
+ KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_SEARCH,
+ KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL
+ )
)
}
@@ -1290,28 +1246,6 @@ class KeyGestureControllerTests {
)
),
TestData(
- "VOLUME_DOWN + VOLUME_UP -> Accessibility Chord",
- intArrayOf(KeyEvent.KEYCODE_VOLUME_DOWN, KeyEvent.KEYCODE_VOLUME_UP),
- KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT_CHORD,
- intArrayOf(KeyEvent.KEYCODE_VOLUME_DOWN, KeyEvent.KEYCODE_VOLUME_UP),
- 0,
- intArrayOf(
- KeyGestureEvent.ACTION_GESTURE_START,
- KeyGestureEvent.ACTION_GESTURE_COMPLETE
- )
- ),
- TestData(
- "BACK + DPAD_DOWN -> Accessibility Chord(for TV)",
- intArrayOf(KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_DPAD_DOWN),
- KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_SHORTCUT_CHORD,
- intArrayOf(KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_DPAD_DOWN),
- 0,
- intArrayOf(
- KeyGestureEvent.ACTION_GESTURE_START,
- KeyGestureEvent.ACTION_GESTURE_COMPLETE
- )
- ),
- TestData(
"BACK + DPAD_CENTER -> TV Trigger Bug Report",
intArrayOf(KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_DPAD_CENTER),
KeyGestureEvent.KEY_GESTURE_TYPE_TV_TRIGGER_BUG_REPORT,
@@ -1428,9 +1362,11 @@ class KeyGestureControllerTests {
testLooper.dispatchAll()
// Reinitialize the gesture controller simulating a login/logout for the user.
+ startNewInputGlobalTestSession()
setupKeyGestureController()
keyGestureController.setCurrentUserId(userId)
testLooper.dispatchAll()
+
val savedInputGestures = keyGestureController.getCustomInputGestures(userId, null)
assertEquals(
"Test: $test doesn't produce correct number of saved input gestures",
@@ -1469,6 +1405,7 @@ class KeyGestureControllerTests {
// Delete the old data and reinitialize the controller simulating a "fresh" install.
tempFile.delete()
+ startNewInputGlobalTestSession()
setupKeyGestureController()
keyGestureController.setCurrentUserId(userId)
testLooper.dispatchAll()
@@ -1541,9 +1478,12 @@ class KeyGestureControllerTests {
val handledEvents = mutableListOf<KeyGestureEvent>()
val handler = KeyGestureHandler { event, _ ->
handledEvents.add(KeyGestureEvent(event))
- true
}
- keyGestureController.registerKeyGestureHandler(handler, 0)
+ keyGestureController.registerKeyGestureHandler(
+ intArrayOf(test.expectedKeyGestureType),
+ handler,
+ TEST_PID
+ )
handledEvents.clear()
keyGestureController.handleTouchpadGesture(test.touchpadGestureType)
@@ -1570,7 +1510,7 @@ class KeyGestureControllerTests {
event.appLaunchData
)
- keyGestureController.unregisterKeyGestureHandler(handler, 0)
+ keyGestureController.unregisterKeyGestureHandler(handler, TEST_PID)
}
@Test
@@ -1591,9 +1531,11 @@ class KeyGestureControllerTests {
testLooper.dispatchAll()
// Reinitialize the gesture controller simulating a login/logout for the user.
+ startNewInputGlobalTestSession()
setupKeyGestureController()
keyGestureController.setCurrentUserId(userId)
testLooper.dispatchAll()
+
val savedInputGestures = keyGestureController.getCustomInputGestures(userId, null)
assertEquals(
"Test: $test doesn't produce correct number of saved input gestures",
@@ -1627,6 +1569,7 @@ class KeyGestureControllerTests {
// Delete the old data and reinitialize the controller simulating a "fresh" install.
tempFile.delete()
+ startNewInputGlobalTestSession()
setupKeyGestureController()
keyGestureController.setCurrentUserId(userId)
testLooper.dispatchAll()
@@ -1699,13 +1642,97 @@ class KeyGestureControllerTests {
Mockito.verify(accessibilityShortcutController, never()).performAccessibilityShortcut()
}
+ @Test
+ fun testUnableToRegisterFromSamePidTwice() {
+ setupKeyGestureController()
+
+ val handler1 = KeyGestureHandler { _, _ -> }
+ val handler2 = KeyGestureHandler { _, _ -> }
+ keyGestureController.registerKeyGestureHandler(
+ intArrayOf(KeyGestureEvent.KEY_GESTURE_TYPE_HOME),
+ handler1,
+ RANDOM_PID1
+ )
+
+ assertThrows(IllegalStateException::class.java) {
+ keyGestureController.registerKeyGestureHandler(
+ intArrayOf(KeyGestureEvent.KEY_GESTURE_TYPE_BACK),
+ handler2,
+ RANDOM_PID1
+ )
+ }
+ }
+
+ @Test
+ fun testUnableToRegisterSameGestureTwice() {
+ setupKeyGestureController()
+
+ val handler1 = KeyGestureHandler { _, _ -> }
+ val handler2 = KeyGestureHandler { _, _ -> }
+ keyGestureController.registerKeyGestureHandler(
+ intArrayOf(KeyGestureEvent.KEY_GESTURE_TYPE_HOME),
+ handler1,
+ RANDOM_PID1
+ )
+
+ assertThrows(IllegalArgumentException::class.java) {
+ keyGestureController.registerKeyGestureHandler(
+ intArrayOf(KeyGestureEvent.KEY_GESTURE_TYPE_HOME),
+ handler2,
+ RANDOM_PID2
+ )
+ }
+ }
+
+ @Test
+ fun testUnableToRegisterEmptyListOfGestures() {
+ setupKeyGestureController()
+
+ val handler = KeyGestureHandler { _, _ -> }
+
+ assertThrows(IllegalArgumentException::class.java) {
+ keyGestureController.registerKeyGestureHandler(
+ intArrayOf(),
+ handler,
+ RANDOM_PID1
+ )
+ }
+ }
+
+ @Test
+ fun testGestureHandlerNotCalledOnceUnregistered() {
+ setupKeyGestureController()
+
+ var callbackCount = 0
+ val handler1 = KeyGestureHandler { _, _ -> callbackCount++ }
+ keyGestureController.registerKeyGestureHandler(
+ intArrayOf(KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS),
+ handler1,
+ TEST_PID
+ )
+ sendKeys(intArrayOf(KeyEvent.KEYCODE_RECENT_APPS))
+ assertEquals(1, callbackCount)
+
+ keyGestureController.unregisterKeyGestureHandler(
+ handler1,
+ TEST_PID
+ )
+
+ // Callback should not be sent after unregister
+ sendKeys(intArrayOf(KeyEvent.KEYCODE_RECENT_APPS))
+ assertEquals(1, callbackCount)
+ }
+
private fun testKeyGestureInternal(test: TestData) {
val handledEvents = mutableListOf<KeyGestureEvent>()
val handler = KeyGestureHandler { event, _ ->
handledEvents.add(KeyGestureEvent(event))
- true
}
- keyGestureController.registerKeyGestureHandler(handler, 0)
+ keyGestureController.registerKeyGestureHandler(
+ intArrayOf(test.expectedKeyGestureType),
+ handler,
+ TEST_PID
+ )
handledEvents.clear()
sendKeys(test.keys)
@@ -1744,16 +1771,19 @@ class KeyGestureControllerTests {
)
}
- keyGestureController.unregisterKeyGestureHandler(handler, 0)
+ keyGestureController.unregisterKeyGestureHandler(handler, TEST_PID)
}
- private fun testKeyGestureNotProduced(testName: String, testKeys: IntArray) {
+ private fun testKeyGestureNotProduced(
+ testName: String,
+ testKeys: IntArray,
+ possibleGestures: IntArray
+ ) {
var handledEvents = mutableListOf<KeyGestureEvent>()
val handler = KeyGestureHandler { event, _ ->
handledEvents.add(KeyGestureEvent(event))
- true
}
- keyGestureController.registerKeyGestureHandler(handler, 0)
+ keyGestureController.registerKeyGestureHandler(possibleGestures, handler, TEST_PID)
handledEvents.clear()
sendKeys(testKeys)
@@ -1823,10 +1853,10 @@ class KeyGestureControllerTests {
}
inner class KeyGestureHandler(
- private var handler: (event: AidlKeyGestureEvent, token: IBinder?) -> Boolean
+ private var handler: (event: AidlKeyGestureEvent, token: IBinder?) -> Unit
) : IKeyGestureHandler.Stub() {
- override fun handleKeyGesture(event: AidlKeyGestureEvent, token: IBinder?): Boolean {
- return handler(event, token)
+ override fun handleKeyGesture(event: AidlKeyGestureEvent, token: IBinder?) {
+ handler(event, token)
}
}
}