Drawable.java revision 3f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aa
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     * Gets the current alpha value for the drawable. 0 means fully transparent,
415     * 255 means fully opaque. This method is implemented by
416     * Drawable subclasses and the value returned is specific to how that class treats alpha.
417     * The default return value is 255 if the class does not override this method to return a value
418     * specific to its use of alpha.
419     */
420    public int getAlpha() {
421        return 0xFF;
422    }
423
424    /**
425     * Specify an optional colorFilter for the drawable. Pass null to remove
426     * any filters.
427    */
428    public abstract void setColorFilter(ColorFilter cf);
429
430    /**
431     * Specify a color and porterduff mode to be the colorfilter for this
432     * drawable.
433     */
434    public void setColorFilter(int color, PorterDuff.Mode mode) {
435        setColorFilter(new PorterDuffColorFilter(color, mode));
436    }
437
438    public void clearColorFilter() {
439        setColorFilter(null);
440    }
441
442    /**
443     * Indicates whether this view will change its appearance based on state.
444     * Clients can use this to determine whether it is necessary to calculate
445     * their state and call setState.
446     *
447     * @return True if this view changes its appearance based on state, false
448     *         otherwise.
449     *
450     * @see #setState(int[])
451     */
452    public boolean isStateful() {
453        return false;
454    }
455
456    /**
457     * Specify a set of states for the drawable. These are use-case specific,
458     * so see the relevant documentation. As an example, the background for
459     * widgets like Button understand the following states:
460     * [{@link android.R.attr#state_focused},
461     *  {@link android.R.attr#state_pressed}].
462     *
463     * <p>If the new state you are supplying causes the appearance of the
464     * Drawable to change, then it is responsible for calling
465     * {@link #invalidateSelf} in order to have itself redrawn, <em>and</em>
466     * true will be returned from this function.
467     *
468     * <p>Note: The Drawable holds a reference on to <var>stateSet</var>
469     * until a new state array is given to it, so you must not modify this
470     * array during that time.</p>
471     *
472     * @param stateSet The new set of states to be displayed.
473     *
474     * @return Returns true if this change in state has caused the appearance
475     * of the Drawable to change (hence requiring an invalidate), otherwise
476     * returns false.
477     */
478    public boolean setState(final int[] stateSet) {
479        if (!Arrays.equals(mStateSet, stateSet)) {
480            mStateSet = stateSet;
481            return onStateChange(stateSet);
482        }
483        return false;
484    }
485
486    /**
487     * Describes the current state, as a union of primitve states, such as
488     * {@link android.R.attr#state_focused},
489     * {@link android.R.attr#state_selected}, etc.
490     * Some drawables may modify their imagery based on the selected state.
491     * @return An array of resource Ids describing the current state.
492     */
493    public int[] getState() {
494        return mStateSet;
495    }
496
497    /**
498     * If this Drawable does transition animations between states, ask that
499     * it immediately jump to the current state and skip any active animations.
500     */
501    public void jumpToCurrentState() {
502    }
503
504    /**
505     * @return The current drawable that will be used by this drawable. For simple drawables, this
506     *         is just the drawable itself. For drawables that change state like
507     *         {@link StateListDrawable} and {@link LevelListDrawable} this will be the child drawable
508     *         currently in use.
509     */
510    public Drawable getCurrent() {
511        return this;
512    }
513
514    /**
515     * Specify the level for the drawable.  This allows a drawable to vary its
516     * imagery based on a continuous controller, for example to show progress
517     * or volume level.
518     *
519     * <p>If the new level you are supplying causes the appearance of the
520     * Drawable to change, then it is responsible for calling
521     * {@link #invalidateSelf} in order to have itself redrawn, <em>and</em>
522     * true will be returned from this function.
523     *
524     * @param level The new level, from 0 (minimum) to 10000 (maximum).
525     *
526     * @return Returns true if this change in level has caused the appearance
527     * of the Drawable to change (hence requiring an invalidate), otherwise
528     * returns false.
529     */
530    public final boolean setLevel(int level) {
531        if (mLevel != level) {
532            mLevel = level;
533            return onLevelChange(level);
534        }
535        return false;
536    }
537
538    /**
539     * Retrieve the current level.
540     *
541     * @return int Current level, from 0 (minimum) to 10000 (maximum).
542     */
543    public final int getLevel() {
544        return mLevel;
545    }
546
547    /**
548     * Set whether this Drawable is visible.  This generally does not impact
549     * the Drawable's behavior, but is a hint that can be used by some
550     * Drawables, for example, to decide whether run animations.
551     *
552     * @param visible Set to true if visible, false if not.
553     * @param restart You can supply true here to force the drawable to behave
554     *                as if it has just become visible, even if it had last
555     *                been set visible.  Used for example to force animations
556     *                to restart.
557     *
558     * @return boolean Returns true if the new visibility is different than
559     *         its previous state.
560     */
561    public boolean setVisible(boolean visible, boolean restart) {
562        boolean changed = mVisible != visible;
563        if (changed) {
564            mVisible = visible;
565            invalidateSelf();
566        }
567        return changed;
568    }
569
570    public final boolean isVisible() {
571        return mVisible;
572    }
573
574    /**
575     * Set whether this Drawable is automatically mirrored when its layout direction is RTL
576     * (right-to left). See {@link android.util.LayoutDirection}.
577     *
578     * @param mirrored Set to true if the Drawable should be mirrored, false if not.
579     */
580    public void setAutoMirrored(boolean mirrored) {
581    }
582
583    /**
584     * Tells if this Drawable will be automatically mirrored  when its layout direction is RTL
585     * right-to-left. See {@link android.util.LayoutDirection}.
586     *
587     * @return boolean Returns true if this Drawable will be automatically mirrored.
588     */
589    public boolean isAutoMirrored() {
590        return false;
591    }
592
593    /**
594     * Return the opacity/transparency of this Drawable.  The returned value is
595     * one of the abstract format constants in
596     * {@link android.graphics.PixelFormat}:
597     * {@link android.graphics.PixelFormat#UNKNOWN},
598     * {@link android.graphics.PixelFormat#TRANSLUCENT},
599     * {@link android.graphics.PixelFormat#TRANSPARENT}, or
600     * {@link android.graphics.PixelFormat#OPAQUE}.
601     *
602     * <p>Generally a Drawable should be as conservative as possible with the
603     * value it returns.  For example, if it contains multiple child drawables
604     * and only shows one of them at a time, if only one of the children is
605     * TRANSLUCENT and the others are OPAQUE then TRANSLUCENT should be
606     * returned.  You can use the method {@link #resolveOpacity} to perform a
607     * standard reduction of two opacities to the appropriate single output.
608     *
609     * <p>Note that the returned value does <em>not</em> take into account a
610     * custom alpha or color filter that has been applied by the client through
611     * the {@link #setAlpha} or {@link #setColorFilter} methods.
612     *
613     * @return int The opacity class of the Drawable.
614     *
615     * @see android.graphics.PixelFormat
616     */
617    public abstract int getOpacity();
618
619    /**
620     * Return the appropriate opacity value for two source opacities.  If
621     * either is UNKNOWN, that is returned; else, if either is TRANSLUCENT,
622     * that is returned; else, if either is TRANSPARENT, that is returned;
623     * else, OPAQUE is returned.
624     *
625     * <p>This is to help in implementing {@link #getOpacity}.
626     *
627     * @param op1 One opacity value.
628     * @param op2 Another opacity value.
629     *
630     * @return int The combined opacity value.
631     *
632     * @see #getOpacity
633     */
634    public static int resolveOpacity(int op1, int op2) {
635        if (op1 == op2) {
636            return op1;
637        }
638        if (op1 == PixelFormat.UNKNOWN || op2 == PixelFormat.UNKNOWN) {
639            return PixelFormat.UNKNOWN;
640        }
641        if (op1 == PixelFormat.TRANSLUCENT || op2 == PixelFormat.TRANSLUCENT) {
642            return PixelFormat.TRANSLUCENT;
643        }
644        if (op1 == PixelFormat.TRANSPARENT || op2 == PixelFormat.TRANSPARENT) {
645            return PixelFormat.TRANSPARENT;
646        }
647        return PixelFormat.OPAQUE;
648    }
649
650    /**
651     * Returns a Region representing the part of the Drawable that is completely
652     * transparent.  This can be used to perform drawing operations, identifying
653     * which parts of the target will not change when rendering the Drawable.
654     * The default implementation returns null, indicating no transparent
655     * region; subclasses can optionally override this to return an actual
656     * Region if they want to supply this optimization information, but it is
657     * not required that they do so.
658     *
659     * @return Returns null if the Drawables has no transparent region to
660     * report, else a Region holding the parts of the Drawable's bounds that
661     * are transparent.
662     */
663    public Region getTransparentRegion() {
664        return null;
665    }
666
667    /**
668     * Override this in your subclass to change appearance if you recognize the
669     * specified state.
670     *
671     * @return Returns true if the state change has caused the appearance of
672     * the Drawable to change (that is, it needs to be drawn), else false
673     * if it looks the same and there is no need to redraw it since its
674     * last state.
675     */
676    protected boolean onStateChange(int[] state) { return false; }
677    /** Override this in your subclass to change appearance if you vary based
678     *  on level.
679     * @return Returns true if the level change has caused the appearance of
680     * the Drawable to change (that is, it needs to be drawn), else false
681     * if it looks the same and there is no need to redraw it since its
682     * last level.
683     */
684    protected boolean onLevelChange(int level) { return false; }
685    /**
686     * Override this in your subclass to change appearance if you recognize the
687     * specified state.
688     */
689    protected void onBoundsChange(Rect bounds) {}
690
691    /**
692     * Return the intrinsic width of the underlying drawable object.  Returns
693     * -1 if it has no intrinsic width, such as with a solid color.
694     */
695    public int getIntrinsicWidth() {
696        return -1;
697    }
698
699    /**
700     * Return the intrinsic height of the underlying drawable object. Returns
701     * -1 if it has no intrinsic height, such as with a solid color.
702     */
703    public int getIntrinsicHeight() {
704        return -1;
705    }
706
707    /**
708     * Returns the minimum width suggested by this Drawable. If a View uses this
709     * Drawable as a background, it is suggested that the View use at least this
710     * value for its width. (There will be some scenarios where this will not be
711     * possible.) This value should INCLUDE any padding.
712     *
713     * @return The minimum width suggested by this Drawable. If this Drawable
714     *         doesn't have a suggested minimum width, 0 is returned.
715     */
716    public int getMinimumWidth() {
717        final int intrinsicWidth = getIntrinsicWidth();
718        return intrinsicWidth > 0 ? intrinsicWidth : 0;
719    }
720
721    /**
722     * Returns the minimum height suggested by this Drawable. If a View uses this
723     * Drawable as a background, it is suggested that the View use at least this
724     * value for its height. (There will be some scenarios where this will not be
725     * possible.) This value should INCLUDE any padding.
726     *
727     * @return The minimum height suggested by this Drawable. If this Drawable
728     *         doesn't have a suggested minimum height, 0 is returned.
729     */
730    public int getMinimumHeight() {
731        final int intrinsicHeight = getIntrinsicHeight();
732        return intrinsicHeight > 0 ? intrinsicHeight : 0;
733    }
734
735    /**
736     * Return in padding the insets suggested by this Drawable for placing
737     * content inside the drawable's bounds. Positive values move toward the
738     * center of the Drawable (set Rect.inset). Returns true if this drawable
739     * actually has a padding, else false. When false is returned, the padding
740     * is always set to 0.
741     */
742    public boolean getPadding(Rect padding) {
743        padding.set(0, 0, 0, 0);
744        return false;
745    }
746
747    /**
748     * Return in insets the layout insets suggested by this Drawable for use with alignment
749     * operations during layout.
750     *
751     * @hide
752     */
753    public Insets getOpticalInsets() {
754        return Insets.NONE;
755    }
756
757    /**
758     * Make this drawable mutable. This operation cannot be reversed. A mutable
759     * drawable is guaranteed to not share its state with any other drawable.
760     * This is especially useful when you need to modify properties of drawables
761     * loaded from resources. By default, all drawables instances loaded from
762     * the same resource share a common state; if you modify the state of one
763     * instance, all the other instances will receive the same modification.
764     *
765     * Calling this method on a mutable Drawable will have no effect.
766     *
767     * @return This drawable.
768     * @see ConstantState
769     * @see #getConstantState()
770     */
771    public Drawable mutate() {
772        return this;
773    }
774
775    /**
776     * Create a drawable from an inputstream
777     */
778    public static Drawable createFromStream(InputStream is, String srcName) {
779        Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, srcName != null ? srcName : "Unknown drawable");
780        try {
781            return createFromResourceStream(null, null, is, srcName, null);
782        } finally {
783            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
784        }
785    }
786
787    /**
788     * Create a drawable from an inputstream, using the given resources and
789     * value to determine density information.
790     */
791    public static Drawable createFromResourceStream(Resources res, TypedValue value,
792            InputStream is, String srcName) {
793        Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, srcName != null ? srcName : "Unknown drawable");
794        try {
795            return createFromResourceStream(res, value, is, srcName, null);
796        } finally {
797            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
798        }
799    }
800
801    /**
802     * Create a drawable from an inputstream, using the given resources and
803     * value to determine density information.
804     */
805    public static Drawable createFromResourceStream(Resources res, TypedValue value,
806            InputStream is, String srcName, BitmapFactory.Options opts) {
807
808        if (is == null) {
809            return null;
810        }
811
812        /*  ugh. The decodeStream contract is that we have already allocated
813            the pad rect, but if the bitmap does not had a ninepatch chunk,
814            then the pad will be ignored. If we could change this to lazily
815            alloc/assign the rect, we could avoid the GC churn of making new
816            Rects only to drop them on the floor.
817        */
818        Rect pad = new Rect();
819
820        // Special stuff for compatibility mode: if the target density is not
821        // the same as the display density, but the resource -is- the same as
822        // the display density, then don't scale it down to the target density.
823        // This allows us to load the system's density-correct resources into
824        // an application in compatibility mode, without scaling those down
825        // to the compatibility density only to have them scaled back up when
826        // drawn to the screen.
827        if (opts == null) opts = new BitmapFactory.Options();
828        opts.inScreenDensity = res != null
829                ? res.getDisplayMetrics().noncompatDensityDpi : DisplayMetrics.DENSITY_DEVICE;
830        Bitmap  bm = BitmapFactory.decodeResourceStream(res, value, is, pad, opts);
831        if (bm != null) {
832            byte[] np = bm.getNinePatchChunk();
833            if (np == null || !NinePatch.isNinePatchChunk(np)) {
834                np = null;
835                pad = null;
836            }
837            int[] layoutBounds = bm.getLayoutBounds();
838            Rect layoutBoundsRect = null;
839            if (layoutBounds != null) {
840                layoutBoundsRect = new Rect(layoutBounds[0], layoutBounds[1],
841                                             layoutBounds[2], layoutBounds[3]);
842            }
843            return drawableFromBitmap(res, bm, np, pad, layoutBoundsRect, srcName);
844        }
845        return null;
846    }
847
848    /**
849     * Create a drawable from an XML document. For more information on how to
850     * create resources in XML, see
851     * <a href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.
852     */
853    public static Drawable createFromXml(Resources r, XmlPullParser parser)
854            throws XmlPullParserException, IOException {
855        AttributeSet attrs = Xml.asAttributeSet(parser);
856
857        int type;
858        while ((type=parser.next()) != XmlPullParser.START_TAG &&
859                type != XmlPullParser.END_DOCUMENT) {
860            // Empty loop
861        }
862
863        if (type != XmlPullParser.START_TAG) {
864            throw new XmlPullParserException("No start tag found");
865        }
866
867        Drawable drawable = createFromXmlInner(r, parser, attrs);
868
869        if (drawable == null) {
870            throw new RuntimeException("Unknown initial tag: " + parser.getName());
871        }
872
873        return drawable;
874    }
875
876    /**
877     * Create from inside an XML document.  Called on a parser positioned at
878     * a tag in an XML document, tries to create a Drawable from that tag.
879     * Returns null if the tag is not a valid drawable.
880     */
881    public static Drawable createFromXmlInner(Resources r, XmlPullParser parser, AttributeSet attrs)
882    throws XmlPullParserException, IOException {
883        Drawable drawable;
884
885        final String name = parser.getName();
886
887        if (name.equals("selector")) {
888            drawable = new StateListDrawable();
889        } else if (name.equals("level-list")) {
890            drawable = new LevelListDrawable();
891        } else if (name.equals("layer-list")) {
892            drawable = new LayerDrawable();
893        } else if (name.equals("transition")) {
894            drawable = new TransitionDrawable();
895        } else if (name.equals("color")) {
896            drawable = new ColorDrawable();
897        } else if (name.equals("shape")) {
898            drawable = new GradientDrawable();
899        } else if (name.equals("scale")) {
900            drawable = new ScaleDrawable();
901        } else if (name.equals("clip")) {
902            drawable = new ClipDrawable();
903        } else if (name.equals("rotate")) {
904            drawable = new RotateDrawable();
905        } else if (name.equals("animated-rotate")) {
906            drawable = new AnimatedRotateDrawable();
907        } else if (name.equals("animation-list")) {
908            drawable = new AnimationDrawable();
909        } else if (name.equals("inset")) {
910            drawable = new InsetDrawable();
911        } else if (name.equals("bitmap")) {
912            //noinspection deprecation
913            drawable = new BitmapDrawable(r);
914            if (r != null) {
915               ((BitmapDrawable) drawable).setTargetDensity(r.getDisplayMetrics());
916            }
917        } else if (name.equals("nine-patch")) {
918            drawable = new NinePatchDrawable();
919            if (r != null) {
920                ((NinePatchDrawable) drawable).setTargetDensity(r.getDisplayMetrics());
921             }
922        } else {
923            throw new XmlPullParserException(parser.getPositionDescription() +
924                    ": invalid drawable tag " + name);
925        }
926
927        drawable.inflate(r, parser, attrs);
928        return drawable;
929    }
930
931
932    /**
933     * Create a drawable from file path name.
934     */
935    public static Drawable createFromPath(String pathName) {
936        if (pathName == null) {
937            return null;
938        }
939
940        Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, pathName);
941        try {
942            Bitmap bm = BitmapFactory.decodeFile(pathName);
943            if (bm != null) {
944                return drawableFromBitmap(null, bm, null, null, null, pathName);
945            }
946        } finally {
947            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
948        }
949
950        return null;
951    }
952
953    /**
954     * Inflate this Drawable from an XML resource.
955     */
956    public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs)
957            throws XmlPullParserException, IOException {
958
959        TypedArray a = r.obtainAttributes(attrs, com.android.internal.R.styleable.Drawable);
960        inflateWithAttributes(r, parser, a, com.android.internal.R.styleable.Drawable_visible);
961        a.recycle();
962    }
963
964    /**
965     * Inflate a Drawable from an XML resource.
966     *
967     * @throws XmlPullParserException
968     * @throws IOException
969     */
970    void inflateWithAttributes(Resources r, XmlPullParser parser,
971            TypedArray attrs, int visibleAttr)
972            throws XmlPullParserException, IOException {
973
974        mVisible = attrs.getBoolean(visibleAttr, mVisible);
975    }
976
977    /**
978     * This abstract class is used by {@link Drawable}s to store shared constant state and data
979     * between Drawables. {@link BitmapDrawable}s created from the same resource will for instance
980     * share a unique bitmap stored in their ConstantState.
981     *
982     * <p>
983     * {@link #newDrawable(Resources)} can be used as a factory to create new Drawable instances
984     * from this ConstantState.
985     * </p>
986     *
987     * Use {@link Drawable#getConstantState()} to retrieve the ConstantState of a Drawable. Calling
988     * {@link Drawable#mutate()} on a Drawable should typically create a new ConstantState for that
989     * Drawable.
990     */
991    public static abstract class ConstantState {
992        /**
993         * Create a new drawable without supplying resources the caller
994         * is running in.  Note that using this means the density-dependent
995         * drawables (like bitmaps) will not be able to update their target
996         * density correctly. One should use {@link #newDrawable(Resources)}
997         * instead to provide a resource.
998         */
999        public abstract Drawable newDrawable();
1000        /**
1001         * Create a new Drawable instance from its constant state.  This
1002         * must be implemented for drawables that change based on the target
1003         * density of their caller (that is depending on whether it is
1004         * in compatibility mode).
1005         */
1006        public Drawable newDrawable(Resources res) {
1007            return newDrawable();
1008        }
1009        /**
1010         * Return a bit mask of configuration changes that will impact
1011         * this drawable (and thus require completely reloading it).
1012         */
1013        public abstract int getChangingConfigurations();
1014
1015        /**
1016         * @hide
1017         */
1018        public Bitmap getBitmap() {
1019            return null;
1020        }
1021    }
1022
1023    /**
1024     * Return a {@link ConstantState} instance that holds the shared state of this Drawable.
1025     *q
1026     * @return The ConstantState associated to that Drawable.
1027     * @see ConstantState
1028     * @see Drawable#mutate()
1029     */
1030    public ConstantState getConstantState() {
1031        return null;
1032    }
1033
1034    private static Drawable drawableFromBitmap(Resources res, Bitmap bm, byte[] np,
1035            Rect pad, Rect layoutBounds, String srcName) {
1036
1037        if (np != null) {
1038            return new NinePatchDrawable(res, bm, np, pad, layoutBounds, srcName);
1039        }
1040
1041        return new BitmapDrawable(res, bm);
1042    }
1043}
1044
1045