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