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