Loading graphics/java/android/graphics/drawable/LayerDrawable.java +249 −105 Original line number Original line Diff line number Diff line Loading @@ -30,6 +30,7 @@ import android.graphics.PixelFormat; import android.graphics.PorterDuff.Mode; import android.graphics.PorterDuff.Mode; import android.graphics.Rect; import android.graphics.Rect; import android.util.AttributeSet; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.LayoutDirection; import android.util.LayoutDirection; import android.view.Gravity; import android.view.Gravity; import android.view.View; import android.view.View; Loading Loading @@ -124,7 +125,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { final int length = layers.length; final int length = layers.length; final ChildDrawable[] r = new ChildDrawable[length]; final ChildDrawable[] r = new ChildDrawable[length]; for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) { r[i] = new ChildDrawable(); r[i] = new ChildDrawable(mLayerState.mDensity); r[i].mDrawable = layers[i]; r[i].mDrawable = layers[i]; layers[i].setCallback(this); layers[i].setCallback(this); mLayerState.mChildrenChangingConfigurations |= layers[i].getChangingConfigurations(); mLayerState.mChildrenChangingConfigurations |= layers[i].getChangingConfigurations(); Loading @@ -140,6 +141,10 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { this((LayerState) null, null); this((LayerState) null, null); } } /** * The one constructor to rule them all. This is called by all public * constructors to set the state and initialize local properties. */ LayerDrawable(@Nullable LayerState state, @Nullable Resources res) { LayerDrawable(@Nullable LayerState state, @Nullable Resources res) { mLayerState = createConstantState(state, res); mLayerState = createConstantState(state, res); if (mLayerState.mNum > 0) { if (mLayerState.mNum > 0) { Loading @@ -153,63 +158,78 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { } } @Override @Override public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme) public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, @Nullable Theme theme) throws XmlPullParserException, IOException { throws XmlPullParserException, IOException { super.inflate(r, parser, attrs, theme); super.inflate(r, parser, attrs, theme); final LayerState state = mLayerState; if (state == null) { return; } // The density may have changed since the last update. This will // apply scaling to any existing constant state properties. final int densityDpi = r.getDisplayMetrics().densityDpi; final int density = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi; state.setDensity(density); final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.LayerDrawable); final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.LayerDrawable); updateStateFromTypedArray(a); updateStateFromTypedArray(a); a.recycle(); a.recycle(); final ChildDrawable[] array = state.mChildren; final int N = state.mNum; for (int i = 0; i < N; i++) { final ChildDrawable layer = array[i]; layer.setDensity(density); } inflateLayers(r, parser, attrs, theme); inflateLayers(r, parser, attrs, theme); ensurePadding(); ensurePadding(); refreshPadding(); refreshPadding(); } } /** @Override * Initializes the constant state from the values in the typed array. public void applyTheme(@NonNull Theme t) { */ super.applyTheme(t); private void updateStateFromTypedArray(TypedArray a) { final LayerState state = mLayerState; final LayerState state = mLayerState; if (state == null) { return; } // Account for any configuration changes. final int densityDpi = t.getResources().getDisplayMetrics().densityDpi; state.mChangingConfigurations |= a.getChangingConfigurations(); final int density = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi; state.setDensity(density); // Extract the theme attributes, if any. if (state.mThemeAttrs != null) { state.mThemeAttrs = a.extractThemeAttrs(); final TypedArray a = t.resolveAttributes( state.mThemeAttrs, R.styleable.LayerDrawable); updateStateFromTypedArray(a); a.recycle(); } final int N = a.getIndexCount(); final ChildDrawable[] array = state.mChildren; final int N = state.mNum; for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) { int attr = a.getIndex(i); final ChildDrawable layer = array[i]; switch (attr) { layer.setDensity(density); case R.styleable.LayerDrawable_opacity: state.mOpacityOverride = a.getInt(attr, state.mOpacityOverride); if (layer.mThemeAttrs != null) { break; final TypedArray a = t.resolveAttributes( case R.styleable.LayerDrawable_paddingTop: layer.mThemeAttrs, R.styleable.LayerDrawableItem); state.mPaddingTop = a.getDimensionPixelOffset(attr, state.mPaddingTop); updateLayerFromTypedArray(layer, a); break; a.recycle(); case R.styleable.LayerDrawable_paddingBottom: } state.mPaddingBottom = a.getDimensionPixelOffset(attr, state.mPaddingBottom); break; final Drawable d = layer.mDrawable; case R.styleable.LayerDrawable_paddingLeft: if (d != null && d.canApplyTheme()) { state.mPaddingLeft = a.getDimensionPixelOffset(attr, state.mPaddingLeft); d.applyTheme(t); break; case R.styleable.LayerDrawable_paddingRight: // Update cached mask of child changing configurations. state.mPaddingRight = a.getDimensionPixelOffset(attr, state.mPaddingRight); state.mChildrenChangingConfigurations |= d.getChangingConfigurations(); break; case R.styleable.LayerDrawable_paddingStart: state.mPaddingStart = a.getDimensionPixelOffset(attr, state.mPaddingStart); break; case R.styleable.LayerDrawable_paddingEnd: state.mPaddingEnd = a.getDimensionPixelOffset(attr, state.mPaddingEnd); break; case R.styleable.LayerDrawable_autoMirrored: state.mAutoMirrored = a.getBoolean(attr, state.mAutoMirrored); break; case R.styleable.LayerDrawable_paddingMode: state.mPaddingMode = a.getInteger(attr, state.mPaddingMode); break; } } } } } } Loading @@ -217,7 +237,8 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { /** /** * Inflates child layers using the specified parser. * Inflates child layers using the specified parser. */ */ private void inflateLayers(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme) private void inflateLayers(@NonNull Resources r, @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, @Nullable Theme theme) throws XmlPullParserException, IOException { throws XmlPullParserException, IOException { final LayerState state = mLayerState; final LayerState state = mLayerState; Loading @@ -234,7 +255,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { continue; continue; } } final ChildDrawable layer = new ChildDrawable(); final ChildDrawable layer = new ChildDrawable(state.mDensity); final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.LayerDrawableItem); final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.LayerDrawableItem); updateLayerFromTypedArray(layer, a); updateLayerFromTypedArray(layer, a); a.recycle(); a.recycle(); Loading Loading @@ -264,77 +285,103 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { } } } } private void updateLayerFromTypedArray(ChildDrawable layer, TypedArray a) { /** * Initializes the constant state from the values in the typed array. */ private void updateStateFromTypedArray(@NonNull TypedArray a) { final LayerState state = mLayerState; final LayerState state = mLayerState; // Account for any configuration changes. // Account for any configuration changes. state.mChildrenChangingConfigurations |= a.getChangingConfigurations(); state.mChangingConfigurations |= a.getChangingConfigurations(); // Extract the theme attributes, if any. // Extract the theme attributes, if any. layer.mThemeAttrs = a.extractThemeAttrs(); state.mThemeAttrs = a.extractThemeAttrs(); layer.mInsetL = a.getDimensionPixelOffset( R.styleable.LayerDrawableItem_left, layer.mInsetL); layer.mInsetT = a.getDimensionPixelOffset( R.styleable.LayerDrawableItem_top, layer.mInsetT); layer.mInsetR = a.getDimensionPixelOffset( R.styleable.LayerDrawableItem_right, layer.mInsetR); layer.mInsetB = a.getDimensionPixelOffset( R.styleable.LayerDrawableItem_bottom, layer.mInsetB); layer.mInsetS = a.getDimensionPixelOffset( R.styleable.LayerDrawableItem_start, layer.mInsetS); layer.mInsetE = a.getDimensionPixelOffset( R.styleable.LayerDrawableItem_end, layer.mInsetE); layer.mWidth = a.getDimensionPixelSize( R.styleable.LayerDrawableItem_width, layer.mWidth); layer.mHeight = a.getDimensionPixelSize( R.styleable.LayerDrawableItem_height, layer.mHeight); layer.mGravity = a.getInteger( R.styleable.LayerDrawableItem_gravity, layer.mGravity); layer.mId = a.getResourceId(R.styleable.LayerDrawableItem_id, layer.mId); final Drawable dr = a.getDrawable(R.styleable.LayerDrawableItem_drawable); final int N = a.getIndexCount(); if (dr != null) { for (int i = 0; i < N; i++) { layer.mDrawable = dr; final int attr = a.getIndex(i); switch (attr) { case R.styleable.LayerDrawable_opacity: state.mOpacityOverride = a.getInt(attr, state.mOpacityOverride); break; case R.styleable.LayerDrawable_paddingTop: state.mPaddingTop = a.getDimensionPixelOffset(attr, state.mPaddingTop); break; case R.styleable.LayerDrawable_paddingBottom: state.mPaddingBottom = a.getDimensionPixelOffset(attr, state.mPaddingBottom); break; case R.styleable.LayerDrawable_paddingLeft: state.mPaddingLeft = a.getDimensionPixelOffset(attr, state.mPaddingLeft); break; case R.styleable.LayerDrawable_paddingRight: state.mPaddingRight = a.getDimensionPixelOffset(attr, state.mPaddingRight); break; case R.styleable.LayerDrawable_paddingStart: state.mPaddingStart = a.getDimensionPixelOffset(attr, state.mPaddingStart); break; case R.styleable.LayerDrawable_paddingEnd: state.mPaddingEnd = a.getDimensionPixelOffset(attr, state.mPaddingEnd); break; case R.styleable.LayerDrawable_autoMirrored: state.mAutoMirrored = a.getBoolean(attr, state.mAutoMirrored); break; case R.styleable.LayerDrawable_paddingMode: state.mPaddingMode = a.getInteger(attr, state.mPaddingMode); break; } } } } @Override public void applyTheme(Theme t) { super.applyTheme(t); final LayerState state = mLayerState; if (state == null) { return; } } if (state.mThemeAttrs != null) { private void updateLayerFromTypedArray(@NonNull ChildDrawable layer, @NonNull TypedArray a) { final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.LayerDrawable); final LayerState state = mLayerState; updateStateFromTypedArray(a); a.recycle(); } final ChildDrawable[] array = state.mChildren; // Account for any configuration changes. final int N = state.mNum; state.mChildrenChangingConfigurations |= a.getChangingConfigurations(); for (int i = 0; i < N; i++) { final ChildDrawable layer = array[i]; if (layer.mThemeAttrs != null) { final TypedArray a = t.resolveAttributes(layer.mThemeAttrs, R.styleable.LayerDrawableItem); updateLayerFromTypedArray(layer, a); a.recycle(); } final Drawable d = layer.mDrawable; // Extract the theme attributes, if any. if (d != null && d.canApplyTheme()) { layer.mThemeAttrs = a.extractThemeAttrs(); d.applyTheme(t); // Update cached mask of child changing configurations. final int N = a.getIndexCount(); state.mChildrenChangingConfigurations |= d.getChangingConfigurations(); for (int i = 0; i < N; i++) { final int attr = a.getIndex(i); switch (attr) { case R.styleable.LayerDrawableItem_left: layer.mInsetL = a.getDimensionPixelOffset(attr, layer.mInsetL); break; case R.styleable.LayerDrawableItem_top: layer.mInsetT = a.getDimensionPixelOffset(attr, layer.mInsetT); break; case R.styleable.LayerDrawableItem_right: layer.mInsetR = a.getDimensionPixelOffset(attr, layer.mInsetR); break; case R.styleable.LayerDrawableItem_bottom: layer.mInsetB = a.getDimensionPixelOffset(attr, layer.mInsetB); break; case R.styleable.LayerDrawableItem_start: layer.mInsetS = a.getDimensionPixelOffset(attr, layer.mInsetS); break; case R.styleable.LayerDrawableItem_end: layer.mInsetE = a.getDimensionPixelOffset(attr, layer.mInsetE); break; case R.styleable.LayerDrawableItem_width: layer.mWidth = a.getDimensionPixelSize(attr, layer.mWidth); break; case R.styleable.LayerDrawableItem_height: layer.mHeight = a.getDimensionPixelSize(attr, layer.mHeight); break; case R.styleable.LayerDrawableItem_gravity: layer.mGravity = a.getInteger(attr, layer.mGravity); break; case R.styleable.LayerDrawableItem_id: layer.mId = a.getResourceId(attr, layer.mId); break; } } } } ensurePadding(); final Drawable dr = a.getDrawable(R.styleable.LayerDrawableItem_drawable); if (dr != null) { layer.mDrawable = dr; } } } @Override @Override Loading Loading @@ -368,7 +415,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { * @param layer The layer to add. * @param layer The layer to add. * @return The index of the layer. * @return The index of the layer. */ */ int addLayer(ChildDrawable layer) { int addLayer(@NonNull ChildDrawable layer) { final LayerState st = mLayerState; final LayerState st = mLayerState; final int N = st.mChildren != null ? st.mChildren.length : 0; final int N = st.mChildren != null ? st.mChildren.length : 0; final int i = st.mNum; final int i = st.mNum; Loading Loading @@ -418,7 +465,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { } } private ChildDrawable createLayer(Drawable dr) { private ChildDrawable createLayer(Drawable dr) { final ChildDrawable layer = new ChildDrawable(); final ChildDrawable layer = new ChildDrawable(mLayerState.mDensity); layer.mDrawable = dr; layer.mDrawable = dr; return layer; return layer; } } Loading Loading @@ -1708,6 +1755,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { static class ChildDrawable { static class ChildDrawable { public Drawable mDrawable; public Drawable mDrawable; public int[] mThemeAttrs; public int[] mThemeAttrs; public int mDensity = DisplayMetrics.DENSITY_DEFAULT; public int mInsetL, mInsetT, mInsetR, mInsetB; public int mInsetL, mInsetT, mInsetR, mInsetB; public int mInsetS = UNDEFINED_INSET; public int mInsetS = UNDEFINED_INSET; public int mInsetE = UNDEFINED_INSET; public int mInsetE = UNDEFINED_INSET; Loading @@ -1716,11 +1764,12 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { public int mGravity = Gravity.NO_GRAVITY; public int mGravity = Gravity.NO_GRAVITY; public int mId = View.NO_ID; public int mId = View.NO_ID; ChildDrawable() { ChildDrawable(int density) { // Default empty constructor. mDensity = density; } } ChildDrawable(ChildDrawable orig, LayerDrawable owner, Resources res) { ChildDrawable(@NonNull ChildDrawable orig, @NonNull LayerDrawable owner, @Nullable Resources res) { final Drawable dr = orig.mDrawable; final Drawable dr = orig.mDrawable; final Drawable clone; final Drawable clone; if (dr != null) { if (dr != null) { Loading Loading @@ -1750,19 +1799,58 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { mHeight = orig.mHeight; mHeight = orig.mHeight; mGravity = orig.mGravity; mGravity = orig.mGravity; mId = orig.mId; mId = orig.mId; final int densityDpi = res == null ? orig.mDensity : res.getDisplayMetrics().densityDpi; mDensity = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi; if (orig.mDensity != mDensity) { applyDensityScaling(orig.mDensity, mDensity); } } } public boolean canApplyTheme() { public boolean canApplyTheme() { return mThemeAttrs != null return mThemeAttrs != null || (mDrawable != null && mDrawable.canApplyTheme()); || (mDrawable != null && mDrawable.canApplyTheme()); } } public final void setDensity(int targetDensity) { if (mDensity != targetDensity) { final int sourceDensity = mDensity; mDensity = targetDensity; applyDensityScaling(sourceDensity, targetDensity); } } private void applyDensityScaling(int sourceDensity, int targetDensity) { mInsetL = Bitmap.scaleFromDensity(mInsetL, sourceDensity, targetDensity); mInsetT = Bitmap.scaleFromDensity(mInsetT, sourceDensity, targetDensity); mInsetR = Bitmap.scaleFromDensity(mInsetR, sourceDensity, targetDensity); mInsetB = Bitmap.scaleFromDensity(mInsetB, sourceDensity, targetDensity); if (mInsetS != UNDEFINED_INSET) { mInsetS = Bitmap.scaleFromDensity(mInsetS, sourceDensity, targetDensity); } if (mInsetE != UNDEFINED_INSET) { mInsetE = Bitmap.scaleFromDensity(mInsetE, sourceDensity, targetDensity); } if (mWidth > 0) { mWidth = Bitmap.scaleFromDensity(mWidth, sourceDensity, targetDensity); } if (mHeight > 0) { mHeight = Bitmap.scaleFromDensity(mHeight, sourceDensity, targetDensity); } } } } static class LayerState extends ConstantState { static class LayerState extends ConstantState { private int[] mThemeAttrs; int mNum; int mNum; ChildDrawable[] mChildren; ChildDrawable[] mChildren; int[] mThemeAttrs; int mDensity; // These values all correspond to mDensity. int mPaddingTop = -1; int mPaddingTop = -1; int mPaddingBottom = -1; int mPaddingBottom = -1; int mPaddingLeft = -1; int mPaddingLeft = -1; Loading @@ -1784,7 +1872,19 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { private int mPaddingMode = PADDING_MODE_NEST; private int mPaddingMode = PADDING_MODE_NEST; LayerState(LayerState orig, LayerDrawable owner, Resources res) { LayerState(@Nullable LayerState orig, @NonNull LayerDrawable owner, @Nullable Resources res) { final int densityDpi; if (res != null) { densityDpi = res.getDisplayMetrics().densityDpi; } else if (orig != null) { densityDpi = orig.mDensity; } else { densityDpi = 0; } mDensity = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi; if (orig != null) { if (orig != null) { final ChildDrawable[] origChildDrawable = orig.mChildren; final ChildDrawable[] origChildDrawable = orig.mChildren; final int N = orig.mNum; final int N = orig.mNum; Loading Loading @@ -1814,12 +1914,56 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { mPaddingStart = orig.mPaddingStart; mPaddingStart = orig.mPaddingStart; mPaddingEnd = orig.mPaddingEnd; mPaddingEnd = orig.mPaddingEnd; mOpacityOverride = orig.mOpacityOverride; mOpacityOverride = orig.mOpacityOverride; if (orig.mDensity != mDensity) { applyDensityScaling(orig.mDensity, mDensity); } } else { } else { mNum = 0; mNum = 0; mChildren = null; mChildren = null; } } } } public final void setDensity(int targetDensity) { if (mDensity != targetDensity) { final int sourceDensity = mDensity; mDensity = targetDensity; onDensityChanged(sourceDensity, targetDensity); } } protected void onDensityChanged(int sourceDensity, int targetDensity) { applyDensityScaling(sourceDensity, targetDensity); } private void applyDensityScaling(int sourceDensity, int targetDensity) { if (mPaddingLeft > 0) { mPaddingLeft = Bitmap.scaleFromDensity( mPaddingLeft, sourceDensity, targetDensity); } if (mPaddingTop > 0) { mPaddingTop = Bitmap.scaleFromDensity( mPaddingTop, sourceDensity, targetDensity); } if (mPaddingRight > 0) { mPaddingRight = Bitmap.scaleFromDensity( mPaddingRight, sourceDensity, targetDensity); } if (mPaddingBottom > 0) { mPaddingBottom = Bitmap.scaleFromDensity( mPaddingBottom, sourceDensity, targetDensity); } if (mPaddingStart > 0) { mPaddingStart = Bitmap.scaleFromDensity( mPaddingStart, sourceDensity, targetDensity); } if (mPaddingEnd > 0) { mPaddingEnd = Bitmap.scaleFromDensity( mPaddingEnd, sourceDensity, targetDensity); } } @Override @Override public boolean canApplyTheme() { public boolean canApplyTheme() { if (mThemeAttrs != null || super.canApplyTheme()) { if (mThemeAttrs != null || super.canApplyTheme()) { Loading @@ -1844,7 +1988,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { } } @Override @Override public Drawable newDrawable(Resources res) { public Drawable newDrawable(@Nullable Resources res) { return new LayerDrawable(this, res); return new LayerDrawable(this, res); } } Loading graphics/java/android/graphics/drawable/RippleDrawable.java +29 −22 Original line number Original line Diff line number Diff line Loading @@ -409,18 +409,20 @@ public class RippleDrawable extends LayerDrawable { } } @Override @Override public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme) public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, @Nullable Theme theme) throws XmlPullParserException, IOException { throws XmlPullParserException, IOException { final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.RippleDrawable); final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.RippleDrawable); updateStateFromTypedArray(a); a.recycle(); // Force padding default to STACK before inflating. // Force padding default to STACK before inflating. setPaddingMode(PADDING_MODE_STACK); setPaddingMode(PADDING_MODE_STACK); // Inflation will advance the XmlPullParser and AttributeSet. super.inflate(r, parser, attrs, theme); super.inflate(r, parser, attrs, theme); setTargetDensity(r.getDisplayMetrics()); updateStateFromTypedArray(a); verifyRequiredAttributes(a); a.recycle(); updateLocalState(); updateLocalState(); } } Loading Loading @@ -461,7 +463,7 @@ public class RippleDrawable extends LayerDrawable { /** /** * Initializes the constant state from the values in the typed array. * Initializes the constant state from the values in the typed array. */ */ private void updateStateFromTypedArray(TypedArray a) throws XmlPullParserException { private void updateStateFromTypedArray(@NonNull TypedArray a) throws XmlPullParserException { final RippleState state = mState; final RippleState state = mState; // Account for any configuration changes. // Account for any configuration changes. Loading @@ -477,11 +479,9 @@ public class RippleDrawable extends LayerDrawable { mState.mMaxRadius = a.getDimensionPixelSize( mState.mMaxRadius = a.getDimensionPixelSize( R.styleable.RippleDrawable_radius, mState.mMaxRadius); R.styleable.RippleDrawable_radius, mState.mMaxRadius); verifyRequiredAttributes(a); } } private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException { private void verifyRequiredAttributes(@NonNull TypedArray a) throws XmlPullParserException { if (mState.mColor == null && (mState.mTouchThemeAttrs == null if (mState.mColor == null && (mState.mTouchThemeAttrs == null || mState.mTouchThemeAttrs[R.styleable.RippleDrawable_color] == 0)) { || mState.mTouchThemeAttrs[R.styleable.RippleDrawable_color] == 0)) { throw new XmlPullParserException(a.getPositionDescription() + throw new XmlPullParserException(a.getPositionDescription() + Loading @@ -489,20 +489,8 @@ public class RippleDrawable extends LayerDrawable { } } } } /** * Set the density at which this drawable will be rendered. * * @param metrics The display metrics for this drawable. */ private void setTargetDensity(DisplayMetrics metrics) { if (mDensity != metrics.density) { mDensity = metrics.density; invalidateSelf(false); } } @Override @Override public void applyTheme(Theme t) { public void applyTheme(@NonNull Theme t) { super.applyTheme(t); super.applyTheme(t); final RippleState state = mState; final RippleState state = mState; Loading @@ -515,6 +503,7 @@ public class RippleDrawable extends LayerDrawable { R.styleable.RippleDrawable); R.styleable.RippleDrawable); try { try { updateStateFromTypedArray(a); updateStateFromTypedArray(a); verifyRequiredAttributes(a); } catch (XmlPullParserException e) { } catch (XmlPullParserException e) { throw new RuntimeException(e); throw new RuntimeException(e); } finally { } finally { Loading Loading @@ -555,7 +544,8 @@ public class RippleDrawable extends LayerDrawable { mBackground = new RippleBackground(this, mHotspotBounds, mForceSoftware); mBackground = new RippleBackground(this, mHotspotBounds, mForceSoftware); } } mBackground.setup(mState.mMaxRadius, mDensity); final float densityScale = mState.mDensity * DisplayMetrics.DENSITY_DEFAULT_SCALE; mBackground.setup(mState.mMaxRadius, densityScale); mBackground.enter(focused); mBackground.enter(focused); } } Loading Loading @@ -1002,6 +992,23 @@ public class RippleDrawable extends LayerDrawable { mTouchThemeAttrs = origs.mTouchThemeAttrs; mTouchThemeAttrs = origs.mTouchThemeAttrs; mColor = origs.mColor; mColor = origs.mColor; mMaxRadius = origs.mMaxRadius; mMaxRadius = origs.mMaxRadius; if (origs.mDensity != mDensity) { applyDensityScaling(orig.mDensity, mDensity); } } } @Override protected void onDensityChanged(int sourceDensity, int targetDensity) { super.onDensityChanged(sourceDensity, targetDensity); applyDensityScaling(sourceDensity, targetDensity); } private void applyDensityScaling(int sourceDensity, int targetDensity) { if (mMaxRadius != RADIUS_AUTO) { mMaxRadius = Bitmap.scaleFromDensity(mMaxRadius, sourceDensity, targetDensity); } } } } Loading Loading
graphics/java/android/graphics/drawable/LayerDrawable.java +249 −105 Original line number Original line Diff line number Diff line Loading @@ -30,6 +30,7 @@ import android.graphics.PixelFormat; import android.graphics.PorterDuff.Mode; import android.graphics.PorterDuff.Mode; import android.graphics.Rect; import android.graphics.Rect; import android.util.AttributeSet; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.LayoutDirection; import android.util.LayoutDirection; import android.view.Gravity; import android.view.Gravity; import android.view.View; import android.view.View; Loading Loading @@ -124,7 +125,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { final int length = layers.length; final int length = layers.length; final ChildDrawable[] r = new ChildDrawable[length]; final ChildDrawable[] r = new ChildDrawable[length]; for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) { r[i] = new ChildDrawable(); r[i] = new ChildDrawable(mLayerState.mDensity); r[i].mDrawable = layers[i]; r[i].mDrawable = layers[i]; layers[i].setCallback(this); layers[i].setCallback(this); mLayerState.mChildrenChangingConfigurations |= layers[i].getChangingConfigurations(); mLayerState.mChildrenChangingConfigurations |= layers[i].getChangingConfigurations(); Loading @@ -140,6 +141,10 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { this((LayerState) null, null); this((LayerState) null, null); } } /** * The one constructor to rule them all. This is called by all public * constructors to set the state and initialize local properties. */ LayerDrawable(@Nullable LayerState state, @Nullable Resources res) { LayerDrawable(@Nullable LayerState state, @Nullable Resources res) { mLayerState = createConstantState(state, res); mLayerState = createConstantState(state, res); if (mLayerState.mNum > 0) { if (mLayerState.mNum > 0) { Loading @@ -153,63 +158,78 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { } } @Override @Override public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme) public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, @Nullable Theme theme) throws XmlPullParserException, IOException { throws XmlPullParserException, IOException { super.inflate(r, parser, attrs, theme); super.inflate(r, parser, attrs, theme); final LayerState state = mLayerState; if (state == null) { return; } // The density may have changed since the last update. This will // apply scaling to any existing constant state properties. final int densityDpi = r.getDisplayMetrics().densityDpi; final int density = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi; state.setDensity(density); final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.LayerDrawable); final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.LayerDrawable); updateStateFromTypedArray(a); updateStateFromTypedArray(a); a.recycle(); a.recycle(); final ChildDrawable[] array = state.mChildren; final int N = state.mNum; for (int i = 0; i < N; i++) { final ChildDrawable layer = array[i]; layer.setDensity(density); } inflateLayers(r, parser, attrs, theme); inflateLayers(r, parser, attrs, theme); ensurePadding(); ensurePadding(); refreshPadding(); refreshPadding(); } } /** @Override * Initializes the constant state from the values in the typed array. public void applyTheme(@NonNull Theme t) { */ super.applyTheme(t); private void updateStateFromTypedArray(TypedArray a) { final LayerState state = mLayerState; final LayerState state = mLayerState; if (state == null) { return; } // Account for any configuration changes. final int densityDpi = t.getResources().getDisplayMetrics().densityDpi; state.mChangingConfigurations |= a.getChangingConfigurations(); final int density = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi; state.setDensity(density); // Extract the theme attributes, if any. if (state.mThemeAttrs != null) { state.mThemeAttrs = a.extractThemeAttrs(); final TypedArray a = t.resolveAttributes( state.mThemeAttrs, R.styleable.LayerDrawable); updateStateFromTypedArray(a); a.recycle(); } final int N = a.getIndexCount(); final ChildDrawable[] array = state.mChildren; final int N = state.mNum; for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) { int attr = a.getIndex(i); final ChildDrawable layer = array[i]; switch (attr) { layer.setDensity(density); case R.styleable.LayerDrawable_opacity: state.mOpacityOverride = a.getInt(attr, state.mOpacityOverride); if (layer.mThemeAttrs != null) { break; final TypedArray a = t.resolveAttributes( case R.styleable.LayerDrawable_paddingTop: layer.mThemeAttrs, R.styleable.LayerDrawableItem); state.mPaddingTop = a.getDimensionPixelOffset(attr, state.mPaddingTop); updateLayerFromTypedArray(layer, a); break; a.recycle(); case R.styleable.LayerDrawable_paddingBottom: } state.mPaddingBottom = a.getDimensionPixelOffset(attr, state.mPaddingBottom); break; final Drawable d = layer.mDrawable; case R.styleable.LayerDrawable_paddingLeft: if (d != null && d.canApplyTheme()) { state.mPaddingLeft = a.getDimensionPixelOffset(attr, state.mPaddingLeft); d.applyTheme(t); break; case R.styleable.LayerDrawable_paddingRight: // Update cached mask of child changing configurations. state.mPaddingRight = a.getDimensionPixelOffset(attr, state.mPaddingRight); state.mChildrenChangingConfigurations |= d.getChangingConfigurations(); break; case R.styleable.LayerDrawable_paddingStart: state.mPaddingStart = a.getDimensionPixelOffset(attr, state.mPaddingStart); break; case R.styleable.LayerDrawable_paddingEnd: state.mPaddingEnd = a.getDimensionPixelOffset(attr, state.mPaddingEnd); break; case R.styleable.LayerDrawable_autoMirrored: state.mAutoMirrored = a.getBoolean(attr, state.mAutoMirrored); break; case R.styleable.LayerDrawable_paddingMode: state.mPaddingMode = a.getInteger(attr, state.mPaddingMode); break; } } } } } } Loading @@ -217,7 +237,8 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { /** /** * Inflates child layers using the specified parser. * Inflates child layers using the specified parser. */ */ private void inflateLayers(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme) private void inflateLayers(@NonNull Resources r, @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, @Nullable Theme theme) throws XmlPullParserException, IOException { throws XmlPullParserException, IOException { final LayerState state = mLayerState; final LayerState state = mLayerState; Loading @@ -234,7 +255,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { continue; continue; } } final ChildDrawable layer = new ChildDrawable(); final ChildDrawable layer = new ChildDrawable(state.mDensity); final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.LayerDrawableItem); final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.LayerDrawableItem); updateLayerFromTypedArray(layer, a); updateLayerFromTypedArray(layer, a); a.recycle(); a.recycle(); Loading Loading @@ -264,77 +285,103 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { } } } } private void updateLayerFromTypedArray(ChildDrawable layer, TypedArray a) { /** * Initializes the constant state from the values in the typed array. */ private void updateStateFromTypedArray(@NonNull TypedArray a) { final LayerState state = mLayerState; final LayerState state = mLayerState; // Account for any configuration changes. // Account for any configuration changes. state.mChildrenChangingConfigurations |= a.getChangingConfigurations(); state.mChangingConfigurations |= a.getChangingConfigurations(); // Extract the theme attributes, if any. // Extract the theme attributes, if any. layer.mThemeAttrs = a.extractThemeAttrs(); state.mThemeAttrs = a.extractThemeAttrs(); layer.mInsetL = a.getDimensionPixelOffset( R.styleable.LayerDrawableItem_left, layer.mInsetL); layer.mInsetT = a.getDimensionPixelOffset( R.styleable.LayerDrawableItem_top, layer.mInsetT); layer.mInsetR = a.getDimensionPixelOffset( R.styleable.LayerDrawableItem_right, layer.mInsetR); layer.mInsetB = a.getDimensionPixelOffset( R.styleable.LayerDrawableItem_bottom, layer.mInsetB); layer.mInsetS = a.getDimensionPixelOffset( R.styleable.LayerDrawableItem_start, layer.mInsetS); layer.mInsetE = a.getDimensionPixelOffset( R.styleable.LayerDrawableItem_end, layer.mInsetE); layer.mWidth = a.getDimensionPixelSize( R.styleable.LayerDrawableItem_width, layer.mWidth); layer.mHeight = a.getDimensionPixelSize( R.styleable.LayerDrawableItem_height, layer.mHeight); layer.mGravity = a.getInteger( R.styleable.LayerDrawableItem_gravity, layer.mGravity); layer.mId = a.getResourceId(R.styleable.LayerDrawableItem_id, layer.mId); final Drawable dr = a.getDrawable(R.styleable.LayerDrawableItem_drawable); final int N = a.getIndexCount(); if (dr != null) { for (int i = 0; i < N; i++) { layer.mDrawable = dr; final int attr = a.getIndex(i); switch (attr) { case R.styleable.LayerDrawable_opacity: state.mOpacityOverride = a.getInt(attr, state.mOpacityOverride); break; case R.styleable.LayerDrawable_paddingTop: state.mPaddingTop = a.getDimensionPixelOffset(attr, state.mPaddingTop); break; case R.styleable.LayerDrawable_paddingBottom: state.mPaddingBottom = a.getDimensionPixelOffset(attr, state.mPaddingBottom); break; case R.styleable.LayerDrawable_paddingLeft: state.mPaddingLeft = a.getDimensionPixelOffset(attr, state.mPaddingLeft); break; case R.styleable.LayerDrawable_paddingRight: state.mPaddingRight = a.getDimensionPixelOffset(attr, state.mPaddingRight); break; case R.styleable.LayerDrawable_paddingStart: state.mPaddingStart = a.getDimensionPixelOffset(attr, state.mPaddingStart); break; case R.styleable.LayerDrawable_paddingEnd: state.mPaddingEnd = a.getDimensionPixelOffset(attr, state.mPaddingEnd); break; case R.styleable.LayerDrawable_autoMirrored: state.mAutoMirrored = a.getBoolean(attr, state.mAutoMirrored); break; case R.styleable.LayerDrawable_paddingMode: state.mPaddingMode = a.getInteger(attr, state.mPaddingMode); break; } } } } @Override public void applyTheme(Theme t) { super.applyTheme(t); final LayerState state = mLayerState; if (state == null) { return; } } if (state.mThemeAttrs != null) { private void updateLayerFromTypedArray(@NonNull ChildDrawable layer, @NonNull TypedArray a) { final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.LayerDrawable); final LayerState state = mLayerState; updateStateFromTypedArray(a); a.recycle(); } final ChildDrawable[] array = state.mChildren; // Account for any configuration changes. final int N = state.mNum; state.mChildrenChangingConfigurations |= a.getChangingConfigurations(); for (int i = 0; i < N; i++) { final ChildDrawable layer = array[i]; if (layer.mThemeAttrs != null) { final TypedArray a = t.resolveAttributes(layer.mThemeAttrs, R.styleable.LayerDrawableItem); updateLayerFromTypedArray(layer, a); a.recycle(); } final Drawable d = layer.mDrawable; // Extract the theme attributes, if any. if (d != null && d.canApplyTheme()) { layer.mThemeAttrs = a.extractThemeAttrs(); d.applyTheme(t); // Update cached mask of child changing configurations. final int N = a.getIndexCount(); state.mChildrenChangingConfigurations |= d.getChangingConfigurations(); for (int i = 0; i < N; i++) { final int attr = a.getIndex(i); switch (attr) { case R.styleable.LayerDrawableItem_left: layer.mInsetL = a.getDimensionPixelOffset(attr, layer.mInsetL); break; case R.styleable.LayerDrawableItem_top: layer.mInsetT = a.getDimensionPixelOffset(attr, layer.mInsetT); break; case R.styleable.LayerDrawableItem_right: layer.mInsetR = a.getDimensionPixelOffset(attr, layer.mInsetR); break; case R.styleable.LayerDrawableItem_bottom: layer.mInsetB = a.getDimensionPixelOffset(attr, layer.mInsetB); break; case R.styleable.LayerDrawableItem_start: layer.mInsetS = a.getDimensionPixelOffset(attr, layer.mInsetS); break; case R.styleable.LayerDrawableItem_end: layer.mInsetE = a.getDimensionPixelOffset(attr, layer.mInsetE); break; case R.styleable.LayerDrawableItem_width: layer.mWidth = a.getDimensionPixelSize(attr, layer.mWidth); break; case R.styleable.LayerDrawableItem_height: layer.mHeight = a.getDimensionPixelSize(attr, layer.mHeight); break; case R.styleable.LayerDrawableItem_gravity: layer.mGravity = a.getInteger(attr, layer.mGravity); break; case R.styleable.LayerDrawableItem_id: layer.mId = a.getResourceId(attr, layer.mId); break; } } } } ensurePadding(); final Drawable dr = a.getDrawable(R.styleable.LayerDrawableItem_drawable); if (dr != null) { layer.mDrawable = dr; } } } @Override @Override Loading Loading @@ -368,7 +415,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { * @param layer The layer to add. * @param layer The layer to add. * @return The index of the layer. * @return The index of the layer. */ */ int addLayer(ChildDrawable layer) { int addLayer(@NonNull ChildDrawable layer) { final LayerState st = mLayerState; final LayerState st = mLayerState; final int N = st.mChildren != null ? st.mChildren.length : 0; final int N = st.mChildren != null ? st.mChildren.length : 0; final int i = st.mNum; final int i = st.mNum; Loading Loading @@ -418,7 +465,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { } } private ChildDrawable createLayer(Drawable dr) { private ChildDrawable createLayer(Drawable dr) { final ChildDrawable layer = new ChildDrawable(); final ChildDrawable layer = new ChildDrawable(mLayerState.mDensity); layer.mDrawable = dr; layer.mDrawable = dr; return layer; return layer; } } Loading Loading @@ -1708,6 +1755,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { static class ChildDrawable { static class ChildDrawable { public Drawable mDrawable; public Drawable mDrawable; public int[] mThemeAttrs; public int[] mThemeAttrs; public int mDensity = DisplayMetrics.DENSITY_DEFAULT; public int mInsetL, mInsetT, mInsetR, mInsetB; public int mInsetL, mInsetT, mInsetR, mInsetB; public int mInsetS = UNDEFINED_INSET; public int mInsetS = UNDEFINED_INSET; public int mInsetE = UNDEFINED_INSET; public int mInsetE = UNDEFINED_INSET; Loading @@ -1716,11 +1764,12 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { public int mGravity = Gravity.NO_GRAVITY; public int mGravity = Gravity.NO_GRAVITY; public int mId = View.NO_ID; public int mId = View.NO_ID; ChildDrawable() { ChildDrawable(int density) { // Default empty constructor. mDensity = density; } } ChildDrawable(ChildDrawable orig, LayerDrawable owner, Resources res) { ChildDrawable(@NonNull ChildDrawable orig, @NonNull LayerDrawable owner, @Nullable Resources res) { final Drawable dr = orig.mDrawable; final Drawable dr = orig.mDrawable; final Drawable clone; final Drawable clone; if (dr != null) { if (dr != null) { Loading Loading @@ -1750,19 +1799,58 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { mHeight = orig.mHeight; mHeight = orig.mHeight; mGravity = orig.mGravity; mGravity = orig.mGravity; mId = orig.mId; mId = orig.mId; final int densityDpi = res == null ? orig.mDensity : res.getDisplayMetrics().densityDpi; mDensity = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi; if (orig.mDensity != mDensity) { applyDensityScaling(orig.mDensity, mDensity); } } } public boolean canApplyTheme() { public boolean canApplyTheme() { return mThemeAttrs != null return mThemeAttrs != null || (mDrawable != null && mDrawable.canApplyTheme()); || (mDrawable != null && mDrawable.canApplyTheme()); } } public final void setDensity(int targetDensity) { if (mDensity != targetDensity) { final int sourceDensity = mDensity; mDensity = targetDensity; applyDensityScaling(sourceDensity, targetDensity); } } private void applyDensityScaling(int sourceDensity, int targetDensity) { mInsetL = Bitmap.scaleFromDensity(mInsetL, sourceDensity, targetDensity); mInsetT = Bitmap.scaleFromDensity(mInsetT, sourceDensity, targetDensity); mInsetR = Bitmap.scaleFromDensity(mInsetR, sourceDensity, targetDensity); mInsetB = Bitmap.scaleFromDensity(mInsetB, sourceDensity, targetDensity); if (mInsetS != UNDEFINED_INSET) { mInsetS = Bitmap.scaleFromDensity(mInsetS, sourceDensity, targetDensity); } if (mInsetE != UNDEFINED_INSET) { mInsetE = Bitmap.scaleFromDensity(mInsetE, sourceDensity, targetDensity); } if (mWidth > 0) { mWidth = Bitmap.scaleFromDensity(mWidth, sourceDensity, targetDensity); } if (mHeight > 0) { mHeight = Bitmap.scaleFromDensity(mHeight, sourceDensity, targetDensity); } } } } static class LayerState extends ConstantState { static class LayerState extends ConstantState { private int[] mThemeAttrs; int mNum; int mNum; ChildDrawable[] mChildren; ChildDrawable[] mChildren; int[] mThemeAttrs; int mDensity; // These values all correspond to mDensity. int mPaddingTop = -1; int mPaddingTop = -1; int mPaddingBottom = -1; int mPaddingBottom = -1; int mPaddingLeft = -1; int mPaddingLeft = -1; Loading @@ -1784,7 +1872,19 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { private int mPaddingMode = PADDING_MODE_NEST; private int mPaddingMode = PADDING_MODE_NEST; LayerState(LayerState orig, LayerDrawable owner, Resources res) { LayerState(@Nullable LayerState orig, @NonNull LayerDrawable owner, @Nullable Resources res) { final int densityDpi; if (res != null) { densityDpi = res.getDisplayMetrics().densityDpi; } else if (orig != null) { densityDpi = orig.mDensity; } else { densityDpi = 0; } mDensity = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi; if (orig != null) { if (orig != null) { final ChildDrawable[] origChildDrawable = orig.mChildren; final ChildDrawable[] origChildDrawable = orig.mChildren; final int N = orig.mNum; final int N = orig.mNum; Loading Loading @@ -1814,12 +1914,56 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { mPaddingStart = orig.mPaddingStart; mPaddingStart = orig.mPaddingStart; mPaddingEnd = orig.mPaddingEnd; mPaddingEnd = orig.mPaddingEnd; mOpacityOverride = orig.mOpacityOverride; mOpacityOverride = orig.mOpacityOverride; if (orig.mDensity != mDensity) { applyDensityScaling(orig.mDensity, mDensity); } } else { } else { mNum = 0; mNum = 0; mChildren = null; mChildren = null; } } } } public final void setDensity(int targetDensity) { if (mDensity != targetDensity) { final int sourceDensity = mDensity; mDensity = targetDensity; onDensityChanged(sourceDensity, targetDensity); } } protected void onDensityChanged(int sourceDensity, int targetDensity) { applyDensityScaling(sourceDensity, targetDensity); } private void applyDensityScaling(int sourceDensity, int targetDensity) { if (mPaddingLeft > 0) { mPaddingLeft = Bitmap.scaleFromDensity( mPaddingLeft, sourceDensity, targetDensity); } if (mPaddingTop > 0) { mPaddingTop = Bitmap.scaleFromDensity( mPaddingTop, sourceDensity, targetDensity); } if (mPaddingRight > 0) { mPaddingRight = Bitmap.scaleFromDensity( mPaddingRight, sourceDensity, targetDensity); } if (mPaddingBottom > 0) { mPaddingBottom = Bitmap.scaleFromDensity( mPaddingBottom, sourceDensity, targetDensity); } if (mPaddingStart > 0) { mPaddingStart = Bitmap.scaleFromDensity( mPaddingStart, sourceDensity, targetDensity); } if (mPaddingEnd > 0) { mPaddingEnd = Bitmap.scaleFromDensity( mPaddingEnd, sourceDensity, targetDensity); } } @Override @Override public boolean canApplyTheme() { public boolean canApplyTheme() { if (mThemeAttrs != null || super.canApplyTheme()) { if (mThemeAttrs != null || super.canApplyTheme()) { Loading @@ -1844,7 +1988,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { } } @Override @Override public Drawable newDrawable(Resources res) { public Drawable newDrawable(@Nullable Resources res) { return new LayerDrawable(this, res); return new LayerDrawable(this, res); } } Loading
graphics/java/android/graphics/drawable/RippleDrawable.java +29 −22 Original line number Original line Diff line number Diff line Loading @@ -409,18 +409,20 @@ public class RippleDrawable extends LayerDrawable { } } @Override @Override public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme) public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, @Nullable Theme theme) throws XmlPullParserException, IOException { throws XmlPullParserException, IOException { final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.RippleDrawable); final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.RippleDrawable); updateStateFromTypedArray(a); a.recycle(); // Force padding default to STACK before inflating. // Force padding default to STACK before inflating. setPaddingMode(PADDING_MODE_STACK); setPaddingMode(PADDING_MODE_STACK); // Inflation will advance the XmlPullParser and AttributeSet. super.inflate(r, parser, attrs, theme); super.inflate(r, parser, attrs, theme); setTargetDensity(r.getDisplayMetrics()); updateStateFromTypedArray(a); verifyRequiredAttributes(a); a.recycle(); updateLocalState(); updateLocalState(); } } Loading Loading @@ -461,7 +463,7 @@ public class RippleDrawable extends LayerDrawable { /** /** * Initializes the constant state from the values in the typed array. * Initializes the constant state from the values in the typed array. */ */ private void updateStateFromTypedArray(TypedArray a) throws XmlPullParserException { private void updateStateFromTypedArray(@NonNull TypedArray a) throws XmlPullParserException { final RippleState state = mState; final RippleState state = mState; // Account for any configuration changes. // Account for any configuration changes. Loading @@ -477,11 +479,9 @@ public class RippleDrawable extends LayerDrawable { mState.mMaxRadius = a.getDimensionPixelSize( mState.mMaxRadius = a.getDimensionPixelSize( R.styleable.RippleDrawable_radius, mState.mMaxRadius); R.styleable.RippleDrawable_radius, mState.mMaxRadius); verifyRequiredAttributes(a); } } private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException { private void verifyRequiredAttributes(@NonNull TypedArray a) throws XmlPullParserException { if (mState.mColor == null && (mState.mTouchThemeAttrs == null if (mState.mColor == null && (mState.mTouchThemeAttrs == null || mState.mTouchThemeAttrs[R.styleable.RippleDrawable_color] == 0)) { || mState.mTouchThemeAttrs[R.styleable.RippleDrawable_color] == 0)) { throw new XmlPullParserException(a.getPositionDescription() + throw new XmlPullParserException(a.getPositionDescription() + Loading @@ -489,20 +489,8 @@ public class RippleDrawable extends LayerDrawable { } } } } /** * Set the density at which this drawable will be rendered. * * @param metrics The display metrics for this drawable. */ private void setTargetDensity(DisplayMetrics metrics) { if (mDensity != metrics.density) { mDensity = metrics.density; invalidateSelf(false); } } @Override @Override public void applyTheme(Theme t) { public void applyTheme(@NonNull Theme t) { super.applyTheme(t); super.applyTheme(t); final RippleState state = mState; final RippleState state = mState; Loading @@ -515,6 +503,7 @@ public class RippleDrawable extends LayerDrawable { R.styleable.RippleDrawable); R.styleable.RippleDrawable); try { try { updateStateFromTypedArray(a); updateStateFromTypedArray(a); verifyRequiredAttributes(a); } catch (XmlPullParserException e) { } catch (XmlPullParserException e) { throw new RuntimeException(e); throw new RuntimeException(e); } finally { } finally { Loading Loading @@ -555,7 +544,8 @@ public class RippleDrawable extends LayerDrawable { mBackground = new RippleBackground(this, mHotspotBounds, mForceSoftware); mBackground = new RippleBackground(this, mHotspotBounds, mForceSoftware); } } mBackground.setup(mState.mMaxRadius, mDensity); final float densityScale = mState.mDensity * DisplayMetrics.DENSITY_DEFAULT_SCALE; mBackground.setup(mState.mMaxRadius, densityScale); mBackground.enter(focused); mBackground.enter(focused); } } Loading Loading @@ -1002,6 +992,23 @@ public class RippleDrawable extends LayerDrawable { mTouchThemeAttrs = origs.mTouchThemeAttrs; mTouchThemeAttrs = origs.mTouchThemeAttrs; mColor = origs.mColor; mColor = origs.mColor; mMaxRadius = origs.mMaxRadius; mMaxRadius = origs.mMaxRadius; if (origs.mDensity != mDensity) { applyDensityScaling(orig.mDensity, mDensity); } } } @Override protected void onDensityChanged(int sourceDensity, int targetDensity) { super.onDensityChanged(sourceDensity, targetDensity); applyDensityScaling(sourceDensity, targetDensity); } private void applyDensityScaling(int sourceDensity, int targetDensity) { if (mMaxRadius != RADIUS_AUTO) { mMaxRadius = Bitmap.scaleFromDensity(mMaxRadius, sourceDensity, targetDensity); } } } } Loading