Drawable.java revision 17cd4dfe3a05c2eddbcbc76066ff3b13fc3f2c8b
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;
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 */
125public 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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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         */
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         */
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         */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
444    public int getAlpha() {
445        return 0xFF;
446    }
447
448    /**
449     * @hide Consider for future API inclusion
450     */
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     */
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     */
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     */
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     */
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     */
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     */
516    public ColorFilter getColorFilter() {
517        return null;
518    }
519
520    /**
521     * Removes the color filter for this drawable.
522     */
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     */
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     */
544    public void setHotspotBounds(int left, int top, int right, int bottom) {}
545
546    /** @hide For internal use only. Individual results may vary. */
547    public void getHotspotBounds(Rect outRect) {
548        outRect.set(getBounds());
549    }
550
551    /**
552     * Whether this drawable requests projection.
553     *
554     * @hide magic!
555     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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
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     */
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     */
706    public boolean isAutoMirrored() {
707        return false;
708    }
709
710    /**
711     * Applies the specified theme to this Drawable and its children.
712     */
713    public void applyTheme(@SuppressWarnings("unused") Theme t) {
714    }
715
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
915    public Drawable mutate() {
916        return this;
917    }
918
919    /**
920     * Clears the mutated state, allowing this drawable to be cached and
921     * mutated again.
922     * <p>
923     * This is hidden because only framework drawables can be cached, so
924     * custom drawables don't need to support constant state, mutate(), or
925     * clearMutated().
926     *
927     * @hide
928     */
929    public void clearMutated() {
930        // Default implementation is no-op.
931    }
932
933    /**
934     * Create a drawable from an inputstream
935     */
936    public static Drawable createFromStream(InputStream is, String srcName) {
937        Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, srcName != null ? srcName : "Unknown drawable");
938        try {
939            return createFromResourceStream(null, null, is, srcName);
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     */
949    public static Drawable createFromResourceStream(Resources res, TypedValue value,
950            InputStream is, String srcName) {
951        Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, srcName != null ? srcName : "Unknown drawable");
952        try {
953            return createFromResourceStream(res, value, is, srcName, null);
954        } finally {
955            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
956        }
957    }
958
959    /**
960     * Create a drawable from an inputstream, using the given resources and
961     * value to determine density information.
962     */
963    public static Drawable createFromResourceStream(Resources res, TypedValue value,
964            InputStream is, String srcName, BitmapFactory.Options opts) {
965        if (is == null) {
966            return null;
967        }
968
969        /*  ugh. The decodeStream contract is that we have already allocated
970            the pad rect, but if the bitmap does not had a ninepatch chunk,
971            then the pad will be ignored. If we could change this to lazily
972            alloc/assign the rect, we could avoid the GC churn of making new
973            Rects only to drop them on the floor.
974        */
975        Rect pad = new Rect();
976
977        // Special stuff for compatibility mode: if the target density is not
978        // the same as the display density, but the resource -is- the same as
979        // the display density, then don't scale it down to the target density.
980        // This allows us to load the system's density-correct resources into
981        // an application in compatibility mode, without scaling those down
982        // to the compatibility density only to have them scaled back up when
983        // drawn to the screen.
984        if (opts == null) opts = new BitmapFactory.Options();
985        opts.inScreenDensity = res != null
986                ? res.getDisplayMetrics().noncompatDensityDpi : DisplayMetrics.DENSITY_DEVICE;
987        Bitmap  bm = BitmapFactory.decodeResourceStream(res, value, is, pad, opts);
988        if (bm != null) {
989            byte[] np = bm.getNinePatchChunk();
990            if (np == null || !NinePatch.isNinePatchChunk(np)) {
991                np = null;
992                pad = null;
993            }
994
995            final Rect opticalInsets = new Rect();
996            bm.getOpticalInsets(opticalInsets);
997            return drawableFromBitmap(res, bm, np, pad, opticalInsets, srcName);
998        }
999        return null;
1000    }
1001
1002    /**
1003     * Create a drawable from an XML document. For more information on how to
1004     * create resources in XML, see
1005     * <a href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.
1006     */
1007    public static Drawable createFromXml(Resources r, XmlPullParser parser)
1008            throws XmlPullParserException, IOException {
1009        return createFromXml(r, parser, null);
1010    }
1011
1012    /**
1013     * Create a drawable from an XML document using an optional {@link Theme}.
1014     * For more information on how to create resources in XML, see
1015     * <a href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.
1016     */
1017    public static Drawable createFromXml(Resources r, XmlPullParser parser, Theme theme)
1018            throws XmlPullParserException, IOException {
1019        AttributeSet attrs = Xml.asAttributeSet(parser);
1020
1021        int type;
1022        while ((type=parser.next()) != XmlPullParser.START_TAG &&
1023                type != XmlPullParser.END_DOCUMENT) {
1024            // Empty loop
1025        }
1026
1027        if (type != XmlPullParser.START_TAG) {
1028            throw new XmlPullParserException("No start tag found");
1029        }
1030
1031        Drawable drawable = createFromXmlInner(r, parser, attrs, theme);
1032
1033        if (drawable == null) {
1034            throw new RuntimeException("Unknown initial tag: " + parser.getName());
1035        }
1036
1037        return drawable;
1038    }
1039
1040    /**
1041     * Create from inside an XML document.  Called on a parser positioned at
1042     * a tag in an XML document, tries to create a Drawable from that tag.
1043     * Returns null if the tag is not a valid drawable.
1044     */
1045    public static Drawable createFromXmlInner(Resources r, XmlPullParser parser, AttributeSet attrs)
1046            throws XmlPullParserException, IOException {
1047        return createFromXmlInner(r, parser, attrs, null);
1048    }
1049
1050    /**
1051     * Create a drawable from inside an XML document using an optional
1052     * {@link Theme}. Called on a parser positioned at a tag in an XML
1053     * document, tries to create a Drawable from that tag. Returns {@code null}
1054     * if the tag is not a valid drawable.
1055     */
1056    public static Drawable createFromXmlInner(Resources r, XmlPullParser parser, AttributeSet attrs,
1057            Theme theme) throws XmlPullParserException, IOException {
1058        final Drawable drawable;
1059
1060        final String name = parser.getName();
1061        if (name.equals("selector")) {
1062            drawable = new StateListDrawable();
1063        } else if (name.equals("animated-selector")) {
1064            drawable = new AnimatedStateListDrawable();
1065        } else if (name.equals("level-list")) {
1066            drawable = new LevelListDrawable();
1067        } else if (name.equals("layer-list")) {
1068            drawable = new LayerDrawable();
1069        } else if (name.equals("transition")) {
1070            drawable = new TransitionDrawable();
1071        } else if (name.equals("ripple")) {
1072            drawable = new RippleDrawable();
1073        } else if (name.equals("color")) {
1074            drawable = new ColorDrawable();
1075        } else if (name.equals("shape")) {
1076            drawable = new GradientDrawable();
1077        } else if (name.equals("vector")) {
1078            drawable = new VectorDrawable();
1079        } else if (name.equals("animated-vector")) {
1080            drawable = new AnimatedVectorDrawable();
1081        } else if (name.equals("scale")) {
1082            drawable = new ScaleDrawable();
1083        } else if (name.equals("clip")) {
1084            drawable = new ClipDrawable();
1085        } else if (name.equals("rotate")) {
1086            drawable = new RotateDrawable();
1087        } else if (name.equals("animated-rotate")) {
1088            drawable = new AnimatedRotateDrawable();
1089        } else if (name.equals("animation-list")) {
1090            drawable = new AnimationDrawable();
1091        } else if (name.equals("inset")) {
1092            drawable = new InsetDrawable();
1093        } else if (name.equals("bitmap")) {
1094            //noinspection deprecation
1095            drawable = new BitmapDrawable(r);
1096            if (r != null) {
1097               ((BitmapDrawable) drawable).setTargetDensity(r.getDisplayMetrics());
1098            }
1099        } else if (name.equals("nine-patch")) {
1100            drawable = new NinePatchDrawable();
1101            if (r != null) {
1102                ((NinePatchDrawable) drawable).setTargetDensity(r.getDisplayMetrics());
1103             }
1104        } else {
1105            throw new XmlPullParserException(parser.getPositionDescription() +
1106                    ": invalid drawable tag " + name);
1107        }
1108
1109        drawable.inflate(r, parser, attrs, theme);
1110        return drawable;
1111    }
1112
1113
1114    /**
1115     * Create a drawable from file path name.
1116     */
1117    public static Drawable createFromPath(String pathName) {
1118        if (pathName == null) {
1119            return null;
1120        }
1121
1122        Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, pathName);
1123        try {
1124            Bitmap bm = BitmapFactory.decodeFile(pathName);
1125            if (bm != null) {
1126                return drawableFromBitmap(null, bm, null, null, null, pathName);
1127            }
1128        } finally {
1129            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
1130        }
1131
1132        return null;
1133    }
1134
1135    /**
1136     * Inflate this Drawable from an XML resource. Does not apply a theme.
1137     *
1138     * @see #inflate(Resources, XmlPullParser, AttributeSet, Theme)
1139     */
1140    public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs)
1141            throws XmlPullParserException, IOException {
1142        inflate(r, parser, attrs, null);
1143    }
1144
1145    /**
1146     * Inflate this Drawable from an XML resource optionally styled by a theme.
1147     *
1148     * @param r Resources used to resolve attribute values
1149     * @param parser XML parser from which to inflate this Drawable
1150     * @param attrs Base set of attribute values
1151     * @param theme Theme to apply, may be null
1152     * @throws XmlPullParserException
1153     * @throws IOException
1154     */
1155    public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
1156            throws XmlPullParserException, IOException {
1157        final TypedArray a;
1158        if (theme != null) {
1159            a = theme.obtainStyledAttributes(
1160                    attrs, com.android.internal.R.styleable.Drawable, 0, 0);
1161        } else {
1162            a = r.obtainAttributes(attrs, com.android.internal.R.styleable.Drawable);
1163        }
1164
1165        inflateWithAttributes(r, parser, a, com.android.internal.R.styleable.Drawable_visible);
1166        a.recycle();
1167    }
1168
1169    /**
1170     * Inflate a Drawable from an XML resource.
1171     *
1172     * @throws XmlPullParserException
1173     * @throws IOException
1174     */
1175    void inflateWithAttributes(Resources r, XmlPullParser parser, TypedArray attrs, int visibleAttr)
1176            throws XmlPullParserException, IOException {
1177        mVisible = attrs.getBoolean(visibleAttr, mVisible);
1178    }
1179
1180    /**
1181     * This abstract class is used by {@link Drawable}s to store shared constant state and data
1182     * between Drawables. {@link BitmapDrawable}s created from the same resource will for instance
1183     * share a unique bitmap stored in their ConstantState.
1184     *
1185     * <p>
1186     * {@link #newDrawable(Resources)} can be used as a factory to create new Drawable instances
1187     * from this ConstantState.
1188     * </p>
1189     *
1190     * Use {@link Drawable#getConstantState()} to retrieve the ConstantState of a Drawable. Calling
1191     * {@link Drawable#mutate()} on a Drawable should typically create a new ConstantState for that
1192     * Drawable.
1193     */
1194    public static abstract class ConstantState {
1195        /**
1196         * Create a new drawable without supplying resources the caller
1197         * is running in.  Note that using this means the density-dependent
1198         * drawables (like bitmaps) will not be able to update their target
1199         * density correctly. One should use {@link #newDrawable(Resources)}
1200         * instead to provide a resource.
1201         */
1202        public abstract Drawable newDrawable();
1203
1204        /**
1205         * Create a new Drawable instance from its constant state.  This
1206         * must be implemented for drawables that change based on the target
1207         * density of their caller (that is depending on whether it is
1208         * in compatibility mode).
1209         */
1210        public Drawable newDrawable(Resources res) {
1211            return newDrawable();
1212        }
1213
1214        /**
1215         * Create a new Drawable instance from its constant state. This must be
1216         * implemented for drawables that can have a theme applied.
1217         */
1218        public Drawable newDrawable(Resources res, Theme theme) {
1219            return newDrawable(null);
1220        }
1221
1222        /**
1223         * Return a bit mask of configuration changes that will impact
1224         * this drawable (and thus require completely reloading it).
1225         */
1226        public abstract int getChangingConfigurations();
1227
1228        /**
1229         * @hide
1230         */
1231        public Bitmap getBitmap() {
1232            return null;
1233        }
1234
1235        /**
1236         * Return whether this constant state can have a theme applied.
1237         */
1238        public boolean canApplyTheme() {
1239            return false;
1240        }
1241    }
1242
1243    /**
1244     * Return a {@link ConstantState} instance that holds the shared state of this Drawable.
1245     *
1246     * @return The ConstantState associated to that Drawable.
1247     * @see ConstantState
1248     * @see Drawable#mutate()
1249     */
1250    public ConstantState getConstantState() {
1251        return null;
1252    }
1253
1254    private static Drawable drawableFromBitmap(Resources res, Bitmap bm, byte[] np,
1255            Rect pad, Rect layoutBounds, String srcName) {
1256
1257        if (np != null) {
1258            return new NinePatchDrawable(res, bm, np, pad, layoutBounds, srcName);
1259        }
1260
1261        return new BitmapDrawable(res, bm);
1262    }
1263
1264    /**
1265     * Ensures the tint filter is consistent with the current tint color and
1266     * mode.
1267     */
1268    PorterDuffColorFilter updateTintFilter(PorterDuffColorFilter tintFilter, ColorStateList tint,
1269            PorterDuff.Mode tintMode) {
1270        if (tint == null || tintMode == null) {
1271            return null;
1272        }
1273
1274        final int color = tint.getColorForState(getState(), Color.TRANSPARENT);
1275        if (tintFilter == null) {
1276            return new PorterDuffColorFilter(color, tintMode);
1277        }
1278
1279        tintFilter.setColor(color);
1280        tintFilter.setMode(tintMode);
1281        return tintFilter;
1282    }
1283
1284    /**
1285     * Obtains styled attributes from the theme, if available, or unstyled
1286     * resources if the theme is null.
1287     */
1288    static TypedArray obtainAttributes(
1289            Resources res, Theme theme, AttributeSet set, int[] attrs) {
1290        if (theme == null) {
1291            return res.obtainAttributes(set, attrs);
1292        }
1293        return theme.obtainStyledAttributes(set, attrs, 0, 0);
1294    }
1295
1296    /**
1297     * Parses a {@link android.graphics.PorterDuff.Mode} from a tintMode
1298     * attribute's enum value.
1299     *
1300     * @hide
1301     */
1302    public static PorterDuff.Mode parseTintMode(int value, Mode defaultMode) {
1303        switch (value) {
1304            case 3: return Mode.SRC_OVER;
1305            case 5: return Mode.SRC_IN;
1306            case 9: return Mode.SRC_ATOP;
1307            case 14: return Mode.MULTIPLY;
1308            case 15: return Mode.SCREEN;
1309            case 16: return Mode.ADD;
1310            default: return defaultMode;
1311        }
1312    }
1313}
1314
1315