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