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