Change Animators to reset values when restarted if their target changes
Bug: 15710503
Change-Id: Ib39bf0e13199978ffb389111c225beb30312c965
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();
}