12352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown/* 22352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * Copyright (C) 2011 The Android Open Source Project 32352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * 42352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * Licensed under the Apache License, Version 2.0 (the "License"); 52352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * you may not use this file except in compliance with the License. 62352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * You may obtain a copy of the License at 72352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * 82352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * http://www.apache.org/licenses/LICENSE-2.0 92352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * 102352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * Unless required by applicable law or agreed to in writing, software 112352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * distributed under the License is distributed on an "AS IS" BASIS, 122352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 132352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * See the License for the specific language governing permissions and 142352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * limitations under the License. 152352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown */ 162352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 172352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brownpackage android.view; 182352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 192352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brownimport com.android.internal.util.XmlUtils; 202352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 212352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brownimport android.content.Context; 222352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brownimport android.content.res.Resources; 232352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brownimport android.content.res.TypedArray; 242352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brownimport android.content.res.XmlResourceParser; 252352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brownimport android.graphics.Bitmap; 262352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brownimport android.graphics.drawable.BitmapDrawable; 272352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brownimport android.graphics.drawable.Drawable; 282352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brownimport android.os.Parcel; 292352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brownimport android.os.Parcelable; 302352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brownimport android.util.Log; 312352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 322352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown/** 332352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * Represents an icon that can be used as a mouse pointer. 342352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * <p> 352352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * Pointer icons can be provided either by the system using system styles, 362352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * or by applications using bitmaps or application resources. 372352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * </p> 382352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * 392352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * @hide 402352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown */ 412352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brownpublic final class PointerIcon implements Parcelable { 422352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown private static final String TAG = "PointerIcon"; 432352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 442352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown /** Style constant: Custom icon with a user-supplied bitmap. */ 452352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown public static final int STYLE_CUSTOM = -1; 462352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 472352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown /** Style constant: Null icon. It has no bitmap. */ 482352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown public static final int STYLE_NULL = 0; 492352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 502352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown /** Style constant: Arrow icon. (Default mouse pointer) */ 512352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown public static final int STYLE_ARROW = 1000; 522352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 532352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown /** {@hide} Style constant: Spot hover icon for touchpads. */ 542352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown public static final int STYLE_SPOT_HOVER = 2000; 552352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 562352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown /** {@hide} Style constant: Spot touch icon for touchpads. */ 572352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown public static final int STYLE_SPOT_TOUCH = 2001; 582352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 592352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown /** {@hide} Style constant: Spot anchor icon for touchpads. */ 602352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown public static final int STYLE_SPOT_ANCHOR = 2002; 612352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 622352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown // OEM private styles should be defined starting at this range to avoid 632352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown // conflicts with any system styles that may be defined in the future. 642352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown private static final int STYLE_OEM_FIRST = 10000; 652352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 662352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown // The default pointer icon. 672352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown private static final int STYLE_DEFAULT = STYLE_ARROW; 682352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 692352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown private static final PointerIcon gNullIcon = new PointerIcon(STYLE_NULL); 702352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 712352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown private final int mStyle; 722352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown private int mSystemIconResourceId; 732352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown private Bitmap mBitmap; 742352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown private float mHotSpotX; 752352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown private float mHotSpotY; 762352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 772352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown private PointerIcon(int style) { 782352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown mStyle = style; 792352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } 802352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 812352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown /** 822352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * Gets a special pointer icon that has no bitmap. 832352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * 842352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * @return The null pointer icon. 852352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * 862352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * @see #STYLE_NULL 872352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown */ 882352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown public static PointerIcon getNullIcon() { 892352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown return gNullIcon; 902352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } 912352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 922352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown /** 932352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * Gets the default pointer icon. 942352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * 952352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * @param context The context. 962352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * @return The default pointer icon. 972352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * 982352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * @throws IllegalArgumentException if context is null. 992352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown */ 1002352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown public static PointerIcon getDefaultIcon(Context context) { 1012352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown return getSystemIcon(context, STYLE_DEFAULT); 1022352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } 1032352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 1042352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown /** 1052352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * Gets a system pointer icon for the given style. 1062352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * If style is not recognized, returns the default pointer icon. 1072352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * 1082352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * @param context The context. 1092352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * @param style The pointer icon style. 1102352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * @return The pointer icon. 1112352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * 1122352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * @throws IllegalArgumentException if context is null. 1132352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown */ 1142352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown public static PointerIcon getSystemIcon(Context context, int style) { 1152352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown if (context == null) { 1162352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown throw new IllegalArgumentException("context must not be null"); 1172352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } 1182352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 1192352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown if (style == STYLE_NULL) { 1202352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown return gNullIcon; 1212352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } 1222352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 1232352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown int styleIndex = getSystemIconStyleIndex(style); 1242352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown if (styleIndex == 0) { 1252352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown styleIndex = getSystemIconStyleIndex(STYLE_DEFAULT); 1262352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } 1272352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 1282352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown TypedArray a = context.obtainStyledAttributes(null, 1292352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown com.android.internal.R.styleable.Pointer, 1302352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown com.android.internal.R.attr.pointerStyle, 0); 1312352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown int resourceId = a.getResourceId(styleIndex, -1); 1322352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown a.recycle(); 1332352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 1342352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown if (resourceId == -1) { 1352352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown Log.w(TAG, "Missing theme resources for pointer icon style " + style); 1362352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown return style == STYLE_DEFAULT ? gNullIcon : getSystemIcon(context, STYLE_DEFAULT); 1372352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } 1382352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 1392352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown PointerIcon icon = new PointerIcon(style); 1402352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown if ((resourceId & 0xff000000) == 0x01000000) { 1412352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown icon.mSystemIconResourceId = resourceId; 1422352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } else { 1438eea3ea5591e59f55cbb4f6b2b7e9363a285ced3Alan Viverette icon.loadResource(context, context.getResources(), resourceId); 1442352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } 1452352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown return icon; 1462352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } 1472352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 1482352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown /** 1492352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * Creates a custom pointer from the given bitmap and hotspot information. 1502352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * 1512352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * @param bitmap The bitmap for the icon. 152376d10e99e7db597fdff8a4e8f396161017c243cAlan Viverette * @param hotSpotX The X offset of the pointer icon hotspot in the bitmap. 1532352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * Must be within the [0, bitmap.getWidth()) range. 154376d10e99e7db597fdff8a4e8f396161017c243cAlan Viverette * @param hotSpotY The Y offset of the pointer icon hotspot in the bitmap. 1552352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * Must be within the [0, bitmap.getHeight()) range. 1562352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * @return A pointer icon for this bitmap. 1572352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * 1582352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * @throws IllegalArgumentException if bitmap is null, or if the x/y hotspot 1592352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * parameters are invalid. 1602352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown */ 1612352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown public static PointerIcon createCustomIcon(Bitmap bitmap, float hotSpotX, float hotSpotY) { 1622352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown if (bitmap == null) { 1632352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown throw new IllegalArgumentException("bitmap must not be null"); 1642352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } 1652352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown validateHotSpot(bitmap, hotSpotX, hotSpotY); 1662352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 1672352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown PointerIcon icon = new PointerIcon(STYLE_CUSTOM); 1682352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown icon.mBitmap = bitmap; 1692352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown icon.mHotSpotX = hotSpotX; 1702352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown icon.mHotSpotY = hotSpotY; 1712352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown return icon; 1722352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } 1732352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 1742352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown /** 1752352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * Loads a custom pointer icon from an XML resource. 1762352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * <p> 1772352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * The XML resource should have the following form: 1782352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * <code> 1792352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * <?xml version="1.0" encoding="utf-8"?> 1802352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * <pointer-icon xmlns:android="http://schemas.android.com/apk/res/android" 1812352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * android:bitmap="@drawable/my_pointer_bitmap" 1822352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * android:hotSpotX="24" 1832352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * android:hotSpotY="24" /> 1842352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * </code> 1852352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * </p> 1862352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * 1872352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * @param resources The resources object. 1882352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * @param resourceId The resource id. 1892352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * @return The pointer icon. 1902352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * 1912352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * @throws IllegalArgumentException if resources is null. 1922352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * @throws Resources.NotFoundException if the resource was not found or the drawable 1932352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * linked in the resource was not found. 1942352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown */ 1952352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown public static PointerIcon loadCustomIcon(Resources resources, int resourceId) { 1962352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown if (resources == null) { 1972352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown throw new IllegalArgumentException("resources must not be null"); 1982352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } 1992352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 2002352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown PointerIcon icon = new PointerIcon(STYLE_CUSTOM); 2018eea3ea5591e59f55cbb4f6b2b7e9363a285ced3Alan Viverette icon.loadResource(null, resources, resourceId); 2022352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown return icon; 2032352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } 2042352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 2052352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown /** 2062352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * Loads the bitmap and hotspot information for a pointer icon, if it is not already loaded. 2072352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * Returns a pointer icon (not necessarily the same instance) with the information filled in. 2082352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * 2092352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * @param context The context. 2102352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * @return The loaded pointer icon. 2112352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * 2122352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * @throws IllegalArgumentException if context is null. 2132352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * @see #isLoaded() 2142352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * @hide 2152352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown */ 2162352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown public PointerIcon load(Context context) { 2172352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown if (context == null) { 2182352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown throw new IllegalArgumentException("context must not be null"); 2192352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } 2202352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 2212352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown if (mSystemIconResourceId == 0 || mBitmap != null) { 2222352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown return this; 2232352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } 2242352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 2252352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown PointerIcon result = new PointerIcon(mStyle); 2262352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown result.mSystemIconResourceId = mSystemIconResourceId; 2278eea3ea5591e59f55cbb4f6b2b7e9363a285ced3Alan Viverette result.loadResource(context, context.getResources(), mSystemIconResourceId); 2282352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown return result; 2292352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } 2302352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 2312352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown /** 2322352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * Returns true if the pointer icon style is {@link #STYLE_NULL}. 2332352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * 2342352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * @return True if the pointer icon style is {@link #STYLE_NULL}. 2352352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown */ 2362352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown public boolean isNullIcon() { 2372352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown return mStyle == STYLE_NULL; 2382352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } 2392352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 2402352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown /** 2412352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * Returns true if the pointer icon has been loaded and its bitmap and hotspot 2422352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * information are available. 2432352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * 2442352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * @return True if the pointer icon is loaded. 2452352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * @see #load(Context) 2462352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown */ 2472352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown public boolean isLoaded() { 2482352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown return mBitmap != null || mStyle == STYLE_NULL; 2492352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } 2502352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 2512352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown /** 2522352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * Gets the style of the pointer icon. 2532352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * 2542352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * @return The pointer icon style. 2552352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown */ 2562352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown public int getStyle() { 2572352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown return mStyle; 2582352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } 2592352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 2602352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown /** 2612352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * Gets the bitmap of the pointer icon. 2622352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * 2632352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * @return The pointer icon bitmap, or null if the style is {@link #STYLE_NULL}. 2642352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * 2652352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * @throws IllegalStateException if the bitmap is not loaded. 2662352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * @see #isLoaded() 2672352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * @see #load(Context) 2682352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown */ 2692352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown public Bitmap getBitmap() { 2702352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown throwIfIconIsNotLoaded(); 2712352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown return mBitmap; 2722352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } 2732352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 2742352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown /** 2752352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * Gets the X offset of the pointer icon hotspot. 2762352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * 2772352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * @return The hotspot X offset. 2782352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * 2792352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * @throws IllegalStateException if the bitmap is not loaded. 2802352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * @see #isLoaded() 2812352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * @see #load(Context) 2822352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown */ 2832352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown public float getHotSpotX() { 2842352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown throwIfIconIsNotLoaded(); 2852352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown return mHotSpotX; 2862352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } 2872352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 2882352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown /** 2892352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * Gets the Y offset of the pointer icon hotspot. 2902352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * 2912352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * @return The hotspot Y offset. 2922352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * 2932352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * @throws IllegalStateException if the bitmap is not loaded. 2942352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * @see #isLoaded() 2952352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * @see #load(Context) 2962352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown */ 2972352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown public float getHotSpotY() { 2982352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown throwIfIconIsNotLoaded(); 2992352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown return mHotSpotY; 3002352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } 3012352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 3022352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown private void throwIfIconIsNotLoaded() { 3032352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown if (!isLoaded()) { 3042352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown throw new IllegalStateException("The icon is not loaded."); 3052352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } 3062352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } 3072352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 3082352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown public static final Parcelable.Creator<PointerIcon> CREATOR 3092352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown = new Parcelable.Creator<PointerIcon>() { 3102352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown public PointerIcon createFromParcel(Parcel in) { 3112352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown int style = in.readInt(); 3122352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown if (style == STYLE_NULL) { 3132352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown return getNullIcon(); 3142352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } 3152352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 3162352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown int systemIconResourceId = in.readInt(); 3172352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown if (systemIconResourceId != 0) { 3182352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown PointerIcon icon = new PointerIcon(style); 3192352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown icon.mSystemIconResourceId = systemIconResourceId; 3202352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown return icon; 3212352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } 3222352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 3232352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown Bitmap bitmap = Bitmap.CREATOR.createFromParcel(in); 3242352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown float hotSpotX = in.readFloat(); 3252352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown float hotSpotY = in.readFloat(); 3262352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown return PointerIcon.createCustomIcon(bitmap, hotSpotX, hotSpotY); 3272352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } 3282352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 3292352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown public PointerIcon[] newArray(int size) { 3302352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown return new PointerIcon[size]; 3312352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } 3322352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown }; 3332352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 3342352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown public int describeContents() { 3352352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown return 0; 3362352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } 3372352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 3382352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown public void writeToParcel(Parcel out, int flags) { 3392352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown out.writeInt(mStyle); 3402352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 3412352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown if (mStyle != STYLE_NULL) { 3422352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown out.writeInt(mSystemIconResourceId); 3432352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown if (mSystemIconResourceId == 0) { 3442352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown mBitmap.writeToParcel(out, flags); 3452352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown out.writeFloat(mHotSpotX); 3462352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown out.writeFloat(mHotSpotY); 3472352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } 3482352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } 3492352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } 3502352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 3512352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown @Override 3522352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown public boolean equals(Object other) { 3532352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown if (this == other) { 3542352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown return true; 3552352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } 3562352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 3572352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown if (other == null || !(other instanceof PointerIcon)) { 3582352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown return false; 3592352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } 3602352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 3612352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown PointerIcon otherIcon = (PointerIcon) other; 3622352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown if (mStyle != otherIcon.mStyle 3632352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown || mSystemIconResourceId != otherIcon.mSystemIconResourceId) { 3642352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown return false; 3652352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } 3662352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 3672352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown if (mSystemIconResourceId == 0 && (mBitmap != otherIcon.mBitmap 3682352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown || mHotSpotX != otherIcon.mHotSpotX 3692352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown || mHotSpotY != otherIcon.mHotSpotY)) { 3702352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown return false; 3712352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } 3722352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 3732352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown return true; 3742352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } 3752352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 3768eea3ea5591e59f55cbb4f6b2b7e9363a285ced3Alan Viverette private void loadResource(Context context, Resources resources, int resourceId) { 377376d10e99e7db597fdff8a4e8f396161017c243cAlan Viverette final XmlResourceParser parser = resources.getXml(resourceId); 3782352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown final int bitmapRes; 3792352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown final float hotSpotX; 3802352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown final float hotSpotY; 3812352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown try { 3822352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown XmlUtils.beginDocument(parser, "pointer-icon"); 3832352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 384376d10e99e7db597fdff8a4e8f396161017c243cAlan Viverette final TypedArray a = resources.obtainAttributes( 3852352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown parser, com.android.internal.R.styleable.PointerIcon); 3862352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown bitmapRes = a.getResourceId(com.android.internal.R.styleable.PointerIcon_bitmap, 0); 387376d10e99e7db597fdff8a4e8f396161017c243cAlan Viverette hotSpotX = a.getDimension(com.android.internal.R.styleable.PointerIcon_hotSpotX, 0); 388376d10e99e7db597fdff8a4e8f396161017c243cAlan Viverette hotSpotY = a.getDimension(com.android.internal.R.styleable.PointerIcon_hotSpotY, 0); 3892352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown a.recycle(); 3902352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } catch (Exception ex) { 3912352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown throw new IllegalArgumentException("Exception parsing pointer icon resource.", ex); 3922352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } finally { 3932352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown parser.close(); 3942352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } 3952352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 3962352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown if (bitmapRes == 0) { 3972352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown throw new IllegalArgumentException("<pointer-icon> is missing bitmap attribute."); 3982352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } 3992352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 4008eea3ea5591e59f55cbb4f6b2b7e9363a285ced3Alan Viverette Drawable drawable; 4018eea3ea5591e59f55cbb4f6b2b7e9363a285ced3Alan Viverette if (context == null) { 4028eea3ea5591e59f55cbb4f6b2b7e9363a285ced3Alan Viverette drawable = resources.getDrawable(bitmapRes); 4038eea3ea5591e59f55cbb4f6b2b7e9363a285ced3Alan Viverette } else { 4048eea3ea5591e59f55cbb4f6b2b7e9363a285ced3Alan Viverette drawable = context.getDrawable(bitmapRes); 4058eea3ea5591e59f55cbb4f6b2b7e9363a285ced3Alan Viverette } 4062352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown if (!(drawable instanceof BitmapDrawable)) { 4072352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown throw new IllegalArgumentException("<pointer-icon> bitmap attribute must " 4082352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown + "refer to a bitmap drawable."); 4092352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } 4102352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 4112352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown // Set the properties now that we have successfully loaded the icon. 4122352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown mBitmap = ((BitmapDrawable)drawable).getBitmap(); 4132352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown mHotSpotX = hotSpotX; 4142352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown mHotSpotY = hotSpotY; 4152352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } 4162352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 4172352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown private static void validateHotSpot(Bitmap bitmap, float hotSpotX, float hotSpotY) { 4182352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown if (hotSpotX < 0 || hotSpotX >= bitmap.getWidth()) { 4192352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown throw new IllegalArgumentException("x hotspot lies outside of the bitmap area"); 4202352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } 4212352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown if (hotSpotY < 0 || hotSpotY >= bitmap.getHeight()) { 4222352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown throw new IllegalArgumentException("y hotspot lies outside of the bitmap area"); 4232352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } 4242352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } 4252352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown 4262352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown private static int getSystemIconStyleIndex(int style) { 4272352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown switch (style) { 4282352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown case STYLE_ARROW: 4292352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown return com.android.internal.R.styleable.Pointer_pointerIconArrow; 4302352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown case STYLE_SPOT_HOVER: 4312352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown return com.android.internal.R.styleable.Pointer_pointerIconSpotHover; 4322352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown case STYLE_SPOT_TOUCH: 4332352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown return com.android.internal.R.styleable.Pointer_pointerIconSpotTouch; 4342352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown case STYLE_SPOT_ANCHOR: 4352352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown return com.android.internal.R.styleable.Pointer_pointerIconSpotAnchor; 4362352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown default: 4372352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown return 0; 4382352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } 4392352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown } 4402352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown} 441