diff options
12 files changed, 128 insertions, 32 deletions
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl index 88d7231bc7be..6626baffd134 100644 --- a/core/java/android/hardware/input/IInputManager.aidl +++ b/core/java/android/hardware/input/IInputManager.aidl @@ -169,6 +169,8 @@ interface IInputManager { void setPointerIconType(int typeId); void setCustomPointerIcon(in PointerIcon icon); + boolean setPointerIcon(in PointerIcon icon, int displayId, int deviceId, int pointerId, + in IBinder inputToken); oneway void requestPointerCapture(IBinder inputChannelToken, boolean enabled); diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java index abbf95403d80..f941ad87bac5 100644 --- a/core/java/android/hardware/input/InputManager.java +++ b/core/java/android/hardware/input/InputManager.java @@ -1057,6 +1057,12 @@ public final class InputManager { mGlobal.setCustomPointerIcon(icon); } + /** @hide */ + public boolean setPointerIcon(PointerIcon icon, int displayId, int deviceId, int pointerId, + IBinder inputToken) { + return mGlobal.setPointerIcon(icon, displayId, deviceId, pointerId, inputToken); + } + /** * Check if showing a {@link android.view.PointerIcon} for styluses is enabled. * diff --git a/core/java/android/hardware/input/InputManagerGlobal.java b/core/java/android/hardware/input/InputManagerGlobal.java index cf1dfe3fceb1..24a69116e77e 100644 --- a/core/java/android/hardware/input/InputManagerGlobal.java +++ b/core/java/android/hardware/input/InputManagerGlobal.java @@ -1286,6 +1286,18 @@ public final class InputManagerGlobal { } /** + * @see InputManager#setPointerIcon(PointerIcon, int, int, int, IBinder) + */ + public boolean setPointerIcon(PointerIcon icon, int displayId, int deviceId, int pointerId, + IBinder inputToken) { + try { + return mIm.setPointerIcon(icon, displayId, deviceId, pointerId, inputToken); + } catch (RemoteException ex) { + throw ex.rethrowFromSystemServer(); + } + } + + /** * @see InputManager#requestPointerCapture(IBinder, boolean) */ public void requestPointerCapture(IBinder windowToken, boolean enable) { diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java index d131dc9a4c7d..f2c3abc8edb4 100644 --- a/core/java/android/view/InputDevice.java +++ b/core/java/android/view/InputDevice.java @@ -1308,24 +1308,6 @@ public final class InputDevice implements Parcelable { } /** - * Sets the current pointer type. - * @param pointerType the type of the pointer icon. - * @hide - */ - public void setPointerType(int pointerType) { - InputManagerGlobal.getInstance().setPointerIconType(pointerType); - } - - /** - * Specifies the current custom pointer. - * @param icon the icon data. - * @hide - */ - public void setCustomPointerIcon(PointerIcon icon) { - InputManagerGlobal.getInstance().setCustomPointerIcon(icon); - } - - /** * Reports whether the device has a battery. * @return true if the device has a battery, false otherwise. * @hide diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java index fee88d91283d..7800c28ae089 100644 --- a/core/java/android/view/PointerIcon.java +++ b/core/java/android/view/PointerIcon.java @@ -223,6 +223,9 @@ public final class PointerIcon implements Parcelable { * @throws IllegalArgumentException if context is null. */ public static @NonNull PointerIcon getSystemIcon(@NonNull Context context, int type) { + // TODO(b/293587049): Pointer Icon Refactor: There is no need to load the system + // icon resource into memory outside of system server. Remove the need to load + // resources when getting a system icon. if (context == null) { throw new IllegalArgumentException("context must not be null"); } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index d27f787072e2..8d469ee454ae 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -97,6 +97,8 @@ import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodCl import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.INSETS_CONTROLLER; import static android.view.flags.Flags.toolkitSetFrameRateReadOnly; +import static com.android.input.flags.Flags.enablePointerChoreographer; + import android.Manifest; import android.accessibilityservice.AccessibilityService; import android.animation.AnimationHandler; @@ -7485,18 +7487,34 @@ public final class ViewRootImpl implements ViewParent, mPointerIconType = pointerType; mCustomPointerIcon = null; if (mPointerIconType != PointerIcon.TYPE_CUSTOM) { - InputManagerGlobal - .getInstance() - .setPointerIconType(pointerType); + if (enablePointerChoreographer()) { + InputManagerGlobal + .getInstance() + .setPointerIcon(PointerIcon.getSystemIcon(mContext, pointerType), + event.getDisplayId(), event.getDeviceId(), + event.getPointerId(pointerIndex), getInputToken()); + } else { + InputManagerGlobal + .getInstance() + .setPointerIconType(pointerType); + } return true; } } if (mPointerIconType == PointerIcon.TYPE_CUSTOM && !pointerIcon.equals(mCustomPointerIcon)) { mCustomPointerIcon = pointerIcon; - InputManagerGlobal - .getInstance() - .setCustomPointerIcon(mCustomPointerIcon); + if (enablePointerChoreographer()) { + InputManagerGlobal + .getInstance() + .setPointerIcon(mCustomPointerIcon, + event.getDisplayId(), event.getDeviceId(), + event.getPointerId(pointerIndex), getInputToken()); + } else { + InputManagerGlobal + .getInstance() + .setCustomPointerIcon(mCustomPointerIcon); + } } return true; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java index 53ec20192f2b..8511a21d4294 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java @@ -24,6 +24,7 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERL import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_CONSUMER; +import static com.android.input.flags.Flags.enablePointerChoreographer; import static com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_BOTTOM; import static com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_LEFT; import static com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_RIGHT; @@ -63,6 +64,7 @@ import java.util.function.Supplier; class DragResizeInputListener implements AutoCloseable { private static final String TAG = "DragResizeInputListener"; private final IWindowSession mWindowSession = WindowManagerGlobal.getWindowSession(); + private final Context mContext; private final Handler mHandler; private final Choreographer mChoreographer; private final InputManager mInputManager; @@ -110,6 +112,7 @@ class DragResizeInputListener implements AutoCloseable { Supplier<SurfaceControl.Transaction> surfaceControlTransactionSupplier, DisplayController displayController) { mInputManager = context.getSystemService(InputManager.class); + mContext = context; mHandler = handler; mChoreographer = choreographer; mSurfaceControlTransactionSupplier = surfaceControlTransactionSupplier; @@ -451,7 +454,9 @@ class DragResizeInputListener implements AutoCloseable { } case MotionEvent.ACTION_HOVER_ENTER: case MotionEvent.ACTION_HOVER_MOVE: { - updateCursorType(e.getXCursorPosition(), e.getYCursorPosition()); + updateCursorType(e.getDisplayId(), e.getDeviceId(), + e.getPointerId(/*pointerIndex=*/0), e.getXCursorPosition(), + e.getYCursorPosition()); result = true; break; } @@ -579,7 +584,8 @@ class DragResizeInputListener implements AutoCloseable { return 0; } - private void updateCursorType(float x, float y) { + private void updateCursorType(int displayId, int deviceId, int pointerId, float x, + float y) { @DragPositioningCallback.CtrlType int ctrlType = calculateResizeHandlesCtrlType(x, y); int cursorType = PointerIcon.TYPE_DEFAULT; @@ -611,9 +617,14 @@ class DragResizeInputListener implements AutoCloseable { // where views in the task can receive input events because we can't set touch regions // of input sinks to have rounded corners. if (mLastCursorType != cursorType || cursorType != PointerIcon.TYPE_DEFAULT) { - mInputManager.setPointerIconType(cursorType); + if (enablePointerChoreographer()) { + mInputManager.setPointerIcon(PointerIcon.getSystemIcon(mContext, cursorType), + displayId, deviceId, pointerId, mInputChannel.getToken()); + } else { + mInputManager.setPointerIconType(cursorType); + } mLastCursorType = cursorType; } } } -}
\ No newline at end of file +} diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h index fa07c3989720..a8b963367f4c 100644 --- a/libs/input/PointerController.h +++ b/libs/input/PointerController.h @@ -65,9 +65,9 @@ public: void setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex, BitSet32 spotIdBits, int32_t displayId) override; void clearSpots() override; + void updatePointerIcon(PointerIconStyle iconId) override; + void setCustomPointerIcon(const SpriteIcon& icon) override; - void updatePointerIcon(PointerIconStyle iconId); - void setCustomPointerIcon(const SpriteIcon& icon); virtual void setInactivityTimeout(InactivityTimeout inactivityTimeout); void doInactivityTimeout(); void reloadPointerResources(); @@ -192,10 +192,10 @@ public: void setPresentation(Presentation) override { LOG_ALWAYS_FATAL("Should not be called"); } - void updatePointerIcon(PointerIconStyle) { + void updatePointerIcon(PointerIconStyle) override { LOG_ALWAYS_FATAL("Should not be called"); } - void setCustomPointerIcon(const SpriteIcon&) { + void setCustomPointerIcon(const SpriteIcon&) override { LOG_ALWAYS_FATAL("Should not be called"); } // fade() should not be called by inactivity timeout. Do nothing. diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index 2533e0297679..3fc9594965a2 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -295,6 +295,8 @@ public class InputManagerService extends IInputManager.Stub @GuardedBy("mAdditionalDisplayInputPropertiesLock") private final AdditionalDisplayInputProperties mCurrentDisplayProperties = new AdditionalDisplayInputProperties(); + // TODO(b/293587049): Pointer Icon Refactor: There can be more than one pointer icon + // visible at once. Update this to support multi-pointer use cases. @GuardedBy("mAdditionalDisplayInputPropertiesLock") private int mPointerIconType = PointerIcon.TYPE_NOT_SPECIFIED; @GuardedBy("mAdditionalDisplayInputPropertiesLock") @@ -1756,6 +1758,21 @@ public class InputManagerService extends IInputManager.Stub } } + // Binder call + @Override + public boolean setPointerIcon(PointerIcon icon, int displayId, int deviceId, int pointerId, + IBinder inputToken) { + Objects.requireNonNull(icon); + synchronized (mAdditionalDisplayInputPropertiesLock) { + mPointerIconType = icon.getType(); + mPointerIcon = mPointerIconType == PointerIcon.TYPE_CUSTOM ? icon : null; + + if (!mCurrentDisplayProperties.pointerIconVisible) return false; + + return mNative.setPointerIcon(icon, displayId, deviceId, pointerId, inputToken); + } + } + /** * Add a runtime association between the input port and the display port. This overrides any * static associations. diff --git a/services/core/java/com/android/server/input/NativeInputManagerService.java b/services/core/java/com/android/server/input/NativeInputManagerService.java index f126a89eedf7..620cde59fb52 100644 --- a/services/core/java/com/android/server/input/NativeInputManagerService.java +++ b/services/core/java/com/android/server/input/NativeInputManagerService.java @@ -186,6 +186,9 @@ interface NativeInputManagerService { void setCustomPointerIcon(PointerIcon icon); + boolean setPointerIcon(PointerIcon icon, int displayId, int deviceId, int pointerId, + IBinder inputToken); + void requestPointerCapture(IBinder windowToken, boolean enabled); boolean canDispatchToDisplay(int deviceId, int displayId); @@ -434,6 +437,10 @@ interface NativeInputManagerService { public native void setCustomPointerIcon(PointerIcon icon); @Override + public native boolean setPointerIcon(PointerIcon icon, int displayId, int deviceId, + int pointerId, IBinder inputToken); + + @Override public native void requestPointerCapture(IBinder windowToken, boolean enabled); @Override diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java index 7af4aadb2f0e..a888f8467b3a 100644 --- a/services/core/java/com/android/server/wm/DragState.java +++ b/services/core/java/com/android/server/wm/DragState.java @@ -692,6 +692,7 @@ class DragState { void overridePointerIconLocked(int touchSource) { mTouchSource = touchSource; if (isFromSource(InputDevice.SOURCE_MOUSE)) { + // TODO(b/293587049): Pointer Icon Refactor: Set the pointer icon from the drag window. InputManagerGlobal.getInstance().setPointerIconType(PointerIcon.TYPE_GRABBING); } } diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index f1cddc643422..7de50e8f1ecf 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -308,6 +308,8 @@ public: void reloadPointerIcons(); void requestPointerCapture(const sp<IBinder>& windowToken, bool enabled); void setCustomPointerIcon(const SpriteIcon& icon); + bool setPointerIcon(std::variant<std::unique_ptr<SpriteIcon>, PointerIconStyle> icon, + int32_t displayId, DeviceId deviceId); void setMotionClassifierEnabled(bool enabled); std::optional<std::string> getBluetoothAddress(int32_t deviceId); void setStylusButtonMotionEventsEnabled(bool enabled); @@ -1347,6 +1349,12 @@ void NativeInputManager::setCustomPointerIcon(const SpriteIcon& icon) { } } +bool NativeInputManager::setPointerIcon( + std::variant<std::unique_ptr<SpriteIcon>, PointerIconStyle> icon, int32_t displayId, + DeviceId deviceId) { + return mInputManager->getChoreographer().setPointerIcon(std::move(icon), displayId, deviceId); +} + TouchAffineTransformation NativeInputManager::getTouchAffineTransformation( JNIEnv *env, jfloatArray matrixArr) { ATRACE_CALL(); @@ -2511,6 +2519,33 @@ static void nativeSetCustomPointerIcon(JNIEnv* env, jobject nativeImplObj, jobje im->setCustomPointerIcon(spriteIcon); } +static bool nativeSetPointerIcon(JNIEnv* env, jobject nativeImplObj, jobject iconObj, + jint displayId, jint deviceId, jint pointerId, + jobject inputTokenObj) { + NativeInputManager* im = getNativeInputManager(env, nativeImplObj); + + PointerIcon pointerIcon; + status_t result = android_view_PointerIcon_getLoadedIcon(env, iconObj, &pointerIcon); + if (result) { + jniThrowRuntimeException(env, "Failed to load pointer icon."); + return false; + } + + std::variant<std::unique_ptr<SpriteIcon>, PointerIconStyle> icon; + if (pointerIcon.style == PointerIconStyle::TYPE_CUSTOM) { + icon = std::make_unique<SpriteIcon>(pointerIcon.bitmap.copy( + ANDROID_BITMAP_FORMAT_RGBA_8888), + pointerIcon.style, pointerIcon.hotSpotX, + pointerIcon.hotSpotY); + } else { + icon = pointerIcon.style; + } + // TODO(b/293587049): Perform hit test to ensure the pointer is dispatched to the channel. + sp<IBinder> inputToken = ibinderForJavaObject(env, inputTokenObj); + + return im->setPointerIcon(std::move(icon), displayId, deviceId); +} + static jboolean nativeCanDispatchToDisplay(JNIEnv* env, jobject nativeImplObj, jint deviceId, jint displayId) { NativeInputManager* im = getNativeInputManager(env, nativeImplObj); @@ -2769,6 +2804,8 @@ static const JNINativeMethod gInputManagerMethods[] = { {"reloadPointerIcons", "()V", (void*)nativeReloadPointerIcons}, {"setCustomPointerIcon", "(Landroid/view/PointerIcon;)V", (void*)nativeSetCustomPointerIcon}, + {"setPointerIcon", "(Landroid/view/PointerIcon;IIILandroid/os/IBinder;)Z", + (void*)nativeSetPointerIcon}, {"canDispatchToDisplay", "(II)Z", (void*)nativeCanDispatchToDisplay}, {"notifyPortAssociationsChanged", "()V", (void*)nativeNotifyPortAssociationsChanged}, {"changeUniqueIdAssociation", "()V", (void*)nativeChangeUniqueIdAssociation}, |