Merge "Don't call property getters during initialization." into udc-dev

This commit is contained in:
Treehugger Robot
2023-06-02 01:23:20 +00:00
committed by Android (Google) Code Review
4 changed files with 84 additions and 77 deletions

View File

@@ -568,13 +568,13 @@ public abstract class Animator implements Cloneable {
* repetition. lastPlayTime is similar and is used to calculate how many repeats have been * repetition. lastPlayTime is similar and is used to calculate how many repeats have been
* done between the two times. * done between the two times.
*/ */
void animateValuesInRange(long currentPlayTime, long lastPlayTime, boolean notify) {} void animateValuesInRange(long currentPlayTime, long lastPlayTime) {}
/** /**
* Internal use only. This animates any animation that has ended since lastPlayTime. * Internal use only. This animates any animation that has ended since lastPlayTime.
* If an animation hasn't been finished, no change will be made. * If an animation hasn't been finished, no change will be made.
*/ */
void animateSkipToEnds(long currentPlayTime, long lastPlayTime, boolean notify) {} void animateSkipToEnds(long currentPlayTime, long lastPlayTime) {}
/** /**
* Internal use only. Adds all start times (after delay) to and end times to times. * Internal use only. Adds all start times (after delay) to and end times to times.

View File

@@ -825,8 +825,7 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim
private void animateBasedOnPlayTime( private void animateBasedOnPlayTime(
long currentPlayTime, long currentPlayTime,
long lastPlayTime, long lastPlayTime,
boolean inReverse, boolean inReverse
boolean notify
) { ) {
if (currentPlayTime < 0 || lastPlayTime < -1) { if (currentPlayTime < 0 || lastPlayTime < -1) {
throw new UnsupportedOperationException("Error: Play time should never be negative."); throw new UnsupportedOperationException("Error: Play time should never be negative.");
@@ -857,8 +856,8 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim
while (index < endIndex) { while (index < endIndex) {
long playTime = startEndTimes[index]; long playTime = startEndTimes[index];
if (lastPlayTime != playTime) { if (lastPlayTime != playTime) {
animateSkipToEnds(playTime, lastPlayTime, notify); animateSkipToEnds(playTime, lastPlayTime);
animateValuesInRange(playTime, lastPlayTime, notify); animateValuesInRange(playTime, lastPlayTime);
lastPlayTime = playTime; lastPlayTime = playTime;
} }
index++; index++;
@@ -868,15 +867,15 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim
index--; index--;
long playTime = startEndTimes[index]; long playTime = startEndTimes[index];
if (lastPlayTime != playTime) { if (lastPlayTime != playTime) {
animateSkipToEnds(playTime, lastPlayTime, notify); animateSkipToEnds(playTime, lastPlayTime);
animateValuesInRange(playTime, lastPlayTime, notify); animateValuesInRange(playTime, lastPlayTime);
lastPlayTime = playTime; lastPlayTime = playTime;
} }
} }
} }
if (currentPlayTime != lastPlayTime) { if (currentPlayTime != lastPlayTime) {
animateSkipToEnds(currentPlayTime, lastPlayTime, notify); animateSkipToEnds(currentPlayTime, lastPlayTime);
animateValuesInRange(currentPlayTime, lastPlayTime, notify); animateValuesInRange(currentPlayTime, lastPlayTime);
} }
} }
@@ -896,13 +895,11 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim
} }
@Override @Override
void animateSkipToEnds(long currentPlayTime, long lastPlayTime, boolean notify) { void animateSkipToEnds(long currentPlayTime, long lastPlayTime) {
initAnimation(); initAnimation();
if (lastPlayTime > currentPlayTime) { if (lastPlayTime > currentPlayTime) {
if (notify) { notifyStartListeners(true);
notifyStartListeners(true);
}
for (int i = mEvents.size() - 1; i >= 0; i--) { for (int i = mEvents.size() - 1; i >= 0; i--) {
AnimationEvent event = mEvents.get(i); AnimationEvent event = mEvents.get(i);
Node node = event.mNode; Node node = event.mNode;
@@ -916,31 +913,25 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim
if (currentPlayTime <= start && start < lastPlayTime) { if (currentPlayTime <= start && start < lastPlayTime) {
animator.animateSkipToEnds( animator.animateSkipToEnds(
0, 0,
lastPlayTime - node.mStartTime, lastPlayTime - node.mStartTime
notify
); );
if (notify) { mPlayingSet.remove(node);
mPlayingSet.remove(node);
}
} else if (start <= currentPlayTime && currentPlayTime <= end) { } else if (start <= currentPlayTime && currentPlayTime <= end) {
animator.animateSkipToEnds( animator.animateSkipToEnds(
currentPlayTime - node.mStartTime, currentPlayTime - node.mStartTime,
lastPlayTime - node.mStartTime, lastPlayTime - node.mStartTime
notify
); );
if (notify && !mPlayingSet.contains(node)) { if (!mPlayingSet.contains(node)) {
mPlayingSet.add(node); mPlayingSet.add(node);
} }
} }
} }
} }
if (currentPlayTime <= 0 && notify) { if (currentPlayTime <= 0) {
notifyEndListeners(true); notifyEndListeners(true);
} }
} else { } else {
if (notify) { notifyStartListeners(false);
notifyStartListeners(false);
}
int eventsSize = mEvents.size(); int eventsSize = mEvents.size();
for (int i = 0; i < eventsSize; i++) { for (int i = 0; i < eventsSize; i++) {
AnimationEvent event = mEvents.get(i); AnimationEvent event = mEvents.get(i);
@@ -955,45 +946,39 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim
if (lastPlayTime < end && end <= currentPlayTime) { if (lastPlayTime < end && end <= currentPlayTime) {
animator.animateSkipToEnds( animator.animateSkipToEnds(
end - node.mStartTime, end - node.mStartTime,
lastPlayTime - node.mStartTime, lastPlayTime - node.mStartTime
notify
); );
if (notify) { mPlayingSet.remove(node);
mPlayingSet.remove(node);
}
} else if (start <= currentPlayTime && currentPlayTime <= end) { } else if (start <= currentPlayTime && currentPlayTime <= end) {
animator.animateSkipToEnds( animator.animateSkipToEnds(
currentPlayTime - node.mStartTime, currentPlayTime - node.mStartTime,
lastPlayTime - node.mStartTime, lastPlayTime - node.mStartTime
notify
); );
if (notify && !mPlayingSet.contains(node)) { if (!mPlayingSet.contains(node)) {
mPlayingSet.add(node); mPlayingSet.add(node);
} }
} }
} }
} }
if (currentPlayTime >= getTotalDuration() && notify) { if (currentPlayTime >= getTotalDuration()) {
notifyEndListeners(false); notifyEndListeners(false);
} }
} }
} }
@Override @Override
void animateValuesInRange(long currentPlayTime, long lastPlayTime, boolean notify) { void animateValuesInRange(long currentPlayTime, long lastPlayTime) {
initAnimation(); initAnimation();
if (notify) { if (lastPlayTime < 0 || (lastPlayTime == 0 && currentPlayTime > 0)) {
if (lastPlayTime < 0 || (lastPlayTime == 0 && currentPlayTime > 0)) { notifyStartListeners(false);
notifyStartListeners(false); } else {
} else { long duration = getTotalDuration();
long duration = getTotalDuration(); if (duration >= 0
if (duration >= 0 && (lastPlayTime > duration || (lastPlayTime == duration
&& (lastPlayTime > duration || (lastPlayTime == duration && currentPlayTime < duration))
&& currentPlayTime < duration)) ) {
) { notifyStartListeners(true);
notifyStartListeners(true);
}
} }
} }
@@ -1014,8 +999,7 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim
) { ) {
animator.animateValuesInRange( animator.animateValuesInRange(
currentPlayTime - node.mStartTime, currentPlayTime - node.mStartTime,
Math.max(-1, lastPlayTime - node.mStartTime), Math.max(-1, lastPlayTime - node.mStartTime)
notify
); );
} }
} }
@@ -1111,7 +1095,7 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim
} }
} }
mSeekState.setPlayTime(playTime, mReversing); mSeekState.setPlayTime(playTime, mReversing);
animateBasedOnPlayTime(playTime, lastPlayTime, mReversing, true); animateBasedOnPlayTime(playTime, lastPlayTime, mReversing);
} }
/** /**
@@ -1144,16 +1128,7 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim
private void initChildren() { private void initChildren() {
if (!isInitialized()) { if (!isInitialized()) {
mChildrenInitialized = true; mChildrenInitialized = true;
skipToEndValue(false);
// We have to initialize all the start values so that they are based on the previous
// values.
long[] times = ensureChildStartAndEndTimes();
long previousTime = -1;
for (long time : times) {
animateBasedOnPlayTime(time, previousTime, false, false);
previousTime = time;
}
} }
} }
@@ -1489,6 +1464,7 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim
anim.mPauseTime = -1; anim.mPauseTime = -1;
anim.mSeekState = new SeekState(); anim.mSeekState = new SeekState();
anim.mSelfPulse = true; anim.mSelfPulse = true;
anim.mStartListenersCalled = false;
anim.mPlayingSet = new ArrayList<Node>(); anim.mPlayingSet = new ArrayList<Node>();
anim.mNodeMap = new ArrayMap<Animator, Node>(); anim.mNodeMap = new ArrayMap<Animator, Node>();
anim.mNodes = new ArrayList<Node>(nodeCount); anim.mNodes = new ArrayList<Node>(nodeCount);

View File

@@ -1417,21 +1417,19 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
* will be called. * will be called.
*/ */
@Override @Override
void animateValuesInRange(long currentPlayTime, long lastPlayTime, boolean notify) { void animateValuesInRange(long currentPlayTime, long lastPlayTime) {
if (currentPlayTime < 0 || lastPlayTime < -1) { if (currentPlayTime < 0 || lastPlayTime < -1) {
throw new UnsupportedOperationException("Error: Play time should never be negative."); throw new UnsupportedOperationException("Error: Play time should never be negative.");
} }
initAnimation(); initAnimation();
long duration = getTotalDuration(); long duration = getTotalDuration();
if (notify) { if (lastPlayTime < 0 || (lastPlayTime == 0 && currentPlayTime > 0)) {
if (lastPlayTime < 0 || (lastPlayTime == 0 && currentPlayTime > 0)) { notifyStartListeners(false);
notifyStartListeners(false); } else if (lastPlayTime > duration
} else if (lastPlayTime > duration || (lastPlayTime == duration && currentPlayTime < duration)
|| (lastPlayTime == duration && currentPlayTime < duration) ) {
) { notifyStartListeners(true);
notifyStartListeners(true);
}
} }
if (duration >= 0) { if (duration >= 0) {
lastPlayTime = Math.min(duration, lastPlayTime); lastPlayTime = Math.min(duration, lastPlayTime);
@@ -1448,7 +1446,7 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
iteration = Math.min(iteration, mRepeatCount); iteration = Math.min(iteration, mRepeatCount);
lastIteration = Math.min(lastIteration, mRepeatCount); lastIteration = Math.min(lastIteration, mRepeatCount);
if (notify && iteration != lastIteration) { if (iteration != lastIteration) {
notifyListeners(AnimatorCaller.ON_REPEAT, false); notifyListeners(AnimatorCaller.ON_REPEAT, false);
} }
} }
@@ -1464,7 +1462,7 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
} }
@Override @Override
void animateSkipToEnds(long currentPlayTime, long lastPlayTime, boolean notify) { void animateSkipToEnds(long currentPlayTime, long lastPlayTime) {
boolean inReverse = currentPlayTime < lastPlayTime; boolean inReverse = currentPlayTime < lastPlayTime;
boolean doSkip; boolean doSkip;
if (currentPlayTime <= 0 && lastPlayTime > 0) { if (currentPlayTime <= 0 && lastPlayTime > 0) {
@@ -1474,13 +1472,9 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
doSkip = duration >= 0 && currentPlayTime >= duration && lastPlayTime < duration; doSkip = duration >= 0 && currentPlayTime >= duration && lastPlayTime < duration;
} }
if (doSkip) { if (doSkip) {
if (notify) { notifyStartListeners(inReverse);
notifyStartListeners(inReverse);
}
skipToEndValue(inReverse); skipToEndValue(inReverse);
if (notify) { notifyEndListeners(inReverse);
notifyEndListeners(inReverse);
}
} }
} }

View File

@@ -21,6 +21,7 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import android.util.Property;
import android.view.View; import android.view.View;
import androidx.test.annotation.UiThreadTest; import androidx.test.annotation.UiThreadTest;
@@ -576,6 +577,42 @@ public class AnimatorSetActivityTest {
}); });
} }
@Test
public void testInitializeWithoutReadingValues() throws Throwable {
// Some consumers crash while reading values before the animator starts
Property<int[], Integer> property = new Property<>(Integer.class, "firstValue") {
@Override
public Integer get(int[] target) {
throw new IllegalStateException("Shouldn't be called");
}
@Override
public void set(int[] target, Integer value) {
target[0] = value;
}
};
int[] target1 = new int[1];
int[] target2 = new int[1];
int[] target3 = new int[1];
ObjectAnimator animator1 = ObjectAnimator.ofInt(target1, property, 0, 100);
ObjectAnimator animator2 = ObjectAnimator.ofInt(target2, property, 0, 100);
ObjectAnimator animator3 = ObjectAnimator.ofInt(target3, property, 0, 100);
AnimatorSet set = new AnimatorSet();
set.playSequentially(animator1, animator2, animator3);
mActivityRule.runOnUiThread(() -> {
set.setCurrentPlayTime(900);
assertEquals(100, target1[0]);
assertEquals(100, target2[0]);
assertEquals(100, target3[0]);
set.setCurrentPlayTime(0);
assertEquals(0, target1[0]);
assertEquals(0, target2[0]);
assertEquals(0, target3[0]);
});
}
/** /**
* Check that the animator list contains exactly the given animators and nothing else. * Check that the animator list contains exactly the given animators and nothing else.
*/ */