Update View docs for pointer icon and default resolution behavior
We now support showing a pointer icon for styluses in Android. When
a device is configured to show pointer icons for styluses, apps can
select the pointer icon to be used for the stylus pointer by overriding
onResolvePointerIcon.
Previously, onResolvePointerIcon was only called for mouse events, but
now it's possible that it will be called for stylus pointers as well.
To limit unexpected behavior in existing apps that only expect pointer
icons to be shown for mouse devices, a pointer icon set using
View#setPointerIcon will now only apply to mouse pointers. We update
the docs to reflect these changes, and add instructions for explicitly
resolving stylus pointers.
Bug: 215436642
Test: atest PointerIconTest
Change-Id: I40364cb01277cb9c98704dfc1cbee9dbfd526000
diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java
index 6a493e6..d88994b 100644
--- a/core/java/android/view/PointerIcon.java
+++ b/core/java/android/view/PointerIcon.java
@@ -57,8 +57,9 @@
/** Type constant: Null icon. It has no bitmap. */
public static final int TYPE_NULL = 0;
- /** Type constant: no icons are specified. If all views uses this, then falls back
- * to the default type, but this is helpful to distinguish a view explicitly want
+ /**
+ * Type constant: no icons are specified. If all views uses this, then the pointer icon falls
+ * back to the default type, but this is helpful to distinguish a view that explicitly wants
* to have the default icon.
* @hide
*/
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 6cd8941..003307d 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -92,6 +92,7 @@
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.hardware.display.DisplayManagerGlobal;
+import android.hardware.input.InputManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
@@ -5413,7 +5414,7 @@
/**
* The pointer icon when the mouse hovers on this view. The default is null.
*/
- private PointerIcon mPointerIcon;
+ private PointerIcon mMousePointerIcon;
/**
* @hide
@@ -29506,30 +29507,71 @@
}
/**
- * Returns the pointer icon for the motion event, or null if it doesn't specify the icon.
- * The default implementation does not care the location or event types, but some subclasses
- * may use it (such as WebViews).
- * @param event The MotionEvent from a mouse
- * @param pointerIndex The index of the pointer for which to retrieve the {@link PointerIcon}.
- * This will be between 0 and {@link MotionEvent#getPointerCount()}.
+ * Resolve the pointer icon that should be used for specified pointer in the motion event.
+ *
+ * The default implementation will resolve the pointer icon to one set using
+ * {@link #setPointerIcon(PointerIcon)} for mouse devices. Subclasses may override this to
+ * customize the icon for the given pointer.
+ *
+ * For example, the pointer icon for a stylus pointer can be resolved in the following way:
+ * <code><pre>
+ * @Override
+ * public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) {
+ * final int toolType = event.getToolType(pointerIndex);
+ * if (!event.isFromSource(InputDevice.SOURCE_MOUSE)
+ * && event.isFromSource(InputDevice.SOURCE_STYLUS)
+ * && (toolType == MotionEvent.TOOL_TYPE_STYLUS
+ * || toolType == MotionEvent.TOOL_TYPE_ERASER)) {
+ * // Show this pointer icon only if this pointer is a stylus.
+ * return PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_WAIT);
+ * }
+ * // Use the default logic for determining the pointer icon for other non-stylus pointers,
+ * // like for the mouse cursor.
+ * return super.onResolvePointerIcon(event, pointerIndex);
+ * }
+ * </pre></code>
+ *
+ * @param event The {@link MotionEvent} that requires a pointer icon to be resolved for one of
+ * pointers.
+ * @param pointerIndex The index of the pointer in {@code event} for which to retrieve the
+ * {@link PointerIcon}. This will be between 0 and {@link MotionEvent#getPointerCount()}.
+ * @return the pointer icon to use for specified pointer, or {@code null} if a pointer icon
+ * is not specified and the default icon should be used.
* @see PointerIcon
+ * @see InputManager#isStylusPointerIconEnabled()
*/
public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) {
final float x = event.getX(pointerIndex);
final float y = event.getY(pointerIndex);
if (isDraggingScrollBar() || isOnScrollbarThumb(x, y)) {
- return PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_ARROW);
+ // Use the default pointer icon.
+ return null;
}
- return mPointerIcon;
+
+ // Note: A drawing tablet will have both SOURCE_MOUSE and SOURCE_STYLUS, but it would use
+ // TOOL_TYPE_STYLUS. For now, treat drawing tablets the same way as a mouse or touchpad.
+ if (event.isFromSource(InputDevice.SOURCE_MOUSE)) {
+ return mMousePointerIcon;
+ }
+
+ return null;
}
/**
- * Set the pointer icon for the current view.
+ * Set the pointer icon to be used for a mouse pointer in the current view.
+ *
* Passing {@code null} will restore the pointer icon to its default value.
+ * Note that setting the pointer icon using this method will only set it for events coming from
+ * a mouse device (i.e. with source {@link InputDevice#SOURCE_MOUSE}). To resolve
+ * the pointer icon for other device types like styluses, override
+ * {@link #onResolvePointerIcon(MotionEvent, int)}.
+ *
* @param pointerIcon A PointerIcon instance which will be shown when the mouse hovers.
+ * @see #onResolvePointerIcon(MotionEvent, int)
+ * @see PointerIcon
*/
public void setPointerIcon(PointerIcon pointerIcon) {
- mPointerIcon = pointerIcon;
+ mMousePointerIcon = pointerIcon;
if (mAttachInfo == null || mAttachInfo.mHandlingPointerEvent) {
return;
}
@@ -29540,11 +29582,13 @@
}
/**
- * Gets the pointer icon for the current view.
+ * Gets the mouse pointer icon for the current view.
+ *
+ * @see #setPointerIcon(PointerIcon)
*/
@InspectableProperty
public PointerIcon getPointerIcon() {
- return mPointerIcon;
+ return mMousePointerIcon;
}
/**