Loading graphics/java/android/graphics/drawable/BitmapDrawable.java +2 −9 Original line number Diff line number Diff line Loading @@ -812,8 +812,7 @@ public class BitmapDrawable extends Drawable { setTileModeY(parseTileMode(tileModeY)); } final int densityDpi = r.getDisplayMetrics().densityDpi; state.mTargetDensity = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi; state.mTargetDensity = Drawable.resolveDensity(r, 0); } @Override Loading Loading @@ -975,13 +974,7 @@ public class BitmapDrawable extends Drawable { * after inflating or applying a theme. */ private void updateLocalState(Resources res) { if (res != null) { final int densityDpi = res.getDisplayMetrics().densityDpi; mTargetDensity = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi; } else { mTargetDensity = mBitmapState.mTargetDensity; } mTargetDensity = resolveDensity(res, mBitmapState.mTargetDensity); mTintFilter = updateTintFilter(mTintFilter, mBitmapState.mTint, mBitmapState.mTintMode); computeBitmapSize(); } Loading graphics/java/android/graphics/drawable/Drawable.java +60 −2 Original line number Diff line number Diff line Loading @@ -1079,8 +1079,7 @@ public abstract class Drawable { // to the compatibility density only to have them scaled back up when // drawn to the screen. if (opts == null) opts = new BitmapFactory.Options(); opts.inScreenDensity = res != null ? res.getDisplayMetrics().noncompatDensityDpi : DisplayMetrics.DENSITY_DEVICE; opts.inScreenDensity = Drawable.resolveDensity(res, 0); Bitmap bm = BitmapFactory.decodeResourceStream(res, value, is, pad, opts); if (bm != null) { byte[] np = bm.getNinePatchChunk(); Loading Loading @@ -1337,6 +1336,65 @@ public abstract class Drawable { return theme.obtainStyledAttributes(set, attrs, 0, 0); } /** * Scales a floating-point pixel value from the source density to the * target density. * * @param pixels the pixel value for use in source density * @param sourceDensity the source density * @param targetDensity the target density * @return the scaled pixel value for use in target density */ static float scaleFromDensity(float pixels, int sourceDensity, int targetDensity) { return pixels * targetDensity / sourceDensity; } /** * Scales a pixel value from the source density to the target density, * optionally handling the resulting pixel value as a size rather than an * offset. * <p> * A size conversion involves rounding the base value and ensuring that * a non-zero base value is at least one pixel in size. * <p> * An offset conversion involves simply truncating the base value to an * integer. * * @param pixels the pixel value for use in source density * @param sourceDensity the source density * @param targetDensity the target density * @param isSize {@code true} to handle the resulting scaled value as a * size, or {@code false} to handle it as an offset * @return the scaled pixel value for use in target density */ static int scaleFromDensity( int pixels, int sourceDensity, int targetDensity, boolean isSize) { if (pixels == 0 || sourceDensity == targetDensity) { return pixels; } final float result = pixels * targetDensity / (float) sourceDensity; if (!isSize) { return (int) result; } final int rounded = Math.round(result); if (rounded != 0) { return rounded; } else if (pixels == 0) { return 0; } else if (pixels > 0) { return 1; } else { return -1; } } static int resolveDensity(@NonNull Resources r, int parentDensity) { final int densityDpi = r == null ? parentDensity : r.getDisplayMetrics().densityDpi; return densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi; } /** * Parses a {@link android.graphics.PorterDuff.Mode} from a tintMode * attribute's enum value. Loading graphics/java/android/graphics/drawable/DrawableContainer.java +7 −14 Original line number Diff line number Diff line Loading @@ -701,13 +701,8 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { DrawableContainerState(DrawableContainerState orig, DrawableContainer owner, Resources res) { mOwner = owner; final Resources sourceRes = res != null ? res : (orig != null ? orig.mSourceRes : null); mSourceRes = sourceRes; final int densityDpi = sourceRes == null ? 0 : sourceRes.getDisplayMetrics().densityDpi; final int sourceDensity = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi; mDensity = sourceDensity; mSourceRes = res != null ? res : (orig != null ? orig.mSourceRes : null); mDensity = Drawable.resolveDensity(res, orig != null ? orig.mDensity : 0); if (orig != null) { mChangingConfigurations = orig.mChangingConfigurations; Loading @@ -731,7 +726,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { mHasTintList = orig.mHasTintList; mHasTintMode = orig.mHasTintMode; if (orig.mDensity == sourceDensity) { if (orig.mDensity == mDensity) { if (orig.mCheckedPadding) { mConstantPadding = new Rect(orig.mConstantPadding); mCheckedPadding = true; Loading Loading @@ -903,13 +898,11 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { // The density may have changed since the last update (if any). Any // dimension-type attributes will need their default values scaled. final int densityDpi = res.getDisplayMetrics().densityDpi; final int newSourceDensity = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi; final int oldSourceDensity = mDensity; mDensity = newSourceDensity; final int targetDensity = Drawable.resolveDensity(res, mDensity); final int sourceDensity = mDensity; mDensity = targetDensity; if (oldSourceDensity != newSourceDensity) { if (sourceDensity != targetDensity) { mCheckedConstantSize = false; mCheckedPadding = false; } Loading graphics/java/android/graphics/drawable/GradientDrawable.java +163 −52 Original line number Diff line number Diff line Loading @@ -17,11 +17,13 @@ package android.graphics.drawable; import android.annotation.ColorInt; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.res.ColorStateList; import android.content.res.Resources; import android.content.res.Resources.Theme; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.ColorFilter; Loading @@ -40,6 +42,7 @@ import android.graphics.RectF; import android.graphics.Shader; import android.graphics.SweepGradient; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; import android.util.TypedValue; Loading Loading @@ -1136,10 +1139,14 @@ public class GradientDrawable extends Drawable { } @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); mGradientState.setDensity(Drawable.resolveDensity(r, 0)); final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.GradientDrawable); super.inflateWithAttributes(r, parser, a, R.styleable.GradientDrawable_visible); updateStateFromTypedArray(a); a.recycle(); Loading @@ -1149,7 +1156,7 @@ public class GradientDrawable extends Drawable { } @Override public void applyTheme(Theme t) { public void applyTheme(@NonNull Theme t) { super.applyTheme(t); final GradientState state = mGradientState; Loading @@ -1157,6 +1164,8 @@ public class GradientDrawable extends Drawable { return; } state.setDensity(Drawable.resolveDensity(t.getResources(), 0)); if (state.mThemeAttrs != null) { final TypedArray a = t.resolveAttributes( state.mThemeAttrs, R.styleable.GradientDrawable); Loading Loading @@ -1668,7 +1677,7 @@ public class GradientDrawable extends Drawable { @Override public Drawable mutate() { if (!mMutated && super.mutate() == this) { mGradientState = new GradientState(mGradientState); mGradientState = new GradientState(mGradientState, null); updateLocalState(null); mMutated = true; } Loading Loading @@ -1723,6 +1732,8 @@ public class GradientDrawable extends Drawable { ColorStateList mTint = null; PorterDuff.Mode mTintMode = DEFAULT_TINT_MODE; int mDensity = DisplayMetrics.DENSITY_DEFAULT; int[] mThemeAttrs; int[] mAttrSize; int[] mAttrGradient; Loading @@ -1736,55 +1747,145 @@ public class GradientDrawable extends Drawable { setGradientColors(gradientColors); } public GradientState(GradientState state) { mChangingConfigurations = state.mChangingConfigurations; mShape = state.mShape; mGradient = state.mGradient; mAngle = state.mAngle; mOrientation = state.mOrientation; mSolidColors = state.mSolidColors; if (state.mGradientColors != null) { mGradientColors = state.mGradientColors.clone(); } if (state.mPositions != null) { mPositions = state.mPositions.clone(); } mStrokeColors = state.mStrokeColors; mStrokeWidth = state.mStrokeWidth; mStrokeDashWidth = state.mStrokeDashWidth; mStrokeDashGap = state.mStrokeDashGap; mRadius = state.mRadius; if (state.mRadiusArray != null) { mRadiusArray = state.mRadiusArray.clone(); } if (state.mPadding != null) { mPadding = new Rect(state.mPadding); } mWidth = state.mWidth; mHeight = state.mHeight; mInnerRadiusRatio = state.mInnerRadiusRatio; mThicknessRatio = state.mThicknessRatio; mInnerRadius = state.mInnerRadius; mThickness = state.mThickness; mDither = state.mDither; mOpticalInsets = state.mOpticalInsets; mCenterX = state.mCenterX; mCenterY = state.mCenterY; mGradientRadius = state.mGradientRadius; mGradientRadiusType = state.mGradientRadiusType; mUseLevel = state.mUseLevel; mUseLevelForShape = state.mUseLevelForShape; mOpaqueOverBounds = state.mOpaqueOverBounds; mOpaqueOverShape = state.mOpaqueOverShape; mTint = state.mTint; mTintMode = state.mTintMode; mThemeAttrs = state.mThemeAttrs; mAttrSize = state.mAttrSize; mAttrGradient = state.mAttrGradient; mAttrSolid = state.mAttrSolid; mAttrStroke = state.mAttrStroke; mAttrCorners = state.mAttrCorners; mAttrPadding = state.mAttrPadding; public GradientState(@NonNull GradientState orig, @Nullable Resources res) { mChangingConfigurations = orig.mChangingConfigurations; mShape = orig.mShape; mGradient = orig.mGradient; mAngle = orig.mAngle; mOrientation = orig.mOrientation; mSolidColors = orig.mSolidColors; if (orig.mGradientColors != null) { mGradientColors = orig.mGradientColors.clone(); } if (orig.mPositions != null) { mPositions = orig.mPositions.clone(); } mStrokeColors = orig.mStrokeColors; mStrokeWidth = orig.mStrokeWidth; mStrokeDashWidth = orig.mStrokeDashWidth; mStrokeDashGap = orig.mStrokeDashGap; mRadius = orig.mRadius; if (orig.mRadiusArray != null) { mRadiusArray = orig.mRadiusArray.clone(); } if (orig.mPadding != null) { mPadding = new Rect(orig.mPadding); } mWidth = orig.mWidth; mHeight = orig.mHeight; mInnerRadiusRatio = orig.mInnerRadiusRatio; mThicknessRatio = orig.mThicknessRatio; mInnerRadius = orig.mInnerRadius; mThickness = orig.mThickness; mDither = orig.mDither; mOpticalInsets = orig.mOpticalInsets; mCenterX = orig.mCenterX; mCenterY = orig.mCenterY; mGradientRadius = orig.mGradientRadius; mGradientRadiusType = orig.mGradientRadiusType; mUseLevel = orig.mUseLevel; mUseLevelForShape = orig.mUseLevelForShape; mOpaqueOverBounds = orig.mOpaqueOverBounds; mOpaqueOverShape = orig.mOpaqueOverShape; mTint = orig.mTint; mTintMode = orig.mTintMode; mThemeAttrs = orig.mThemeAttrs; mAttrSize = orig.mAttrSize; mAttrGradient = orig.mAttrGradient; mAttrSolid = orig.mAttrSolid; mAttrStroke = orig.mAttrStroke; mAttrCorners = orig.mAttrCorners; mAttrPadding = orig.mAttrPadding; mDensity = Drawable.resolveDensity(res, orig.mDensity); if (orig.mDensity != mDensity) { applyDensityScaling(orig.mDensity, mDensity); } } /** * Sets the constant state density. * <p> * If the density has been previously set, dispatches the change to * subclasses so that density-dependent properties may be scaled as * necessary. * * @param targetDensity the new constant state density */ 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) { if (mInnerRadius > 0) { mInnerRadius = Drawable.scaleFromDensity( mInnerRadius, sourceDensity, targetDensity, true); } if (mThickness > 0) { mThickness = Drawable.scaleFromDensity( mThickness, sourceDensity, targetDensity, true); } if (mOpticalInsets != Insets.NONE) { final int left = Drawable.scaleFromDensity( mOpticalInsets.left, sourceDensity, targetDensity, true); final int top = Drawable.scaleFromDensity( mOpticalInsets.top, sourceDensity, targetDensity, true); final int right = Drawable.scaleFromDensity( mOpticalInsets.right, sourceDensity, targetDensity, true); final int bottom = Drawable.scaleFromDensity( mOpticalInsets.bottom, sourceDensity, targetDensity, true); mOpticalInsets = Insets.of(left, top, right, bottom); } if (mPadding != null) { mPadding.left = Drawable.scaleFromDensity( mPadding.left, sourceDensity, targetDensity, false); mPadding.top = Drawable.scaleFromDensity( mPadding.top, sourceDensity, targetDensity, false); mPadding.right = Drawable.scaleFromDensity( mPadding.right, sourceDensity, targetDensity, false); mPadding.bottom = Drawable.scaleFromDensity( mPadding.bottom, sourceDensity, targetDensity, false); } if (mRadius > 0) { mRadius = Drawable.scaleFromDensity(mRadius, sourceDensity, targetDensity); } if (mRadiusArray != null) { mRadiusArray[0] = Drawable.scaleFromDensity( (int) mRadiusArray[0], sourceDensity, targetDensity, true); mRadiusArray[1] = Drawable.scaleFromDensity( (int) mRadiusArray[1], sourceDensity, targetDensity, true); mRadiusArray[2] = Drawable.scaleFromDensity( (int) mRadiusArray[2], sourceDensity, targetDensity, true); mRadiusArray[3] = Drawable.scaleFromDensity( (int) mRadiusArray[3], sourceDensity, targetDensity, true); } if (mStrokeWidth > 0) { mStrokeWidth = Drawable.scaleFromDensity( mStrokeWidth, sourceDensity, targetDensity, true); } if (mStrokeDashWidth > 0) { mStrokeDashWidth = Drawable.scaleFromDensity( mStrokeDashGap, sourceDensity, targetDensity); } if (mStrokeDashGap > 0) { mStrokeDashGap = Drawable.scaleFromDensity( mStrokeDashGap, sourceDensity, targetDensity); } if (mGradientRadiusType == RADIUS_TYPE_PIXELS) { mGradientRadius = Drawable.scaleFromDensity( mGradientRadius, sourceDensity, targetDensity); } if (mWidth > 0) { mWidth = Drawable.scaleFromDensity(mWidth, sourceDensity, targetDensity, true); } if (mHeight > 0) { mHeight = Drawable.scaleFromDensity(mHeight, sourceDensity, targetDensity, true); } } @Override Loading @@ -1805,8 +1906,18 @@ public class GradientDrawable extends Drawable { } @Override public Drawable newDrawable(Resources res) { return new GradientDrawable(this, res); public Drawable newDrawable(@Nullable Resources res) { // If this drawable is being created for a different density, // just create a new constant state and call it a day. final GradientState state; final int density = Drawable.resolveDensity(res, mDensity); if (density != mDensity) { state = new GradientState(this, res); } else { state = this; } return new GradientDrawable(state, res); } @Override Loading Loading @@ -1913,7 +2024,7 @@ public class GradientDrawable extends Drawable { * * @param state Constant state from which the drawable inherits */ private GradientDrawable(GradientState state, Resources res) { private GradientDrawable(@NonNull GradientState state, @Nullable Resources res) { mGradientState = state; updateLocalState(res); Loading graphics/java/android/graphics/drawable/LayerDrawable.java +24 −37 Original line number Diff line number Diff line Loading @@ -170,8 +170,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { // 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; final int density = Drawable.resolveDensity(r, 0); state.setDensity(density); final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.LayerDrawable); Loading Loading @@ -200,8 +199,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { return; } final int densityDpi = t.getResources().getDisplayMetrics().densityDpi; final int density = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi; final int density = Drawable.resolveDensity(t.getResources(), 0); state.setDensity(density); if (state.mThemeAttrs != null) { Loading Loading @@ -1800,9 +1798,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { mGravity = orig.mGravity; mId = orig.mId; final int densityDpi = res == null ? orig.mDensity : res.getDisplayMetrics().densityDpi; mDensity = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi; mDensity = Drawable.resolveDensity(res, orig.mDensity); if (orig.mDensity != mDensity) { applyDensityScaling(orig.mDensity, mDensity); } Loading @@ -1823,21 +1819,21 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { } 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); mInsetL = Drawable.scaleFromDensity(mInsetL, sourceDensity, targetDensity, false); mInsetT = Drawable.scaleFromDensity(mInsetT, sourceDensity, targetDensity, false); mInsetR = Drawable.scaleFromDensity(mInsetR, sourceDensity, targetDensity, false); mInsetB = Drawable.scaleFromDensity(mInsetB, sourceDensity, targetDensity, false); if (mInsetS != UNDEFINED_INSET) { mInsetS = Bitmap.scaleFromDensity(mInsetS, sourceDensity, targetDensity); mInsetS = Drawable.scaleFromDensity(mInsetS, sourceDensity, targetDensity, false); } if (mInsetE != UNDEFINED_INSET) { mInsetE = Bitmap.scaleFromDensity(mInsetE, sourceDensity, targetDensity); mInsetE = Drawable.scaleFromDensity(mInsetE, sourceDensity, targetDensity, false); } if (mWidth > 0) { mWidth = Bitmap.scaleFromDensity(mWidth, sourceDensity, targetDensity); mWidth = Drawable.scaleFromDensity(mWidth, sourceDensity, targetDensity, true); } if (mHeight > 0) { mHeight = Bitmap.scaleFromDensity(mHeight, sourceDensity, targetDensity); mHeight = Drawable.scaleFromDensity(mHeight, sourceDensity, targetDensity, true); } } } Loading Loading @@ -1874,16 +1870,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { 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; mDensity = Drawable.resolveDensity(res, orig != null ? orig.mDensity : 0); if (orig != null) { final ChildDrawable[] origChildDrawable = orig.mChildren; Loading Loading @@ -1939,28 +1926,28 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { private void applyDensityScaling(int sourceDensity, int targetDensity) { if (mPaddingLeft > 0) { mPaddingLeft = Bitmap.scaleFromDensity( mPaddingLeft, sourceDensity, targetDensity); mPaddingLeft = Drawable.scaleFromDensity( mPaddingLeft, sourceDensity, targetDensity, false); } if (mPaddingTop > 0) { mPaddingTop = Bitmap.scaleFromDensity( mPaddingTop, sourceDensity, targetDensity); mPaddingTop = Drawable.scaleFromDensity( mPaddingTop, sourceDensity, targetDensity, false); } if (mPaddingRight > 0) { mPaddingRight = Bitmap.scaleFromDensity( mPaddingRight, sourceDensity, targetDensity); mPaddingRight = Drawable.scaleFromDensity( mPaddingRight, sourceDensity, targetDensity, false); } if (mPaddingBottom > 0) { mPaddingBottom = Bitmap.scaleFromDensity( mPaddingBottom, sourceDensity, targetDensity); mPaddingBottom = Drawable.scaleFromDensity( mPaddingBottom, sourceDensity, targetDensity, false); } if (mPaddingStart > 0) { mPaddingStart = Bitmap.scaleFromDensity( mPaddingStart, sourceDensity, targetDensity); mPaddingStart = Drawable.scaleFromDensity( mPaddingStart, sourceDensity, targetDensity, false); } if (mPaddingEnd > 0) { mPaddingEnd = Bitmap.scaleFromDensity( mPaddingEnd, sourceDensity, targetDensity); mPaddingEnd = Drawable.scaleFromDensity( mPaddingEnd, sourceDensity, targetDensity, false); } } Loading Loading
graphics/java/android/graphics/drawable/BitmapDrawable.java +2 −9 Original line number Diff line number Diff line Loading @@ -812,8 +812,7 @@ public class BitmapDrawable extends Drawable { setTileModeY(parseTileMode(tileModeY)); } final int densityDpi = r.getDisplayMetrics().densityDpi; state.mTargetDensity = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi; state.mTargetDensity = Drawable.resolveDensity(r, 0); } @Override Loading Loading @@ -975,13 +974,7 @@ public class BitmapDrawable extends Drawable { * after inflating or applying a theme. */ private void updateLocalState(Resources res) { if (res != null) { final int densityDpi = res.getDisplayMetrics().densityDpi; mTargetDensity = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi; } else { mTargetDensity = mBitmapState.mTargetDensity; } mTargetDensity = resolveDensity(res, mBitmapState.mTargetDensity); mTintFilter = updateTintFilter(mTintFilter, mBitmapState.mTint, mBitmapState.mTintMode); computeBitmapSize(); } Loading
graphics/java/android/graphics/drawable/Drawable.java +60 −2 Original line number Diff line number Diff line Loading @@ -1079,8 +1079,7 @@ public abstract class Drawable { // to the compatibility density only to have them scaled back up when // drawn to the screen. if (opts == null) opts = new BitmapFactory.Options(); opts.inScreenDensity = res != null ? res.getDisplayMetrics().noncompatDensityDpi : DisplayMetrics.DENSITY_DEVICE; opts.inScreenDensity = Drawable.resolveDensity(res, 0); Bitmap bm = BitmapFactory.decodeResourceStream(res, value, is, pad, opts); if (bm != null) { byte[] np = bm.getNinePatchChunk(); Loading Loading @@ -1337,6 +1336,65 @@ public abstract class Drawable { return theme.obtainStyledAttributes(set, attrs, 0, 0); } /** * Scales a floating-point pixel value from the source density to the * target density. * * @param pixels the pixel value for use in source density * @param sourceDensity the source density * @param targetDensity the target density * @return the scaled pixel value for use in target density */ static float scaleFromDensity(float pixels, int sourceDensity, int targetDensity) { return pixels * targetDensity / sourceDensity; } /** * Scales a pixel value from the source density to the target density, * optionally handling the resulting pixel value as a size rather than an * offset. * <p> * A size conversion involves rounding the base value and ensuring that * a non-zero base value is at least one pixel in size. * <p> * An offset conversion involves simply truncating the base value to an * integer. * * @param pixels the pixel value for use in source density * @param sourceDensity the source density * @param targetDensity the target density * @param isSize {@code true} to handle the resulting scaled value as a * size, or {@code false} to handle it as an offset * @return the scaled pixel value for use in target density */ static int scaleFromDensity( int pixels, int sourceDensity, int targetDensity, boolean isSize) { if (pixels == 0 || sourceDensity == targetDensity) { return pixels; } final float result = pixels * targetDensity / (float) sourceDensity; if (!isSize) { return (int) result; } final int rounded = Math.round(result); if (rounded != 0) { return rounded; } else if (pixels == 0) { return 0; } else if (pixels > 0) { return 1; } else { return -1; } } static int resolveDensity(@NonNull Resources r, int parentDensity) { final int densityDpi = r == null ? parentDensity : r.getDisplayMetrics().densityDpi; return densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi; } /** * Parses a {@link android.graphics.PorterDuff.Mode} from a tintMode * attribute's enum value. Loading
graphics/java/android/graphics/drawable/DrawableContainer.java +7 −14 Original line number Diff line number Diff line Loading @@ -701,13 +701,8 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { DrawableContainerState(DrawableContainerState orig, DrawableContainer owner, Resources res) { mOwner = owner; final Resources sourceRes = res != null ? res : (orig != null ? orig.mSourceRes : null); mSourceRes = sourceRes; final int densityDpi = sourceRes == null ? 0 : sourceRes.getDisplayMetrics().densityDpi; final int sourceDensity = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi; mDensity = sourceDensity; mSourceRes = res != null ? res : (orig != null ? orig.mSourceRes : null); mDensity = Drawable.resolveDensity(res, orig != null ? orig.mDensity : 0); if (orig != null) { mChangingConfigurations = orig.mChangingConfigurations; Loading @@ -731,7 +726,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { mHasTintList = orig.mHasTintList; mHasTintMode = orig.mHasTintMode; if (orig.mDensity == sourceDensity) { if (orig.mDensity == mDensity) { if (orig.mCheckedPadding) { mConstantPadding = new Rect(orig.mConstantPadding); mCheckedPadding = true; Loading Loading @@ -903,13 +898,11 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { // The density may have changed since the last update (if any). Any // dimension-type attributes will need their default values scaled. final int densityDpi = res.getDisplayMetrics().densityDpi; final int newSourceDensity = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi; final int oldSourceDensity = mDensity; mDensity = newSourceDensity; final int targetDensity = Drawable.resolveDensity(res, mDensity); final int sourceDensity = mDensity; mDensity = targetDensity; if (oldSourceDensity != newSourceDensity) { if (sourceDensity != targetDensity) { mCheckedConstantSize = false; mCheckedPadding = false; } Loading
graphics/java/android/graphics/drawable/GradientDrawable.java +163 −52 Original line number Diff line number Diff line Loading @@ -17,11 +17,13 @@ package android.graphics.drawable; import android.annotation.ColorInt; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.res.ColorStateList; import android.content.res.Resources; import android.content.res.Resources.Theme; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.ColorFilter; Loading @@ -40,6 +42,7 @@ import android.graphics.RectF; import android.graphics.Shader; import android.graphics.SweepGradient; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; import android.util.TypedValue; Loading Loading @@ -1136,10 +1139,14 @@ public class GradientDrawable extends Drawable { } @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); mGradientState.setDensity(Drawable.resolveDensity(r, 0)); final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.GradientDrawable); super.inflateWithAttributes(r, parser, a, R.styleable.GradientDrawable_visible); updateStateFromTypedArray(a); a.recycle(); Loading @@ -1149,7 +1156,7 @@ public class GradientDrawable extends Drawable { } @Override public void applyTheme(Theme t) { public void applyTheme(@NonNull Theme t) { super.applyTheme(t); final GradientState state = mGradientState; Loading @@ -1157,6 +1164,8 @@ public class GradientDrawable extends Drawable { return; } state.setDensity(Drawable.resolveDensity(t.getResources(), 0)); if (state.mThemeAttrs != null) { final TypedArray a = t.resolveAttributes( state.mThemeAttrs, R.styleable.GradientDrawable); Loading Loading @@ -1668,7 +1677,7 @@ public class GradientDrawable extends Drawable { @Override public Drawable mutate() { if (!mMutated && super.mutate() == this) { mGradientState = new GradientState(mGradientState); mGradientState = new GradientState(mGradientState, null); updateLocalState(null); mMutated = true; } Loading Loading @@ -1723,6 +1732,8 @@ public class GradientDrawable extends Drawable { ColorStateList mTint = null; PorterDuff.Mode mTintMode = DEFAULT_TINT_MODE; int mDensity = DisplayMetrics.DENSITY_DEFAULT; int[] mThemeAttrs; int[] mAttrSize; int[] mAttrGradient; Loading @@ -1736,55 +1747,145 @@ public class GradientDrawable extends Drawable { setGradientColors(gradientColors); } public GradientState(GradientState state) { mChangingConfigurations = state.mChangingConfigurations; mShape = state.mShape; mGradient = state.mGradient; mAngle = state.mAngle; mOrientation = state.mOrientation; mSolidColors = state.mSolidColors; if (state.mGradientColors != null) { mGradientColors = state.mGradientColors.clone(); } if (state.mPositions != null) { mPositions = state.mPositions.clone(); } mStrokeColors = state.mStrokeColors; mStrokeWidth = state.mStrokeWidth; mStrokeDashWidth = state.mStrokeDashWidth; mStrokeDashGap = state.mStrokeDashGap; mRadius = state.mRadius; if (state.mRadiusArray != null) { mRadiusArray = state.mRadiusArray.clone(); } if (state.mPadding != null) { mPadding = new Rect(state.mPadding); } mWidth = state.mWidth; mHeight = state.mHeight; mInnerRadiusRatio = state.mInnerRadiusRatio; mThicknessRatio = state.mThicknessRatio; mInnerRadius = state.mInnerRadius; mThickness = state.mThickness; mDither = state.mDither; mOpticalInsets = state.mOpticalInsets; mCenterX = state.mCenterX; mCenterY = state.mCenterY; mGradientRadius = state.mGradientRadius; mGradientRadiusType = state.mGradientRadiusType; mUseLevel = state.mUseLevel; mUseLevelForShape = state.mUseLevelForShape; mOpaqueOverBounds = state.mOpaqueOverBounds; mOpaqueOverShape = state.mOpaqueOverShape; mTint = state.mTint; mTintMode = state.mTintMode; mThemeAttrs = state.mThemeAttrs; mAttrSize = state.mAttrSize; mAttrGradient = state.mAttrGradient; mAttrSolid = state.mAttrSolid; mAttrStroke = state.mAttrStroke; mAttrCorners = state.mAttrCorners; mAttrPadding = state.mAttrPadding; public GradientState(@NonNull GradientState orig, @Nullable Resources res) { mChangingConfigurations = orig.mChangingConfigurations; mShape = orig.mShape; mGradient = orig.mGradient; mAngle = orig.mAngle; mOrientation = orig.mOrientation; mSolidColors = orig.mSolidColors; if (orig.mGradientColors != null) { mGradientColors = orig.mGradientColors.clone(); } if (orig.mPositions != null) { mPositions = orig.mPositions.clone(); } mStrokeColors = orig.mStrokeColors; mStrokeWidth = orig.mStrokeWidth; mStrokeDashWidth = orig.mStrokeDashWidth; mStrokeDashGap = orig.mStrokeDashGap; mRadius = orig.mRadius; if (orig.mRadiusArray != null) { mRadiusArray = orig.mRadiusArray.clone(); } if (orig.mPadding != null) { mPadding = new Rect(orig.mPadding); } mWidth = orig.mWidth; mHeight = orig.mHeight; mInnerRadiusRatio = orig.mInnerRadiusRatio; mThicknessRatio = orig.mThicknessRatio; mInnerRadius = orig.mInnerRadius; mThickness = orig.mThickness; mDither = orig.mDither; mOpticalInsets = orig.mOpticalInsets; mCenterX = orig.mCenterX; mCenterY = orig.mCenterY; mGradientRadius = orig.mGradientRadius; mGradientRadiusType = orig.mGradientRadiusType; mUseLevel = orig.mUseLevel; mUseLevelForShape = orig.mUseLevelForShape; mOpaqueOverBounds = orig.mOpaqueOverBounds; mOpaqueOverShape = orig.mOpaqueOverShape; mTint = orig.mTint; mTintMode = orig.mTintMode; mThemeAttrs = orig.mThemeAttrs; mAttrSize = orig.mAttrSize; mAttrGradient = orig.mAttrGradient; mAttrSolid = orig.mAttrSolid; mAttrStroke = orig.mAttrStroke; mAttrCorners = orig.mAttrCorners; mAttrPadding = orig.mAttrPadding; mDensity = Drawable.resolveDensity(res, orig.mDensity); if (orig.mDensity != mDensity) { applyDensityScaling(orig.mDensity, mDensity); } } /** * Sets the constant state density. * <p> * If the density has been previously set, dispatches the change to * subclasses so that density-dependent properties may be scaled as * necessary. * * @param targetDensity the new constant state density */ 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) { if (mInnerRadius > 0) { mInnerRadius = Drawable.scaleFromDensity( mInnerRadius, sourceDensity, targetDensity, true); } if (mThickness > 0) { mThickness = Drawable.scaleFromDensity( mThickness, sourceDensity, targetDensity, true); } if (mOpticalInsets != Insets.NONE) { final int left = Drawable.scaleFromDensity( mOpticalInsets.left, sourceDensity, targetDensity, true); final int top = Drawable.scaleFromDensity( mOpticalInsets.top, sourceDensity, targetDensity, true); final int right = Drawable.scaleFromDensity( mOpticalInsets.right, sourceDensity, targetDensity, true); final int bottom = Drawable.scaleFromDensity( mOpticalInsets.bottom, sourceDensity, targetDensity, true); mOpticalInsets = Insets.of(left, top, right, bottom); } if (mPadding != null) { mPadding.left = Drawable.scaleFromDensity( mPadding.left, sourceDensity, targetDensity, false); mPadding.top = Drawable.scaleFromDensity( mPadding.top, sourceDensity, targetDensity, false); mPadding.right = Drawable.scaleFromDensity( mPadding.right, sourceDensity, targetDensity, false); mPadding.bottom = Drawable.scaleFromDensity( mPadding.bottom, sourceDensity, targetDensity, false); } if (mRadius > 0) { mRadius = Drawable.scaleFromDensity(mRadius, sourceDensity, targetDensity); } if (mRadiusArray != null) { mRadiusArray[0] = Drawable.scaleFromDensity( (int) mRadiusArray[0], sourceDensity, targetDensity, true); mRadiusArray[1] = Drawable.scaleFromDensity( (int) mRadiusArray[1], sourceDensity, targetDensity, true); mRadiusArray[2] = Drawable.scaleFromDensity( (int) mRadiusArray[2], sourceDensity, targetDensity, true); mRadiusArray[3] = Drawable.scaleFromDensity( (int) mRadiusArray[3], sourceDensity, targetDensity, true); } if (mStrokeWidth > 0) { mStrokeWidth = Drawable.scaleFromDensity( mStrokeWidth, sourceDensity, targetDensity, true); } if (mStrokeDashWidth > 0) { mStrokeDashWidth = Drawable.scaleFromDensity( mStrokeDashGap, sourceDensity, targetDensity); } if (mStrokeDashGap > 0) { mStrokeDashGap = Drawable.scaleFromDensity( mStrokeDashGap, sourceDensity, targetDensity); } if (mGradientRadiusType == RADIUS_TYPE_PIXELS) { mGradientRadius = Drawable.scaleFromDensity( mGradientRadius, sourceDensity, targetDensity); } if (mWidth > 0) { mWidth = Drawable.scaleFromDensity(mWidth, sourceDensity, targetDensity, true); } if (mHeight > 0) { mHeight = Drawable.scaleFromDensity(mHeight, sourceDensity, targetDensity, true); } } @Override Loading @@ -1805,8 +1906,18 @@ public class GradientDrawable extends Drawable { } @Override public Drawable newDrawable(Resources res) { return new GradientDrawable(this, res); public Drawable newDrawable(@Nullable Resources res) { // If this drawable is being created for a different density, // just create a new constant state and call it a day. final GradientState state; final int density = Drawable.resolveDensity(res, mDensity); if (density != mDensity) { state = new GradientState(this, res); } else { state = this; } return new GradientDrawable(state, res); } @Override Loading Loading @@ -1913,7 +2024,7 @@ public class GradientDrawable extends Drawable { * * @param state Constant state from which the drawable inherits */ private GradientDrawable(GradientState state, Resources res) { private GradientDrawable(@NonNull GradientState state, @Nullable Resources res) { mGradientState = state; updateLocalState(res); Loading
graphics/java/android/graphics/drawable/LayerDrawable.java +24 −37 Original line number Diff line number Diff line Loading @@ -170,8 +170,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { // 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; final int density = Drawable.resolveDensity(r, 0); state.setDensity(density); final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.LayerDrawable); Loading Loading @@ -200,8 +199,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { return; } final int densityDpi = t.getResources().getDisplayMetrics().densityDpi; final int density = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi; final int density = Drawable.resolveDensity(t.getResources(), 0); state.setDensity(density); if (state.mThemeAttrs != null) { Loading Loading @@ -1800,9 +1798,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { mGravity = orig.mGravity; mId = orig.mId; final int densityDpi = res == null ? orig.mDensity : res.getDisplayMetrics().densityDpi; mDensity = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi; mDensity = Drawable.resolveDensity(res, orig.mDensity); if (orig.mDensity != mDensity) { applyDensityScaling(orig.mDensity, mDensity); } Loading @@ -1823,21 +1819,21 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { } 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); mInsetL = Drawable.scaleFromDensity(mInsetL, sourceDensity, targetDensity, false); mInsetT = Drawable.scaleFromDensity(mInsetT, sourceDensity, targetDensity, false); mInsetR = Drawable.scaleFromDensity(mInsetR, sourceDensity, targetDensity, false); mInsetB = Drawable.scaleFromDensity(mInsetB, sourceDensity, targetDensity, false); if (mInsetS != UNDEFINED_INSET) { mInsetS = Bitmap.scaleFromDensity(mInsetS, sourceDensity, targetDensity); mInsetS = Drawable.scaleFromDensity(mInsetS, sourceDensity, targetDensity, false); } if (mInsetE != UNDEFINED_INSET) { mInsetE = Bitmap.scaleFromDensity(mInsetE, sourceDensity, targetDensity); mInsetE = Drawable.scaleFromDensity(mInsetE, sourceDensity, targetDensity, false); } if (mWidth > 0) { mWidth = Bitmap.scaleFromDensity(mWidth, sourceDensity, targetDensity); mWidth = Drawable.scaleFromDensity(mWidth, sourceDensity, targetDensity, true); } if (mHeight > 0) { mHeight = Bitmap.scaleFromDensity(mHeight, sourceDensity, targetDensity); mHeight = Drawable.scaleFromDensity(mHeight, sourceDensity, targetDensity, true); } } } Loading Loading @@ -1874,16 +1870,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { 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; mDensity = Drawable.resolveDensity(res, orig != null ? orig.mDensity : 0); if (orig != null) { final ChildDrawable[] origChildDrawable = orig.mChildren; Loading Loading @@ -1939,28 +1926,28 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { private void applyDensityScaling(int sourceDensity, int targetDensity) { if (mPaddingLeft > 0) { mPaddingLeft = Bitmap.scaleFromDensity( mPaddingLeft, sourceDensity, targetDensity); mPaddingLeft = Drawable.scaleFromDensity( mPaddingLeft, sourceDensity, targetDensity, false); } if (mPaddingTop > 0) { mPaddingTop = Bitmap.scaleFromDensity( mPaddingTop, sourceDensity, targetDensity); mPaddingTop = Drawable.scaleFromDensity( mPaddingTop, sourceDensity, targetDensity, false); } if (mPaddingRight > 0) { mPaddingRight = Bitmap.scaleFromDensity( mPaddingRight, sourceDensity, targetDensity); mPaddingRight = Drawable.scaleFromDensity( mPaddingRight, sourceDensity, targetDensity, false); } if (mPaddingBottom > 0) { mPaddingBottom = Bitmap.scaleFromDensity( mPaddingBottom, sourceDensity, targetDensity); mPaddingBottom = Drawable.scaleFromDensity( mPaddingBottom, sourceDensity, targetDensity, false); } if (mPaddingStart > 0) { mPaddingStart = Bitmap.scaleFromDensity( mPaddingStart, sourceDensity, targetDensity); mPaddingStart = Drawable.scaleFromDensity( mPaddingStart, sourceDensity, targetDensity, false); } if (mPaddingEnd > 0) { mPaddingEnd = Bitmap.scaleFromDensity( mPaddingEnd, sourceDensity, targetDensity); mPaddingEnd = Drawable.scaleFromDensity( mPaddingEnd, sourceDensity, targetDensity, false); } } Loading