summaryrefslogtreecommitdiff
path: root/core/java/android
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android')
-rw-r--r--core/java/android/hardware/input/IInputManager.aidl2
-rw-r--r--core/java/android/hardware/input/InputManager.java10
-rw-r--r--core/java/android/view/InputDevice.java9
-rw-r--r--core/java/android/view/PointerIcon.java106
-rw-r--r--core/java/android/view/View.java67
-rw-r--r--core/java/android/view/ViewGroup.java11
-rw-r--r--core/java/android/view/ViewRootImpl.java28
-rw-r--r--core/java/android/widget/TextView.java9
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