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

Commit 0cacad70 authored by Alan Viverette's avatar Alan Viverette
Browse files

Apply density scaling in LayerDrawable and subclasses

Bug: 25081461
Change-Id: I48e62caf5017ff2dd84cf62b68a828f4542b6ae5
parent 5918519f
Loading
Loading
Loading
Loading
+249 −105
Original line number Diff line number Diff line
@@ -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);

        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();
        }
    private void updateLayerFromTypedArray(@NonNull ChildDrawable layer, @NonNull TypedArray a) {
        final LayerState state = mLayerState;

        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);
        }

+29 −22
Original line number Diff line number Diff line
@@ -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);
            }
        }