Merge "AVD now support path morphing."
diff --git a/core/java/android/animation/AnimatorInflater.java b/core/java/android/animation/AnimatorInflater.java
index 39fcf73..0f5e954 100644
--- a/core/java/android/animation/AnimatorInflater.java
+++ b/core/java/android/animation/AnimatorInflater.java
@@ -23,10 +23,12 @@
 import android.content.res.XmlResourceParser;
 import android.graphics.Path;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.util.PathParser;
 import android.util.StateSet;
 import android.util.TypedValue;
 import android.util.Xml;
+import android.view.InflateException;
 import android.view.animation.AnimationUtils;
 
 import com.android.internal.R;
@@ -47,7 +49,7 @@
  * <em>something</em> file.)
  */
 public class AnimatorInflater {
-
+    private static final String TAG = "AnimatorInflater";
     /**
      * These flags are used when parsing AnimatorSet objects
      */
@@ -59,9 +61,12 @@
      */
     private static final int VALUE_TYPE_FLOAT       = 0;
     private static final int VALUE_TYPE_INT         = 1;
+    private static final int VALUE_TYPE_PATH        = 2;
     private static final int VALUE_TYPE_COLOR       = 4;
     private static final int VALUE_TYPE_CUSTOM      = 5;
 
+    private static final boolean DBG_ANIMATOR_INFLATER = false;
+
     /**
      * Loads an {@link Animator} object from a resource
      *
@@ -189,6 +194,56 @@
     }
 
     /**
+     * PathDataEvaluator is used to interpolate between two paths which are
+     * represented in the same format but different control points' values.
+     * The path is represented as an array of PathDataNode here, which is
+     * fundamentally an array of floating point numbers.
+     */
+    private static class PathDataEvaluator implements TypeEvaluator<PathParser.PathDataNode[]> {
+        private PathParser.PathDataNode[] mNodeArray;
+
+        /**
+         * Create a PathParser.PathDataNode[] that does not reuse the animated value.
+         * Care must be taken when using this option because on every evaluation
+         * a new <code>PathParser.PathDataNode[]</code> will be allocated.
+         */
+        private PathDataEvaluator() {}
+
+        /**
+         * Create a PathDataEvaluator that reuses <code>nodeArray</code> for every evaluate() call.
+         * Caution must be taken to ensure that the value returned from
+         * {@link android.animation.ValueAnimator#getAnimatedValue()} is not cached, modified, or
+         * used across threads. The value will be modified on each <code>evaluate()</code> call.
+         *
+         * @param nodeArray The array to modify and return from <code>evaluate</code>.
+         */
+        public PathDataEvaluator(PathParser.PathDataNode[] nodeArray) {
+            mNodeArray = nodeArray;
+        }
+
+        @Override
+        public PathParser.PathDataNode[] evaluate(float fraction,
+                PathParser.PathDataNode[] startPathData,
+                PathParser.PathDataNode[] endPathData) {
+            if (!PathParser.canMorph(startPathData, endPathData)) {
+                throw new IllegalArgumentException("Can't interpolate between"
+                        + " two incompatible pathData");
+            }
+
+            if (mNodeArray == null || !PathParser.canMorph(mNodeArray, startPathData)) {
+                mNodeArray = PathParser.deepCopyNodes(startPathData);
+            }
+
+            for (int i = 0; i < startPathData.length; i++) {
+                mNodeArray[i].interpolatePathDataNode(startPathData[i],
+                        endPathData[i], fraction);
+            }
+
+            return mNodeArray;
+        }
+    }
+
+    /**
      * @param anim Null if this is a ValueAnimator, otherwise this is an
      *            ObjectAnimator
      * @param arrayAnimator Incoming typed array for Animator's attributes.
@@ -209,27 +264,157 @@
         }
 
         TypeEvaluator evaluator = null;
-        int valueFromIndex = R.styleable.Animator_valueFrom;
-        int valueToIndex = R.styleable.Animator_valueTo;
 
         boolean getFloats = (valueType == VALUE_TYPE_FLOAT);
 
-        TypedValue tvFrom = arrayAnimator.peekValue(valueFromIndex);
+        TypedValue tvFrom = arrayAnimator.peekValue(R.styleable.Animator_valueFrom);
         boolean hasFrom = (tvFrom != null);
         int fromType = hasFrom ? tvFrom.type : 0;
-        TypedValue tvTo = arrayAnimator.peekValue(valueToIndex);
+        TypedValue tvTo = arrayAnimator.peekValue(R.styleable.Animator_valueTo);
         boolean hasTo = (tvTo != null);
         int toType = hasTo ? tvTo.type : 0;
 
-        if ((hasFrom && (fromType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
-                (fromType <= TypedValue.TYPE_LAST_COLOR_INT)) ||
-                (hasTo && (toType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
-                        (toType <= TypedValue.TYPE_LAST_COLOR_INT))) {
-            // special case for colors: ignore valueType and get ints
-            getFloats = false;
-            evaluator = ArgbEvaluator.getInstance();
+        // TODO: Further clean up this part of code into 4 types : path, color,
+        // integer and float.
+        if (valueType == VALUE_TYPE_PATH) {
+            evaluator = setupAnimatorForPath(anim, arrayAnimator);
+        } else {
+            // Integer and float value types are handled here.
+            if ((hasFrom && (fromType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
+                    (fromType <= TypedValue.TYPE_LAST_COLOR_INT)) ||
+                    (hasTo && (toType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
+                            (toType <= TypedValue.TYPE_LAST_COLOR_INT))) {
+                // special case for colors: ignore valueType and get ints
+                getFloats = false;
+                evaluator = ArgbEvaluator.getInstance();
+            }
+            setupValues(anim, arrayAnimator, getFloats, hasFrom, fromType, hasTo, toType);
         }
 
+        anim.setDuration(duration);
+        anim.setStartDelay(startDelay);
+
+        if (arrayAnimator.hasValue(R.styleable.Animator_repeatCount)) {
+            anim.setRepeatCount(
+                    arrayAnimator.getInt(R.styleable.Animator_repeatCount, 0));
+        }
+        if (arrayAnimator.hasValue(R.styleable.Animator_repeatMode)) {
+            anim.setRepeatMode(
+                    arrayAnimator.getInt(R.styleable.Animator_repeatMode,
+                            ValueAnimator.RESTART));
+        }
+        if (evaluator != null) {
+            anim.setEvaluator(evaluator);
+        }
+
+        if (arrayObjectAnimator != null) {
+            setupObjectAnimator(anim, arrayObjectAnimator, getFloats);
+        }
+    }
+
+    /**
+     * Setup the Animator to achieve path morphing.
+     *
+     * @param anim The target Animator which will be updated.
+     * @param arrayAnimator TypedArray for the ValueAnimator.
+     * @return the PathDataEvaluator.
+     */
+    private static TypeEvaluator setupAnimatorForPath(ValueAnimator anim,
+             TypedArray arrayAnimator) {
+        TypeEvaluator evaluator = null;
+        String fromString = arrayAnimator.getString(R.styleable.Animator_valueFrom);
+        String toString = arrayAnimator.getString(R.styleable.Animator_valueTo);
+        PathParser.PathDataNode[] nodesFrom = PathParser.createNodesFromPathData(fromString);
+        PathParser.PathDataNode[] nodesTo = PathParser.createNodesFromPathData(toString);
+
+        if (nodesFrom != null) {
+            if (nodesTo != null) {
+                anim.setObjectValues(nodesFrom, nodesTo);
+                if (!PathParser.canMorph(nodesFrom, nodesTo)) {
+                    throw new InflateException(arrayAnimator.getPositionDescription()
+                            + " Can't morph from " + fromString + " to " + toString);
+                }
+            } else {
+                anim.setObjectValues((Object)nodesFrom);
+            }
+            evaluator = new PathDataEvaluator(PathParser.deepCopyNodes(nodesFrom));
+        } else if (nodesTo != null) {
+            anim.setObjectValues((Object)nodesTo);
+            evaluator = new PathDataEvaluator(PathParser.deepCopyNodes(nodesTo));
+        }
+
+        if (DBG_ANIMATOR_INFLATER && evaluator != null) {
+            Log.v(TAG, "create a new PathDataEvaluator here");
+        }
+
+        return evaluator;
+    }
+
+    /**
+     * Setup ObjectAnimator's property or values from pathData.
+     *
+     * @param anim The target Animator which will be updated.
+     * @param arrayObjectAnimator TypedArray for the ObjectAnimator.
+     * @param getFloats True if the value type is float.
+     */
+    private static void setupObjectAnimator(ValueAnimator anim, TypedArray arrayObjectAnimator,
+            boolean getFloats) {
+        ObjectAnimator oa = (ObjectAnimator) anim;
+        String pathData = arrayObjectAnimator.getString(R.styleable.PropertyAnimator_pathData);
+
+        // Note that if there is a pathData defined in the Object Animator,
+        // valueFrom / valueTo will be ignored.
+        if (pathData != null) {
+            String propertyXName =
+                    arrayObjectAnimator.getString(R.styleable.PropertyAnimator_propertyXName);
+            String propertyYName =
+                    arrayObjectAnimator.getString(R.styleable.PropertyAnimator_propertyYName);
+
+            if (propertyXName == null && propertyYName == null) {
+                throw new InflateException(arrayObjectAnimator.getPositionDescription()
+                        + " propertyXName or propertyYName is needed for PathData");
+            } else {
+                Path path = PathParser.createPathFromPathData(pathData);
+                Keyframe[][] keyframes = PropertyValuesHolder.createKeyframes(path, !getFloats);
+                PropertyValuesHolder x = null;
+                PropertyValuesHolder y = null;
+                if (propertyXName != null) {
+                    x = PropertyValuesHolder.ofKeyframe(propertyXName, keyframes[0]);
+                }
+                if (propertyYName != null) {
+                    y = PropertyValuesHolder.ofKeyframe(propertyYName, keyframes[1]);
+                }
+                if (x == null) {
+                    oa.setValues(y);
+                } else if (y == null) {
+                    oa.setValues(x);
+                } else {
+                    oa.setValues(x, y);
+                }
+            }
+        } else {
+            String propertyName =
+                    arrayObjectAnimator.getString(R.styleable.PropertyAnimator_propertyName);
+            oa.setPropertyName(propertyName);
+        }
+    }
+
+    /**
+     * Setup ValueAnimator's values.
+     * This will handle all of the integer, float and color types.
+     *
+     * @param anim The target Animator which will be updated.
+     * @param arrayAnimator TypedArray for the ValueAnimator.
+     * @param getFloats True if the value type is float.
+     * @param hasFrom True if "valueFrom" exists.
+     * @param fromType The type of "valueFrom".
+     * @param hasTo True if "valueTo" exists.
+     * @param toType The type of "valueTo".
+     */
+    private static void setupValues(ValueAnimator anim, TypedArray arrayAnimator,
+            boolean getFloats, boolean hasFrom, int fromType, boolean hasTo, int toType) {
+        int valueFromIndex = R.styleable.Animator_valueFrom;
+        int valueToIndex = R.styleable.Animator_valueTo;
         if (getFloats) {
             float valueFrom;
             float valueTo;
@@ -296,63 +481,6 @@
                 }
             }
         }
