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