EventsTest.java revision 7dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5
1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package android.animation;
17
18import android.os.Handler;
19import android.test.ActivityInstrumentationTestCase2;
20import android.test.UiThreadTest;
21import android.test.suitebuilder.annotation.MediumTest;
22import android.test.suitebuilder.annotation.SmallTest;
23
24/**
25 * Tests for the various lifecycle events of Animators. This abstract class is subclassed by
26 * concrete implementations that provide the actual Animator objects being tested. All of the
27 * testing mechanisms are in this class; the subclasses are only responsible for providing
28 * the mAnimator object.
29 *
30 * This test is more complicated than a typical synchronous test because much of the functionality
31 * must happen on the UI thread. Some tests do this by using the UiThreadTest annotation to
32 * automatically run the whole test on that thread. Other tests must run on the UI thread and also
33 * wait for some later event to occur before ending. These tests use a combination of an
34 * AbstractFuture mechanism and a delayed action to release that Future later.
35 */
36public abstract class EventsTest
37        extends ActivityInstrumentationTestCase2<BasicAnimatorActivity> {
38
39    private static final int ANIM_DURATION = 400;
40    private static final int ANIM_DELAY = 100;
41    private static final int ANIM_MID_DURATION = ANIM_DURATION / 2;
42    private static final int ANIM_MID_DELAY = ANIM_DELAY / 2;
43
44    private boolean mRunning;  // tracks whether we've started the animator
45    private boolean mCanceled; // trackes whether we've canceled the animator
46    private Animator.AnimatorListener mFutureListener; // mechanism for delaying the end of the test
47    private FutureWaiter mFuture; // Mechanism for waiting for the UI test to complete
48    private Animator.AnimatorListener mListener; // Listener that handles/tests the events
49
50    protected Animator mAnimator; // The animator used in the tests. Must be set in subclass
51                                  // setup() method prior to calling the superclass setup()
52
53    /**
54     * Cancels the given animator. Used to delay cancelation until some later time (after the
55     * animator has started playing).
56     */
57    static class Canceler implements Runnable {
58        Animator mAnim;
59        public Canceler(Animator anim) {
60            mAnim = anim;
61        }
62        @Override
63        public void run() {
64            mAnim.cancel();
65        }
66    };
67
68    /**
69     * Releases the given Future object when the listener's end() event is called. Specifically,
70     * it releases it after some further delay, to give the test time to do other things right
71     * after an animation ends.
72     */
73    static class FutureReleaseListener extends AnimatorListenerAdapter {
74        FutureWaiter mFuture;
75
76        public FutureReleaseListener(FutureWaiter future) {
77            mFuture = future;
78        }
79        @Override
80        public void onAnimationEnd(Animator animation) {
81            Handler handler = new Handler();
82            handler.postDelayed(new Runnable() {
83                @Override
84                public void run() {
85                    mFuture.release();
86                }
87            }, ANIM_MID_DURATION);
88        }
89    };
90
91    public EventsTest() {
92        super(BasicAnimatorActivity.class);
93    }
94
95
96    /**
97     * Sets up the fields used by each test. Subclasses must override this method to create
98     * the protected mAnimator object used in all tests. Overrides must create that animator
99     * and then call super.setup(), where further properties are set on that animator.
100     * @throws Exception
101     */
102    @Override
103    public void setUp() throws Exception {
104        super.setUp();
105
106        // mListener is the main testing mechanism of this file. The asserts of each test
107        // are embedded in the listener callbacks that it implements.
108        mListener = new AnimatorListenerAdapter() {
109            @Override
110            public void onAnimationCancel(Animator animation) {
111                // This should only be called on an animation that has been started and not
112                // yet canceled or ended
113                assertFalse(mCanceled);
114                assertTrue(mRunning);
115                mCanceled = true;
116            }
117
118            @Override
119            public void onAnimationEnd(Animator animation) {
120                // This should only be called on an animation that has been started and not
121                // yet ended
122                assertTrue(mRunning);
123                mRunning = false;
124                super.onAnimationEnd(animation);
125            }
126        };
127
128        mAnimator.addListener(mListener);
129        mAnimator.setDuration(ANIM_DURATION);
130
131        mFuture = new FutureWaiter();
132
133        mRunning = false;
134        mCanceled = false;
135    }
136
137    /**
138     * Verify that calling cancel on an unstarted animator does nothing.
139     */
140    @UiThreadTest
141    @SmallTest
142    public void testCancel() throws Exception {
143        mAnimator.cancel();
144    }
145
146    /**
147     * Verify that calling cancel on a started animator does the right thing.
148     */
149    @UiThreadTest
150    @SmallTest
151    public void testStartCancel() throws Exception {
152        mRunning = true;
153        mAnimator.start();
154        mAnimator.cancel();
155    }
156
157    /**
158     * Same as testStartCancel, but with a startDelayed animator
159     */
160    @UiThreadTest
161    @SmallTest
162    public void testStartDelayedCancel() throws Exception {
163        mAnimator.setStartDelay(ANIM_DELAY);
164        mRunning = true;
165        mAnimator.start();
166        mAnimator.cancel();
167    }
168
169    /**
170     * Verify that canceling an animator that is playing does the right thing.
171     */
172    @MediumTest
173    public void testPlayingCancel() throws Exception {
174        mFutureListener = new FutureReleaseListener(mFuture);
175        getActivity().runOnUiThread(new Runnable() {
176            @Override
177            public void run() {
178                try {
179                    Handler handler = new Handler();
180                    mAnimator.addListener(mFutureListener);
181                    mRunning = true;
182                    mAnimator.start();
183                    handler.postDelayed(new Canceler(mAnimator), ANIM_MID_DURATION);
184                } catch (junit.framework.AssertionFailedError e) {
185                    mFuture.setException(new RuntimeException(e));
186                }
187            }
188        });
189        mFuture.get();
190    }
191
192    /**
193     * Same as testPlayingCancel, but with a startDelayed animator
194     */
195    @MediumTest
196    public void testPlayingDelayedCancel() throws Exception {
197        mAnimator.setStartDelay(ANIM_DELAY);
198        mFutureListener = new FutureReleaseListener(mFuture);
199        getActivity().runOnUiThread(new Runnable() {
200            @Override
201            public void run() {
202                try {
203                    Handler handler = new Handler();
204                    mAnimator.addListener(mFutureListener);
205                    mRunning = true;
206                    mAnimator.start();
207                    handler.postDelayed(new Canceler(mAnimator), ANIM_MID_DURATION);
208                } catch (junit.framework.AssertionFailedError e) {
209                    mFuture.setException(new RuntimeException(e));
210                }
211            }
212        });
213        mFuture.get();
214    }
215
216    /**
217     * Verifies that canceling a started animation after it has already been canceled
218     * does nothing.
219     */
220    @MediumTest
221    public void testStartDoubleCancel() throws Exception {
222        mFutureListener = new FutureReleaseListener(mFuture);
223        getActivity().runOnUiThread(new Runnable() {
224            @Override
225            public void run() {
226                try {
227                    mRunning = true;
228                    mAnimator.start();
229                    mAnimator.cancel();
230                    mAnimator.cancel();
231                    mFuture.release();
232                } catch (junit.framework.AssertionFailedError e) {
233                    mFuture.setException(new RuntimeException(e));
234                }
235            }
236        });
237        mFuture.get();
238    }
239
240    /**
241     * Same as testStartDoubleCancel, but with a startDelayed animator
242     */
243    @MediumTest
244    public void testStartDelayedDoubleCancel() throws Exception {
245        mAnimator.setStartDelay(ANIM_DELAY);
246        mFutureListener = new FutureReleaseListener(mFuture);
247        getActivity().runOnUiThread(new Runnable() {
248            @Override
249            public void run() {
250                try {
251                    mRunning = true;
252                    mAnimator.start();
253                    mAnimator.cancel();
254                    mAnimator.cancel();
255                    mFuture.release();
256                } catch (junit.framework.AssertionFailedError e) {
257                    mFuture.setException(new RuntimeException(e));
258                }
259            }
260        });
261        mFuture.get();
262    }
263
264
265}
266