-
-        anim.setDuration(duration);
-        anim.setStartDelay(startDelay);
-
-        if (arrayAnimator.hasValue(R.styleable.Animator_repeatCount)) {
-            anim.setRepeatCount(
-                    arrayAnimator.getInt(R.styleable.Animator_repeatCount, 0));
-        }
-        if (arrayAnimator.hasValue(R.styleable.Animator_repeatMode)) {
-            anim.setRepeatMode(
-                    arrayAnimator.getInt(R.styleable.Animator_repeatMode,
-                            ValueAnimator.RESTART));
-        }
-        if (evaluator != null) {
-            anim.setEvaluator(evaluator);
-        }
-
-        if (arrayObjectAnimator != null) {
-            ObjectAnimator oa = (ObjectAnimator) anim;
-            String pathData = arrayObjectAnimator.getString(R.styleable.PropertyAnimator_pathData);
-
-            // Note that if there is a pathData defined in the Object Animator,
-            // valueFrom / valueTo will be overwritten by the pathData.
-            if (pathData != null) {
-                String propertyXName =
-                        arrayObjectAnimator.getString(R.styleable.PropertyAnimator_propertyXName);
-                String propertyYName =
-                        arrayObjectAnimator.getString(R.styleable.PropertyAnimator_propertyYName);
-
-                if (propertyXName == null && propertyYName == null) {
-                    throw new IllegalArgumentException("propertyXName or propertyYName"
-                            + " is needed for PathData in Object Animator");
-                } else {
-                    Path path = PathParser.createPathFromPathData(pathData);
-                    Keyframe[][] keyframes = PropertyValuesHolder.createKeyframes(path, !getFloats);
-                    PropertyValuesHolder x = null;
-                    PropertyValuesHolder y = null;
-                    if (propertyXName != null) {
-                        x = PropertyValuesHolder.ofKeyframe(propertyXName, keyframes[0]);
-                    }
-                    if (propertyYName != null) {
-                        y = PropertyValuesHolder.ofKeyframe(propertyYName, keyframes[1]);
-                    }
-                    if (x == null) {
-                        oa.setValues(y);
-                    } else if (y == null) {
-                        oa.setValues(x);
-                    } else {
-                        oa.setValues(x, y);
-                    }
-                }
-            } else {
-                String propertyName =
-                        arrayObjectAnimator.getString(R.styleable.PropertyAnimator_propertyName);
-                oa.setPropertyName(propertyName);
-            }
-        }
     }
 
     private static Animator createAnimatorFromXml(Resources res, Theme theme, XmlPullParser parser)
