Home | History | Annotate | Download | only in drawable
      1 /*
      2  * Copyright (C) 2006 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.graphics.drawable;
     18 
     19 import org.xmlpull.v1.XmlPullParser;
     20 import org.xmlpull.v1.XmlPullParserException;
     21 
     22 import android.content.res.Resources;
     23 import android.content.res.TypedArray;
     24 import android.graphics.Canvas;
     25 import android.graphics.ColorFilter;
     26 import android.graphics.PixelFormat;
     27 import android.graphics.Rect;
     28 import android.util.AttributeSet;
     29 import android.view.View;
     30 
     31 import java.io.IOException;
     32 
     33 /**
     34  * A Drawable that manages an array of other Drawables. These are drawn in array
     35  * order, so the element with the largest index will be drawn on top.
     36  * <p>
     37  * It can be defined in an XML file with the <code>&lt;layer-list></code> element.
     38  * Each Drawable in the layer is defined in a nested <code>&lt;item></code>. For more
     39  * information, see the guide to <a
     40  * href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.</p>
     41  *
     42  * @attr ref android.R.styleable#LayerDrawableItem_left
     43  * @attr ref android.R.styleable#LayerDrawableItem_top
     44  * @attr ref android.R.styleable#LayerDrawableItem_right
     45  * @attr ref android.R.styleable#LayerDrawableItem_bottom
     46  * @attr ref android.R.styleable#LayerDrawableItem_drawable
     47  * @attr ref android.R.styleable#LayerDrawableItem_id
     48 */
     49 public class LayerDrawable extends Drawable implements Drawable.Callback {
     50     LayerState mLayerState;
     51 
     52     private int mOpacityOverride = PixelFormat.UNKNOWN;
     53     private int[] mPaddingL;
     54     private int[] mPaddingT;
     55     private int[] mPaddingR;
     56     private int[] mPaddingB;
     57 
     58     private final Rect mTmpRect = new Rect();
     59     private boolean mMutated;
     60 
     61     /**
     62      * Create a new layer drawable with the list of specified layers.
     63      *
     64      * @param layers A list of drawables to use as layers in this new drawable.
     65      */
     66     public LayerDrawable(Drawable[] layers) {
     67         this(layers, null);
     68     }
     69 
     70     /**
     71      * Create a new layer drawable with the specified list of layers and the specified
     72      * constant state.
     73      *
     74      * @param layers The list of layers to add to this drawable.
     75      * @param state The constant drawable state.
     76      */
     77     LayerDrawable(Drawable[] layers, LayerState state) {
     78         this(state, null);
     79         int length = layers.length;
     80         ChildDrawable[] r = new ChildDrawable[length];
     81 
     82         for (int i = 0; i < length; i++) {
     83             r[i] = new ChildDrawable();
     84             r[i].mDrawable = layers[i];
     85             layers[i].setCallback(this);
     86             mLayerState.mChildrenChangingConfigurations |= layers[i].getChangingConfigurations();
     87         }
     88         mLayerState.mNum = length;
     89         mLayerState.mChildren = r;
     90 
     91         ensurePadding();
     92     }
     93 
     94     LayerDrawable() {
     95         this((LayerState) null, null);
     96     }
     97 
     98     LayerDrawable(LayerState state, Resources res) {
     99         LayerState as = createConstantState(state, res);
    100         mLayerState = as;
    101         if (as.mNum > 0) {
    102             ensurePadding();
    103         }
    104     }
    105 
    106     LayerState createConstantState(LayerState state, Resources res) {
    107         return new LayerState(state, this, res);
    108     }
    109 
    110     @Override
    111     public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs)
    112             throws XmlPullParserException, IOException {
    113         super.inflate(r, parser, attrs);
    114 
    115         int type;
    116 
    117         TypedArray a = r.obtainAttributes(attrs, com.android.internal.R.styleable.LayerDrawable);
    118 
    119         mOpacityOverride = a.getInt(com.android.internal.R.styleable.LayerDrawable_opacity,
    120                 PixelFormat.UNKNOWN);
    121 
    122         setAutoMirrored(a.getBoolean(com.android.internal.R.styleable.LayerDrawable_autoMirrored,
    123                 false));
    124 
    125         a.recycle();
    126 
    127         final int innerDepth = parser.getDepth() + 1;
    128         int depth;
    129         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
    130                 && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) {
    131             if (type != XmlPullParser.START_TAG) {
    132                 continue;
    133             }
    134 
    135             if (depth > innerDepth || !parser.getName().equals("item")) {
    136                 continue;
    137             }
    138 
    139             a = r.obtainAttributes(attrs,
    140                     com.android.internal.R.styleable.LayerDrawableItem);
    141 
    142             int left = a.getDimensionPixelOffset(
    143                     com.android.internal.R.styleable.LayerDrawableItem_left, 0);
    144             int top = a.getDimensionPixelOffset(
    145                     com.android.internal.R.styleable.LayerDrawableItem_top, 0);
    146             int right = a.getDimensionPixelOffset(
    147                     com.android.internal.R.styleable.LayerDrawableItem_right, 0);
    148             int bottom = a.getDimensionPixelOffset(
    149                     com.android.internal.R.styleable.LayerDrawableItem_bottom, 0);
    150             int drawableRes = a.getResourceId(
    151                     com.android.internal.R.styleable.LayerDrawableItem_drawable, 0);
    152             int id = a.getResourceId(com.android.internal.R.styleable.LayerDrawableItem_id,
    153                     View.NO_ID);
    154 
    155             a.recycle();
    156 
    157             Drawable dr;
    158             if (drawableRes != 0) {
    159                 dr = r.getDrawable(drawableRes);
    160             } else {
    161                 while ((type = parser.next()) == XmlPullParser.TEXT) {
    162                 }
    163                 if (type != XmlPullParser.START_TAG) {
    164                     throw new XmlPullParserException(parser.getPositionDescription()
    165                             + ": <item> tag requires a 'drawable' attribute or "
    166                             + "child tag defining a drawable");
    167                 }
    168                 dr = Drawable.createFromXmlInner(r, parser, attrs);
    169             }
    170 
    171             addLayer(dr, id, left, top, right, bottom);
    172         }
    173 
    174         ensurePadding();
    175         onStateChange(getState());
    176     }
    177 
    178     /**
    179      * Add a new layer to this drawable. The new layer is identified by an id.
    180      *
    181      * @param layer The drawable to add as a layer.
    182      * @param id The id of the new layer.
    183      * @param left The left padding of the new layer.
    184      * @param top The top padding of the new layer.
    185      * @param right The right padding of the new layer.
    186      * @param bottom The bottom padding of the new layer.
    187      */
    188     private void addLayer(Drawable layer, int id, int left, int top, int right, int bottom) {
    189         final LayerState st = mLayerState;
    190         int N = st.mChildren != null ? st.mChildren.length : 0;
    191         int i = st.mNum;
    192         if (i >= N) {
    193             ChildDrawable[] nu = new ChildDrawable[N + 10];
    194             if (i > 0) {
    195                 System.arraycopy(st.mChildren, 0, nu, 0, i);
    196             }
    197             st.mChildren = nu;
    198         }
    199 
    200         mLayerState.mChildrenChangingConfigurations |= layer.getChangingConfigurations();
    201 
    202         ChildDrawable childDrawable = new ChildDrawable();
    203         st.mChildren[i] = childDrawable;
    204         childDrawable.mId = id;
    205         childDrawable.mDrawable = layer;
    206         childDrawable.mDrawable.setAutoMirrored(isAutoMirrored());
    207         childDrawable.mInsetL = left;
    208         childDrawable.mInsetT = top;
    209         childDrawable.mInsetR = right;
    210         childDrawable.mInsetB = bottom;
    211         st.mNum++;
    212 
    213         layer.setCallback(this);
    214     }
    215 
    216     /**
    217      * Look for a layer with the given id, and returns its {@link Drawable}.
    218      *
    219      * @param id The layer ID to search for.
    220      * @return The {@link Drawable} of the layer that has the given id in the hierarchy or null.
    221      */
    222     public Drawable findDrawableByLayerId(int id) {
    223         final ChildDrawable[] layers = mLayerState.mChildren;
    224 
    225         for (int i = mLayerState.mNum - 1; i >= 0; i--) {
    226             if (layers[i].mId == id) {
    227                 return layers[i].mDrawable;
    228             }
    229         }
    230 
    231         return null;
    232     }
    233 
    234     /**
    235      * Sets the ID of a layer.
    236      *
    237      * @param index The index of the layer which will received the ID.
    238      * @param id The ID to assign to the layer.
    239      */
    240     public void setId(int index, int id) {
    241         mLayerState.mChildren[index].mId = id;
    242     }
    243 
    244     /**
    245      * Returns the number of layers contained within this.
    246      * @return The number of layers.
    247      */
    248     public int getNumberOfLayers() {
    249         return mLayerState.mNum;
    250     }
    251 
    252     /**
    253      * Returns the drawable at the specified layer index.
    254      *
    255      * @param index The layer index of the drawable to retrieve.
    256      *
    257      * @return The {@link android.graphics.drawable.Drawable} at the specified layer index.
    258      */
    259     public Drawable getDrawable(int index) {
    260         return mLayerState.mChildren[index].mDrawable;
    261     }
    262 
    263     /**
    264      * Returns the id of the specified layer.
    265      *
    266      * @param index The index of the layer.
    267      *
    268      * @return The id of the layer or {@link android.view.View#NO_ID} if the layer has no id.
    269      */
    270     public int getId(int index) {
    271         return mLayerState.mChildren[index].mId;
    272     }
    273 
    274     /**
    275      * Sets (or replaces) the {@link Drawable} for the layer with the given id.
    276      *
    277      * @param id The layer ID to search for.
    278      * @param drawable The replacement {@link Drawable}.
    279      * @return Whether the {@link Drawable} was replaced (could return false if
    280      *         the id was not found).
    281      */
    282     public boolean setDrawableByLayerId(int id, Drawable drawable) {
    283         final ChildDrawable[] layers = mLayerState.mChildren;
    284 
    285         for (int i = mLayerState.mNum - 1; i >= 0; i--) {
    286             if (layers[i].mId == id) {
    287                 if (layers[i].mDrawable != null) {
    288                     if (drawable != null) {
    289                         Rect bounds = layers[i].mDrawable.getBounds();
    290                         drawable.setBounds(bounds);
    291                     }
    292                     layers[i].mDrawable.setCallback(null);
    293                 }
    294                 if (drawable != null) {
    295                     drawable.setCallback(this);
    296                 }
    297                 layers[i].mDrawable = drawable;
    298                 return true;
    299             }
    300         }
    301 
    302         return false;
    303     }
    304 
    305     /** Specify modifiers to the bounds for the drawable[index].
    306         left += l
    307         top += t;
    308         right -= r;
    309         bottom -= b;
    310     */
    311     public void setLayerInset(int index, int l, int t, int r, int b) {
    312         ChildDrawable childDrawable = mLayerState.mChildren[index];
    313         childDrawable.mInsetL = l;
    314         childDrawable.mInsetT = t;
    315         childDrawable.mInsetR = r;
    316         childDrawable.mInsetB = b;
    317     }
    318 
    319     // overrides from Drawable.Callback
    320 
    321     public void invalidateDrawable(Drawable who) {
    322         final Callback callback = getCallback();
    323         if (callback != null) {
    324             callback.invalidateDrawable(this);
    325         }
    326     }
    327 
    328     public void scheduleDrawable(Drawable who, Runnable what, long when) {
    329         final Callback callback = getCallback();
    330         if (callback != null) {
    331             callback.scheduleDrawable(this, what, when);
    332         }
    333     }
    334 
    335     public void unscheduleDrawable(Drawable who, Runnable what) {
    336         final Callback callback = getCallback();
    337         if (callback != null) {
    338             callback.unscheduleDrawable(this, what);
    339         }
    340     }
    341 
    342     // overrides from Drawable
    343 
    344     @Override
    345     public void draw(Canvas canvas) {
    346         final ChildDrawable[] array = mLayerState.mChildren;
    347         final int N = mLayerState.mNum;
    348         for (int i=0; i<N; i++) {
    349             array[i].mDrawable.draw(canvas);
    350         }
    351     }
    352 
    353     @Override
    354     public int getChangingConfigurations() {
    355         return super.getChangingConfigurations()
    356                 | mLayerState.mChangingConfigurations
    357                 | mLayerState.mChildrenChangingConfigurations;
    358     }
    359 
    360     @Override
    361     public boolean getPadding(Rect padding) {
    362         // Arbitrarily get the padding from the first image.
    363         // Technically we should maybe do something more intelligent,
    364         // like take the max padding of all the images.
    365         padding.left = 0;
    366         padding.top = 0;
    367         padding.right = 0;
    368         padding.bottom = 0;
    369         final ChildDrawable[] array = mLayerState.mChildren;
    370         final int N = mLayerState.mNum;
    371         for (int i=0; i<N; i++) {
    372             reapplyPadding(i, array[i]);
    373             padding.left += mPaddingL[i];
    374             padding.top += mPaddingT[i];
    375             padding.right += mPaddingR[i];
    376             padding.bottom += mPaddingB[i];
    377         }
    378         return true;
    379     }
    380 
    381     @Override
    382     public boolean setVisible(boolean visible, boolean restart) {
    383         boolean changed = super.setVisible(visible, restart);
    384         final ChildDrawable[] array = mLayerState.mChildren;
    385         final int N = mLayerState.mNum;
    386         for (int i=0; i<N; i++) {
    387             array[i].mDrawable.setVisible(visible, restart);
    388         }
    389         return changed;
    390     }
    391 
    392     @Override
    393     public void setDither(boolean dither) {
    394         final ChildDrawable[] array = mLayerState.mChildren;
    395         final int N = mLayerState.mNum;
    396         for (int i=0; i<N; i++) {
    397             array[i].mDrawable.setDither(dither);
    398         }
    399     }
    400 
    401     @Override
    402     public void setAlpha(int alpha) {
    403         final ChildDrawable[] array = mLayerState.mChildren;
    404         final int N = mLayerState.mNum;
    405         for (int i=0; i<N; i++) {
    406             array[i].mDrawable.setAlpha(alpha);
    407         }
    408     }
    409 
    410     @Override
    411     public int getAlpha() {
    412         final ChildDrawable[] array = mLayerState.mChildren;
    413         if (mLayerState.mNum > 0) {
    414             // All layers should have the same alpha set on them - just return the first one
    415             return array[0].mDrawable.getAlpha();
    416         } else {
    417             return super.getAlpha();
    418         }
    419     }
    420 
    421     @Override
    422     public void setColorFilter(ColorFilter cf) {
    423         final ChildDrawable[] array = mLayerState.mChildren;
    424         final int N = mLayerState.mNum;
    425         for (int i=0; i<N; i++) {
    426             array[i].mDrawable.setColorFilter(cf);
    427         }
    428     }
    429 
    430     /**
    431      * Sets the opacity of this drawable directly, instead of collecting the states from
    432      * the layers
    433      *
    434      * @param opacity The opacity to use, or {@link PixelFormat#UNKNOWN PixelFormat.UNKNOWN}
    435      * for the default behavior
    436      *
    437      * @see PixelFormat#UNKNOWN
    438      * @see PixelFormat#TRANSLUCENT
    439      * @see PixelFormat#TRANSPARENT
    440      * @see PixelFormat#OPAQUE
    441      */
    442     public void setOpacity(int opacity) {
    443         mOpacityOverride = opacity;
    444     }
    445 
    446     @Override
    447     public int getOpacity() {
    448         if (mOpacityOverride != PixelFormat.UNKNOWN) {
    449             return mOpacityOverride;
    450         }
    451         return mLayerState.getOpacity();
    452     }
    453 
    454     @Override
    455     public void setAutoMirrored(boolean mirrored) {
    456         mLayerState.mAutoMirrored = mirrored;
    457         final ChildDrawable[] array = mLayerState.mChildren;
    458         final int N = mLayerState.mNum;
    459         for (int i=0; i<N; i++) {
    460             array[i].mDrawable.setAutoMirrored(mirrored);
    461         }
    462     }
    463 
    464     @Override
    465     public boolean isAutoMirrored() {
    466         return mLayerState.mAutoMirrored;
    467     }
    468 
    469     @Override
    470     public boolean isStateful() {
    471         return mLayerState.isStateful();
    472     }
    473 
    474     @Override
    475     protected boolean onStateChange(int[] state) {
    476         final ChildDrawable[] array = mLayerState.mChildren;
    477         final int N = mLayerState.mNum;
    478         boolean paddingChanged = false;
    479         boolean changed = false;
    480         for (int i=0; i<N; i++) {
    481             final ChildDrawable r = array[i];
    482             if (r.mDrawable.setState(state)) {
    483                 changed = true;
    484             }
    485             if (reapplyPadding(i, r)) {
    486                 paddingChanged = true;
    487             }
    488         }
    489         if (paddingChanged) {
    490             onBoundsChange(getBounds());
    491         }
    492         return changed;
    493     }
    494 
    495     @Override
    496     protected boolean onLevelChange(int level) {
    497         final ChildDrawable[] array = mLayerState.mChildren;
    498         final int N = mLayerState.mNum;
    499         boolean paddingChanged = false;
    500         boolean changed = false;
    501         for (int i=0; i<N; i++) {
    502             final ChildDrawable r = array[i];
    503             if (r.mDrawable.setLevel(level)) {
    504                 changed = true;
    505             }
    506             if (reapplyPadding(i, r)) {
    507                 paddingChanged = true;
    508             }
    509         }
    510         if (paddingChanged) {
    511             onBoundsChange(getBounds());
    512         }
    513         return changed;
    514     }
    515 
    516     @Override
    517     protected void onBoundsChange(Rect bounds) {
    518         final ChildDrawable[] array = mLayerState.mChildren;
    519         final int N = mLayerState.mNum;
    520         int padL=0, padT=0, padR=0, padB=0;
    521         for (int i=0; i<N; i++) {
    522             final ChildDrawable r = array[i];
    523             r.mDrawable.setBounds(bounds.left + r.mInsetL + padL,
    524                                   bounds.top + r.mInsetT + padT,
    525                                   bounds.right - r.mInsetR - padR,
    526                                   bounds.bottom - r.mInsetB - padB);
    527             padL += mPaddingL[i];
    528             padR += mPaddingR[i];
    529             padT += mPaddingT[i];
    530             padB += mPaddingB[i];
    531         }
    532     }
    533 
    534     @Override
    535     public int getIntrinsicWidth() {
    536         int width = -1;
    537         final ChildDrawable[] array = mLayerState.mChildren;
    538         final int N = mLayerState.mNum;
    539         int padL=0, padR=0;
    540         for (int i=0; i<N; i++) {
    541             final ChildDrawable r = array[i];
    542             int w = r.mDrawable.getIntrinsicWidth()
    543                   + r.mInsetL + r.mInsetR + padL + padR;
    544             if (w > width) {
    545                 width = w;
    546             }
    547             padL += mPaddingL[i];
    548             padR += mPaddingR[i];
    549         }
    550         return width;
    551     }
    552 
    553     @Override
    554     public int getIntrinsicHeight() {
    555         int height = -1;
    556         final ChildDrawable[] array = mLayerState.mChildren;
    557         final int N = mLayerState.mNum;
    558         int padT=0, padB=0;
    559         for (int i=0; i<N; i++) {
    560             final ChildDrawable r = array[i];
    561             int h = r.mDrawable.getIntrinsicHeight() + r.mInsetT + r.mInsetB + + padT + padB;
    562             if (h > height) {
    563                 height = h;
    564             }
    565             padT += mPaddingT[i];
    566             padB += mPaddingB[i];
    567         }
    568         return height;
    569     }
    570 
    571     private boolean reapplyPadding(int i, ChildDrawable r) {
    572         final Rect rect = mTmpRect;
    573         r.mDrawable.getPadding(rect);
    574         if (rect.left != mPaddingL[i] || rect.top != mPaddingT[i] ||
    575                 rect.right != mPaddingR[i] || rect.bottom != mPaddingB[i]) {
    576             mPaddingL[i] = rect.left;
    577             mPaddingT[i] = rect.top;
    578             mPaddingR[i] = rect.right;
    579             mPaddingB[i] = rect.bottom;
    580             return true;
    581         }
    582         return false;
    583     }
    584 
    585     private void ensurePadding() {
    586         final int N = mLayerState.mNum;
    587         if (mPaddingL != null && mPaddingL.length >= N) {
    588             return;
    589         }
    590         mPaddingL = new int[N];
    591         mPaddingT = new int[N];
    592         mPaddingR = new int[N];
    593         mPaddingB = new int[N];
    594     }
    595 
    596     @Override
    597     public ConstantState getConstantState() {
    598         if (mLayerState.canConstantState()) {
    599             mLayerState.mChangingConfigurations = getChangingConfigurations();
    600             return mLayerState;
    601         }
    602         return null;
    603     }
    604 
    605     @Override
    606     public Drawable mutate() {
    607         if (!mMutated && super.mutate() == this) {
    608             mLayerState = createConstantState(mLayerState, null);
    609             final ChildDrawable[] array = mLayerState.mChildren;
    610             final int N = mLayerState.mNum;
    611             for (int i = 0; i < N; i++) {
    612                 array[i].mDrawable.mutate();
    613             }
    614             mMutated = true;
    615         }
    616         return this;
    617     }
    618 
    619     /** @hide */
    620     @Override
    621     public void setLayoutDirection(int layoutDirection) {
    622         final ChildDrawable[] array = mLayerState.mChildren;
    623         final int N = mLayerState.mNum;
    624         for (int i = 0; i < N; i++) {
    625             array[i].mDrawable.setLayoutDirection(layoutDirection);
    626         }
    627         super.setLayoutDirection(layoutDirection);
    628     }
    629 
    630     static class ChildDrawable {
    631         public Drawable mDrawable;
    632         public int mInsetL, mInsetT, mInsetR, mInsetB;
    633         public int mId;
    634     }
    635 
    636     static class LayerState extends ConstantState {
    637         int mNum;
    638         ChildDrawable[] mChildren;
    639 
    640         int mChangingConfigurations;
    641         int mChildrenChangingConfigurations;
    642 
    643         private boolean mHaveOpacity = false;
    644         private int mOpacity;
    645 
    646         private boolean mHaveStateful = false;
    647         private boolean mStateful;
    648 
    649         private boolean mCheckedConstantState;
    650         private boolean mCanConstantState;
    651 
    652         private boolean mAutoMirrored;
    653 
    654         LayerState(LayerState orig, LayerDrawable owner, Resources res) {
    655             if (orig != null) {
    656                 final ChildDrawable[] origChildDrawable = orig.mChildren;
    657                 final int N = orig.mNum;
    658 
    659                 mNum = N;
    660                 mChildren = new ChildDrawable[N];
    661 
    662                 mChangingConfigurations = orig.mChangingConfigurations;
    663                 mChildrenChangingConfigurations = orig.mChildrenChangingConfigurations;
    664 
    665                 for (int i = 0; i < N; i++) {
    666                     final ChildDrawable r = mChildren[i] = new ChildDrawable();
    667                     final ChildDrawable or = origChildDrawable[i];
    668                     if (res != null) {
    669                         r.mDrawable = or.mDrawable.getConstantState().newDrawable(res);
    670                     } else {
    671                         r.mDrawable = or.mDrawable.getConstantState().newDrawable();
    672                     }
    673                     r.mDrawable.setCallback(owner);
    674                     r.mDrawable.setLayoutDirection(or.mDrawable.getLayoutDirection());
    675                     r.mInsetL = or.mInsetL;
    676                     r.mInsetT = or.mInsetT;
    677                     r.mInsetR = or.mInsetR;
    678                     r.mInsetB = or.mInsetB;
    679                     r.mId = or.mId;
    680                 }
    681 
    682                 mHaveOpacity = orig.mHaveOpacity;
    683                 mOpacity = orig.mOpacity;
    684                 mHaveStateful = orig.mHaveStateful;
    685                 mStateful = orig.mStateful;
    686                 mCheckedConstantState = mCanConstantState = true;
    687                 mAutoMirrored = orig.mAutoMirrored;
    688             } else {
    689                 mNum = 0;
    690                 mChildren = null;
    691             }
    692         }
    693 
    694         @Override
    695         public Drawable newDrawable() {
    696             return new LayerDrawable(this, null);
    697         }
    698 
    699         @Override
    700         public Drawable newDrawable(Resources res) {
    701             return new LayerDrawable(this, res);
    702         }
    703 
    704         @Override
    705         public int getChangingConfigurations() {
    706             return mChangingConfigurations;
    707         }
    708 
    709         public final int getOpacity() {
    710             if (mHaveOpacity) {
    711                 return mOpacity;
    712             }
    713 
    714             final int N = mNum;
    715             int op = N > 0 ? mChildren[0].mDrawable.getOpacity() : PixelFormat.TRANSPARENT;
    716             for (int i = 1; i < N; i++) {
    717                 op = Drawable.resolveOpacity(op, mChildren[i].mDrawable.getOpacity());
    718             }
    719             mOpacity = op;
    720             mHaveOpacity = true;
    721             return op;
    722         }
    723 
    724         public final boolean isStateful() {
    725             if (mHaveStateful) {
    726                 return mStateful;
    727             }
    728 
    729             boolean stateful = false;
    730             final int N = mNum;
    731             for (int i = 0; i < N; i++) {
    732                 if (mChildren[i].mDrawable.isStateful()) {
    733                     stateful = true;
    734                     break;
    735                 }
    736             }
    737 
    738             mStateful = stateful;
    739             mHaveStateful = true;
    740             return stateful;
    741         }
    742 
    743         public boolean canConstantState() {
    744             if (!mCheckedConstantState && mChildren != null) {
    745                 mCanConstantState = true;
    746                 final int N = mNum;
    747                 for (int i=0; i<N; i++) {
    748                     if (mChildren[i].mDrawable.getConstantState() == null) {
    749                         mCanConstantState = false;
    750                         break;
    751                     }
    752                 }
    753                 mCheckedConstantState = true;
    754             }
    755 
    756             return mCanConstantState;
    757         }
    758     }
    759 }
    760 
    761