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