OSDN Git Service

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