diff options
author | 2015-10-30 15:54:33 -0700 | |
---|---|---|
committer | 2015-12-14 19:45:10 -0800 | |
commit | d4eaef7f4c5a5d281de4fff272cd33e892e26264 (patch) | |
tree | 7141708f5759a078b74932d487dc8fe83c29887f | |
parent | 40aa9f1b989a7896fb683a5a7dd664aa3174012d (diff) |
Make public pointer icon API with custom icons.
BUG: 25778347, 23804184
Change-Id: If138b97c750c912e9848412c27b65004899961eb
-rw-r--r-- | api/current.txt | 34 | ||||
-rw-r--r-- | api/system-current.txt | 34 | ||||
-rw-r--r-- | api/test-current.txt | 34 | ||||
-rw-r--r-- | core/java/android/hardware/input/IInputManager.aidl | 2 | ||||
-rw-r--r-- | core/java/android/hardware/input/InputManager.java | 10 | ||||
-rw-r--r-- | core/java/android/view/InputDevice.java | 9 | ||||
-rw-r--r-- | core/java/android/view/PointerIcon.java | 106 | ||||
-rw-r--r-- | core/java/android/view/View.java | 67 | ||||
-rw-r--r-- | core/java/android/view/ViewGroup.java | 11 | ||||
-rw-r--r-- | core/java/android/view/ViewRootImpl.java | 28 | ||||
-rw-r--r-- | core/java/android/widget/TextView.java | 9 | ||||
-rw-r--r-- | core/jni/android_view_PointerIcon.cpp | 34 | ||||
-rw-r--r-- | core/jni/android_view_PointerIcon.h | 5 | ||||
-rw-r--r-- | libs/input/PointerController.cpp | 11 | ||||
-rw-r--r-- | libs/input/PointerController.h | 2 | ||||
-rw-r--r-- | packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java | 5 | ||||
-rw-r--r-- | services/core/java/com/android/server/input/InputManagerService.java | 7 | ||||
-rw-r--r-- | services/core/jni/com_android_server_input_InputManagerService.cpp | 30 |
18 files changed, 271 insertions, 167 deletions
diff --git a/api/current.txt b/api/current.txt index f5ccf0e10743..df6c473a3a66 100644 --- a/api/current.txt +++ b/api/current.txt @@ -40337,6 +40337,38 @@ package android.view { field public static final int ORIENTATION_UNKNOWN = -1; // 0xffffffff } + public final class PointerIcon implements android.os.Parcelable { + method public static android.view.PointerIcon createCustomIcon(android.graphics.Bitmap, float, float); + method public int describeContents(); + method public static android.view.PointerIcon getSystemIcon(android.content.Context, int); + method public static android.view.PointerIcon loadCustomIcon(android.content.res.Resources, int); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.view.PointerIcon> CREATOR; + field public static final int STYLE_ALIAS = 1010; // 0x3f2 + field public static final int STYLE_ALL_SCROLL = 1013; // 0x3f5 + field public static final int STYLE_ARROW = 1000; // 0x3e8 + field public static final int STYLE_CELL = 1006; // 0x3ee + field public static final int STYLE_CONTEXT_MENU = 1001; // 0x3e9 + field public static final int STYLE_COPY = 1011; // 0x3f3 + field public static final int STYLE_CROSSHAIR = 1007; // 0x3ef + field public static final int STYLE_DEFAULT = 1000; // 0x3e8 + field public static final int STYLE_GRAB = 1020; // 0x3fc + field public static final int STYLE_GRABBING = 1021; // 0x3fd + field public static final int STYLE_HAND = 1002; // 0x3ea + field public static final int STYLE_HELP = 1003; // 0x3eb + field public static final int STYLE_HORIZONTAL_DOUBLE_ARROW = 1014; // 0x3f6 + field public static final int STYLE_NO_DROP = 1012; // 0x3f4 + field public static final int STYLE_NULL = 0; // 0x0 + field public static final int STYLE_TEXT = 1008; // 0x3f0 + field public static final int STYLE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW = 1017; // 0x3f9 + field public static final int STYLE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW = 1016; // 0x3f8 + field public static final int STYLE_VERTICAL_DOUBLE_ARROW = 1015; // 0x3f7 + field public static final int STYLE_VERTICAL_TEXT = 1009; // 0x3f1 + field public static final int STYLE_WAIT = 1004; // 0x3ec + field public static final int STYLE_ZOOM_IN = 1018; // 0x3fa + field public static final int STYLE_ZOOM_OUT = 1019; // 0x3fb + } + public class ScaleGestureDetector { ctor public ScaleGestureDetector(android.content.Context, android.view.ScaleGestureDetector.OnScaleGestureListener); ctor public ScaleGestureDetector(android.content.Context, android.view.ScaleGestureDetector.OnScaleGestureListener, android.os.Handler); @@ -40696,6 +40728,7 @@ package android.view { method public android.view.ViewParent getParentForAccessibility(); method public float getPivotX(); method public float getPivotY(); + method public android.view.PointerIcon getPointerIcon(android.view.MotionEvent, float, float); method public android.content.res.Resources getResources(); method public final int getRight(); method protected float getRightFadingEdgeStrength(); @@ -40978,6 +41011,7 @@ package android.view { method public void setPaddingRelative(int, int, int, int); method public void setPivotX(float); method public void setPivotY(float); + method public void setPointerIcon(android.view.PointerIcon); method public void setPressed(boolean); method public final void setRight(int); method public void setRotation(float); diff --git a/api/system-current.txt b/api/system-current.txt index bc63b4871a20..ee975d1b2fe2 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -42675,6 +42675,38 @@ package android.view { field public static final int ORIENTATION_UNKNOWN = -1; // 0xffffffff } + public final class PointerIcon implements android.os.Parcelable { + method public static android.view.PointerIcon createCustomIcon(android.graphics.Bitmap, float, float); + method public int describeContents(); + method public static android.view.PointerIcon getSystemIcon(android.content.Context, int); + method public static android.view.PointerIcon loadCustomIcon(android.content.res.Resources, int); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.view.PointerIcon> CREATOR; + field public static final int STYLE_ALIAS = 1010; // 0x3f2 + field public static final int STYLE_ALL_SCROLL = 1013; // 0x3f5 + field public static final int STYLE_ARROW = 1000; // 0x3e8 + field public static final int STYLE_CELL = 1006; // 0x3ee + field public static final int STYLE_CONTEXT_MENU = 1001; // 0x3e9 + field public static final int STYLE_COPY = 1011; // 0x3f3 + field public static final int STYLE_CROSSHAIR = 1007; // 0x3ef + field public static final int STYLE_DEFAULT = 1000; // 0x3e8 + field public static final int STYLE_GRAB = 1020; // 0x3fc + field public static final int STYLE_GRABBING = 1021; // 0x3fd + field public static final int STYLE_HAND = 1002; // 0x3ea + field public static final int STYLE_HELP = 1003; // 0x3eb + field public static final int STYLE_HORIZONTAL_DOUBLE_ARROW = 1014; // 0x3f6 + field public static final int STYLE_NO_DROP = 1012; // 0x3f4 + field public static final int STYLE_NULL = 0; // 0x0 + field public static final int STYLE_TEXT = 1008; // 0x3f0 + field public static final int STYLE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW = 1017; // 0x3f9 + field public static final int STYLE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW = 1016; // 0x3f8 + field public static final int STYLE_VERTICAL_DOUBLE_ARROW = 1015; // 0x3f7 + field public static final int STYLE_VERTICAL_TEXT = 1009; // 0x3f1 + field public static final int STYLE_WAIT = 1004; // 0x3ec + field public static final int STYLE_ZOOM_IN = 1018; // 0x3fa + field public static final int STYLE_ZOOM_OUT = 1019; // 0x3fb + } + public class ScaleGestureDetector { ctor public ScaleGestureDetector(android.content.Context, android.view.ScaleGestureDetector.OnScaleGestureListener); ctor public ScaleGestureDetector(android.content.Context, android.view.ScaleGestureDetector.OnScaleGestureListener, android.os.Handler); @@ -43034,6 +43066,7 @@ package android.view { method public android.view.ViewParent getParentForAccessibility(); method public float getPivotX(); method public float getPivotY(); + method public android.view.PointerIcon getPointerIcon(android.view.MotionEvent, float, float); method public android.content.res.Resources getResources(); method public final int getRight(); method protected float getRightFadingEdgeStrength(); @@ -43316,6 +43349,7 @@ package android.view { method public void setPaddingRelative(int, int, int, int); method public void setPivotX(float); method public void setPivotY(float); + method public void setPointerIcon(android.view.PointerIcon); method public void setPressed(boolean); method public final void setRight(int); method public void setRotation(float); diff --git a/api/test-current.txt b/api/test-current.txt index a2220374936f..c4948957cb52 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -40339,6 +40339,38 @@ package android.view { field public static final int ORIENTATION_UNKNOWN = -1; // 0xffffffff } + public final class PointerIcon implements android.os.Parcelable { + method public static android.view.PointerIcon createCustomIcon(android.graphics.Bitmap, float, float); + method public int describeContents(); + method public static android.view.PointerIcon getSystemIcon(android.content.Context, int); + method public static android.view.PointerIcon loadCustomIcon(android.content.res.Resources, int); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.view.PointerIcon> CREATOR; + field public static final int STYLE_ALIAS = 1010; // 0x3f2 + field public static final int STYLE_ALL_SCROLL = 1013; // 0x3f5 + field public static final int STYLE_ARROW = 1000; // 0x3e8 + field public static final int STYLE_CELL = 1006; // 0x3ee + field public static final int STYLE_CONTEXT_MENU = 1001; // 0x3e9 + field public static final int STYLE_COPY = 1011; // 0x3f3 + field public static final int STYLE_CROSSHAIR = 1007; // 0x3ef + field public static final int STYLE_DEFAULT = 1000; // 0x3e8 + field public static final int STYLE_GRAB = 1020; // 0x3fc + field public static final int STYLE_GRABBING = 1021; // 0x3fd + field public static final int STYLE_HAND = 1002; // 0x3ea + field public static final int STYLE_HELP = 1003; // 0x3eb + field public static final int STYLE_HORIZONTAL_DOUBLE_ARROW = 1014; // 0x3f6 + field public static final int STYLE_NO_DROP = 1012; // 0x3f4 + field public static final int STYLE_NULL = 0; // 0x0 + field public static final int STYLE_TEXT = 1008; // 0x3f0 + field public static final int STYLE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW = 1017; // 0x3f9 + field public static final int STYLE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW = 1016; // 0x3f8 + field public static final int STYLE_VERTICAL_DOUBLE_ARROW = 1015; // 0x3f7 + field public static final int STYLE_VERTICAL_TEXT = 1009; // 0x3f1 + field public static final int STYLE_WAIT = 1004; // 0x3ec + field public static final int STYLE_ZOOM_IN = 1018; // 0x3fa + field public static final int STYLE_ZOOM_OUT = 1019; // 0x3fb + } + public class ScaleGestureDetector { ctor public ScaleGestureDetector(android.content.Context, android.view.ScaleGestureDetector.OnScaleGestureListener); ctor public ScaleGestureDetector(android.content.Context, android.view.ScaleGestureDetector.OnScaleGestureListener, android.os.Handler); @@ -40698,6 +40730,7 @@ package android.view { method public android.view.ViewParent getParentForAccessibility(); method public float getPivotX(); method public float getPivotY(); + method public android.view.PointerIcon getPointerIcon(android.view.MotionEvent, float, float); method public android.content.res.Resources getResources(); method public final int getRight(); method protected float getRightFadingEdgeStrength(); @@ -40980,6 +41013,7 @@ package android.view { method public void setPaddingRelative(int, int, int, int); method public void setPivotX(float); method public void setPivotY(float); + method public void setPointerIcon(android.view.PointerIcon); method public void setPressed(boolean); method public final void setRight(int); method public void setRotation(float); diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl index 174291e40c0f..ff33bd959175 100644 --- a/core/java/android/hardware/input/IInputManager.aidl +++ b/core/java/android/hardware/input/IInputManager.aidl @@ -24,6 +24,7 @@ import android.hardware.input.TouchCalibration; import android.os.IBinder; import android.view.InputDevice; import android.view.InputEvent; +import android.view.PointerIcon; /** @hide */ interface IInputManager { @@ -71,4 +72,5 @@ interface IInputManager { void cancelVibrate(int deviceId, IBinder token); void setPointerIconShape(int shapeId); + void setCustomPointerIcon(in PointerIcon icon); } diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java index 201afee58965..fab47181cfef 100644 --- a/core/java/android/hardware/input/InputManager.java +++ b/core/java/android/hardware/input/InputManager.java @@ -16,6 +16,7 @@ package android.hardware.input; +import android.view.PointerIcon; import com.android.internal.os.SomeArgs; import com.android.internal.util.ArrayUtils; @@ -819,6 +820,15 @@ public final class InputManager { } } + /** @hide */ + public void setCustomPointerIcon(PointerIcon icon) { + try { + mIm.setCustomPointerIcon(icon); + } catch (RemoteException ex) { + // Do nothing. + } + } + private void populateInputDevicesLocked() { if (mInputDevicesChangedListener == null) { final InputDevicesChangedListener listener = new InputDevicesChangedListener(); diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java index 46b9a4694d9d..88cd7ca71a4e 100644 --- a/core/java/android/view/InputDevice.java +++ b/core/java/android/view/InputDevice.java @@ -784,6 +784,15 @@ public final class InputDevice implements Parcelable { } /** + * Specifies the current custom pointer. + * @param icon the icon data. + * @hide + */ + public void setCustomPointerIcon(PointerIcon icon) { + InputManager.getInstance().setCustomPointerIcon(icon); + } + + /** * Provides information about the range of values for a particular {@link MotionEvent} axis. * * @see InputDevice#getMotionRange(int) diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java index d2a7d4ad4859..aa879cdce69c 100644 --- a/core/java/android/view/PointerIcon.java +++ b/core/java/android/view/PointerIcon.java @@ -16,8 +16,10 @@ package android.view; +import android.annotation.NonNull; import android.os.UserHandle; import android.provider.Settings; +import android.util.SparseArray; import com.android.internal.util.XmlUtils; import android.annotation.XmlRes; @@ -39,13 +41,11 @@ import android.util.Log; * Pointer icons can be provided either by the system using system styles, * or by applications using bitmaps or application resources. * </p> - * - * @hide */ public final class PointerIcon implements Parcelable { private static final String TAG = "PointerIcon"; - /** Style constant: Custom icon with a user-supplied bitmap. */ + /** {@hide} Style constant: Custom icon with a user-supplied bitmap. */ public static final int STYLE_CUSTOM = -1; /** Style constant: Null icon. It has no bitmap. */ @@ -54,6 +54,7 @@ public final class PointerIcon implements Parcelable { /** Style constant: no icons are specified. If all views uses this, then falls back * to the default style, but this is helpful to distinguish a view explicitly want * to have the default icon. + * @hide */ public static final int STYLE_NOT_SPECIFIED = 1; @@ -135,10 +136,11 @@ public final class PointerIcon implements Parcelable { // conflicts with any system styles that may be defined in the future. private static final int STYLE_OEM_FIRST = 10000; - /** {@hide} The default pointer icon. */ + /** The default pointer icon. */ public static final int STYLE_DEFAULT = STYLE_ARROW; private static final PointerIcon gNullIcon = new PointerIcon(STYLE_NULL); + private static final SparseArray<PointerIcon> gSystemIcons = new SparseArray<PointerIcon>(); private final int mStyle; private int mSystemIconResourceId; @@ -160,6 +162,7 @@ public final class PointerIcon implements Parcelable { * @return The null pointer icon. * * @see #STYLE_NULL + * @hide */ public static PointerIcon getNullIcon() { return gNullIcon; @@ -172,8 +175,9 @@ public final class PointerIcon implements Parcelable { * @return The default pointer icon. * * @throws IllegalArgumentException if context is null. + * @hide */ - public static PointerIcon getDefaultIcon(Context context) { + public static PointerIcon getDefaultIcon(@NonNull Context context) { return getSystemIcon(context, STYLE_DEFAULT); } @@ -187,7 +191,7 @@ public final class PointerIcon implements Parcelable { * * @throws IllegalArgumentException if context is null. */ - public static PointerIcon getSystemIcon(Context context, int style) { + public static PointerIcon getSystemIcon(@NonNull Context context, int style) { if (context == null) { throw new IllegalArgumentException("context must not be null"); } @@ -196,6 +200,11 @@ public final class PointerIcon implements Parcelable { return gNullIcon; } + PointerIcon icon = gSystemIcons.get(style); + if (icon != null) { + return icon; + } + int styleIndex = getSystemIconStyleIndex(style); if (styleIndex == 0) { styleIndex = getSystemIconStyleIndex(STYLE_DEFAULT); @@ -217,12 +226,13 @@ public final class PointerIcon implements Parcelable { return style == STYLE_DEFAULT ? gNullIcon : getSystemIcon(context, STYLE_DEFAULT); } - PointerIcon icon = new PointerIcon(style); + icon = new PointerIcon(style); if ((resourceId & 0xff000000) == 0x01000000) { icon.mSystemIconResourceId = resourceId; } else { icon.loadResource(context, context.getResources(), resourceId); } + gSystemIcons.append(style, icon); return icon; } @@ -239,7 +249,8 @@ public final class PointerIcon implements Parcelable { * @throws IllegalArgumentException if bitmap is null, or if the x/y hotspot * parameters are invalid. */ - public static PointerIcon createCustomIcon(Bitmap bitmap, float hotSpotX, float hotSpotY) { + public static PointerIcon createCustomIcon( + @NonNull Bitmap bitmap, float hotSpotX, float hotSpotY) { if (bitmap == null) { throw new IllegalArgumentException("bitmap must not be null"); } @@ -273,7 +284,7 @@ public final class PointerIcon implements Parcelable { * @throws Resources.NotFoundException if the resource was not found or the drawable * linked in the resource was not found. */ - public static PointerIcon loadCustomIcon(Resources resources, @XmlRes int resourceId) { + public static PointerIcon loadCustomIcon(@NonNull Resources resources, @XmlRes int resourceId) { if (resources == null) { throw new IllegalArgumentException("resources must not be null"); } @@ -291,10 +302,9 @@ public final class PointerIcon implements Parcelable { * @return The loaded pointer icon. * * @throws IllegalArgumentException if context is null. - * @see #isLoaded() * @hide */ - public PointerIcon load(Context context) { + public PointerIcon load(@NonNull Context context) { if (context == null) { throw new IllegalArgumentException("context must not be null"); } @@ -309,83 +319,11 @@ public final class PointerIcon implements Parcelable { return result; } - /** - * Returns true if the pointer icon style is {@link #STYLE_NULL}. - * - * @return True if the pointer icon style is {@link #STYLE_NULL}. - */ - public boolean isNullIcon() { - return mStyle == STYLE_NULL; - } - - /** - * Returns true if the pointer icon has been loaded and its bitmap and hotspot - * information are available. - * - * @return True if the pointer icon is loaded. - * @see #load(Context) - */ - public boolean isLoaded() { - return mBitmap != null || mStyle == STYLE_NULL; - } - - /** - * Gets the style of the pointer icon. - * - * @return The pointer icon style. - */ + /** @hide */ public int getStyle() { return mStyle; } - /** - * Gets the bitmap of the pointer icon. - * - * @return The pointer icon bitmap, or null if the style is {@link #STYLE_NULL}. - * - * @throws IllegalStateException if the bitmap is not loaded. - * @see #isLoaded() - * @see #load(Context) - */ - public Bitmap getBitmap() { - throwIfIconIsNotLoaded(); - return mBitmap; - } - - /** - * Gets the X offset of the pointer icon hotspot. - * - * @return The hotspot X offset. - * - * @throws IllegalStateException if the bitmap is not loaded. - * @see #isLoaded() - * @see #load(Context) - */ - public float getHotSpotX() { - throwIfIconIsNotLoaded(); - return mHotSpotX; - } - - /** - * Gets the Y offset of the pointer icon hotspot. - * - * @return The hotspot Y offset. - * - * @throws IllegalStateException if the bitmap is not loaded. - * @see #isLoaded() - * @see #load(Context) - */ - public float getHotSpotY() { - throwIfIconIsNotLoaded(); - return mHotSpotY; - } - - private void throwIfIconIsNotLoaded() { - if (!isLoaded()) { - throw new IllegalStateException("The icon is not loaded."); - } - } - public static final Parcelable.Creator<PointerIcon> CREATOR = new Parcelable.Creator<PointerIcon>() { public PointerIcon createFromParcel(Parcel in) { diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 3db18066c296..236864285546 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -2628,7 +2628,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, static final int PFLAG3_POINTER_ICON_LSHIFT = 15; /** - * Value indicating {@link PointerIcon.STYLE_NOT_SPECIFIED}. + * Value indicating no specific pointer icons. */ private static final int PFLAG3_POINTER_ICON_NOT_SPECIFIED = 0 << PFLAG3_POINTER_ICON_LSHIFT; @@ -2638,14 +2638,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private static final int PFLAG3_POINTER_ICON_NULL = 1 << PFLAG3_POINTER_ICON_LSHIFT; /** - * Value incicating {@link PointerIcon.STYLE_CUSTOM}. - */ - private static final int PFLAG3_POINTER_ICON_CUSTOM = 2 << PFLAG3_POINTER_ICON_LSHIFT; - - /** * The base value for other pointer icon shapes. */ - private static final int PFLAG3_POINTER_ICON_VALUE_START = 3 << PFLAG3_POINTER_ICON_LSHIFT; + private static final int PFLAG3_POINTER_ICON_VALUE_START = 2 << PFLAG3_POINTER_ICON_LSHIFT; /** * Always allow a user to over-scroll this view, provided it is a @@ -3927,6 +3922,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private HandlerActionQueue mRunQueue; /** + * The pointer icon when the mouse hovers on this view. The default is null. + */ + private PointerIcon mPointerIcon; + + /** * @hide */ String mStartActivityRequestWho; @@ -4490,7 +4490,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, case R.styleable.View_pointerShape: final int pointerShape = a.getInt(attr, PointerIcon.STYLE_NOT_SPECIFIED); if (pointerShape != PointerIcon.STYLE_NOT_SPECIFIED) { - setPointerShape(pointerShape); + setPointerIcon(PointerIcon.getSystemIcon(context, pointerShape)); } break; } @@ -21191,42 +21191,25 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } } - /** @hide */ - public int getPointerShape(MotionEvent event, float x, float y) { - final int value = (mPrivateFlags3 & PFLAG3_POINTER_ICON_MASK); - switch (value) { - case PFLAG3_POINTER_ICON_NOT_SPECIFIED: - return PointerIcon.STYLE_NOT_SPECIFIED; - case PFLAG3_POINTER_ICON_NULL: - return PointerIcon.STYLE_NULL; - case PFLAG3_POINTER_ICON_CUSTOM: - return PointerIcon.STYLE_CUSTOM; - default: - return ((value - PFLAG3_POINTER_ICON_VALUE_START) >> PFLAG3_POINTER_ICON_LSHIFT) - + PointerIcon.STYLE_ARROW; - } + /** + * 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 x The x position of the event, local to the view + * @param y The y position of the event, local to the view + * @see PointerIcon + */ + public PointerIcon getPointerIcon(MotionEvent event, float x, float y) { + return mPointerIcon; } - /** @hide */ - public void setPointerShape(int pointerShape) { - int newValue; - if (pointerShape == PointerIcon.STYLE_NOT_SPECIFIED) { - newValue = PFLAG3_POINTER_ICON_NOT_SPECIFIED; - } else if (pointerShape == PointerIcon.STYLE_NULL) { - newValue = PFLAG3_POINTER_ICON_NULL; - } else if (pointerShape == PointerIcon.STYLE_CUSTOM) { - newValue = PFLAG3_POINTER_ICON_CUSTOM; - } else if (pointerShape >= PointerIcon.STYLE_ARROW - && pointerShape <= PointerIcon.STYLE_GRABBING) { - newValue = ((pointerShape - PointerIcon.STYLE_ARROW) << PFLAG3_POINTER_ICON_LSHIFT) - + PFLAG3_POINTER_ICON_VALUE_START; - } else { - Log.w(VIEW_LOG_TAG, "Invalid pointer shape " + pointerShape + " is specified."); - return; - } - if (newValue != (mPrivateFlags3 & PFLAG3_POINTER_ICON_MASK)) { - mPrivateFlags3 = (mPrivateFlags3 & ~PFLAG3_POINTER_ICON_MASK) | newValue; - } + /** + * Set the pointer icon for the current view. + * @param pointerIcon A PointerIcon instance which will be shown when the mouse hovers. + */ + public void setPointerIcon(PointerIcon pointerIcon) { + mPointerIcon = pointerIcon; } // diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 0f7d296a1555..cd93dab0c48b 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -1715,9 +1715,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager return false; } - /** @hide */ @Override - public int getPointerShape(MotionEvent event, float x, float y) { + public PointerIcon getPointerIcon(MotionEvent event, float x, float y) { // Check what the child under the pointer says about the pointer. final int childrenCount = mChildrenCount; if (childrenCount != 0) { @@ -1731,9 +1730,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager ? children[childIndex] : preorderedList.get(childIndex); PointF point = getLocalPoint(); if (isTransformedTouchPointInView(x, y, child, point)) { - final int pointerShape = child.getPointerShape(event, point.x, point.y); - if (pointerShape != PointerIcon.STYLE_NOT_SPECIFIED) { - return pointerShape; + final PointerIcon pointerIcon = child.getPointerIcon(event, point.x, point.y); + if (pointerIcon != null) { + return pointerIcon; } break; } @@ -1742,7 +1741,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager // The pointer is not a child or the child has no preferences, returning the default // implementation. - return super.getPointerShape(event, x, y); + return super.getPointerIcon(event, x, y); } /** diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 12cf66ed3b3a..faf26405c199 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -332,6 +332,7 @@ public final class ViewRootImpl implements ViewParent, private int mFpsNumFrames; private int mPointerIconShape = PointerIcon.STYLE_NOT_SPECIFIED; + private PointerIcon mCustomPointerIcon = null; /** * see {@link #playSoundEffect(int)} @@ -4210,16 +4211,23 @@ public final class ViewRootImpl implements ViewParent, final float y = event.getY(); if (event.getActionMasked() != MotionEvent.ACTION_HOVER_EXIT && x >= 0 && x < mView.getWidth() && y >= 0 && y < mView.getHeight()) { - int pointerShape = mView.getPointerShape(event, x, y); - if (pointerShape == PointerIcon.STYLE_NOT_SPECIFIED) { - pointerShape = PointerIcon.STYLE_DEFAULT; - } - - if (mPointerIconShape != pointerShape) { - mPointerIconShape = pointerShape; - final InputDevice inputDevice = event.getDevice(); - if (inputDevice != null) { - inputDevice.setPointerShape(pointerShape); + PointerIcon pointerIcon = mView.getPointerIcon(event, x, y); + int pointerShape = (pointerIcon != null) ? + pointerIcon.getStyle() : PointerIcon.STYLE_DEFAULT; + + final InputDevice inputDevice = event.getDevice(); + if (inputDevice != null) { + if (mPointerIconShape != pointerShape) { + mPointerIconShape = pointerShape; + if (mPointerIconShape != PointerIcon.STYLE_CUSTOM) { + mCustomPointerIcon = null; + inputDevice.setPointerShape(pointerShape); + } + } + if (mPointerIconShape == PointerIcon.STYLE_CUSTOM && + !pointerIcon.equals(mCustomPointerIcon)) { + mCustomPointerIcon = pointerIcon; + inputDevice.setCustomPointerIcon(mCustomPointerIcon); } } } else if (event.getActionMasked() == MotionEvent.ACTION_HOVER_MOVE) { diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 5574f86795fb..17c803f76cbb 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -5955,15 +5955,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return mLayout != null ? mLayout.getHeight() : 0; } - /** - * @hide - */ @Override - public int getPointerShape(MotionEvent event, float x, float y) { + public PointerIcon getPointerIcon(MotionEvent event, float x, float y) { if (isTextSelectable() || isTextEditable()) { - return PointerIcon.STYLE_TEXT; + return PointerIcon.getSystemIcon(mContext, PointerIcon.STYLE_TEXT); } - return super.getPointerShape(event, x, y); + return super.getPointerIcon(event, x, y); } @Override diff --git a/core/jni/android_view_PointerIcon.cpp b/core/jni/android_view_PointerIcon.cpp index d7e2c028a23f..71be52e52e57 100644 --- a/core/jni/android_view_PointerIcon.cpp +++ b/core/jni/android_view_PointerIcon.cpp @@ -65,33 +65,34 @@ status_t android_view_PointerIcon_load(JNIEnv* env, jobject pointerIconObj, jobj return OK; } - jobject loadedPointerIconObj = env->CallObjectMethod(pointerIconObj, - gPointerIconClassInfo.load, contextObj); - if (env->ExceptionCheck() || !loadedPointerIconObj) { + ScopedLocalRef<jobject> loadedPointerIconObj(env, env->CallObjectMethod(pointerIconObj, + gPointerIconClassInfo.load, contextObj)); + if (env->ExceptionCheck() || !loadedPointerIconObj.get()) { ALOGW("An exception occurred while loading a pointer icon."); LOGW_EX(env); env->ExceptionClear(); return UNKNOWN_ERROR; } + return android_view_PointerIcon_getLoadedIcon(env, loadedPointerIconObj.get(), outPointerIcon); +} - outPointerIcon->style = env->GetIntField(loadedPointerIconObj, - gPointerIconClassInfo.mStyle); - outPointerIcon->hotSpotX = env->GetFloatField(loadedPointerIconObj, - gPointerIconClassInfo.mHotSpotX); - outPointerIcon->hotSpotY = env->GetFloatField(loadedPointerIconObj, - gPointerIconClassInfo.mHotSpotY); - - jobject bitmapObj = env->GetObjectField(loadedPointerIconObj, gPointerIconClassInfo.mBitmap); - if (bitmapObj) { - GraphicsJNI::getSkBitmap(env, bitmapObj, &(outPointerIcon->bitmap)); - env->DeleteLocalRef(bitmapObj); +status_t android_view_PointerIcon_getLoadedIcon(JNIEnv* env, jobject pointerIconObj, + PointerIcon* outPointerIcon) { + outPointerIcon->style = env->GetIntField(pointerIconObj, gPointerIconClassInfo.mStyle); + outPointerIcon->hotSpotX = env->GetFloatField(pointerIconObj, gPointerIconClassInfo.mHotSpotX); + outPointerIcon->hotSpotY = env->GetFloatField(pointerIconObj, gPointerIconClassInfo.mHotSpotY); + + ScopedLocalRef<jobject> bitmapObj( + env, env->GetObjectField(pointerIconObj, gPointerIconClassInfo.mBitmap)); + if (bitmapObj.get()) { + GraphicsJNI::getSkBitmap(env, bitmapObj.get(), &(outPointerIcon->bitmap)); } ScopedLocalRef<jobjectArray> bitmapFramesObj(env, reinterpret_cast<jobjectArray>( - env->GetObjectField(loadedPointerIconObj, gPointerIconClassInfo.mBitmapFrames))); + env->GetObjectField(pointerIconObj, gPointerIconClassInfo.mBitmapFrames))); if (bitmapFramesObj.get()) { outPointerIcon->durationPerFrame = env->GetIntField( - loadedPointerIconObj, gPointerIconClassInfo.mDurationPerFrame); + pointerIconObj, gPointerIconClassInfo.mDurationPerFrame); jsize size = env->GetArrayLength(bitmapFramesObj.get()); outPointerIcon->bitmapFrames.resize(size); for (jsize i = 0; i < size; ++i) { @@ -100,7 +101,6 @@ status_t android_view_PointerIcon_load(JNIEnv* env, jobject pointerIconObj, jobj } } - env->DeleteLocalRef(loadedPointerIconObj); return OK; } diff --git a/core/jni/android_view_PointerIcon.h b/core/jni/android_view_PointerIcon.h index ca080850df94..00bdfb4bf04e 100644 --- a/core/jni/android_view_PointerIcon.h +++ b/core/jni/android_view_PointerIcon.h @@ -97,6 +97,11 @@ extern jobject android_view_PointerIcon_getSystemIcon(JNIEnv* env, extern status_t android_view_PointerIcon_load(JNIEnv* env, jobject pointerIconObj, jobject contextObj, PointerIcon* outPointerIcon); +/* Obtain the data of pointerIconObj and put to outPointerIcon. */ +extern status_t android_view_PointerIcon_getLoadedIcon(JNIEnv* env, jobject pointerIconObj, + PointerIcon* outPointerIcon); + + /* Loads the bitmap associated with a pointer icon by style. * If pointerIconObj is NULL, returns OK and a pointer icon with POINTER_ICON_STYLE_NULL. */ extern status_t android_view_PointerIcon_loadSystemIcon(JNIEnv* env, diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp index 6a1167a02c0b..529849e99fb6 100644 --- a/libs/input/PointerController.cpp +++ b/libs/input/PointerController.cpp @@ -439,6 +439,17 @@ void PointerController::updatePointerShape(int32_t iconId) { } } +void PointerController::setCustomPointerIcon(const SpriteIcon& icon) { + AutoMutex _l(mLock); + + const int32_t iconId = mPolicy->getCustomPointerIconId(); + mLocked.additionalMouseResources[iconId] = icon; + mLocked.requestedPointerShape = iconId; + mLocked.presentationChanged = true; + + updatePointerLocked(); +} + void PointerController::handleMessage(const Message& message) { switch (message.what) { case MSG_INACTIVITY_TIMEOUT: diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h index 4fd2d8503272..9ba37b338276 100644 --- a/libs/input/PointerController.h +++ b/libs/input/PointerController.h @@ -67,6 +67,7 @@ public: virtual void loadAdditionalMouseResources(std::map<int32_t, SpriteIcon>* outResources, std::map<int32_t, PointerAnimation>* outAnimationResources) = 0; virtual int32_t getDefaultPointerIconId() = 0; + virtual int32_t getCustomPointerIconId() = 0; }; @@ -105,6 +106,7 @@ public: virtual void clearSpots(); void updatePointerShape(int32_t iconId); + void setCustomPointerIcon(const SpriteIcon& icon); void setDisplayViewport(int32_t width, int32_t height, int32_t orientation); void setInactivityTimeout(InactivityTimeout inactivityTimeout); void reloadPointerResources(); diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java index 93264ff0d003..c01f1703dab6 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java @@ -30,6 +30,7 @@ import android.util.AttributeSet; import android.view.Display; import android.view.DisplayInfo; import android.view.MotionEvent; +import android.view.PointerIcon; import android.view.VelocityTracker; import android.view.View; import android.view.View.OnTouchListener; @@ -118,8 +119,8 @@ public class DividerView extends FrameLayout implements OnTouchListener, updateDisplayInfo(); boolean landscape = getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE; - mHandle.setPointerShape( - landscape ? STYLE_HORIZONTAL_DOUBLE_ARROW : STYLE_VERTICAL_DOUBLE_ARROW); + mHandle.setPointerIcon(PointerIcon.getSystemIcon(getContext(), + landscape ? STYLE_HORIZONTAL_DOUBLE_ARROW : STYLE_VERTICAL_DOUBLE_ARROW)); getViewTreeObserver().addOnComputeInternalInsetsListener(this); } diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index f2d0031fa1c5..8b373834a6b3 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -213,6 +213,7 @@ public class InputManagerService extends IInputManager.Stub private static native void nativeMonitor(long ptr); private static native void nativeSetPointerIconShape(long ptr, int iconId); private static native void nativeReloadPointerIcons(long ptr); + private static native void nativeSetCustomPointerIcon(long ptr, PointerIcon icon); // Input event injection constants defined in InputDispatcher.h. private static final int INPUT_EVENT_INJECTION_SUCCEEDED = 0; @@ -1451,6 +1452,12 @@ public class InputManagerService extends IInputManager.Stub nativeSetPointerIconShape(mPtr, iconId); } + // Binder call + @Override + public void setCustomPointerIcon(PointerIcon icon) { + nativeSetCustomPointerIcon(mPtr, icon); + } + @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP) diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index 9c9a5dae1600..4c8474ab29f1 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -206,6 +206,7 @@ public: void reloadCalibration(); void setPointerIconShape(int32_t iconId); void reloadPointerIcons(); + void setCustomPointerIcon(const SpriteIcon& icon); /* --- InputReaderPolicyInterface implementation --- */ @@ -248,6 +249,7 @@ public: virtual void loadAdditionalMouseResources(std::map<int32_t, SpriteIcon>* outResources, std::map<int32_t, PointerAnimation>* outAnimationResources); virtual int32_t getDefaultPointerIconId(); + virtual int32_t getCustomPointerIconId(); private: sp<InputManager> mInputManager; @@ -790,6 +792,14 @@ void NativeInputManager::reloadPointerIcons() { } } +void NativeInputManager::setCustomPointerIcon(const SpriteIcon& icon) { + AutoMutex _l(mLock); + sp<PointerController> controller = mLocked.pointerController.promote(); + if (controller != NULL) { + controller->setCustomPointerIcon(icon); + } +} + TouchAffineTransformation NativeInputManager::getTouchAffineTransformation( JNIEnv *env, jfloatArray matrixArr) { ScopedFloatArrayRO matrix(env, matrixArr); @@ -1090,6 +1100,10 @@ int32_t NativeInputManager::getDefaultPointerIconId() { return POINTER_ICON_STYLE_ARROW; } +int32_t NativeInputManager::getCustomPointerIconId() { + return POINTER_ICON_STYLE_CUSTOM; +} + // ---------------------------------------------------------------------------- static jlong nativeInit(JNIEnv* env, jclass /* clazz */, @@ -1437,6 +1451,20 @@ static void nativeReloadPointerIcons(JNIEnv* /* env */, jclass /* clazz */, jlon im->reloadPointerIcons(); } +static void nativeSetCustomPointerIcon(JNIEnv* env, jclass /* clazz */, + jlong ptr, jobject iconObj) { + NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); + + PointerIcon pointerIcon; + android_view_PointerIcon_getLoadedIcon(env, iconObj, &pointerIcon); + + SpriteIcon spriteIcon; + pointerIcon.bitmap.copyTo(&spriteIcon.bitmap, kN32_SkColorType); + spriteIcon.hotSpotX = pointerIcon.hotSpotX; + spriteIcon.hotSpotY = pointerIcon.hotSpotY; + im->setCustomPointerIcon(spriteIcon); +} + // ---------------------------------------------------------------------------- static const JNINativeMethod gInputManagerMethods[] = { @@ -1499,6 +1527,8 @@ static const JNINativeMethod gInputManagerMethods[] = { (void*) nativeSetPointerIconShape }, { "nativeReloadPointerIcons", "(J)V", (void*) nativeReloadPointerIcons }, + { "nativeSetCustomPointerIcon", "(JLandroid/view/PointerIcon;)V", + (void*) nativeSetCustomPointerIcon }, }; #define FIND_CLASS(var, className) \ |