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