diff --git a/core/java/android/util/PathParser.java b/core/java/android/util/PathParser.java
index f90ce51..f4a0448 100644
--- a/core/java/android/util/PathParser.java
+++ b/core/java/android/util/PathParser.java
@@ -45,6 +45,9 @@
      * @return an array of the PathDataNode.
      */
     public static PathDataNode[] createNodesFromPathData(String pathData) {
+        if (pathData == null) {
+            return null;
+        }
         int start = 0;
         int end = 1;
 
@@ -64,6 +67,57 @@
         return list.toArray(new PathDataNode[list.size()]);
     }
 
+    /**
+     * @param source The array of PathDataNode to be duplicated.
+     * @return a deep copy of the <code>source</code>.
+     */
+    public static PathDataNode[] deepCopyNodes(PathDataNode[] source) {
+        PathDataNode[] copy = new PathParser.PathDataNode[source.length];
+        for (int i = 0; i < source.length; i ++) {
+            copy[i] = new PathDataNode(source[i]);
+        }
+        return copy;
+    }
+
+    /**
+     * @param nodesFrom The source path represented in an array of PathDataNode
+     * @param nodesTo The target path represented in an array of PathDataNode
+     * @return whether the <code>nodesFrom</code> can morph into <code>nodesTo</code>
+     */
+    public static boolean canMorph(PathDataNode[] nodesFrom, PathDataNode[] nodesTo) {
+        if (nodesFrom == null || nodesTo == null) {
+            return false;
+        }
+
+        if (nodesFrom.length != nodesTo.length) {
+            return false;
+        }
+
+        for (int i = 0; i < nodesFrom.length; i ++) {
+            if (nodesFrom[i].mType != nodesTo[i].mType
+                    || nodesFrom[i].mParams.length != nodesTo[i].mParams.length) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Update the target's data to match the source.
+     * Before calling this, make sure canMorph(target, source) is true.
+     *
+     * @param target The target path represented in an array of PathDataNode
+     * @param source The source path represented in an array of PathDataNode
+     */
+    public static void updateNodes(PathDataNode[] target, PathDataNode[] source) {
+        for (int i = 0; i < source.length; i ++) {
+            target[i].mType = source[i].mType;
+            for (int j = 0; j < source[i].mParams.length; j ++) {
+                target[i].mParams[j] = source[i].mParams[j];
+            }
+        }
+    }
+
     private static int nextStart(String s, int end) {
         char c;
 
@@ -132,6 +186,11 @@
         return (comma > space) ? space : comma;
     }
 
+    /**
+     * Each PathDataNode represents one command in the "d" attribute of the svg
+     * file.
+     * An array of PathDataNode can represent the whole "d" attribute.
+     */
     public static class PathDataNode {
         private char mType;
         private float[] mParams;
@@ -146,6 +205,12 @@
             mParams = Arrays.copyOf(n.mParams, n.mParams.length);
         }
 
+        /**
+         * Convert an array of PathDataNode to Path.
+         *
+         * @param node The source array of PathDataNode.
+         * @param path The target Path object.
+         */
         public static void nodesToPath(PathDataNode[] node, Path path) {
             float[] current = new float[4];
             char previousCommand = 'm';
@@ -155,6 +220,23 @@
             }
         }
 
+        /**
+         * The current PathDataNode will be interpolated between the
+         * <code>nodeFrom</code> and <code>nodeTo</code> according to the
+         * <code>fraction</code>.
+         *
+         * @param nodeFrom The start value as a PathDataNode.
+         * @param nodeTo The end value as a PathDataNode
+         * @param fraction The fraction to interpolate.
+         */
+        public void interpolatePathDataNode(PathDataNode nodeFrom,
+                PathDataNode nodeTo, float fraction) {
+            for (int i = 0; i < nodeFrom.mParams.length; i++) {
+                mParams[i] = nodeFrom.mParams[i] * (1 - fraction)
+                        + nodeTo.mParams[i] * fraction;
+            }
+        }
+
         private static void addCommand(Path path, float[] current,
                 char previousCmd, char cmd, float[] val) {
 
@@ -523,6 +605,5 @@
                 ep1y = ep2y;
             }
         }
