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