diff options
author | 2015-10-28 16:37:25 -0400 | |
---|---|---|
committer | 2015-10-28 16:37:25 -0400 | |
commit | 0cacad7023ad30ad886ef85751e9e39b10f846f9 (patch) | |
tree | 7941eb5be48c50f769d5aadfba20f1083372072b | |
parent | 5918519f972b4eedfc0e402b96cf8a288446deed (diff) |
Apply density scaling in LayerDrawable and subclasses
Bug: 25081461
Change-Id: I48e62caf5017ff2dd84cf62b68a828f4542b6ae5
-rw-r--r-- | graphics/java/android/graphics/drawable/LayerDrawable.java | 354 | ||||
-rw-r--r-- | graphics/java/android/graphics/drawable/RippleDrawable.java | 51 |
2 files changed, 278 insertions, 127 deletions
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java index 1a0ba6f2eabc..4368fe99030a 100644 --- a/graphics/java/android/graphics/drawable/LayerDrawable.java +++ b/graphics/java/android/graphics/drawable/LayerDrawable.java @@ -30,6 +30,7 @@ import android.graphics.PixelFormat; import android.graphics.PorterDuff.Mode; import android.graphics.Rect; import android.util.AttributeSet; +import android.util.DisplayMetrics; import android.util.LayoutDirection; import android.view.Gravity; import android.view.View; @@ -124,7 +125,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { final int length = layers.length; final ChildDrawable[] r = new ChildDrawable[length]; for (int i = 0; i < length; i++) { - r[i] = new ChildDrawable(); + r[i] = new ChildDrawable(mLayerState.mDensity); r[i].mDrawable = layers[i]; layers[i].setCallback(this); mLayerState.mChildrenChangingConfigurations |= layers[i].getChangingConfigurations(); @@ -140,6 +141,10 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { 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) { mLayerState = createConstantState(state, res); if (mLayerState.mNum > 0) { @@ -153,63 +158,78 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { } @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 { 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); updateStateFromTypedArray(a); 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); ensurePadding(); refreshPadding(); } - /** - * Initializes the constant state from the values in the typed array. - */ - private void updateStateFromTypedArray(TypedArray a) { + @Override + public void applyTheme(@NonNull Theme t) { + super.applyTheme(t); + final LayerState state = mLayerState; + if (state == null) { + return; + } - // Account for any configuration changes. - state.mChangingConfigurations |= a.getChangingConfigurations(); + final int densityDpi = t.getResources().getDisplayMetrics().densityDpi; + final int density = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi; + state.setDensity(density); - // Extract the theme attributes, if any. - state.mThemeAttrs = a.extractThemeAttrs(); + if (state.mThemeAttrs != null) { + 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++) { - 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; + final ChildDrawable layer = array[i]; + layer.setDensity(density); + + if (layer.mThemeAttrs != null) { + final TypedArray a = t.resolveAttributes( + layer.mThemeAttrs, R.styleable.LayerDrawableItem); + updateLayerFromTypedArray(layer, a); + a.recycle(); + } + + final Drawable d = layer.mDrawable; + if (d != null && d.canApplyTheme()) { + d.applyTheme(t); + + // Update cached mask of child changing configurations. + state.mChildrenChangingConfigurations |= d.getChangingConfigurations(); } } } @@ -217,7 +237,8 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { /** * 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 { final LayerState state = mLayerState; @@ -234,7 +255,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { continue; } - final ChildDrawable layer = new ChildDrawable(); + final ChildDrawable layer = new ChildDrawable(state.mDensity); final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.LayerDrawableItem); updateLayerFromTypedArray(layer, a); a.recycle(); @@ -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; // Account for any configuration changes. - state.mChildrenChangingConfigurations |= a.getChangingConfigurations(); + state.mChangingConfigurations |= a.getChangingConfigurations(); // Extract the theme attributes, if any. - layer.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); + state.mThemeAttrs = a.extractThemeAttrs(); - final Drawable dr = a.getDrawable(R.styleable.LayerDrawableItem_drawable); - if (dr != null) { - layer.mDrawable = dr; + final int N = a.getIndexCount(); + for (int i = 0; i < N; i++) { + 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); - + private void updateLayerFromTypedArray(@NonNull ChildDrawable layer, @NonNull TypedArray a) { final LayerState state = mLayerState; - if (state == null) { - return; - } - - if (state.mThemeAttrs != null) { - final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.LayerDrawable); - updateStateFromTypedArray(a); - a.recycle(); - } - final ChildDrawable[] array = state.mChildren; - final int N = state.mNum; - 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(); - } + // Account for any configuration changes. + state.mChildrenChangingConfigurations |= a.getChangingConfigurations(); - final Drawable d = layer.mDrawable; - if (d != null && d.canApplyTheme()) { - d.applyTheme(t); + // Extract the theme attributes, if any. + layer.mThemeAttrs = a.extractThemeAttrs(); - // Update cached mask of child changing configurations. - state.mChildrenChangingConfigurations |= d.getChangingConfigurations(); + final int N = a.getIndexCount(); + 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 @@ -368,7 +415,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { * @param layer The layer to add. * @return The index of the layer. */ - int addLayer(ChildDrawable layer) { + int addLayer(@NonNull ChildDrawable layer) { final LayerState st = mLayerState; final int N = st.mChildren != null ? st.mChildren.length : 0; final int i = st.mNum; @@ -418,7 +465,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { } private ChildDrawable createLayer(Drawable dr) { - final ChildDrawable layer = new ChildDrawable(); + final ChildDrawable layer = new ChildDrawable(mLayerState.mDensity); layer.mDrawable = dr; return layer; } @@ -1708,6 +1755,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { static class ChildDrawable { public Drawable mDrawable; public int[] mThemeAttrs; + public int mDensity = DisplayMetrics.DENSITY_DEFAULT; public int mInsetL, mInsetT, mInsetR, mInsetB; public int mInsetS = UNDEFINED_INSET; public int mInsetE = UNDEFINED_INSET; @@ -1716,11 +1764,12 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { public int mGravity = Gravity.NO_GRAVITY; public int mId = View.NO_ID; - ChildDrawable() { - // Default empty constructor. + ChildDrawable(int density) { + 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 clone; if (dr != null) { @@ -1750,19 +1799,58 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { mHeight = orig.mHeight; mGravity = orig.mGravity; 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() { return mThemeAttrs != null || (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 { + private int[] mThemeAttrs; + int mNum; ChildDrawable[] mChildren; - int[] mThemeAttrs; + int mDensity; + + // These values all correspond to mDensity. int mPaddingTop = -1; int mPaddingBottom = -1; int mPaddingLeft = -1; @@ -1784,7 +1872,19 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { 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) { final ChildDrawable[] origChildDrawable = orig.mChildren; final int N = orig.mNum; @@ -1814,12 +1914,56 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { mPaddingStart = orig.mPaddingStart; mPaddingEnd = orig.mPaddingEnd; mOpacityOverride = orig.mOpacityOverride; + + if (orig.mDensity != mDensity) { + applyDensityScaling(orig.mDensity, mDensity); + } } else { mNum = 0; 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 public boolean canApplyTheme() { if (mThemeAttrs != null || super.canApplyTheme()) { @@ -1844,7 +1988,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { } @Override - public Drawable newDrawable(Resources res) { + public Drawable newDrawable(@Nullable Resources res) { return new LayerDrawable(this, res); } diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java index 2690223e3e20..a196fad25b7e 100644 --- a/graphics/java/android/graphics/drawable/RippleDrawable.java +++ b/graphics/java/android/graphics/drawable/RippleDrawable.java @@ -409,18 +409,20 @@ public class RippleDrawable extends LayerDrawable { } @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 { final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.RippleDrawable); - updateStateFromTypedArray(a); - a.recycle(); // Force padding default to STACK before inflating. setPaddingMode(PADDING_MODE_STACK); + // Inflation will advance the XmlPullParser and AttributeSet. super.inflate(r, parser, attrs, theme); - setTargetDensity(r.getDisplayMetrics()); + updateStateFromTypedArray(a); + verifyRequiredAttributes(a); + a.recycle(); updateLocalState(); } @@ -461,7 +463,7 @@ public class RippleDrawable extends LayerDrawable { /** * 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; // Account for any configuration changes. @@ -477,11 +479,9 @@ public class RippleDrawable extends LayerDrawable { mState.mMaxRadius = a.getDimensionPixelSize( 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 || mState.mTouchThemeAttrs[R.styleable.RippleDrawable_color] == 0)) { throw new XmlPullParserException(a.getPositionDescription() + @@ -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 - public void applyTheme(Theme t) { + public void applyTheme(@NonNull Theme t) { super.applyTheme(t); final RippleState state = mState; @@ -515,6 +503,7 @@ public class RippleDrawable extends LayerDrawable { R.styleable.RippleDrawable); try { updateStateFromTypedArray(a); + verifyRequiredAttributes(a); } catch (XmlPullParserException e) { throw new RuntimeException(e); } finally { @@ -555,7 +544,8 @@ public class RippleDrawable extends LayerDrawable { 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); } @@ -1002,6 +992,23 @@ public class RippleDrawable extends LayerDrawable { mTouchThemeAttrs = origs.mTouchThemeAttrs; mColor = origs.mColor; 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); } } |