• 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.annotation.TestApi;
25 import android.annotation.UnsupportedAppUsage;
26 import android.content.pm.ActivityInfo.Config;
27 import android.content.res.ColorStateList;
28 import android.content.res.Resources;
29 import android.content.res.Resources.Theme;
30 import android.content.res.TypedArray;
31 import android.graphics.Bitmap;
32 import android.graphics.BitmapFactory;
33 import android.graphics.BlendMode;
34 import android.graphics.BlendModeColorFilter;
35 import android.graphics.Canvas;
36 import android.graphics.Color;
37 import android.graphics.ColorFilter;
38 import android.graphics.ImageDecoder;
39 import android.graphics.Insets;
40 import android.graphics.NinePatch;
41 import android.graphics.Outline;
42 import android.graphics.PixelFormat;
43 import android.graphics.PorterDuff;
44 import android.graphics.PorterDuff.Mode;
45 import android.graphics.PorterDuffColorFilter;
46 import android.graphics.Rect;
47 import android.graphics.Region;
48 import android.graphics.Xfermode;
49 import android.os.Trace;
50 import android.util.AttributeSet;
51 import android.util.DisplayMetrics;
52 import android.util.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 {@link #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      *
812      * @hide
813      */
814     @TestApi
hasFocusStateSpecified()815     public boolean hasFocusStateSpecified() {
816         return false;
817     }
818 
819     /**
820      * Specify a set of states for the drawable. These are use-case specific,
821      * so see the relevant documentation. As an example, the background for
822      * widgets like Button understand the following states:
823      * [{@link android.R.attr#state_focused},
824      *  {@link android.R.attr#state_pressed}].
825      *
826      * <p>If the new state you are supplying causes the appearance of the
827      * Drawable to change, then it is responsible for calling
828      * {@link #invalidateSelf} in order to have itself redrawn, <em>and</em>
829      * true will be returned from this function.
830      *
831      * <p>Note: The Drawable holds a reference on to <var>stateSet</var>
832      * until a new state array is given to it, so you must not modify this
833      * array during that time.</p>
834      *
835      * @param stateSet The new set of states to be displayed.
836      *
837      * @return Returns true if this change in state has caused the appearance
838      * of the Drawable to change (hence requiring an invalidate), otherwise
839      * returns false.
840      */
setState(@onNull final int[] stateSet)841     public boolean setState(@NonNull final int[] stateSet) {
842         if (!Arrays.equals(mStateSet, stateSet)) {
843             mStateSet = stateSet;
844             return onStateChange(stateSet);
845         }
846         return false;
847     }
848 
849     /**
850      * Describes the current state, as a union of primitve states, such as
851      * {@link android.R.attr#state_focused},
852      * {@link android.R.attr#state_selected}, etc.
853      * Some drawables may modify their imagery based on the selected state.
854      * @return An array of resource Ids describing the current state.
855      */
getState()856     public @NonNull int[] getState() {
857         return mStateSet;
858     }
859 
860     /**
861      * If this Drawable does transition animations between states, ask that
862      * it immediately jump to the current state and skip any active animations.
863      */
jumpToCurrentState()864     public void jumpToCurrentState() {
865     }
866 
867     /**
868      * @return The current drawable that will be used by this drawable. For simple drawables, this
869      *         is just the drawable itself. For drawables that change state like
870      *         {@link StateListDrawable} and {@link LevelListDrawable} this will be the child drawable
871      *         currently in use.
872      */
getCurrent()873     public @NonNull Drawable getCurrent() {
874         return this;
875     }
876 
877     /**
878      * Specify the level for the drawable.  This allows a drawable to vary its
879      * imagery based on a continuous controller, for example to show progress
880      * or volume level.
881      *
882      * <p>If the new level you are supplying causes the appearance of the
883      * Drawable to change, then it is responsible for calling
884      * {@link #invalidateSelf} in order to have itself redrawn, <em>and</em>
885      * true will be returned from this function.
886      *
887      * @param level The new level, from 0 (minimum) to 10000 (maximum).
888      *
889      * @return Returns true if this change in level has caused the appearance
890      * of the Drawable to change (hence requiring an invalidate), otherwise
891      * returns false.
892      */
setLevel(@ntRangefrom=0,to=10000) int level)893     public final boolean setLevel(@IntRange(from=0,to=10000) int level) {
894         if (mLevel != level) {
895             mLevel = level;
896             return onLevelChange(level);
897         }
898         return false;
899     }
900 
901     /**
902      * Retrieve the current level.
903      *
904      * @return int Current level, from 0 (minimum) to 10000 (maximum).
905      */
getLevel()906     public final @IntRange(from=0,to=10000) int getLevel() {
907         return mLevel;
908     }
909 
910     /**
911      * Set whether this Drawable is visible.  This generally does not impact
912      * the Drawable's behavior, but is a hint that can be used by some
913      * Drawables, for example, to decide whether run animations.
914      *
915      * @param visible Set to true if visible, false if not.
916      * @param restart You can supply true here to force the drawable to behave
917      *                as if it has just become visible, even if it had last
918      *                been set visible.  Used for example to force animations
919      *                to restart.
920      *
921      * @return boolean Returns true if the new visibility is different than
922      *         its previous state.
923      */
setVisible(boolean visible, boolean restart)924     public boolean setVisible(boolean visible, boolean restart) {
925         boolean changed = mVisible != visible;
926         if (changed) {
927             mVisible = visible;
928             invalidateSelf();
929         }
930         return changed;
931     }
932 
isVisible()933     public final boolean isVisible() {
934         return mVisible;
935     }
936 
937     /**
938      * Set whether this Drawable is automatically mirrored when its layout direction is RTL
939      * (right-to left). See {@link android.util.LayoutDirection}.
940      *
941      * @param mirrored Set to true if the Drawable should be mirrored, false if not.
942      */
setAutoMirrored(boolean mirrored)943     public void setAutoMirrored(boolean mirrored) {
944     }
945 
946     /**
947      * Tells if this Drawable will be automatically mirrored  when its layout direction is RTL
948      * right-to-left. See {@link android.util.LayoutDirection}.
949      *
950      * @return boolean Returns true if this Drawable will be automatically mirrored.
951      */
isAutoMirrored()952     public boolean isAutoMirrored() {
953         return false;
954     }
955 
956     /**
957      * Applies the specified theme to this Drawable and its children.
958      *
959      * @param t the theme to apply
960      */
applyTheme(@onNull @uppressWarnings"unused") Theme t)961     public void applyTheme(@NonNull @SuppressWarnings("unused") Theme t) {
962     }
963 
canApplyTheme()964     public boolean canApplyTheme() {
965         return false;
966     }
967 
968     /**
969      * Return the opacity/transparency of this Drawable.  The returned value is
970      * one of the abstract format constants in
971      * {@link android.graphics.PixelFormat}:
972      * {@link android.graphics.PixelFormat#UNKNOWN},
973      * {@link android.graphics.PixelFormat#TRANSLUCENT},
974      * {@link android.graphics.PixelFormat#TRANSPARENT}, or
975      * {@link android.graphics.PixelFormat#OPAQUE}.
976      *
977      * <p>An OPAQUE drawable is one that draws all all content within its bounds, completely
978      * covering anything behind the drawable. A TRANSPARENT drawable is one that draws nothing
979      * within its bounds, allowing everything behind it to show through. A TRANSLUCENT drawable
980      * is a drawable in any other state, where the drawable will draw some, but not all,
981      * of the content within its bounds and at least some content behind the drawable will
982      * be visible. If the visibility of the drawable's contents cannot be determined, the
983      * safest/best return value is TRANSLUCENT.
984      *
985      * <p>Generally a Drawable should be as conservative as possible with the
986      * value it returns.  For example, if it contains multiple child drawables
987      * and only shows one of them at a time, if only one of the children is
988      * TRANSLUCENT and the others are OPAQUE then TRANSLUCENT should be
989      * returned.  You can use the method {@link #resolveOpacity} to perform a
990      * standard reduction of two opacities to the appropriate single output.
991      *
992      * <p>Note that the returned value does not necessarily take into account a
993      * custom alpha or color filter that has been applied by the client through
994      * the {@link #setAlpha} or {@link #setColorFilter} methods. Some subclasses,
995      * such as {@link BitmapDrawable}, {@link ColorDrawable}, and {@link GradientDrawable},
996      * do account for the value of {@link #setAlpha}, but the general behavior is dependent
997      * upon the implementation of the subclass.
998      *
999      * @deprecated This method is no longer used in graphics optimizations
1000      *
1001      * @return int The opacity class of the Drawable.
1002      *
1003      * @see android.graphics.PixelFormat
1004      */
getOpacity()1005     @Deprecated public abstract @PixelFormat.Opacity int getOpacity();
1006 
1007     /**
1008      * Return the appropriate opacity value for two source opacities.  If
1009      * either is UNKNOWN, that is returned; else, if either is TRANSLUCENT,
1010      * that is returned; else, if either is TRANSPARENT, that is returned;
1011      * else, OPAQUE is returned.
1012      *
1013      * <p>This is to help in implementing {@link #getOpacity}.
1014      *
1015      * @param op1 One opacity value.
1016      * @param op2 Another opacity value.
1017      *
1018      * @return int The combined opacity value.
1019      *
1020      * @see #getOpacity
1021      */
resolveOpacity(@ixelFormat.Opacity int op1, @PixelFormat.Opacity int op2)1022     public static @PixelFormat.Opacity int resolveOpacity(@PixelFormat.Opacity int op1,
1023             @PixelFormat.Opacity int op2) {
1024         if (op1 == op2) {
1025             return op1;
1026         }
1027         if (op1 == PixelFormat.UNKNOWN || op2 == PixelFormat.UNKNOWN) {
1028             return PixelFormat.UNKNOWN;
1029         }
1030         if (op1 == PixelFormat.TRANSLUCENT || op2 == PixelFormat.TRANSLUCENT) {
1031             return PixelFormat.TRANSLUCENT;
1032         }
1033         if (op1 == PixelFormat.TRANSPARENT || op2 == PixelFormat.TRANSPARENT) {
1034             return PixelFormat.TRANSPARENT;
1035         }
1036         return PixelFormat.OPAQUE;
1037     }
1038 
1039     /**
1040      * Returns a Region representing the part of the Drawable that is completely
1041      * transparent.  This can be used to perform drawing operations, identifying
1042      * which parts of the target will not change when rendering the Drawable.
1043      * The default implementation returns null, indicating no transparent
1044      * region; subclasses can optionally override this to return an actual
1045      * Region if they want to supply this optimization information, but it is
1046      * not required that they do so.
1047      *
1048      * @return Returns null if the Drawables has no transparent region to
1049      * report, else a Region holding the parts of the Drawable's bounds that
1050      * are transparent.
1051      */
getTransparentRegion()1052     public @Nullable Region getTransparentRegion() {
1053         return null;
1054     }
1055 
1056     /**
1057      * Override this in your subclass to change appearance if you recognize the
1058      * specified state.
1059      *
1060      * @return Returns true if the state change has caused the appearance of
1061      * the Drawable to change (that is, it needs to be drawn), else false
1062      * if it looks the same and there is no need to redraw it since its
1063      * last state.
1064      */
onStateChange(int[] state)1065     protected boolean onStateChange(int[] state) {
1066         return false;
1067     }
1068 
1069     /** Override this in your subclass to change appearance if you vary based
1070      *  on level.
1071      * @return Returns true if the level change has caused the appearance of
1072      * the Drawable to change (that is, it needs to be drawn), else false
1073      * if it looks the same and there is no need to redraw it since its
1074      * last level.
1075      */
onLevelChange(int level)1076     protected boolean onLevelChange(int level) {
1077         return false;
1078     }
1079 
1080     /**
1081      * Override this in your subclass to change appearance if you vary based on
1082      * the bounds.
1083      */
onBoundsChange(Rect bounds)1084     protected void onBoundsChange(Rect bounds) {
1085         // Stub method.
1086     }
1087 
1088     /**
1089      * Returns the drawable's intrinsic width.
1090      * <p>
1091      * Intrinsic width is the width at which the drawable would like to be laid
1092      * out, including any inherent padding. If the drawable has no intrinsic
1093      * width, such as a solid color, this method returns -1.
1094      *
1095      * @return the intrinsic width, or -1 if no intrinsic width
1096      */
getIntrinsicWidth()1097     public int getIntrinsicWidth() {
1098         return -1;
1099     }
1100 
1101     /**
1102      * Returns the drawable's intrinsic height.
1103      * <p>
1104      * Intrinsic height is the height at which the drawable would like to be
1105      * laid out, including any inherent padding. If the drawable has no
1106      * intrinsic height, such as a solid color, this method returns -1.
1107      *
1108      * @return the intrinsic height, or -1 if no intrinsic height
1109      */
getIntrinsicHeight()1110     public int getIntrinsicHeight() {
1111         return -1;
1112     }
1113 
1114     /**
1115      * Returns the minimum width suggested by this Drawable. If a View uses this
1116      * Drawable as a background, it is suggested that the View use at least this
1117      * value for its width. (There will be some scenarios where this will not be
1118      * possible.) This value should INCLUDE any padding.
1119      *
1120      * @return The minimum width suggested by this Drawable. If this Drawable
1121      *         doesn't have a suggested minimum width, 0 is returned.
1122      */
getMinimumWidth()1123     public int getMinimumWidth() {
1124         final int intrinsicWidth = getIntrinsicWidth();
1125         return intrinsicWidth > 0 ? intrinsicWidth : 0;
1126     }
1127 
1128     /**
1129      * Returns the minimum height suggested by this Drawable. If a View uses this
1130      * Drawable as a background, it is suggested that the View use at least this
1131      * value for its height. (There will be some scenarios where this will not be
1132      * possible.) This value should INCLUDE any padding.
1133      *
1134      * @return The minimum height suggested by this Drawable. If this Drawable
1135      *         doesn't have a suggested minimum height, 0 is returned.
1136      */
getMinimumHeight()1137     public int getMinimumHeight() {
1138         final int intrinsicHeight = getIntrinsicHeight();
1139         return intrinsicHeight > 0 ? intrinsicHeight : 0;
1140     }
1141 
1142     /**
1143      * Return in padding the insets suggested by this Drawable for placing
1144      * content inside the drawable's bounds. Positive values move toward the
1145      * center of the Drawable (set Rect.inset).
1146      *
1147      * @return true if this drawable actually has a padding, else false. When false is returned,
1148      * the padding is always set to 0.
1149      */
getPadding(@onNull Rect padding)1150     public boolean getPadding(@NonNull Rect padding) {
1151         padding.set(0, 0, 0, 0);
1152         return false;
1153     }
1154 
1155     /**
1156      * Return in insets the layout insets suggested by this Drawable for use with alignment
1157      * operations during layout.
1158      *
1159      */
getOpticalInsets()1160     public @NonNull Insets getOpticalInsets() {
1161         return Insets.NONE;
1162     }
1163 
1164     /**
1165      * Called to get the drawable to populate the Outline that defines its drawing area.
1166      * <p>
1167      * This method is called by the default {@link android.view.ViewOutlineProvider} to define
1168      * the outline of the View.
1169      * <p>
1170      * The default behavior defines the outline to be the bounding rectangle of 0 alpha.
1171      * Subclasses that wish to convey a different shape or alpha value must override this method.
1172      *
1173      * @see android.view.View#setOutlineProvider(android.view.ViewOutlineProvider)
1174      */
getOutline(@onNull Outline outline)1175     public void getOutline(@NonNull Outline outline) {
1176         outline.setRect(getBounds());
1177         outline.setAlpha(0);
1178     }
1179 
1180     /**
1181      * Make this drawable mutable. This operation cannot be reversed. A mutable
1182      * drawable is guaranteed to not share its state with any other drawable.
1183      * This is especially useful when you need to modify properties of drawables
1184      * loaded from resources. By default, all drawables instances loaded from
1185      * the same resource share a common state; if you modify the state of one
1186      * instance, all the other instances will receive the same modification.
1187      *
1188      * Calling this method on a mutable Drawable will have no effect.
1189      *
1190      * @return This drawable.
1191      * @see ConstantState
1192      * @see #getConstantState()
1193      */
mutate()1194     public @NonNull Drawable mutate() {
1195         return this;
1196     }
1197 
1198     /**
1199      * Clears the mutated state, allowing this drawable to be cached and
1200      * mutated again.
1201      * <p>
1202      * This is hidden because only framework drawables can be cached, so
1203      * custom drawables don't need to support constant state, mutate(), or
1204      * clearMutated().
1205      *
1206      * @hide
1207      */
clearMutated()1208     public void clearMutated() {
1209         // Default implementation is no-op.
1210     }
1211 
1212     /**
1213      * Create a drawable from an inputstream
1214      */
createFromStream(InputStream is, String srcName)1215     public static Drawable createFromStream(InputStream is, String srcName) {
1216         Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, srcName != null ? srcName : "Unknown drawable");
1217         try {
1218             return createFromResourceStream(null, null, is, srcName);
1219         } finally {
1220             Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
1221         }
1222     }
1223 
1224     /**
1225      * Create a drawable from an inputstream, using the given resources and
1226      * value to determine density information.
1227      */
createFromResourceStream(Resources res, TypedValue value, InputStream is, String srcName)1228     public static Drawable createFromResourceStream(Resources res, TypedValue value,
1229             InputStream is, String srcName) {
1230         Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, srcName != null ? srcName : "Unknown drawable");
1231         try {
1232             return createFromResourceStream(res, value, is, srcName, null);
1233         } finally {
1234             Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
1235         }
1236     }
1237 
1238     /**
1239      * Create a drawable from an inputstream, using the given resources and
1240      * value to determine density information.
1241      *
1242      * @deprecated Prefer the version without an Options object.
1243      */
1244     @Nullable
createFromResourceStream(@ullable Resources res, @Nullable TypedValue value, @Nullable InputStream is, @Nullable String srcName, @Nullable BitmapFactory.Options opts)1245     public static Drawable createFromResourceStream(@Nullable Resources res,
1246             @Nullable TypedValue value, @Nullable InputStream is, @Nullable String srcName,
1247             @Nullable BitmapFactory.Options opts) {
1248         if (is == null) {
1249             return null;
1250         }
1251 
1252         if (opts == null) {
1253             return getBitmapDrawable(res, value, is);
1254         }
1255 
1256         /*  ugh. The decodeStream contract is that we have already allocated
1257             the pad rect, but if the bitmap does not had a ninepatch chunk,
1258             then the pad will be ignored. If we could change this to lazily
1259             alloc/assign the rect, we could avoid the GC churn of making new
1260             Rects only to drop them on the floor.
1261         */
1262         Rect pad = new Rect();
1263 
1264         // Special stuff for compatibility mode: if the target density is not
1265         // the same as the display density, but the resource -is- the same as
1266         // the display density, then don't scale it down to the target density.
1267         // This allows us to load the system's density-correct resources into
1268         // an application in compatibility mode, without scaling those down
1269         // to the compatibility density only to have them scaled back up when
1270         // drawn to the screen.
1271         opts.inScreenDensity = Drawable.resolveDensity(res, 0);
1272         Bitmap  bm = BitmapFactory.decodeResourceStream(res, value, is, pad, opts);
1273         if (bm != null) {
1274             byte[] np = bm.getNinePatchChunk();
1275             if (np == null || !NinePatch.isNinePatchChunk(np)) {
1276                 np = null;
1277                 pad = null;
1278             }
1279 
1280             final Rect opticalInsets = new Rect();
1281             bm.getOpticalInsets(opticalInsets);
1282             return drawableFromBitmap(res, bm, np, pad, opticalInsets, srcName);
1283         }
1284         return null;
1285     }
1286 
getBitmapDrawable(Resources res, TypedValue value, InputStream is)1287     private static Drawable getBitmapDrawable(Resources res, TypedValue value, InputStream is) {
1288         try {
1289             ImageDecoder.Source source = null;
1290             if (value != null) {
1291                 int density = Bitmap.DENSITY_NONE;
1292                 if (value.density == TypedValue.DENSITY_DEFAULT) {
1293                     density = DisplayMetrics.DENSITY_DEFAULT;
1294                 } else if (value.density != TypedValue.DENSITY_NONE) {
1295                     density = value.density;
1296                 }
1297                 source = ImageDecoder.createSource(res, is, density);
1298             } else {
1299                 source = ImageDecoder.createSource(res, is);
1300             }
1301 
1302             return ImageDecoder.decodeDrawable(source, (decoder, info, src) -> {
1303                 decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
1304                 decoder.setOnPartialImageListener((e) -> {
1305                     return e.getError() == ImageDecoder.DecodeException.SOURCE_INCOMPLETE;
1306                 });
1307             });
1308         } catch (IOException e) {
1309             /*  do nothing.
1310                 If the exception happened on decode, the drawable will be null.
1311             */
1312             Log.e("Drawable", "Unable to decode stream: " + e);
1313         }
1314         return null;
1315     }
1316 
1317     /**
1318      * Create a drawable from an XML document. For more information on how to
1319      * create resources in XML, see
1320      * <a href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.
1321      */
1322     @NonNull
createFromXml(@onNull Resources r, @NonNull XmlPullParser parser)1323     public static Drawable createFromXml(@NonNull Resources r, @NonNull XmlPullParser parser)
1324             throws XmlPullParserException, IOException {
1325         return createFromXml(r, parser, null);
1326     }
1327 
1328     /**
1329      * Create a drawable from an XML document using an optional {@link Theme}.
1330      * For more information on how to create resources in XML, see
1331      * <a href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.
1332      */
1333     @NonNull
createFromXml(@onNull Resources r, @NonNull XmlPullParser parser, @Nullable Theme theme)1334     public static Drawable createFromXml(@NonNull Resources r, @NonNull XmlPullParser parser,
1335             @Nullable Theme theme) throws XmlPullParserException, IOException {
1336         return createFromXmlForDensity(r, parser, 0, theme);
1337     }
1338 
1339     /**
1340      * Version of {@link #createFromXml(Resources, XmlPullParser, Theme)} that accepts a density
1341      * override.
1342      * @hide
1343      */
1344     @NonNull
createFromXmlForDensity(@onNull Resources r, @NonNull XmlPullParser parser, int density, @Nullable Theme theme)1345     public static Drawable createFromXmlForDensity(@NonNull Resources r,
1346             @NonNull XmlPullParser parser, int density, @Nullable Theme theme)
1347             throws XmlPullParserException, IOException {
1348         AttributeSet attrs = Xml.asAttributeSet(parser);
1349 
1350         int type;
1351         //noinspection StatementWithEmptyBody
1352         while ((type=parser.next()) != XmlPullParser.START_TAG
1353                 && type != XmlPullParser.END_DOCUMENT) {
1354             // Empty loop.
1355         }
1356 
1357         if (type != XmlPullParser.START_TAG) {
1358             throw new XmlPullParserException("No start tag found");
1359         }
1360 
1361         Drawable drawable = createFromXmlInnerForDensity(r, parser, attrs, density, theme);
1362 
1363         if (drawable == null) {
1364             throw new RuntimeException("Unknown initial tag: " + parser.getName());
1365         }
1366 
1367         return drawable;
1368     }
1369 
1370     /**
1371      * Create from inside an XML document.  Called on a parser positioned at
1372      * a tag in an XML document, tries to create a Drawable from that tag.
1373      * Returns null if the tag is not a valid drawable.
1374      */
1375     @NonNull
createFromXmlInner(@onNull Resources r, @NonNull XmlPullParser parser, @NonNull AttributeSet attrs)1376     public static Drawable createFromXmlInner(@NonNull Resources r, @NonNull XmlPullParser parser,
1377             @NonNull AttributeSet attrs) throws XmlPullParserException, IOException {
1378         return createFromXmlInner(r, parser, attrs, null);
1379     }
1380 
1381     /**
1382      * Create a drawable from inside an XML document using an optional
1383      * {@link Theme}. Called on a parser positioned at a tag in an XML
1384      * document, tries to create a Drawable from that tag. Returns {@code null}
1385      * if the tag is not a valid drawable.
1386      */
1387     @NonNull
createFromXmlInner(@onNull Resources r, @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, @Nullable Theme theme)1388     public static Drawable createFromXmlInner(@NonNull Resources r, @NonNull XmlPullParser parser,
1389             @NonNull AttributeSet attrs, @Nullable Theme theme)
1390             throws XmlPullParserException, IOException {
1391         return createFromXmlInnerForDensity(r, parser, attrs, 0, theme);
1392     }
1393 
1394     /**
1395      * Version of {@link #createFromXmlInner(Resources, XmlPullParser, AttributeSet, Theme)} that
1396      * accepts an override density.
1397      */
1398     @NonNull
createFromXmlInnerForDensity(@onNull Resources r, @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, int density, @Nullable Theme theme)1399     static Drawable createFromXmlInnerForDensity(@NonNull Resources r,
1400             @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, int density,
1401             @Nullable Theme theme) throws XmlPullParserException, IOException {
1402         return r.getDrawableInflater().inflateFromXmlForDensity(parser.getName(), parser, attrs,
1403                 density, theme);
1404     }
1405 
1406     /**
1407      * Create a drawable from file path name.
1408      */
1409     @Nullable
createFromPath(String pathName)1410     public static Drawable createFromPath(String pathName) {
1411         if (pathName == null) {
1412             return null;
1413         }
1414 
1415         Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, pathName);
1416         try (FileInputStream stream = new FileInputStream(pathName)) {
1417             return getBitmapDrawable(null, null, stream);
1418         } catch(IOException e) {
1419             // Do nothing; we will just return null if the FileInputStream had an error
1420         } finally {
1421             Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
1422         }
1423 
1424         return null;
1425     }
1426 
1427     /**
1428      * Inflate this Drawable from an XML resource. Does not apply a theme.
1429      *
1430      * @see #inflate(Resources, XmlPullParser, AttributeSet, Theme)
1431      */
inflate(@onNull Resources r, @NonNull XmlPullParser parser, @NonNull AttributeSet attrs)1432     public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser,
1433             @NonNull AttributeSet attrs) throws XmlPullParserException, IOException {
1434         inflate(r, parser, attrs, null);
1435     }
1436 
1437     /**
1438      * Inflate this Drawable from an XML resource optionally styled by a theme.
1439      * This can't be called more than once for each Drawable. Note that framework may have called
1440      * this once to create the Drawable instance from XML resource.
1441      *
1442      * @param r Resources used to resolve attribute values
1443      * @param parser XML parser from which to inflate this Drawable
1444      * @param attrs Base set of attribute values
1445      * @param theme Theme to apply, may be null
1446      * @throws XmlPullParserException
1447      * @throws IOException
1448      */
inflate(@onNull Resources r, @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, @Nullable Theme theme)1449     public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser,
1450             @NonNull AttributeSet attrs, @Nullable Theme theme)
1451             throws XmlPullParserException, IOException {
1452         final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.Drawable);
1453         mVisible = a.getBoolean(R.styleable.Drawable_visible, mVisible);
1454         a.recycle();
1455     }
1456 
1457     /**
1458      * Inflate a Drawable from an XML resource.
1459      *
1460      * @throws XmlPullParserException
1461      * @throws IOException
1462      */
1463     @UnsupportedAppUsage
inflateWithAttributes(@onNull @uppressWarnings"unused") Resources r, @NonNull @SuppressWarnings("unused") XmlPullParser parser, @NonNull TypedArray attrs, @AttrRes int visibleAttr)1464     void inflateWithAttributes(@NonNull @SuppressWarnings("unused") Resources r,
1465             @NonNull @SuppressWarnings("unused") XmlPullParser parser, @NonNull TypedArray attrs,
1466             @AttrRes int visibleAttr) throws XmlPullParserException, IOException {
1467         mVisible = attrs.getBoolean(visibleAttr, mVisible);
1468     }
1469 
1470     /**
1471      * Sets the source override density for this Drawable. If non-zero, this density is to be used
1472      * for any calls to {@link Resources#getDrawableForDensity(int, int, Theme)} or
1473      * {@link Resources#getValueForDensity(int, int, TypedValue, boolean)}.
1474      * @hide
1475      */
setSrcDensityOverride(int density)1476     final void setSrcDensityOverride(int density) {
1477         mSrcDensityOverride = density;
1478     }
1479 
1480     /**
1481      * This abstract class is used by {@link Drawable}s to store shared constant state and data
1482      * between Drawables. {@link BitmapDrawable}s created from the same resource will for instance
1483      * share a unique bitmap stored in their ConstantState.
1484      *
1485      * <p>
1486      * {@link #newDrawable(Resources)} can be used as a factory to create new Drawable instances
1487      * from this ConstantState.
1488      * </p>
1489      *
1490      * Use {@link Drawable#getConstantState()} to retrieve the ConstantState of a Drawable. Calling
1491      * {@link Drawable#mutate()} on a Drawable should typically create a new ConstantState for that
1492      * Drawable.
1493      */
1494     public static abstract class ConstantState {
1495         /**
1496          * Creates a new Drawable instance from its constant state.
1497          * <p>
1498          * <strong>Note:</strong> Using this method means density-dependent
1499          * properties, such as pixel dimensions or bitmap images, will not be
1500          * updated to match the density of the target display. To ensure
1501          * correct scaling, use {@link #newDrawable(Resources)} instead to
1502          * provide an appropriate Resources object.
1503          *
1504          * @return a new drawable object based on this constant state
1505          * @see #newDrawable(Resources)
1506          */
newDrawable()1507         public abstract @NonNull Drawable newDrawable();
1508 
1509         /**
1510          * Creates a new Drawable instance from its constant state using the
1511          * specified resources. This method should be implemented for drawables
1512          * that have density-dependent properties.
1513          * <p>
1514          * The default implementation for this method calls through to
1515          * {@link #newDrawable()}.
1516          *
1517          * @param res the resources of the context in which the drawable will
1518          *            be displayed
1519          * @return a new drawable object based on this constant state
1520          */
newDrawable(@ullable Resources res)1521         public @NonNull Drawable newDrawable(@Nullable Resources res) {
1522             return newDrawable();
1523         }
1524 
1525         /**
1526          * Creates a new Drawable instance from its constant state using the
1527          * specified resources and theme. This method should be implemented for
1528          * drawables that have theme-dependent properties.
1529          * <p>
1530          * The default implementation for this method calls through to
1531          * {@link #newDrawable(Resources)}.
1532          *
1533          * @param res the resources of the context in which the drawable will
1534          *            be displayed
1535          * @param theme the theme of the context in which the drawable will be
1536          *              displayed
1537          * @return a new drawable object based on this constant state
1538          */
newDrawable(@ullable Resources res, @Nullable @SuppressWarnings("unused") Theme theme)1539         public @NonNull Drawable newDrawable(@Nullable Resources res,
1540                 @Nullable @SuppressWarnings("unused") Theme theme) {
1541             return newDrawable(res);
1542         }
1543 
1544         /**
1545          * Return a bit mask of configuration changes that will impact
1546          * this drawable (and thus require completely reloading it).
1547          */
getChangingConfigurations()1548         public abstract @Config int getChangingConfigurations();
1549 
1550         /**
1551          * Return whether this constant state can have a theme applied.
1552          */
canApplyTheme()1553         public boolean canApplyTheme() {
1554             return false;
1555         }
1556     }
1557 
1558     /**
1559      * Return a {@link ConstantState} instance that holds the shared state of this Drawable.
1560      *
1561      * @return The ConstantState associated to that Drawable.
1562      * @see ConstantState
1563      * @see Drawable#mutate()
1564      */
getConstantState()1565     public @Nullable ConstantState getConstantState() {
1566         return null;
1567     }
1568 
drawableFromBitmap(Resources res, Bitmap bm, byte[] np, Rect pad, Rect layoutBounds, String srcName)1569     private static Drawable drawableFromBitmap(Resources res, Bitmap bm, byte[] np,
1570             Rect pad, Rect layoutBounds, String srcName) {
1571 
1572         if (np != null) {
1573             return new NinePatchDrawable(res, bm, np, pad, layoutBounds, srcName);
1574         }
1575 
1576         return new BitmapDrawable(res, bm);
1577     }
1578 
1579     /**
1580      * Ensures the tint filter is consistent with the current tint color and
1581      * mode.
1582      */
1583     @UnsupportedAppUsage
updateTintFilter(@ullable PorterDuffColorFilter tintFilter, @Nullable ColorStateList tint, @Nullable PorterDuff.Mode tintMode)1584     @Nullable PorterDuffColorFilter updateTintFilter(@Nullable PorterDuffColorFilter tintFilter,
1585             @Nullable ColorStateList tint, @Nullable PorterDuff.Mode tintMode) {
1586         if (tint == null || tintMode == null) {
1587             return null;
1588         }
1589 
1590         final int color = tint.getColorForState(getState(), Color.TRANSPARENT);
1591         if (tintFilter == null || tintFilter.getColor() != color
1592                 || tintFilter.getMode() != tintMode) {
1593             return new PorterDuffColorFilter(color, tintMode);
1594         }
1595 
1596         return tintFilter;
1597     }
1598 
updateBlendModeFilter(@ullable BlendModeColorFilter blendFilter, @Nullable ColorStateList tint, @Nullable BlendMode blendMode)1599     @Nullable BlendModeColorFilter updateBlendModeFilter(@Nullable BlendModeColorFilter blendFilter,
1600             @Nullable ColorStateList tint, @Nullable BlendMode blendMode) {
1601         if (tint == null || blendMode == null) {
1602             return null;
1603         }
1604 
1605         final int color = tint.getColorForState(getState(), Color.TRANSPARENT);
1606         if (blendFilter == null || blendFilter.getColor() != color
1607                 || blendFilter.getMode() != blendMode) {
1608             return new BlendModeColorFilter(color, blendMode);
1609         }
1610         return blendFilter;
1611     }
1612 
1613     /**
1614      * Obtains styled attributes from the theme, if available, or unstyled
1615      * resources if the theme is null.
1616      * @hide
1617      */
obtainAttributes(@onNull Resources res, @Nullable Theme theme, @NonNull AttributeSet set, @NonNull int[] attrs)1618     protected static @NonNull TypedArray obtainAttributes(@NonNull Resources res,
1619             @Nullable Theme theme, @NonNull AttributeSet set, @NonNull int[] attrs) {
1620         if (theme == null) {
1621             return res.obtainAttributes(set, attrs);
1622         }
1623         return theme.obtainStyledAttributes(set, attrs, 0, 0);
1624     }
1625 
1626     /**
1627      * Scales a floating-point pixel value from the source density to the
1628      * target density.
1629      *
1630      * @param pixels the pixel value for use in source density
1631      * @param sourceDensity the source density
1632      * @param targetDensity the target density
1633      * @return the scaled pixel value for use in target density
1634      */
scaleFromDensity(float pixels, int sourceDensity, int targetDensity)1635     static float scaleFromDensity(float pixels, int sourceDensity, int targetDensity) {
1636         return pixels * targetDensity / sourceDensity;
1637     }
1638 
1639     /**
1640      * Scales a pixel value from the source density to the target density,
1641      * optionally handling the resulting pixel value as a size rather than an
1642      * offset.
1643      * <p>
1644      * A size conversion involves rounding the base value and ensuring that
1645      * a non-zero base value is at least one pixel in size.
1646      * <p>
1647      * An offset conversion involves simply truncating the base value to an
1648      * integer.
1649      *
1650      * @param pixels the pixel value for use in source density
1651      * @param sourceDensity the source density
1652      * @param targetDensity the target density
1653      * @param isSize {@code true} to handle the resulting scaled value as a
1654      *               size, or {@code false} to handle it as an offset
1655      * @return the scaled pixel value for use in target density
1656      */
scaleFromDensity( int pixels, int sourceDensity, int targetDensity, boolean isSize)1657     static int scaleFromDensity(
1658             int pixels, int sourceDensity, int targetDensity, boolean isSize) {
1659         if (pixels == 0 || sourceDensity == targetDensity) {
1660             return pixels;
1661         }
1662 
1663         final float result = pixels * targetDensity / (float) sourceDensity;
1664         if (!isSize) {
1665             return (int) result;
1666         }
1667 
1668         final int rounded = Math.round(result);
1669         if (rounded != 0) {
1670             return rounded;
1671         } else if (pixels > 0) {
1672             return 1;
1673         } else {
1674             return -1;
1675         }
1676     }
1677 
resolveDensity(@ullable Resources r, int parentDensity)1678     static int resolveDensity(@Nullable Resources r, int parentDensity) {
1679         final int densityDpi = r == null ? parentDensity : r.getDisplayMetrics().densityDpi;
1680         return densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi;
1681     }
1682 
1683     /**
1684      * Re-throws an exception as a {@link RuntimeException} with an empty stack
1685      * trace to avoid cluttering the log. The original exception's stack trace
1686      * will still be included.
1687      *
1688      * @param cause the exception to re-throw
1689      * @throws RuntimeException
1690      */
rethrowAsRuntimeException(@onNull Exception cause)1691     static void rethrowAsRuntimeException(@NonNull Exception cause) throws RuntimeException {
1692         final RuntimeException e = new RuntimeException(cause);
1693         e.setStackTrace(new StackTraceElement[0]);
1694         throw e;
1695     }
1696 
1697     /**
1698      * Parses a {@link android.graphics.PorterDuff.Mode} from a tintMode
1699      * attribute's enum value.
1700      *
1701      * @hide
1702      */
1703     @UnsupportedAppUsage
parseTintMode(int value, Mode defaultMode)1704     public static PorterDuff.Mode parseTintMode(int value, Mode defaultMode) {
1705         switch (value) {
1706             case 3: return Mode.SRC_OVER;
1707             case 5: return Mode.SRC_IN;
1708             case 9: return Mode.SRC_ATOP;
1709             case 14: return Mode.MULTIPLY;
1710             case 15: return Mode.SCREEN;
1711             case 16: return Mode.ADD;
1712             default: return defaultMode;
1713         }
1714     }
1715 
1716     /**
1717      * Parses a {@link android.graphics.BlendMode} from a tintMode
1718      * attribute's enum value.
1719      *
1720      * @hide
1721      */
1722     @UnsupportedAppUsage
parseBlendMode(int value, BlendMode defaultMode)1723     public static BlendMode parseBlendMode(int value, BlendMode defaultMode) {
1724         switch (value) {
1725             case 3: return BlendMode.SRC_OVER;
1726             case 5: return BlendMode.SRC_IN;
1727             case 9: return BlendMode.SRC_ATOP;
1728             // b/73224934 PorterDuff Multiply maps to Skia Modulate so actually
1729             // return BlendMode.MODULATE here
1730             case 14: return BlendMode.MODULATE;
1731             case 15: return BlendMode.SCREEN;
1732             case 16: return BlendMode.PLUS;
1733             default: return defaultMode;
1734         }
1735     }
1736 }
1737 
1738