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.annotation.Nullable;
     21 import android.content.pm.ActivityInfo.Config;
     22 import android.content.res.ColorStateList;
     23 import android.content.res.Resources;
     24 import android.content.res.Resources.Theme;
     25 import android.content.res.TypedArray;
     26 import android.graphics.Canvas;
     27 import android.graphics.ColorFilter;
     28 import android.graphics.Outline;
     29 import android.graphics.PixelFormat;
     30 import android.graphics.PorterDuff.Mode;
     31 import android.graphics.Rect;
     32 import android.util.AttributeSet;
     33 import android.util.DisplayMetrics;
     34 import android.util.LayoutDirection;
     35 import android.util.Log;
     36 import android.view.Gravity;
     37 import android.view.View;
     38 
     39 import com.android.internal.R;
     40 
     41 import org.xmlpull.v1.XmlPullParser;
     42 import org.xmlpull.v1.XmlPullParserException;
     43 
     44 import java.io.IOException;
     45 
     46 /**
     47  * A Drawable that manages an array of other Drawables. These are drawn in array
     48  * order, so the element with the largest index will be drawn on top.
     49  * <p>
     50  * It can be defined in an XML file with the <code>&lt;layer-list></code> element.
     51  * Each Drawable in the layer is defined in a nested <code>&lt;item></code>.
     52  * <p>
     53  * For more information, see the guide to
     54  * <a href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.
     55  *
     56  * @attr ref android.R.styleable#LayerDrawable_paddingMode
     57  * @attr ref android.R.styleable#LayerDrawableItem_left
     58  * @attr ref android.R.styleable#LayerDrawableItem_top
     59  * @attr ref android.R.styleable#LayerDrawableItem_right
     60  * @attr ref android.R.styleable#LayerDrawableItem_bottom
     61  * @attr ref android.R.styleable#LayerDrawableItem_start
     62  * @attr ref android.R.styleable#LayerDrawableItem_end
     63  * @attr ref android.R.styleable#LayerDrawableItem_width
     64  * @attr ref android.R.styleable#LayerDrawableItem_height
     65  * @attr ref android.R.styleable#LayerDrawableItem_gravity
     66  * @attr ref android.R.styleable#LayerDrawableItem_drawable
     67  * @attr ref android.R.styleable#LayerDrawableItem_id
     68 */
     69 public class LayerDrawable extends Drawable implements Drawable.Callback {
     70     private static final String LOG_TAG = "LayerDrawable";
     71 
     72     /**
     73      * Padding mode used to nest each layer inside the padding of the previous
     74      * layer.
     75      *
     76      * @see #setPaddingMode(int)
     77      */
     78     public static final int PADDING_MODE_NEST = 0;
     79 
     80     /**
     81      * Padding mode used to stack each layer directly atop the previous layer.
     82      *
     83      * @see #setPaddingMode(int)
     84      */
     85     public static final int PADDING_MODE_STACK = 1;
     86 
     87     /**
     88      * Value used for undefined start and end insets.
     89      *
     90      * @see #getLayerInsetStart(int)
     91      * @see #getLayerInsetEnd(int)
     92      */
     93     public static final int INSET_UNDEFINED = Integer.MIN_VALUE;
     94 
     95     @NonNull
     96     LayerState mLayerState;
     97 
     98     private int[] mPaddingL;
     99     private int[] mPaddingT;
    100     private int[] mPaddingR;
    101     private int[] mPaddingB;
    102 
    103     private final Rect mTmpRect = new Rect();
    104     private final Rect mTmpOutRect = new Rect();
    105     private final Rect mTmpContainer = new Rect();
    106     private Rect mHotspotBounds;
    107     private boolean mMutated;
    108 
    109     private boolean mSuspendChildInvalidation;
    110     private boolean mChildRequestedInvalidation;
    111 
    112     /**
    113      * Creates a new layer drawable with the list of specified layers.
    114      *
    115      * @param layers a list of drawables to use as layers in this new drawable,
    116      *               must be non-null
    117      */
    118     public LayerDrawable(@NonNull Drawable[] layers) {
    119         this(layers, null);
    120     }
    121 
    122     /**
    123      * Creates a new layer drawable with the specified list of layers and the
    124      * specified constant state.
    125      *
    126      * @param layers The list of layers to add to this drawable.
    127      * @param state The constant drawable state.
    128      */
    129     LayerDrawable(@NonNull Drawable[] layers, @Nullable LayerState state) {
    130         this(state, null);
    131 
    132         if (layers == null) {
    133             throw new IllegalArgumentException("layers must be non-null");
    134         }
    135 
    136         final int length = layers.length;
    137         final ChildDrawable[] r = new ChildDrawable[length];
    138         for (int i = 0; i < length; i++) {
    139             r[i] = new ChildDrawable(mLayerState.mDensity);
    140             r[i].mDrawable = layers[i];
    141             layers[i].setCallback(this);
    142             mLayerState.mChildrenChangingConfigurations |= layers[i].getChangingConfigurations();
    143         }
    144         mLayerState.mNumChildren = length;
    145         mLayerState.mChildren = r;
    146 
    147         ensurePadding();
    148         refreshPadding();
    149     }
    150 
    151     LayerDrawable() {
    152         this((LayerState) null, null);
    153     }
    154 
    155     /**
    156      * The one constructor to rule them all. This is called by all public
    157      * constructors to set the state and initialize local properties.
    158      */
    159     LayerDrawable(@Nullable LayerState state, @Nullable Resources res) {
    160         mLayerState = createConstantState(state, res);
    161         if (mLayerState.mNumChildren > 0) {
    162             ensurePadding();
    163             refreshPadding();
    164         }
    165     }
    166 
    167     LayerState createConstantState(@Nullable LayerState state, @Nullable Resources res) {
    168         return new LayerState(state, this, res);
    169     }
    170 
    171     @Override
    172     public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser,
    173             @NonNull AttributeSet attrs, @Nullable Theme theme)
    174             throws XmlPullParserException, IOException {
    175         super.inflate(r, parser, attrs, theme);
    176 
    177         // The density may have changed since the last update. This will
    178         // apply scaling to any existing constant state properties.
    179         final LayerState state = mLayerState;
    180         final int density = Drawable.resolveDensity(r, 0);
    181         state.setDensity(density);
    182 
    183         final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.LayerDrawable);
    184         updateStateFromTypedArray(a);
    185         a.recycle();
    186 
    187         final ChildDrawable[] array = state.mChildren;
    188         final int N = state.mNumChildren;
    189         for (int i = 0; i < N; i++) {
    190             final ChildDrawable layer = array[i];
    191             layer.setDensity(density);
    192         }
    193 
    194         inflateLayers(r, parser, attrs, theme);
    195 
    196         ensurePadding();
    197         refreshPadding();
    198     }
    199 
    200     @Override
    201     public void applyTheme(@NonNull Theme t) {
    202         super.applyTheme(t);
    203 
    204         final LayerState state = mLayerState;
    205         final int density = Drawable.resolveDensity(t.getResources(), 0);
    206         state.setDensity(density);
    207 
    208         if (state.mThemeAttrs != null) {
    209             final TypedArray a = t.resolveAttributes(
    210                     state.mThemeAttrs, R.styleable.LayerDrawable);
    211             updateStateFromTypedArray(a);
    212             a.recycle();
    213         }
    214 
    215         final ChildDrawable[] array = state.mChildren;
    216         final int N = state.mNumChildren;
    217         for (int i = 0; i < N; i++) {
    218             final ChildDrawable layer = array[i];
    219             layer.setDensity(density);
    220 
    221             if (layer.mThemeAttrs != null) {
    222                 final TypedArray a = t.resolveAttributes(
    223                         layer.mThemeAttrs, R.styleable.LayerDrawableItem);
    224                 updateLayerFromTypedArray(layer, a);
    225                 a.recycle();
    226             }
    227 
    228             final Drawable d = layer.mDrawable;
    229             if (d != null && d.canApplyTheme()) {
    230                 d.applyTheme(t);
    231 
    232                 // Update cached mask of child changing configurations.
    233                 state.mChildrenChangingConfigurations |= d.getChangingConfigurations();
    234             }
    235         }
    236     }
    237 
    238     /**
    239      * Inflates child layers using the specified parser.
    240      */
    241     private void inflateLayers(@NonNull Resources r, @NonNull XmlPullParser parser,
    242             @NonNull AttributeSet attrs, @Nullable Theme theme)
    243             throws XmlPullParserException, IOException {
    244         final LayerState state = mLayerState;
    245 
    246         final int innerDepth = parser.getDepth() + 1;
    247         int type;
    248         int depth;
    249         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
    250                 && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) {
    251             if (type != XmlPullParser.START_TAG) {
    252                 continue;
    253             }
    254 
    255             if (depth > innerDepth || !parser.getName().equals("item")) {
    256                 continue;
    257             }
    258 
    259             final ChildDrawable layer = new ChildDrawable(state.mDensity);
    260             final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.LayerDrawableItem);
    261             updateLayerFromTypedArray(layer, a);
    262             a.recycle();
    263 
    264             // If the layer doesn't have a drawable or unresolved theme
    265             // attribute for a drawable, attempt to parse one from the child
    266             // element. If multiple child elements exist, we'll only use the
    267             // first one.
    268             if (layer.mDrawable == null && (layer.mThemeAttrs == null ||
    269                     layer.mThemeAttrs[R.styleable.LayerDrawableItem_drawable] == 0)) {
    270                 while ((type = parser.next()) == XmlPullParser.TEXT) {
    271                 }
    272                 if (type != XmlPullParser.START_TAG) {
    273                     throw new XmlPullParserException(parser.getPositionDescription()
    274                             + ": <item> tag requires a 'drawable' attribute or "
    275                             + "child tag defining a drawable");
    276                 }
    277 
    278                 // We found a child drawable. Take ownership.
    279                 layer.mDrawable = Drawable.createFromXmlInner(r, parser, attrs, theme);
    280                 layer.mDrawable.setCallback(this);
    281                 state.mChildrenChangingConfigurations |=
    282                         layer.mDrawable.getChangingConfigurations();
    283             }
    284 
    285             addLayer(layer);
    286         }
    287     }
    288 
    289     /**
    290      * Initializes the constant state from the values in the typed array.
    291      */
    292     private void updateStateFromTypedArray(@NonNull TypedArray a) {
    293         final LayerState state = mLayerState;
    294 
    295         // Account for any configuration changes.
    296         state.mChangingConfigurations |= a.getChangingConfigurations();
    297 
    298         // Extract the theme attributes, if any.
    299         state.mThemeAttrs = a.extractThemeAttrs();
    300 
    301         final int N = a.getIndexCount();
    302         for (int i = 0; i < N; i++) {
    303             final int attr = a.getIndex(i);
    304             switch (attr) {
    305                 case R.styleable.LayerDrawable_opacity:
    306                     state.mOpacityOverride = a.getInt(attr, state.mOpacityOverride);
    307                     break;
    308                 case R.styleable.LayerDrawable_paddingTop:
    309                     state.mPaddingTop = a.getDimensionPixelOffset(attr, state.mPaddingTop);
    310                     break;
    311                 case R.styleable.LayerDrawable_paddingBottom:
    312                     state.mPaddingBottom = a.getDimensionPixelOffset(attr, state.mPaddingBottom);
    313                     break;
    314                 case R.styleable.LayerDrawable_paddingLeft:
    315                     state.mPaddingLeft = a.getDimensionPixelOffset(attr, state.mPaddingLeft);
    316                     break;
    317                 case R.styleable.LayerDrawable_paddingRight:
    318                     state.mPaddingRight = a.getDimensionPixelOffset(attr, state.mPaddingRight);
    319                     break;
    320                 case R.styleable.LayerDrawable_paddingStart:
    321                     state.mPaddingStart = a.getDimensionPixelOffset(attr, state.mPaddingStart);
    322                     break;
    323                 case R.styleable.LayerDrawable_paddingEnd:
    324                     state.mPaddingEnd = a.getDimensionPixelOffset(attr, state.mPaddingEnd);
    325                     break;
    326                 case R.styleable.LayerDrawable_autoMirrored:
    327                     state.mAutoMirrored = a.getBoolean(attr, state.mAutoMirrored);
    328                     break;
    329                 case R.styleable.LayerDrawable_paddingMode:
    330                     state.mPaddingMode = a.getInteger(attr, state.mPaddingMode);
    331                     break;
    332             }
    333         }
    334     }
    335 
    336     private void updateLayerFromTypedArray(@NonNull ChildDrawable layer, @NonNull TypedArray a) {
    337         final LayerState state = mLayerState;
    338 
    339         // Account for any configuration changes.
    340         state.mChildrenChangingConfigurations |= a.getChangingConfigurations();
    341 
    342         // Extract the theme attributes, if any.
    343         layer.mThemeAttrs = a.extractThemeAttrs();
    344 
    345         final int N = a.getIndexCount();
    346         for (int i = 0; i < N; i++) {
    347             final int attr = a.getIndex(i);
    348             switch (attr) {
    349                 case R.styleable.LayerDrawableItem_left:
    350                     layer.mInsetL = a.getDimensionPixelOffset(attr, layer.mInsetL);
    351                     break;
    352                 case R.styleable.LayerDrawableItem_top:
    353                     layer.mInsetT = a.getDimensionPixelOffset(attr, layer.mInsetT);
    354                     break;
    355                 case R.styleable.LayerDrawableItem_right:
    356                     layer.mInsetR = a.getDimensionPixelOffset(attr, layer.mInsetR);
    357                     break;
    358                 case R.styleable.LayerDrawableItem_bottom:
    359                     layer.mInsetB = a.getDimensionPixelOffset(attr, layer.mInsetB);
    360                     break;
    361                 case R.styleable.LayerDrawableItem_start:
    362                     layer.mInsetS = a.getDimensionPixelOffset(attr, layer.mInsetS);
    363                     break;
    364                 case R.styleable.LayerDrawableItem_end:
    365                     layer.mInsetE = a.getDimensionPixelOffset(attr, layer.mInsetE);
    366                     break;
    367                 case R.styleable.LayerDrawableItem_width:
    368                     layer.mWidth = a.getDimensionPixelSize(attr, layer.mWidth);
    369                     break;
    370                 case R.styleable.LayerDrawableItem_height:
    371                     layer.mHeight = a.getDimensionPixelSize(attr, layer.mHeight);
    372                     break;
    373                 case R.styleable.LayerDrawableItem_gravity:
    374                     layer.mGravity = a.getInteger(attr, layer.mGravity);
    375                     break;
    376                 case R.styleable.LayerDrawableItem_id:
    377                     layer.mId = a.getResourceId(attr, layer.mId);
    378                     break;
    379             }
    380         }
    381 
    382         final Drawable dr = a.getDrawable(R.styleable.LayerDrawableItem_drawable);
    383         if (dr != null) {
    384             if (layer.mDrawable != null) {
    385                 // It's possible that a drawable was already set, in which case
    386                 // we should clear the callback. We may have also integrated the
    387                 // drawable's changing configurations, but we don't have enough
    388                 // information to revert that change.
    389                 layer.mDrawable.setCallback(null);
    390             }
    391 
    392             // Take ownership of the new drawable.
    393             layer.mDrawable = dr;
    394             layer.mDrawable.setCallback(this);
    395             state.mChildrenChangingConfigurations |=
    396                     layer.mDrawable.getChangingConfigurations();
    397         }
    398     }
    399 
    400     @Override
    401     public boolean canApplyTheme() {
    402         return mLayerState.canApplyTheme() || super.canApplyTheme();
    403     }
    404 
    405     /**
    406      * @hide
    407      */
    408     @Override
    409     public boolean isProjected() {
    410         if (super.isProjected()) {
    411             return true;
    412         }
    413 
    414         final ChildDrawable[] layers = mLayerState.mChildren;
    415         final int N = mLayerState.mNumChildren;
    416         for (int i = 0; i < N; i++) {
    417             if (layers[i].mDrawable.isProjected()) {
    418                 return true;
    419             }
    420         }
    421 
    422         return false;
    423     }
    424 
    425     /**
    426      * Adds a new layer at the end of list of layers and returns its index.
    427      *
    428      * @param layer The layer to add.
    429      * @return The index of the layer.
    430      */
    431     int addLayer(@NonNull ChildDrawable layer) {
    432         final LayerState st = mLayerState;
    433         final int N = st.mChildren != null ? st.mChildren.length : 0;
    434         final int i = st.mNumChildren;
    435         if (i >= N) {
    436             final ChildDrawable[] nu = new ChildDrawable[N + 10];
    437             if (i > 0) {
    438                 System.arraycopy(st.mChildren, 0, nu, 0, i);
    439             }
    440 
    441             st.mChildren = nu;
    442         }
    443 
    444         st.mChildren[i] = layer;
    445         st.mNumChildren++;
    446         st.invalidateCache();
    447         return i;
    448     }
    449 
    450     /**
    451      * Add a new layer to this drawable. The new layer is identified by an id.
    452      *
    453      * @param dr The drawable to add as a layer.
    454      * @param themeAttrs Theme attributes extracted from the layer.
    455      * @param id The id of the new layer.
    456      * @param left The left padding of the new layer.
    457      * @param top The top padding of the new layer.
    458      * @param right The right padding of the new layer.
    459      * @param bottom The bottom padding of the new layer.
    460      */
    461     ChildDrawable addLayer(Drawable dr, int[] themeAttrs, int id,
    462             int left, int top, int right, int bottom) {
    463         final ChildDrawable childDrawable = createLayer(dr);
    464         childDrawable.mId = id;
    465         childDrawable.mThemeAttrs = themeAttrs;
    466         childDrawable.mDrawable.setAutoMirrored(isAutoMirrored());
    467         childDrawable.mInsetL = left;
    468         childDrawable.mInsetT = top;
    469         childDrawable.mInsetR = right;
    470         childDrawable.mInsetB = bottom;
    471 
    472         addLayer(childDrawable);
    473 
    474         mLayerState.mChildrenChangingConfigurations |= dr.getChangingConfigurations();
    475         dr.setCallback(this);
    476 
    477         return childDrawable;
    478     }
    479 
    480     private ChildDrawable createLayer(Drawable dr) {
    481         final ChildDrawable layer = new ChildDrawable(mLayerState.mDensity);
    482         layer.mDrawable = dr;
    483         return layer;
    484     }
    485 
    486     /**
    487      * Adds a new layer containing the specified {@code drawable} to the end of
    488      * the layer list and returns its index.
    489      *
    490      * @param dr The drawable to add as a new layer.
    491      * @return The index of the new layer.
    492      */
    493     public int addLayer(Drawable dr) {
    494         final ChildDrawable layer = createLayer(dr);
    495         final int index = addLayer(layer);
    496         ensurePadding();
    497         refreshChildPadding(index, layer);
    498         return index;
    499     }
    500 
    501     /**
    502      * Looks for a layer with the given ID and returns its {@link Drawable}.
    503      * <p>
    504      * If multiple layers are found for the given ID, returns the
    505      * {@link Drawable} for the matching layer at the highest index.
    506      *
    507      * @param id The layer ID to search for.
    508      * @return The {@link Drawable} for the highest-indexed layer that has the
    509      *         given ID, or null if not found.
    510      */
    511     public Drawable findDrawableByLayerId(int id) {
    512         final ChildDrawable[] layers = mLayerState.mChildren;
    513         for (int i = mLayerState.mNumChildren - 1; i >= 0; i--) {
    514             if (layers[i].mId == id) {
    515                 return layers[i].mDrawable;
    516             }
    517         }
    518 
    519         return null;
    520     }
    521 
    522     /**
    523      * Sets the ID of a layer.
    524      *
    525      * @param index The index of the layer to modify, must be in the range
    526      *              {@code 0...getNumberOfLayers()-1}.
    527      * @param id The id to assign to the layer.
    528      *
    529      * @see #getId(int)
    530      * @attr ref android.R.styleable#LayerDrawableItem_id
    531      */
    532     public void setId(int index, int id) {
    533         mLayerState.mChildren[index].mId = id;
    534     }
    535 
    536     /**
    537      * Returns the ID of the specified layer.
    538      *
    539      * @param index The index of the layer, must be in the range
    540      *              {@code 0...getNumberOfLayers()-1}.
    541      * @return The id of the layer or {@link android.view.View#NO_ID} if the
    542      *         layer has no id.
    543      *
    544      * @see #setId(int, int)
    545      * @attr ref android.R.styleable#LayerDrawableItem_id
    546      */
    547     public int getId(int index) {
    548         if (index >= mLayerState.mNumChildren) {
    549             throw new IndexOutOfBoundsException();
    550         }
    551         return mLayerState.mChildren[index].mId;
    552     }
    553 
    554     /**
    555      * Returns the number of layers contained within this layer drawable.
    556      *
    557      * @return The number of layers.
    558      */
    559     public int getNumberOfLayers() {
    560         return mLayerState.mNumChildren;
    561     }
    562 
    563     /**
    564      * Replaces the {@link Drawable} for the layer with the given id.
    565      *
    566      * @param id The layer ID to search for.
    567      * @param drawable The replacement {@link Drawable}.
    568      * @return Whether the {@link Drawable} was replaced (could return false if
    569      *         the id was not found).
    570      */
    571     public boolean setDrawableByLayerId(int id, Drawable drawable) {
    572         final int index = findIndexByLayerId(id);
    573         if (index < 0) {
    574             return false;
    575         }
    576 
    577         setDrawable(index, drawable);
    578         return true;
    579     }
    580 
    581     /**
    582      * Returns the layer with the specified {@code id}.
    583      * <p>
    584      * If multiple layers have the same ID, returns the layer with the lowest
    585      * index.
    586      *
    587      * @param id The ID of the layer to return.
    588      * @return The index of the layer with the specified ID.
    589      */
    590     public int findIndexByLayerId(int id) {
    591         final ChildDrawable[] layers = mLayerState.mChildren;
    592         final int N = mLayerState.mNumChildren;
    593         for (int i = 0; i < N; i++) {
    594             final ChildDrawable childDrawable = layers[i];
    595             if (childDrawable.mId == id) {
    596                 return i;
    597             }
    598         }
    599 
    600         return -1;
    601     }
    602 
    603     /**
    604      * Sets the drawable for the layer at the specified index.
    605      *
    606      * @param index The index of the layer to modify, must be in the range
    607      *              {@code 0...getNumberOfLayers()-1}.
    608      * @param drawable The drawable to set for the layer.
    609      *
    610      * @see #getDrawable(int)
    611      * @attr ref android.R.styleable#LayerDrawableItem_drawable
    612      */
    613     public void setDrawable(int index, Drawable drawable) {
    614         if (index >= mLayerState.mNumChildren) {
    615             throw new IndexOutOfBoundsException();
    616         }
    617 
    618         final ChildDrawable[] layers = mLayerState.mChildren;
    619         final ChildDrawable childDrawable = layers[index];
    620         if (childDrawable.mDrawable != null) {
    621             if (drawable != null) {
    622                 final Rect bounds = childDrawable.mDrawable.getBounds();
    623                 drawable.setBounds(bounds);
    624             }
    625 
    626             childDrawable.mDrawable.setCallback(null);
    627         }
    628 
    629         if (drawable != null) {
    630             drawable.setCallback(this);
    631         }
    632 
    633         childDrawable.mDrawable = drawable;
    634         mLayerState.invalidateCache();
    635 
    636         refreshChildPadding(index, childDrawable);
    637     }
    638 
    639     /**
    640      * Returns the drawable for the layer at the specified index.
    641      *
    642      * @param index The index of the layer, must be in the range
    643      *              {@code 0...getNumberOfLayers()-1}.
    644      * @return The {@link Drawable} at the specified layer index.
    645      *
    646      * @see #setDrawable(int, Drawable)
    647      * @attr ref android.R.styleable#LayerDrawableItem_drawable
    648      */
    649     public Drawable getDrawable(int index) {
    650         if (index >= mLayerState.mNumChildren) {
    651             throw new IndexOutOfBoundsException();
    652         }
    653         return mLayerState.mChildren[index].mDrawable;
    654     }
    655 
    656     /**
    657      * Sets an explicit size for the specified layer.
    658      * <p>
    659      * <strong>Note:</strong> Setting an explicit layer size changes the
    660      * default layer gravity behavior. See {@link #setLayerGravity(int, int)}
    661      * for more information.
    662      *
    663      * @param index the index of the layer to adjust
    664      * @param w width in pixels, or -1 to use the intrinsic width
    665      * @param h height in pixels, or -1 to use the intrinsic height
    666      * @see #getLayerWidth(int)
    667      * @see #getLayerHeight(int)
    668      * @attr ref android.R.styleable#LayerDrawableItem_width
    669      * @attr ref android.R.styleable#LayerDrawableItem_height
    670      */
    671     public void setLayerSize(int index, int w, int h) {
    672         final ChildDrawable childDrawable = mLayerState.mChildren[index];
    673         childDrawable.mWidth = w;
    674         childDrawable.mHeight = h;
    675     }
    676 
    677     /**
    678      * @param index the index of the layer to adjust
    679      * @param w width in pixels, or -1 to use the intrinsic width
    680      * @attr ref android.R.styleable#LayerDrawableItem_width
    681      */
    682     public void setLayerWidth(int index, int w) {
    683         final ChildDrawable childDrawable = mLayerState.mChildren[index];
    684         childDrawable.mWidth = w;
    685     }
    686 
    687     /**
    688      * @param index the index of the drawable to adjust
    689      * @return the explicit width of the layer, or -1 if not specified
    690      * @see #setLayerSize(int, int, int)
    691      * @attr ref android.R.styleable#LayerDrawableItem_width
    692      */
    693     public int getLayerWidth(int index) {
    694         final ChildDrawable childDrawable = mLayerState.mChildren[index];
    695         return childDrawable.mWidth;
    696     }
    697 
    698     /**
    699      * @param index the index of the layer to adjust
    700      * @param h height in pixels, or -1 to use the intrinsic height
    701      * @attr ref android.R.styleable#LayerDrawableItem_height
    702      */
    703     public void setLayerHeight(int index, int h) {
    704         final ChildDrawable childDrawable = mLayerState.mChildren[index];
    705         childDrawable.mHeight = h;
    706     }
    707 
    708     /**
    709      * @param index the index of the drawable to adjust
    710      * @return the explicit height of the layer, or -1 if not specified
    711      * @see #setLayerSize(int, int, int)
    712      * @attr ref android.R.styleable#LayerDrawableItem_height
    713      */
    714     public int getLayerHeight(int index) {
    715         final ChildDrawable childDrawable = mLayerState.mChildren[index];
    716         return childDrawable.mHeight;
    717     }
    718 
    719     /**
    720      * Sets the gravity used to position or stretch the specified layer within
    721      * its container. Gravity is applied after any layer insets (see
    722      * {@link #setLayerInset(int, int, int, int, int)}) or padding (see
    723      * {@link #setPaddingMode(int)}).
    724      * <p>
    725      * If gravity is specified as {@link Gravity#NO_GRAVITY}, the default
    726      * behavior depends on whether an explicit width or height has been set
    727      * (see {@link #setLayerSize(int, int, int)}), If a dimension is not set,
    728      * gravity in that direction defaults to {@link Gravity#FILL_HORIZONTAL} or
    729      * {@link Gravity#FILL_VERTICAL}; otherwise, gravity in that direction
    730      * defaults to {@link Gravity#LEFT} or {@link Gravity#TOP}.
    731      *
    732      * @param index the index of the drawable to adjust
    733      * @param gravity the gravity to set for the layer
    734      *
    735      * @see #getLayerGravity(int)
    736      * @attr ref android.R.styleable#LayerDrawableItem_gravity
    737      */
    738     public void setLayerGravity(int index, int gravity) {
    739         final ChildDrawable childDrawable = mLayerState.mChildren[index];
    740         childDrawable.mGravity = gravity;
    741     }
    742 
    743     /**
    744      * @param index the index of the layer
    745      * @return the gravity used to position or stretch the specified layer
    746      *         within its container
    747      *
    748      * @see #setLayerGravity(int, int)
    749      * @attr ref android.R.styleable#LayerDrawableItem_gravity
    750      */
    751     public int getLayerGravity(int index) {
    752         final ChildDrawable childDrawable = mLayerState.mChildren[index];
    753         return childDrawable.mGravity;
    754     }
    755 
    756     /**
    757      * Specifies the insets in pixels for the drawable at the specified index.
    758      *
    759      * @param index the index of the drawable to adjust
    760      * @param l number of pixels to add to the left bound
    761      * @param t number of pixels to add to the top bound
    762      * @param r number of pixels to subtract from the right bound
    763      * @param b number of pixels to subtract from the bottom bound
    764      *
    765      * @attr ref android.R.styleable#LayerDrawableItem_left
    766      * @attr ref android.R.styleable#LayerDrawableItem_top
    767      * @attr ref android.R.styleable#LayerDrawableItem_right
    768      * @attr ref android.R.styleable#LayerDrawableItem_bottom
    769      */
    770     public void setLayerInset(int index, int l, int t, int r, int b) {
    771         setLayerInsetInternal(index, l, t, r, b, INSET_UNDEFINED, INSET_UNDEFINED);
    772     }
    773 
    774     /**
    775      * Specifies the relative insets in pixels for the drawable at the
    776      * specified index.
    777      *
    778      * @param index the index of the layer to adjust
    779      * @param s number of pixels to inset from the start bound
    780      * @param t number of pixels to inset from the top bound
    781      * @param e number of pixels to inset from the end bound
    782      * @param b number of pixels to inset from the bottom bound
    783      *
    784      * @attr ref android.R.styleable#LayerDrawableItem_start
    785      * @attr ref android.R.styleable#LayerDrawableItem_top
    786      * @attr ref android.R.styleable#LayerDrawableItem_end
    787      * @attr ref android.R.styleable#LayerDrawableItem_bottom
    788      */
    789     public void setLayerInsetRelative(int index, int s, int t, int e, int b) {
    790         setLayerInsetInternal(index, 0, t, 0, b, s, e);
    791     }
    792 
    793     /**
    794      * @param index the index of the layer to adjust
    795      * @param l number of pixels to inset from the left bound
    796      * @attr ref android.R.styleable#LayerDrawableItem_left
    797      */
    798     public void setLayerInsetLeft(int index, int l) {
    799         final ChildDrawable childDrawable = mLayerState.mChildren[index];
    800         childDrawable.mInsetL = l;
    801     }
    802 
    803     /**
    804      * @param index the index of the layer
    805      * @return number of pixels to inset from the left bound
    806      * @attr ref android.R.styleable#LayerDrawableItem_left
    807      */
    808     public int getLayerInsetLeft(int index) {
    809         final ChildDrawable childDrawable = mLayerState.mChildren[index];
    810         return childDrawable.mInsetL;
    811     }
    812 
    813     /**
    814      * @param index the index of the layer to adjust
    815      * @param r number of pixels to inset from the right bound
    816      * @attr ref android.R.styleable#LayerDrawableItem_right
    817      */
    818     public void setLayerInsetRight(int index, int r) {
    819         final ChildDrawable childDrawable = mLayerState.mChildren[index];
    820         childDrawable.mInsetR = r;
    821     }
    822 
    823     /**
    824      * @param index the index of the layer
    825      * @return number of pixels to inset from the right bound
    826      * @attr ref android.R.styleable#LayerDrawableItem_right
    827      */
    828     public int getLayerInsetRight(int index) {
    829         final ChildDrawable childDrawable = mLayerState.mChildren[index];
    830         return childDrawable.mInsetR;
    831     }
    832 
    833     /**
    834      * @param index the index of the layer to adjust
    835      * @param t number of pixels to inset from the top bound
    836      * @attr ref android.R.styleable#LayerDrawableItem_top
    837      */
    838     public void setLayerInsetTop(int index, int t) {
    839         final ChildDrawable childDrawable = mLayerState.mChildren[index];
    840         childDrawable.mInsetT = t;
    841     }
    842 
    843     /**
    844      * @param index the index of the layer
    845      * @return number of pixels to inset from the top bound
    846      * @attr ref android.R.styleable#LayerDrawableItem_top
    847      */
    848     public int getLayerInsetTop(int index) {
    849         final ChildDrawable childDrawable = mLayerState.mChildren[index];
    850         return childDrawable.mInsetT;
    851     }
    852 
    853     /**
    854      * @param index the index of the layer to adjust
    855      * @param b number of pixels to inset from the bottom bound
    856      * @attr ref android.R.styleable#LayerDrawableItem_bottom
    857      */
    858     public void setLayerInsetBottom(int index, int b) {
    859         final ChildDrawable childDrawable = mLayerState.mChildren[index];
    860         childDrawable.mInsetB = b;
    861     }
    862 
    863     /**
    864      * @param index the index of the layer
    865      * @return number of pixels to inset from the bottom bound
    866      * @attr ref android.R.styleable#LayerDrawableItem_bottom
    867      */
    868     public int getLayerInsetBottom(int index) {
    869         final ChildDrawable childDrawable = mLayerState.mChildren[index];
    870         return childDrawable.mInsetB;
    871     }
    872 
    873     /**
    874      * @param index the index of the layer to adjust
    875      * @param s number of pixels to inset from the start bound
    876      * @attr ref android.R.styleable#LayerDrawableItem_start
    877      */
    878     public void setLayerInsetStart(int index, int s) {
    879         final ChildDrawable childDrawable = mLayerState.mChildren[index];
    880         childDrawable.mInsetS = s;
    881     }
    882 
    883     /**
    884      * @param index the index of the layer
    885      * @return the number of pixels to inset from the start bound, or
    886      *         {@link #INSET_UNDEFINED} if not specified
    887      * @attr ref android.R.styleable#LayerDrawableItem_start
    888      */
    889     public int getLayerInsetStart(int index) {
    890         final ChildDrawable childDrawable = mLayerState.mChildren[index];
    891         return childDrawable.mInsetS;
    892     }
    893 
    894     /**
    895      * @param index the index of the layer to adjust
    896      * @param e number of pixels to inset from the end bound, or
    897      *         {@link #INSET_UNDEFINED} if not specified
    898      * @attr ref android.R.styleable#LayerDrawableItem_end
    899      */
    900     public void setLayerInsetEnd(int index, int e) {
    901         final ChildDrawable childDrawable = mLayerState.mChildren[index];
    902         childDrawable.mInsetE = e;
    903     }
    904 
    905     /**
    906      * @param index the index of the layer
    907      * @return number of pixels to inset from the end bound
    908      * @attr ref android.R.styleable#LayerDrawableItem_end
    909      */
    910     public int getLayerInsetEnd(int index) {
    911         final ChildDrawable childDrawable = mLayerState.mChildren[index];
    912         return childDrawable.mInsetE;
    913     }
    914 
    915     private void setLayerInsetInternal(int index, int l, int t, int r, int b, int s, int e) {
    916         final ChildDrawable childDrawable = mLayerState.mChildren[index];
    917         childDrawable.mInsetL = l;
    918         childDrawable.mInsetT = t;
    919         childDrawable.mInsetR = r;
    920         childDrawable.mInsetB = b;
    921         childDrawable.mInsetS = s;
    922         childDrawable.mInsetE = e;
    923     }
    924 
    925     /**
    926      * Specifies how layer padding should affect the bounds of subsequent
    927      * layers. The default value is {@link #PADDING_MODE_NEST}.
    928      *
    929      * @param mode padding mode, one of:
    930      *            <ul>
    931      *            <li>{@link #PADDING_MODE_NEST} to nest each layer inside the
    932      *            padding of the previous layer
    933      *            <li>{@link #PADDING_MODE_STACK} to stack each layer directly
    934      *            atop the previous layer
    935      *            </ul>
    936      *
    937      * @see #getPaddingMode()
    938      * @attr ref android.R.styleable#LayerDrawable_paddingMode
    939      */
    940     public void setPaddingMode(int mode) {
    941         if (mLayerState.mPaddingMode != mode) {
    942             mLayerState.mPaddingMode = mode;
    943         }
    944     }
    945 
    946     /**
    947      * @return the current padding mode
    948      *
    949      * @see #setPaddingMode(int)
    950      * @attr ref android.R.styleable#LayerDrawable_paddingMode
    951      */
    952     public int getPaddingMode() {
    953       return mLayerState.mPaddingMode;
    954     }
    955 
    956     /**
    957      * Temporarily suspends child invalidation.
    958      *
    959      * @see #resumeChildInvalidation()
    960      */
    961     private void suspendChildInvalidation() {
    962         mSuspendChildInvalidation = true;
    963     }
    964 
    965     /**
    966      * Resumes child invalidation after suspension, immediately performing an
    967      * invalidation if one was requested by a child during suspension.
    968      *
    969      * @see #suspendChildInvalidation()
    970      */
    971     private void resumeChildInvalidation() {
    972         mSuspendChildInvalidation = false;
    973 
    974         if (mChildRequestedInvalidation) {
    975             mChildRequestedInvalidation = false;
    976             invalidateSelf();
    977         }
    978     }
    979 
    980     @Override
    981     public void invalidateDrawable(@NonNull Drawable who) {
    982         if (mSuspendChildInvalidation) {
    983             mChildRequestedInvalidation = true;
    984         } else {
    985             // This may have been called as the result of a tint changing, in
    986             // which case we may need to refresh the cached statefulness or
    987             // opacity.
    988             mLayerState.invalidateCache();
    989 
    990             invalidateSelf();
    991         }
    992     }
    993 
    994     @Override
    995     public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) {
    996         scheduleSelf(what, when);
    997     }
    998 
    999     @Override
   1000     public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) {
   1001         unscheduleSelf(what);
   1002     }
   1003 
   1004     @Override
   1005     public void draw(Canvas canvas) {
   1006         final ChildDrawable[] array = mLayerState.mChildren;
   1007         final int N = mLayerState.mNumChildren;
   1008         for (int i = 0; i < N; i++) {
   1009             final Drawable dr = array[i].mDrawable;
   1010             if (dr != null) {
   1011                 dr.draw(canvas);
   1012             }
   1013         }
   1014     }
   1015 
   1016     @Override
   1017     public @Config int getChangingConfigurations() {
   1018         return super.getChangingConfigurations() | mLayerState.getChangingConfigurations();
   1019     }
   1020 
   1021     @Override
   1022     public boolean getPadding(Rect padding) {
   1023         final LayerState layerState = mLayerState;
   1024         if (layerState.mPaddingMode == PADDING_MODE_NEST) {
   1025             computeNestedPadding(padding);
   1026         } else {
   1027             computeStackedPadding(padding);
   1028         }
   1029 
   1030         final int paddingT = layerState.mPaddingTop;
   1031         final int paddingB = layerState.mPaddingBottom;
   1032 
   1033         // Resolve padding for RTL. Relative padding overrides absolute
   1034         // padding.
   1035         final boolean isLayoutRtl = getLayoutDirection() == LayoutDirection.RTL;
   1036         final int paddingRtlL = isLayoutRtl ? layerState.mPaddingEnd : layerState.mPaddingStart;
   1037         final int paddingRtlR = isLayoutRtl ? layerState.mPaddingStart : layerState.mPaddingEnd;
   1038         final int paddingL = paddingRtlL >= 0 ? paddingRtlL : layerState.mPaddingLeft;
   1039         final int paddingR = paddingRtlR >= 0 ? paddingRtlR : layerState.mPaddingRight;
   1040 
   1041         // If padding was explicitly specified (e.g. not -1) then override the
   1042         // computed padding in that dimension.
   1043         if (paddingL >= 0) {
   1044             padding.left = paddingL;
   1045         }
   1046 
   1047         if (paddingT >= 0) {
   1048             padding.top = paddingT;
   1049         }
   1050 
   1051         if (paddingR >= 0) {
   1052             padding.right = paddingR;
   1053         }
   1054 
   1055         if (paddingB >= 0) {
   1056             padding.bottom = paddingB;
   1057         }
   1058 
   1059         return padding.left != 0 || padding.top != 0 || padding.right != 0 || padding.bottom != 0;
   1060     }
   1061 
   1062     /**
   1063      * Sets the absolute padding.
   1064      * <p>
   1065      * If padding in a dimension is specified as {@code -1}, the resolved
   1066      * padding will use the value computed according to the padding mode (see
   1067      * {@link #setPaddingMode(int)}).
   1068      * <p>
   1069      * Calling this method clears any relative padding values previously set
   1070      * using {@link #setPaddingRelative(int, int, int, int)}.
   1071      *
   1072      * @param left the left padding in pixels, or -1 to use computed padding
   1073      * @param top the top padding in pixels, or -1 to use computed padding
   1074      * @param right the right padding in pixels, or -1 to use computed padding
   1075      * @param bottom the bottom padding in pixels, or -1 to use computed
   1076      *               padding
   1077      * @attr ref android.R.styleable#LayerDrawable_paddingLeft
   1078      * @attr ref android.R.styleable#LayerDrawable_paddingTop
   1079      * @attr ref android.R.styleable#LayerDrawable_paddingRight
   1080      * @attr ref android.R.styleable#LayerDrawable_paddingBottom
   1081      * @see #setPaddingRelative(int, int, int, int)
   1082      */
   1083     public void setPadding(int left, int top, int right, int bottom) {
   1084         final LayerState layerState = mLayerState;
   1085         layerState.mPaddingLeft = left;
   1086         layerState.mPaddingTop = top;
   1087         layerState.mPaddingRight = right;
   1088         layerState.mPaddingBottom = bottom;
   1089 
   1090         // Clear relative padding values.
   1091         layerState.mPaddingStart = -1;
   1092         layerState.mPaddingEnd = -1;
   1093     }
   1094 
   1095     /**
   1096      * Sets the relative padding.
   1097      * <p>
   1098      * If padding in a dimension is specified as {@code -1}, the resolved
   1099      * padding will use the value computed according to the padding mode (see
   1100      * {@link #setPaddingMode(int)}).
   1101      * <p>
   1102      * Calling this method clears any absolute padding values previously set
   1103      * using {@link #setPadding(int, int, int, int)}.
   1104      *
   1105      * @param start the start padding in pixels, or -1 to use computed padding
   1106      * @param top the top padding in pixels, or -1 to use computed padding
   1107      * @param end the end padding in pixels, or -1 to use computed padding
   1108      * @param bottom the bottom padding in pixels, or -1 to use computed
   1109      *               padding
   1110      * @attr ref android.R.styleable#LayerDrawable_paddingStart
   1111      * @attr ref android.R.styleable#LayerDrawable_paddingTop
   1112      * @attr ref android.R.styleable#LayerDrawable_paddingEnd
   1113      * @attr ref android.R.styleable#LayerDrawable_paddingBottom
   1114      * @see #setPadding(int, int, int, int)
   1115      */
   1116     public void setPaddingRelative(int start, int top, int end, int bottom) {
   1117         final LayerState layerState = mLayerState;
   1118         layerState.mPaddingStart = start;
   1119         layerState.mPaddingTop = top;
   1120         layerState.mPaddingEnd = end;
   1121         layerState.mPaddingBottom = bottom;
   1122 
   1123         // Clear absolute padding values.
   1124         layerState.mPaddingLeft = -1;
   1125         layerState.mPaddingRight = -1;
   1126     }
   1127 
   1128     /**
   1129      * Returns the left padding in pixels.
   1130      * <p>
   1131      * A return value of {@code -1} means there is no explicit padding set for
   1132      * this dimension. As a result, the value for this dimension returned by
   1133      * {@link #getPadding(Rect)} will be computed from the child layers
   1134      * according to the padding mode (see {@link #getPaddingMode()}.
   1135      *
   1136      * @return the left padding in pixels, or -1 if not explicitly specified
   1137      * @see #setPadding(int, int, int, int)
   1138      * @see #getPadding(Rect)
   1139      */
   1140     public int getLeftPadding() {
   1141         return mLayerState.mPaddingLeft;
   1142     }
   1143 
   1144     /**
   1145      * Returns the right padding in pixels.
   1146      * <p>
   1147      * A return value of {@code -1} means there is no explicit padding set for
   1148      * this dimension. As a result, the value for this dimension returned by
   1149      * {@link #getPadding(Rect)} will be computed from the child layers
   1150      * according to the padding mode (see {@link #getPaddingMode()}.
   1151      *
   1152      * @return the right padding in pixels, or -1 if not explicitly specified
   1153      * @see #setPadding(int, int, int, int)
   1154      * @see #getPadding(Rect)
   1155      */
   1156     public int getRightPadding() {
   1157         return mLayerState.mPaddingRight;
   1158     }
   1159 
   1160     /**
   1161      * Returns the start padding in pixels.
   1162      * <p>
   1163      * A return value of {@code -1} means there is no explicit padding set for
   1164      * this dimension. As a result, the value for this dimension returned by
   1165      * {@link #getPadding(Rect)} will be computed from the child layers
   1166      * according to the padding mode (see {@link #getPaddingMode()}.
   1167      *
   1168      * @return the start padding in pixels, or -1 if not explicitly specified
   1169      * @see #setPaddingRelative(int, int, int, int)
   1170      * @see #getPadding(Rect)
   1171      */
   1172     public int getStartPadding() {
   1173         return mLayerState.mPaddingStart;
   1174     }
   1175 
   1176     /**
   1177      * Returns the end padding in pixels.
   1178      * <p>
   1179      * A return value of {@code -1} means there is no explicit padding set for
   1180      * this dimension. As a result, the value for this dimension returned by
   1181      * {@link #getPadding(Rect)} will be computed from the child layers
   1182      * according to the padding mode (see {@link #getPaddingMode()}.
   1183      *
   1184      * @return the end padding in pixels, or -1 if not explicitly specified
   1185      * @see #setPaddingRelative(int, int, int, int)
   1186      * @see #getPadding(Rect)
   1187      */
   1188     public int getEndPadding() {
   1189         return mLayerState.mPaddingEnd;
   1190     }
   1191 
   1192     /**
   1193      * Returns the top padding in pixels.
   1194      * <p>
   1195      * A return value of {@code -1} means there is no explicit padding set for
   1196      * this dimension. As a result, the value for this dimension returned by
   1197      * {@link #getPadding(Rect)} will be computed from the child layers
   1198      * according to the padding mode (see {@link #getPaddingMode()}.
   1199      *
   1200      * @return the top padding in pixels, or -1 if not explicitly specified
   1201      * @see #setPadding(int, int, int, int)
   1202      * @see #setPaddingRelative(int, int, int, int)
   1203      * @see #getPadding(Rect)
   1204      */
   1205     public int getTopPadding() {
   1206         return mLayerState.mPaddingTop;
   1207     }
   1208 
   1209     /**
   1210      * Returns the bottom padding in pixels.
   1211      * <p>
   1212      * A return value of {@code -1} means there is no explicit padding set for
   1213      * this dimension. As a result, the value for this dimension returned by
   1214      * {@link #getPadding(Rect)} will be computed from the child layers
   1215      * according to the padding mode (see {@link #getPaddingMode()}.
   1216      *
   1217      * @return the bottom padding in pixels, or -1 if not explicitly specified
   1218      * @see #setPadding(int, int, int, int)
   1219      * @see #setPaddingRelative(int, int, int, int)
   1220      * @see #getPadding(Rect)
   1221      */
   1222     public int getBottomPadding() {
   1223         return mLayerState.mPaddingBottom;
   1224     }
   1225 
   1226     private void computeNestedPadding(Rect padding) {
   1227         padding.left = 0;
   1228         padding.top = 0;
   1229         padding.right = 0;
   1230         padding.bottom = 0;
   1231 
   1232         // Add all the padding.
   1233         final ChildDrawable[] array = mLayerState.mChildren;
   1234         final int N = mLayerState.mNumChildren;
   1235         for (int i = 0; i < N; i++) {
   1236             refreshChildPadding(i, array[i]);
   1237 
   1238             padding.left += mPaddingL[i];
   1239             padding.top += mPaddingT[i];
   1240             padding.right += mPaddingR[i];
   1241             padding.bottom += mPaddingB[i];
   1242         }
   1243     }
   1244 
   1245     private void computeStackedPadding(Rect padding) {
   1246         padding.left = 0;
   1247         padding.top = 0;
   1248         padding.right = 0;
   1249         padding.bottom = 0;
   1250 
   1251         // Take the max padding.
   1252         final ChildDrawable[] array = mLayerState.mChildren;
   1253         final int N = mLayerState.mNumChildren;
   1254         for (int i = 0; i < N; i++) {
   1255             refreshChildPadding(i, array[i]);
   1256 
   1257             padding.left = Math.max(padding.left, mPaddingL[i]);
   1258             padding.top = Math.max(padding.top, mPaddingT[i]);
   1259             padding.right = Math.max(padding.right, mPaddingR[i]);
   1260             padding.bottom = Math.max(padding.bottom, mPaddingB[i]);
   1261         }
   1262     }
   1263 
   1264     /**
   1265      * Populates <code>outline</code> with the first available (non-empty) layer outline.
   1266      *
   1267      * @param outline Outline in which to place the first available layer outline
   1268      */
   1269     @Override
   1270     public void getOutline(@NonNull Outline outline) {
   1271         final ChildDrawable[] array = mLayerState.mChildren;
   1272         final int N = mLayerState.mNumChildren;
   1273         for (int i = 0; i < N; i++) {
   1274             final Drawable dr = array[i].mDrawable;
   1275             if (dr != null) {
   1276                 dr.getOutline(outline);
   1277                 if (!outline.isEmpty()) {
   1278                     return;
   1279                 }
   1280             }
   1281         }
   1282     }
   1283 
   1284     @Override
   1285     public void setHotspot(float x, float y) {
   1286         final ChildDrawable[] array = mLayerState.mChildren;
   1287         final int N = mLayerState.mNumChildren;
   1288         for (int i = 0; i < N; i++) {
   1289             final Drawable dr = array[i].mDrawable;
   1290             if (dr != null) {
   1291                 dr.setHotspot(x, y);
   1292             }
   1293         }
   1294     }
   1295 
   1296     @Override
   1297     public void setHotspotBounds(int left, int top, int right, int bottom) {
   1298         final ChildDrawable[] array = mLayerState.mChildren;
   1299         final int N = mLayerState.mNumChildren;
   1300         for (int i = 0; i < N; i++) {
   1301             final Drawable dr = array[i].mDrawable;
   1302             if (dr != null) {
   1303                 dr.setHotspotBounds(left, top, right, bottom);
   1304             }
   1305         }
   1306 
   1307         if (mHotspotBounds == null) {
   1308             mHotspotBounds = new Rect(left, top, right, bottom);
   1309         } else {
   1310             mHotspotBounds.set(left, top, right, bottom);
   1311         }
   1312     }
   1313 
   1314     @Override
   1315     public void getHotspotBounds(Rect outRect) {
   1316         if (mHotspotBounds != null) {
   1317             outRect.set(mHotspotBounds);
   1318         } else {
   1319             super.getHotspotBounds(outRect);
   1320         }
   1321     }
   1322 
   1323     @Override
   1324     public boolean setVisible(boolean visible, boolean restart) {
   1325         final boolean changed = super.setVisible(visible, restart);
   1326         final ChildDrawable[] array = mLayerState.mChildren;
   1327         final int N = mLayerState.mNumChildren;
   1328         for (int i = 0; i < N; i++) {
   1329             final Drawable dr = array[i].mDrawable;
   1330             if (dr != null) {
   1331                 dr.setVisible(visible, restart);
   1332             }
   1333         }
   1334 
   1335         return changed;
   1336     }
   1337 
   1338     @Override
   1339     public void setDither(boolean dither) {
   1340         final ChildDrawable[] array = mLayerState.mChildren;
   1341         final int N = mLayerState.mNumChildren;
   1342         for (int i = 0; i < N; i++) {
   1343             final Drawable dr = array[i].mDrawable;
   1344             if (dr != null) {
   1345                 dr.setDither(dither);
   1346             }
   1347         }
   1348     }
   1349 
   1350     @Override
   1351     public void setAlpha(int alpha) {
   1352         final ChildDrawable[] array = mLayerState.mChildren;
   1353         final int N = mLayerState.mNumChildren;
   1354         for (int i = 0; i < N; i++) {
   1355             final Drawable dr = array[i].mDrawable;
   1356             if (dr != null) {
   1357                 dr.setAlpha(alpha);
   1358             }
   1359         }
   1360     }
   1361 
   1362     @Override
   1363     public int getAlpha() {
   1364         final Drawable dr = getFirstNonNullDrawable();
   1365         if (dr != null) {
   1366             return dr.getAlpha();
   1367         } else {
   1368             return super.getAlpha();
   1369         }
   1370     }
   1371 
   1372     @Override
   1373     public void setColorFilter(ColorFilter colorFilter) {
   1374         final ChildDrawable[] array = mLayerState.mChildren;
   1375         final int N = mLayerState.mNumChildren;
   1376         for (int i = 0; i < N; i++) {
   1377             final Drawable dr = array[i].mDrawable;
   1378             if (dr != null) {
   1379                 dr.setColorFilter(colorFilter);
   1380             }
   1381         }
   1382     }
   1383 
   1384     @Override
   1385     public void setTintList(ColorStateList tint) {
   1386         final ChildDrawable[] array = mLayerState.mChildren;
   1387         final int N = mLayerState.mNumChildren;
   1388         for (int i = 0; i < N; i++) {
   1389             final Drawable dr = array[i].mDrawable;
   1390             if (dr != null) {
   1391                 dr.setTintList(tint);
   1392             }
   1393         }
   1394     }
   1395 
   1396     @Override
   1397     public void setTintMode(Mode tintMode) {
   1398         final ChildDrawable[] array = mLayerState.mChildren;
   1399         final int N = mLayerState.mNumChildren;
   1400         for (int i = 0; i < N; i++) {
   1401             final Drawable dr = array[i].mDrawable;
   1402             if (dr != null) {
   1403                 dr.setTintMode(tintMode);
   1404             }
   1405         }
   1406     }
   1407 
   1408     private Drawable getFirstNonNullDrawable() {
   1409         final ChildDrawable[] array = mLayerState.mChildren;
   1410         final int N = mLayerState.mNumChildren;
   1411         for (int i = 0; i < N; i++) {
   1412             final Drawable dr = array[i].mDrawable;
   1413             if (dr != null) {
   1414                 return dr;
   1415             }
   1416         }
   1417         return null;
   1418     }
   1419 
   1420     /**
   1421      * Sets the opacity of this drawable directly instead of collecting the
   1422      * states from the layers.
   1423      *
   1424      * @param opacity The opacity to use, or {@link PixelFormat#UNKNOWN
   1425      *            PixelFormat.UNKNOWN} for the default behavior
   1426      * @see PixelFormat#UNKNOWN
   1427      * @see PixelFormat#TRANSLUCENT
   1428      * @see PixelFormat#TRANSPARENT
   1429      * @see PixelFormat#OPAQUE
   1430      */
   1431     public void setOpacity(int opacity) {
   1432         mLayerState.mOpacityOverride = opacity;
   1433     }
   1434 
   1435     @Override
   1436     public int getOpacity() {
   1437         if (mLayerState.mOpacityOverride != PixelFormat.UNKNOWN) {
   1438             return mLayerState.mOpacityOverride;
   1439         }
   1440         return mLayerState.getOpacity();
   1441     }
   1442 
   1443     @Override
   1444     public void setAutoMirrored(boolean mirrored) {
   1445         mLayerState.mAutoMirrored = mirrored;
   1446 
   1447         final ChildDrawable[] array = mLayerState.mChildren;
   1448         final int N = mLayerState.mNumChildren;
   1449         for (int i = 0; i < N; i++) {
   1450             final Drawable dr = array[i].mDrawable;
   1451             if (dr != null) {
   1452                 dr.setAutoMirrored(mirrored);
   1453             }
   1454         }
   1455     }
   1456 
   1457     @Override
   1458     public boolean isAutoMirrored() {
   1459         return mLayerState.mAutoMirrored;
   1460     }
   1461 
   1462     @Override
   1463     public void jumpToCurrentState() {
   1464         final ChildDrawable[] array = mLayerState.mChildren;
   1465         final int N = mLayerState.mNumChildren;
   1466         for (int i = 0; i < N; i++) {
   1467             final Drawable dr = array[i].mDrawable;
   1468             if (dr != null) {
   1469                 dr.jumpToCurrentState();
   1470             }
   1471         }
   1472     }
   1473 
   1474     @Override
   1475     public boolean isStateful() {
   1476         return mLayerState.isStateful();
   1477     }
   1478 
   1479     /** @hide */
   1480     @Override
   1481     public boolean hasFocusStateSpecified() {
   1482         return mLayerState.hasFocusStateSpecified();
   1483     }
   1484 
   1485     @Override
   1486     protected boolean onStateChange(int[] state) {
   1487         boolean changed = false;
   1488 
   1489         final ChildDrawable[] array = mLayerState.mChildren;
   1490         final int N = mLayerState.mNumChildren;
   1491         for (int i = 0; i < N; i++) {
   1492             final Drawable dr = array[i].mDrawable;
   1493             if (dr != null && dr.isStateful() && dr.setState(state)) {
   1494                 refreshChildPadding(i, array[i]);
   1495                 changed = true;
   1496             }
   1497         }
   1498 
   1499         if (changed) {
   1500             updateLayerBounds(getBounds());
   1501         }
   1502 
   1503         return changed;
   1504     }
   1505 
   1506     @Override
   1507     protected boolean onLevelChange(int level) {
   1508         boolean changed = false;
   1509 
   1510         final ChildDrawable[] array = mLayerState.mChildren;
   1511         final int N = mLayerState.mNumChildren;
   1512         for (int i = 0; i < N; i++) {
   1513             final Drawable dr = array[i].mDrawable;
   1514             if (dr != null && dr.setLevel(level)) {
   1515                 refreshChildPadding(i, array[i]);
   1516                 changed = true;
   1517             }
   1518         }
   1519 
   1520         if (changed) {
   1521             updateLayerBounds(getBounds());
   1522         }
   1523 
   1524         return changed;
   1525     }
   1526 
   1527     @Override
   1528     protected void onBoundsChange(Rect bounds) {
   1529         updateLayerBounds(bounds);
   1530     }
   1531 
   1532     private void updateLayerBounds(Rect bounds) {
   1533         try {
   1534             suspendChildInvalidation();
   1535             updateLayerBoundsInternal(bounds);
   1536         } finally {
   1537             resumeChildInvalidation();
   1538         }
   1539     }
   1540 
   1541     private void updateLayerBoundsInternal(Rect bounds) {
   1542         int paddingL = 0;
   1543         int paddingT = 0;
   1544         int paddingR = 0;
   1545         int paddingB = 0;
   1546 
   1547         final Rect outRect = mTmpOutRect;
   1548         final int layoutDirection = getLayoutDirection();
   1549         final boolean isLayoutRtl = layoutDirection == LayoutDirection.RTL;
   1550         final boolean isPaddingNested = mLayerState.mPaddingMode == PADDING_MODE_NEST;
   1551         final ChildDrawable[] array = mLayerState.mChildren;
   1552 
   1553         for (int i = 0, count = mLayerState.mNumChildren; i < count; i++) {
   1554             final ChildDrawable r = array[i];
   1555             final Drawable d = r.mDrawable;
   1556             if (d == null) {
   1557                 continue;
   1558             }
   1559 
   1560             final int insetT = r.mInsetT;
   1561             final int insetB = r.mInsetB;
   1562 
   1563             // Resolve insets for RTL. Relative insets override absolute
   1564             // insets.
   1565             final int insetRtlL = isLayoutRtl ? r.mInsetE : r.mInsetS;
   1566             final int insetRtlR = isLayoutRtl ? r.mInsetS : r.mInsetE;
   1567             final int insetL = insetRtlL == INSET_UNDEFINED ? r.mInsetL : insetRtlL;
   1568             final int insetR = insetRtlR == INSET_UNDEFINED ? r.mInsetR : insetRtlR;
   1569 
   1570             // Establish containing region based on aggregate padding and
   1571             // requested insets for the current layer.
   1572             final Rect container = mTmpContainer;
   1573             container.set(bounds.left + insetL + paddingL, bounds.top + insetT + paddingT,
   1574                     bounds.right - insetR - paddingR, bounds.bottom - insetB - paddingB);
   1575 
   1576             // Compute a reasonable default gravity based on the intrinsic and
   1577             // explicit dimensions, if specified.
   1578             final int intrinsicW = d.getIntrinsicWidth();
   1579             final int intrinsicH = d.getIntrinsicHeight();
   1580             final int layerW = r.mWidth;
   1581             final int layerH = r.mHeight;
   1582             final int gravity = resolveGravity(r.mGravity, layerW, layerH, intrinsicW, intrinsicH);
   1583 
   1584             // Explicit dimensions override intrinsic dimensions.
   1585             final int resolvedW = layerW < 0 ? intrinsicW : layerW;
   1586             final int resolvedH = layerH < 0 ? intrinsicH : layerH;
   1587             Gravity.apply(gravity, resolvedW, resolvedH, container, outRect, layoutDirection);
   1588             d.setBounds(outRect);
   1589 
   1590             if (isPaddingNested) {
   1591                 paddingL += mPaddingL[i];
   1592                 paddingR += mPaddingR[i];
   1593                 paddingT += mPaddingT[i];
   1594                 paddingB += mPaddingB[i];
   1595             }
   1596         }
   1597     }
   1598 
   1599     /**
   1600      * Resolves layer gravity given explicit gravity and dimensions.
   1601      * <p>
   1602      * If the client hasn't specified a gravity but has specified an explicit
   1603      * dimension, defaults to START or TOP. Otherwise, defaults to FILL to
   1604      * preserve legacy behavior.
   1605      *
   1606      * @param gravity layer gravity
   1607      * @param width width of the layer if set, -1 otherwise
   1608      * @param height height of the layer if set, -1 otherwise
   1609      * @return the default gravity for the layer
   1610      */
   1611     private static int resolveGravity(int gravity, int width, int height,
   1612             int intrinsicWidth, int intrinsicHeight) {
   1613         if (!Gravity.isHorizontal(gravity)) {
   1614             if (width < 0) {
   1615                 gravity |= Gravity.FILL_HORIZONTAL;
   1616             } else {
   1617                 gravity |= Gravity.START;
   1618             }
   1619         }
   1620 
   1621         if (!Gravity.isVertical(gravity)) {
   1622             if (height < 0) {
   1623                 gravity |= Gravity.FILL_VERTICAL;
   1624             } else {
   1625                 gravity |= Gravity.TOP;
   1626             }
   1627         }
   1628 
   1629         // If a dimension if not specified, either implicitly or explicitly,
   1630         // force FILL for that dimension's gravity. This ensures that colors
   1631         // are handled correctly and ensures backward compatibility.
   1632         if (width < 0 && intrinsicWidth < 0) {
   1633             gravity |= Gravity.FILL_HORIZONTAL;
   1634         }
   1635 
   1636         if (height < 0 && intrinsicHeight < 0) {
   1637             gravity |= Gravity.FILL_VERTICAL;
   1638         }
   1639 
   1640         return gravity;
   1641     }
   1642 
   1643     @Override
   1644     public int getIntrinsicWidth() {
   1645         int width = -1;
   1646         int padL = 0;
   1647         int padR = 0;
   1648 
   1649         final boolean nest = mLayerState.mPaddingMode == PADDING_MODE_NEST;
   1650         final boolean isLayoutRtl = getLayoutDirection() == LayoutDirection.RTL;
   1651         final ChildDrawable[] array = mLayerState.mChildren;
   1652         final int N = mLayerState.mNumChildren;
   1653         for (int i = 0; i < N; i++) {
   1654             final ChildDrawable r = array[i];
   1655             if (r.mDrawable == null) {
   1656                 continue;
   1657             }
   1658 
   1659             // Take the resolved layout direction into account. If start / end
   1660             // padding are defined, they will be resolved (hence overriding) to
   1661             // left / right or right / left depending on the resolved layout
   1662             // direction. If start / end padding are not defined, use the
   1663             // left / right ones.
   1664             final int insetRtlL = isLayoutRtl ? r.mInsetE : r.mInsetS;
   1665             final int insetRtlR = isLayoutRtl ? r.mInsetS : r.mInsetE;
   1666             final int insetL = insetRtlL == INSET_UNDEFINED ? r.mInsetL : insetRtlL;
   1667             final int insetR = insetRtlR == INSET_UNDEFINED ? r.mInsetR : insetRtlR;
   1668 
   1669             // Don't apply padding and insets for children that don't have
   1670             // an intrinsic dimension.
   1671             final int minWidth = r.mWidth < 0 ? r.mDrawable.getIntrinsicWidth() : r.mWidth;
   1672             final int w = minWidth < 0 ? -1 : minWidth + insetL + insetR + padL + padR;
   1673             if (w > width) {
   1674                 width = w;
   1675             }
   1676 
   1677             if (nest) {
   1678                 padL += mPaddingL[i];
   1679                 padR += mPaddingR[i];
   1680             }
   1681         }
   1682 
   1683         return width;
   1684     }
   1685 
   1686     @Override
   1687     public int getIntrinsicHeight() {
   1688         int height = -1;
   1689         int padT = 0;
   1690         int padB = 0;
   1691 
   1692         final boolean nest = mLayerState.mPaddingMode == PADDING_MODE_NEST;
   1693         final ChildDrawable[] array = mLayerState.mChildren;
   1694         final int N = mLayerState.mNumChildren;
   1695         for (int i = 0; i < N; i++) {
   1696             final ChildDrawable r = array[i];
   1697             if (r.mDrawable == null) {
   1698                 continue;
   1699             }
   1700 
   1701             // Don't apply padding and insets for children that don't have
   1702             // an intrinsic dimension.
   1703             final int minHeight = r.mHeight < 0 ? r.mDrawable.getIntrinsicHeight() : r.mHeight;
   1704             final int h = minHeight < 0 ? -1 : minHeight + r.mInsetT + r.mInsetB + padT + padB;
   1705             if (h > height) {
   1706                 height = h;
   1707             }
   1708 
   1709             if (nest) {
   1710                 padT += mPaddingT[i];
   1711                 padB += mPaddingB[i];
   1712             }
   1713         }
   1714 
   1715         return height;
   1716     }
   1717 
   1718     /**
   1719      * Refreshes the cached padding values for the specified child.
   1720      *
   1721      * @return true if the child's padding has changed
   1722      */
   1723     private boolean refreshChildPadding(int i, ChildDrawable r) {
   1724         if (r.mDrawable != null) {
   1725             final Rect rect = mTmpRect;
   1726             r.mDrawable.getPadding(rect);
   1727             if (rect.left != mPaddingL[i] || rect.top != mPaddingT[i]
   1728                     || rect.right != mPaddingR[i] || rect.bottom != mPaddingB[i]) {
   1729                 mPaddingL[i] = rect.left;
   1730                 mPaddingT[i] = rect.top;
   1731                 mPaddingR[i] = rect.right;
   1732                 mPaddingB[i] = rect.bottom;
   1733                 return true;
   1734             }
   1735         }
   1736         return false;
   1737     }
   1738 
   1739     /**
   1740      * Ensures the child padding caches are large enough.
   1741      */
   1742     void ensurePadding() {
   1743         final int N = mLayerState.mNumChildren;
   1744         if (mPaddingL != null && mPaddingL.length >= N) {
   1745             return;
   1746         }
   1747 
   1748         mPaddingL = new int[N];
   1749         mPaddingT = new int[N];
   1750         mPaddingR = new int[N];
   1751         mPaddingB = new int[N];
   1752     }
   1753 
   1754     void refreshPadding() {
   1755         final int N = mLayerState.mNumChildren;
   1756         final ChildDrawable[] array = mLayerState.mChildren;
   1757         for (int i = 0; i < N; i++) {
   1758             refreshChildPadding(i, array[i]);
   1759         }
   1760     }
   1761 
   1762     @Override
   1763     public ConstantState getConstantState() {
   1764         if (mLayerState.canConstantState()) {
   1765             mLayerState.mChangingConfigurations = getChangingConfigurations();
   1766             return mLayerState;
   1767         }
   1768         return null;
   1769     }
   1770 
   1771     @Override
   1772     public Drawable mutate() {
   1773         if (!mMutated && super.mutate() == this) {
   1774             mLayerState = createConstantState(mLayerState, null);
   1775             final ChildDrawable[] array = mLayerState.mChildren;
   1776             final int N = mLayerState.mNumChildren;
   1777             for (int i = 0; i < N; i++) {
   1778                 final Drawable dr = array[i].mDrawable;
   1779                 if (dr != null) {
   1780                     dr.mutate();
   1781                 }
   1782             }
   1783             mMutated = true;
   1784         }
   1785         return this;
   1786     }
   1787 
   1788     /**
   1789      * @hide
   1790      */
   1791     public void clearMutated() {
   1792         super.clearMutated();
   1793 
   1794         final ChildDrawable[] array = mLayerState.mChildren;
   1795         final int N = mLayerState.mNumChildren;
   1796         for (int i = 0; i < N; i++) {
   1797             final Drawable dr = array[i].mDrawable;
   1798             if (dr != null) {
   1799                 dr.clearMutated();
   1800             }
   1801         }
   1802         mMutated = false;
   1803     }
   1804 
   1805     @Override
   1806     public boolean onLayoutDirectionChanged(@View.ResolvedLayoutDir int layoutDirection) {
   1807         boolean changed = false;
   1808 
   1809         final ChildDrawable[] array = mLayerState.mChildren;
   1810         final int N = mLayerState.mNumChildren;
   1811         for (int i = 0; i < N; i++) {
   1812             final Drawable dr = array[i].mDrawable;
   1813             if (dr != null) {
   1814                 changed |= dr.setLayoutDirection(layoutDirection);
   1815             }
   1816         }
   1817 
   1818         updateLayerBounds(getBounds());
   1819         return changed;
   1820     }
   1821 
   1822     static class ChildDrawable {
   1823         public Drawable mDrawable;
   1824         public int[] mThemeAttrs;
   1825         public int mDensity = DisplayMetrics.DENSITY_DEFAULT;
   1826         public int mInsetL, mInsetT, mInsetR, mInsetB;
   1827         public int mInsetS = INSET_UNDEFINED;
   1828         public int mInsetE = INSET_UNDEFINED;
   1829         public int mWidth = -1;
   1830         public int mHeight = -1;
   1831         public int mGravity = Gravity.NO_GRAVITY;
   1832         public int mId = View.NO_ID;
   1833 
   1834         ChildDrawable(int density) {
   1835             mDensity = density;
   1836         }
   1837 
   1838         ChildDrawable(@NonNull ChildDrawable orig, @NonNull LayerDrawable owner,
   1839                 @Nullable Resources res) {
   1840             final Drawable dr = orig.mDrawable;
   1841             final Drawable clone;
   1842             if (dr != null) {
   1843                 final ConstantState cs = dr.getConstantState();
   1844                 if (cs == null) {
   1845                     clone = dr;
   1846                     if (dr.getCallback() != null) {
   1847                         // This drawable already has an owner.
   1848                         Log.w(LOG_TAG, "Invalid drawable added to LayerDrawable! Drawable already "
   1849                                 + "belongs to another owner but does not expose a constant state.",
   1850                                 new RuntimeException());
   1851                     }
   1852                 } else if (res != null) {
   1853                     clone = cs.newDrawable(res);
   1854                 } else {
   1855                     clone = cs.newDrawable();
   1856                 }
   1857                 clone.setLayoutDirection(dr.getLayoutDirection());
   1858                 clone.setBounds(dr.getBounds());
   1859                 clone.setLevel(dr.getLevel());
   1860 
   1861                 // Set the callback last to prevent invalidation from
   1862                 // propagating before the constant state has been set.
   1863                 clone.setCallback(owner);
   1864             } else {
   1865                 clone = null;
   1866             }
   1867 
   1868             mDrawable = clone;
   1869             mThemeAttrs = orig.mThemeAttrs;
   1870             mInsetL = orig.mInsetL;
   1871             mInsetT = orig.mInsetT;
   1872             mInsetR = orig.mInsetR;
   1873             mInsetB = orig.mInsetB;
   1874             mInsetS = orig.mInsetS;
   1875             mInsetE = orig.mInsetE;
   1876             mWidth = orig.mWidth;
   1877             mHeight = orig.mHeight;
   1878             mGravity = orig.mGravity;
   1879             mId = orig.mId;
   1880 
   1881             mDensity = Drawable.resolveDensity(res, orig.mDensity);
   1882             if (orig.mDensity != mDensity) {
   1883                 applyDensityScaling(orig.mDensity, mDensity);
   1884             }
   1885         }
   1886 
   1887         public boolean canApplyTheme() {
   1888             return mThemeAttrs != null
   1889                     || (mDrawable != null && mDrawable.canApplyTheme());
   1890         }
   1891 
   1892         public final void setDensity(int targetDensity) {
   1893             if (mDensity != targetDensity) {
   1894                 final int sourceDensity = mDensity;
   1895                 mDensity = targetDensity;
   1896 
   1897                 applyDensityScaling(sourceDensity, targetDensity);
   1898             }
   1899         }
   1900 
   1901         private void applyDensityScaling(int sourceDensity, int targetDensity) {
   1902             mInsetL = Drawable.scaleFromDensity(mInsetL, sourceDensity, targetDensity, false);
   1903             mInsetT = Drawable.scaleFromDensity(mInsetT, sourceDensity, targetDensity, false);
   1904             mInsetR = Drawable.scaleFromDensity(mInsetR, sourceDensity, targetDensity, false);
   1905             mInsetB = Drawable.scaleFromDensity(mInsetB, sourceDensity, targetDensity, false);
   1906             if (mInsetS != INSET_UNDEFINED) {
   1907                 mInsetS = Drawable.scaleFromDensity(mInsetS, sourceDensity, targetDensity, false);
   1908             }
   1909             if (mInsetE != INSET_UNDEFINED) {
   1910                 mInsetE = Drawable.scaleFromDensity(mInsetE, sourceDensity, targetDensity, false);
   1911             }
   1912             if (mWidth > 0) {
   1913                 mWidth = Drawable.scaleFromDensity(mWidth, sourceDensity, targetDensity, true);
   1914             }
   1915             if (mHeight > 0) {
   1916                 mHeight = Drawable.scaleFromDensity(mHeight, sourceDensity, targetDensity, true);
   1917             }
   1918         }
   1919     }
   1920 
   1921     static class LayerState extends ConstantState {
   1922         private int[] mThemeAttrs;
   1923 
   1924         int mNumChildren;
   1925         ChildDrawable[] mChildren;
   1926 
   1927         int mDensity;
   1928 
   1929         // These values all correspond to mDensity.
   1930         int mPaddingTop = -1;
   1931         int mPaddingBottom = -1;
   1932         int mPaddingLeft = -1;
   1933         int mPaddingRight = -1;
   1934         int mPaddingStart = -1;
   1935         int mPaddingEnd = -1;
   1936         int mOpacityOverride = PixelFormat.UNKNOWN;
   1937 
   1938         @Config int mChangingConfigurations;
   1939         @Config int mChildrenChangingConfigurations;
   1940 
   1941         private boolean mCheckedOpacity;
   1942         private int mOpacity;
   1943 
   1944         private boolean mCheckedStateful;
   1945         private boolean mIsStateful;
   1946 
   1947         private boolean mAutoMirrored = false;
   1948 
   1949         private int mPaddingMode = PADDING_MODE_NEST;
   1950 
   1951         LayerState(@Nullable LayerState orig, @NonNull LayerDrawable owner,
   1952                 @Nullable Resources res) {
   1953             mDensity = Drawable.resolveDensity(res, orig != null ? orig.mDensity : 0);
   1954 
   1955             if (orig != null) {
   1956                 final ChildDrawable[] origChildDrawable = orig.mChildren;
   1957                 final int N = orig.mNumChildren;
   1958 
   1959                 mNumChildren = N;
   1960                 mChildren = new ChildDrawable[N];
   1961 
   1962                 mChangingConfigurations = orig.mChangingConfigurations;
   1963                 mChildrenChangingConfigurations = orig.mChildrenChangingConfigurations;
   1964 
   1965                 for (int i = 0; i < N; i++) {
   1966                     final ChildDrawable or = origChildDrawable[i];
   1967                     mChildren[i] = new ChildDrawable(or, owner, res);
   1968                 }
   1969 
   1970                 mCheckedOpacity = orig.mCheckedOpacity;
   1971                 mOpacity = orig.mOpacity;
   1972                 mCheckedStateful = orig.mCheckedStateful;
   1973                 mIsStateful = orig.mIsStateful;
   1974                 mAutoMirrored = orig.mAutoMirrored;
   1975                 mPaddingMode = orig.mPaddingMode;
   1976                 mThemeAttrs = orig.mThemeAttrs;
   1977                 mPaddingTop = orig.mPaddingTop;
   1978                 mPaddingBottom = orig.mPaddingBottom;
   1979                 mPaddingLeft = orig.mPaddingLeft;
   1980                 mPaddingRight = orig.mPaddingRight;
   1981                 mPaddingStart = orig.mPaddingStart;
   1982                 mPaddingEnd = orig.mPaddingEnd;
   1983                 mOpacityOverride = orig.mOpacityOverride;
   1984 
   1985                 if (orig.mDensity != mDensity) {
   1986                     applyDensityScaling(orig.mDensity, mDensity);
   1987                 }
   1988             } else {
   1989                 mNumChildren = 0;
   1990                 mChildren = null;
   1991             }
   1992         }
   1993 
   1994         public final void setDensity(int targetDensity) {
   1995             if (mDensity != targetDensity) {
   1996                 final int sourceDensity = mDensity;
   1997                 mDensity = targetDensity;
   1998 
   1999                 onDensityChanged(sourceDensity, targetDensity);
   2000             }
   2001         }
   2002 
   2003         protected void onDensityChanged(int sourceDensity, int targetDensity) {
   2004             applyDensityScaling(sourceDensity, targetDensity);
   2005         }
   2006 
   2007         private void applyDensityScaling(int sourceDensity, int targetDensity) {
   2008             if (mPaddingLeft > 0) {
   2009                 mPaddingLeft = Drawable.scaleFromDensity(
   2010                         mPaddingLeft, sourceDensity, targetDensity, false);
   2011             }
   2012             if (mPaddingTop > 0) {
   2013                 mPaddingTop = Drawable.scaleFromDensity(
   2014                         mPaddingTop, sourceDensity, targetDensity, false);
   2015             }
   2016             if (mPaddingRight > 0) {
   2017                 mPaddingRight = Drawable.scaleFromDensity(
   2018                         mPaddingRight, sourceDensity, targetDensity, false);
   2019             }
   2020             if (mPaddingBottom > 0) {
   2021                 mPaddingBottom = Drawable.scaleFromDensity(
   2022                         mPaddingBottom, sourceDensity, targetDensity, false);
   2023             }
   2024             if (mPaddingStart > 0) {
   2025                 mPaddingStart = Drawable.scaleFromDensity(
   2026                         mPaddingStart, sourceDensity, targetDensity, false);
   2027             }
   2028             if (mPaddingEnd > 0) {
   2029                 mPaddingEnd = Drawable.scaleFromDensity(
   2030                         mPaddingEnd, sourceDensity, targetDensity, false);
   2031             }
   2032         }
   2033 
   2034         @Override
   2035         public boolean canApplyTheme() {
   2036             if (mThemeAttrs != null || super.canApplyTheme()) {
   2037                 return true;
   2038             }
   2039 
   2040             final ChildDrawable[] array = mChildren;
   2041             final int N = mNumChildren;
   2042             for (int i = 0; i < N; i++) {
   2043                 final ChildDrawable layer = array[i];
   2044                 if (layer.canApplyTheme()) {
   2045                     return true;
   2046                 }
   2047             }
   2048 
   2049             return false;
   2050         }
   2051 
   2052         @Override
   2053         public Drawable newDrawable() {
   2054             return new LayerDrawable(this, null);
   2055         }
   2056 
   2057         @Override
   2058         public Drawable newDrawable(@Nullable Resources res) {
   2059             return new LayerDrawable(this, res);
   2060         }
   2061 
   2062         @Override
   2063         public @Config int getChangingConfigurations() {
   2064             return mChangingConfigurations
   2065                     | mChildrenChangingConfigurations;
   2066         }
   2067 
   2068         public final int getOpacity() {
   2069             if (mCheckedOpacity) {
   2070                 return mOpacity;
   2071             }
   2072 
   2073             final int N = mNumChildren;
   2074             final ChildDrawable[] array = mChildren;
   2075 
   2076             // Seek to the first non-null drawable.
   2077             int firstIndex = -1;
   2078             for (int i = 0; i < N; i++) {
   2079                 if (array[i].mDrawable != null) {
   2080                     firstIndex = i;
   2081                     break;
   2082                 }
   2083             }
   2084 
   2085             int op;
   2086             if (firstIndex >= 0) {
   2087                 op = array[firstIndex].mDrawable.getOpacity();
   2088             } else {
   2089                 op = PixelFormat.TRANSPARENT;
   2090             }
   2091 
   2092             // Merge all remaining non-null drawables.
   2093             for (int i = firstIndex + 1; i < N; i++) {
   2094                 final Drawable dr = array[i].mDrawable;
   2095                 if (dr != null) {
   2096                     op = Drawable.resolveOpacity(op, dr.getOpacity());
   2097                 }
   2098             }
   2099 
   2100             mOpacity = op;
   2101             mCheckedOpacity = true;
   2102             return op;
   2103         }
   2104 
   2105         public final boolean isStateful() {
   2106             if (mCheckedStateful) {
   2107                 return mIsStateful;
   2108             }
   2109 
   2110             final int N = mNumChildren;
   2111             final ChildDrawable[] array = mChildren;
   2112             boolean isStateful = false;
   2113             for (int i = 0; i < N; i++) {
   2114                 final Drawable dr = array[i].mDrawable;
   2115                 if (dr != null && dr.isStateful()) {
   2116                     isStateful = true;
   2117                     break;
   2118                 }
   2119             }
   2120 
   2121             mIsStateful = isStateful;
   2122             mCheckedStateful = true;
   2123             return isStateful;
   2124         }
   2125 
   2126         public final boolean hasFocusStateSpecified() {
   2127             final int N = mNumChildren;
   2128             final ChildDrawable[] array = mChildren;
   2129             for (int i = 0; i < N; i++) {
   2130                 final Drawable dr = array[i].mDrawable;
   2131                 if (dr != null && dr.hasFocusStateSpecified()) {
   2132                     return true;
   2133                 }
   2134             }
   2135             return false;
   2136         }
   2137 
   2138         public final boolean canConstantState() {
   2139             final ChildDrawable[] array = mChildren;
   2140             final int N = mNumChildren;
   2141             for (int i = 0; i < N; i++) {
   2142                 final Drawable dr = array[i].mDrawable;
   2143                 if (dr != null && dr.getConstantState() == null) {
   2144                     return false;
   2145                 }
   2146             }
   2147 
   2148             // Don't cache the result, this method is not called very often.
   2149             return true;
   2150         }
   2151 
   2152         /**
   2153          * Invalidates the cached opacity and statefulness.
   2154          */
   2155         void invalidateCache() {
   2156             mCheckedOpacity = false;
   2157             mCheckedStateful = false;
   2158         }
   2159 
   2160     }
   2161 }
   2162 
   2163