pause/resume for Animators
It is now possible to pause Animator-based animations. Pausing an animator causes it to hold the current time/value indefinitely, or until end/cancel/resume is called. When resume() is called, it continues from where it left off. There is a new listener interface on Animator, AnimatorPauseListener, which can be used to listen to pause/resume events. Change-Id: I77d1535e792fb7bf349f549a0ac0a0d85958cb47
This commit is contained in:
@@ -2338,17 +2338,23 @@ package android.animation {
|
||||
public abstract class Animator implements java.lang.Cloneable {
|
||||
ctor public Animator();
|
||||
method public void addListener(android.animation.Animator.AnimatorListener);
|
||||
method public void addPauseListener(android.animation.Animator.AnimatorPauseListener);
|
||||
method public void cancel();
|
||||
method public android.animation.Animator clone();
|
||||
method public void end();
|
||||
method public abstract long getDuration();
|
||||
method public android.animation.TimeInterpolator getInterpolator();
|
||||
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 boolean isPaused();
|
||||
method public abstract boolean isRunning();
|
||||
method public boolean isStarted();
|
||||
method public void pause();
|
||||
method public void removeAllListeners();
|
||||
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 void setInterpolator(android.animation.TimeInterpolator);
|
||||
method public abstract void setStartDelay(long);
|
||||
@@ -2365,16 +2371,23 @@ package android.animation {
|
||||
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 {
|
||||
ctor public AnimatorInflater();
|
||||
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();
|
||||
method public void onAnimationCancel(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 onAnimationResume(android.animation.Animator);
|
||||
method public void onAnimationStart(android.animation.Animator);
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,17 @@ public abstract class Animator implements Cloneable {
|
||||
*/
|
||||
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
|
||||
* 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() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* after {@link #start()} is called.
|
||||
@@ -179,16 +250,59 @@ public abstract class Animator implements Cloneable {
|
||||
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
|
||||
* <code>getListeners()</code> followed by calling <code>clear()</code> on the
|
||||
* returned list of listeners.
|
||||
* {@link #getListeners()} and {@link #getPauseListeners()} followed by calling
|
||||
* {@link ArrayList#clear()} on the returned lists of listeners.
|
||||
*/
|
||||
public void removeAllListeners() {
|
||||
if (mListeners != null) {
|
||||
mListeners.clear();
|
||||
mListeners = null;
|
||||
}
|
||||
if (mPauseListeners != null) {
|
||||
mPauseListeners.clear();
|
||||
mPauseListeners = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -203,6 +317,14 @@ public abstract class Animator implements Cloneable {
|
||||
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;
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new AssertionError();
|
||||
@@ -280,4 +402,29 @@ public abstract class Animator implements Cloneable {
|
||||
*/
|
||||
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
|
||||
* 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}
|
||||
@@ -51,4 +52,17 @@ public abstract class AnimatorListenerAdapter implements Animator.AnimatorListen
|
||||
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}
|
||||
*
|
||||
@@ -467,6 +497,7 @@ public final class AnimatorSet extends Animator {
|
||||
public void start() {
|
||||
mTerminated = false;
|
||||
mStarted = true;
|
||||
mPaused = false;
|
||||
|
||||
if (mDuration >= 0) {
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
mDelayAnim = null;
|
||||
}
|
||||
});
|
||||
mDelayAnim.start();
|
||||
@@ -787,6 +819,7 @@ public final class AnimatorSet extends Animator {
|
||||
}
|
||||
}
|
||||
mAnimatorSet.mStarted = false;
|
||||
mAnimatorSet.mPaused = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,6 +80,20 @@ public class ValueAnimator extends Animator {
|
||||
*/
|
||||
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
|
||||
// are based
|
||||
/**
|
||||
@@ -147,7 +161,7 @@ public class ValueAnimator extends Animator {
|
||||
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
|
||||
* startDelay and whether start() was called before end().
|
||||
*/
|
||||
@@ -914,6 +928,7 @@ public class ValueAnimator extends Animator {
|
||||
mPlayingState = STOPPED;
|
||||
mStarted = true;
|
||||
mStartedDelay = false;
|
||||
mPaused = false;
|
||||
AnimationHandler animationHandler = getOrCreateAnimationHandler();
|
||||
animationHandler.mPendingAnimations.add(this);
|
||||
if (mStartDelay == 0) {
|
||||
@@ -970,6 +985,24 @@ public class ValueAnimator extends Animator {
|
||||
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
|
||||
public boolean isRunning() {
|
||||
return (mPlayingState == RUNNING || mRunning);
|
||||
@@ -1008,6 +1041,7 @@ public class ValueAnimator extends Animator {
|
||||
handler.mPendingAnimations.remove(this);
|
||||
handler.mDelayedAnims.remove(this);
|
||||
mPlayingState = STOPPED;
|
||||
mPaused = false;
|
||||
if ((mStarted || mRunning) && mListeners != null) {
|
||||
if (!mRunning) {
|
||||
// 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;
|
||||
mDelayStartTime = currentTime;
|
||||
} 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;
|
||||
if (deltaTime > mStartDelay) {
|
||||
// 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
|
||||
* @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 done = false;
|
||||
@@ -1148,6 +1194,18 @@ public class ValueAnimator extends Animator {
|
||||
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
|
||||
// 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
|
||||
|
||||
@@ -37,14 +37,12 @@ public class AnimatorSetEventsTest extends EventsTest {
|
||||
button = (Button) getActivity().findViewById(R.id.animatingButton);
|
||||
mAnimator = new AnimatorSet();
|
||||
((AnimatorSet)mAnimator).playSequentially(xAnim, yAnim);
|
||||
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long getTimeout() {
|
||||
return (xAnim.getDuration() + yAnim.getDuration()) +
|
||||
(xAnim.getStartDelay() + yAnim.getStartDelay()) +
|
||||
return (2 * mAnimator.getDuration()) + (2 * mAnimator.getStartDelay()) +
|
||||
ANIM_DELAY + FUTURE_RELEASE_DELAY;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import android.test.suitebuilder.annotation.MediumTest;
|
||||
import android.test.suitebuilder.annotation.SmallTest;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
/**
|
||||
* 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_MID_DURATION = ANIM_DURATION / 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 ANIM_FULL_DURATION_SLOP = 100;
|
||||
|
||||
private boolean mStarted; // tracks whether we've received the onAnimationStart() callback
|
||||
protected boolean mRunning; // tracks whether we've started the animator
|
||||
private boolean mCanceled; // trackes whether we've canceled the animator
|
||||
protected Animator.AnimatorListener mFutureListener; // mechanism for delaying the end of the test
|
||||
private boolean mCanceled; // tracks whether we've canceled the animator
|
||||
protected Animator.AnimatorListener mFutureListener; // mechanism for delaying end of the test
|
||||
protected FutureWaiter mFuture; // Mechanism for waiting for the UI test to complete
|
||||
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,
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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