diff options
Diffstat (limited to 'core/java/android')
| -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 |
8 files changed, 94 insertions, 148 deletions
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 |
