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