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