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