am cd89feb9: Merge "pause/resume for Animators" into klp-dev
* commit 'cd89feb9d14d6ed5d832d563a754048ab79134e2': pause/resume for Animators
This commit is contained in:
@@ -2338,17 +2338,23 @@ package android.animation {
|
|||||||
public abstract class Animator implements java.lang.Cloneable {
|
public abstract class Animator implements java.lang.Cloneable {
|
||||||
ctor public Animator();
|
ctor public Animator();
|
||||||
method public void addListener(android.animation.Animator.AnimatorListener);
|
method public void addListener(android.animation.Animator.AnimatorListener);
|
||||||
|
method public void addPauseListener(android.animation.Animator.AnimatorPauseListener);
|
||||||
method public void cancel();
|
method public void cancel();
|
||||||
method public android.animation.Animator clone();
|
method public android.animation.Animator clone();
|
||||||
method public void end();
|
method public void end();
|
||||||
method public abstract long getDuration();
|
method public abstract long getDuration();
|
||||||
method public android.animation.TimeInterpolator getInterpolator();
|
method public android.animation.TimeInterpolator getInterpolator();
|
||||||
method public java.util.ArrayList<android.animation.Animator.AnimatorListener> getListeners();
|
method public java.util.ArrayList<android.animation.Animator.AnimatorListener> getListeners();
|
||||||
|
method public java.util.ArrayList<android.animation.Animator.AnimatorPauseListener> getPauseListeners();
|
||||||
method public abstract long getStartDelay();
|
method public abstract long getStartDelay();
|
||||||
|
method public boolean isPaused();
|
||||||
method public abstract boolean isRunning();
|
method public abstract boolean isRunning();
|
||||||
method public boolean isStarted();
|
method public boolean isStarted();
|
||||||
|
method public void pause();
|
||||||
method public void removeAllListeners();
|
method public void removeAllListeners();
|
||||||
method public void removeListener(android.animation.Animator.AnimatorListener);
|
method public void removeListener(android.animation.Animator.AnimatorListener);
|
||||||
|
method public void removePauseListener(android.animation.Animator.AnimatorPauseListener);
|
||||||
|
method public void resume();
|
||||||
method public abstract android.animation.Animator setDuration(long);
|
method public abstract android.animation.Animator setDuration(long);
|
||||||
method public abstract void setInterpolator(android.animation.TimeInterpolator);
|
method public abstract void setInterpolator(android.animation.TimeInterpolator);
|
||||||
method public abstract void setStartDelay(long);
|
method public abstract void setStartDelay(long);
|
||||||
@@ -2365,16 +2371,23 @@ package android.animation {
|
|||||||
method public abstract void onAnimationStart(android.animation.Animator);
|
method public abstract void onAnimationStart(android.animation.Animator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static abstract interface Animator.AnimatorPauseListener {
|
||||||
|
method public abstract void onAnimationPause(android.animation.Animator);
|
||||||
|
method public abstract void onAnimationResume(android.animation.Animator);
|
||||||
|
}
|
||||||
|
|
||||||
public class AnimatorInflater {
|
public class AnimatorInflater {
|
||||||
ctor public AnimatorInflater();
|
ctor public AnimatorInflater();
|
||||||
method public static android.animation.Animator loadAnimator(android.content.Context, int) throws android.content.res.Resources.NotFoundException;
|
method public static android.animation.Animator loadAnimator(android.content.Context, int) throws android.content.res.Resources.NotFoundException;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract class AnimatorListenerAdapter implements android.animation.Animator.AnimatorListener {
|
public abstract class AnimatorListenerAdapter implements android.animation.Animator.AnimatorListener android.animation.Animator.AnimatorPauseListener {
|
||||||
ctor public AnimatorListenerAdapter();
|
ctor public AnimatorListenerAdapter();
|
||||||
method public void onAnimationCancel(android.animation.Animator);
|
method public void onAnimationCancel(android.animation.Animator);
|
||||||
method public void onAnimationEnd(android.animation.Animator);
|
method public void onAnimationEnd(android.animation.Animator);
|
||||||
|
method public void onAnimationPause(android.animation.Animator);
|
||||||
method public void onAnimationRepeat(android.animation.Animator);
|
method public void onAnimationRepeat(android.animation.Animator);
|
||||||
|
method public void onAnimationResume(android.animation.Animator);
|
||||||
method public void onAnimationStart(android.animation.Animator);
|
method public void onAnimationStart(android.animation.Animator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,17 @@ public abstract class Animator implements Cloneable {
|
|||||||
*/
|
*/
|
||||||
ArrayList<AnimatorListener> mListeners = null;
|
ArrayList<AnimatorListener> mListeners = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The set of listeners to be sent pause/resume events through the life
|
||||||
|
* of an animation.
|
||||||
|
*/
|
||||||
|
ArrayList<AnimatorPauseListener> mPauseListeners = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this animator is currently in a paused state.
|
||||||
|
*/
|
||||||
|
boolean mPaused = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts this animation. If the animation has a nonzero startDelay, the animation will start
|
* Starts this animation. If the animation has a nonzero startDelay, the animation will start
|
||||||
* running after that delay elapses. A non-delayed animation will have its initial
|
* running after that delay elapses. A non-delayed animation will have its initial
|
||||||
@@ -68,6 +79,66 @@ public abstract class Animator implements Cloneable {
|
|||||||
public void end() {
|
public void end() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pauses a running animation. This method should only be called on the same thread on
|
||||||
|
* which the animation was started. If the animation has not yet been {@link
|
||||||
|
* #isStarted() started} or has since ended, then the call is ignored. Paused
|
||||||
|
* animations can be resumed by calling {@link #resume()}.
|
||||||
|
*
|
||||||
|
* @see #resume()
|
||||||
|
* @see #isPaused()
|
||||||
|
* @see AnimatorPauseListener
|
||||||
|
*/
|
||||||
|
public void pause() {
|
||||||
|
if (isStarted() && !mPaused) {
|
||||||
|
mPaused = true;
|
||||||
|
if (mPauseListeners != null) {
|
||||||
|
ArrayList<AnimatorPauseListener> tmpListeners =
|
||||||
|
(ArrayList<AnimatorPauseListener>) mPauseListeners.clone();
|
||||||
|
int numListeners = tmpListeners.size();
|
||||||
|
for (int i = 0; i < numListeners; ++i) {
|
||||||
|
tmpListeners.get(i).onAnimationPause(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resumes a paused animation, causing the animator to pick up where it left off
|
||||||
|
* when it was paused. This method should only be called on the same thread on
|
||||||
|
* which the animation was started. Calls to resume() on an animator that is
|
||||||
|
* not currently paused will be ignored.
|
||||||
|
*
|
||||||
|
* @see #pause()
|
||||||
|
* @see #isPaused()
|
||||||
|
* @see AnimatorPauseListener
|
||||||
|
*/
|
||||||
|
public void resume() {
|
||||||
|
if (mPaused) {
|
||||||
|
mPaused = false;
|
||||||
|
if (mPauseListeners != null) {
|
||||||
|
ArrayList<AnimatorPauseListener> tmpListeners =
|
||||||
|
(ArrayList<AnimatorPauseListener>) mPauseListeners.clone();
|
||||||
|
int numListeners = tmpListeners.size();
|
||||||
|
for (int i = 0; i < numListeners; ++i) {
|
||||||
|
tmpListeners.get(i).onAnimationResume(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether this animator is currently in a paused state.
|
||||||
|
*
|
||||||
|
* @return True if the animator is currently paused, false otherwise.
|
||||||
|
*
|
||||||
|
* @see #pause()
|
||||||
|
* @see #resume()
|
||||||
|
*/
|
||||||
|
public boolean isPaused() {
|
||||||
|
return mPaused;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The amount of time, in milliseconds, to delay processing the animation
|
* The amount of time, in milliseconds, to delay processing the animation
|
||||||
* after {@link #start()} is called.
|
* after {@link #start()} is called.
|
||||||
@@ -179,16 +250,59 @@ public abstract class Animator implements Cloneable {
|
|||||||
return mListeners;
|
return mListeners;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a pause listener to this animator.
|
||||||
|
*
|
||||||
|
* @param listener the listener to be added to the current set of pause listeners
|
||||||
|
* for this animation.
|
||||||
|
*/
|
||||||
|
public void addPauseListener(AnimatorPauseListener listener) {
|
||||||
|
if (mPauseListeners == null) {
|
||||||
|
mPauseListeners = new ArrayList<AnimatorPauseListener>();
|
||||||
|
}
|
||||||
|
mPauseListeners.add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a pause listener from the set listening to this animation.
|
||||||
|
*
|
||||||
|
* @param listener the listener to be removed from the current set of pause
|
||||||
|
* listeners for this animation.
|
||||||
|
*/
|
||||||
|
public void removePauseListener(AnimatorPauseListener listener) {
|
||||||
|
if (mPauseListeners == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mPauseListeners.remove(listener);
|
||||||
|
if (mPauseListeners.size() == 0) {
|
||||||
|
mPauseListeners = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the set of {@link AnimatorPauseListener} objects that are currently
|
||||||
|
* listening for pause/resume events on this animator.
|
||||||
|
*
|
||||||
|
* @return ArrayList<AnimatorListener> The set of pause listeners.
|
||||||
|
*/
|
||||||
|
public ArrayList<AnimatorPauseListener> getPauseListeners() {
|
||||||
|
return mPauseListeners;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes all listeners from this object. This is equivalent to calling
|
* Removes all listeners from this object. This is equivalent to calling
|
||||||
* <code>getListeners()</code> followed by calling <code>clear()</code> on the
|
* {@link #getListeners()} and {@link #getPauseListeners()} followed by calling
|
||||||
* returned list of listeners.
|
* {@link ArrayList#clear()} on the returned lists of listeners.
|
||||||
*/
|
*/
|
||||||
public void removeAllListeners() {
|
public void removeAllListeners() {
|
||||||
if (mListeners != null) {
|
if (mListeners != null) {
|
||||||
mListeners.clear();
|
mListeners.clear();
|
||||||
mListeners = null;
|
mListeners = null;
|
||||||
}
|
}
|
||||||
|
if (mPauseListeners != null) {
|
||||||
|
mPauseListeners.clear();
|
||||||
|
mPauseListeners = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -203,6 +317,14 @@ public abstract class Animator implements Cloneable {
|
|||||||
anim.mListeners.add(oldListeners.get(i));
|
anim.mListeners.add(oldListeners.get(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (mPauseListeners != null) {
|
||||||
|
ArrayList<AnimatorPauseListener> oldListeners = mPauseListeners;
|
||||||
|
anim.mPauseListeners = new ArrayList<AnimatorPauseListener>();
|
||||||
|
int numListeners = oldListeners.size();
|
||||||
|
for (int i = 0; i < numListeners; ++i) {
|
||||||
|
anim.mPauseListeners.add(oldListeners.get(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
return anim;
|
return anim;
|
||||||
} catch (CloneNotSupportedException e) {
|
} catch (CloneNotSupportedException e) {
|
||||||
throw new AssertionError();
|
throw new AssertionError();
|
||||||
@@ -280,4 +402,29 @@ public abstract class Animator implements Cloneable {
|
|||||||
*/
|
*/
|
||||||
void onAnimationRepeat(Animator animation);
|
void onAnimationRepeat(Animator animation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A pause listener receives notifications from an animation when the
|
||||||
|
* animation is {@link #pause() paused} or {@link #resume() resumed}.
|
||||||
|
*
|
||||||
|
* @see #addPauseListener(AnimatorPauseListener)
|
||||||
|
*/
|
||||||
|
public static interface AnimatorPauseListener {
|
||||||
|
/**
|
||||||
|
* <p>Notifies that the animation was paused.</p>
|
||||||
|
*
|
||||||
|
* @param animation The animaton being paused.
|
||||||
|
* @see #pause()
|
||||||
|
*/
|
||||||
|
void onAnimationPause(Animator animation);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Notifies that the animation was resumed, after being
|
||||||
|
* previously paused.</p>
|
||||||
|
*
|
||||||
|
* @param animation The animation being resumed.
|
||||||
|
* @see #resume()
|
||||||
|
*/
|
||||||
|
void onAnimationResume(Animator animation);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ package android.animation;
|
|||||||
* Any custom listener that cares only about a subset of the methods of this listener can
|
* Any custom listener that cares only about a subset of the methods of this listener can
|
||||||
* simply subclass this adapter class instead of implementing the interface directly.
|
* simply subclass this adapter class instead of implementing the interface directly.
|
||||||
*/
|
*/
|
||||||
public abstract class AnimatorListenerAdapter implements Animator.AnimatorListener {
|
public abstract class AnimatorListenerAdapter implements Animator.AnimatorListener,
|
||||||
|
Animator.AnimatorPauseListener {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
@@ -51,4 +52,17 @@ public abstract class AnimatorListenerAdapter implements Animator.AnimatorListen
|
|||||||
public void onAnimationStart(Animator animation) {
|
public void onAnimationStart(Animator animation) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void onAnimationPause(Animator animation) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void onAnimationResume(Animator animation) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -455,6 +455,36 @@ public final class AnimatorSet extends Animator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void pause() {
|
||||||
|
boolean previouslyPaused = mPaused;
|
||||||
|
super.pause();
|
||||||
|
if (!previouslyPaused && mPaused) {
|
||||||
|
if (mDelayAnim != null) {
|
||||||
|
mDelayAnim.pause();
|
||||||
|
} else {
|
||||||
|
for (Node node : mNodes) {
|
||||||
|
node.animation.pause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resume() {
|
||||||
|
boolean previouslyPaused = mPaused;
|
||||||
|
super.resume();
|
||||||
|
if (previouslyPaused && !mPaused) {
|
||||||
|
if (mDelayAnim != null) {
|
||||||
|
mDelayAnim.resume();
|
||||||
|
} else {
|
||||||
|
for (Node node : mNodes) {
|
||||||
|
node.animation.resume();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*
|
*
|
||||||
@@ -467,6 +497,7 @@ public final class AnimatorSet extends Animator {
|
|||||||
public void start() {
|
public void start() {
|
||||||
mTerminated = false;
|
mTerminated = false;
|
||||||
mStarted = true;
|
mStarted = true;
|
||||||
|
mPaused = false;
|
||||||
|
|
||||||
if (mDuration >= 0) {
|
if (mDuration >= 0) {
|
||||||
// If the duration was set on this AnimatorSet, pass it along to all child animations
|
// If the duration was set on this AnimatorSet, pass it along to all child animations
|
||||||
@@ -549,6 +580,7 @@ public final class AnimatorSet extends Animator {
|
|||||||
mPlayingSet.add(node.animation);
|
mPlayingSet.add(node.animation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
mDelayAnim = null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
mDelayAnim.start();
|
mDelayAnim.start();
|
||||||
@@ -787,6 +819,7 @@ public final class AnimatorSet extends Animator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
mAnimatorSet.mStarted = false;
|
mAnimatorSet.mStarted = false;
|
||||||
|
mAnimatorSet.mPaused = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,6 +80,20 @@ public class ValueAnimator extends Animator {
|
|||||||
*/
|
*/
|
||||||
long mSeekTime = -1;
|
long mSeekTime = -1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set on the next frame after pause() is called, used to calculate a new startTime
|
||||||
|
* or delayStartTime which allows the animator to continue from the point at which
|
||||||
|
* it was paused. If negative, has not yet been set.
|
||||||
|
*/
|
||||||
|
private long mPauseTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set when an animator is resumed. This triggers logic in the next frame which
|
||||||
|
* actually resumes the animator.
|
||||||
|
*/
|
||||||
|
private boolean mResumed = false;
|
||||||
|
|
||||||
|
|
||||||
// The static sAnimationHandler processes the internal timing loop on which all animations
|
// The static sAnimationHandler processes the internal timing loop on which all animations
|
||||||
// are based
|
// are based
|
||||||
/**
|
/**
|
||||||
@@ -147,7 +161,7 @@ public class ValueAnimator extends Animator {
|
|||||||
private boolean mStarted = false;
|
private boolean mStarted = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tracks whether we've notified listeners of the onAnimationSTart() event. This can be
|
* Tracks whether we've notified listeners of the onAnimationStart() event. This can be
|
||||||
* complex to keep track of since we notify listeners at different times depending on
|
* complex to keep track of since we notify listeners at different times depending on
|
||||||
* startDelay and whether start() was called before end().
|
* startDelay and whether start() was called before end().
|
||||||
*/
|
*/
|
||||||
@@ -914,6 +928,7 @@ public class ValueAnimator extends Animator {
|
|||||||
mPlayingState = STOPPED;
|
mPlayingState = STOPPED;
|
||||||
mStarted = true;
|
mStarted = true;
|
||||||
mStartedDelay = false;
|
mStartedDelay = false;
|
||||||
|
mPaused = false;
|
||||||
AnimationHandler animationHandler = getOrCreateAnimationHandler();
|
AnimationHandler animationHandler = getOrCreateAnimationHandler();
|
||||||
animationHandler.mPendingAnimations.add(this);
|
animationHandler.mPendingAnimations.add(this);
|
||||||
if (mStartDelay == 0) {
|
if (mStartDelay == 0) {
|
||||||
@@ -970,6 +985,24 @@ public class ValueAnimator extends Animator {
|
|||||||
endAnimation(handler);
|
endAnimation(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resume() {
|
||||||
|
if (mPaused) {
|
||||||
|
mResumed = true;
|
||||||
|
}
|
||||||
|
super.resume();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void pause() {
|
||||||
|
boolean previouslyPaused = mPaused;
|
||||||
|
super.pause();
|
||||||
|
if (!previouslyPaused && mPaused) {
|
||||||
|
mPauseTime = -1;
|
||||||
|
mResumed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isRunning() {
|
public boolean isRunning() {
|
||||||
return (mPlayingState == RUNNING || mRunning);
|
return (mPlayingState == RUNNING || mRunning);
|
||||||
@@ -1008,6 +1041,7 @@ public class ValueAnimator extends Animator {
|
|||||||
handler.mPendingAnimations.remove(this);
|
handler.mPendingAnimations.remove(this);
|
||||||
handler.mDelayedAnims.remove(this);
|
handler.mDelayedAnims.remove(this);
|
||||||
mPlayingState = STOPPED;
|
mPlayingState = STOPPED;
|
||||||
|
mPaused = false;
|
||||||
if ((mStarted || mRunning) && mListeners != null) {
|
if ((mStarted || mRunning) && mListeners != null) {
|
||||||
if (!mRunning) {
|
if (!mRunning) {
|
||||||
// If it's not yet running, then start listeners weren't called. Call them now.
|
// If it's not yet running, then start listeners weren't called. Call them now.
|
||||||
@@ -1071,6 +1105,18 @@ public class ValueAnimator extends Animator {
|
|||||||
mStartedDelay = true;
|
mStartedDelay = true;
|
||||||
mDelayStartTime = currentTime;
|
mDelayStartTime = currentTime;
|
||||||
} else {
|
} else {
|
||||||
|
if (mPaused) {
|
||||||
|
if (mPauseTime < 0) {
|
||||||
|
mPauseTime = currentTime;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} else if (mResumed) {
|
||||||
|
mResumed = false;
|
||||||
|
if (mPauseTime > 0) {
|
||||||
|
// Offset by the duration that the animation was paused
|
||||||
|
mDelayStartTime += (currentTime - mPauseTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
long deltaTime = currentTime - mDelayStartTime;
|
long deltaTime = currentTime - mDelayStartTime;
|
||||||
if (deltaTime > mStartDelay) {
|
if (deltaTime > mStartDelay) {
|
||||||
// startDelay ended - start the anim and record the
|
// startDelay ended - start the anim and record the
|
||||||
@@ -1093,7 +1139,7 @@ public class ValueAnimator extends Animator {
|
|||||||
*
|
*
|
||||||
* @param currentTime The current time, as tracked by the static timing handler
|
* @param currentTime The current time, as tracked by the static timing handler
|
||||||
* @return true if the animation's duration, including any repetitions due to
|
* @return true if the animation's duration, including any repetitions due to
|
||||||
* <code>repeatCount</code> has been exceeded and the animation should be ended.
|
* <code>repeatCount</code>, has been exceeded and the animation should be ended.
|
||||||
*/
|
*/
|
||||||
boolean animationFrame(long currentTime) {
|
boolean animationFrame(long currentTime) {
|
||||||
boolean done = false;
|
boolean done = false;
|
||||||
@@ -1148,6 +1194,18 @@ public class ValueAnimator extends Animator {
|
|||||||
mSeekTime = -1;
|
mSeekTime = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (mPaused) {
|
||||||
|
if (mPauseTime < 0) {
|
||||||
|
mPauseTime = frameTime;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} else if (mResumed) {
|
||||||
|
mResumed = false;
|
||||||
|
if (mPauseTime > 0) {
|
||||||
|
// Offset by the duration that the animation was paused
|
||||||
|
mStartTime += (frameTime - mPauseTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
// The frame time might be before the start time during the first frame of
|
// The frame time might be before the start time during the first frame of
|
||||||
// an animation. The "current time" must always be on or after the start
|
// an animation. The "current time" must always be on or after the start
|
||||||
// time to avoid animating frames at negative time intervals. In practice, this
|
// time to avoid animating frames at negative time intervals. In practice, this
|
||||||
|
|||||||
@@ -37,14 +37,12 @@ public class AnimatorSetEventsTest extends EventsTest {
|
|||||||
button = (Button) getActivity().findViewById(R.id.animatingButton);
|
button = (Button) getActivity().findViewById(R.id.animatingButton);
|
||||||
mAnimator = new AnimatorSet();
|
mAnimator = new AnimatorSet();
|
||||||
((AnimatorSet)mAnimator).playSequentially(xAnim, yAnim);
|
((AnimatorSet)mAnimator).playSequentially(xAnim, yAnim);
|
||||||
|
|
||||||
super.setUp();
|
super.setUp();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected long getTimeout() {
|
protected long getTimeout() {
|
||||||
return (xAnim.getDuration() + yAnim.getDuration()) +
|
return (2 * mAnimator.getDuration()) + (2 * mAnimator.getStartDelay()) +
|
||||||
(xAnim.getStartDelay() + yAnim.getStartDelay()) +
|
|
||||||
ANIM_DELAY + FUTURE_RELEASE_DELAY;
|
ANIM_DELAY + FUTURE_RELEASE_DELAY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import android.test.suitebuilder.annotation.MediumTest;
|
|||||||
import android.test.suitebuilder.annotation.SmallTest;
|
import android.test.suitebuilder.annotation.SmallTest;
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for the various lifecycle events of Animators. This abstract class is subclassed by
|
* Tests for the various lifecycle events of Animators. This abstract class is subclassed by
|
||||||
@@ -42,12 +43,15 @@ public abstract class EventsTest
|
|||||||
protected static final int ANIM_DELAY = 100;
|
protected static final int ANIM_DELAY = 100;
|
||||||
protected static final int ANIM_MID_DURATION = ANIM_DURATION / 2;
|
protected static final int ANIM_MID_DURATION = ANIM_DURATION / 2;
|
||||||
protected static final int ANIM_MID_DELAY = ANIM_DELAY / 2;
|
protected static final int ANIM_MID_DELAY = ANIM_DELAY / 2;
|
||||||
|
protected static final int ANIM_PAUSE_DURATION = ANIM_DELAY;
|
||||||
|
protected static final int ANIM_PAUSE_DELAY = ANIM_DELAY / 2;
|
||||||
protected static final int FUTURE_RELEASE_DELAY = 50;
|
protected static final int FUTURE_RELEASE_DELAY = 50;
|
||||||
|
protected static final int ANIM_FULL_DURATION_SLOP = 100;
|
||||||
|
|
||||||
private boolean mStarted; // tracks whether we've received the onAnimationStart() callback
|
private boolean mStarted; // tracks whether we've received the onAnimationStart() callback
|
||||||
protected boolean mRunning; // tracks whether we've started the animator
|
protected boolean mRunning; // tracks whether we've started the animator
|
||||||
private boolean mCanceled; // trackes whether we've canceled the animator
|
private boolean mCanceled; // tracks whether we've canceled the animator
|
||||||
protected Animator.AnimatorListener mFutureListener; // mechanism for delaying the end of the test
|
protected Animator.AnimatorListener mFutureListener; // mechanism for delaying end of the test
|
||||||
protected FutureWaiter mFuture; // Mechanism for waiting for the UI test to complete
|
protected FutureWaiter mFuture; // Mechanism for waiting for the UI test to complete
|
||||||
private Animator.AnimatorListener mListener; // Listener that handles/tests the events
|
private Animator.AnimatorListener mListener; // Listener that handles/tests the events
|
||||||
|
|
||||||
@@ -103,6 +107,48 @@ public abstract class EventsTest
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pauses the given animator. Used to delay pausing until some later time (after the
|
||||||
|
* animator has started playing).
|
||||||
|
*/
|
||||||
|
static class Pauser implements Runnable {
|
||||||
|
Animator mAnim;
|
||||||
|
FutureWaiter mFuture;
|
||||||
|
public Pauser(Animator anim, FutureWaiter future) {
|
||||||
|
mAnim = anim;
|
||||||
|
mFuture = future;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
mAnim.pause();
|
||||||
|
} catch (junit.framework.AssertionFailedError e) {
|
||||||
|
mFuture.setException(new RuntimeException(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resumes the given animator. Used to delay resuming until some later time (after the
|
||||||
|
* animator has paused for some duration).
|
||||||
|
*/
|
||||||
|
static class Resumer implements Runnable {
|
||||||
|
Animator mAnim;
|
||||||
|
FutureWaiter mFuture;
|
||||||
|
public Resumer(Animator anim, FutureWaiter future) {
|
||||||
|
mAnim = anim;
|
||||||
|
mFuture = future;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
mAnim.resume();
|
||||||
|
} catch (junit.framework.AssertionFailedError e) {
|
||||||
|
mFuture.setException(new RuntimeException(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Releases the given Future object when the listener's end() event is called. Specifically,
|
* Releases the given Future object when the listener's end() event is called. Specifically,
|
||||||
* it releases it after some further delay, to give the test time to do other things right
|
* it releases it after some further delay, to give the test time to do other things right
|
||||||
@@ -555,4 +601,114 @@ public abstract class EventsTest
|
|||||||
mFuture.get(getTimeout(), TimeUnit.MILLISECONDS);
|
mFuture.get(getTimeout(), TimeUnit.MILLISECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify that pausing and resuming an animator ends within
|
||||||
|
* the appropriate timeout duration.
|
||||||
|
*/
|
||||||
|
@MediumTest
|
||||||
|
public void testPauseResume() throws Exception {
|
||||||
|
mFutureListener = new FutureReleaseListener(mFuture);
|
||||||
|
getActivity().runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
Handler handler = new Handler();
|
||||||
|
mAnimator.addListener(mFutureListener);
|
||||||
|
mRunning = true;
|
||||||
|
mAnimator.start();
|
||||||
|
handler.postDelayed(new Pauser(mAnimator, mFuture), ANIM_PAUSE_DELAY);
|
||||||
|
handler.postDelayed(new Resumer(mAnimator, mFuture),
|
||||||
|
ANIM_PAUSE_DELAY + ANIM_PAUSE_DURATION);
|
||||||
|
} catch (junit.framework.AssertionFailedError e) {
|
||||||
|
mFuture.setException(new RuntimeException(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
mFuture.get(getTimeout() + ANIM_PAUSE_DURATION, TimeUnit.MILLISECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify that pausing and resuming a startDelayed animator ends within
|
||||||
|
* the appropriate timeout duration.
|
||||||
|
*/
|
||||||
|
@MediumTest
|
||||||
|
public void testPauseResumeDelayed() throws Exception {
|
||||||
|
mAnimator.setStartDelay(ANIM_DELAY);
|
||||||
|
mFutureListener = new FutureReleaseListener(mFuture);
|
||||||
|
getActivity().runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
Handler handler = new Handler();
|
||||||
|
mAnimator.addListener(mFutureListener);
|
||||||
|
mRunning = true;
|
||||||
|
mAnimator.start();
|
||||||
|
handler.postDelayed(new Pauser(mAnimator, mFuture), ANIM_PAUSE_DELAY);
|
||||||
|
handler.postDelayed(new Resumer(mAnimator, mFuture),
|
||||||
|
ANIM_PAUSE_DELAY + ANIM_PAUSE_DURATION);
|
||||||
|
} catch (junit.framework.AssertionFailedError e) {
|
||||||
|
mFuture.setException(new RuntimeException(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
mFuture.get(getTimeout() + ANIM_PAUSE_DURATION + ANIM_FULL_DURATION_SLOP,
|
||||||
|
TimeUnit.MILLISECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify that pausing an animator without resuming it causes a timeout.
|
||||||
|
*/
|
||||||
|
@MediumTest
|
||||||
|
public void testPauseTimeout() throws Exception {
|
||||||
|
mFutureListener = new FutureReleaseListener(mFuture);
|
||||||
|
getActivity().runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
Handler handler = new Handler();
|
||||||
|
mAnimator.addListener(mFutureListener);
|
||||||
|
mRunning = true;
|
||||||
|
mAnimator.start();
|
||||||
|
handler.postDelayed(new Pauser(mAnimator, mFuture), ANIM_PAUSE_DELAY);
|
||||||
|
} catch (junit.framework.AssertionFailedError e) {
|
||||||
|
mFuture.setException(new RuntimeException(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
mFuture.get(getTimeout() + ANIM_PAUSE_DURATION + ANIM_FULL_DURATION_SLOP,
|
||||||
|
TimeUnit.MILLISECONDS);
|
||||||
|
} catch (TimeoutException e) {
|
||||||
|
// Expected behavior, swallow the exception
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify that pausing a startDelayed animator without resuming it causes a timeout.
|
||||||
|
*/
|
||||||
|
@MediumTest
|
||||||
|
public void testPauseTimeoutDelayed() throws Exception {
|
||||||
|
mAnimator.setStartDelay(ANIM_DELAY);
|
||||||
|
mFutureListener = new FutureReleaseListener(mFuture);
|
||||||
|
getActivity().runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
Handler handler = new Handler();
|
||||||
|
mAnimator.addListener(mFutureListener);
|
||||||
|
mRunning = true;
|
||||||
|
mAnimator.start();
|
||||||
|
handler.postDelayed(new Pauser(mAnimator, mFuture), ANIM_PAUSE_DELAY);
|
||||||
|
} catch (junit.framework.AssertionFailedError e) {
|
||||||
|
mFuture.setException(new RuntimeException(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
mFuture.get(getTimeout() + ANIM_PAUSE_DURATION + ANIM_FULL_DURATION_SLOP,
|
||||||
|
TimeUnit.MILLISECONDS);
|
||||||
|
} catch (TimeoutException e) {
|
||||||
|
// Expected behavior, swallow the exception
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user