From 010dbaa1236cf2dcdc62c29049468e90188acaae Mon Sep 17 00:00:00 2001 From: Chet Haase Date: Mon, 19 Jul 2010 17:29:49 -0700 Subject: [PATCH] Fix bugs in Sequencer Change-Id: I03aebe8d822bef0b9e163ba3280699ca02a6563c --- core/java/android/animation/Animator.java | 9 +++- core/java/android/animation/Sequencer.java | 55 ++++++++++++---------- 2 files changed, 38 insertions(+), 26 deletions(-) diff --git a/core/java/android/animation/Animator.java b/core/java/android/animation/Animator.java index b6c4763dd404e..db8b9eba5fb8e 100755 --- a/core/java/android/animation/Animator.java +++ b/core/java/android/animation/Animator.java @@ -28,8 +28,13 @@ import java.util.ArrayList; * This class provides a simple timing engine for running animations * which calculate animated values and set them on target objects. * - * There is a single timing pulse that all animations use. It runs in a - * custom handler to ensure that property changes happen on the UI thread. + *

There is a single timing pulse that all animations use. It runs in a + * custom handler to ensure that property changes happen on the UI thread.

+ * + *

By default, Animator uses non-linear time interpolation, via the + * {@link AccelerateDecelerateInterpolator} class, which accelerates into and decelerates + * out of an animation. This behavior can be changed by calling + * {@link Animator#setInterpolator(Interpolator)}.

*/ public class Animator extends Animatable { diff --git a/core/java/android/animation/Sequencer.java b/core/java/android/animation/Sequencer.java index 00ab6a3342daa..e73ac88313db3 100644 --- a/core/java/android/animation/Sequencer.java +++ b/core/java/android/animation/Sequencer.java @@ -27,7 +27,7 @@ import java.util.HashMap; * either the {@link Sequencer#playTogether(Animatable...) playTogether()} or * {@link Sequencer#playSequentially(Animatable...) playSequentially()} methods can be called to add * a set of animations all at once, or the {@link Sequencer#play(Animatable)} can be - * used in conjunction with methods in the {@link android.animation.Sequencer.Builder Builder} + * used in conjunction with methods in the {@link myandroid.animation.Sequencer.Builder Builder} * class to add animations * one by one.

* @@ -82,6 +82,13 @@ public final class Sequencer extends Animatable { private SequencerAnimatableListener mSequenceListener = null; + /** + * Flag indicating that the Sequencer has been canceled (by calling cancel() or end()). + * This flag is used to avoid starting other animations when currently-playing + * child animations of this Sequencer end. + */ + boolean mCanceled = false; + /** * Sets up this Sequencer to play all of the supplied animations at the same time. * @@ -161,6 +168,7 @@ public final class Sequencer extends Animatable { @SuppressWarnings("unchecked") @Override public void cancel() { + mCanceled = true; if (mListeners != null) { ArrayList tmpListeners = (ArrayList) mListeners.clone(); @@ -168,11 +176,10 @@ public final class Sequencer extends Animatable { listener.onAnimationCancel(this); } } - if (mPlayingSet.size() > 0) { - for (Animatable item : mPlayingSet) { - item.cancel(); + if (mSortedNodes.size() > 0) { + for (Node node : mSortedNodes) { + node.animation.cancel(); } - mPlayingSet.clear(); } } @@ -184,11 +191,11 @@ public final class Sequencer extends Animatable { */ @Override public void end() { - if (mPlayingSet.size() > 0) { - for (Animatable item : mPlayingSet) { - item.end(); + mCanceled = true; + if (mSortedNodes.size() > 0) { + for (Node node : mSortedNodes) { + node.animation.end(); } - mPlayingSet.clear(); } } @@ -202,6 +209,8 @@ public final class Sequencer extends Animatable { @SuppressWarnings("unchecked") @Override public void start() { + mCanceled = false; + // First, sort the nodes (if necessary). This will ensure that sortedNodes // contains the animation nodes in the correct order. sortNodes(); @@ -221,7 +230,7 @@ public final class Sequencer extends Animatable { } else { for (Dependency dependency : node.dependencies) { dependency.node.animation.addListener( - new DependencyListener(node, dependency.rule)); + new DependencyListener(this, node, dependency.rule)); } node.tmpDependencies = (ArrayList) node.dependencies.clone(); } @@ -247,6 +256,8 @@ public final class Sequencer extends Animatable { */ private static class DependencyListener implements AnimatableListener { + private Sequencer mSequencer; + // The node upon which the dependency is based. private Node mNode; @@ -254,27 +265,18 @@ public final class Sequencer extends Animatable { // the node private int mRule; - public DependencyListener(Node node, int rule) { + public DependencyListener(Sequencer sequencer, Node node, int rule) { + this.mSequencer = sequencer; this.mNode = node; this.mRule = rule; } /** - * If an animation that is being listened for is canceled, then this removes - * the listener on that animation, to avoid triggering further animations down - * the line when the animation ends. + * Ignore cancel events for now. We may want to handle this eventually, + * to prevent follow-on animations from running when some dependency + * animation is canceled. */ public void onAnimationCancel(Animatable animation) { - Dependency dependencyToRemove = null; - for (Dependency dependency : mNode.tmpDependencies) { - if (dependency.node.animation == animation) { - // animation canceled - remove the dependency and listener - dependencyToRemove = dependency; - animation.removeListener(this); - break; - } - } - mNode.tmpDependencies.remove(dependencyToRemove); } /** @@ -308,6 +310,10 @@ public final class Sequencer extends Animatable { * @param dependencyAnimation the animation that sent the event. */ private void startIfReady(Animatable dependencyAnimation) { + if (mSequencer.mCanceled) { + // if the parent Sequencer was canceled, then don't start any dependent anims + return; + } Dependency dependencyToRemove = null; for (Dependency dependency : mNode.tmpDependencies) { if (dependency.rule == mRule && @@ -405,6 +411,7 @@ public final class Sequencer extends Animatable { } } } + roots.clear(); roots.addAll(tmpRoots); tmpRoots.clear(); }