diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl index a645ae4a3964e..3a07bb0d77362 100644 --- a/core/java/android/hardware/input/IInputManager.aidl +++ b/core/java/android/hardware/input/IInputManager.aidl @@ -160,4 +160,9 @@ interface IInputManager { void registerBatteryListener(int deviceId, IInputDeviceBatteryListener listener); void unregisterBatteryListener(int deviceId, IInputDeviceBatteryListener listener); + + @EnforcePermission("MONITOR_INPUT") + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = " + + "android.Manifest.permission.MONITOR_INPUT)") + void pilferPointers(IBinder inputChannelToken); } diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java index 97812cea23e18..1cf3bb548a7e8 100644 --- a/core/java/android/hardware/input/InputManager.java +++ b/core/java/android/hardware/input/InputManager.java @@ -1818,6 +1818,34 @@ public final class InputManager { } } + /** + * Pilfer pointers from an input channel. + * + * Takes all the current pointer event streams that are currently being sent to the given + * input channel and generates appropriate cancellations for all other windows that are + * receiving these pointers. + * + * This API is intended to be used in conjunction with spy windows. When a spy window pilfers + * pointers, the foreground windows and all other spy windows that are receiving any of the + * pointers that are currently being dispatched to the pilfering window will have those pointers + * canceled. Only the pilfering window will continue to receive events for the affected pointers + * until the pointer is lifted. + * + * This method should be used with caution as unexpected pilfering can break fundamental user + * interactions. + * + * @see android.os.InputConfig#SPY + * @hide + */ + @RequiresPermission(Manifest.permission.MONITOR_INPUT) + public void pilferPointers(IBinder inputChannelToken) { + try { + mIm.pilferPointers(inputChannelToken); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** * Removes a previously registered battery listener for an input device. * @see #addInputDeviceBatteryListener(int, Executor, InputDeviceBatteryListener) diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index 91d5698123e8f..89e0d0510cf89 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -18,6 +18,8 @@ package com.android.server.input; import static android.view.KeyEvent.KEYCODE_UNKNOWN; +import android.Manifest; +import android.annotation.EnforcePermission; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManagerInternal; @@ -2678,6 +2680,13 @@ public class InputManagerService extends IInputManager.Stub mNative.cancelCurrentTouch(); } + @EnforcePermission(Manifest.permission.MONITOR_INPUT) + @Override + public void pilferPointers(IBinder inputChannelToken) { + Objects.requireNonNull(inputChannelToken); + mNative.pilferPointers(inputChannelToken); + } + @Override public void registerBatteryListener(int deviceId, IInputDeviceBatteryListener listener) { Objects.requireNonNull(listener);