-
     }
 }
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 390da2c..4a6311a 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -5410,6 +5410,9 @@
             <enum name="floatType" value="0" />
             <!-- valueFrom and valueTo are integers. -->
             <enum name="intType"   value="1" />
+            <!-- valueFrom and valueTo are paths defined as strings.
+                 This type is used for path morphing in AnimatedVectorDrawable. -->
+            <enum name="pathType"   value="2" />
         </attr>
     </declare-styleable>
 
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index 60177af8f..3773a9b 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -1040,67 +1040,98 @@
             }
         }
 
-        /* Setters and Getters */
+        /* Setters and Getters, mostly used by animator from AnimatedVectorDrawable. */
+        @SuppressWarnings("unused")
+        public PathParser.PathDataNode[] getPathData() {
+            return mNode;
+        }
+
+        @SuppressWarnings("unused")
+        public void setPathData(PathParser.PathDataNode[] node) {
+            if (!PathParser.canMorph(mNode, node)) {
+                // This should not happen in the middle of animation.
+                mNode = PathParser.deepCopyNodes(node);
+            } else {
+                PathParser.updateNodes(mNode, node);
+            }
+        }
+
+        @SuppressWarnings("unused")
         int getStroke() {
             return mStrokeColor;
         }
 
+        @SuppressWarnings("unused")
         void setStroke(int strokeColor) {
             mStrokeColor = strokeColor;
         }
 
