Merge "Fix Animator cancel() behavior"
This commit is contained in:
@@ -87,11 +87,13 @@ public final class AnimatorSet extends Animator {
|
||||
private AnimatorSetListener mSetListener = null;
|
||||
|
||||
/**
|
||||
* Flag indicating that the AnimatorSet has been canceled (by calling cancel() or end()).
|
||||
* Flag indicating that the AnimatorSet has been manually
|
||||
* terminated (by calling cancel() or end()).
|
||||
* This flag is used to avoid starting other animations when currently-playing
|
||||
* child animations of this AnimatorSet end.
|
||||
* child animations of this AnimatorSet end. It also determines whether cancel/end
|
||||
* notifications are sent out via the normal AnimatorSetListener mechanism.
|
||||
*/
|
||||
boolean mCanceled = false;
|
||||
boolean mTerminated = false;
|
||||
|
||||
// The amount of time in ms to delay starting the animation after start() is called
|
||||
private long mStartDelay = 0;
|
||||
@@ -271,31 +273,29 @@ public final class AnimatorSet extends Animator {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void cancel() {
|
||||
mCanceled = true;
|
||||
if (mListeners != null) {
|
||||
ArrayList<AnimatorListener> tmpListeners =
|
||||
(ArrayList<AnimatorListener>) mListeners.clone();
|
||||
for (AnimatorListener listener : tmpListeners) {
|
||||
listener.onAnimationCancel(this);
|
||||
}
|
||||
}
|
||||
if (mDelayAnim != null && mDelayAnim.isRunning()) {
|
||||
// If we're currently in the startDelay period, just cancel that animator and
|
||||
// send out the end event to all listeners
|
||||
mDelayAnim.cancel();
|
||||
mTerminated = true;
|
||||
if (isRunning()) {
|
||||
ArrayList<AnimatorListener> tmpListeners = null;
|
||||
if (mListeners != null) {
|
||||
ArrayList<AnimatorListener> tmpListeners =
|
||||
(ArrayList<AnimatorListener>) mListeners.clone();
|
||||
tmpListeners = (ArrayList<AnimatorListener>) mListeners.clone();
|
||||
for (AnimatorListener listener : tmpListeners) {
|
||||
listener.onAnimationCancel(this);
|
||||
}
|
||||
}
|
||||
if (mDelayAnim != null && mDelayAnim.isRunning()) {
|
||||
// If we're currently in the startDelay period, just cancel that animator and
|
||||
// send out the end event to all listeners
|
||||
mDelayAnim.cancel();
|
||||
} else if (mSortedNodes.size() > 0) {
|
||||
for (Node node : mSortedNodes) {
|
||||
node.animation.cancel();
|
||||
}
|
||||
}
|
||||
if (tmpListeners != null) {
|
||||
for (AnimatorListener listener : tmpListeners) {
|
||||
listener.onAnimationEnd(this);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (mSortedNodes.size() > 0) {
|
||||
for (Node node : mSortedNodes) {
|
||||
node.animation.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -307,23 +307,32 @@ public final class AnimatorSet extends Animator {
|
||||
*/
|
||||
@Override
|
||||
public void end() {
|
||||
mCanceled = true;
|
||||
if (mSortedNodes.size() != mNodes.size()) {
|
||||
// hasn't been started yet - sort the nodes now, then end them
|
||||
sortNodes();
|
||||
for (Node node : mSortedNodes) {
|
||||
if (mSetListener == null) {
|
||||
mSetListener = new AnimatorSetListener(this);
|
||||
mTerminated = true;
|
||||
if (isRunning()) {
|
||||
if (mSortedNodes.size() != mNodes.size()) {
|
||||
// hasn't been started yet - sort the nodes now, then end them
|
||||
sortNodes();
|
||||
for (Node node : mSortedNodes) {
|
||||
if (mSetListener == null) {
|
||||
mSetListener = new AnimatorSetListener(this);
|
||||
}
|
||||
node.animation.addListener(mSetListener);
|
||||
}
|
||||
node.animation.addListener(mSetListener);
|
||||
}
|
||||
}
|
||||
if (mDelayAnim != null) {
|
||||
mDelayAnim.cancel();
|
||||
}
|
||||
if (mSortedNodes.size() > 0) {
|
||||
for (Node node : mSortedNodes) {
|
||||
node.animation.end();
|
||||
if (mDelayAnim != null) {
|
||||
mDelayAnim.cancel();
|
||||
}
|
||||
if (mSortedNodes.size() > 0) {
|
||||
for (Node node : mSortedNodes) {
|
||||
node.animation.end();
|
||||
}
|
||||
}
|
||||
if (mListeners != null) {
|
||||
ArrayList<AnimatorListener> tmpListeners =
|
||||
(ArrayList<AnimatorListener>) mListeners.clone();
|
||||
for (AnimatorListener listener : tmpListeners) {
|
||||
listener.onAnimationEnd(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -424,7 +433,7 @@ public final class AnimatorSet extends Animator {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void start() {
|
||||
mCanceled = false;
|
||||
mTerminated = false;
|
||||
|
||||
// First, sort the nodes (if necessary). This will ensure that sortedNodes
|
||||
// contains the animation nodes in the correct order.
|
||||
@@ -437,7 +446,8 @@ public final class AnimatorSet extends Animator {
|
||||
ArrayList<AnimatorListener> oldListeners = node.animation.getListeners();
|
||||
if (oldListeners != null && oldListeners.size() > 0) {
|
||||
for (AnimatorListener listener : oldListeners) {
|
||||
if (listener instanceof DependencyListener) {
|
||||
if (listener instanceof DependencyListener ||
|
||||
listener instanceof AnimatorSetListener) {
|
||||
node.animation.removeListener(listener);
|
||||
}
|
||||
}
|
||||
@@ -522,7 +532,7 @@ public final class AnimatorSet extends Animator {
|
||||
* and will populate any appropriate lists, when it is started.
|
||||
*/
|
||||
anim.mNeedsSort = true;
|
||||
anim.mCanceled = false;
|
||||
anim.mTerminated = false;
|
||||
anim.mPlayingSet = new ArrayList<Animator>();
|
||||
anim.mNodeMap = new HashMap<Animator, Node>();
|
||||
anim.mNodes = new ArrayList<Node>();
|
||||
@@ -640,7 +650,7 @@ public final class AnimatorSet extends Animator {
|
||||
* @param dependencyAnimation the animation that sent the event.
|
||||
*/
|
||||
private void startIfReady(Animator dependencyAnimation) {
|
||||
if (mAnimatorSet.mCanceled) {
|
||||
if (mAnimatorSet.mTerminated) {
|
||||
// if the parent AnimatorSet was canceled, then don't start any dependent anims
|
||||
return;
|
||||
}
|
||||
@@ -676,11 +686,15 @@ public final class AnimatorSet extends Animator {
|
||||
}
|
||||
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
if (mPlayingSet.size() == 0) {
|
||||
if (mListeners != null) {
|
||||
int numListeners = mListeners.size();
|
||||
for (int i = 0; i < numListeners; ++i) {
|
||||
mListeners.get(i).onAnimationCancel(mAnimatorSet);
|
||||
if (!mTerminated) {
|
||||
// Listeners are already notified of the AnimatorSet canceling in cancel().
|
||||
// The logic below only kicks in when animations end normally
|
||||
if (mPlayingSet.size() == 0) {
|
||||
if (mListeners != null) {
|
||||
int numListeners = mListeners.size();
|
||||
for (int i = 0; i < numListeners; ++i) {
|
||||
mListeners.get(i).onAnimationCancel(mAnimatorSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -692,24 +706,28 @@ public final class AnimatorSet extends Animator {
|
||||
mPlayingSet.remove(animation);
|
||||
Node animNode = mAnimatorSet.mNodeMap.get(animation);
|
||||
animNode.done = true;
|
||||
ArrayList<Node> sortedNodes = mAnimatorSet.mSortedNodes;
|
||||
boolean allDone = true;
|
||||
int numSortedNodes = sortedNodes.size();
|
||||
for (int i = 0; i < numSortedNodes; ++i) {
|
||||
if (!sortedNodes.get(i).done) {
|
||||
allDone = false;
|
||||
break;
|
||||
if (!mTerminated) {
|
||||
// Listeners are already notified of the AnimatorSet ending in cancel() or
|
||||
// end(); the logic below only kicks in when animations end normally
|
||||
ArrayList<Node> sortedNodes = mAnimatorSet.mSortedNodes;
|
||||
boolean allDone = true;
|
||||
int numSortedNodes = sortedNodes.size();
|
||||
for (int i = 0; i < numSortedNodes; ++i) {
|
||||
if (!sortedNodes.get(i).done) {
|
||||
allDone = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (allDone) {
|
||||
// If this was the last child animation to end, then notify listeners that this
|
||||
// AnimatorSet has ended
|
||||
if (mListeners != null) {
|
||||
ArrayList<AnimatorListener> tmpListeners =
|
||||
(ArrayList<AnimatorListener>) mListeners.clone();
|
||||
int numListeners = tmpListeners.size();
|
||||
for (int i = 0; i < numListeners; ++i) {
|
||||
tmpListeners.get(i).onAnimationEnd(mAnimatorSet);
|
||||
if (allDone) {
|
||||
// If this was the last child animation to end, then notify listeners that this
|
||||
// AnimatorSet has ended
|
||||
if (mListeners != null) {
|
||||
ArrayList<AnimatorListener> tmpListeners =
|
||||
(ArrayList<AnimatorListener>) mListeners.clone();
|
||||
int numListeners = tmpListeners.size();
|
||||
for (int i = 0; i < numListeners; ++i) {
|
||||
tmpListeners.get(i).onAnimationEnd(mAnimatorSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -791,6 +809,8 @@ public final class AnimatorSet extends Animator {
|
||||
}
|
||||
}
|
||||
}
|
||||
// nodes are 'done' by default; they become un-done when started, and done
|
||||
// again when ended
|
||||
node.done = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -933,17 +933,17 @@ public class ValueAnimator extends Animator {
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
if (mListeners != null) {
|
||||
ArrayList<AnimatorListener> tmpListeners =
|
||||
(ArrayList<AnimatorListener>) mListeners.clone();
|
||||
for (AnimatorListener listener : tmpListeners) {
|
||||
listener.onAnimationCancel(this);
|
||||
}
|
||||
}
|
||||
// Only cancel if the animation is actually running or has been started and is about
|
||||
// to run
|
||||
if (mPlayingState != STOPPED || sPendingAnimations.get().contains(this) ||
|
||||
sDelayedAnims.get().contains(this)) {
|
||||
if (mListeners != null) {
|
||||
ArrayList<AnimatorListener> tmpListeners =
|
||||
(ArrayList<AnimatorListener>) mListeners.clone();
|
||||
for (AnimatorListener listener : tmpListeners) {
|
||||
listener.onAnimationCancel(this);
|
||||
}
|
||||
}
|
||||
endAnimation();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ LOCAL_SRC_FILES := \
|
||||
$(call all-java-files-under, EnabledTestApp/src)
|
||||
|
||||
LOCAL_DX_FLAGS := --core-library
|
||||
LOCAL_STATIC_JAVA_LIBRARIES := core-tests android-common frameworks-core-util-lib mockwebserver
|
||||
LOCAL_STATIC_JAVA_LIBRARIES := core-tests android-common frameworks-core-util-lib mockwebserver guava
|
||||
LOCAL_JAVA_LIBRARIES := android.test.runner
|
||||
LOCAL_PACKAGE_NAME := FrameworksCoreTests
|
||||
|
||||
|
||||
@@ -1242,6 +1242,13 @@
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name="android.animation.BasicAnimatorActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
</application>
|
||||
|
||||
<instrumentation android:name="android.test.InstrumentationTestRunner"
|
||||
|
||||
11
core/tests/coretests/res/layout/animator_basic.xml
Normal file
11
core/tests/coretests/res/layout/animator_basic.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:orientation="vertical">
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/animatingButton"/>
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package android.animation;
|
||||
|
||||
import android.widget.Button;
|
||||
import com.android.frameworks.coretests.R;
|
||||
|
||||
/**
|
||||
* Listener tests for AnimatorSet.
|
||||
*/
|
||||
public class AnimatorSetEventsTest extends EventsTest {
|
||||
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
final BasicAnimatorActivity activity = getActivity();
|
||||
Button button = (Button) activity.findViewById(R.id.animatingButton);
|
||||
|
||||
ObjectAnimator xAnim = ObjectAnimator.ofFloat(button, "translationX", 0, 100);
|
||||
ObjectAnimator yAnim = ObjectAnimator.ofFloat(button, "translationX", 0, 100);
|
||||
mAnimator = new AnimatorSet();
|
||||
((AnimatorSet)mAnimator).playSequentially(xAnim, yAnim);
|
||||
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package android.animation;
|
||||
|
||||
import com.android.frameworks.coretests.R;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
|
||||
public class BasicAnimatorActivity extends Activity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.animator_basic);
|
||||
}
|
||||
}
|
||||
265
core/tests/coretests/src/android/animation/EventsTest.java
Normal file
265
core/tests/coretests/src/android/animation/EventsTest.java
Normal file
@@ -0,0 +1,265 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package android.animation;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.test.ActivityInstrumentationTestCase2;
|
||||
import android.test.UiThreadTest;
|
||||
import android.test.suitebuilder.annotation.MediumTest;
|
||||
import android.test.suitebuilder.annotation.SmallTest;
|
||||
|
||||
/**
|
||||
* Tests for the various lifecycle events of Animators. This abstract class is subclassed by
|
||||
* concrete implementations that provide the actual Animator objects being tested. All of the
|
||||
* testing mechanisms are in this class; the subclasses are only responsible for providing
|
||||
* the mAnimator object.
|
||||
*
|
||||
* This test is more complicated than a typical synchronous test because much of the functionality
|
||||
* must happen on the UI thread. Some tests do this by using the UiThreadTest annotation to
|
||||
* automatically run the whole test on that thread. Other tests must run on the UI thread and also
|
||||
* wait for some later event to occur before ending. These tests use a combination of an
|
||||
* AbstractFuture mechanism and a delayed action to release that Future later.
|
||||
*/
|
||||
public abstract class EventsTest
|
||||
extends ActivityInstrumentationTestCase2<BasicAnimatorActivity> {
|
||||
|
||||
private static final int ANIM_DURATION = 400;
|
||||
private static final int ANIM_DELAY = 100;
|
||||
private static final int ANIM_MID_DURATION = ANIM_DURATION / 2;
|
||||
private static final int ANIM_MID_DELAY = ANIM_DELAY / 2;
|
||||
|
||||
private boolean mRunning; // tracks whether we've started the animator
|
||||
private boolean mCanceled; // trackes whether we've canceled the animator
|
||||
private Animator.AnimatorListener mFutureListener; // mechanism for delaying the end of the test
|
||||
private FutureWaiter mFuture; // Mechanism for waiting for the UI test to complete
|
||||
private Animator.AnimatorListener mListener; // Listener that handles/tests the events
|
||||
|
||||
protected Animator mAnimator; // The animator used in the tests. Must be set in subclass
|
||||
// setup() method prior to calling the superclass setup()
|
||||
|
||||
/**
|
||||
* Cancels the given animator. Used to delay cancelation until some later time (after the
|
||||
* animator has started playing).
|
||||
*/
|
||||
static class Canceler implements Runnable {
|
||||
Animator mAnim;
|
||||
public Canceler(Animator anim) {
|
||||
mAnim = anim;
|
||||
}
|
||||
@Override
|
||||
public void run() {
|
||||
mAnim.cancel();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 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
|
||||
* after an animation ends.
|
||||
*/
|
||||
static class FutureReleaseListener extends AnimatorListenerAdapter {
|
||||
FutureWaiter mFuture;
|
||||
|
||||
public FutureReleaseListener(FutureWaiter future) {
|
||||
mFuture = future;
|
||||
}
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
Handler handler = new Handler();
|
||||
handler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mFuture.release();
|
||||
}
|
||||
}, ANIM_MID_DURATION);
|
||||
}
|
||||
};
|
||||
|
||||
public EventsTest() {
|
||||
super(BasicAnimatorActivity.class);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets up the fields used by each test. Subclasses must override this method to create
|
||||
* the protected mAnimator object used in all tests. Overrides must create that animator
|
||||
* and then call super.setup(), where further properties are set on that animator.
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
// mListener is the main testing mechanism of this file. The asserts of each test
|
||||
// are embedded in the listener callbacks that it implements.
|
||||
mListener = new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
// This should only be called on an animation that has been started and not
|
||||
// yet canceled or ended
|
||||
assertFalse(mCanceled);
|
||||
assertTrue(mRunning);
|
||||
mCanceled = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
// This should only be called on an animation that has been started and not
|
||||
// yet ended
|
||||
assertTrue(mRunning);
|
||||
mRunning = false;
|
||||
super.onAnimationEnd(animation);
|
||||
}
|
||||
};
|
||||
|
||||
mAnimator.addListener(mListener);
|
||||
mAnimator.setDuration(ANIM_DURATION);
|
||||
|
||||
mFuture = new FutureWaiter();
|
||||
|
||||
mRunning = false;
|
||||
mCanceled = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that calling cancel on an unstarted animator does nothing.
|
||||
*/
|
||||
@UiThreadTest
|
||||
@SmallTest
|
||||
public void testCancel() throws Exception {
|
||||
mAnimator.cancel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that calling cancel on a started animator does the right thing.
|
||||
*/
|
||||
@UiThreadTest
|
||||
@SmallTest
|
||||
public void testStartCancel() throws Exception {
|
||||
mRunning = true;
|
||||
mAnimator.start();
|
||||
mAnimator.cancel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as testStartCancel, but with a startDelayed animator
|
||||
*/
|
||||
@UiThreadTest
|
||||
@SmallTest
|
||||
public void testStartDelayedCancel() throws Exception {
|
||||
mAnimator.setStartDelay(ANIM_DELAY);
|
||||
mRunning = true;
|
||||
mAnimator.start();
|
||||
mAnimator.cancel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that canceling an animator that is playing does the right thing.
|
||||
*/
|
||||
@MediumTest
|
||||
public void testPlayingCancel() 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 Canceler(mAnimator), ANIM_MID_DURATION);
|
||||
} catch (junit.framework.AssertionFailedError e) {
|
||||
mFuture.setException(new RuntimeException(e));
|
||||
}
|
||||
}
|
||||
});
|
||||
mFuture.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as testPlayingCancel, but with a startDelayed animator
|
||||
*/
|
||||
@MediumTest
|
||||
public void testPlayingDelayedCancel() 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 Canceler(mAnimator), ANIM_MID_DURATION);
|
||||
} catch (junit.framework.AssertionFailedError e) {
|
||||
mFuture.setException(new RuntimeException(e));
|
||||
}
|
||||
}
|
||||
});
|
||||
mFuture.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that canceling a started animation after it has already been canceled
|
||||
* does nothing.
|
||||
*/
|
||||
@MediumTest
|
||||
public void testStartDoubleCancel() throws Exception {
|
||||
mFutureListener = new FutureReleaseListener(mFuture);
|
||||
getActivity().runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
mRunning = true;
|
||||
mAnimator.start();
|
||||
mAnimator.cancel();
|
||||
mAnimator.cancel();
|
||||
mFuture.release();
|
||||
} catch (junit.framework.AssertionFailedError e) {
|
||||
mFuture.setException(new RuntimeException(e));
|
||||
}
|
||||
}
|
||||
});
|
||||
mFuture.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as testStartDoubleCancel, but with a startDelayed animator
|
||||
*/
|
||||
@MediumTest
|
||||
public void testStartDelayedDoubleCancel() throws Exception {
|
||||
mAnimator.setStartDelay(ANIM_DELAY);
|
||||
mFutureListener = new FutureReleaseListener(mFuture);
|
||||
getActivity().runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
mRunning = true;
|
||||
mAnimator.start();
|
||||
mAnimator.cancel();
|
||||
mAnimator.cancel();
|
||||
mFuture.release();
|
||||
} catch (junit.framework.AssertionFailedError e) {
|
||||
mFuture.setException(new RuntimeException(e));
|
||||
}
|
||||
}
|
||||
});
|
||||
mFuture.get();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
40
core/tests/coretests/src/android/animation/FutureWaiter.java
Normal file
40
core/tests/coretests/src/android/animation/FutureWaiter.java
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package android.animation;
|
||||
|
||||
import com.google.common.util.concurrent.AbstractFuture;
|
||||
|
||||
/**
|
||||
* Simple extension of {@link com.google.common.util.concurrent.AbstractFuture} which exposes a new
|
||||
* release() method which calls the protected
|
||||
* {@link com.google.common.util.concurrent.AbstractFuture#set(Object)} method internally. It
|
||||
* also exposes the protected {@link AbstractFuture#setException(Throwable)} method.
|
||||
*/
|
||||
public class FutureWaiter extends AbstractFuture<Void> {
|
||||
|
||||
/**
|
||||
* Release the Future currently waiting on
|
||||
* {@link com.google.common.util.concurrent.AbstractFuture#get()}.
|
||||
*/
|
||||
public void release() {
|
||||
super.set(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setException(Throwable throwable) {
|
||||
return super.setException(throwable);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package android.animation;
|
||||
|
||||
import android.widget.Button;
|
||||
import com.android.frameworks.coretests.R;
|
||||
|
||||
/**
|
||||
* Listener tests for ObjectAnimator.
|
||||
*/
|
||||
public class ObjectAnimatorEventsTest extends EventsTest {
|
||||
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
final BasicAnimatorActivity activity = getActivity();
|
||||
Button button = (Button) activity.findViewById(R.id.animatingButton);
|
||||
|
||||
mAnimator = ObjectAnimator.ofFloat(button, "translationX", 0, 100);
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package android.animation;
|
||||
|
||||
/**
|
||||
* Listener tests for ValueAnimator.
|
||||
*/
|
||||
public class ValueAnimatorEventsTest extends EventsTest {
|
||||
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
mAnimator = ValueAnimator.ofFloat(0, 1);
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user