Drawable.java revision 12b97f5d2b15194ed6673c9838b13c8312157709
1/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.graphics.drawable;
18
19import android.graphics.Insets;
20import android.graphics.Xfermode;
21import android.os.Trace;
22
23import org.xmlpull.v1.XmlPullParser;
24import org.xmlpull.v1.XmlPullParserException;
25
26import android.content.res.Resources;
27import android.content.res.TypedArray;
28import android.graphics.Bitmap;
29import android.graphics.BitmapFactory;
30import android.graphics.Canvas;
31import android.graphics.ColorFilter;
32import android.graphics.NinePatch;
33import android.graphics.PixelFormat;
34import android.graphics.PorterDuff;
35import android.graphics.PorterDuffColorFilter;
36import android.graphics.Rect;
37import android.graphics.Region;
38import android.graphics.PorterDuff.Mode;
39import android.util.AttributeSet;
40import android.util.DisplayMetrics;
41import android.util.StateSet;
42import android.util.TypedValue;
43import android.util.Xml;
44import android.view.View;
45
46import java.io.IOException;
47import java.io.InputStream;
48import java.lang.ref.WeakReference;
49import java.util.Arrays;
50
51/**
52 * A Drawable is a general abstraction for "something that can be drawn."  Most
53 * often you will deal with Drawable as the type of resource retrieved for
54 * drawing things to the screen; the Drawable class provides a generic API for
55 * dealing with an underlying visual resource that may take a variety of forms.
56 * Unlike a {@link android.view.View}, a Drawable does not have any facility to
57 * receive events or otherwise interact with the user.
58 *
59 * <p>In addition to simple drawing, Drawable provides a number of generic
60 * mechanisms for its client to interact with what is being drawn:
61 *
62 * <ul>
63 *     <li> The {@link #setBounds} method <var>must</var> be called to tell the
64 *     Drawable where it is drawn and how large it should be.  All Drawables
65 *     should respect the requested size, often simply by scaling their
66 *     imagery.  A client can find the preferred size for some Drawables with
67 *     the {@link #getIntrinsicHeight} and {@link #getIntrinsicWidth} methods.
68 *
69 *     <li> The {@link #getPadding} method can return from some Drawables
70 *     information about how to frame content that is placed inside of them.
71 *     For example, a Drawable that is intended to be the frame for a button
72 *     widget would need to return padding that correctly places the label
73 *     inside of itself.
74 *
75 *     <li> The {@link #setState} method allows the client to tell the Drawable
76 *     in which state it is to be drawn, such as "focused", "selected", etc.
77 *     Some drawables may modify their imagery based on the selected state.
78 *
79 *     <li> The {@link #setLevel} method allows the client to supply a single
80 *     continuous controller that can modify the Drawable is displayed, such as
81 *     a battery level or progress level.  Some drawables may modify their
82 *     imagery based on the current level.
83 *
84 *     <li> A Drawable can perform animations by calling back to its client
85 *     through the {@link Callback} interface.  All clients should support this
86 *     interface (via {@link #setCallback}) so that animations will work.  A
87 *     simple way to do this is through the system facilities such as
88 *     {@link android.view.View#setBackground(Drawable)} and
89 *     {@link android.widget.ImageView}.
90 * </ul>
91 *
92 * Though usually not visible to the application, Drawables may take a variety
93 * of forms:
94 *
95 * <ul>
96 *     <li> <b>Bitmap</b>: the simplest Drawable, a PNG or JPEG image.
97 *     <li> <b>Nine Patch</b>: an extension to the PNG format allows it to
98 *     specify information about how to stretch it and place things inside of
99 *     it.
100 *     <li> <b>Shape</b>: contains simple drawing commands instead of a raw
101 *     bitmap, allowing it to resize better in some cases.
102 *     <li> <b>Layers</b>: a compound drawable, which draws multiple underlying
103 *     drawables on top of each other.
104 *     <li> <b>States</b>: a compound drawable that selects one of a set of
105 *     drawables based on its state.
106 *     <li> <b>Levels</b>: a compound drawable that selects one of a set of
107 *     drawables based on its level.
108 *     <li> <b>Scale</b>: a compound drawable with a single child drawable,
109 *     whose overall size is modified based on the current level.
110 * </ul>
111 *
112 * <div class="special reference">
113 * <h3>Developer Guides</h3>
114 * <p>For more information about how to use drawables, read the
115 * <a href="{@docRoot}guide/topics/graphics/2d-graphics.html">Canvas and Drawables</a> developer
116 * guide. For information and examples of creating drawable resources (XML or bitmap files that
117 * can be loaded in code), read the
118 * <a href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>
119 * document.</p></div>
120 */
121public abstract class Drawable {
122    /**
123     * Hotspot identifier mask for tracking touch points.
124     *
125     * @hide until hotspot APIs are finalized
126     */
127    public static final int HOTSPOT_TOUCH_MASK = 0xFF;
128
129    /**
130     * Hotspot identifier for tracking keyboard focus.
131     *
132     * @hide until hotspot APIs are finalized
133     */
134    public static final int HOTSPOT_FOCUS = 0x100;
135
136    private static final Rect ZERO_BOUNDS_RECT = new Rect();
137
138    private int[] mStateSet = StateSet.WILD_CARD;
139    private int mLevel = 0;
140    private int mChangingConfigurations = 0;
141    private Rect mBounds = ZERO_BOUNDS_RECT;  // lazily becomes a new Rect()
142    private WeakReference<Callback> mCallback = null;
143    private boolean mVisible = true;
144
145    private int mLayoutDirection;
146
147    /**
148     * Draw in its bounds (set via setBounds) respecting optional effects such
149     * as alpha (set via setAlpha) and color filter (set via setColorFilter).
150     *
151     * @param canvas The canvas to draw into
152     */
153    public abstract void draw(Canvas canvas);
154
155    /**
156     * Specify a bounding rectangle for the Drawable. This is where the drawable
157     * will draw when its draw() method is called.
158     */
159    public void setBounds(int left, int top, int right, int bottom) {
160        Rect oldBounds = mBounds;
161
162        if (oldBounds == ZERO_BOUNDS_RECT) {
163            oldBounds = mBounds = new Rect();
164        }
165
166        if (oldBounds.left != left || oldBounds.top != top ||
167                oldBounds.right != right || oldBounds.bottom != bottom) {
168            if (!oldBounds.isEmpty()) {
169                // first invalidate the previous bounds
170                invalidateSelf();
171            }
172            mBounds.set(left, top, right, bottom);
173            onBoundsChange(mBounds);
174        }
175    }
176
177    /**
178     * Specify a bounding rectangle for the Drawable. This is where the drawable
179     * will draw when its draw() method is called.
180     */
181    public void setBounds(Rect bounds) {
182        setBounds(bounds.left, bounds.top, bounds.right, bounds.bottom);
183    }
184
185    /**
186     * Return a copy of the drawable's bounds in the specified Rect (allocated
187     * by the caller). The bounds specify where this will draw when its draw()
188     * method is called.
189     *
190     * @param bounds Rect to receive the drawable's bounds (allocated by the
191     *               caller).
192     */
193    public final void copyBounds(Rect bounds) {
194        bounds.set(mBounds);
195    }
196
197    /**
198     * Return a copy of the drawable's bounds in a new Rect. This returns the
199     * same values as getBounds(), but the returned object is guaranteed to not
200     * be changed later by the drawable (i.e. it retains no reference to this
201     * rect). If the caller already has a Rect allocated, call copyBounds(rect).
202     *
203     * @return A copy of the drawable's bounds
204     */
205    public final Rect copyBounds() {
206        return new Rect(mBounds);
207    }
208
209    /**
210     * Return the drawable's bounds Rect. Note: for efficiency, the returned
211     * object may be the same object stored in the drawable (though this is not
212     * guaranteed), so if a persistent copy of the bounds is needed, call
213     * copyBounds(rect) instead.
214     * You should also not change the object returned by this method as it may
215     * be the same object stored in the drawable.
216     *
217     * @return The bounds of the drawable (which may change later, so caller
218     *         beware). DO NOT ALTER the returned object as it may change the
219     *         stored bounds of this drawable.
220     *
221     * @see #copyBounds()
222     * @see #copyBounds(android.graphics.Rect)
223     */
224    public final Rect getBounds() {
225        if (mBounds == ZERO_BOUNDS_RECT) {
226            mBounds = new Rect();
227        }
228
229        return mBounds;
230    }
231
232    /**
233     * Return the drawable's dirty bounds Rect. Note: for efficiency, the
234     * returned object may be the same object stored in the drawable (though
235     * this is not guaranteed).
236     * <p>
237     * By default, this returns the full drawable bounds. Custom drawables may
238     * override this method to perform more precise invalidation.
239     *
240     * @hide
241     */
242    public Rect getDirtyBounds() {
243        return getBounds();
244    }
245
246    /**
247     * Set a mask of the configuration parameters for which this drawable
248     * may change, requiring that it be re-created.
249     *
250     * @param configs A mask of the changing configuration parameters, as
251     * defined by {@link android.content.res.Configuration}.
252     *
253     * @see android.content.res.Configuration
254     */
255    public void setChangingConfigurations(int configs) {
256        mChangingConfigurations = configs;
257    }
258
259    /**
260     * Return a mask of the configuration parameters for which this drawable
261     * may change, requiring that it be re-created.  The default implementation
262     * returns whatever was provided through
263     * {@link #setChangingConfigurations(int)} or 0 by default.  Subclasses
264     * may extend this to or in the changing configurations of any other
265     * drawables they hold.
266     *
267     * @return Returns a mask of the changing configuration parameters, as
268     * defined by {@link android.content.res.Configuration}.
269     *
270     * @see android.content.res.Configuration
271     */
272    public int getChangingConfigurations() {
273        return mChangingConfigurations;
274    }
275
276    /**
277     * Set to true to have the drawable dither its colors when drawn to a device
278     * with fewer than 8-bits per color component. This can improve the look on
279     * those devices, but can also slow down the drawing a little.
280     */
281    public void setDither(boolean dither) {}
282
283    /**
284     * Set to true to have the drawable filter its bitmap when scaled or rotated
285     * (for drawables that use bitmaps). If the drawable does not use bitmaps,
286     * this call is ignored. This can improve the look when scaled or rotated,
287     * but also slows down the drawing.
288     */
289    public void setFilterBitmap(boolean filter) {}
290
291    /**
292     * Implement this interface if you want to create an animated drawable that
293     * extends {@link android.graphics.drawable.Drawable Drawable}.
294     * Upon retrieving a drawable, use
295     * {@link Drawable#setCallback(android.graphics.drawable.Drawable.Callback)}
296     * to supply your implementation of the interface to the drawable; it uses
297     * this interface to schedule and execute animation changes.
298     */
299    public static interface Callback {
300        /**
301         * Called when the drawable needs to be redrawn.  A view at this point
302         * should invalidate itself (or at least the part of itself where the
303         * drawable appears).
304         *
305         * @param who The drawable that is requesting the update.
306         */
307        public void invalidateDrawable(Drawable who);
308
309        /**
310         * A Drawable can call this to schedule the next frame of its
311         * animation.  An implementation can generally simply call
312         * {@link android.os.Handler#postAtTime(Runnable, Object, long)} with
313         * the parameters <var>(what, who, when)</var> to perform the
314         * scheduling.
315         *
316         * @param who The drawable being scheduled.
317         * @param what The action to execute.
318         * @param when The time (in milliseconds) to run.  The timebase is
319         *             {@link android.os.SystemClock#uptimeMillis}
320         */
321        public void scheduleDrawable(Drawable who, Runnable what, long when);
322
323        /**
324         * A Drawable can call this to unschedule an action previously
325         * scheduled with {@link #scheduleDrawable}.  An implementation can
326         * generally simply call
327         * {@link android.os.Handler#removeCallbacks(Runnable, Object)} with
328         * the parameters <var>(what, who)</var> to unschedule the drawable.
329         *
330         * @param who The drawable being unscheduled.
331         * @param what The action being unscheduled.
332         */
333        public void unscheduleDrawable(Drawable who, Runnable what);
334    }
335
336    /**
337     * Bind a {@link Callback} object to this Drawable.  Required for clients
338     * that want to support animated drawables.
339     *
340     * @param cb The client's Callback implementation.
341     *
342     * @see #getCallback()
343     */
344    public final void setCallback(Callback cb) {
345        mCallback = new WeakReference<Callback>(cb);
346    }
347
348    /**
349     * Return the current {@link Callback} implementation attached to this
350     * Drawable.
351     *
352     * @return A {@link Callback} instance or null if no callback was set.
353     *
354     * @see #setCallback(android.graphics.drawable.Drawable.Callback)
355     */
356    public Callback getCallback() {
357        if (mCallback != null) {
358            return mCallback.get();
359        }
360        return null;
361    }
362
363    /**
364     * Use the current {@link Callback} implementation to have this Drawable
365     * redrawn.  Does nothing if there is no Callback attached to the
366     * Drawable.
367     *
368     * @see Callback#invalidateDrawable
369     * @see #getCallback()
370     * @see #setCallback(android.graphics.drawable.Drawable.Callback)
371     */
372    public void invalidateSelf() {
373        final Callback callback = getCallback();
374        if (callback != null) {
375            callback.invalidateDrawable(this);
376        }
377    }
378
379    /**
380     * Use the current {@link Callback} implementation to have this Drawable
381     * scheduled.  Does nothing if there is no Callback attached to the
382     * Drawable.
383     *
384     * @param what The action being scheduled.
385     * @param when The time (in milliseconds) to run.
386     *
387     * @see Callback#scheduleDrawable
388     */
389    public void scheduleSelf(Runnable what, long when) {
390        final Callback callback = getCallback();
391        if (callback != null) {
392            callback.scheduleDrawable(this, what, when);
393        }
394    }
395
396    /**
397     * Use the current {@link Callback} implementation to have this Drawable
398     * unscheduled.  Does nothing if there is no Callback attached to the
399     * Drawable.
400     *
401     * @param what The runnable that you no longer want called.
402     *
403     * @see Callback#unscheduleDrawable
404     */
405    public void unscheduleSelf(Runnable what) {
406        final Callback callback = getCallback();
407        if (callback != null) {
408            callback.unscheduleDrawable(this, what);
409        }
410    }
411
412    /**
413     * Returns the resolved layout direction for this Drawable.
414     *
415     * @return One of {@link android.view.View#LAYOUT_DIRECTION_LTR},
416     *   {@link android.view.View#LAYOUT_DIRECTION_RTL}
417     *
418     * @hide
419     */
420    public int getLayoutDirection() {
421        return mLayoutDirection;
422    }
423
424    /**
425     * Set the layout direction for this drawable. Should be a resolved direction as the
426     * Drawable as no capacity to do the resolution on his own.
427     *
428     * @param layoutDirection One of {@link android.view.View#LAYOUT_DIRECTION_LTR},
429     *   {@link android.view.View#LAYOUT_DIRECTION_RTL}
430     *
431     * @hide
432     */
433    public void setLayoutDirection(@View.ResolvedLayoutDir int layoutDirection) {
434        if (getLayoutDirection() != layoutDirection) {
435            mLayoutDirection = layoutDirection;
436        }
437    }
438
439    /**
440     * Specify an alpha value for the drawable. 0 means fully transparent, and
441     * 255 means fully opaque.
442     */
443    public abstract void setAlpha(int alpha);
444
445    /**
446     * Gets the current alpha value for the drawable. 0 means fully transparent,
447     * 255 means fully opaque. This method is implemented by
448     * Drawable subclasses and the value returned is specific to how that class treats alpha.
449     * The default return value is 255 if the class does not override this method to return a value
450     * specific to its use of alpha.
451     */
452    public int getAlpha() {
453        return 0xFF;
454    }
455
456    /**
457     * Specify an optional color filter for the drawable. Pass null to remove
458     * any existing color filter.
459     */
460    public abstract void setColorFilter(ColorFilter cf);
461
462    /**
463     * @hide Consider for future API inclusion
464     */
465    public void setXfermode(Xfermode mode) {
466        // Base implementation drops it on the floor for compatibility. Whee!
467        // TODO: For this to be included in the API proper, all framework drawables need impls.
468        // For right now only BitmapDrawable has it.
469    }
470
471    /**
472     * Specify a color and Porter-Duff mode to be the color filter for this
473     * drawable.
474     */
475    public void setColorFilter(int color, PorterDuff.Mode mode) {
476        setColorFilter(new PorterDuffColorFilter(color, mode));
477    }
478
479    /**
480     * Removes the color filter for this drawable.
481     */
482    public void clearColorFilter() {
483        setColorFilter(null);
484    }
485
486    /**
487     * Indicates whether the drawable supports hotspots. Hotspots are uniquely
488     * identifiable coordinates the may be added, updated and removed within the
489     * drawable.
490     *
491     * @return true if hotspots are supported
492     * @see #setHotspot(int, float, float)
493     * @see #removeHotspot(int)
494     * @see #clearHotspots()
495     * @hide until hotspot APIs are finalized
496     */
497    public boolean supportsHotspots() {
498        return false;
499    }
500
501    /**
502     * Specifies a hotspot's location within the drawable.
503     *
504     * @param id unique identifier for the hotspot
505     * @param x x-coordinate
506     * @param y y-coordinate
507     * @hide until hotspot APIs are finalized
508     */
509    public void setHotspot(int id, float x, float y) {}
510
511    /**
512     * Removes the specified hotspot from the drawable.
513     *
514     * @param id unique identifier for the hotspot
515     * @hide until hotspot APIs are finalized
516     */
517    public void removeHotspot(int id) {}
518
519    /**
520     * Removes all hotspots from the drawable.
521     *
522     * @hide until hotspot APIs are finalized
523     */
524    public void clearHotspots() {}
525
526    /**
527     * Whether this drawable requests projection.
528     *
529     * @hide
530     */
531    public boolean isProjected() {
532        return false;
533    }
534
535    /**
536     * Indicates whether this view will change its appearance based on state.
537     * Clients can use this to determine whether it is necessary to calculate
538     * their state and call setState.
539     *
540     * @return True if this view changes its appearance based on state, false
541     *         otherwise.
542     *
543     * @see #setState(int[])
544     */
545    public boolean isStateful() {
546        return false;
547    }
548
549    /**
550     * Specify a set of states for the drawable. These are use-case specific,
551     * so see the relevant documentation. As an example, the background for
552     * widgets like Button understand the following states:
553     * [{@link android.R.attr#state_focused},
554     *  {@link android.R.attr#state_pressed}].
555     *
556     * <p>If the new state you are supplying causes the appearance of the
557     * Drawable to change, then it is responsible for calling
558     * {@link #invalidateSelf} in order to have itself redrawn, <em>and</em>
559     * true will be returned from this function.
560     *
561     * <p>Note: The Drawable holds a reference on to <var>stateSet</var>
562     * until a new state array is given to it, so you must not modify this
563     * array during that time.</p>
564     *
565     * @param stateSet The new set of states to be displayed.
566     *
567     * @return Returns true if this change in state has caused the appearance
568     * of the Drawable to change (hence requiring an invalidate), otherwise
569     * returns false.
570     */
571    public boolean setState(final int[] stateSet) {
572        if (!Arrays.equals(mStateSet, stateSet)) {
573            mStateSet = stateSet;
574            return onStateChange(stateSet);
575        }
576        return false;
577    }
578
579    /**
580     * Describes the current state, as a union of primitve states, such as
581     * {@link android.R.attr#state_focused},
582     * {@link android.R.attr#state_selected}, etc.
583     * Some drawables may modify their imagery based on the selected state.
584     * @return An array of resource Ids describing the current state.
585     */
586    public int[] getState() {
587        return mStateSet;
588    }
589
590    /**
591     * If this Drawable does transition animations between states, ask that
592     * it immediately jump to the current state and skip any active animations.
593     */
594    public void jumpToCurrentState() {
595    }
596
597    /**
598     * @return The current drawable that will be used by this drawable. For simple drawables, this
599     *         is just the drawable itself. For drawables that change state like
600     *         {@link StateListDrawable} and {@link LevelListDrawable} this will be the child drawable
601     *         currently in use.
602     */
603    public Drawable getCurrent() {
604        return this;
605    }
606
607    /**
608     * Specify the level for the drawable.  This allows a drawable to vary its
609     * imagery based on a continuous controller, for example to show progress
610     * or volume level.
611     *
612     * <p>If the new level you are supplying causes the appearance of the
613     * Drawable to change, then it is responsible for calling
614     * {@link #invalidateSelf} in order to have itself redrawn, <em>and</em>
615     * true will be returned from this function.
616     *
617     * @param level The new level, from 0 (minimum) to 10000 (maximum).
618     *
619     * @return Returns true if this change in level has caused the appearance
620     * of the Drawable to change (hence requiring an invalidate), otherwise
621     * returns false.
622     */
623    public final boolean setLevel(int level) {
624        if (mLevel != level) {
625            mLevel = level;
626            return onLevelChange(level);
627        }
628        return false;
629    }
630
631    /**
632     * Retrieve the current level.
633     *
634     * @return int Current level, from 0 (minimum) to 10000 (maximum).
635     */
636    public final int getLevel() {
637        return mLevel;
638    }
639
640    /**
641     * Set whether this Drawable is visible.  This generally does not impact
642     * the Drawable's behavior, but is a hint that can be used by some
643     * Drawables, for example, to decide whether run animations.
644     *
645     * @param visible Set to true if visible, false if not.
646     * @param restart You can supply true here to force the drawable to behave
647     *                as if it has just become visible, even if it had last
648     *                been set visible.  Used for example to force animations
649     *                to restart.
650     *
651     * @return boolean Returns true if the new visibility is different than
652     *         its previous state.
653     */
654    public boolean setVisible(boolean visible, boolean restart) {
655        boolean changed = mVisible != visible;
656        if (changed) {
657            mVisible = visible;
658            invalidateSelf();
659        }
660        return changed;
661    }
662
663    public final boolean isVisible() {
664        return mVisible;
665    }
666
667    /**
668     * Set whether this Drawable is automatically mirrored when its layout direction is RTL
669     * (right-to left). See {@link android.util.LayoutDirection}.
670     *
671     * @param mirrored Set to true if the Drawable should be mirrored, false if not.
672     */
673    public void setAutoMirrored(boolean mirrored) {
674    }
675
676    /**
677     * Tells if this Drawable will be automatically mirrored  when its layout direction is RTL
678     * right-to-left. See {@link android.util.LayoutDirection}.
679     *
680     * @return boolean Returns true if this Drawable will be automatically mirrored.
681     */
682    public boolean isAutoMirrored() {
683        return false;
684    }
685
686    /**
687     * Return the opacity/transparency of this Drawable.  The returned value is
688     * one of the abstract format constants in
689     * {@link android.graphics.PixelFormat}:
690     * {@link android.graphics.PixelFormat#UNKNOWN},
691     * {@link android.graphics.PixelFormat#TRANSLUCENT},
692     * {@link android.graphics.PixelFormat#TRANSPARENT}, or
693     * {@link android.graphics.PixelFormat#OPAQUE}.
694     *
695     * <p>Generally a Drawable should be as conservative as possible with the
696     * value it returns.  For example, if it contains multiple child drawables
697     * and only shows one of them at a time, if only one of the children is
698     * TRANSLUCENT and the others are OPAQUE then TRANSLUCENT should be
699     * returned.  You can use the method {@link #resolveOpacity} to perform a
700     * standard reduction of two opacities to the appropriate single output.
701     *
702     * <p>Note that the returned value does <em>not</em> take into account a
703     * custom alpha or color filter that has been applied by the client through
704     * the {@link #setAlpha} or {@link #setColorFilter} methods.
705     *
706     * @return int The opacity class of the Drawable.
707     *
708     * @see android.graphics.PixelFormat
709     */
710    public abstract int getOpacity();
711
712    /**
713     * Return the appropriate opacity value for two source opacities.  If
714     * either is UNKNOWN, that is returned; else, if either is TRANSLUCENT,
715     * that is returned; else, if either is TRANSPARENT, that is returned;
716     * else, OPAQUE is returned.
717     *
718     * <p>This is to help in implementing {@link #getOpacity}.
719     *
720     * @param op1 One opacity value.
721     * @param op2 Another opacity value.
722     *
723     * @return int The combined opacity value.
724     *
725     * @see #getOpacity
726     */
727    public static int resolveOpacity(int op1, int op2) {
728        if (op1 == op2) {
729            return op1;
730        }
731        if (op1 == PixelFormat.UNKNOWN || op2 == PixelFormat.UNKNOWN) {
732            return PixelFormat.UNKNOWN;
733        }
734        if (op1 == PixelFormat.TRANSLUCENT || op2 == PixelFormat.TRANSLUCENT) {
735            return PixelFormat.TRANSLUCENT;
736        }
737        if (op1 == PixelFormat.TRANSPARENT || op2 == PixelFormat.TRANSPARENT) {
738            return PixelFormat.TRANSPARENT;
739        }
740        return PixelFormat.OPAQUE;
741    }
742
743    /**
744     * Returns a Region representing the part of the Drawable that is completely
745     * transparent.  This can be used to perform drawing operations, identifying
746     * which parts of the target will not change when rendering the Drawable.
747     * The default implementation returns null, indicating no transparent
748     * region; subclasses can optionally override this to return an actual
749     * Region if they want to supply this optimization information, but it is
750     * not required that they do so.
751     *
752     * @return Returns null if the Drawables has no transparent region to
753     * report, else a Region holding the parts of the Drawable's bounds that
754     * are transparent.
755     */
756    public Region getTransparentRegion() {
757        return null;
758    }
759
760    /**
761     * Override this in your subclass to change appearance if you recognize the
762     * specified state.
763     *
764     * @return Returns true if the state change has caused the appearance of
765     * the Drawable to change (that is, it needs to be drawn), else false
766     * if it looks the same and there is no need to redraw it since its
767     * last state.
768     */
769    protected boolean onStateChange(int[] state) { return false; }
770    /** Override this in your subclass to change appearance if you vary based
771     *  on level.
772     * @return Returns true if the level change has caused the appearance of
773     * the Drawable to change (that is, it needs to be drawn), else false
774     * if it looks the same and there is no need to redraw it since its
775     * last level.
776     */
777    protected boolean onLevelChange(int level) { return false; }
778    /**
779     * Override this in your subclass to change appearance if you vary based on
780     * the bounds.
781     */
782    protected void onBoundsChange(Rect bounds) {}
783
784    /**
785     * Return the intrinsic width of the underlying drawable object.  Returns
786     * -1 if it has no intrinsic width, such as with a solid color.
787     */
788    public int getIntrinsicWidth() {
789        return -1;
790    }
791
792    /**
793     * Return the intrinsic height of the underlying drawable object. Returns
794     * -1 if it has no intrinsic height, such as with a solid color.
795     */
796    public int getIntrinsicHeight() {
797        return -1;
798    }
799
800    /**
801     * Returns the minimum width suggested by this Drawable. If a View uses this
802     * Drawable as a background, it is suggested that the View use at least this
803     * value for its width. (There will be some scenarios where this will not be
804     * possible.) This value should INCLUDE any padding.
805     *
806     * @return The minimum width suggested by this Drawable. If this Drawable
807     *         doesn't have a suggested minimum width, 0 is returned.
808     */
809    public int getMinimumWidth() {
810        final int intrinsicWidth = getIntrinsicWidth();
811        return intrinsicWidth > 0 ? intrinsicWidth : 0;
812    }
813
814    /**
815     * Returns the minimum height suggested by this Drawable. If a View uses this
816     * Drawable as a background, it is suggested that the View use at least this
817     * value for its height. (There will be some scenarios where this will not be
818     * possible.) This value should INCLUDE any padding.
819     *
820     * @return The minimum height suggested by this Drawable. If this Drawable
821     *         doesn't have a suggested minimum height, 0 is returned.
822     */
823    public int getMinimumHeight() {
824        final int intrinsicHeight = getIntrinsicHeight();
825        return intrinsicHeight > 0 ? intrinsicHeight : 0;
826    }
827
828    /**
829     * Return in padding the insets suggested by this Drawable for placing
830     * content inside the drawable's bounds. Positive values move toward the
831     * center of the Drawable (set Rect.inset). Returns true if this drawable
832     * actually has a padding, else false. When false is returned, the padding
833     * is always set to 0.
834     */
835    public boolean getPadding(Rect padding) {
836        padding.set(0, 0, 0, 0);
837        return false;
838    }
839
840    /**
841     * Return in insets the layout insets suggested by this Drawable for use with alignment
842     * operations during layout.
843     *
844     * @hide
845     */
846    public Insets getOpticalInsets() {
847        return Insets.NONE;
848    }
849
850    /**
851     * Make this drawable mutable. This operation cannot be reversed. A mutable
852     * drawable is guaranteed to not share its state with any other drawable.
853     * This is especially useful when you need to modify properties of drawables
854     * loaded from resources. By default, all drawables instances loaded from
855     * the same resource share a common state; if you modify the state of one
856     * instance, all the other instances will receive the same modification.
857     *
858     * Calling this method on a mutable Drawable will have no effect.
859     *
860     * @return This drawable.
861     * @see ConstantState
862     * @see #getConstantState()
863     */
864    public Drawable mutate() {
865        return this;
866    }
867
868    /**
869     * Create a drawable from an inputstream
870     */
871    public static Drawable createFromStream(InputStream is, String srcName) {
872        Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, srcName != null ? srcName : "Unknown drawable");
873        try {
874            return createFromResourceStream(null, null, is, srcName, null);
875        } finally {
876            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
877        }
878    }
879
880    /**
881     * Create a drawable from an inputstream, using the given resources and
882     * value to determine density information.
883     */
884    public static Drawable createFromResourceStream(Resources res, TypedValue value,
885            InputStream is, String srcName) {
886        Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, srcName != null ? srcName : "Unknown drawable");
887        try {
888            return createFromResourceStream(res, value, is, srcName, null);
889        } finally {
890            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
891        }
892    }
893
894    /**
895     * Create a drawable from an inputstream, using the given resources and
896     * value to determine density information.
897     */
898    public static Drawable createFromResourceStream(Resources res, TypedValue value,
899            InputStream is, String srcName, BitmapFactory.Options opts) {
900
901        if (is == null) {
902            return null;
903        }
904
905        /*  ugh. The decodeStream contract is that we have already allocated
906            the pad rect, but if the bitmap does not had a ninepatch chunk,
907            then the pad will be ignored. If we could change this to lazily
908            alloc/assign the rect, we could avoid the GC churn of making new
909            Rects only to drop them on the floor.
910        */
911        Rect pad = new Rect();
912
913        // Special stuff for compatibility mode: if the target density is not
914        // the same as the display density, but the resource -is- the same as
915        // the display density, then don't scale it down to the target density.
916        // This allows us to load the system's density-correct resources into
917        // an application in compatibility mode, without scaling those down
918        // to the compatibility density only to have them scaled back up when
919        // drawn to the screen.
920        if (opts == null) opts = new BitmapFactory.Options();
921        opts.inScreenDensity = res != null
922                ? res.getDisplayMetrics().noncompatDensityDpi : DisplayMetrics.DENSITY_DEVICE;
923        Bitmap  bm = BitmapFactory.decodeResourceStream(res, value, is, pad, opts);
924        if (bm != null) {
925            byte[] np = bm.getNinePatchChunk();
926            if (np == null || !NinePatch.isNinePatchChunk(np)) {
927                np = null;
928                pad = null;
929            }
930            int[] layoutBounds = bm.getLayoutBounds();
931            Rect layoutBoundsRect = null;
932            if (layoutBounds != null) {
933                layoutBoundsRect = new Rect(layoutBounds[0], layoutBounds[1],
934                                             layoutBounds[2], layoutBounds[3]);
935            }
936            return drawableFromBitmap(res, bm, np, pad, layoutBoundsRect, srcName);
937        }
938        return null;
939    }
940
941    /**
942     * Create a drawable from an XML document. For more information on how to
943     * create resources in XML, see
944     * <a href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.
945     */
946    public static Drawable createFromXml(Resources r, XmlPullParser parser)
947            throws XmlPullParserException, IOException {
948        AttributeSet attrs = Xml.asAttributeSet(parser);
949
950        int type;
951        while ((type=parser.next()) != XmlPullParser.START_TAG &&
952                type != XmlPullParser.END_DOCUMENT) {
953            // Empty loop
954        }
955
956        if (type != XmlPullParser.START_TAG) {
957            throw new XmlPullParserException("No start tag found");
958        }
959
960        Drawable drawable = createFromXmlInner(r, parser, attrs);
961
962        if (drawable == null) {
963            throw new RuntimeException("Unknown initial tag: " + parser.getName());
964        }
965
966        return drawable;
967    }
968
969    /**
970     * Create from inside an XML document.  Called on a parser positioned at
971     * a tag in an XML document, tries to create a Drawable from that tag.
972     * Returns null if the tag is not a valid drawable.
973     */
974    public static Drawable createFromXmlInner(Resources r, XmlPullParser parser, AttributeSet attrs)
975    throws XmlPullParserException, IOException {
976        Drawable drawable;
977
978        final String name = parser.getName();
979
980        if (name.equals("selector")) {
981            drawable = new StateListDrawable();
982        } else if (name.equals("level-list")) {
983            drawable = new LevelListDrawable();
984        } else if (name.equals("layer-list")) {
985            drawable = new LayerDrawable();
986        } else if (name.equals("transition")) {
987            drawable = new TransitionDrawable();
988        } else if (name.equals("reveal")) {
989            drawable = new RevealDrawable();
990        } else if (name.equals("touch-feedback")) {
991            drawable = new TouchFeedbackDrawable();
992        } else if (name.equals("color")) {
993            drawable = new ColorDrawable();
994        } else if (name.equals("shape")) {
995            drawable = new GradientDrawable();
996        } else if (name.equals("scale")) {
997            drawable = new ScaleDrawable();
998        } else if (name.equals("clip")) {
999            drawable = new ClipDrawable();
1000        } else if (name.equals("rotate")) {
1001            drawable = new RotateDrawable();
1002        } else if (name.equals("animated-rotate")) {
1003            drawable = new AnimatedRotateDrawable();
1004        } else if (name.equals("animation-list")) {
1005            drawable = new AnimationDrawable();
1006        } else if (name.equals("inset")) {
1007            drawable = new InsetDrawable();
1008        } else if (name.equals("bitmap")) {
1009            //noinspection deprecation
1010            drawable = new BitmapDrawable(r);
1011            if (r != null) {
1012               ((BitmapDrawable) drawable).setTargetDensity(r.getDisplayMetrics());
1013            }
1014        } else if (name.equals("nine-patch")) {
1015            drawable = new NinePatchDrawable();
1016            if (r != null) {
1017                ((NinePatchDrawable) drawable).setTargetDensity(r.getDisplayMetrics());
1018             }
1019        } else {
1020            throw new XmlPullParserException(parser.getPositionDescription() +
1021                    ": invalid drawable tag " + name);
1022        }
1023
1024        drawable.inflate(r, parser, attrs);
1025        return drawable;
1026    }
1027
1028
1029    /**
1030     * Create a drawable from file path name.
1031     */
1032    public static Drawable createFromPath(String pathName) {
1033        if (pathName == null) {
1034            return null;
1035        }
1036
1037        Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, pathName);
1038        try {
1039            Bitmap bm = BitmapFactory.decodeFile(pathName);
1040            if (bm != null) {
1041                return drawableFromBitmap(null, bm, null, null, null, pathName);
1042            }
1043        } finally {
1044            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
1045        }
1046
1047        return null;
1048    }
1049
1050    /**
1051     * Inflate this Drawable from an XML resource.
1052     */
1053    public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs)
1054            throws XmlPullParserException, IOException {
1055
1056        TypedArray a = r.obtainAttributes(attrs, com.android.internal.R.styleable.Drawable);
1057        inflateWithAttributes(r, parser, a, com.android.internal.R.styleable.Drawable_visible);
1058        a.recycle();
1059    }
1060
1061    /**
1062     * Inflate a Drawable from an XML resource.
1063     *
1064     * @throws XmlPullParserException
1065     * @throws IOException
1066     */
1067    void inflateWithAttributes(Resources r, XmlPullParser parser,
1068            TypedArray attrs, int visibleAttr)
1069            throws XmlPullParserException, IOException {
1070
1071        mVisible = attrs.getBoolean(visibleAttr, mVisible);
1072    }
1073
1074    /**
1075     * This abstract class is used by {@link Drawable}s to store shared constant state and data
1076     * between Drawables. {@link BitmapDrawable}s created from the same resource will for instance
1077     * share a unique bitmap stored in their ConstantState.
1078     *
1079     * <p>
1080     * {@link #newDrawable(Resources)} can be used as a factory to create new Drawable instances
1081     * from this ConstantState.
1082     * </p>
1083     *
1084     * Use {@link Drawable#getConstantState()} to retrieve the ConstantState of a Drawable. Calling
1085     * {@link Drawable#mutate()} on a Drawable should typically create a new ConstantState for that
1086     * Drawable.
1087     */
1088    public static abstract class ConstantState {
1089        /**
1090         * Create a new drawable without supplying resources the caller
1091         * is running in.  Note that using this means the density-dependent
1092         * drawables (like bitmaps) will not be able to update their target
1093         * density correctly. One should use {@link #newDrawable(Resources)}
1094         * instead to provide a resource.
1095         */
1096        public abstract Drawable newDrawable();
1097        /**
1098         * Create a new Drawable instance from its constant state.  This
1099         * must be implemented for drawables that change based on the target
1100         * density of their caller (that is depending on whether it is
1101         * in compatibility mode).
1102         */
1103        public Drawable newDrawable(Resources res) {
1104            return newDrawable();
1105        }
1106        /**
1107         * Return a bit mask of configuration changes that will impact
1108         * this drawable (and thus require completely reloading it).
1109         */
1110        public abstract int getChangingConfigurations();
1111
1112        /**
1113         * @hide
1114         */
1115        public Bitmap getBitmap() {
1116            return null;
1117        }
1118    }
1119
1120    /**
1121     * Return a {@link ConstantState} instance that holds the shared state of this Drawable.
1122     *
1123     * @return The ConstantState associated to that Drawable.
1124     * @see ConstantState
1125     * @see Drawable#mutate()
1126     */
1127    public ConstantState getConstantState() {
1128        return null;
1129    }
1130
1131    private static Drawable drawableFromBitmap(Resources res, Bitmap bm, byte[] np,
1132            Rect pad, Rect layoutBounds, String srcName) {
1133
1134        if (np != null) {
1135            return new NinePatchDrawable(res, bm, np, pad, layoutBounds, srcName);
1136        }
1137
1138        return new BitmapDrawable(res, bm);
1139    }
1140
1141    /**
1142     * Parses a {@link android.graphics.PorterDuff.Mode} from a tintMode
1143     * attribute's enum value.
1144     */
1145    static PorterDuff.Mode parseTintMode(int value, Mode defaultMode) {
1146        switch (value) {
1147            case 0:
1148                return Mode.SRC_IN;
1149            case 1:
1150                return Mode.SRC_ATOP;
1151            case 2:
1152                return Mode.MULTIPLY;
1153            case 3:
1154                return Mode.SCREEN;
1155        }
1156        return defaultMode;
1157    }
1158}
1159
1160