+        @SuppressWarnings("unused")
         float getStrokeWidth() {
             return mStrokeWidth;
         }
 
+        @SuppressWarnings("unused")
         void setStrokeWidth(float strokeWidth) {
             mStrokeWidth = strokeWidth;
         }
 
+        @SuppressWarnings("unused")
         float getStrokeOpacity() {
             return mStrokeOpacity;
         }
 
+        @SuppressWarnings("unused")
         void setStrokeOpacity(float strokeOpacity) {
             mStrokeOpacity = strokeOpacity;
         }
 
+        @SuppressWarnings("unused")
         int getFill() {
             return mFillColor;
         }
 
+        @SuppressWarnings("unused")
         void setFill(int fillColor) {
             mFillColor = fillColor;
         }
 
+        @SuppressWarnings("unused")
         float getFillOpacity() {
             return mFillOpacity;
         }
 
+        @SuppressWarnings("unused")
         void setFillOpacity(float fillOpacity) {
             mFillOpacity = fillOpacity;
         }
 
+        @SuppressWarnings("unused")
         float getTrimPathStart() {
             return mTrimPathStart;
         }
 
+        @SuppressWarnings("unused")
         void setTrimPathStart(float trimPathStart) {
             mTrimPathStart = trimPathStart;
         }
 
+        @SuppressWarnings("unused")
         float getTrimPathEnd() {
             return mTrimPathEnd;
         }
 
+        @SuppressWarnings("unused")
         void setTrimPathEnd(float trimPathEnd) {
             mTrimPathEnd = trimPathEnd;
         }
 
+        @SuppressWarnings("unused")
         float getTrimPathOffset() {
             return mTrimPathOffset;
         }
 
