Gradient for VectorDrawable's fill and stroke
Add ComplexColor interface for both GradientColor and ColorStateList.
Set up constant state, factory, theme attrs for GradientColor, while
refactoring the ColorStateList's similar code. (Functionality in CSL should
be the same).
Support themeing in both the root and item level in GradientColor.
For example, both startColor in <gradient> tag or color in <item> tag can
have theme color.
Add tests for both simple and complex cases with themeing etc.
Hook up the native VectorDrawable implementation using 2 extra JNI calls for
simplicity. Such calls only happen at inflate and applyTheme call.
b/22564318
Change-Id: Ibdc564ddb4a7ee0133c6141c4784782f0c93ce0e
diff --git a/api/current.txt b/api/current.txt
index bfbb17e..6c7b5b8 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -506,6 +506,8 @@
field public static final int encryptionAware = 16844038; // 0x1010506
field public static final int end = 16843996; // 0x10104dc
field public static final int endColor = 16843166; // 0x101019e
+ field public static final int endX = 16844051; // 0x1010513
+ field public static final int endY = 16844052; // 0x1010514
field public static final deprecated int endYear = 16843133; // 0x101017d
field public static final int enterFadeDuration = 16843532; // 0x101030c
field public static final int entries = 16842930; // 0x10100b2
@@ -881,6 +883,7 @@
field public static final int numbersTextColor = 16843937; // 0x10104a1
field public static final deprecated int numeric = 16843109; // 0x1010165
field public static final int numericShortcut = 16843236; // 0x10101e4
+ field public static final int offset = 16844053; // 0x1010515
field public static final int onClick = 16843375; // 0x101026f
field public static final int oneshot = 16843159; // 0x1010197
field public static final int opacity = 16843550; // 0x101031e
@@ -1128,6 +1131,8 @@
field public static final int startColor = 16843165; // 0x101019d
field public static final int startDelay = 16843746; // 0x10103e2
field public static final int startOffset = 16843198; // 0x10101be
+ field public static final int startX = 16844049; // 0x1010511
+ field public static final int startY = 16844050; // 0x1010512
field public static final deprecated int startYear = 16843132; // 0x101017c
field public static final int stateListAnimator = 16843848; // 0x1010448
field public static final int stateNotNeeded = 16842774; // 0x1010016
@@ -9949,7 +9954,7 @@
method public final long skip(long) throws java.io.IOException;
}
- public class ColorStateList implements android.os.Parcelable {
+ public class ColorStateList extends android.content.res.ComplexColor implements android.os.Parcelable {
ctor public ColorStateList(int[][], int[]);
method public static deprecated android.content.res.ColorStateList createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
method public static android.content.res.ColorStateList createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
@@ -9958,13 +9963,18 @@
method public int getColorForState(int[], int);
method public int getDefaultColor();
method public boolean isOpaque();
- method public boolean isStateful();
method public static android.content.res.ColorStateList valueOf(int);
method public android.content.res.ColorStateList withAlpha(int);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.content.res.ColorStateList> CREATOR;
}
+ public abstract class ComplexColor {
+ ctor public ComplexColor();
+ method public abstract int getDefaultColor();
+ method public boolean isStateful();
+ }
+
public final class Configuration implements java.lang.Comparable android.os.Parcelable {
ctor public Configuration();
ctor public Configuration(android.content.res.Configuration);
@@ -10068,6 +10078,11 @@
field public int uiMode;
}
+ public class GradientColor extends android.content.res.ComplexColor {
+ method public static android.content.res.GradientColor createFromXml(android.content.res.Resources, android.content.res.XmlResourceParser, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public int getDefaultColor();
+ }
+
public class ObbInfo implements android.os.Parcelable {
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
@@ -10127,6 +10142,7 @@
method public void getValue(java.lang.String, android.util.TypedValue, boolean) throws android.content.res.Resources.NotFoundException;
method public void getValueForDensity(int, int, android.util.TypedValue, boolean) throws android.content.res.Resources.NotFoundException;
method public android.content.res.XmlResourceParser getXml(int) throws android.content.res.Resources.NotFoundException;
+ method public android.content.res.ComplexColor loadComplexColor(android.util.TypedValue, int, android.content.res.Resources.Theme);
method public final android.content.res.Resources.Theme newTheme();
method public android.content.res.TypedArray obtainAttributes(android.util.AttributeSet, int[]);
method public android.content.res.TypedArray obtainTypedArray(int) throws android.content.res.Resources.NotFoundException;
@@ -10162,6 +10178,7 @@
method public int getChangingConfigurations();
method public int getColor(int, int);
method public android.content.res.ColorStateList getColorStateList(int);
+ method public android.content.res.ComplexColor getComplexColor(int);
method public float getDimension(int, float);
method public int getDimensionPixelOffset(int, int);
method public int getDimensionPixelSize(int, int);
diff --git a/api/system-current.txt b/api/system-current.txt
index c10954c..16c189c 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -601,6 +601,8 @@
field public static final int encryptionAware = 16844038; // 0x1010506
field public static final int end = 16843996; // 0x10104dc
field public static final int endColor = 16843166; // 0x101019e
+ field public static final int endX = 16844051; // 0x1010513
+ field public static final int endY = 16844052; // 0x1010514
field public static final deprecated int endYear = 16843133; // 0x101017d
field public static final int enterFadeDuration = 16843532; // 0x101030c
field public static final int entries = 16842930; // 0x10100b2
@@ -976,6 +978,7 @@
field public static final int numbersTextColor = 16843937; // 0x10104a1
field public static final deprecated int numeric = 16843109; // 0x1010165
field public static final int numericShortcut = 16843236; // 0x10101e4
+ field public static final int offset = 16844053; // 0x1010515
field public static final int onClick = 16843375; // 0x101026f
field public static final int oneshot = 16843159; // 0x1010197
field public static final int opacity = 16843550; // 0x101031e
@@ -1227,6 +1230,8 @@
field public static final int startColor = 16843165; // 0x101019d
field public static final int startDelay = 16843746; // 0x10103e2
field public static final int startOffset = 16843198; // 0x10101be
+ field public static final int startX = 16844049; // 0x1010511
+ field public static final int startY = 16844050; // 0x1010512
field public static final deprecated int startYear = 16843132; // 0x101017c
field public static final int stateListAnimator = 16843848; // 0x1010448
field public static final int stateNotNeeded = 16842774; // 0x1010016
@@ -10349,7 +10354,7 @@
method public final long skip(long) throws java.io.IOException;
}
- public class ColorStateList implements android.os.Parcelable {
+ public class ColorStateList extends android.content.res.ComplexColor implements android.os.Parcelable {
ctor public ColorStateList(int[][], int[]);
method public static deprecated android.content.res.ColorStateList createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
method public static android.content.res.ColorStateList createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
@@ -10358,13 +10363,18 @@
method public int getColorForState(int[], int);
method public int getDefaultColor();
method public boolean isOpaque();
- method public boolean isStateful();
method public static android.content.res.ColorStateList valueOf(int);
method public android.content.res.ColorStateList withAlpha(int);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.content.res.ColorStateList> CREATOR;
}
+ public abstract class ComplexColor {
+ ctor public ComplexColor();
+ method public abstract int getDefaultColor();
+ method public boolean isStateful();
+ }
+
public final class Configuration implements java.lang.Comparable android.os.Parcelable {
ctor public Configuration();
ctor public Configuration(android.content.res.Configuration);
@@ -10468,6 +10478,11 @@
field public int uiMode;
}
+ public class GradientColor extends android.content.res.ComplexColor {
+ method public static android.content.res.GradientColor createFromXml(android.content.res.Resources, android.content.res.XmlResourceParser, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public int getDefaultColor();
+ }
+
public class ObbInfo implements android.os.Parcelable {
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
@@ -10527,6 +10542,7 @@
method public void getValue(java.lang.String, android.util.TypedValue, boolean) throws android.content.res.Resources.NotFoundException;
method public void getValueForDensity(int, int, android.util.TypedValue, boolean) throws android.content.res.Resources.NotFoundException;
method public android.content.res.XmlResourceParser getXml(int) throws android.content.res.Resources.NotFoundException;
+ method public android.content.res.ComplexColor loadComplexColor(android.util.TypedValue, int, android.content.res.Resources.Theme);
method public final android.content.res.Resources.Theme newTheme();
method public android.content.res.TypedArray obtainAttributes(android.util.AttributeSet, int[]);
method public android.content.res.TypedArray obtainTypedArray(int) throws android.content.res.Resources.NotFoundException;
@@ -10562,6 +10578,7 @@
method public int getChangingConfigurations();
method public int getColor(int, int);
method public android.content.res.ColorStateList getColorStateList(int);
+ method public android.content.res.ComplexColor getComplexColor(int);
method public float getDimension(int, float);
method public int getDimensionPixelOffset(int, int);
method public int getDimensionPixelSize(int, int);
diff --git a/api/test-current.txt b/api/test-current.txt
index c076ad6..8fc63fe 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -506,6 +506,8 @@
field public static final int encryptionAware = 16844038; // 0x1010506
field public static final int end = 16843996; // 0x10104dc
field public static final int endColor = 16843166; // 0x101019e
+ field public static final int endX = 16844051; // 0x1010513
+ field public static final int endY = 16844052; // 0x1010514
field public static final deprecated int endYear = 16843133; // 0x101017d
field public static final int enterFadeDuration = 16843532; // 0x101030c
field public static final int entries = 16842930; // 0x10100b2
@@ -881,6 +883,7 @@
field public static final int numbersTextColor = 16843937; // 0x10104a1
field public static final deprecated int numeric = 16843109; // 0x1010165
field public static final int numericShortcut = 16843236; // 0x10101e4
+ field public static final int offset = 16844053; // 0x1010515
field public static final int onClick = 16843375; // 0x101026f
field public static final int oneshot = 16843159; // 0x1010197
field public static final int opacity = 16843550; // 0x101031e
@@ -1128,6 +1131,8 @@
field public static final int startColor = 16843165; // 0x101019d
field public static final int startDelay = 16843746; // 0x10103e2
field public static final int startOffset = 16843198; // 0x10101be
+ field public static final int startX = 16844049; // 0x1010511
+ field public static final int startY = 16844050; // 0x1010512
field public static final deprecated int startYear = 16843132; // 0x101017c
field public static final int stateListAnimator = 16843848; // 0x1010448
field public static final int stateNotNeeded = 16842774; // 0x1010016
@@ -9957,7 +9962,7 @@
method public final long skip(long) throws java.io.IOException;
}
- public class ColorStateList implements android.os.Parcelable {
+ public class ColorStateList extends android.content.res.ComplexColor implements android.os.Parcelable {
ctor public ColorStateList(int[][], int[]);
method public static deprecated android.content.res.ColorStateList createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
method public static android.content.res.ColorStateList createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
@@ -9966,13 +9971,18 @@
method public int getColorForState(int[], int);
method public int getDefaultColor();
method public boolean isOpaque();
- method public boolean isStateful();
method public static android.content.res.ColorStateList valueOf(int);
method public android.content.res.ColorStateList withAlpha(int);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.content.res.ColorStateList> CREATOR;
}
+ public abstract class ComplexColor {
+ ctor public ComplexColor();
+ method public abstract int getDefaultColor();
+ method public boolean isStateful();
+ }
+
public final class Configuration implements java.lang.Comparable android.os.Parcelable {
ctor public Configuration();
ctor public Configuration(android.content.res.Configuration);
@@ -10076,6 +10086,11 @@
field public int uiMode;
}
+ public class GradientColor extends android.content.res.ComplexColor {
+ method public static android.content.res.GradientColor createFromXml(android.content.res.Resources, android.content.res.XmlResourceParser, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public int getDefaultColor();
+ }
+
public class ObbInfo implements android.os.Parcelable {
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
@@ -10135,6 +10150,7 @@
method public void getValue(java.lang.String, android.util.TypedValue, boolean) throws android.content.res.Resources.NotFoundException;
method public void getValueForDensity(int, int, android.util.TypedValue, boolean) throws android.content.res.Resources.NotFoundException;
method public android.content.res.XmlResourceParser getXml(int) throws android.content.res.Resources.NotFoundException;
+ method public android.content.res.ComplexColor loadComplexColor(android.util.TypedValue, int, android.content.res.Resources.Theme);
method public final android.content.res.Resources.Theme newTheme();
method public android.content.res.TypedArray obtainAttributes(android.util.AttributeSet, int[]);
method public android.content.res.TypedArray obtainTypedArray(int) throws android.content.res.Resources.NotFoundException;
@@ -10170,6 +10186,7 @@
method public int getChangingConfigurations();
method public int getColor(int, int);
method public android.content.res.ColorStateList getColorStateList(int);
+ method public android.content.res.ComplexColor getComplexColor(int);
method public float getDimension(int, float);
method public int getDimensionPixelOffset(int, int);
method public int getDimensionPixelSize(int, int);
diff --git a/core/java/android/content/res/ColorStateList.java b/core/java/android/content/res/ColorStateList.java
index 19921b5..9e1b312 100644
--- a/core/java/android/content/res/ColorStateList.java
+++ b/core/java/android/content/res/ColorStateList.java
@@ -69,7 +69,7 @@
* href="{@docRoot}guide/topics/resources/color-list-resource.html">Color State
* List Resource</a>.</p>
*/
-public class ColorStateList implements Parcelable {
+public class ColorStateList extends ComplexColor implements Parcelable {
private static final String TAG = "ColorStateList";
private static final int DEFAULT_COLOR = Color.RED;
@@ -209,7 +209,7 @@
* @return A new color state list for the current tag.
*/
@NonNull
- private static ColorStateList createFromXmlInner(@NonNull Resources r,
+ static ColorStateList createFromXmlInner(@NonNull Resources r,
@NonNull XmlPullParser parser, @NonNull AttributeSet attrs, @Nullable Theme theme)
throws XmlPullParserException, IOException {
final String name = parser.getName();
@@ -340,6 +340,7 @@
* @return whether a theme can be applied to this color state list
* @hide only for resource preloading
*/
+ @Override
public boolean canApplyTheme() {
return mThemeAttrs != null;
}
@@ -419,6 +420,7 @@
* attributes
* @hide only for resource preloading
*/
+ @Override
public ColorStateList obtainForTheme(Theme t) {
if (t == null || !canApplyTheme()) {
return this;
@@ -460,6 +462,7 @@
* otherwise.
* @see #getColorForState(int[], int)
*/
+ @Override
public boolean isStateful() {
return mStateSpecs.length > 1;
}
@@ -602,14 +605,14 @@
* @return a factory that can create new instances of this ColorStateList
* @hide only for resource preloading
*/
- public ConstantState<ColorStateList> getConstantState() {
+ public ConstantState<ComplexColor> getConstantState() {
if (mFactory == null) {
mFactory = new ColorStateListFactory(this);
}
return mFactory;
}
- private static class ColorStateListFactory extends ConstantState<ColorStateList> {
+ private static class ColorStateListFactory extends ConstantState<ComplexColor> {
private final ColorStateList mSrc;
public ColorStateListFactory(ColorStateList src) {
@@ -628,7 +631,7 @@
@Override
public ColorStateList newInstance(Resources res, Theme theme) {
- return mSrc.obtainForTheme(theme);
+ return (ColorStateList) mSrc.obtainForTheme(theme);
}
}
diff --git a/core/java/android/content/res/ComplexColor.java b/core/java/android/content/res/ComplexColor.java
new file mode 100644
index 0000000..d96ec62
--- /dev/null
+++ b/core/java/android/content/res/ComplexColor.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.res;
+
+import android.annotation.ColorInt;
+import android.content.res.Resources.Theme;
+import android.graphics.Color;
+
+/**
+ * Defines an abstract class for the complex color information, like
+ * {@link android.content.res.ColorStateList} or {@link android.content.res.GradientColor}
+ */
+public abstract class ComplexColor {
+ /**
+ * @return {@code true} if this ComplexColor changes color based on state, {@code false}
+ * otherwise.
+ */
+ public boolean isStateful() { return false; }
+
+ /**
+ * @return the default color.
+ */
+ @ColorInt
+ public abstract int getDefaultColor();
+
+ /**
+ * @hide only for resource preloading
+ *
+ */
+ public abstract ConstantState<ComplexColor> getConstantState();
+
+ /**
+ * @hide only for resource preloading
+ */
+ public abstract boolean canApplyTheme();
+
+ /**
+ * @hide only for resource preloading
+ */
+ public abstract ComplexColor obtainForTheme(Theme t);
+}
diff --git a/core/java/android/content/res/GradientColor.java b/core/java/android/content/res/GradientColor.java
new file mode 100644
index 0000000..98ef2ea
--- /dev/null
+++ b/core/java/android/content/res/GradientColor.java
@@ -0,0 +1,523 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.res;
+
+import android.annotation.ColorInt;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.res.Resources.Theme;
+
+import com.android.internal.R;
+import com.android.internal.util.GrowingArrayUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.graphics.LinearGradient;
+import android.graphics.RadialGradient;
+import android.graphics.Shader;
+import android.graphics.SweepGradient;
+import android.graphics.drawable.GradientDrawable;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.Xml;
+
+import java.io.IOException;
+
+
+public class GradientColor extends ComplexColor {
+ private static final String TAG = "GradientColor";
+
+ private static final boolean DBG_GRADIENT = false;
+
+ /** Lazily-created factory for this GradientColor. */
+ private GradientColorFactory mFactory;
+
+ private int mChangingConfigurations;
+ private int mDefaultColor;
+
+ // After parsing all the attributes from XML, this shader is the ultimate result containing
+ // all the XML information.
+ private Shader mShader = null;
+
+ // Below are the attributes at the root element <gradient>
+ private int mGradientType = GradientDrawable.LINEAR_GRADIENT;
+
+ private float mCenterX = 0f;
+ private float mCenterY = 0f;
+
+ private float mStartX = 0f;
+ private float mStartY = 0f;
+ private float mEndX = 0f;
+ private float mEndY = 0f;
+
+ private int mStartColor = 0;
+ private int mCenterColor = 0;
+ private int mEndColor = 0;
+ private boolean mHasCenterColor = false;
+
+ private float mGradientRadius = 0f;
+
+ // Below are the attributes for the <item> element.
+ private int[] mItemColors;
+ private float[] mItemOffsets;
+
+ // Theme attributes for the root and item elements.
+ private int[] mThemeAttrs;
+ private int[][] mItemsThemeAttrs;
+
+ private GradientColor() {
+ }
+
+ private GradientColor(GradientColor copy) {
+ if (copy != null) {
+ mChangingConfigurations = copy.mChangingConfigurations;
+ mDefaultColor = copy.mDefaultColor;
+ mShader = copy.mShader;
+ mGradientType = copy.mGradientType;
+ mCenterX = copy.mCenterX;
+ mCenterY = copy.mCenterY;
+ mStartX = copy.mStartX;
+ mStartY = copy.mStartY;
+ mEndX = copy.mEndX;
+ mEndY = copy.mEndY;
+ mStartColor = copy.mStartColor;
+ mCenterColor = copy.mCenterColor;
+ mEndColor = copy.mEndColor;
+ mHasCenterColor = copy.mHasCenterColor;
+ mGradientRadius = copy.mGradientRadius;
+
+ if (copy.mItemColors != null) {
+ mItemColors = copy.mItemColors.clone();
+ }
+ if (copy.mItemOffsets != null) {
+ mItemOffsets = copy.mItemOffsets.clone();
+ }
+
+ if (copy.mThemeAttrs != null) {
+ mThemeAttrs = copy.mThemeAttrs.clone();
+ }
+ if (copy.mItemsThemeAttrs != null) {
+ mItemsThemeAttrs = copy.mItemsThemeAttrs.clone();
+ }
+ }
+ }
+
+ /**
+ * Update the root level's attributes, either for inflate or applyTheme.
+ */
+ private void updateRootElementState(TypedArray a) {
+ // Extract the theme attributes, if any.
+ mThemeAttrs = a.extractThemeAttrs();
+
+ mStartX = a.getFloat(
+ R.styleable.GradientColor_startX, mStartX);
+ mStartY = a.getFloat(
+ R.styleable.GradientColor_startY, mStartY);
+ mEndX = a.getFloat(
+ R.styleable.GradientColor_endX, mEndX);
+ mEndY = a.getFloat(
+ R.styleable.GradientColor_endY, mEndY);
+
+ mCenterX = a.getFloat(
+ R.styleable.GradientColor_centerX, mCenterX);
+ mCenterY = a.getFloat(
+ R.styleable.GradientColor_centerY, mCenterY);
+
+ mGradientType = a.getInt(
+ R.styleable.GradientColor_type, mGradientType);
+
+ mStartColor = a.getColor(
+ R.styleable.GradientColor_startColor, mStartColor);
+ mHasCenterColor |= a.hasValue(
+ R.styleable.GradientColor_centerColor);
+ mCenterColor = a.getColor(
+ R.styleable.GradientColor_centerColor, mCenterColor);
+ mEndColor = a.getColor(
+ R.styleable.GradientColor_endColor, mEndColor);
+
+ if (DBG_GRADIENT) {
+ Log.v(TAG, "hasCenterColor is " + mHasCenterColor);
+ if (mHasCenterColor) {
+ Log.v(TAG, "centerColor:" + mCenterColor);
+ }
+ Log.v(TAG, "startColor: " + mStartColor);
+ Log.v(TAG, "endColor: " + mEndColor);
+ }
+
+ mGradientRadius = a.getFloat(R.styleable.GradientColor_gradientRadius,
+ mGradientRadius);
+ }
+
+ /**
+ * Check if the XML content is valid.
+ *
+ * @throws XmlPullParserException if errors were found.
+ */
+ private void validateXmlContent() throws XmlPullParserException {
+ if (mGradientRadius <= 0
+ && mGradientType == GradientDrawable.RADIAL_GRADIENT) {
+ throw new XmlPullParserException(
+ "<gradient> tag requires 'gradientRadius' "
+ + "attribute with radial type");
+ }
+ }
+
+ /**
+ * The shader information will be applied to the native VectorDrawable's path.
+ * @hide
+ */
+ public Shader getShader() {
+ return mShader;
+ }
+
+ /**
+ * A public method to create GradientColor from a XML resource.
+ */
+ public static GradientColor createFromXml(Resources r, XmlResourceParser parser, Theme theme)
+ throws XmlPullParserException, IOException {
+ final AttributeSet attrs = Xml.asAttributeSet(parser);
+
+ int type;
+ while ((type = parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT) {
+ // Seek parser to start tag.
+ }
+
+ if (type != XmlPullParser.START_TAG) {
+ throw new XmlPullParserException("No start tag found");
+ }
+
+ return createFromXmlInner(r, parser, attrs, theme);
+ }
+
+ /**
+ * Create from inside an XML document. Called on a parser positioned at a
+ * tag in an XML document, tries to create a GradientColor from that tag.
+ *
+ * @return A new GradientColor for the current tag.
+ * @throws XmlPullParserException if the current tag is not <gradient>
+ */
+ @NonNull
+ static GradientColor createFromXmlInner(@NonNull Resources r,
+ @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, @Nullable Theme theme)
+ throws XmlPullParserException, IOException {
+ final String name = parser.getName();
+ if (!name.equals("gradient")) {
+ throw new XmlPullParserException(
+ parser.getPositionDescription() + ": invalid gradient color tag " + name);
+ }
+
+ final GradientColor gradientColor = new GradientColor();
+ gradientColor.inflate(r, parser, attrs, theme);
+ return gradientColor;
+ }
+
+ /**
+ * Fill in this object based on the contents of an XML "gradient" element.
+ */
+ private void inflate(@NonNull Resources r, @NonNull XmlPullParser parser,
+ @NonNull AttributeSet attrs, @Nullable Theme theme)
+ throws XmlPullParserException, IOException {
+ final TypedArray a = Resources.obtainAttributes(r, theme, attrs, R.styleable.GradientColor);
+ updateRootElementState(a);
+ mChangingConfigurations |= a.getChangingConfigurations();
+ a.recycle();
+
+ // Check correctness and throw exception if errors found.
+ validateXmlContent();
+
+ inflateChildElements(r, parser, attrs, theme);
+
+ onColorsChange();
+ }
+
+ /**
+ * Inflates child elements "item"s for each color stop.
+ *
+ * Note that at root level, we need to save ThemeAttrs for theme applied later.
+ * Here similarly, at each child item, we need to save the theme's attributes, and apply theme
+ * later as applyItemsAttrsTheme().
+ */
+ private void inflateChildElements(@NonNull Resources r, @NonNull XmlPullParser parser,
+ @NonNull AttributeSet attrs, @NonNull Theme theme)
+ throws XmlPullParserException, IOException {
+ final int innerDepth = parser.getDepth() + 1;
+ int type;
+ int depth;
+
+ // Pre-allocate the array with some size, for better performance.
+ float[] offsetList = new float[20];
+ int[] colorList = new int[offsetList.length];
+ int[][] themeAttrsList = new int[offsetList.length][];
+
+ int listSize = 0;
+ boolean hasUnresolvedAttrs = false;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && ((depth = parser.getDepth()) >= innerDepth
+ || type != XmlPullParser.END_TAG)) {
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
+ if (depth > innerDepth || !parser.getName().equals("item")) {
+ continue;
+ }
+
+ final TypedArray a = Resources.obtainAttributes(r, theme, attrs,
+ R.styleable.GradientColorItem);
+ boolean hasColor = a.hasValue(R.styleable.GradientColorItem_color);
+ boolean hasOffset = a.hasValue(R.styleable.GradientColorItem_offset);
+ if (!hasColor || !hasOffset) {
+ throw new XmlPullParserException(
+ parser.getPositionDescription()
+ + ": <item> tag requires a 'color' attribute and a 'offset' "
+ + "attribute!");
+ }
+
+ final int[] themeAttrs = a.extractThemeAttrs();
+ int color = a.getColor(R.styleable.GradientColorItem_color, 0);
+ float offset = a.getFloat(R.styleable.GradientColorItem_offset, 0);
+
+ if (DBG_GRADIENT) {
+ Log.v(TAG, "new item color " + color + " " + Integer.toHexString(color));
+ Log.v(TAG, "offset" + offset);
+ }
+ mChangingConfigurations |= a.getChangingConfigurations();
+ a.recycle();
+
+ if (themeAttrs != null) {
+ hasUnresolvedAttrs = true;
+ }
+
+ colorList = GrowingArrayUtils.append(colorList, listSize, color);
+ offsetList = GrowingArrayUtils.append(offsetList, listSize, offset);
+ themeAttrsList = GrowingArrayUtils.append(themeAttrsList, listSize, themeAttrs);
+ listSize++;
+ }
+ if (listSize > 0) {
+ if (hasUnresolvedAttrs) {
+ mItemsThemeAttrs = new int[listSize][];
+ System.arraycopy(themeAttrsList, 0, mItemsThemeAttrs, 0, listSize);
+ } else {
+ mItemsThemeAttrs = null;
+ }
+
+ mItemColors = new int[listSize];
+ mItemOffsets = new float[listSize];
+ System.arraycopy(colorList, 0, mItemColors, 0, listSize);
+ System.arraycopy(offsetList, 0, mItemOffsets, 0, listSize);
+ }
+ }
+
+ /**
+ * Apply theme to all the items.
+ */
+ private void applyItemsAttrsTheme(Theme t) {
+ if (mItemsThemeAttrs == null) {
+ return;
+ }
+
+ boolean hasUnresolvedAttrs = false;
+
+ final int[][] themeAttrsList = mItemsThemeAttrs;
+ final int N = themeAttrsList.length;
+ for (int i = 0; i < N; i++) {
+ if (themeAttrsList[i] != null) {
+ final TypedArray a = t.resolveAttributes(themeAttrsList[i],
+ R.styleable.GradientColorItem);
+
+ // Extract the theme attributes, if any, before attempting to
+ // read from the typed array. This prevents a crash if we have
+ // unresolved attrs.
+ themeAttrsList[i] = a.extractThemeAttrs(themeAttrsList[i]);
+ if (themeAttrsList[i] != null) {
+ hasUnresolvedAttrs = true;
+ }
+
+ mItemColors[i] = a.getColor(R.styleable.GradientColorItem_color, mItemColors[i]);
+ mItemOffsets[i] = a.getFloat(R.styleable.GradientColorItem_offset, mItemOffsets[i]);
+ if (DBG_GRADIENT) {
+ Log.v(TAG, "applyItemsAttrsTheme Colors[i] " + i + " " +
+ Integer.toHexString(mItemColors[i]));
+ Log.v(TAG, "Offsets[i] " + i + " " + mItemOffsets[i]);
+ }
+
+ // Account for any configuration changes.
+ mChangingConfigurations |= a.getChangingConfigurations();
+
+ a.recycle();
+ }
+ }
+
+ if (!hasUnresolvedAttrs) {
+ mItemsThemeAttrs = null;
+ }
+ }
+
+ private void onColorsChange() {
+ int[] tempColors = null;
+ float[] tempOffsets = null;
+
+ if (mItemColors != null) {
+ int length = mItemColors.length;
+ tempColors = new int[length];
+ tempOffsets = new float[length];
+
+ for (int i = 0; i < length; i++) {
+ tempColors[i] = mItemColors[i];
+ tempOffsets[i] = mItemOffsets[i];
+ }
+ } else {
+ if (mHasCenterColor) {
+ tempColors = new int[3];
+ tempColors[0] = mStartColor;
+ tempColors[1] = mCenterColor;
+ tempColors[2] = mEndColor;
+
+ tempOffsets = new float[3];
+ tempOffsets[0] = 0.0f;
+ // Since 0.5f is default value, try to take the one that isn't 0.5f
+ tempOffsets[1] = 0.5f;
+ tempOffsets[2] = 1f;
+ } else {
+ tempColors = new int[2];
+ tempColors[0] = mStartColor;
+ tempColors[1] = mEndColor;
+ }
+ }
+ if (tempColors.length < 2) {
+ Log.w(TAG, "<gradient> tag requires 2 color values specified!" + tempColors.length
+ + " " + tempColors);
+ }
+
+ if (mGradientType == GradientDrawable.LINEAR_GRADIENT) {
+ mShader = new LinearGradient(mStartX, mStartY, mEndX, mEndY, tempColors, tempOffsets,
+ Shader.TileMode.CLAMP);
+ } else {
+ if (mGradientType == GradientDrawable.RADIAL_GRADIENT) {
+ mShader = new RadialGradient(mCenterX, mCenterY, mGradientRadius, tempColors,
+ tempOffsets, Shader.TileMode.CLAMP);
+ } else {
+ mShader = new SweepGradient(mCenterX, mCenterY, tempColors, tempOffsets);
+ }
+ }
+ mDefaultColor = tempColors[0];
+ }
+
+ /**
+ * For Gradient color, the default color is not very useful, since the gradient will override
+ * the color information anyway.
+ */
+ @Override
+ @ColorInt
+ public int getDefaultColor() {
+ return mDefaultColor;
+ }
+
+ /**
+ * Similar to ColorStateList, setup constant state and its factory.
+ * @hide only for resource preloading
+ */
+ @Override
+ public ConstantState<ComplexColor> getConstantState() {
+ if (mFactory == null) {
+ mFactory = new GradientColorFactory(this);
+ }
+ return mFactory;
+ }
+
+ private static class GradientColorFactory extends ConstantState<ComplexColor> {
+ private final GradientColor mSrc;
+
+ public GradientColorFactory(GradientColor src) {
+ mSrc = src;
+ }
+
+ @Override
+ public int getChangingConfigurations() {
+ return mSrc.mChangingConfigurations;
+ }
+
+ @Override
+ public GradientColor newInstance() {
+ return mSrc;
+ }
+
+ @Override
+ public GradientColor newInstance(Resources res, Theme theme) {
+ return mSrc.obtainForTheme(theme);
+ }
+ }
+
+ /**
+ * Returns an appropriately themed gradient color.
+ *
+ * @param t the theme to apply
+ * @return a copy of the gradient color the theme applied, or the
+ * gradient itself if there were no unresolved theme
+ * attributes
+ * @hide only for resource preloading
+ */
+ @Override
+ public GradientColor obtainForTheme(Theme t) {
+ if (t == null || !canApplyTheme()) {
+ return this;
+ }
+
+ final GradientColor clone = new GradientColor(this);
+ clone.applyTheme(t);
+ return clone;
+ }
+
+ private void applyTheme(Theme t) {
+ if (mThemeAttrs != null) {
+ applyRootAttrsTheme(t);
+ }
+ if (mItemsThemeAttrs != null) {
+ applyItemsAttrsTheme(t);
+ }
+ onColorsChange();
+ }
+
+ private void applyRootAttrsTheme(Theme t) {
+ final TypedArray a = t.resolveAttributes(mThemeAttrs, R.styleable.GradientColor);
+ // mThemeAttrs will be set to null if if there are no theme attributes in the
+ // typed array.
+ mThemeAttrs = a.extractThemeAttrs(mThemeAttrs);
+ // merging the attributes update inside the updateRootElementState().
+ updateRootElementState(a);
+
+ // Account for any configuration changes.
+ mChangingConfigurations |= a.getChangingConfigurations();
+ a.recycle();
+ }
+
+
+ /**
+ * Returns whether a theme can be applied to this gradient color, which
+ * usually indicates that the gradient color has unresolved theme
+ * attributes.
+ *
+ * @return whether a theme can be applied to this gradient color.
+ * @hide only for resource preloading
+ */
+ @Override
+ public boolean canApplyTheme() {
+ return mThemeAttrs != null || mItemsThemeAttrs != null;
+ }
+
+}
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index e404429..4967d05 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -56,6 +56,7 @@
import android.util.Pools.SynchronizedPool;
import android.util.Slog;
import android.util.TypedValue;
+import android.util.Xml;
import android.view.ViewDebug;
import android.view.ViewHierarchyEncoder;
@@ -115,8 +116,8 @@
private static final LongSparseArray<ConstantState>[] sPreloadedDrawables;
private static final LongSparseArray<ConstantState> sPreloadedColorDrawables
= new LongSparseArray<>();
- private static final LongSparseArray<android.content.res.ConstantState<ColorStateList>>
- sPreloadedColorStateLists = new LongSparseArray<>();
+ private static final LongSparseArray<android.content.res.ConstantState<ComplexColor>>
+ sPreloadedComplexColors = new LongSparseArray<>();
// Pool of TypedArrays targeted to this Resources object.
final SynchronizedPool<TypedArray> mTypedArrayPool = new SynchronizedPool<>(5);
@@ -133,7 +134,7 @@
private final Configuration mTmpConfig = new Configuration();
private final DrawableCache mDrawableCache = new DrawableCache(this);
private final DrawableCache mColorDrawableCache = new DrawableCache(this);
- private final ConfigurationBoundResourceCache<ColorStateList> mColorStateListCache =
+ private final ConfigurationBoundResourceCache<ComplexColor> mComplexColorCache =
new ConfigurationBoundResourceCache<>(this);
private final ConfigurationBoundResourceCache<Animator> mAnimatorCache =
new ConfigurationBoundResourceCache<>(this);
@@ -1987,7 +1988,7 @@
mDrawableCache.onConfigurationChange(configChanges);
mColorDrawableCache.onConfigurationChange(configChanges);
- mColorStateListCache.onConfigurationChange(configChanges);
+ mComplexColorCache.onConfigurationChange(configChanges);
mAnimatorCache.onConfigurationChange(configChanges);
mStateListAnimatorCache.onConfigurationChange(configChanges);
@@ -2613,6 +2614,82 @@
return dr;
}
+ /**
+ * Given the value and id, we can get the XML filename as in value.data, based on that, we
+ * first try to load CSL from the cache. If not found, try to get from the constant state.
+ * Last, parse the XML and generate the CSL.
+ */
+ private ComplexColor loadComplexColorFromName(Theme theme, TypedValue value, int id) {
+ final long key = (((long) value.assetCookie) << 32) | value.data;
+ final ConfigurationBoundResourceCache<ComplexColor> cache = mComplexColorCache;
+ ComplexColor complexColor = cache.getInstance(key, theme);
+ if (complexColor != null) {
+ return complexColor;
+ }
+
+ final android.content.res.ConstantState<ComplexColor> factory =
+ sPreloadedComplexColors.get(key);
+
+ if (factory != null) {
+ complexColor = factory.newInstance(this, theme);
+ }
+ if (complexColor == null) {
+ complexColor = loadComplexColorForCookie(value, id, theme);
+ }
+
+ if (complexColor != null) {
+ if (mPreloading) {
+ if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
+ "color")) {
+ sPreloadedComplexColors.put(key, complexColor.getConstantState());
+ }
+ } else {
+ cache.put(key, theme, complexColor.getConstantState());
+ }
+ }
+ return complexColor;
+ }
+
+ @Nullable
+ public ComplexColor loadComplexColor(@NonNull TypedValue value, int id, Theme theme) {
+ if (TRACE_FOR_PRELOAD) {
+ // Log only framework resources
+ if ((id >>> 24) == 0x1) {
+ final String name = getResourceName(id);
+ if (name != null) android.util.Log.d("loadComplexColor", name);
+ }
+ }
+
+ final long key = (((long) value.assetCookie) << 32) | value.data;
+
+ // Handle inline color definitions.
+ if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
+ && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
+ return getColorStateListFromInt(value, key);
+ }
+
+ final String file = value.string.toString();
+
+ ComplexColor complexColor;
+ if (file.endsWith(".xml")) {
+ try {
+ complexColor = loadComplexColorFromName(theme, value, id);
+ } catch (Exception e) {
+ final NotFoundException rnf = new NotFoundException(
+ "File " + file + " from complex color resource ID #0x"
+ + Integer.toHexString(id));
+ rnf.initCause(e);
+ throw rnf;
+ }
+ } else {
+ throw new NotFoundException(
+ "File " + file + " from drawable resource ID #0x"
+ + Integer.toHexString(id) + ": .xml extension required");
+ }
+
+ return complexColor;
+ }
+
@Nullable
ColorStateList loadColorStateList(TypedValue value, int id, Theme theme)
throws NotFoundException {
@@ -2626,63 +2703,57 @@
final long key = (((long) value.assetCookie) << 32) | value.data;
- ColorStateList csl;
-
// Handle inline color definitions.
if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
&& value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
- final android.content.res.ConstantState<ColorStateList> factory =
- sPreloadedColorStateLists.get(key);
- if (factory != null) {
- return factory.newInstance();
- }
-
- csl = ColorStateList.valueOf(value.data);
-
- if (mPreloading) {
- if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
- "color")) {
- sPreloadedColorStateLists.put(key, csl.getConstantState());
- }
- }
-
- return csl;
+ return getColorStateListFromInt(value, key);
}
- final ConfigurationBoundResourceCache<ColorStateList> cache = mColorStateListCache;
- csl = cache.getInstance(key, theme);
- if (csl != null) {
- return csl;
+ ComplexColor complexColor = loadComplexColorFromName(theme, value, id);
+ if (complexColor != null && complexColor instanceof ColorStateList) {
+ return (ColorStateList) complexColor;
}
- final android.content.res.ConstantState<ColorStateList> factory =
- sPreloadedColorStateLists.get(key);
+ throw new NotFoundException(
+ "Can't find ColorStateList from drawable resource ID #0x"
+ + Integer.toHexString(id));
+ }
+
+ @NonNull
+ private ColorStateList getColorStateListFromInt(@NonNull TypedValue value, long key) {
+ ColorStateList csl;
+ final android.content.res.ConstantState<ComplexColor> factory =
+ sPreloadedComplexColors.get(key);
if (factory != null) {
- csl = factory.newInstance(this, theme);
+ return (ColorStateList) factory.newInstance();
}
- if (csl == null) {
- csl = loadColorStateListForCookie(value, id, theme);
- }
+ csl = ColorStateList.valueOf(value.data);
- if (csl != null) {
- if (mPreloading) {
- if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
- "color")) {
- sPreloadedColorStateLists.put(key, csl.getConstantState());
- }
- } else {
- cache.put(key, theme, csl.getConstantState());
+ if (mPreloading) {
+ if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
+ "color")) {
+ sPreloadedComplexColors.put(key, csl.getConstantState());
}
}
return csl;
}
- private ColorStateList loadColorStateListForCookie(TypedValue value, int id, Theme theme) {
+ /**
+ * Load a ComplexColor based on the XML file content. The result can be a GradientColor or
+ * ColorStateList. Note that pure color will be wrapped into a ColorStateList.
+ *
+ * We deferred the parser creation to this function b/c we need to differentiate b/t gradient
+ * and selector tag.
+ *
+ * @return a ComplexColor (GradientColor or ColorStateList) based on the XML file content.
+ */
+ @Nullable
+ private ComplexColor loadComplexColorForCookie(TypedValue value, int id, Theme theme) {
if (value.string == null) {
throw new UnsupportedOperationException(
- "Can't convert to color state list: type=0x" + value.type);
+ "Can't convert to ComplexColor: type=0x" + value.type);
}
final String file = value.string.toString();
@@ -2692,29 +2763,45 @@
if ((id >>> 24) == 0x1) {
final String name = getResourceName(id);
if (name != null) {
- Log.d(TAG, "Loading framework color state list #" + Integer.toHexString(id)
+ Log.d(TAG, "Loading framework ComplexColor #" + Integer.toHexString(id)
+ ": " + name + " at " + file);
}
}
}
if (DEBUG_LOAD) {
- Log.v(TAG, "Loading color state list for cookie " + value.assetCookie + ": " + file);
+ Log.v(TAG, "Loading ComplexColor for cookie " + value.assetCookie + ": " + file);
}
- final ColorStateList csl;
+ ComplexColor complexColor = null;
Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
if (file.endsWith(".xml")) {
try {
- final XmlResourceParser rp = loadXmlResourceParser(
- file, id, value.assetCookie, "colorstatelist");
- csl = ColorStateList.createFromXml(this, rp, theme);
- rp.close();
+ final XmlResourceParser parser = loadXmlResourceParser(
+ file, id, value.assetCookie, "ComplexColor");
+
+ final AttributeSet attrs = Xml.asAttributeSet(parser);
+ int type;
+ while ((type = parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT) {
+ // Seek parser to start tag.
+ }
+ if (type != XmlPullParser.START_TAG) {
+ throw new XmlPullParserException("No start tag found");
+ }
+
+ final String name = parser.getName();
+ if (name.equals("gradient")) {
+ complexColor = GradientColor.createFromXmlInner(this, parser, attrs, theme);
+ } else if (name.equals("selector")) {
+ complexColor = ColorStateList.createFromXmlInner(this, parser, attrs, theme);
+ }
+ parser.close();
} catch (Exception e) {
Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
final NotFoundException rnf = new NotFoundException(
- "File " + file + " from color state list resource ID #0x"
+ "File " + file + " from ComplexColor resource ID #0x"
+ Integer.toHexString(id));
rnf.initCause(e);
throw rnf;
@@ -2727,7 +2814,7 @@
}
Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
- return csl;
+ return complexColor;
}
/**
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index cc65e1e..6067577 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -454,6 +454,39 @@
}
/**
+ * Retrieve the ComplexColor for the attribute at <var>index</var>.
+ * The value may be either a {@link android.content.res.ColorStateList} which can wrap a simple
+ * color value or a {@link android.content.res.GradientColor}
+ * <p>
+ * This method will return {@code null} if the attribute is not defined or
+ * is not an integer color, color state list or GradientColor.
+ *
+ * @param index Index of attribute to retrieve.
+ *
+ * @return ComplexColor for the attribute, or {@code null} if not defined.
+ * @throws RuntimeException if the attribute if the TypedArray has already
+ * been recycled.
+ * @throws UnsupportedOperationException if the attribute is defined but is
+ * not an integer color, color state list or GradientColor.
+ */
+ @Nullable
+ public ComplexColor getComplexColor(@StyleableRes int index) {
+ if (mRecycled) {
+ throw new RuntimeException("Cannot make calls to a recycled instance!");
+ }
+
+ final TypedValue value = mValue;
+ if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
+ if (value.type == TypedValue.TYPE_ATTRIBUTE) {
+ throw new UnsupportedOperationException(
+ "Failed to resolve attribute at index " + index + ": " + value);
+ }
+ return mResources.loadComplexColor(value, value.resourceId, mTheme);
+ }
+ return null;
+ }
+
+ /**
* Retrieve the ColorStateList for the attribute at <var>index</var>.
* The value may be either a single solid color or a reference to
* a color or complex {@link android.content.res.ColorStateList}
diff --git a/core/java/com/android/internal/util/GrowingArrayUtils.java b/core/java/com/android/internal/util/GrowingArrayUtils.java
index b4d2d730..968d920 100644
--- a/core/java/com/android/internal/util/GrowingArrayUtils.java
+++ b/core/java/com/android/internal/util/GrowingArrayUtils.java
@@ -97,6 +97,21 @@
}
/**
+ * Primitive float version of {@link #append(Object[], int, Object)}.
+ */
+ public static float[] append(float[] array, int currentSize, float element) {
+ assert currentSize <= array.length;
+
+ if (currentSize + 1 > array.length) {
+ float[] newArray = ArrayUtils.newUnpaddedFloatArray(growSize(currentSize));
+ System.arraycopy(array, 0, newArray, 0, currentSize);
+ array = newArray;
+ }
+ array[currentSize] = element;
+ return array;
+ }
+
+ /**
* Inserts an element into the array at the specified index, growing the array if there is no
* more room.
*
diff --git a/core/jni/android_graphics_drawable_VectorDrawable.cpp b/core/jni/android_graphics_drawable_VectorDrawable.cpp
index 53d4c6a..563ec8b 100644
--- a/core/jni/android_graphics_drawable_VectorDrawable.cpp
+++ b/core/jni/android_graphics_drawable_VectorDrawable.cpp
@@ -90,6 +90,18 @@
strokeLineJoin);
}
+static void updateFullPathFillGradient(JNIEnv*, jobject, jlong pathPtr, jlong fillGradientPtr) {
+ VectorDrawable::FullPath* path = reinterpret_cast<VectorDrawable::FullPath*>(pathPtr);
+ SkShader* fillShader = reinterpret_cast<SkShader*>(fillGradientPtr);
+ path->setFillGradient(fillShader);
+}
+
+static void updateFullPathStrokeGradient(JNIEnv*, jobject, jlong pathPtr, jlong strokeGradientPtr) {
+ VectorDrawable::FullPath* path = reinterpret_cast<VectorDrawable::FullPath*>(pathPtr);
+ SkShader* strokeShader = reinterpret_cast<SkShader*>(strokeGradientPtr);
+ path->setStrokeGradient(strokeShader);
+}
+
static jboolean getFullPathProperties(JNIEnv* env, jobject, jlong fullPathPtr,
jbyteArray outProperties, jint length) {
VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
@@ -331,6 +343,8 @@
{"nCreateFullPath", "!()J", (void*)createEmptyFullPath},
{"nCreateFullPath", "!(J)J", (void*)createFullPath},
{"nUpdateFullPathProperties", "!(JFIFIFFFFFII)V", (void*)updateFullPathPropertiesAndStrokeStyles},
+ {"nUpdateFullPathFillGradient", "!(JJ)V", (void*)updateFullPathFillGradient},
+ {"nUpdateFullPathStrokeGradient", "!(JJ)V", (void*)updateFullPathStrokeGradient},
{"nGetFullPathProperties", "(J[BI)Z", (void*)getFullPathProperties},
{"nGetGroupProperties", "(J[FI)Z", (void*)getGroupProperties},
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 713038b..1f7206e 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3727,7 +3727,7 @@
<!-- Controls how the image should be resized or moved to match the size
of this ImageView. See {@link android.widget.ImageView.ScaleType} -->
<attr name="scaleType">
- <!-- Scale using the image matrix when drawing. See
+ <!-- Scale using the image matrix when drawing. See
{@link android.widget.ImageView#setImageMatrix(Matrix)}. -->
<enum name="matrix" value="0" />
<!-- Scale the image using {@link android.graphics.Matrix.ScaleToFit#FILL}. -->
@@ -3740,7 +3740,7 @@
<enum name="fitEnd" value="4" />
<!-- Center the image in the view, but perform no scaling. -->
<enum name="center" value="5" />
- <!-- Scale the image uniformly (maintain the image's aspect ratio) so both dimensions
+ <!-- Scale the image uniformly (maintain the image's aspect ratio) so both dimensions
(width and height) of the image will be equal to or larger than the corresponding
dimension of the view (minus padding). The image is then centered in the view. -->
<enum name="centerCrop" value="6" />
@@ -8135,4 +8135,52 @@
<attr name="entries" />
<attr name="entryValues" />
</declare-styleable>
+
+ <!-- Used to describe the gradient for fill or stroke in a path of VectorDrawable. -->
+ <declare-styleable name="GradientColor">
+ <!-- Start color of the gradient. -->
+ <attr name="startColor" />
+ <!-- Optional center color. -->
+ <attr name="centerColor" />
+ <!-- End color of the gradient. -->
+ <attr name="endColor" />
+ <!-- Type of gradient. The default type is linear. -->
+ <attr name="type" />
+
+ <!-- Only applied to RadialGradient-->
+ <!-- Radius of the gradient, used only with radial gradient. -->
+ <attr name="gradientRadius" />
+
+ <!-- Only applied to SweepGradient / RadialGradient-->
+ <!-- X coordinate of the center of the gradient within the path. -->
+ <attr name="centerX" />
+ <!-- Y coordinate of the center of the gradient within the path. -->
+ <attr name="centerY" />
+
+ <!-- LinearGradient specific -->
+ <!-- X coordinate of the start point origin of the gradient.
+ Defined in same coordinates as the path itself -->
+ <attr name="startX" format="float" />
+ <!-- Y coordinate of the start point of the gradient within the shape.
+ Defined in same coordinates as the path itself -->
+ <attr name="startY" format="float" />
+ <!-- X coordinate of the end point origin of the gradient.
+ Defined in same coordinates as the path itself -->
+ <attr name="endX" format="float" />
+ <!-- Y coordinate of the end point of the gradient within the shape.
+ Defined in same coordinates as the path itself -->
+ <attr name="endY" format="float" />
+
+ </declare-styleable>
+
+ <!-- Describes an item of a GradientColor. Minimally need 2 items to define the gradient
+ Colors defined in <item> override the simple color attributes such as
+ "startColor / centerColor / endColor" are ignored -->
+ <declare-styleable name="GradientColorItem">
+ <!-- The offset (or ratio) of this current color item inside the gradient.
+ The value is only meaningful when it is between 0 and 1. -->
+ <attr name="offset" format="float" />
+ <!-- The current color for the offset inside the gradient. -->
+ <attr name="color" />
+ </declare-styleable>
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 57132ea..a2ad09b 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2691,6 +2691,11 @@
<public type="attr" name="canPerformGestures" />
<public type="attr" name="externalService" />
<public type="attr" name="supportsLocalInteraction" />
+ <public type="attr" name="startX" />
+ <public type="attr" name="startY" />
+ <public type="attr" name="endX" />
+ <public type="attr" name="endY" />
+ <public type="attr" name="offset" />
<public type="style" name="Theme.Material.Light.DialogWhenLarge.DarkActionBar" />
<public type="style" name="Widget.Material.SeekBar.Discrete" />
diff --git a/graphics/java/android/graphics/Shader.java b/graphics/java/android/graphics/Shader.java
index adb282f..94983b3 100644
--- a/graphics/java/android/graphics/Shader.java
+++ b/graphics/java/android/graphics/Shader.java
@@ -117,7 +117,10 @@
}
}
- /* package */ long getNativeInstance() {
+ /**
+ * @hide
+ */
+ public long getNativeInstance() {
return native_instance;
}
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index 6526021..1fc1b83 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -17,6 +17,8 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.res.ColorStateList;
+import android.content.res.ComplexColor;
+import android.content.res.GradientColor;
import android.content.res.Resources;
import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
@@ -27,6 +29,7 @@
import android.graphics.PorterDuffColorFilter;
import android.graphics.Rect;
import android.graphics.PorterDuff.Mode;
+import android.graphics.Shader;
import android.util.ArrayMap;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
@@ -121,9 +124,9 @@
* <dd>Defines path data using exactly same format as "d" attribute
* in the SVG's path data. This is defined in the viewport space.</dd>
* <dt><code>android:fillColor</code></dt>
- * <dd>Specifies the color used to fill the path. May be a color or (SDK 24+ only) a color state
- * list. If this property is animated, any value set by the animation will override the original
- * value. No path fill is drawn if this property is not specified.</dd>
+ * <dd>Specifies the color used to fill the path. May be a color, also may be a color state list or
+ * a gradient color for SDK 24+. If this property is animated, any value set by the animation will
+ * override the original value. No path fill is drawn if this property is not specified.</dd>
* <dt><code>android:strokeColor</code></dt>
* <dd>Specifies the color used to draw the path outline. May be a color or (SDK 24+ only) a color
* state list. If this property is animated, any value set by the animation will override the
@@ -1276,8 +1279,9 @@
/////////////////////////////////////////////////////
// Variables below need to be copied (deep copy if applicable) for mutation.
private int[] mThemeAttrs;
- ColorStateList mStrokeColors = null;
- ColorStateList mFillColors = null;
+
+ ComplexColor mStrokeColors = null;
+ ComplexColor mFillColors = null;
private long mNativePtr = 0;
public VFullPath() {
@@ -1297,23 +1301,25 @@
public boolean onStateChange(int[] stateSet) {
boolean changed = false;
- if (mStrokeColors != null) {
+ if (mStrokeColors != null && mStrokeColors instanceof ColorStateList) {
final int oldStrokeColor = getStrokeColor();
- final int newStrokeColor = mStrokeColors.getColorForState(stateSet, oldStrokeColor);
+ final int newStrokeColor =
+ ((ColorStateList) mStrokeColors).getColorForState(stateSet, oldStrokeColor);
changed |= oldStrokeColor != newStrokeColor;
if (oldStrokeColor != newStrokeColor) {
nSetStrokeColor(mNativePtr, newStrokeColor);
}
}
- if (mFillColors != null) {
+ if (mFillColors != null && mFillColors instanceof ColorStateList) {
final int oldFillColor = getFillColor();
- final int newFillColor = mFillColors.getColorForState(stateSet, oldFillColor);
+ final int newFillColor = ((ColorStateList) mFillColors).getColorForState(stateSet, oldFillColor);
changed |= oldFillColor != newFillColor;
if (oldFillColor != newFillColor) {
nSetFillColor(mNativePtr, newFillColor);
}
}
+
return changed;
}
@@ -1372,7 +1378,8 @@
int strokeLineCap = properties.getInt(STROKE_LINE_CAP_INDEX * 4);
int strokeLineJoin = properties.getInt(STROKE_LINE_JOIN_INDEX * 4);
float strokeMiterLimit = properties.getFloat(STROKE_MITER_LIMIT_INDEX * 4);
-
+ Shader fillGradient = null;
+ Shader strokeGradient = null;
// Account for any configuration changes.
mChangingConfigurations |= a.getChangingConfigurations();
@@ -1391,23 +1398,43 @@
nSetPathString(mNativePtr, pathString, pathString.length());
}
- final ColorStateList fillColors = a.getColorStateList(
+ final ComplexColor fillColors = a.getComplexColor(
R.styleable.VectorDrawablePath_fillColor);
if (fillColors != null) {
- // If the color state list isn't stateful, discard the state
- // list and keep the default (e.g. the only) color.
- mFillColors = fillColors.isStateful() ? fillColors : null;
+ // If the colors is a gradient color, or the color state list is stateful, keep the
+ // colors information. Otherwise, discard the colors and keep the default color.
+ if (fillColors instanceof GradientColor) {
+ mFillColors = fillColors;
+ fillGradient = ((GradientColor) fillColors).getShader();
+ } else if (fillColors.isStateful()) {
+ mFillColors = fillColors;
+ } else {
+ mFillColors = null;
+ }
fillColor = fillColors.getDefaultColor();
}
- final ColorStateList strokeColors = a.getColorStateList(
+ final ComplexColor strokeColors = a.getComplexColor(
R.styleable.VectorDrawablePath_strokeColor);
if (strokeColors != null) {
- // If the color state list isn't stateful, discard the state
- // list and keep the default (e.g. the only) color.
- mStrokeColors = strokeColors.isStateful() ? strokeColors : null;
+ // If the colors is a gradient color, or the color state list is stateful, keep the
+ // colors information. Otherwise, discard the colors and keep the default color.
+ if (strokeColors instanceof GradientColor) {
+ mStrokeColors = strokeColors;
+ strokeGradient = ((GradientColor) strokeColors).getShader();
+ } else if (strokeColors.isStateful()) {
+ mStrokeColors = strokeColors;
+ } else {
+ mStrokeColors = null;
+ }
strokeColor = strokeColors.getDefaultColor();
}
+ // Update the gradient info, even if the gradiet is null.
+ nUpdateFullPathFillGradient(mNativePtr,
+ fillGradient != null ? fillGradient.getNativeInstance() : 0);
+ nUpdateFullPathStrokeGradient(mNativePtr,
+ strokeGradient != null ? strokeGradient.getNativeInstance() : 0);
+
fillAlpha = a.getFloat(R.styleable.VectorDrawablePath_fillAlpha, fillAlpha);
strokeLineCap = a.getInt(
@@ -1434,18 +1461,44 @@
@Override
public boolean canApplyTheme() {
- return mThemeAttrs != null;
+ if (mThemeAttrs != null) {
+ return true;
+ }
+ boolean fillCanApplyTheme = canGradientApplyTheme(mFillColors);
+ boolean strokeCanApplyTheme = canGradientApplyTheme(mStrokeColors);
+ if (fillCanApplyTheme || strokeCanApplyTheme) {
+ return true;
+ }
+ return false;
+
}
@Override
public void applyTheme(Theme t) {
- if (mThemeAttrs == null) {
- return;
+ if (mThemeAttrs != null) {
+ final TypedArray a = t.resolveAttributes(mThemeAttrs, R.styleable.VectorDrawablePath);
+ updateStateFromTypedArray(a);
+ a.recycle();
}
- final TypedArray a = t.resolveAttributes(mThemeAttrs, R.styleable.VectorDrawablePath);
- updateStateFromTypedArray(a);
- a.recycle();
+ boolean fillCanApplyTheme = canGradientApplyTheme(mFillColors);
+ boolean strokeCanApplyTheme = canGradientApplyTheme(mStrokeColors);
+ if (fillCanApplyTheme) {
+ mFillColors = mFillColors.obtainForTheme(t);
+ nUpdateFullPathFillGradient(mNativePtr,
+ ((GradientColor)mFillColors).getShader().getNativeInstance());
+ }
+
+ if (strokeCanApplyTheme) {
+ mStrokeColors = mStrokeColors.obtainForTheme(t);
+ nUpdateFullPathStrokeGradient(mNativePtr,
+ ((GradientColor)mStrokeColors).getShader().getNativeInstance());
+ }
+ }
+
+ private boolean canGradientApplyTheme(ComplexColor complexColor) {
+ return complexColor != null && complexColor.canApplyTheme()
+ && complexColor instanceof GradientColor;
}
/* Setters and Getters, used by animator from AnimatedVectorDrawable. */
@@ -1560,6 +1613,8 @@
int strokeColor, float strokeAlpha, int fillColor, float fillAlpha, float trimPathStart,
float trimPathEnd, float trimPathOffset, float strokeMiterLimit, int strokeLineCap,
int strokeLineJoin);
+ private static native void nUpdateFullPathFillGradient(long pathPtr, long fillGradientPtr);
+ private static native void nUpdateFullPathStrokeGradient(long pathPtr, long strokeGradientPtr);
private static native long nCreateClipPath();
private static native long nCreateClipPath(long clipPathPtr);
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index 1d31c9e..4d4acb9 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -18,6 +18,7 @@
#include "PathParser.h"
#include "SkImageInfo.h"
+#include "SkShader.h"
#include <utils/Log.h>
#include "utils/Macros.h"
#include "utils/VectorDrawableUtils.h"
@@ -49,7 +50,7 @@
float minScale = fmin(scaleX, scaleY);
float strokeScale = minScale * matrixScale;
- drawPath(outCanvas, renderPath, strokeScale);
+ drawPath(outCanvas, renderPath, strokeScale, pathMatrix);
}
void Path::setPathData(const Data& data) {
@@ -148,6 +149,9 @@
mStrokeMiterLimit = path.mStrokeMiterLimit;
mStrokeLineCap = path.mStrokeLineCap;
mStrokeLineJoin = path.mStrokeLineJoin;
+
+ SkRefCnt_SafeAssign(mStrokeGradient, path.mStrokeGradient);
+ SkRefCnt_SafeAssign(mFillGradient, path.mFillGradient);
}
const SkPath& FullPath::getUpdatedPath() {
@@ -186,22 +190,44 @@
return SkColorSetA(color, alphaBytes * alpha);
}
-void FullPath::drawPath(SkCanvas* outCanvas, const SkPath& renderPath, float strokeScale){
- // Draw path's fill, if fill color isn't transparent.
- if (mFillColor != SK_ColorTRANSPARENT) {
- mPaint.setStyle(SkPaint::Style::kFill_Style);
- mPaint.setAntiAlias(true);
+void FullPath::drawPath(SkCanvas* outCanvas, const SkPath& renderPath, float strokeScale,
+ const SkMatrix& matrix){
+ // Draw path's fill, if fill color or gradient is valid
+ bool needsFill = false;
+ if (mFillGradient != nullptr) {
+ mPaint.setColor(applyAlpha(SK_ColorBLACK, mFillAlpha));
+ SkShader* newShader = mFillGradient->newWithLocalMatrix(matrix);
+ mPaint.setShader(newShader);
+ needsFill = true;
+ } else if (mFillColor != SK_ColorTRANSPARENT) {
mPaint.setColor(applyAlpha(mFillColor, mFillAlpha));
outCanvas->drawPath(renderPath, mPaint);
+ needsFill = true;
}
- // Draw path's stroke, if stroke color isn't transparent
- if (mStrokeColor != SK_ColorTRANSPARENT) {
+
+ if (needsFill) {
+ mPaint.setStyle(SkPaint::Style::kFill_Style);
+ mPaint.setAntiAlias(true);
+ outCanvas->drawPath(renderPath, mPaint);
+ }
+
+ // Draw path's stroke, if stroke color or gradient is valid
+ bool needsStroke = false;
+ if (mStrokeGradient != nullptr) {
+ mPaint.setColor(applyAlpha(SK_ColorBLACK, mStrokeAlpha));
+ SkShader* newShader = mStrokeGradient->newWithLocalMatrix(matrix);
+ mPaint.setShader(newShader);
+ needsStroke = true;
+ } else if (mStrokeColor != SK_ColorTRANSPARENT) {
+ mPaint.setColor(applyAlpha(mStrokeColor, mStrokeAlpha));
+ needsStroke = true;
+ }
+ if (needsStroke) {
mPaint.setStyle(SkPaint::Style::kStroke_Style);
mPaint.setAntiAlias(true);
mPaint.setStrokeJoin(mStrokeLineJoin);
mPaint.setStrokeCap(mStrokeLineCap);
mPaint.setStrokeMiter(mStrokeMiterLimit);
- mPaint.setColor(applyAlpha(mStrokeColor, mStrokeAlpha));
mPaint.setStrokeWidth(mStrokeWidth * strokeScale);
outCanvas->drawPath(renderPath, mPaint);
}
@@ -288,7 +314,7 @@
}
void ClipPath::drawPath(SkCanvas* outCanvas, const SkPath& renderPath,
- float strokeScale){
+ float strokeScale, const SkMatrix& matrix){
outCanvas->clipPath(renderPath, SkRegion::kIntersect_Op);
}
diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h
index 5ae5f6a..09bdce5 100644
--- a/libs/hwui/VectorDrawable.h
+++ b/libs/hwui/VectorDrawable.h
@@ -26,6 +26,7 @@
#include <SkPath.h>
#include <SkPathMeasure.h>
#include <SkRect.h>
+#include <SkShader.h>
#include <cutils/compiler.h>
#include <stddef.h>
@@ -95,7 +96,7 @@
protected:
virtual const SkPath& getUpdatedPath();
virtual void drawPath(SkCanvas *outCanvas, const SkPath& renderPath,
- float strokeScale) = 0;
+ float strokeScale, const SkMatrix& matrix) = 0;
Data mData;
SkPath mSkPath;
bool mSkPathDirty = true;
@@ -108,6 +109,11 @@
FullPath() : Path() {}
FullPath(const Data& nodes) : Path(nodes) {}
+ ~FullPath() {
+ SkSafeUnref(mFillGradient);
+ SkSafeUnref(mStrokeGradient);
+ }
+
void updateProperties(float strokeWidth, SkColor strokeColor,
float strokeAlpha, SkColor fillColor, float fillAlpha,
float trimPathStart, float trimPathEnd, float trimPathOffset,
@@ -162,10 +168,18 @@
}
bool getProperties(int8_t* outProperties, int length);
+ void setFillGradient(SkShader* fillGradient) {
+ SkRefCnt_SafeAssign(mFillGradient, fillGradient);
+ };
+ void setStrokeGradient(SkShader* strokeGradient) {
+ SkRefCnt_SafeAssign(mStrokeGradient, strokeGradient);
+ };
+
+
protected:
const SkPath& getUpdatedPath() override;
void drawPath(SkCanvas* outCanvas, const SkPath& renderPath,
- float strokeScale) override;
+ float strokeScale, const SkMatrix& matrix) override;
private:
// Applies trimming to the specified path.
@@ -174,6 +188,8 @@
SkColor mStrokeColor = SK_ColorTRANSPARENT;
float mStrokeAlpha = 1;
SkColor mFillColor = SK_ColorTRANSPARENT;
+ SkShader* mStrokeGradient = nullptr;
+ SkShader* mFillGradient = nullptr;
float mFillAlpha = 1;
float mTrimPathStart = 0;
float mTrimPathEnd = 1;
@@ -195,7 +211,7 @@
protected:
void drawPath(SkCanvas* outCanvas, const SkPath& renderPath,
- float strokeScale) override;
+ float strokeScale, const SkMatrix& matrix) override;
};
class ANDROID_API Group: public Node {
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_linear.xml b/tests/VectorDrawableTest/res/color/fill_gradient_linear.xml
new file mode 100644
index 0000000..e0e3f03
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/fill_gradient_linear.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+ android:angle="90"
+ android:startColor="?android:attr/colorPrimary"
+ android:endColor="?android:attr/colorControlActivated"
+ android:centerColor="#00ff0000"
+ android:startX="0"
+ android:startY="0"
+ android:endX="100"
+ android:endY="100"
+ android:type="linear">
+</gradient>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_linear_item.xml b/tests/VectorDrawableTest/res/color/fill_gradient_linear_item.xml
new file mode 100644
index 0000000..cfb1236
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/fill_gradient_linear_item.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+ android:angle="90"
+ android:startColor="?android:attr/colorPrimary"
+ android:endColor="?android:attr/colorControlActivated"
+ android:centerColor="#f00"
+ android:startX="0"
+ android:startY="0"
+ android:endX="100"
+ android:endY="100"
+ android:type="linear">
+ <item android:offset="0.1" android:color="?android:attr/colorPrimary"/>
+ <item android:offset="0.4" android:color="#fff"/>
+ <item android:offset="0.9" android:color="?android:attr/colorControlActivated"/>
+</gradient>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_linear_item_overlap.xml b/tests/VectorDrawableTest/res/color/fill_gradient_linear_item_overlap.xml
new file mode 100644
index 0000000..18274b9
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/fill_gradient_linear_item_overlap.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+ android:angle="90"
+ android:startColor="?android:attr/colorPrimary"
+ android:endColor="?android:attr/colorControlActivated"
+ android:centerColor="#f00"
+ android:startX="0"
+ android:startY="0"
+ android:endX="100"
+ android:endY="100"
+ android:type="linear">
+ <item android:offset="0.1" android:color="?android:attr/colorPrimary"/>
+ <item android:offset="0.4" android:color="#f00"/>
+ <item android:offset="0.4" android:color="#fff"/>
+ <item android:offset="0.9" android:color="?android:attr/colorControlActivated"/>
+</gradient>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_radial.xml b/tests/VectorDrawableTest/res/color/fill_gradient_radial.xml
new file mode 100644
index 0000000..ef6fd70
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/fill_gradient_radial.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+ android:centerColor="#ff0000"
+ android:endColor="?android:attr/colorControlActivated"
+ android:centerX="300"
+ android:centerY="300"
+ android:gradientRadius="100"
+ android:startColor="?android:attr/colorPrimary"
+ android:type="radial">
+</gradient>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_radial_item.xml b/tests/VectorDrawableTest/res/color/fill_gradient_radial_item.xml
new file mode 100644
index 0000000..51b0e17
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/fill_gradient_radial_item.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+ <!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+ android:centerColor="#ff0000"
+ android:endColor="#ff0000ff"
+ android:centerX="300"
+ android:centerY="300"
+ android:gradientRadius="100"
+ android:startColor="#ffffffff"
+ android:type="radial">
+ <item android:offset="0.1" android:color="?android:attr/colorPrimary"/>
+ <item android:offset="0.4" android:color="#fff"/>
+ <item android:offset="0.9" android:color="?android:attr/colorControlActivated"/>
+</gradient>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_radial_item_short.xml b/tests/VectorDrawableTest/res/color/fill_gradient_radial_item_short.xml
new file mode 100644
index 0000000..8caa1b4
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/fill_gradient_radial_item_short.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+ <!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+ android:centerX="300"
+ android:centerY="300"
+ android:gradientRadius="100"
+ android:type="radial">
+ <item android:offset="0.1" android:color="?android:attr/colorPrimary"/>
+ <item android:offset="0.9" android:color="?android:attr/colorControlActivated"/>
+</gradient>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_sweep.xml b/tests/VectorDrawableTest/res/color/fill_gradient_sweep.xml
new file mode 100644
index 0000000..e1fbd10
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/fill_gradient_sweep.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+ android:centerColor="#ff0000"
+ android:endColor="#ff0000ff"
+ android:centerX="500"
+ android:centerY="500"
+ android:gradientRadius="10"
+ android:startColor="#ffffffff"
+ android:type="sweep">
+</gradient>
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_sweep_item.xml b/tests/VectorDrawableTest/res/color/fill_gradient_sweep_item.xml
new file mode 100644
index 0000000..332b938
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/fill_gradient_sweep_item.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+ android:centerColor="#ff0000"
+ android:endColor="#ff0000ff"
+ android:centerX="500"
+ android:centerY="500"
+ android:gradientRadius="10"
+ android:startColor="#ffffffff"
+ android:type="sweep">
+ <item android:offset="0.1" android:color="?android:attr/colorPrimary"/>
+ <item android:offset="0.4" android:color="#fff"/>
+ <item android:offset="0.9" android:color="?android:attr/colorControlActivated"/>
+</gradient>
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_sweep_item_long.xml b/tests/VectorDrawableTest/res/color/fill_gradient_sweep_item_long.xml
new file mode 100644
index 0000000..3931288
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/fill_gradient_sweep_item_long.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+ android:centerX="500"
+ android:centerY="500"
+ android:gradientRadius="10"
+ android:type="sweep">
+ <item android:offset="-0.3" android:color="#f00"/>
+ <item android:offset="0.1" android:color="?android:attr/colorPrimary"/>
+ <item android:offset="0.4" android:color="#0f0"/>
+ <item android:offset="0.6" android:color="#00f"/>
+ <item android:offset="0.7" android:color="?android:attr/colorControlActivated"/>
+ <item android:offset="1.5" android:color="#00f"/>
+</gradient>
diff --git a/tests/VectorDrawableTest/res/color/stroke_gradient.xml b/tests/VectorDrawableTest/res/color/stroke_gradient.xml
new file mode 100644
index 0000000..cb324c9
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/stroke_gradient.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+ android:angle="90"
+ android:centerColor="#7f7f7f"
+ android:endColor="#ffffff"
+ android:startColor="#000000"
+ android:startX="0"
+ android:endX="100"
+ android:startY="0"
+ android:endY="0"
+ android:type="linear">
+</gradient>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/color/stroke_gradient_item.xml b/tests/VectorDrawableTest/res/color/stroke_gradient_item.xml
new file mode 100644
index 0000000..15d948c
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/stroke_gradient_item.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+ android:angle="90"
+ android:centerColor="#7f7f7f"
+ android:endColor="#ffffff"
+ android:startColor="#000000"
+ android:startX="0"
+ android:endX="100"
+ android:startY="0"
+ android:endY="0"
+ android:type="linear">
+ <item android:offset="0.1" android:color="#f00"/>
+ <item android:offset="0.2" android:color="#f0f"/>
+ <item android:offset="0.9" android:color="#f00f"/>
+</gradient>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/color/stroke_gradient_item_alpha.xml b/tests/VectorDrawableTest/res/color/stroke_gradient_item_alpha.xml
new file mode 100644
index 0000000..fda2b88
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/stroke_gradient_item_alpha.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+ android:startX="0"
+ android:endX="100"
+ android:startY="0"
+ android:endY="0"
+ android:type="linear">
+ <item android:offset="0.1" android:color="#f00"/>
+ <item android:offset="0.2" android:color="#2f0f"/>
+ <item android:offset="0.9" android:color="#f00f"/>
+</gradient>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/color/vector_icon_fill_state_list.xml b/tests/VectorDrawableTest/res/color/vector_icon_fill_state_list.xml
new file mode 100644
index 0000000..45d88b5
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/vector_icon_fill_state_list.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="?android:attr/colorPrimary" android:state_pressed="true" />
+ <item android:color="?android:attr/colorControlActivated" />
+</selector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/color/vector_icon_stroke_state_list.xml b/tests/VectorDrawableTest/res/color/vector_icon_stroke_state_list.xml
new file mode 100644
index 0000000..16251c8
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/vector_icon_stroke_state_list.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="?android:attr/colorControlActivated" android:state_pressed="true" />
+ <item android:color="?android:attr/colorPrimary" />
+</selector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml
index 2be99be..89afde2 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml
@@ -27,8 +27,8 @@
<path
android:name="box1"
android:pathData="m20,200l100,90l180-180l-35-35l-145,145l-60-60l-40,40z"
- android:fillColor="?android:attr/colorControlNormal"
- android:strokeColor="?android:attr/colorControlNormal"
+ android:fillColor="?android:attr/colorPrimary"
+ android:strokeColor="?android:attr/colorPrimary"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</group>
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_1.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_1.xml
new file mode 100644
index 0000000..d67aca7
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_1.xml
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="400"
+ android:viewportWidth="400" >
+
+<group android:name="backgroundGroup"
+ android:scaleX="0.5"
+ android:scaleY="0.5">
+ <path
+ android:name="background1"
+ android:fillColor="@color/fill_gradient_linear"
+ android:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" />
+ <path
+ android:name="background2"
+ android:fillColor="@color/fill_gradient_radial"
+ android:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" />
+ <path
+ android:name="background3"
+ android:fillColor="@color/fill_gradient_sweep"
+ android:pathData="M 400,400 l 200,0 l 0, 200 l -200, 0 z" />
+</group>
+<group
+ android:name="translateToCenterGroup"
+ android:translateX="50.0"
+ android:translateY="90.0" >
+ <path
+ android:name="twoLines"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="@color/stroke_gradient"
+ android:strokeWidth="20" />
+
+ <group
+ android:name="rotationGroup"
+ android:pivotX="0.0"
+ android:pivotY="0.0"
+ android:rotation="-45.0">
+ <path
+ android:name="twoLines1"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="@color/stroke_gradient"
+ android:strokeWidth="20" />
+
+ <group
+ android:name="translateGroup"
+ android:translateX="130.0"
+ android:translateY="160.0">
+ <group android:name="scaleGroup" >
+ <path
+ android:name="twoLines3"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="@color/stroke_gradient"
+ android:strokeWidth="20" />
+ </group>
+ </group>
+
+ <group
+ android:name="translateGroupHalf"
+ android:translateX="65.0"
+ android:translateY="80.0">
+ <group android:name="scaleGroup" >
+ <path
+ android:name="twoLines2"
+ android:pathData="@string/twoLinePathData"
+ android:fillColor="@color/fill_gradient_linear"
+ android:strokeColor="@color/stroke_gradient"
+ android:strokeWidth="20" />
+ </group>
+ </group>
+ </group>
+</group>
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_2.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_2.xml
new file mode 100644
index 0000000..abf3c7a
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_2.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="400"
+ android:viewportWidth="400" >
+
+<group android:name="backgroundGroup"
+ android:scaleX="0.5"
+ android:scaleY="0.5">
+ <path
+ android:name="background1"
+ android:fillColor="@color/fill_gradient_linear_item"
+ android:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" />
+ <path
+ android:name="background2"
+ android:fillColor="@color/fill_gradient_radial_item"
+ android:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" />
+ <path
+ android:name="background3"
+ android:fillColor="@color/fill_gradient_sweep_item"
+ android:pathData="M 400,400 l 200,0 l 0, 200 l -200, 0 z" />
+</group>
+<group
+ android:name="translateToCenterGroup"
+ android:translateX="50.0"
+ android:translateY="90.0" >
+ <path
+ android:name="twoLines"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="@color/stroke_gradient_item"
+ android:strokeWidth="20" />
+
+ <group
+ android:name="rotationGroup"
+ android:pivotX="0.0"
+ android:pivotY="0.0"
+ android:rotation="-45.0">
+ <path
+ android:name="twoLines1"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="@color/stroke_gradient_item"
+ android:strokeWidth="20" />
+
+ <group
+ android:name="translateGroup"
+ android:translateX="130.0"
+ android:translateY="160.0">
+ <group android:name="scaleGroup" >
+ <path
+ android:name="twoLines3"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="@color/stroke_gradient_item"
+ android:strokeWidth="20" />
+ </group>
+ </group>
+
+ <group
+ android:name="translateGroupHalf"
+ android:translateX="65.0"
+ android:translateY="80.0">
+ <group android:name="scaleGroup" >
+ <path
+ android:name="twoLines2"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="@color/stroke_gradient_item"
+ android:strokeWidth="20" />
+ </group>
+ </group>
+ </group>
+</group>
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_3.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_3.xml
new file mode 100644
index 0000000..5f9726f
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_3.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="400"
+ android:viewportWidth="400" >
+
+<group android:name="backgroundGroup"
+ android:scaleX="0.5"
+ android:scaleY="0.5">
+ <path
+ android:name="background1"
+ android:fillColor="@color/fill_gradient_linear_item_overlap"
+ android:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" />
+ <path
+ android:name="background2"
+ android:fillColor="@color/fill_gradient_radial_item_short"
+ android:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" />
+ <path
+ android:name="background3"
+ android:fillColor="@color/fill_gradient_sweep_item_long"
+ android:pathData="M 400,400 l 200,0 l 0, 200 l -200, 0 z" />
+</group>
+<group
+ android:name="translateToCenterGroup"
+ android:translateX="50.0"
+ android:translateY="90.0" >
+ <path
+ android:name="twoLines"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="@color/stroke_gradient_item_alpha"
+ android:strokeWidth="20" />
+
+ <group
+ android:name="rotationGroup"
+ android:pivotX="0.0"
+ android:pivotY="0.0"
+ android:rotation="-45.0">
+ <path
+ android:name="twoLines1"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="@color/stroke_gradient_item_alpha"
+ android:strokeWidth="20" />
+
+ <group
+ android:name="translateGroup"
+ android:translateX="130.0"
+ android:translateY="160.0">
+ <group android:name="scaleGroup" >
+ <path
+ android:name="twoLines3"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="@color/stroke_gradient_item_alpha"
+ android:strokeWidth="20" />
+ </group>
+ </group>
+
+ <group
+ android:name="translateGroupHalf"
+ android:translateX="65.0"
+ android:translateY="80.0">
+ <group android:name="scaleGroup" >
+ <path
+ android:name="twoLines2"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="@color/stroke_gradient_item_alpha"
+ android:strokeWidth="20" />
+ </group>
+ </group>
+ </group>
+</group>
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_state_list.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_state_list.xml
new file mode 100644
index 0000000..b1ed850
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_state_list.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="24"
+ android:viewportWidth="24" >
+
+ <path
+ android:fillColor="@color/vector_icon_fill_state_list"
+ android:strokeColor="@color/vector_icon_stroke_state_list"
+ android:strokeWidth="3"
+ android:pathData="M16.0,5.0c-1.955.0 -3.83,1.268 -4.5,3.0c-0.67-1.732 -2.547-3.0 -4.5-3.0C4.4570007,5.0 2.5,6.931999 2.5,9.5c0.0,3.529 3.793,6.258 9.0,11.5c5.207-5.242 9.0-7.971 9.0-11.5C20.5,6.931999 18.543,5.0 16.0,5.0z"/>
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
index b4a93f6..a7da286 100644
--- a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
+++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
@@ -35,6 +35,10 @@
public class VectorDrawablePerformance extends Activity {
private static final String LOGCAT = "VectorDrawable1";
protected int[] icon = {
+ R.drawable.vector_icon_gradient_1,
+ R.drawable.vector_icon_gradient_2,
+ R.drawable.vector_icon_gradient_3,
+ R.drawable.vector_icon_state_list,
R.drawable.vector_drawable01,
R.drawable.vector_drawable02,
R.drawable.vector_drawable03,
@@ -102,7 +106,7 @@
ScrollView scrollView = new ScrollView(this);
GridLayout container = new GridLayout(this);
scrollView.addView(container);
- container.setColumnCount(5);
+ container.setColumnCount(4);
Resources res = this.getResources();
container.setBackgroundColor(0xFF888888);
VectorDrawable []d = new VectorDrawable[icon.length];