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
19d4eaef7f4c5a5d281de4fff272cd33e892e26264Jun Mukaiimport android.annotation.NonNull;
20d4eaef7f4c5a5d281de4fff272cd33e892e26264Jun Mukaiimport android.util.SparseArray;
212352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brownimport com.android.internal.util.XmlUtils;
222352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown
237b9c912f536925ac6ec43935d6e97506851b33d6Tor Norbyeimport android.annotation.XmlRes;
242352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brownimport android.content.Context;
252352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brownimport android.content.res.Resources;
262352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brownimport android.content.res.TypedArray;
272352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brownimport android.content.res.XmlResourceParser;
282352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brownimport android.graphics.Bitmap;
29808196f139e93395f1f331f6c7e92ddd66c05979Jun Mukaiimport android.graphics.drawable.AnimationDrawable;
302352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brownimport android.graphics.drawable.BitmapDrawable;
312352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brownimport android.graphics.drawable.Drawable;
322352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brownimport android.os.Parcel;
332352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brownimport android.os.Parcelable;
342352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brownimport android.util.Log;
352352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown
362352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown/**
372352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * Represents an icon that can be used as a mouse pointer.
382352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * <p>
39f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright * Pointer icons can be provided either by the system using system types,
402352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * or by applications using bitmaps or application resources.
412352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown * </p>
422352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown */
432352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brownpublic final class PointerIcon implements Parcelable {
442352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown    private static final String TAG = "PointerIcon";
452352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown
46f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    /** {@hide} Type constant: Custom icon with a user-supplied bitmap. */
47f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    public static final int TYPE_CUSTOM = -1;
482352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown
49f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    /** Type constant: Null icon.  It has no bitmap. */
50f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    public static final int TYPE_NULL = 0;
512352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown
52f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    /** Type constant: no icons are specified. If all views uses this, then falls back
53f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright     * to the default type, but this is helpful to distinguish a view explicitly want
541db5397d88e722b1ab82ccb2b429ceec1179ccd8Jun Mukai     * to have the default icon.
55d4eaef7f4c5a5d281de4fff272cd33e892e26264Jun Mukai     * @hide
561db5397d88e722b1ab82ccb2b429ceec1179ccd8Jun Mukai     */
57f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    public static final int TYPE_NOT_SPECIFIED = 1;
581db5397d88e722b1ab82ccb2b429ceec1179ccd8Jun Mukai
59f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    /** Type constant: Arrow icon.  (Default mouse pointer) */
60f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    public static final int TYPE_ARROW = 1000;
612352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown
62f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    /** {@hide} Type constant: Spot hover icon for touchpads. */
63f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    public static final int TYPE_SPOT_HOVER = 2000;
642352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown
65f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    /** {@hide} Type constant: Spot touch icon for touchpads. */
66f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    public static final int TYPE_SPOT_TOUCH = 2001;
672352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown
68f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    /** {@hide} Type constant: Spot anchor icon for touchpads. */
69f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    public static final int TYPE_SPOT_ANCHOR = 2002;
702352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown
71f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    // Type constants for additional predefined icons for mice.
72f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    /** Type constant: context-menu. */
73f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    public static final int TYPE_CONTEXT_MENU = 1001;
741db5397d88e722b1ab82ccb2b429ceec1179ccd8Jun Mukai
75f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    /** Type constant: hand. */
76f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    public static final int TYPE_HAND = 1002;
771db5397d88e722b1ab82ccb2b429ceec1179ccd8Jun Mukai
78f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    /** Type constant: help. */
79f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    public static final int TYPE_HELP = 1003;
801db5397d88e722b1ab82ccb2b429ceec1179ccd8Jun Mukai
81f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    /** Type constant: wait. */
82f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    public static final int TYPE_WAIT = 1004;
831db5397d88e722b1ab82ccb2b429ceec1179ccd8Jun Mukai
84f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    /** Type constant: cell. */
85f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    public static final int TYPE_CELL = 1006;
861db5397d88e722b1ab82ccb2b429ceec1179ccd8Jun Mukai
87f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    /** Type constant: crosshair. */
88f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    public static final int TYPE_CROSSHAIR = 1007;
891db5397d88e722b1ab82ccb2b429ceec1179ccd8Jun Mukai
90f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    /** Type constant: text. */
91f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    public static final int TYPE_TEXT = 1008;
921db5397d88e722b1ab82ccb2b429ceec1179ccd8Jun Mukai
93f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    /** Type constant: vertical-text. */
94f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    public static final int TYPE_VERTICAL_TEXT = 1009;
951db5397d88e722b1ab82ccb2b429ceec1179ccd8Jun Mukai
96f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    /** Type constant: alias (indicating an alias of/shortcut to something is
971db5397d88e722b1ab82ccb2b429ceec1179ccd8Jun Mukai      * to be created. */
98f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    public static final int TYPE_ALIAS = 1010;
991db5397d88e722b1ab82ccb2b429ceec1179ccd8Jun Mukai
100f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    /** Type constant: copy. */
101f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    public static final int TYPE_COPY = 1011;
1021db5397d88e722b1ab82ccb2b429ceec1179ccd8Jun Mukai
103f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    /** Type constant: no-drop. */
104f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    public static final int TYPE_NO_DROP = 1012;
1051db5397d88e722b1ab82ccb2b429ceec1179ccd8Jun Mukai
106f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    /** Type constant: all-scroll. */
107f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    public static final int TYPE_ALL_SCROLL = 1013;
1081db5397d88e722b1ab82ccb2b429ceec1179ccd8Jun Mukai
109f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    /** Type constant: horizontal double arrow mainly for resizing. */
110f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    public static final int TYPE_HORIZONTAL_DOUBLE_ARROW = 1014;
1111db5397d88e722b1ab82ccb2b429ceec1179ccd8Jun Mukai
112f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    /** Type constant: vertical double arrow mainly for resizing. */
113f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    public static final int TYPE_VERTICAL_DOUBLE_ARROW = 1015;
1141db5397d88e722b1ab82ccb2b429ceec1179ccd8Jun Mukai
115f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    /** Type constant: diagonal double arrow -- top-right to bottom-left. */
116f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    public static final int TYPE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW = 1016;
1171db5397d88e722b1ab82ccb2b429ceec1179ccd8Jun Mukai
118f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    /** Type constant: diagonal double arrow -- top-left to bottom-right. */
119f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    public static final int TYPE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW = 1017;
1201db5397d88e722b1ab82ccb2b429ceec1179ccd8Jun Mukai
121f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    /** Type constant: zoom-in. */
122f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    public static final int TYPE_ZOOM_IN = 1018;
1231db5397d88e722b1ab82ccb2b429ceec1179ccd8Jun Mukai
124f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    /** Type constant: zoom-out. */
125f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    public static final int TYPE_ZOOM_OUT = 1019;
1261db5397d88e722b1ab82ccb2b429ceec1179ccd8Jun Mukai
127f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    /** Type constant: grab. */
128f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    public static final int TYPE_GRAB = 1020;
1291db5397d88e722b1ab82ccb2b429ceec1179ccd8Jun Mukai
130f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    /** Type constant: grabbing. */
131f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    public static final int TYPE_GRABBING = 1021;
1321db5397d88e722b1ab82ccb2b429ceec1179ccd8Jun Mukai
133f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    // OEM private types should be defined starting at this range to avoid
134f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    // conflicts with any system types that may be defined in the future.
135f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    private static final int TYPE_OEM_FIRST = 10000;
1362352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown
137d4eaef7f4c5a5d281de4fff272cd33e892e26264Jun Mukai    /** The default pointer icon. */
138f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    public static final int TYPE_DEFAULT = TYPE_ARROW;
1392352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown
140f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    private static final PointerIcon gNullIcon = new PointerIcon(TYPE_NULL);
141d4eaef7f4c5a5d281de4fff272cd33e892e26264Jun Mukai    private static final SparseArray<PointerIcon> gSystemIcons = new SparseArray<PointerIcon>();
1421f3dbffa0c521d89bce9b43220b279760911bcb7Jun Mukai    private static boolean sUseLargeIcons = false;
143e4e75daa655c862a7d5ee62da4104b13e3f45bbdJun Mukai
144f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    private final int mType;
1452352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown    private int mSystemIconResourceId;
1462352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown    private Bitmap mBitmap;
1472352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown    private float mHotSpotX;
1482352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown    private float mHotSpotY;
149808196f139e93395f1f331f6c7e92ddd66c05979Jun Mukai    // The bitmaps for the additional frame of animated pointer icon. Note that the first frame
150808196f139e93395f1f331f6c7e92ddd66c05979Jun Mukai    // will be stored in mBitmap.
151808196f139e93395f1f331f6c7e92ddd66c05979Jun Mukai    private Bitmap mBitmapFrames[];
152808196f139e93395f1f331f6c7e92ddd66c05979Jun Mukai    private int mDurationPerFrame;
1532352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown
154f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    private PointerIcon(int type) {
155f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright        mType = type;
1562352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown    }
1572352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown
1582352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown    /**
1592352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     * Gets a special pointer icon that has no bitmap.
1602352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     *
1612352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     * @return The null pointer icon.
1622352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     *
163f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright     * @see #TYPE_NULL
164d4eaef7f4c5a5d281de4fff272cd33e892e26264Jun Mukai     * @hide
1652352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     */
1662352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown    public static PointerIcon getNullIcon() {
1672352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        return gNullIcon;
1682352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown    }
1692352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown
1702352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown    /**
1712352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     * Gets the default pointer icon.
1722352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     *
1732352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     * @param context The context.
1742352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     * @return The default pointer icon.
1752352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     *
1762352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     * @throws IllegalArgumentException if context is null.
177d4eaef7f4c5a5d281de4fff272cd33e892e26264Jun Mukai     * @hide
1782352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     */
179d4eaef7f4c5a5d281de4fff272cd33e892e26264Jun Mukai    public static PointerIcon getDefaultIcon(@NonNull Context context) {
180f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright        return getSystemIcon(context, TYPE_DEFAULT);
1812352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown    }
1822352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown
1832352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown    /**
184f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright     * Gets a system pointer icon for the given type.
185f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright     * If typeis not recognized, returns the default pointer icon.
1862352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     *
1872352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     * @param context The context.
188f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright     * @param type The pointer icon type.
1892352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     * @return The pointer icon.
1902352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     *
1912352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     * @throws IllegalArgumentException if context is null.
1922352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     */
193f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    public static PointerIcon getSystemIcon(@NonNull Context context, int type) {
1942352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        if (context == null) {
1952352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown            throw new IllegalArgumentException("context must not be null");
1962352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        }
1972352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown
198f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright        if (type == TYPE_NULL) {
1992352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown            return gNullIcon;
2002352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        }
2012352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown
202f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright        PointerIcon icon = gSystemIcons.get(type);
203d4eaef7f4c5a5d281de4fff272cd33e892e26264Jun Mukai        if (icon != null) {
204d4eaef7f4c5a5d281de4fff272cd33e892e26264Jun Mukai            return icon;
205d4eaef7f4c5a5d281de4fff272cd33e892e26264Jun Mukai        }
206d4eaef7f4c5a5d281de4fff272cd33e892e26264Jun Mukai
207f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright        int typeIndex = getSystemIconTypeIndex(type);
208f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright        if (typeIndex == 0) {
209f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright            typeIndex = getSystemIconTypeIndex(TYPE_DEFAULT);
2102352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        }
2112352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown
212e4e75daa655c862a7d5ee62da4104b13e3f45bbdJun Mukai        int defStyle = sUseLargeIcons ?
21319a560197950425f7e1856d5bd1216fbc680bf70Jun Mukai                com.android.internal.R.style.LargePointer : com.android.internal.R.style.Pointer;
2142352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        TypedArray a = context.obtainStyledAttributes(null,
2152352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown                com.android.internal.R.styleable.Pointer,
21619a560197950425f7e1856d5bd1216fbc680bf70Jun Mukai                0, defStyle);
217f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright        int resourceId = a.getResourceId(typeIndex, -1);
2182352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        a.recycle();
2192352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown
2202352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        if (resourceId == -1) {
221f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright            Log.w(TAG, "Missing theme resources for pointer icon type " + type);
222f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright            return type == TYPE_DEFAULT ? gNullIcon : getSystemIcon(context, TYPE_DEFAULT);
2232352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        }
2242352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown
225f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright        icon = new PointerIcon(type);
2262352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        if ((resourceId & 0xff000000) == 0x01000000) {
2272352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown            icon.mSystemIconResourceId = resourceId;
2282352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        } else {
2298eea3ea5591e59f55cbb4f6b2b7e9363a285ced3Alan Viverette            icon.loadResource(context, context.getResources(), resourceId);
2302352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        }
231f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright        gSystemIcons.append(type, icon);
2322352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        return icon;
2332352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown    }
2342352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown
2352352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown    /**
2361f3dbffa0c521d89bce9b43220b279760911bcb7Jun Mukai     * Updates wheter accessibility large icons are used or not.
2371f3dbffa0c521d89bce9b43220b279760911bcb7Jun Mukai     * @hide
2381f3dbffa0c521d89bce9b43220b279760911bcb7Jun Mukai     */
2391f3dbffa0c521d89bce9b43220b279760911bcb7Jun Mukai    public static void setUseLargeIcons(boolean use) {
2401f3dbffa0c521d89bce9b43220b279760911bcb7Jun Mukai        sUseLargeIcons = use;
2411f3dbffa0c521d89bce9b43220b279760911bcb7Jun Mukai        gSystemIcons.clear();
2421f3dbffa0c521d89bce9b43220b279760911bcb7Jun Mukai    }
2431f3dbffa0c521d89bce9b43220b279760911bcb7Jun Mukai
2441f3dbffa0c521d89bce9b43220b279760911bcb7Jun Mukai    /**
245f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright     * Creates a custom pointer icon from the given bitmap and hotspot information.
2462352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     *
2472352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     * @param bitmap The bitmap for the icon.
248376d10e99e7db597fdff8a4e8f396161017c243cAlan Viverette     * @param hotSpotX The X offset of the pointer icon hotspot in the bitmap.
2492352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     *        Must be within the [0, bitmap.getWidth()) range.
250376d10e99e7db597fdff8a4e8f396161017c243cAlan Viverette     * @param hotSpotY The Y offset of the pointer icon hotspot in the bitmap.
2512352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     *        Must be within the [0, bitmap.getHeight()) range.
2522352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     * @return A pointer icon for this bitmap.
2532352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     *
2542352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     * @throws IllegalArgumentException if bitmap is null, or if the x/y hotspot
2552352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     *         parameters are invalid.
2562352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     */
257f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    public static PointerIcon create(@NonNull Bitmap bitmap, float hotSpotX, float hotSpotY) {
2582352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        if (bitmap == null) {
2592352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown            throw new IllegalArgumentException("bitmap must not be null");
2602352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        }
2612352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        validateHotSpot(bitmap, hotSpotX, hotSpotY);
2622352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown
263f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright        PointerIcon icon = new PointerIcon(TYPE_CUSTOM);
2642352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        icon.mBitmap = bitmap;
2652352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        icon.mHotSpotX = hotSpotX;
2662352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        icon.mHotSpotY = hotSpotY;
2672352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        return icon;
2682352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown    }
2692352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown
2702352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown    /**
2712352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     * Loads a custom pointer icon from an XML resource.
2722352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     * <p>
2732352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     * The XML resource should have the following form:
2742352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     * <code>
2752352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     * &lt;?xml version="1.0" encoding="utf-8"?&gt;
2762352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     * &lt;pointer-icon xmlns:android="http://schemas.android.com/apk/res/android"
2772352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     *   android:bitmap="@drawable/my_pointer_bitmap"
2782352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     *   android:hotSpotX="24"
2792352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     *   android:hotSpotY="24" /&gt;
2802352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     * </code>
2812352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     * </p>
2822352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     *
2832352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     * @param resources The resources object.
2842352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     * @param resourceId The resource id.
2852352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     * @return The pointer icon.
2862352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     *
2872352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     * @throws IllegalArgumentException if resources is null.
2882352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     * @throws Resources.NotFoundException if the resource was not found or the drawable
2892352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     * linked in the resource was not found.
2902352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     */
291f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    public static PointerIcon load(@NonNull Resources resources, @XmlRes int resourceId) {
2922352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        if (resources == null) {
2932352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown            throw new IllegalArgumentException("resources must not be null");
2942352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        }
2952352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown
296f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright        PointerIcon icon = new PointerIcon(TYPE_CUSTOM);
2978eea3ea5591e59f55cbb4f6b2b7e9363a285ced3Alan Viverette        icon.loadResource(null, resources, resourceId);
2982352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        return icon;
2992352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown    }
3002352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown
3012352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown    /**
3022352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     * Loads the bitmap and hotspot information for a pointer icon, if it is not already loaded.
3032352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     * Returns a pointer icon (not necessarily the same instance) with the information filled in.
3042352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     *
3052352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     * @param context The context.
3062352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     * @return The loaded pointer icon.
3072352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     *
3082352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     * @throws IllegalArgumentException if context is null.
3092352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     * @hide
3102352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown     */
311d4eaef7f4c5a5d281de4fff272cd33e892e26264Jun Mukai    public PointerIcon load(@NonNull Context context) {
3122352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        if (context == null) {
3132352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown            throw new IllegalArgumentException("context must not be null");
3142352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        }
3152352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown
3162352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        if (mSystemIconResourceId == 0 || mBitmap != null) {
3172352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown            return this;
3182352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        }
3192352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown
320f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright        PointerIcon result = new PointerIcon(mType);
3212352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        result.mSystemIconResourceId = mSystemIconResourceId;
3228eea3ea5591e59f55cbb4f6b2b7e9363a285ced3Alan Viverette        result.loadResource(context, context.getResources(), mSystemIconResourceId);
3232352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        return result;
3242352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown    }
3252352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown
326d4eaef7f4c5a5d281de4fff272cd33e892e26264Jun Mukai    /** @hide */
327f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    public int getType() {
328f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright        return mType;
3292352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown    }
3302352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown
3312352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown    public static final Parcelable.Creator<PointerIcon> CREATOR
3322352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown            = new Parcelable.Creator<PointerIcon>() {
3332352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        public PointerIcon createFromParcel(Parcel in) {
334f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright            int type = in.readInt();
335f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright            if (type == TYPE_NULL) {
3362352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown                return getNullIcon();
3372352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown            }
3382352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown
3392352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown            int systemIconResourceId = in.readInt();
3402352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown            if (systemIconResourceId != 0) {
341f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright                PointerIcon icon = new PointerIcon(type);
3422352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown                icon.mSystemIconResourceId = systemIconResourceId;
3432352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown                return icon;
3442352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown            }
3452352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown
3462352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown            Bitmap bitmap = Bitmap.CREATOR.createFromParcel(in);
3472352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown            float hotSpotX = in.readFloat();
3482352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown            float hotSpotY = in.readFloat();
349f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright            return PointerIcon.create(bitmap, hotSpotX, hotSpotY);
3502352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        }
3512352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown
3522352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        public PointerIcon[] newArray(int size) {
3532352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown            return new PointerIcon[size];
3542352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        }
3552352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown    };
3562352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown
3572352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown    public int describeContents() {
3582352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        return 0;
3592352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown    }
3602352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown
3612352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown    public void writeToParcel(Parcel out, int flags) {
362f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright        out.writeInt(mType);
3632352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown
364f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright        if (mType != TYPE_NULL) {
3652352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown            out.writeInt(mSystemIconResourceId);
3662352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown            if (mSystemIconResourceId == 0) {
3672352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown                mBitmap.writeToParcel(out, flags);
3682352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown                out.writeFloat(mHotSpotX);
3692352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown                out.writeFloat(mHotSpotY);
3702352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown            }
3712352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        }
3722352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown    }
3732352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown
3742352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown    @Override
3752352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown    public boolean equals(Object other) {
3762352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        if (this == other) {
3772352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown            return true;
3782352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        }
3792352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown
3802352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        if (other == null || !(other instanceof PointerIcon)) {
3812352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown            return false;
3822352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        }
3832352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown
3842352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        PointerIcon otherIcon = (PointerIcon) other;
385f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright        if (mType != otherIcon.mType
3862352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown                || mSystemIconResourceId != otherIcon.mSystemIconResourceId) {
3872352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown            return false;
3882352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        }
3892352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown
3902352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        if (mSystemIconResourceId == 0 && (mBitmap != otherIcon.mBitmap
3912352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown                || mHotSpotX != otherIcon.mHotSpotX
3922352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown                || mHotSpotY != otherIcon.mHotSpotY)) {
3932352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown            return false;
3942352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        }
3952352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown
3962352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        return true;
3972352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown    }
3982352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown
3997b9c912f536925ac6ec43935d6e97506851b33d6Tor Norbye    private void loadResource(Context context, Resources resources, @XmlRes int resourceId) {
400376d10e99e7db597fdff8a4e8f396161017c243cAlan Viverette        final XmlResourceParser parser = resources.getXml(resourceId);
4012352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        final int bitmapRes;
4022352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        final float hotSpotX;
4032352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        final float hotSpotY;
4042352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        try {
4052352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown            XmlUtils.beginDocument(parser, "pointer-icon");
4062352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown
407376d10e99e7db597fdff8a4e8f396161017c243cAlan Viverette            final TypedArray a = resources.obtainAttributes(
4082352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown                    parser, com.android.internal.R.styleable.PointerIcon);
4092352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown            bitmapRes = a.getResourceId(com.android.internal.R.styleable.PointerIcon_bitmap, 0);
410376d10e99e7db597fdff8a4e8f396161017c243cAlan Viverette            hotSpotX = a.getDimension(com.android.internal.R.styleable.PointerIcon_hotSpotX, 0);
411376d10e99e7db597fdff8a4e8f396161017c243cAlan Viverette            hotSpotY = a.getDimension(com.android.internal.R.styleable.PointerIcon_hotSpotY, 0);
4122352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown            a.recycle();
4132352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        } catch (Exception ex) {
4142352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown            throw new IllegalArgumentException("Exception parsing pointer icon resource.", ex);
4152352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        } finally {
4162352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown            parser.close();
4172352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        }
4182352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown
4192352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        if (bitmapRes == 0) {
4202352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown            throw new IllegalArgumentException("<pointer-icon> is missing bitmap attribute.");
4212352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        }
4222352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown
4238eea3ea5591e59f55cbb4f6b2b7e9363a285ced3Alan Viverette        Drawable drawable;
4248eea3ea5591e59f55cbb4f6b2b7e9363a285ced3Alan Viverette        if (context == null) {
4258eea3ea5591e59f55cbb4f6b2b7e9363a285ced3Alan Viverette            drawable = resources.getDrawable(bitmapRes);
4268eea3ea5591e59f55cbb4f6b2b7e9363a285ced3Alan Viverette        } else {
4278eea3ea5591e59f55cbb4f6b2b7e9363a285ced3Alan Viverette            drawable = context.getDrawable(bitmapRes);
4288eea3ea5591e59f55cbb4f6b2b7e9363a285ced3Alan Viverette        }
429808196f139e93395f1f331f6c7e92ddd66c05979Jun Mukai        if (drawable instanceof AnimationDrawable) {
430808196f139e93395f1f331f6c7e92ddd66c05979Jun Mukai            // Extract animation frame bitmaps.
431808196f139e93395f1f331f6c7e92ddd66c05979Jun Mukai            final AnimationDrawable animationDrawable = (AnimationDrawable) drawable;
432808196f139e93395f1f331f6c7e92ddd66c05979Jun Mukai            final int frames = animationDrawable.getNumberOfFrames();
433808196f139e93395f1f331f6c7e92ddd66c05979Jun Mukai            drawable = animationDrawable.getFrame(0);
434808196f139e93395f1f331f6c7e92ddd66c05979Jun Mukai            if (frames == 1) {
435808196f139e93395f1f331f6c7e92ddd66c05979Jun Mukai                Log.w(TAG, "Animation icon with single frame -- simply treating the first "
436808196f139e93395f1f331f6c7e92ddd66c05979Jun Mukai                        + "frame as a normal bitmap icon.");
437808196f139e93395f1f331f6c7e92ddd66c05979Jun Mukai            } else {
438808196f139e93395f1f331f6c7e92ddd66c05979Jun Mukai                // Assumes they have the exact duration.
439808196f139e93395f1f331f6c7e92ddd66c05979Jun Mukai                mDurationPerFrame = animationDrawable.getDuration(0);
440808196f139e93395f1f331f6c7e92ddd66c05979Jun Mukai                mBitmapFrames = new Bitmap[frames - 1];
441808196f139e93395f1f331f6c7e92ddd66c05979Jun Mukai                final int width = drawable.getIntrinsicWidth();
442808196f139e93395f1f331f6c7e92ddd66c05979Jun Mukai                final int height = drawable.getIntrinsicHeight();
443808196f139e93395f1f331f6c7e92ddd66c05979Jun Mukai                for (int i = 1; i < frames; ++i) {
444808196f139e93395f1f331f6c7e92ddd66c05979Jun Mukai                    Drawable drawableFrame = animationDrawable.getFrame(i);
445808196f139e93395f1f331f6c7e92ddd66c05979Jun Mukai                    if (!(drawableFrame instanceof BitmapDrawable)) {
446808196f139e93395f1f331f6c7e92ddd66c05979Jun Mukai                        throw new IllegalArgumentException("Frame of an animated pointer icon "
447808196f139e93395f1f331f6c7e92ddd66c05979Jun Mukai                                + "must refer to a bitmap drawable.");
448808196f139e93395f1f331f6c7e92ddd66c05979Jun Mukai                    }
449808196f139e93395f1f331f6c7e92ddd66c05979Jun Mukai                    if (drawableFrame.getIntrinsicWidth() != width ||
450808196f139e93395f1f331f6c7e92ddd66c05979Jun Mukai                        drawableFrame.getIntrinsicHeight() != height) {
451808196f139e93395f1f331f6c7e92ddd66c05979Jun Mukai                        throw new IllegalArgumentException("The bitmap size of " + i + "-th frame "
452808196f139e93395f1f331f6c7e92ddd66c05979Jun Mukai                                + "is different. All frames should have the exact same size and "
453808196f139e93395f1f331f6c7e92ddd66c05979Jun Mukai                                + "share the same hotspot.");
454808196f139e93395f1f331f6c7e92ddd66c05979Jun Mukai                    }
455808196f139e93395f1f331f6c7e92ddd66c05979Jun Mukai                    mBitmapFrames[i - 1] = ((BitmapDrawable)drawableFrame).getBitmap();
456808196f139e93395f1f331f6c7e92ddd66c05979Jun Mukai                }
457808196f139e93395f1f331f6c7e92ddd66c05979Jun Mukai            }
458808196f139e93395f1f331f6c7e92ddd66c05979Jun Mukai        }
4592352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        if (!(drawable instanceof BitmapDrawable)) {
4602352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown            throw new IllegalArgumentException("<pointer-icon> bitmap attribute must "
4612352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown                    + "refer to a bitmap drawable.");
4622352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        }
4632352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown
4642352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        // Set the properties now that we have successfully loaded the icon.
4652352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        mBitmap = ((BitmapDrawable)drawable).getBitmap();
4662352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        mHotSpotX = hotSpotX;
4672352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        mHotSpotY = hotSpotY;
4682352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown    }
4692352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown
4702352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown    private static void validateHotSpot(Bitmap bitmap, float hotSpotX, float hotSpotY) {
4712352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        if (hotSpotX < 0 || hotSpotX >= bitmap.getWidth()) {
4722352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown            throw new IllegalArgumentException("x hotspot lies outside of the bitmap area");
4732352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        }
4742352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        if (hotSpotY < 0 || hotSpotY >= bitmap.getHeight()) {
4752352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown            throw new IllegalArgumentException("y hotspot lies outside of the bitmap area");
4762352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        }
4772352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown    }
4782352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown
479f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright    private static int getSystemIconTypeIndex(int type) {
480f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright        switch (type) {
481f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright            case TYPE_ARROW:
4822352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown                return com.android.internal.R.styleable.Pointer_pointerIconArrow;
483f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright            case TYPE_SPOT_HOVER:
4842352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown                return com.android.internal.R.styleable.Pointer_pointerIconSpotHover;
485f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright            case TYPE_SPOT_TOUCH:
4862352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown                return com.android.internal.R.styleable.Pointer_pointerIconSpotTouch;
487f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright            case TYPE_SPOT_ANCHOR:
4882352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown                return com.android.internal.R.styleable.Pointer_pointerIconSpotAnchor;
489f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright            case TYPE_HAND:
4901db5397d88e722b1ab82ccb2b429ceec1179ccd8Jun Mukai                return com.android.internal.R.styleable.Pointer_pointerIconHand;
491f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright            case TYPE_CONTEXT_MENU:
4921db5397d88e722b1ab82ccb2b429ceec1179ccd8Jun Mukai                return com.android.internal.R.styleable.Pointer_pointerIconContextMenu;
493f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright            case TYPE_HELP:
4941db5397d88e722b1ab82ccb2b429ceec1179ccd8Jun Mukai                return com.android.internal.R.styleable.Pointer_pointerIconHelp;
495f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright            case TYPE_WAIT:
496808196f139e93395f1f331f6c7e92ddd66c05979Jun Mukai                return com.android.internal.R.styleable.Pointer_pointerIconWait;
497f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright            case TYPE_CELL:
4981db5397d88e722b1ab82ccb2b429ceec1179ccd8Jun Mukai                return com.android.internal.R.styleable.Pointer_pointerIconCell;
499f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright            case TYPE_CROSSHAIR:
5001db5397d88e722b1ab82ccb2b429ceec1179ccd8Jun Mukai                return com.android.internal.R.styleable.Pointer_pointerIconCrosshair;
501f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright            case TYPE_TEXT:
5021db5397d88e722b1ab82ccb2b429ceec1179ccd8Jun Mukai                return com.android.internal.R.styleable.Pointer_pointerIconText;
503f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright            case TYPE_VERTICAL_TEXT:
5041db5397d88e722b1ab82ccb2b429ceec1179ccd8Jun Mukai                return com.android.internal.R.styleable.Pointer_pointerIconVerticalText;
505f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright            case TYPE_ALIAS:
5061db5397d88e722b1ab82ccb2b429ceec1179ccd8Jun Mukai                return com.android.internal.R.styleable.Pointer_pointerIconAlias;
507f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright            case TYPE_COPY:
5081db5397d88e722b1ab82ccb2b429ceec1179ccd8Jun Mukai                return com.android.internal.R.styleable.Pointer_pointerIconCopy;
509f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright            case TYPE_ALL_SCROLL:
5101db5397d88e722b1ab82ccb2b429ceec1179ccd8Jun Mukai                return com.android.internal.R.styleable.Pointer_pointerIconAllScroll;
511f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright            case TYPE_NO_DROP:
5121db5397d88e722b1ab82ccb2b429ceec1179ccd8Jun Mukai                return com.android.internal.R.styleable.Pointer_pointerIconNodrop;
513f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright            case TYPE_HORIZONTAL_DOUBLE_ARROW:
5141db5397d88e722b1ab82ccb2b429ceec1179ccd8Jun Mukai                return com.android.internal.R.styleable.Pointer_pointerIconHorizontalDoubleArrow;
515f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright            case TYPE_VERTICAL_DOUBLE_ARROW:
5161db5397d88e722b1ab82ccb2b429ceec1179ccd8Jun Mukai                return com.android.internal.R.styleable.Pointer_pointerIconVerticalDoubleArrow;
517f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright            case TYPE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW:
5181db5397d88e722b1ab82ccb2b429ceec1179ccd8Jun Mukai                return com.android.internal.R.styleable.
5191db5397d88e722b1ab82ccb2b429ceec1179ccd8Jun Mukai                        Pointer_pointerIconTopRightDiagonalDoubleArrow;
520f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright            case TYPE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW:
5211db5397d88e722b1ab82ccb2b429ceec1179ccd8Jun Mukai                return com.android.internal.R.styleable.
5221db5397d88e722b1ab82ccb2b429ceec1179ccd8Jun Mukai                        Pointer_pointerIconTopLeftDiagonalDoubleArrow;
523f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright            case TYPE_ZOOM_IN:
5241db5397d88e722b1ab82ccb2b429ceec1179ccd8Jun Mukai                return com.android.internal.R.styleable.Pointer_pointerIconZoomIn;
525f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright            case TYPE_ZOOM_OUT:
5261db5397d88e722b1ab82ccb2b429ceec1179ccd8Jun Mukai                return com.android.internal.R.styleable.Pointer_pointerIconZoomOut;
527f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright            case TYPE_GRAB:
5281db5397d88e722b1ab82ccb2b429ceec1179ccd8Jun Mukai                return com.android.internal.R.styleable.Pointer_pointerIconGrab;
529f9d9ce7705475874c82af04eb9b208a7fb556792Michael Wright            case TYPE_GRABBING:
5301db5397d88e722b1ab82ccb2b429ceec1179ccd8Jun Mukai                return com.android.internal.R.styleable.Pointer_pointerIconGrabbing;
5312352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown            default:
5322352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown                return 0;
5332352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown        }
5342352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown    }
5352352b978a3c94cd88f41d0d908f961333fdac1e9Jeff Brown}
536