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