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