From 65add4028167cbe4e469dd6dc9031db3b5a4fad9 Mon Sep 17 00:00:00 2001 From: Nader Jawad Date: Fri, 30 Nov 2018 13:13:26 -0800 Subject: [PATCH] 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 --- .../graphics/drawable/GradientDrawable.java | 31 ++++++++++++++++--- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java index 87402342a3c92..991847ad27fa3 100644 --- a/graphics/java/android/graphics/drawable/GradientDrawable.java +++ b/graphics/java/android/graphics/drawable/GradientDrawable.java @@ -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(