+        @SuppressWarnings("unused")
         void setTrimPathOffset(float trimPathOffset) {
             mTrimPathOffset = trimPathOffset;
         }
diff --git a/tests/VectorDrawableTest/res/anim/trim_path_animation05.xml b/tests/VectorDrawableTest/res/anim/trim_path_animation05.xml
new file mode 100644
index 0000000..7012f4b
--- /dev/null
+++ b/tests/VectorDrawableTest/res/anim/trim_path_animation05.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2014 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.
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+     android:ordering="sequentially" >
+
+    <objectAnimator
+        android:duration="3000"
+        android:propertyName="pathData"
+        android:valueFrom="@string/triangle"
+        android:valueTo="@string/rectangle"
+        android:valueType="pathType"/>
+
+    <objectAnimator
+        android:duration="3000"
+        android:propertyName="pathData"
+        android:valueFrom="@string/rectangle2"
+        android:valueTo="@string/equal2"
+        android:valueType="pathType"/>
+
+</set>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/animation_vector_drawable01.xml b/tests/VectorDrawableTest/res/drawable/animation_vector_drawable01.xml
index 0900b7c..b37b19f 100644
--- a/tests/VectorDrawableTest/res/drawable/animation_vector_drawable01.xml
+++ b/tests/VectorDrawableTest/res/drawable/animation_vector_drawable01.xml
@@ -19,9 +19,13 @@
     <target
         android:name="pie1"
         android:animation="@anim/trim_path_animation01" />
+
     <target
         android:name="v"
         android:animation="@anim/trim_path_animation02" />
+    <target
+        android:name="v"
+        android:animation="@anim/trim_path_animation05" />
 
     <target
         android:name="rotationGroup"
@@ -36,4 +40,4 @@
         android:name="rotationGroup"
         android:animation="@anim/trim_path_animation04" />
 
-</animated-vector>
\ No newline at end of file
+</animated-vector>
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml
index e28ec41..a212def 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml
@@ -32,27 +32,21 @@
             android:name="pie1"
             android:fill="#00000000"
             android:pathData="M300,70 a230,230 0 1,0 1,0 z"
-            android:stroke="#FF00FF00"
+            android:stroke="#FF777777"
             android:strokeWidth="70"
             android:trimPathEnd=".75"
             android:trimPathOffset="0"
             android:trimPathStart="0" />
         <path
             android:name="v"
-            android:fill="#FF00FF00"
-            android:pathData="M300,70 l 0,-70 70,70 -70,70z" />
+            android:fill="#000000"
+            android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" />
 
         <group
             android:name="translateToCenterGroup"
             android:rotation="0.0"
             android:translateX="200.0"
             android:translateY="200.0" >
-            <path
-                android:name="twoLines"
-                android:pathData="@string/twoLinePathData"
-                android:stroke="#FFFF0000"
-                android:strokeWidth="20" />
-
             <group
                 android:name="rotationGroup2"
                 android:pivotX="0.0"
@@ -61,7 +55,7 @@
                 <path
                     android:name="twoLines1"
                     android:pathData="@string/twoLinePathData"
-                    android:stroke="#FF00FF00"
+                    android:stroke="#FFFF0000"
                     android:strokeWidth="20" />
 
                 <group
diff --git a/tests/VectorDrawableTest/res/values/strings.xml b/tests/VectorDrawableTest/res/values/strings.xml
index b49a1aa..6ae3d7f 100644
--- a/tests/VectorDrawableTest/res/values/strings.xml
+++ b/tests/VectorDrawableTest/res/values/strings.xml
@@ -16,4 +16,11 @@
 
 <resources>
     <string name="twoLinePathData" >"M 0,0 v 100 M 0,0 h 100"</string>
+
+    <string name="triangle" > "M300,70 l 0,-70 70,70 0,0   -70,70z"</string>
+    <string name="rectangle" >"M300,70 l 0,-70 70,0  0,140 -70,0 z"</string>
+
+    <string name="rectangle2" >"M300,70 l 0,-70 70,0  0,70z M300,70  l 70,0 0,70 -70,0z"</string>
+    <string name="equal2" >    "M300,35 l 0,-35 70,0  0,35z M300,105 l 70,0 0,35 -70,0z"</string>
+
 </resources>