Loading api/current.txt +4 −0 Original line number Original line Diff line number Diff line Loading @@ -10365,6 +10365,7 @@ package android.graphics.drawable { method public int getId(int); method public int getId(int); method public int getNumberOfLayers(); method public int getNumberOfLayers(); method public int getOpacity(); method public int getOpacity(); method public int getPaddingMode(); method public void invalidateDrawable(android.graphics.drawable.Drawable); method public void invalidateDrawable(android.graphics.drawable.Drawable); method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long); method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long); method public void setAlpha(int); method public void setAlpha(int); Loading @@ -10373,7 +10374,10 @@ package android.graphics.drawable { method public void setId(int, int); method public void setId(int, int); method public void setLayerInset(int, int, int, int, int); method public void setLayerInset(int, int, int, int, int); method public void setOpacity(int); method public void setOpacity(int); method public void setPaddingMode(int); method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable); method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable); field public static final int PADDING_MODE_NEST = 0; // 0x0 field public static final int PADDING_MODE_STACK = 1; // 0x1 } } public class LevelListDrawable extends android.graphics.drawable.DrawableContainer { public class LevelListDrawable extends android.graphics.drawable.DrawableContainer { core/res/res/values/attrs.xml +9 −1 Original line number Original line Diff line number Diff line Loading @@ -4241,6 +4241,14 @@ <!-- Indicates if the drawable needs to be mirrored when its layout direction is <!-- Indicates if the drawable needs to be mirrored when its layout direction is RTL (right-to-left). --> RTL (right-to-left). --> <attr name="autoMirrored" /> <attr name="autoMirrored" /> <!-- Indicates how layer padding should affect the bounds of subsequent layers. The default value is nest. --> <attr name="paddingMode"> <!-- Nest each layer inside the padding of the previous layer. --> <enum name="nest" value="0" /> <!-- Stack each layer directly atop the previous layer. --> <enum name="stack" value="1" /> </attr> </declare-styleable> </declare-styleable> <!-- Describes an item (or child) of a LayerDrawable. --> <!-- Describes an item (or child) of a LayerDrawable. --> Loading @@ -4256,7 +4264,7 @@ <!-- Drawable used to render the layer. --> <!-- Drawable used to render the layer. --> <attr name="drawable" /> <attr name="drawable" /> <!-- Identifier of the layer. This can be used to retrieve the layer <!-- Identifier of the layer. This can be used to retrieve the layer from a drawbable container. --> from a drawable container. --> <attr name="id" /> <attr name="id" /> </declare-styleable> </declare-styleable> Loading graphics/java/android/graphics/drawable/LayerDrawable.java +229 −93 Original line number Original line Diff line number Diff line Loading @@ -47,6 +47,15 @@ import java.io.IOException; * @attr ref android.R.styleable#LayerDrawableItem_id * @attr ref android.R.styleable#LayerDrawableItem_id */ */ public class LayerDrawable extends Drawable implements Drawable.Callback { public class LayerDrawable extends Drawable implements Drawable.Callback { /** * Padding mode used to nest each layer inside the padding of the previous * layer. */ public static final int PADDING_MODE_NEST = 0; /** Padding mode used to stack each layer directly atop the previous layer. */ public static final int PADDING_MODE_STACK = 1; LayerState mLayerState; LayerState mLayerState; private int mOpacityOverride = PixelFormat.UNKNOWN; private int mOpacityOverride = PixelFormat.UNKNOWN; Loading @@ -55,8 +64,10 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { private int[] mPaddingR; private int[] mPaddingR; private int[] mPaddingB; private int[] mPaddingB; private final Rect mCachedPadding = new Rect(); private final Rect mTmpRect = new Rect(); private final Rect mTmpRect = new Rect(); private boolean mMutated; private boolean mMutated; private boolean mHasCachedPadding; /** /** * Create a new layer drawable with the list of specified layers. * Create a new layer drawable with the list of specified layers. Loading Loading @@ -122,6 +133,9 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { setAutoMirrored(a.getBoolean(com.android.internal.R.styleable.LayerDrawable_autoMirrored, setAutoMirrored(a.getBoolean(com.android.internal.R.styleable.LayerDrawable_autoMirrored, false)); false)); mLayerState.mPaddingMode = a.getInteger( com.android.internal.R.styleable.LayerDrawableItem_drawable, PADDING_MODE_NEST); a.recycle(); a.recycle(); final int innerDepth = parser.getDepth() + 1; final int innerDepth = parser.getDepth() + 1; Loading Loading @@ -187,19 +201,20 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { */ */ private void addLayer(Drawable layer, int id, int left, int top, int right, int bottom) { private void addLayer(Drawable layer, int id, int left, int top, int right, int bottom) { final LayerState st = mLayerState; final LayerState st = mLayerState; int N = st.mChildren != null ? st.mChildren.length : 0; final int N = st.mChildren != null ? st.mChildren.length : 0; int i = st.mNum; final int i = st.mNum; if (i >= N) { if (i >= N) { ChildDrawable[] nu = new ChildDrawable[N + 10]; final ChildDrawable[] nu = new ChildDrawable[N + 10]; if (i > 0) { if (i > 0) { System.arraycopy(st.mChildren, 0, nu, 0, i); System.arraycopy(st.mChildren, 0, nu, 0, i); } } st.mChildren = nu; st.mChildren = nu; } } mLayerState.mChildrenChangingConfigurations |= layer.getChangingConfigurations(); mLayerState.mChildrenChangingConfigurations |= layer.getChangingConfigurations(); ChildDrawable childDrawable = new ChildDrawable(); final ChildDrawable childDrawable = new ChildDrawable(); st.mChildren[i] = childDrawable; st.mChildren[i] = childDrawable; childDrawable.mId = id; childDrawable.mId = id; childDrawable.mDrawable = layer; childDrawable.mDrawable = layer; Loading @@ -221,8 +236,8 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { */ */ public Drawable findDrawableByLayerId(int id) { public Drawable findDrawableByLayerId(int id) { final ChildDrawable[] layers = mLayerState.mChildren; final ChildDrawable[] layers = mLayerState.mChildren; final int N = mLayerState.mNum; for (int i = mLayerState.mNum - 1; i >= 0; i--) { for (int i = 0; i < N; i--) { if (layers[i].mId == id) { if (layers[i].mId == id) { return layers[i].mDrawable; return layers[i].mDrawable; } } Loading Loading @@ -281,20 +296,29 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { */ */ public boolean setDrawableByLayerId(int id, Drawable drawable) { public boolean setDrawableByLayerId(int id, Drawable drawable) { final ChildDrawable[] layers = mLayerState.mChildren; final ChildDrawable[] layers = mLayerState.mChildren; final int N = mLayerState.mNum; for (int i = mLayerState.mNum - 1; i >= 0; i--) { for (int i = 0; i < N; i++) { if (layers[i].mId == id) { final ChildDrawable childDrawable = layers[i]; if (layers[i].mDrawable != null) { if (childDrawable.mId == id) { if (childDrawable.mDrawable != null) { if (drawable != null) { if (drawable != null) { Rect bounds = layers[i].mDrawable.getBounds(); final Rect bounds = childDrawable.mDrawable.getBounds(); drawable.setBounds(bounds); drawable.setBounds(bounds); } } layers[i].mDrawable.setCallback(null); childDrawable.mDrawable.setCallback(null); } } if (drawable != null) { if (drawable != null) { drawable.setCallback(this); drawable.setCallback(this); } } layers[i].mDrawable = drawable; childDrawable.mDrawable = drawable; if (refreshChildPadding(i, childDrawable)) { invalidatePadding(); } return true; return true; } } } } Loading @@ -302,22 +326,58 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { return false; return false; } } /** Specify modifiers to the bounds for the drawable[index]. /** left += l * Specifies the insets in pixels for the drawable at the specified index. top += t; * Insets are used to adjust the drawable bounds. right -= r; * bottom -= b; * @param index the index of the drawable to adjust * @param l number of pixels to add to the left bound * @param t number of pixels to add to the top bound * @param r number of pixels to subtract from the right bound * @param b number of pixels to subtract from the bottom bound */ */ public void setLayerInset(int index, int l, int t, int r, int b) { public void setLayerInset(int index, int l, int t, int r, int b) { ChildDrawable childDrawable = mLayerState.mChildren[index]; final ChildDrawable childDrawable = mLayerState.mChildren[index]; childDrawable.mInsetL = l; childDrawable.mInsetL = l; childDrawable.mInsetT = t; childDrawable.mInsetT = t; childDrawable.mInsetR = r; childDrawable.mInsetR = r; childDrawable.mInsetB = b; childDrawable.mInsetB = b; } } // overrides from Drawable.Callback /** * Specifies how layer padding should affect the bounds of subsequent * layers. The default value is {@link #PADDING_MODE_NEST}. * * @param mode padding mode, one of: * <ul> * <li>{@link #PADDING_MODE_NEST} * <li>{@link #PADDING_MODE_STACK} * </ul> */ public void setPaddingMode(int mode) { if (mLayerState.mPaddingMode != mode) { mLayerState.mPaddingMode = mode; invalidatePadding(); } } /** * @return the current padding mode * @see #setPaddingMode(int) */ public int getPaddingMode() { return mLayerState.mPaddingMode; } /** * Invalidates cached padding. */ private void invalidatePadding() { mHasCachedPadding = false; onBoundsChange(getBounds()); } @Override public void invalidateDrawable(Drawable who) { public void invalidateDrawable(Drawable who) { final Callback callback = getCallback(); final Callback callback = getCallback(); if (callback != null) { if (callback != null) { Loading @@ -325,6 +385,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { } } } } @Override public void scheduleDrawable(Drawable who, Runnable what, long when) { public void scheduleDrawable(Drawable who, Runnable what, long when) { final Callback callback = getCallback(); final Callback callback = getCallback(); if (callback != null) { if (callback != null) { Loading @@ -332,6 +393,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { } } } } @Override public void unscheduleDrawable(Drawable who, Runnable what) { public void unscheduleDrawable(Drawable who, Runnable what) { final Callback callback = getCallback(); final Callback callback = getCallback(); if (callback != null) { if (callback != null) { Loading @@ -339,8 +401,6 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { } } } } // overrides from Drawable @Override @Override public void draw(Canvas canvas) { public void draw(Canvas canvas) { final ChildDrawable[] array = mLayerState.mChildren; final ChildDrawable[] array = mLayerState.mChildren; Loading @@ -359,33 +419,69 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { @Override @Override public boolean getPadding(Rect padding) { public boolean getPadding(Rect padding) { // Arbitrarily get the padding from the first image. final Rect cachedPadding = mCachedPadding; // Technically we should maybe do something more intelligent, if (!mHasCachedPadding) { // like take the max padding of all the images. if (mLayerState.mPaddingMode == PADDING_MODE_NEST) { computeNestedPadding(cachedPadding); } else { computeStackedPadding(cachedPadding); } mHasCachedPadding = true; } padding.set(cachedPadding); return padding.left != 0 || padding.top != 0 || padding.right != 0 || padding.bottom != 0; } private void computeNestedPadding(Rect padding) { padding.left = 0; padding.left = 0; padding.top = 0; padding.top = 0; padding.right = 0; padding.right = 0; padding.bottom = 0; padding.bottom = 0; // Add all the padding. final ChildDrawable[] array = mLayerState.mChildren; final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; final int N = mLayerState.mNum; for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) { reapplyPadding(i, array[i]); refreshChildPadding(i, array[i]); padding.left += mPaddingL[i]; padding.left += mPaddingL[i]; padding.top += mPaddingT[i]; padding.top += mPaddingT[i]; padding.right += mPaddingR[i]; padding.right += mPaddingR[i]; padding.bottom += mPaddingB[i]; padding.bottom += mPaddingB[i]; } } return true; } private void computeStackedPadding(Rect padding) { padding.left = 0; padding.top = 0; padding.right = 0; padding.bottom = 0; // Take the max padding. final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; for (int i = 0; i < N; i++) { refreshChildPadding(i, array[i]); padding.left = Math.max(padding.left, mPaddingL[i]); padding.top = Math.max(padding.top, mPaddingT[i]); padding.right = Math.max(padding.right, mPaddingR[i]); padding.bottom = Math.max(padding.bottom, mPaddingB[i]); } } } @Override @Override public boolean setVisible(boolean visible, boolean restart) { public boolean setVisible(boolean visible, boolean restart) { boolean changed = super.setVisible(visible, restart); final boolean changed = super.setVisible(visible, restart); final ChildDrawable[] array = mLayerState.mChildren; final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; final int N = mLayerState.mNum; for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) { array[i].mDrawable.setVisible(visible, restart); array[i].mDrawable.setVisible(visible, restart); } } return changed; return changed; } } Loading Loading @@ -454,6 +550,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { @Override @Override public void setAutoMirrored(boolean mirrored) { public void setAutoMirrored(boolean mirrored) { mLayerState.mAutoMirrored = mirrored; mLayerState.mAutoMirrored = mirrored; final ChildDrawable[] array = mLayerState.mChildren; final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; final int N = mLayerState.mNum; for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) { Loading @@ -473,102 +570,134 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { @Override @Override protected boolean onStateChange(int[] state) { protected boolean onStateChange(int[] state) { final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; boolean paddingChanged = false; boolean paddingChanged = false; boolean changed = false; boolean changed = false; final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) { final ChildDrawable r = array[i]; final ChildDrawable r = array[i]; if (r.mDrawable.setState(state)) { if (r.mDrawable.setState(state)) { changed = true; changed = true; } } if (reapplyPadding(i, r)) { if (refreshChildPadding(i, r)) { paddingChanged = true; paddingChanged = true; } } } } if (paddingChanged) { if (paddingChanged) { onBoundsChange(getBounds()); invalidatePadding(); } } return changed; return changed; } } @Override @Override protected boolean onLevelChange(int level) { protected boolean onLevelChange(int level) { final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; boolean paddingChanged = false; boolean paddingChanged = false; boolean changed = false; boolean changed = false; final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) { final ChildDrawable r = array[i]; final ChildDrawable r = array[i]; if (r.mDrawable.setLevel(level)) { if (r.mDrawable.setLevel(level)) { changed = true; changed = true; } } if (reapplyPadding(i, r)) { if (refreshChildPadding(i, r)) { paddingChanged = true; paddingChanged = true; } } } } if (paddingChanged) { if (paddingChanged) { onBoundsChange(getBounds()); invalidatePadding(); } } return changed; return changed; } } @Override @Override protected void onBoundsChange(Rect bounds) { protected void onBoundsChange(Rect bounds) { int padL = 0; int padT = 0; int padR = 0; int padB = 0; final boolean nest = mLayerState.mPaddingMode == PADDING_MODE_NEST; final ChildDrawable[] array = mLayerState.mChildren; final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; final int N = mLayerState.mNum; int padL=0, padT=0, padR=0, padB=0; for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) { final ChildDrawable r = array[i]; final ChildDrawable r = array[i]; r.mDrawable.setBounds(bounds.left + r.mInsetL + padL, r.mDrawable.setBounds(bounds.left + r.mInsetL + padL, bounds.top + r.mInsetT + padT, bounds.top + r.mInsetT + padT, bounds.right - r.mInsetR - padR, bounds.bottom - r.mInsetB - padB); bounds.right - r.mInsetR - padR, bounds.bottom - r.mInsetB - padB); if (nest) { padL += mPaddingL[i]; padL += mPaddingL[i]; padR += mPaddingR[i]; padR += mPaddingR[i]; padT += mPaddingT[i]; padT += mPaddingT[i]; padB += mPaddingB[i]; padB += mPaddingB[i]; } } } } } @Override @Override public int getIntrinsicWidth() { public int getIntrinsicWidth() { int width = -1; int width = -1; int padL = 0; int padR = 0; final boolean nest = mLayerState.mPaddingMode == PADDING_MODE_NEST; final ChildDrawable[] array = mLayerState.mChildren; final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; final int N = mLayerState.mNum; int padL=0, padR=0; for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) { final ChildDrawable r = array[i]; final ChildDrawable r = array[i]; int w = r.mDrawable.getIntrinsicWidth() final int w = r.mDrawable.getIntrinsicWidth() + r.mInsetL + r.mInsetR + padL + padR; + r.mInsetL + r.mInsetR + padL + padR; if (w > width) { if (w > width) { width = w; width = w; } } if (nest) { padL += mPaddingL[i]; padL += mPaddingL[i]; padR += mPaddingR[i]; padR += mPaddingR[i]; } } } return width; return width; } } @Override @Override public int getIntrinsicHeight() { public int getIntrinsicHeight() { int height = -1; int height = -1; int padT = 0; int padB = 0; final boolean nest = mLayerState.mPaddingMode == PADDING_MODE_NEST; final ChildDrawable[] array = mLayerState.mChildren; final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; final int N = mLayerState.mNum; int padT=0, padB=0; for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) { final ChildDrawable r = array[i]; final ChildDrawable r = array[i]; int h = r.mDrawable.getIntrinsicHeight() + r.mInsetT + r.mInsetB + + padT + padB; int h = r.mDrawable.getIntrinsicHeight() + r.mInsetT + r.mInsetB + padT + padB; if (h > height) { if (h > height) { height = h; height = h; } } if (nest) { padT += mPaddingT[i]; padT += mPaddingT[i]; padB += mPaddingB[i]; padB += mPaddingB[i]; } } } return height; return height; } } private boolean reapplyPadding(int i, ChildDrawable r) { /** * Refreshes the cached padding values for the specified child. * * @return true if the child's padding has changed */ private boolean refreshChildPadding(int i, ChildDrawable r) { final Rect rect = mTmpRect; final Rect rect = mTmpRect; r.mDrawable.getPadding(rect); r.mDrawable.getPadding(rect); if (rect.left != mPaddingL[i] || rect.top != mPaddingT[i] || if (rect.left != mPaddingL[i] || rect.top != mPaddingT[i] || Loading @@ -582,11 +711,15 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { return false; return false; } } /** * Ensures the child padding caches are large enough. */ private void ensurePadding() { private void ensurePadding() { final int N = mLayerState.mNum; final int N = mLayerState.mNum; if (mPaddingL != null && mPaddingL.length >= N) { if (mPaddingL != null && mPaddingL.length >= N) { return; return; } } mPaddingL = new int[N]; mPaddingL = new int[N]; mPaddingT = new int[N]; mPaddingT = new int[N]; mPaddingR = new int[N]; mPaddingR = new int[N]; Loading Loading @@ -651,6 +784,8 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { private boolean mAutoMirrored; private boolean mAutoMirrored; private int mPaddingMode = PADDING_MODE_NEST; LayerState(LayerState orig, LayerDrawable owner, Resources res) { LayerState(LayerState orig, LayerDrawable owner, Resources res) { if (orig != null) { if (orig != null) { final ChildDrawable[] origChildDrawable = orig.mChildren; final ChildDrawable[] origChildDrawable = orig.mChildren; Loading Loading @@ -685,6 +820,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { mStateful = orig.mStateful; mStateful = orig.mStateful; mCheckedConstantState = mCanConstantState = true; mCheckedConstantState = mCanConstantState = true; mAutoMirrored = orig.mAutoMirrored; mAutoMirrored = orig.mAutoMirrored; mPaddingMode = orig.mPaddingMode; } else { } else { mNum = 0; mNum = 0; mChildren = null; mChildren = null; Loading Loading
api/current.txt +4 −0 Original line number Original line Diff line number Diff line Loading @@ -10365,6 +10365,7 @@ package android.graphics.drawable { method public int getId(int); method public int getId(int); method public int getNumberOfLayers(); method public int getNumberOfLayers(); method public int getOpacity(); method public int getOpacity(); method public int getPaddingMode(); method public void invalidateDrawable(android.graphics.drawable.Drawable); method public void invalidateDrawable(android.graphics.drawable.Drawable); method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long); method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long); method public void setAlpha(int); method public void setAlpha(int); Loading @@ -10373,7 +10374,10 @@ package android.graphics.drawable { method public void setId(int, int); method public void setId(int, int); method public void setLayerInset(int, int, int, int, int); method public void setLayerInset(int, int, int, int, int); method public void setOpacity(int); method public void setOpacity(int); method public void setPaddingMode(int); method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable); method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable); field public static final int PADDING_MODE_NEST = 0; // 0x0 field public static final int PADDING_MODE_STACK = 1; // 0x1 } } public class LevelListDrawable extends android.graphics.drawable.DrawableContainer { public class LevelListDrawable extends android.graphics.drawable.DrawableContainer {
core/res/res/values/attrs.xml +9 −1 Original line number Original line Diff line number Diff line Loading @@ -4241,6 +4241,14 @@ <!-- Indicates if the drawable needs to be mirrored when its layout direction is <!-- Indicates if the drawable needs to be mirrored when its layout direction is RTL (right-to-left). --> RTL (right-to-left). --> <attr name="autoMirrored" /> <attr name="autoMirrored" /> <!-- Indicates how layer padding should affect the bounds of subsequent layers. The default value is nest. --> <attr name="paddingMode"> <!-- Nest each layer inside the padding of the previous layer. --> <enum name="nest" value="0" /> <!-- Stack each layer directly atop the previous layer. --> <enum name="stack" value="1" /> </attr> </declare-styleable> </declare-styleable> <!-- Describes an item (or child) of a LayerDrawable. --> <!-- Describes an item (or child) of a LayerDrawable. --> Loading @@ -4256,7 +4264,7 @@ <!-- Drawable used to render the layer. --> <!-- Drawable used to render the layer. --> <attr name="drawable" /> <attr name="drawable" /> <!-- Identifier of the layer. This can be used to retrieve the layer <!-- Identifier of the layer. This can be used to retrieve the layer from a drawbable container. --> from a drawable container. --> <attr name="id" /> <attr name="id" /> </declare-styleable> </declare-styleable> Loading
graphics/java/android/graphics/drawable/LayerDrawable.java +229 −93 Original line number Original line Diff line number Diff line Loading @@ -47,6 +47,15 @@ import java.io.IOException; * @attr ref android.R.styleable#LayerDrawableItem_id * @attr ref android.R.styleable#LayerDrawableItem_id */ */ public class LayerDrawable extends Drawable implements Drawable.Callback { public class LayerDrawable extends Drawable implements Drawable.Callback { /** * Padding mode used to nest each layer inside the padding of the previous * layer. */ public static final int PADDING_MODE_NEST = 0; /** Padding mode used to stack each layer directly atop the previous layer. */ public static final int PADDING_MODE_STACK = 1; LayerState mLayerState; LayerState mLayerState; private int mOpacityOverride = PixelFormat.UNKNOWN; private int mOpacityOverride = PixelFormat.UNKNOWN; Loading @@ -55,8 +64,10 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { private int[] mPaddingR; private int[] mPaddingR; private int[] mPaddingB; private int[] mPaddingB; private final Rect mCachedPadding = new Rect(); private final Rect mTmpRect = new Rect(); private final Rect mTmpRect = new Rect(); private boolean mMutated; private boolean mMutated; private boolean mHasCachedPadding; /** /** * Create a new layer drawable with the list of specified layers. * Create a new layer drawable with the list of specified layers. Loading Loading @@ -122,6 +133,9 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { setAutoMirrored(a.getBoolean(com.android.internal.R.styleable.LayerDrawable_autoMirrored, setAutoMirrored(a.getBoolean(com.android.internal.R.styleable.LayerDrawable_autoMirrored, false)); false)); mLayerState.mPaddingMode = a.getInteger( com.android.internal.R.styleable.LayerDrawableItem_drawable, PADDING_MODE_NEST); a.recycle(); a.recycle(); final int innerDepth = parser.getDepth() + 1; final int innerDepth = parser.getDepth() + 1; Loading Loading @@ -187,19 +201,20 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { */ */ private void addLayer(Drawable layer, int id, int left, int top, int right, int bottom) { private void addLayer(Drawable layer, int id, int left, int top, int right, int bottom) { final LayerState st = mLayerState; final LayerState st = mLayerState; int N = st.mChildren != null ? st.mChildren.length : 0; final int N = st.mChildren != null ? st.mChildren.length : 0; int i = st.mNum; final int i = st.mNum; if (i >= N) { if (i >= N) { ChildDrawable[] nu = new ChildDrawable[N + 10]; final ChildDrawable[] nu = new ChildDrawable[N + 10]; if (i > 0) { if (i > 0) { System.arraycopy(st.mChildren, 0, nu, 0, i); System.arraycopy(st.mChildren, 0, nu, 0, i); } } st.mChildren = nu; st.mChildren = nu; } } mLayerState.mChildrenChangingConfigurations |= layer.getChangingConfigurations(); mLayerState.mChildrenChangingConfigurations |= layer.getChangingConfigurations(); ChildDrawable childDrawable = new ChildDrawable(); final ChildDrawable childDrawable = new ChildDrawable(); st.mChildren[i] = childDrawable; st.mChildren[i] = childDrawable; childDrawable.mId = id; childDrawable.mId = id; childDrawable.mDrawable = layer; childDrawable.mDrawable = layer; Loading @@ -221,8 +236,8 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { */ */ public Drawable findDrawableByLayerId(int id) { public Drawable findDrawableByLayerId(int id) { final ChildDrawable[] layers = mLayerState.mChildren; final ChildDrawable[] layers = mLayerState.mChildren; final int N = mLayerState.mNum; for (int i = mLayerState.mNum - 1; i >= 0; i--) { for (int i = 0; i < N; i--) { if (layers[i].mId == id) { if (layers[i].mId == id) { return layers[i].mDrawable; return layers[i].mDrawable; } } Loading Loading @@ -281,20 +296,29 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { */ */ public boolean setDrawableByLayerId(int id, Drawable drawable) { public boolean setDrawableByLayerId(int id, Drawable drawable) { final ChildDrawable[] layers = mLayerState.mChildren; final ChildDrawable[] layers = mLayerState.mChildren; final int N = mLayerState.mNum; for (int i = mLayerState.mNum - 1; i >= 0; i--) { for (int i = 0; i < N; i++) { if (layers[i].mId == id) { final ChildDrawable childDrawable = layers[i]; if (layers[i].mDrawable != null) { if (childDrawable.mId == id) { if (childDrawable.mDrawable != null) { if (drawable != null) { if (drawable != null) { Rect bounds = layers[i].mDrawable.getBounds(); final Rect bounds = childDrawable.mDrawable.getBounds(); drawable.setBounds(bounds); drawable.setBounds(bounds); } } layers[i].mDrawable.setCallback(null); childDrawable.mDrawable.setCallback(null); } } if (drawable != null) { if (drawable != null) { drawable.setCallback(this); drawable.setCallback(this); } } layers[i].mDrawable = drawable; childDrawable.mDrawable = drawable; if (refreshChildPadding(i, childDrawable)) { invalidatePadding(); } return true; return true; } } } } Loading @@ -302,22 +326,58 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { return false; return false; } } /** Specify modifiers to the bounds for the drawable[index]. /** left += l * Specifies the insets in pixels for the drawable at the specified index. top += t; * Insets are used to adjust the drawable bounds. right -= r; * bottom -= b; * @param index the index of the drawable to adjust * @param l number of pixels to add to the left bound * @param t number of pixels to add to the top bound * @param r number of pixels to subtract from the right bound * @param b number of pixels to subtract from the bottom bound */ */ public void setLayerInset(int index, int l, int t, int r, int b) { public void setLayerInset(int index, int l, int t, int r, int b) { ChildDrawable childDrawable = mLayerState.mChildren[index]; final ChildDrawable childDrawable = mLayerState.mChildren[index]; childDrawable.mInsetL = l; childDrawable.mInsetL = l; childDrawable.mInsetT = t; childDrawable.mInsetT = t; childDrawable.mInsetR = r; childDrawable.mInsetR = r; childDrawable.mInsetB = b; childDrawable.mInsetB = b; } } // overrides from Drawable.Callback /** * Specifies how layer padding should affect the bounds of subsequent * layers. The default value is {@link #PADDING_MODE_NEST}. * * @param mode padding mode, one of: * <ul> * <li>{@link #PADDING_MODE_NEST} * <li>{@link #PADDING_MODE_STACK} * </ul> */ public void setPaddingMode(int mode) { if (mLayerState.mPaddingMode != mode) { mLayerState.mPaddingMode = mode; invalidatePadding(); } } /** * @return the current padding mode * @see #setPaddingMode(int) */ public int getPaddingMode() { return mLayerState.mPaddingMode; } /** * Invalidates cached padding. */ private void invalidatePadding() { mHasCachedPadding = false; onBoundsChange(getBounds()); } @Override public void invalidateDrawable(Drawable who) { public void invalidateDrawable(Drawable who) { final Callback callback = getCallback(); final Callback callback = getCallback(); if (callback != null) { if (callback != null) { Loading @@ -325,6 +385,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { } } } } @Override public void scheduleDrawable(Drawable who, Runnable what, long when) { public void scheduleDrawable(Drawable who, Runnable what, long when) { final Callback callback = getCallback(); final Callback callback = getCallback(); if (callback != null) { if (callback != null) { Loading @@ -332,6 +393,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { } } } } @Override public void unscheduleDrawable(Drawable who, Runnable what) { public void unscheduleDrawable(Drawable who, Runnable what) { final Callback callback = getCallback(); final Callback callback = getCallback(); if (callback != null) { if (callback != null) { Loading @@ -339,8 +401,6 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { } } } } // overrides from Drawable @Override @Override public void draw(Canvas canvas) { public void draw(Canvas canvas) { final ChildDrawable[] array = mLayerState.mChildren; final ChildDrawable[] array = mLayerState.mChildren; Loading @@ -359,33 +419,69 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { @Override @Override public boolean getPadding(Rect padding) { public boolean getPadding(Rect padding) { // Arbitrarily get the padding from the first image. final Rect cachedPadding = mCachedPadding; // Technically we should maybe do something more intelligent, if (!mHasCachedPadding) { // like take the max padding of all the images. if (mLayerState.mPaddingMode == PADDING_MODE_NEST) { computeNestedPadding(cachedPadding); } else { computeStackedPadding(cachedPadding); } mHasCachedPadding = true; } padding.set(cachedPadding); return padding.left != 0 || padding.top != 0 || padding.right != 0 || padding.bottom != 0; } private void computeNestedPadding(Rect padding) { padding.left = 0; padding.left = 0; padding.top = 0; padding.top = 0; padding.right = 0; padding.right = 0; padding.bottom = 0; padding.bottom = 0; // Add all the padding. final ChildDrawable[] array = mLayerState.mChildren; final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; final int N = mLayerState.mNum; for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) { reapplyPadding(i, array[i]); refreshChildPadding(i, array[i]); padding.left += mPaddingL[i]; padding.left += mPaddingL[i]; padding.top += mPaddingT[i]; padding.top += mPaddingT[i]; padding.right += mPaddingR[i]; padding.right += mPaddingR[i]; padding.bottom += mPaddingB[i]; padding.bottom += mPaddingB[i]; } } return true; } private void computeStackedPadding(Rect padding) { padding.left = 0; padding.top = 0; padding.right = 0; padding.bottom = 0; // Take the max padding. final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; for (int i = 0; i < N; i++) { refreshChildPadding(i, array[i]); padding.left = Math.max(padding.left, mPaddingL[i]); padding.top = Math.max(padding.top, mPaddingT[i]); padding.right = Math.max(padding.right, mPaddingR[i]); padding.bottom = Math.max(padding.bottom, mPaddingB[i]); } } } @Override @Override public boolean setVisible(boolean visible, boolean restart) { public boolean setVisible(boolean visible, boolean restart) { boolean changed = super.setVisible(visible, restart); final boolean changed = super.setVisible(visible, restart); final ChildDrawable[] array = mLayerState.mChildren; final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; final int N = mLayerState.mNum; for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) { array[i].mDrawable.setVisible(visible, restart); array[i].mDrawable.setVisible(visible, restart); } } return changed; return changed; } } Loading Loading @@ -454,6 +550,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { @Override @Override public void setAutoMirrored(boolean mirrored) { public void setAutoMirrored(boolean mirrored) { mLayerState.mAutoMirrored = mirrored; mLayerState.mAutoMirrored = mirrored; final ChildDrawable[] array = mLayerState.mChildren; final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; final int N = mLayerState.mNum; for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) { Loading @@ -473,102 +570,134 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { @Override @Override protected boolean onStateChange(int[] state) { protected boolean onStateChange(int[] state) { final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; boolean paddingChanged = false; boolean paddingChanged = false; boolean changed = false; boolean changed = false; final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) { final ChildDrawable r = array[i]; final ChildDrawable r = array[i]; if (r.mDrawable.setState(state)) { if (r.mDrawable.setState(state)) { changed = true; changed = true; } } if (reapplyPadding(i, r)) { if (refreshChildPadding(i, r)) { paddingChanged = true; paddingChanged = true; } } } } if (paddingChanged) { if (paddingChanged) { onBoundsChange(getBounds()); invalidatePadding(); } } return changed; return changed; } } @Override @Override protected boolean onLevelChange(int level) { protected boolean onLevelChange(int level) { final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; boolean paddingChanged = false; boolean paddingChanged = false; boolean changed = false; boolean changed = false; final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) { final ChildDrawable r = array[i]; final ChildDrawable r = array[i]; if (r.mDrawable.setLevel(level)) { if (r.mDrawable.setLevel(level)) { changed = true; changed = true; } } if (reapplyPadding(i, r)) { if (refreshChildPadding(i, r)) { paddingChanged = true; paddingChanged = true; } } } } if (paddingChanged) { if (paddingChanged) { onBoundsChange(getBounds()); invalidatePadding(); } } return changed; return changed; } } @Override @Override protected void onBoundsChange(Rect bounds) { protected void onBoundsChange(Rect bounds) { int padL = 0; int padT = 0; int padR = 0; int padB = 0; final boolean nest = mLayerState.mPaddingMode == PADDING_MODE_NEST; final ChildDrawable[] array = mLayerState.mChildren; final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; final int N = mLayerState.mNum; int padL=0, padT=0, padR=0, padB=0; for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) { final ChildDrawable r = array[i]; final ChildDrawable r = array[i]; r.mDrawable.setBounds(bounds.left + r.mInsetL + padL, r.mDrawable.setBounds(bounds.left + r.mInsetL + padL, bounds.top + r.mInsetT + padT, bounds.top + r.mInsetT + padT, bounds.right - r.mInsetR - padR, bounds.bottom - r.mInsetB - padB); bounds.right - r.mInsetR - padR, bounds.bottom - r.mInsetB - padB); if (nest) { padL += mPaddingL[i]; padL += mPaddingL[i]; padR += mPaddingR[i]; padR += mPaddingR[i]; padT += mPaddingT[i]; padT += mPaddingT[i]; padB += mPaddingB[i]; padB += mPaddingB[i]; } } } } } @Override @Override public int getIntrinsicWidth() { public int getIntrinsicWidth() { int width = -1; int width = -1; int padL = 0; int padR = 0; final boolean nest = mLayerState.mPaddingMode == PADDING_MODE_NEST; final ChildDrawable[] array = mLayerState.mChildren; final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; final int N = mLayerState.mNum; int padL=0, padR=0; for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) { final ChildDrawable r = array[i]; final ChildDrawable r = array[i]; int w = r.mDrawable.getIntrinsicWidth() final int w = r.mDrawable.getIntrinsicWidth() + r.mInsetL + r.mInsetR + padL + padR; + r.mInsetL + r.mInsetR + padL + padR; if (w > width) { if (w > width) { width = w; width = w; } } if (nest) { padL += mPaddingL[i]; padL += mPaddingL[i]; padR += mPaddingR[i]; padR += mPaddingR[i]; } } } return width; return width; } } @Override @Override public int getIntrinsicHeight() { public int getIntrinsicHeight() { int height = -1; int height = -1; int padT = 0; int padB = 0; final boolean nest = mLayerState.mPaddingMode == PADDING_MODE_NEST; final ChildDrawable[] array = mLayerState.mChildren; final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; final int N = mLayerState.mNum; int padT=0, padB=0; for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) { final ChildDrawable r = array[i]; final ChildDrawable r = array[i]; int h = r.mDrawable.getIntrinsicHeight() + r.mInsetT + r.mInsetB + + padT + padB; int h = r.mDrawable.getIntrinsicHeight() + r.mInsetT + r.mInsetB + padT + padB; if (h > height) { if (h > height) { height = h; height = h; } } if (nest) { padT += mPaddingT[i]; padT += mPaddingT[i]; padB += mPaddingB[i]; padB += mPaddingB[i]; } } } return height; return height; } } private boolean reapplyPadding(int i, ChildDrawable r) { /** * Refreshes the cached padding values for the specified child. * * @return true if the child's padding has changed */ private boolean refreshChildPadding(int i, ChildDrawable r) { final Rect rect = mTmpRect; final Rect rect = mTmpRect; r.mDrawable.getPadding(rect); r.mDrawable.getPadding(rect); if (rect.left != mPaddingL[i] || rect.top != mPaddingT[i] || if (rect.left != mPaddingL[i] || rect.top != mPaddingT[i] || Loading @@ -582,11 +711,15 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { return false; return false; } } /** * Ensures the child padding caches are large enough. */ private void ensurePadding() { private void ensurePadding() { final int N = mLayerState.mNum; final int N = mLayerState.mNum; if (mPaddingL != null && mPaddingL.length >= N) { if (mPaddingL != null && mPaddingL.length >= N) { return; return; } } mPaddingL = new int[N]; mPaddingL = new int[N]; mPaddingT = new int[N]; mPaddingT = new int[N]; mPaddingR = new int[N]; mPaddingR = new int[N]; Loading Loading @@ -651,6 +784,8 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { private boolean mAutoMirrored; private boolean mAutoMirrored; private int mPaddingMode = PADDING_MODE_NEST; LayerState(LayerState orig, LayerDrawable owner, Resources res) { LayerState(LayerState orig, LayerDrawable owner, Resources res) { if (orig != null) { if (orig != null) { final ChildDrawable[] origChildDrawable = orig.mChildren; final ChildDrawable[] origChildDrawable = orig.mChildren; Loading Loading @@ -685,6 +820,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { mStateful = orig.mStateful; mStateful = orig.mStateful; mCheckedConstantState = mCanConstantState = true; mCheckedConstantState = mCanConstantState = true; mAutoMirrored = orig.mAutoMirrored; mAutoMirrored = orig.mAutoMirrored; mPaddingMode = orig.mPaddingMode; } else { } else { mNum = 0; mNum = 0; mChildren = null; mChildren = null; Loading