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

Commit 65add402 authored by Nader Jawad's avatar Nader Jawad
Browse files

Fix issue with xml GradientDrawables consuming both resources

and parameters provided by the Theme leading to array size
mismatch exceptions being thrown.

GradientDrawable#updateGradientDrawableGradient is invoked multiple
times during xml inflation, once with the attributes provided in the xml
and another with attributes provided in the Theme. However, if
parameters come from both the xml resources and the theme, when
theme attributes are applied it can partially squash previously applied
values.

In the case of gradients this can lead to a previously initialized
positions array with floating point offsets for color positions
being applied but not overriden with theme attributes that only include
a portion of the attribute values leading to exceptions being thrown
as the colors and positions arrays are not of the same size

Bug: 112122447
Test: Created test of xml inflation of GradientDrawables both with and
without theme attributes

Change-Id: Ie4183e2304677d30b6faef1cdc5c1be27ef9edd4
parent f66699ae
Loading
Loading
Loading
Loading
+26 −5
Original line number Diff line number Diff line
@@ -1571,15 +1571,32 @@ public class GradientDrawable extends Drawable {
        st.mGradient = a.getInt(
                R.styleable.GradientDrawableGradient_type, st.mGradient);

        // TODO: Update these to be themeable.
        final boolean hasGradientColors = st.mGradientColors != null;
        final boolean hasGradientCenter = st.hasCenterColor();
        final int prevStart = hasGradientColors ? st.mGradientColors[0] : 0;
        final int prevCenter = hasGradientCenter ? st.mGradientColors[1] : 0;
        final int prevEnd;

        if (st.hasCenterColor()) {
            // if there is a center color, the end color is the last of the 3 values
            prevEnd = st.mGradientColors[2];
        } else if (hasGradientColors) {
            // if there is not a center color but there are already colors configured, then
            // the end color is the 2nd value in the array
            prevEnd = st.mGradientColors[1];
        } else {
            // otherwise, there isn't a previously configured end color
            prevEnd = 0;
        }

        final int startColor = a.getColor(
                R.styleable.GradientDrawableGradient_startColor, 0);
                R.styleable.GradientDrawableGradient_startColor, prevStart);
        final boolean hasCenterColor = a.hasValue(
                R.styleable.GradientDrawableGradient_centerColor);
                R.styleable.GradientDrawableGradient_centerColor) || hasGradientCenter;
        final int centerColor = a.getColor(
                R.styleable.GradientDrawableGradient_centerColor, 0);
                R.styleable.GradientDrawableGradient_centerColor, prevCenter);
        final int endColor = a.getColor(
                R.styleable.GradientDrawableGradient_endColor, 0);
                R.styleable.GradientDrawableGradient_endColor, prevEnd);

        if (hasCenterColor) {
            st.mGradientColors = new int[3];
@@ -1943,6 +1960,10 @@ public class GradientDrawable extends Drawable {
            }
        }

        public boolean hasCenterColor() {
            return mGradientColors != null && mGradientColors.length == 3;
        }

        private void applyDensityScaling(int sourceDensity, int targetDensity) {
            if (mInnerRadius > 0) {
                mInnerRadius = Drawable.scaleFromDensity(