Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 36555baa authored by Alan Viverette's avatar Alan Viverette Committed by Android (Google) Code Review
Browse files

Merge "Support for changing density of GradientDrawable"

parents 2b2e24c2 ce52037e
Loading
Loading
Loading
Loading
+2 −9
Original line number Diff line number Diff line
@@ -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
@@ -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();
    }
+60 −2
Original line number Diff line number Diff line
@@ -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();
@@ -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.
+7 −14
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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;
            }
+163 −52
Original line number Diff line number Diff line
@@ -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;
@@ -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;

@@ -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();

@@ -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;
@@ -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);
@@ -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;
        }
@@ -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;
@@ -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
@@ -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
@@ -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);
+24 −37
Original line number Diff line number Diff line
@@ -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);
@@ -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) {
@@ -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);
            }
@@ -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);
            }
        }
    }
@@ -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;
@@ -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