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