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 android.annotation.ColorInt;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.content.res.ColorStateList;
23 import android.content.res.Resources;
24 import android.content.res.Resources.Theme;
25 import android.content.res.TypedArray;
26 import android.graphics.Bitmap;
27 import android.graphics.BitmapFactory;
28 import android.graphics.Canvas;
29 import android.graphics.Color;
30 import android.graphics.ColorFilter;
31 import android.graphics.Insets;
32 import android.graphics.NinePatch;
33 import android.graphics.Outline;
34 import android.graphics.PixelFormat;
35 import android.graphics.PorterDuff;
36 import android.graphics.PorterDuff.Mode;
37 import android.graphics.PorterDuffColorFilter;
38 import android.graphics.Rect;
39 import android.graphics.Region;
40 import android.graphics.Xfermode;
41 import android.os.Trace;
42 import android.util.AttributeSet;
43 import android.util.DisplayMetrics;
44 import android.util.StateSet;
45 import android.util.TypedValue;
46 import android.util.Xml;
47 import android.view.View;
48 
49 import org.xmlpull.v1.XmlPullParser;
50 import org.xmlpull.v1.XmlPullParserException;
51 
52 import java.io.IOException;
53 import java.io.InputStream;
54 import java.lang.ref.WeakReference;
55 import java.util.Arrays;
56 import java.util.Collection;
57 
58 /**
59  * A Drawable is a general abstraction for "something that can be drawn."  Most
60  * often you will deal with Drawable as the type of resource retrieved for
61  * drawing things to the screen; the Drawable class provides a generic API for
62  * dealing with an underlying visual resource that may take a variety of forms.
63  * Unlike a {@link android.view.View}, a Drawable does not have any facility to
64  * receive events or otherwise interact with the user.
65  *
66  * <p>In addition to simple drawing, Drawable provides a number of generic
67  * mechanisms for its client to interact with what is being drawn:
68  *
69  * <ul>
70  *     <li> The {@link #setBounds} method <var>must</var> be called to tell the
71  *     Drawable where it is drawn and how large it should be.  All Drawables
72  *     should respect the requested size, often simply by scaling their
73  *     imagery.  A client can find the preferred size for some Drawables with
74  *     the {@link #getIntrinsicHeight} and {@link #getIntrinsicWidth} methods.
75  *
76  *     <li> The {@link #getPadding} method can return from some Drawables
77  *     information about how to frame content that is placed inside of them.
78  *     For example, a Drawable that is intended to be the frame for a button
79  *     widget would need to return padding that correctly places the label
80  *     inside of itself.
81  *
82  *     <li> The {@link #setState} method allows the client to tell the Drawable
83  *     in which state it is to be drawn, such as "focused", "selected", etc.
84  *     Some drawables may modify their imagery based on the selected state.
85  *
86  *     <li> The {@link #setLevel} method allows the client to supply a single
87  *     continuous controller that can modify the Drawable is displayed, such as
88  *     a battery level or progress level.  Some drawables may modify their
89  *     imagery based on the current level.
90  *
91  *     <li> A Drawable can perform animations by calling back to its client
92  *     through the {@link Callback} interface.  All clients should support this
93  *     interface (via {@link #setCallback}) so that animations will work.  A
94  *     simple way to do this is through the system facilities such as
95  *     {@link android.view.View#setBackground(Drawable)} and
96  *     {@link android.widget.ImageView}.
97  * </ul>
98  *
99  * Though usually not visible to the application, Drawables may take a variety
100  * of forms:
101  *
102  * <ul>
103  *     <li> <b>Bitmap</b>: the simplest Drawable, a PNG or JPEG image.
104  *     <li> <b>Nine Patch</b>: an extension to the PNG format allows it to
105  *     specify information about how to stretch it and place things inside of
106  *     it.
107  *     <li> <b>Shape</b>: contains simple drawing commands instead of a raw
108  *     bitmap, allowing it to resize better in some cases.
109  *     <li> <b>Layers</b>: a compound drawable, which draws multiple underlying
110  *     drawables on top of each other.
111  *     <li> <b>States</b>: a compound drawable that selects one of a set of
112  *     drawables based on its state.
113  *     <li> <b>Levels</b>: a compound drawable that selects one of a set of
114  *     drawables based on its level.
115  *     <li> <b>Scale</b>: a compound drawable with a single child drawable,
116  *     whose overall size is modified based on the current level.
117  * </ul>
118  *
119  * <div class="special reference">
120  * <h3>Developer Guides</h3>
121  * <p>For more information about how to use drawables, read the
122  * <a href="{@docRoot}guide/topics/graphics/2d-graphics.html">Canvas and Drawables</a> developer
123  * guide. For information and examples of creating drawable resources (XML or bitmap files that
124  * can be loaded in code), read the
125  * <a href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>
126  * document.</p></div>
127  */
128 public abstract class Drawable {
129     private static final Rect ZERO_BOUNDS_RECT = new Rect();
130 
131     static final PorterDuff.Mode DEFAULT_TINT_MODE = PorterDuff.Mode.SRC_IN;
132 
133     private int[] mStateSet = StateSet.WILD_CARD;
134     private int mLevel = 0;
135     private int mChangingConfigurations = 0;
136     private Rect mBounds = ZERO_BOUNDS_RECT;  // lazily becomes a new Rect()
137     private WeakReference<Callback> mCallback = null;
138     private boolean mVisible = true;
139 
140     private int mLayoutDirection;
141 
142     /**
143      * Draw in its bounds (set via setBounds) respecting optional effects such
144      * as alpha (set via setAlpha) and color filter (set via setColorFilter).
145      *
146      * @param canvas The canvas to draw into
147      */
draw(Canvas canvas)148     public abstract void draw(Canvas canvas);
149 
150     /**
151      * Specify a bounding rectangle for the Drawable. This is where the drawable
152      * will draw when its draw() method is called.
153      */
setBounds(int left, int top, int right, int bottom)154     public void setBounds(int left, int top, int right, int bottom) {
155         Rect oldBounds = mBounds;
156 
157         if (oldBounds == ZERO_BOUNDS_RECT) {
158             oldBounds = mBounds = new Rect();
159         }
160 
161         if (oldBounds.left != left || oldBounds.top != top ||
162                 oldBounds.right != right || oldBounds.bottom != bottom) {
163             if (!oldBounds.isEmpty()) {
164                 // first invalidate the previous bounds
165                 invalidateSelf();
166             }
167             mBounds.set(left, top, right, bottom);
168             onBoundsChange(mBounds);
169         }
170     }
171 
172     /**
173      * Specify a bounding rectangle for the Drawable. This is where the drawable
174      * will draw when its draw() method is called.
175      */
setBounds(Rect bounds)176     public void setBounds(Rect bounds) {
177         setBounds(bounds.left, bounds.top, bounds.right, bounds.bottom);
178     }
179 
180     /**
181      * Return a copy of the drawable's bounds in the specified Rect (allocated
182      * by the caller). The bounds specify where this will draw when its draw()
183      * method is called.
184      *
185      * @param bounds Rect to receive the drawable's bounds (allocated by the
186      *               caller).
187      */
copyBounds(Rect bounds)188     public final void copyBounds(Rect bounds) {
189         bounds.set(mBounds);
190     }
191 
192     /**
193      * Return a copy of the drawable's bounds in a new Rect. This returns the
194      * same values as getBounds(), but the returned object is guaranteed to not
195      * be changed later by the drawable (i.e. it retains no reference to this
196      * rect). If the caller already has a Rect allocated, call copyBounds(rect).
197      *
198      * @return A copy of the drawable's bounds
199      */
copyBounds()200     public final Rect copyBounds() {
201         return new Rect(mBounds);
202     }
203 
204     /**
205      * Return the drawable's bounds Rect. Note: for efficiency, the returned
206      * object may be the same object stored in the drawable (though this is not
207      * guaranteed), so if a persistent copy of the bounds is needed, call
208      * copyBounds(rect) instead.
209      * You should also not change the object returned by this method as it may
210      * be the same object stored in the drawable.
211      *
212      * @return The bounds of the drawable (which may change later, so caller
213      *         beware). DO NOT ALTER the returned object as it may change the
214      *         stored bounds of this drawable.
215      *
216      * @see #copyBounds()
217      * @see #copyBounds(android.graphics.Rect)
218      */
getBounds()219     public final Rect getBounds() {
220         if (mBounds == ZERO_BOUNDS_RECT) {
221             mBounds = new Rect();
222         }
223 
224         return mBounds;
225     }
226 
227     /**
228      * Return the drawable's dirty bounds Rect. Note: for efficiency, the
229      * returned object may be the same object stored in the drawable (though
230      * this is not guaranteed).
231      * <p>
232      * By default, this returns the full drawable bounds. Custom drawables may
233      * override this method to perform more precise invalidation.
234      *
235      * @return The dirty bounds of this drawable
236      */
getDirtyBounds()237     public Rect getDirtyBounds() {
238         return getBounds();
239     }
240 
241     /**
242      * Set a mask of the configuration parameters for which this drawable
243      * may change, requiring that it be re-created.
244      *
245      * @param configs A mask of the changing configuration parameters, as
246      * defined by {@link android.content.pm.ActivityInfo}.
247      *
248      * @see android.content.pm.ActivityInfo
249      */
setChangingConfigurations(int configs)250     public void setChangingConfigurations(int configs) {
251         mChangingConfigurations = configs;
252     }
253 
254     /**
255      * Return a mask of the configuration parameters for which this drawable
256      * may change, requiring that it be re-created.  The default implementation
257      * returns whatever was provided through
258      * {@link #setChangingConfigurations(int)} or 0 by default.  Subclasses
259      * may extend this to or in the changing configurations of any other
260      * drawables they hold.
261      *
262      * @return Returns a mask of the changing configuration parameters, as
263      * defined by {@link android.content.pm.ActivityInfo}.
264      *
265      * @see android.content.pm.ActivityInfo
266      */
getChangingConfigurations()267     public int getChangingConfigurations() {
268         return mChangingConfigurations;
269     }
270 
271     /**
272      * Set to true to have the drawable dither its colors when drawn to a
273      * device with fewer than 8-bits per color component.
274      *
275      * @see android.graphics.Paint#setDither(boolean);
276      * @deprecated This property is ignored.
277      */
278     @Deprecated
setDither(boolean dither)279     public void setDither(boolean dither) {}
280 
281     /**
282      * Set to true to have the drawable filter its bitmaps with bilinear
283      * sampling when they are scaled or rotated.
284      *
285      * <p>This can improve appearance when bitmaps are rotated. If the drawable
286      * does not use bitmaps, this call is ignored.</p>
287      *
288      * @see #isFilterBitmap()
289      * @see android.graphics.Paint#setFilterBitmap(boolean);
290      */
setFilterBitmap(boolean filter)291     public void setFilterBitmap(boolean filter) {}
292 
293     /**
294      * @return whether this drawable filters its bitmaps
295      * @see #setFilterBitmap(boolean)
296      */
isFilterBitmap()297     public boolean isFilterBitmap() {
298         return false;
299     }
300 
301     /**
302      * Implement this interface if you want to create an animated drawable that
303      * extends {@link android.graphics.drawable.Drawable Drawable}.
304      * Upon retrieving a drawable, use
305      * {@link Drawable#setCallback(android.graphics.drawable.Drawable.Callback)}
306      * to supply your implementation of the interface to the drawable; it uses
307      * this interface to schedule and execute animation changes.
308      */
309     public static interface Callback {
310         /**
311          * Called when the drawable needs to be redrawn.  A view at this point
312          * should invalidate itself (or at least the part of itself where the
313          * drawable appears).
314          *
315          * @param who The drawable that is requesting the update.
316          */
invalidateDrawable(Drawable who)317         public void invalidateDrawable(Drawable who);
318 
319         /**
320          * A Drawable can call this to schedule the next frame of its
321          * animation.  An implementation can generally simply call
322          * {@link android.os.Handler#postAtTime(Runnable, Object, long)} with
323          * the parameters <var>(what, who, when)</var> to perform the
324          * scheduling.
325          *
326          * @param who The drawable being scheduled.
327          * @param what The action to execute.
328          * @param when The time (in milliseconds) to run.  The timebase is
329          *             {@link android.os.SystemClock#uptimeMillis}
330          */
scheduleDrawable(Drawable who, Runnable what, long when)331         public void scheduleDrawable(Drawable who, Runnable what, long when);
332 
333         /**
334          * A Drawable can call this to unschedule an action previously
335          * scheduled with {@link #scheduleDrawable}.  An implementation can
336          * generally simply call
337          * {@link android.os.Handler#removeCallbacks(Runnable, Object)} with
338          * the parameters <var>(what, who)</var> to unschedule the drawable.
339          *
340          * @param who The drawable being unscheduled.
341          * @param what The action being unscheduled.
342          */
unscheduleDrawable(Drawable who, Runnable what)343         public void unscheduleDrawable(Drawable who, Runnable what);
344     }
345 
346     /**
347      * Bind a {@link Callback} object to this Drawable.  Required for clients
348      * that want to support animated drawables.
349      *
350      * @param cb The client's Callback implementation.
351      *
352      * @see #getCallback()
353      */
setCallback(Callback cb)354     public final void setCallback(Callback cb) {
355         mCallback = new WeakReference<Callback>(cb);
356     }
357 
358     /**
359      * Return the current {@link Callback} implementation attached to this
360      * Drawable.
361      *
362      * @return A {@link Callback} instance or null if no callback was set.
363      *
364      * @see #setCallback(android.graphics.drawable.Drawable.Callback)
365      */
getCallback()366     public Callback getCallback() {
367         if (mCallback != null) {
368             return mCallback.get();
369         }
370         return null;
371     }
372 
373     /**
374      * Use the current {@link Callback} implementation to have this Drawable
375      * redrawn.  Does nothing if there is no Callback attached to the
376      * Drawable.
377      *
378      * @see Callback#invalidateDrawable
379      * @see #getCallback()
380      * @see #setCallback(android.graphics.drawable.Drawable.Callback)
381      */
invalidateSelf()382     public void invalidateSelf() {
383         final Callback callback = getCallback();
384         if (callback != null) {
385             callback.invalidateDrawable(this);
386         }
387     }
388 
389     /**
390      * Use the current {@link Callback} implementation to have this Drawable
391      * scheduled.  Does nothing if there is no Callback attached to the
392      * Drawable.
393      *
394      * @param what The action being scheduled.
395      * @param when The time (in milliseconds) to run.
396      *
397      * @see Callback#scheduleDrawable
398      */
scheduleSelf(Runnable what, long when)399     public void scheduleSelf(Runnable what, long when) {
400         final Callback callback = getCallback();
401         if (callback != null) {
402             callback.scheduleDrawable(this, what, when);
403         }
404     }
405 
406     /**
407      * Use the current {@link Callback} implementation to have this Drawable
408      * unscheduled.  Does nothing if there is no Callback attached to the
409      * Drawable.
410      *
411      * @param what The runnable that you no longer want called.
412      *
413      * @see Callback#unscheduleDrawable
414      */
unscheduleSelf(Runnable what)415     public void unscheduleSelf(Runnable what) {
416         final Callback callback = getCallback();
417         if (callback != null) {
418             callback.unscheduleDrawable(this, what);
419         }
420     }
421 
422     /**
423      * Returns the resolved layout direction for this Drawable.
424      *
425      * @return One of {@link android.view.View#LAYOUT_DIRECTION_LTR},
426      *         {@link android.view.View#LAYOUT_DIRECTION_RTL}
427      * @see #setLayoutDirection(int)
428      */
getLayoutDirection()429     public int getLayoutDirection() {
430         return mLayoutDirection;
431     }
432 
433     /**
434      * Set the layout direction for this drawable. Should be a resolved
435      * layout direction, as the Drawable has no capacity to do the resolution on
436      * its own.
437      *
438      * @param layoutDirection the resolved layout direction for the drawable,
439      *                        either {@link android.view.View#LAYOUT_DIRECTION_LTR}
440      *                        or {@link android.view.View#LAYOUT_DIRECTION_RTL}
441      * @see #getLayoutDirection()
442      */
setLayoutDirection(@iew.ResolvedLayoutDir int layoutDirection)443     public final boolean setLayoutDirection(@View.ResolvedLayoutDir int layoutDirection) {
444         if (mLayoutDirection != layoutDirection) {
445             mLayoutDirection = layoutDirection;
446             return onLayoutDirectionChanged(layoutDirection);
447         }
448         return false;
449     }
450 
451     /**
452      * Called when the drawable's resolved layout direction changes.
453      *
454      * @param layoutDirection the new resolved layout direction
455      * @return true if the layout direction change has caused the appearance of
456      *         the drawable to change and it needs to be re-drawn
457      * @see #setLayoutDirection(int)
458      */
onLayoutDirectionChanged(@iew.ResolvedLayoutDir int layoutDirection)459     public boolean onLayoutDirectionChanged(@View.ResolvedLayoutDir int layoutDirection) {
460         return false;
461     }
462 
463     /**
464      * Specify an alpha value for the drawable. 0 means fully transparent, and
465      * 255 means fully opaque.
466      */
setAlpha(int alpha)467     public abstract void setAlpha(int alpha);
468 
469     /**
470      * Gets the current alpha value for the drawable. 0 means fully transparent,
471      * 255 means fully opaque. This method is implemented by
472      * Drawable subclasses and the value returned is specific to how that class treats alpha.
473      * The default return value is 255 if the class does not override this method to return a value
474      * specific to its use of alpha.
475      */
getAlpha()476     public int getAlpha() {
477         return 0xFF;
478     }
479 
480     /**
481      * @hide
482      *
483      * Internal-only method for setting xfermode on certain supported drawables.
484      *
485      * Should not be made public since the layers and drawing area with which
486      * Drawables draw is private implementation detail, and not something apps
487      * should rely upon.
488      */
setXfermode(Xfermode mode)489     public void setXfermode(Xfermode mode) {
490         // Base implementation drops it on the floor for compatibility. Whee!
491     }
492 
493     /**
494      * Specify an optional color filter for the drawable.
495      * <p>
496      * If a Drawable has a ColorFilter, each output pixel of the Drawable's
497      * drawing contents will be modified by the color filter before it is
498      * blended onto the render target of a Canvas.
499      * </p>
500      * <p>
501      * Pass {@code null} to remove any existing color filter.
502      * </p>
503      * <p class="note"><strong>Note:</strong> Setting a non-{@code null} color
504      * filter disables {@link #setTintList(ColorStateList) tint}.
505      * </p>
506      *
507      * @param colorFilter The color filter to apply, or {@code null} to remove the
508      *            existing color filter
509      */
setColorFilter(@ullable ColorFilter colorFilter)510     public abstract void setColorFilter(@Nullable ColorFilter colorFilter);
511 
512     /**
513      * Specify a color and Porter-Duff mode to be the color filter for this
514      * drawable.
515      * <p>
516      * Convenience for {@link #setColorFilter(ColorFilter)} which constructs a
517      * {@link PorterDuffColorFilter}.
518      * </p>
519      * <p class="note"><strong>Note:</strong> Setting a color filter disables
520      * {@link #setTintList(ColorStateList) tint}.
521      * </p>
522      */
setColorFilter(@olorInt int color, @NonNull PorterDuff.Mode mode)523     public void setColorFilter(@ColorInt int color, @NonNull PorterDuff.Mode mode) {
524         setColorFilter(new PorterDuffColorFilter(color, mode));
525     }
526 
527     /**
528      * Specifies tint color for this drawable.
529      * <p>
530      * A Drawable's drawing content will be blended together with its tint
531      * before it is drawn to the screen. This functions similarly to
532      * {@link #setColorFilter(int, PorterDuff.Mode)}.
533      * </p>
534      * <p>
535      * To clear the tint, pass {@code null} to
536      * {@link #setTintList(ColorStateList)}.
537      * </p>
538      * <p class="note"><strong>Note:</strong> Setting a color filter via
539      * {@link #setColorFilter(ColorFilter)} or
540      * {@link #setColorFilter(int, PorterDuff.Mode)} overrides tint.
541      * </p>
542      *
543      * @param tintColor Color to use for tinting this drawable
544      * @see #setTintList(ColorStateList)
545      * @see #setTintMode(PorterDuff.Mode)
546      */
setTint(@olorInt int tintColor)547     public void setTint(@ColorInt int tintColor) {
548         setTintList(ColorStateList.valueOf(tintColor));
549     }
550 
551     /**
552      * Specifies tint color for this drawable as a color state list.
553      * <p>
554      * A Drawable's drawing content will be blended together with its tint
555      * before it is drawn to the screen. This functions similarly to
556      * {@link #setColorFilter(int, PorterDuff.Mode)}.
557      * </p>
558      * <p class="note"><strong>Note:</strong> Setting a color filter via
559      * {@link #setColorFilter(ColorFilter)} or
560      * {@link #setColorFilter(int, PorterDuff.Mode)} overrides tint.
561      * </p>
562      *
563      * @param tint Color state list to use for tinting this drawable, or
564      *            {@code null} to clear the tint
565      * @see #setTint(int)
566      * @see #setTintMode(PorterDuff.Mode)
567      */
setTintList(@ullable ColorStateList tint)568     public void setTintList(@Nullable ColorStateList tint) {}
569 
570     /**
571      * Specifies a tint blending mode for this drawable.
572      * <p>
573      * Defines how this drawable's tint color should be blended into the drawable
574      * before it is drawn to screen. Default tint mode is {@link PorterDuff.Mode#SRC_IN}.
575      * </p>
576      * <p class="note"><strong>Note:</strong> Setting a color filter via
577      * {@link #setColorFilter(ColorFilter)} or
578      * {@link #setColorFilter(int, PorterDuff.Mode)} overrides tint.
579      * </p>
580      *
581      * @param tintMode A Porter-Duff blending mode
582      * @see #setTint(int)
583      * @see #setTintList(ColorStateList)
584      */
setTintMode(@onNull PorterDuff.Mode tintMode)585     public void setTintMode(@NonNull PorterDuff.Mode tintMode) {}
586 
587     /**
588      * Returns the current color filter, or {@code null} if none set.
589      *
590      * @return the current color filter, or {@code null} if none set
591      */
getColorFilter()592     public ColorFilter getColorFilter() {
593         return null;
594     }
595 
596     /**
597      * Removes the color filter for this drawable.
598      */
clearColorFilter()599     public void clearColorFilter() {
600         setColorFilter(null);
601     }
602 
603     /**
604      * Specifies the hotspot's location within the drawable.
605      *
606      * @param x The X coordinate of the center of the hotspot
607      * @param y The Y coordinate of the center of the hotspot
608      */
setHotspot(float x, float y)609     public void setHotspot(float x, float y) {}
610 
611     /**
612      * Sets the bounds to which the hotspot is constrained, if they should be
613      * different from the drawable bounds.
614      *
615      * @param left position in pixels of the left bound
616      * @param top position in pixels of the top bound
617      * @param right position in pixels of the right bound
618      * @param bottom position in pixels of the bottom bound
619      * @see #getHotspotBounds(android.graphics.Rect)
620      */
setHotspotBounds(int left, int top, int right, int bottom)621     public void setHotspotBounds(int left, int top, int right, int bottom) {}
622 
623     /**
624      * Populates {@code outRect} with the hotspot bounds.
625      *
626      * @param outRect the rect to populate with the hotspot bounds
627      * @see #setHotspotBounds(int, int, int, int)
628      */
getHotspotBounds(Rect outRect)629     public void getHotspotBounds(Rect outRect) {
630         outRect.set(getBounds());
631     }
632 
633     /**
634      * Whether this drawable requests projection.
635      *
636      * @hide magic!
637      */
isProjected()638     public boolean isProjected() {
639         return false;
640     }
641 
642     /**
643      * Indicates whether this drawable will change its appearance based on
644      * state. Clients can use this to determine whether it is necessary to
645      * calculate their state and call setState.
646      *
647      * @return True if this drawable changes its appearance based on state,
648      *         false otherwise.
649      * @see #setState(int[])
650      */
isStateful()651     public boolean isStateful() {
652         return false;
653     }
654 
655     /**
656      * Specify a set of states for the drawable. These are use-case specific,
657      * so see the relevant documentation. As an example, the background for
658      * widgets like Button understand the following states:
659      * [{@link android.R.attr#state_focused},
660      *  {@link android.R.attr#state_pressed}].
661      *
662      * <p>If the new state you are supplying causes the appearance of the
663      * Drawable to change, then it is responsible for calling
664      * {@link #invalidateSelf} in order to have itself redrawn, <em>and</em>
665      * true will be returned from this function.
666      *
667      * <p>Note: The Drawable holds a reference on to <var>stateSet</var>
668      * until a new state array is given to it, so you must not modify this
669      * array during that time.</p>
670      *
671      * @param stateSet The new set of states to be displayed.
672      *
673      * @return Returns true if this change in state has caused the appearance
674      * of the Drawable to change (hence requiring an invalidate), otherwise
675      * returns false.
676      */
setState(final int[] stateSet)677     public boolean setState(final int[] stateSet) {
678         if (!Arrays.equals(mStateSet, stateSet)) {
679             mStateSet = stateSet;
680             return onStateChange(stateSet);
681         }
682         return false;
683     }
684 
685     /**
686      * Describes the current state, as a union of primitve states, such as
687      * {@link android.R.attr#state_focused},
688      * {@link android.R.attr#state_selected}, etc.
689      * Some drawables may modify their imagery based on the selected state.
690      * @return An array of resource Ids describing the current state.
691      */
getState()692     public int[] getState() {
693         return mStateSet;
694     }
695 
696     /**
697      * If this Drawable does transition animations between states, ask that
698      * it immediately jump to the current state and skip any active animations.
699      */
jumpToCurrentState()700     public void jumpToCurrentState() {
701     }
702 
703     /**
704      * @return The current drawable that will be used by this drawable. For simple drawables, this
705      *         is just the drawable itself. For drawables that change state like
706      *         {@link StateListDrawable} and {@link LevelListDrawable} this will be the child drawable
707      *         currently in use.
708      */
getCurrent()709     public Drawable getCurrent() {
710         return this;
711     }
712 
713     /**
714      * Specify the level for the drawable.  This allows a drawable to vary its
715      * imagery based on a continuous controller, for example to show progress
716      * or volume level.
717      *
718      * <p>If the new level you are supplying causes the appearance of the
719      * Drawable to change, then it is responsible for calling
720      * {@link #invalidateSelf} in order to have itself redrawn, <em>and</em>
721      * true will be returned from this function.
722      *
723      * @param level The new level, from 0 (minimum) to 10000 (maximum).
724      *
725      * @return Returns true if this change in level has caused the appearance
726      * of the Drawable to change (hence requiring an invalidate), otherwise
727      * returns false.
728      */
setLevel(int level)729     public final boolean setLevel(int level) {
730         if (mLevel != level) {
731             mLevel = level;
732             return onLevelChange(level);
733         }
734         return false;
735     }
736 
737     /**
738      * Retrieve the current level.
739      *
740      * @return int Current level, from 0 (minimum) to 10000 (maximum).
741      */
getLevel()742     public final int getLevel() {
743         return mLevel;
744     }
745 
746     /**
747      * Set whether this Drawable is visible.  This generally does not impact
748      * the Drawable's behavior, but is a hint that can be used by some
749      * Drawables, for example, to decide whether run animations.
750      *
751      * @param visible Set to true if visible, false if not.
752      * @param restart You can supply true here to force the drawable to behave
753      *                as if it has just become visible, even if it had last
754      *                been set visible.  Used for example to force animations
755      *                to restart.
756      *
757      * @return boolean Returns true if the new visibility is different than
758      *         its previous state.
759      */
setVisible(boolean visible, boolean restart)760     public boolean setVisible(boolean visible, boolean restart) {
761         boolean changed = mVisible != visible;
762         if (changed) {
763             mVisible = visible;
764             invalidateSelf();
765         }
766         return changed;
767     }
768 
isVisible()769     public final boolean isVisible() {
770         return mVisible;
771     }
772 
773     /**
774      * Set whether this Drawable is automatically mirrored when its layout direction is RTL
775      * (right-to left). See {@link android.util.LayoutDirection}.
776      *
777      * @param mirrored Set to true if the Drawable should be mirrored, false if not.
778      */
setAutoMirrored(boolean mirrored)779     public void setAutoMirrored(boolean mirrored) {
780     }
781 
782     /**
783      * Tells if this Drawable will be automatically mirrored  when its layout direction is RTL
784      * right-to-left. See {@link android.util.LayoutDirection}.
785      *
786      * @return boolean Returns true if this Drawable will be automatically mirrored.
787      */
isAutoMirrored()788     public boolean isAutoMirrored() {
789         return false;
790     }
791 
792     /**
793      * Applies the specified theme to this Drawable and its children.
794      */
applyTheme(@uppressWarnings"unused") Theme t)795     public void applyTheme(@SuppressWarnings("unused") Theme t) {
796     }
797 
canApplyTheme()798     public boolean canApplyTheme() {
799         return false;
800     }
801 
802     /**
803      * Return the opacity/transparency of this Drawable.  The returned value is
804      * one of the abstract format constants in
805      * {@link android.graphics.PixelFormat}:
806      * {@link android.graphics.PixelFormat#UNKNOWN},
807      * {@link android.graphics.PixelFormat#TRANSLUCENT},
808      * {@link android.graphics.PixelFormat#TRANSPARENT}, or
809      * {@link android.graphics.PixelFormat#OPAQUE}.
810      *
811      * <p>An OPAQUE drawable is one that draws all all content within its bounds, completely
812      * covering anything behind the drawable. A TRANSPARENT drawable is one that draws nothing
813      * within its bounds, allowing everything behind it to show through. A TRANSLUCENT drawable
814      * is a drawable in any other state, where the drawable will draw some, but not all,
815      * of the content within its bounds and at least some content behind the drawable will
816      * be visible. If the visibility of the drawable's contents cannot be determined, the
817      * safest/best return value is TRANSLUCENT.
818      *
819      * <p>Generally a Drawable should be as conservative as possible with the
820      * value it returns.  For example, if it contains multiple child drawables
821      * and only shows one of them at a time, if only one of the children is
822      * TRANSLUCENT and the others are OPAQUE then TRANSLUCENT should be
823      * returned.  You can use the method {@link #resolveOpacity} to perform a
824      * standard reduction of two opacities to the appropriate single output.
825      *
826      * <p>Note that the returned value does not necessarily take into account a
827      * custom alpha or color filter that has been applied by the client through
828      * the {@link #setAlpha} or {@link #setColorFilter} methods. Some subclasses,
829      * such as {@link BitmapDrawable}, {@link ColorDrawable}, and {@link GradientDrawable},
830      * do account for the value of {@link #setAlpha}, but the general behavior is dependent
831      * upon the implementation of the subclass.
832      *
833      * @return int The opacity class of the Drawable.
834      *
835      * @see android.graphics.PixelFormat
836      */
getOpacity()837     public abstract int getOpacity();
838 
839     /**
840      * Return the appropriate opacity value for two source opacities.  If
841      * either is UNKNOWN, that is returned; else, if either is TRANSLUCENT,
842      * that is returned; else, if either is TRANSPARENT, that is returned;
843      * else, OPAQUE is returned.
844      *
845      * <p>This is to help in implementing {@link #getOpacity}.
846      *
847      * @param op1 One opacity value.
848      * @param op2 Another opacity value.
849      *
850      * @return int The combined opacity value.
851      *
852      * @see #getOpacity
853      */
resolveOpacity(int op1, int op2)854     public static int resolveOpacity(int op1, int op2) {
855         if (op1 == op2) {
856             return op1;
857         }
858         if (op1 == PixelFormat.UNKNOWN || op2 == PixelFormat.UNKNOWN) {
859             return PixelFormat.UNKNOWN;
860         }
861         if (op1 == PixelFormat.TRANSLUCENT || op2 == PixelFormat.TRANSLUCENT) {
862             return PixelFormat.TRANSLUCENT;
863         }
864         if (op1 == PixelFormat.TRANSPARENT || op2 == PixelFormat.TRANSPARENT) {
865             return PixelFormat.TRANSPARENT;
866         }
867         return PixelFormat.OPAQUE;
868     }
869 
870     /**
871      * Returns a Region representing the part of the Drawable that is completely
872      * transparent.  This can be used to perform drawing operations, identifying
873      * which parts of the target will not change when rendering the Drawable.
874      * The default implementation returns null, indicating no transparent
875      * region; subclasses can optionally override this to return an actual
876      * Region if they want to supply this optimization information, but it is
877      * not required that they do so.
878      *
879      * @return Returns null if the Drawables has no transparent region to
880      * report, else a Region holding the parts of the Drawable's bounds that
881      * are transparent.
882      */
getTransparentRegion()883     public Region getTransparentRegion() {
884         return null;
885     }
886 
887     /**
888      * Override this in your subclass to change appearance if you recognize the
889      * specified state.
890      *
891      * @return Returns true if the state change has caused the appearance of
892      * the Drawable to change (that is, it needs to be drawn), else false
893      * if it looks the same and there is no need to redraw it since its
894      * last state.
895      */
onStateChange(int[] state)896     protected boolean onStateChange(int[] state) { return false; }
897     /** Override this in your subclass to change appearance if you vary based
898      *  on level.
899      * @return Returns true if the level change has caused the appearance of
900      * the Drawable to change (that is, it needs to be drawn), else false
901      * if it looks the same and there is no need to redraw it since its
902      * last level.
903      */
onLevelChange(int level)904     protected boolean onLevelChange(int level) { return false; }
905     /**
906      * Override this in your subclass to change appearance if you vary based on
907      * the bounds.
908      */
onBoundsChange(Rect bounds)909     protected void onBoundsChange(Rect bounds) {}
910 
911     /**
912      * Return the intrinsic width of the underlying drawable object.  Returns
913      * -1 if it has no intrinsic width, such as with a solid color.
914      */
getIntrinsicWidth()915     public int getIntrinsicWidth() {
916         return -1;
917     }
918 
919     /**
920      * Return the intrinsic height of the underlying drawable object. Returns
921      * -1 if it has no intrinsic height, such as with a solid color.
922      */
getIntrinsicHeight()923     public int getIntrinsicHeight() {
924         return -1;
925     }
926 
927     /**
928      * Returns the minimum width suggested by this Drawable. If a View uses this
929      * Drawable as a background, it is suggested that the View use at least this
930      * value for its width. (There will be some scenarios where this will not be
931      * possible.) This value should INCLUDE any padding.
932      *
933      * @return The minimum width suggested by this Drawable. If this Drawable
934      *         doesn't have a suggested minimum width, 0 is returned.
935      */
getMinimumWidth()936     public int getMinimumWidth() {
937         final int intrinsicWidth = getIntrinsicWidth();
938         return intrinsicWidth > 0 ? intrinsicWidth : 0;
939     }
940 
941     /**
942      * Returns the minimum height suggested by this Drawable. If a View uses this
943      * Drawable as a background, it is suggested that the View use at least this
944      * value for its height. (There will be some scenarios where this will not be
945      * possible.) This value should INCLUDE any padding.
946      *
947      * @return The minimum height suggested by this Drawable. If this Drawable
948      *         doesn't have a suggested minimum height, 0 is returned.
949      */
getMinimumHeight()950     public int getMinimumHeight() {
951         final int intrinsicHeight = getIntrinsicHeight();
952         return intrinsicHeight > 0 ? intrinsicHeight : 0;
953     }
954 
955     /**
956      * Return in padding the insets suggested by this Drawable for placing
957      * content inside the drawable's bounds. Positive values move toward the
958      * center of the Drawable (set Rect.inset).
959      *
960      * @return true if this drawable actually has a padding, else false. When false is returned,
961      * the padding is always set to 0.
962      */
getPadding(@onNull Rect padding)963     public boolean getPadding(@NonNull Rect padding) {
964         padding.set(0, 0, 0, 0);
965         return false;
966     }
967 
968     /**
969      * Return in insets the layout insets suggested by this Drawable for use with alignment
970      * operations during layout.
971      *
972      * @hide
973      */
getOpticalInsets()974     public Insets getOpticalInsets() {
975         return Insets.NONE;
976     }
977 
978     /**
979      * Called to get the drawable to populate the Outline that defines its drawing area.
980      * <p>
981      * This method is called by the default {@link android.view.ViewOutlineProvider} to define
982      * the outline of the View.
983      * <p>
984      * The default behavior defines the outline to be the bounding rectangle of 0 alpha.
985      * Subclasses that wish to convey a different shape or alpha value must override this method.
986      *
987      * @see android.view.View#setOutlineProvider(android.view.ViewOutlineProvider)
988      */
getOutline(@onNull Outline outline)989     public void getOutline(@NonNull Outline outline) {
990         outline.setRect(getBounds());
991         outline.setAlpha(0);
992     }
993 
994     /**
995      * Make this drawable mutable. This operation cannot be reversed. A mutable
996      * drawable is guaranteed to not share its state with any other drawable.
997      * This is especially useful when you need to modify properties of drawables
998      * loaded from resources. By default, all drawables instances loaded from
999      * the same resource share a common state; if you modify the state of one
1000      * instance, all the other instances will receive the same modification.
1001      *
1002      * Calling this method on a mutable Drawable will have no effect.
1003      *
1004      * @return This drawable.
1005      * @see ConstantState
1006      * @see #getConstantState()
1007      */
mutate()1008     public Drawable mutate() {
1009         return this;
1010     }
1011 
1012     /**
1013      * Clears the mutated state, allowing this drawable to be cached and
1014      * mutated again.
1015      * <p>
1016      * This is hidden because only framework drawables can be cached, so
1017      * custom drawables don't need to support constant state, mutate(), or
1018      * clearMutated().
1019      *
1020      * @hide
1021      */
clearMutated()1022     public void clearMutated() {
1023         // Default implementation is no-op.
1024     }
1025 
1026     /**
1027      * Create a drawable from an inputstream
1028      */
createFromStream(InputStream is, String srcName)1029     public static Drawable createFromStream(InputStream is, String srcName) {
1030         Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, srcName != null ? srcName : "Unknown drawable");
1031         try {
1032             return createFromResourceStream(null, null, is, srcName);
1033         } finally {
1034             Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
1035         }
1036     }
1037 
1038     /**
1039      * Create a drawable from an inputstream, using the given resources and
1040      * value to determine density information.
1041      */
createFromResourceStream(Resources res, TypedValue value, InputStream is, String srcName)1042     public static Drawable createFromResourceStream(Resources res, TypedValue value,
1043             InputStream is, String srcName) {
1044         Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, srcName != null ? srcName : "Unknown drawable");
1045         try {
1046             return createFromResourceStream(res, value, is, srcName, null);
1047         } finally {
1048             Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
1049         }
1050     }
1051 
1052     /**
1053      * Create a drawable from an inputstream, using the given resources and
1054      * value to determine density information.
1055      */
createFromResourceStream(Resources res, TypedValue value, InputStream is, String srcName, BitmapFactory.Options opts)1056     public static Drawable createFromResourceStream(Resources res, TypedValue value,
1057             InputStream is, String srcName, BitmapFactory.Options opts) {
1058         if (is == null) {
1059             return null;
1060         }
1061 
1062         /*  ugh. The decodeStream contract is that we have already allocated
1063             the pad rect, but if the bitmap does not had a ninepatch chunk,
1064             then the pad will be ignored. If we could change this to lazily
1065             alloc/assign the rect, we could avoid the GC churn of making new
1066             Rects only to drop them on the floor.
1067         */
1068         Rect pad = new Rect();
1069 
1070         // Special stuff for compatibility mode: if the target density is not
1071         // the same as the display density, but the resource -is- the same as
1072         // the display density, then don't scale it down to the target density.
1073         // This allows us to load the system's density-correct resources into
1074         // an application in compatibility mode, without scaling those down
1075         // to the compatibility density only to have them scaled back up when
1076         // drawn to the screen.
1077         if (opts == null) opts = new BitmapFactory.Options();
1078         opts.inScreenDensity = res != null
1079                 ? res.getDisplayMetrics().noncompatDensityDpi : DisplayMetrics.DENSITY_DEVICE;
1080         Bitmap  bm = BitmapFactory.decodeResourceStream(res, value, is, pad, opts);
1081         if (bm != null) {
1082             byte[] np = bm.getNinePatchChunk();
1083             if (np == null || !NinePatch.isNinePatchChunk(np)) {
1084                 np = null;
1085                 pad = null;
1086             }
1087 
1088             final Rect opticalInsets = new Rect();
1089             bm.getOpticalInsets(opticalInsets);
1090             return drawableFromBitmap(res, bm, np, pad, opticalInsets, srcName);
1091         }
1092         return null;
1093     }
1094 
1095     /**
1096      * Create a drawable from an XML document. For more information on how to
1097      * create resources in XML, see
1098      * <a href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.
1099      */
createFromXml(Resources r, XmlPullParser parser)1100     public static Drawable createFromXml(Resources r, XmlPullParser parser)
1101             throws XmlPullParserException, IOException {
1102         return createFromXml(r, parser, null);
1103     }
1104 
1105     /**
1106      * Create a drawable from an XML document using an optional {@link Theme}.
1107      * For more information on how to create resources in XML, see
1108      * <a href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.
1109      */
createFromXml(Resources r, XmlPullParser parser, Theme theme)1110     public static Drawable createFromXml(Resources r, XmlPullParser parser, Theme theme)
1111             throws XmlPullParserException, IOException {
1112         AttributeSet attrs = Xml.asAttributeSet(parser);
1113 
1114         int type;
1115         while ((type=parser.next()) != XmlPullParser.START_TAG &&
1116                 type != XmlPullParser.END_DOCUMENT) {
1117             // Empty loop
1118         }
1119 
1120         if (type != XmlPullParser.START_TAG) {
1121             throw new XmlPullParserException("No start tag found");
1122         }
1123 
1124         Drawable drawable = createFromXmlInner(r, parser, attrs, theme);
1125 
1126         if (drawable == null) {
1127             throw new RuntimeException("Unknown initial tag: " + parser.getName());
1128         }
1129 
1130         return drawable;
1131     }
1132 
1133     /**
1134      * Create from inside an XML document.  Called on a parser positioned at
1135      * a tag in an XML document, tries to create a Drawable from that tag.
1136      * Returns null if the tag is not a valid drawable.
1137      */
createFromXmlInner(Resources r, XmlPullParser parser, AttributeSet attrs)1138     public static Drawable createFromXmlInner(Resources r, XmlPullParser parser, AttributeSet attrs)
1139             throws XmlPullParserException, IOException {
1140         return createFromXmlInner(r, parser, attrs, null);
1141     }
1142 
1143     /**
1144      * Create a drawable from inside an XML document using an optional
1145      * {@link Theme}. Called on a parser positioned at a tag in an XML
1146      * document, tries to create a Drawable from that tag. Returns {@code null}
1147      * if the tag is not a valid drawable.
1148      */
1149     @SuppressWarnings("deprecation")
createFromXmlInner(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)1150     public static Drawable createFromXmlInner(Resources r, XmlPullParser parser, AttributeSet attrs,
1151             Theme theme) throws XmlPullParserException, IOException {
1152         final Drawable drawable;
1153 
1154         final String name = parser.getName();
1155         switch (name) {
1156             case "selector":
1157                 drawable = new StateListDrawable();
1158                 break;
1159             case "animated-selector":
1160                 drawable = new AnimatedStateListDrawable();
1161                 break;
1162             case "level-list":
1163                 drawable = new LevelListDrawable();
1164                 break;
1165             case "layer-list":
1166                 drawable = new LayerDrawable();
1167                 break;
1168             case "transition":
1169                 drawable = new TransitionDrawable();
1170                 break;
1171             case "ripple":
1172                 drawable = new RippleDrawable();
1173                 break;
1174             case "color":
1175                 drawable = new ColorDrawable();
1176                 break;
1177             case "shape":
1178                 drawable = new GradientDrawable();
1179                 break;
1180             case "vector":
1181                 drawable = new VectorDrawable();
1182                 break;
1183             case "animated-vector":
1184                 drawable = new AnimatedVectorDrawable();
1185                 break;
1186             case "scale":
1187                 drawable = new ScaleDrawable();
1188                 break;
1189             case "clip":
1190                 drawable = new ClipDrawable();
1191                 break;
1192             case "rotate":
1193                 drawable = new RotateDrawable();
1194                 break;
1195             case "animated-rotate":
1196                 drawable = new AnimatedRotateDrawable();
1197                 break;
1198             case "animation-list":
1199                 drawable = new AnimationDrawable();
1200                 break;
1201             case "inset":
1202                 drawable = new InsetDrawable();
1203                 break;
1204             case "bitmap":
1205                 drawable = new BitmapDrawable();
1206                 break;
1207             case "nine-patch":
1208                 drawable = new NinePatchDrawable();
1209                 break;
1210             default:
1211                 throw new XmlPullParserException(parser.getPositionDescription() +
1212                         ": invalid drawable tag " + name);
1213 
1214         }
1215         drawable.inflate(r, parser, attrs, theme);
1216         return drawable;
1217     }
1218 
1219 
1220     /**
1221      * Create a drawable from file path name.
1222      */
createFromPath(String pathName)1223     public static Drawable createFromPath(String pathName) {
1224         if (pathName == null) {
1225             return null;
1226         }
1227 
1228         Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, pathName);
1229         try {
1230             Bitmap bm = BitmapFactory.decodeFile(pathName);
1231             if (bm != null) {
1232                 return drawableFromBitmap(null, bm, null, null, null, pathName);
1233             }
1234         } finally {
1235             Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
1236         }
1237 
1238         return null;
1239     }
1240 
1241     /**
1242      * Inflate this Drawable from an XML resource. Does not apply a theme.
1243      *
1244      * @see #inflate(Resources, XmlPullParser, AttributeSet, Theme)
1245      */
inflate(Resources r, XmlPullParser parser, AttributeSet attrs)1246     public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs)
1247             throws XmlPullParserException, IOException {
1248         inflate(r, parser, attrs, null);
1249     }
1250 
1251     /**
1252      * Inflate this Drawable from an XML resource optionally styled by a theme.
1253      *
1254      * @param r Resources used to resolve attribute values
1255      * @param parser XML parser from which to inflate this Drawable
1256      * @param attrs Base set of attribute values
1257      * @param theme Theme to apply, may be null
1258      * @throws XmlPullParserException
1259      * @throws IOException
1260      */
inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)1261     public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
1262             throws XmlPullParserException, IOException {
1263         final TypedArray a;
1264         if (theme != null) {
1265             a = theme.obtainStyledAttributes(
1266                     attrs, com.android.internal.R.styleable.Drawable, 0, 0);
1267         } else {
1268             a = r.obtainAttributes(attrs, com.android.internal.R.styleable.Drawable);
1269         }
1270 
1271         inflateWithAttributes(r, parser, a, com.android.internal.R.styleable.Drawable_visible);
1272         a.recycle();
1273     }
1274 
1275     /**
1276      * Inflate a Drawable from an XML resource.
1277      *
1278      * @throws XmlPullParserException
1279      * @throws IOException
1280      */
inflateWithAttributes(Resources r, XmlPullParser parser, TypedArray attrs, int visibleAttr)1281     void inflateWithAttributes(Resources r, XmlPullParser parser, TypedArray attrs, int visibleAttr)
1282             throws XmlPullParserException, IOException {
1283         mVisible = attrs.getBoolean(visibleAttr, mVisible);
1284     }
1285 
1286     /**
1287      * This abstract class is used by {@link Drawable}s to store shared constant state and data
1288      * between Drawables. {@link BitmapDrawable}s created from the same resource will for instance
1289      * share a unique bitmap stored in their ConstantState.
1290      *
1291      * <p>
1292      * {@link #newDrawable(Resources)} can be used as a factory to create new Drawable instances
1293      * from this ConstantState.
1294      * </p>
1295      *
1296      * Use {@link Drawable#getConstantState()} to retrieve the ConstantState of a Drawable. Calling
1297      * {@link Drawable#mutate()} on a Drawable should typically create a new ConstantState for that
1298      * Drawable.
1299      */
1300     public static abstract class ConstantState {
1301         /**
1302          * Create a new drawable without supplying resources the caller
1303          * is running in.  Note that using this means the density-dependent
1304          * drawables (like bitmaps) will not be able to update their target
1305          * density correctly. One should use {@link #newDrawable(Resources)}
1306          * instead to provide a resource.
1307          */
newDrawable()1308         public abstract Drawable newDrawable();
1309 
1310         /**
1311          * Create a new Drawable instance from its constant state.  This
1312          * must be implemented for drawables that change based on the target
1313          * density of their caller (that is depending on whether it is
1314          * in compatibility mode).
1315          */
newDrawable(Resources res)1316         public Drawable newDrawable(Resources res) {
1317             return newDrawable();
1318         }
1319 
1320         /**
1321          * Create a new Drawable instance from its constant state. This must be
1322          * implemented for drawables that can have a theme applied.
1323          */
newDrawable(Resources res, Theme theme)1324         public Drawable newDrawable(Resources res, Theme theme) {
1325             return newDrawable(null);
1326         }
1327 
1328         /**
1329          * Return a bit mask of configuration changes that will impact
1330          * this drawable (and thus require completely reloading it).
1331          */
getChangingConfigurations()1332         public abstract int getChangingConfigurations();
1333 
1334         /**
1335          * @return Total pixel count
1336          * @hide
1337          */
addAtlasableBitmaps(Collection<Bitmap> atlasList)1338         public int addAtlasableBitmaps(Collection<Bitmap> atlasList) {
1339             return 0;
1340         }
1341 
1342         /** @hide */
isAtlasable(Bitmap bitmap)1343         protected final boolean isAtlasable(Bitmap bitmap) {
1344             return bitmap != null && bitmap.getConfig() == Bitmap.Config.ARGB_8888;
1345         }
1346 
1347         /**
1348          * Return whether this constant state can have a theme applied.
1349          */
canApplyTheme()1350         public boolean canApplyTheme() {
1351             return false;
1352         }
1353     }
1354 
1355     /**
1356      * Return a {@link ConstantState} instance that holds the shared state of this Drawable.
1357      *
1358      * @return The ConstantState associated to that Drawable.
1359      * @see ConstantState
1360      * @see Drawable#mutate()
1361      */
getConstantState()1362     public ConstantState getConstantState() {
1363         return null;
1364     }
1365 
drawableFromBitmap(Resources res, Bitmap bm, byte[] np, Rect pad, Rect layoutBounds, String srcName)1366     private static Drawable drawableFromBitmap(Resources res, Bitmap bm, byte[] np,
1367             Rect pad, Rect layoutBounds, String srcName) {
1368 
1369         if (np != null) {
1370             return new NinePatchDrawable(res, bm, np, pad, layoutBounds, srcName);
1371         }
1372 
1373         return new BitmapDrawable(res, bm);
1374     }
1375 
1376     /**
1377      * Ensures the tint filter is consistent with the current tint color and
1378      * mode.
1379      */
updateTintFilter(PorterDuffColorFilter tintFilter, ColorStateList tint, PorterDuff.Mode tintMode)1380     PorterDuffColorFilter updateTintFilter(PorterDuffColorFilter tintFilter, ColorStateList tint,
1381             PorterDuff.Mode tintMode) {
1382         if (tint == null || tintMode == null) {
1383             return null;
1384         }
1385 
1386         final int color = tint.getColorForState(getState(), Color.TRANSPARENT);
1387         if (tintFilter == null) {
1388             return new PorterDuffColorFilter(color, tintMode);
1389         }
1390 
1391         tintFilter.setColor(color);
1392         tintFilter.setMode(tintMode);
1393         return tintFilter;
1394     }
1395 
1396     /**
1397      * Obtains styled attributes from the theme, if available, or unstyled
1398      * resources if the theme is null.
1399      */
obtainAttributes( Resources res, Theme theme, AttributeSet set, int[] attrs)1400     static TypedArray obtainAttributes(
1401             Resources res, Theme theme, AttributeSet set, int[] attrs) {
1402         if (theme == null) {
1403             return res.obtainAttributes(set, attrs);
1404         }
1405         return theme.obtainStyledAttributes(set, attrs, 0, 0);
1406     }
1407 
1408     /**
1409      * Parses a {@link android.graphics.PorterDuff.Mode} from a tintMode
1410      * attribute's enum value.
1411      *
1412      * @hide
1413      */
parseTintMode(int value, Mode defaultMode)1414     public static PorterDuff.Mode parseTintMode(int value, Mode defaultMode) {
1415         switch (value) {
1416             case 3: return Mode.SRC_OVER;
1417             case 5: return Mode.SRC_IN;
1418             case 9: return Mode.SRC_ATOP;
1419             case 14: return Mode.MULTIPLY;
1420             case 15: return Mode.SCREEN;
1421             case 16: return Mode.ADD;
1422             default: return defaultMode;
1423         }
1424     }
1425 }
1426 
1427