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