Merge "Change Animators to reset values when restarted if their target changes" into lmp-dev
diff --git a/core/java/android/animation/FloatKeyframeSet.java b/core/java/android/animation/FloatKeyframeSet.java
index 377b5a05..2d87e13 100644
--- a/core/java/android/animation/FloatKeyframeSet.java
+++ b/core/java/android/animation/FloatKeyframeSet.java
@@ -57,6 +57,11 @@
         return newSet;
     }
 
+    @Override
+    void invalidateCache() {
+        firstTime = true;
+    }
+
     public float getFloatValue(float fraction) {
         if (mNumKeyframes == 2) {
             if (firstTime) {
diff --git a/core/java/android/animation/IntKeyframeSet.java b/core/java/android/animation/IntKeyframeSet.java
index 7b7c876..ce47e2b 100644
--- a/core/java/android/animation/IntKeyframeSet.java
+++ b/core/java/android/animation/IntKeyframeSet.java
@@ -57,6 +57,11 @@
         return newSet;
     }
 
+    @Override
+    void invalidateCache() {
+        firstTime = true;
+    }
+
     public int getIntValue(float fraction) {
         if (mNumKeyframes == 2) {
             if (firstTime) {
diff --git a/core/java/android/animation/Keyframe.java b/core/java/android/animation/Keyframe.java
index dc8538f..5483c49 100644
--- a/core/java/android/animation/Keyframe.java
+++ b/core/java/android/animation/Keyframe.java
@@ -35,6 +35,20 @@
  */
 public abstract class Keyframe implements Cloneable {
     /**
+     * Flag to indicate whether this keyframe has a valid value. This flag is used when an
+     * animation first starts, to populate placeholder keyframes with real values derived
+     * from the target object.
+     */
+    boolean mHasValue;
+
+    /**
+     * Flag to indicate whether the value in the keyframe was read from the target object or not.
+     * If so, its value will be recalculated if target changes.
+     */
+    boolean mValueWasSetOnStart;
+
+
+    /**
      * The time at which mValue will hold true.
      */
     float mFraction;
@@ -51,12 +65,7 @@
      */
     private TimeInterpolator mInterpolator = null;
 
-    /**
-     * Flag to indicate whether this keyframe has a valid value. This flag is used when an
-     * animation first starts, to populate placeholder keyframes with real values derived
-     * from the target object.
-     */
-    boolean mHasValue = false;
+
 
     /**
      * Constructs a Keyframe object with the given time and value. The time defines the
@@ -166,6 +175,20 @@
     }
 
     /**
+     * If the Keyframe's value was acquired from the target object, this flag should be set so that,
+     * if target changes, value will be reset.
+     *
+     * @return boolean Whether this Keyframe's value was retieved from the target object or not.
+     */
+    boolean valueWasSetOnStart() {
+        return mValueWasSetOnStart;
+    }
+
+    void setValueWasSetOnStart(boolean valueWasSetOnStart) {
+        mValueWasSetOnStart = valueWasSetOnStart;
+    }
+
+    /**
      * Gets the value for this Keyframe.
      *
      * @return The value for this Keyframe.
@@ -261,7 +284,8 @@
 
         @Override
         public ObjectKeyframe clone() {
-            ObjectKeyframe kfClone = new ObjectKeyframe(getFraction(), mHasValue ? mValue : null);
+            ObjectKeyframe kfClone = new ObjectKeyframe(getFraction(), hasValue() ? mValue : null);
+            kfClone.mValueWasSetOnStart = mValueWasSetOnStart;
             kfClone.setInterpolator(getInterpolator());
             return kfClone;
         }
@@ -310,6 +334,7 @@
                     new IntKeyframe(getFraction(), mValue) :
                     new IntKeyframe(getFraction());
             kfClone.setInterpolator(getInterpolator());
+            kfClone.mValueWasSetOnStart = mValueWasSetOnStart;
             return kfClone;
         }
     }
@@ -356,6 +381,7 @@
                     new FloatKeyframe(getFraction(), mValue) :
                     new FloatKeyframe(getFraction());
             kfClone.setInterpolator(getInterpolator());
+            kfClone.mValueWasSetOnStart = mValueWasSetOnStart;
             return kfClone;
         }
     }
diff --git a/core/java/android/animation/KeyframeSet.java b/core/java/android/animation/KeyframeSet.java
index 4026f7f..a3db3a1 100644
--- a/core/java/android/animation/KeyframeSet.java
+++ b/core/java/android/animation/KeyframeSet.java
@@ -48,6 +48,13 @@
         mInterpolator = mLastKeyframe.getInterpolator();
     }
 
+    /**
+     * If subclass has variables that it calculates based on the Keyframes, it should reset them
+     * when this method is called because Keyframe contents might have changed.
+     */
+    void invalidateCache() {
+    }
+
     public static KeyframeSet ofInt(int... values) {
         int numKeyframes = values.length;
         IntKeyframe keyframes[] = new IntKeyframe[Math.max(numKeyframes,2)];
diff --git a/core/java/android/animation/ObjectAnimator.java b/core/java/android/animation/ObjectAnimator.java
index da56a77..a4ac73f 100644
--- a/core/java/android/animation/ObjectAnimator.java
+++ b/core/java/android/animation/ObjectAnimator.java
@@ -883,10 +883,7 @@
         final Object oldTarget = getTarget();
         if (oldTarget != target) {
             mTarget = target == null ? null : new WeakReference<Object>(target);
-            if (oldTarget != null && target != null && oldTarget.getClass() == target.getClass()) {
-                return;
-            }
-            // New target type should cause re-initialization prior to starting
+            // New target should cause re-initialization prior to starting
             mInitialized = false;
         }
     }
diff --git a/core/java/android/animation/PropertyValuesHolder.java b/core/java/android/animation/PropertyValuesHolder.java
index bdfbde1..73b83ef 100644
--- a/core/java/android/animation/PropertyValuesHolder.java
+++ b/core/java/android/animation/PropertyValuesHolder.java
@@ -775,16 +775,18 @@
      * @param target The object on which the setter (and possibly getter) exist.
      */
     void setupSetterAndGetter(Object target) {
+        mKeyframeSet.invalidateCache();
         if (mProperty != null) {
             // check to make sure that mProperty is on the class of target
             try {
                 Object testValue = null;
                 for (Keyframe kf : mKeyframeSet.mKeyframes) {
-                    if (!kf.hasValue()) {
+                    if (!kf.hasValue() || kf.valueWasSetOnStart()) {
                         if (testValue == null) {
                             testValue = convertBack(mProperty.get(target));
                         }
                         kf.setValue(testValue);
+                        kf.setValueWasSetOnStart(true);
                     }
                 }
                 return;
@@ -799,7 +801,7 @@
             setupSetter(targetClass);
         }
         for (Keyframe kf : mKeyframeSet.mKeyframes) {
-            if (!kf.hasValue()) {
+            if (!kf.hasValue() || kf.valueWasSetOnStart()) {
                 if (mGetter == null) {
                     setupGetter(targetClass);
                     if (mGetter == null) {
@@ -810,6 +812,7 @@
                 try {
                     Object value = convertBack(mGetter.invoke(target));
                     kf.setValue(value);
+                    kf.setValueWasSetOnStart(true);
                 } catch (InvocationTargetException e) {
                     Log.e("PropertyValuesHolder", e.toString());
                 } catch (IllegalAccessException e) {
diff --git a/core/java/android/animation/StateListAnimator.java b/core/java/android/animation/StateListAnimator.java
index 810f050..7256a06 100644
--- a/core/java/android/animation/StateListAnimator.java
+++ b/core/java/android/animation/StateListAnimator.java
@@ -57,6 +57,7 @@
     private AnimatorListenerAdapter mAnimatorListener = new AnimatorListenerAdapter() {
         @Override
         public void onAnimationEnd(Animator animation) {
+            animation.setTarget(null);
             if (mRunningAnimator == animation) {
                 mRunningAnimator = null;
             }
@@ -151,7 +152,7 @@
 
     private void start(Tuple match) {
         match.mAnimator.setTarget(getTarget());
-        mRunningAnimator = match.mAnimator.clone();
+        mRunningAnimator = match.mAnimator;
         mRunningAnimator.start();
     }