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