Home | History | Annotate | Download | only in animation
      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  */
     16 package android.animation;
     17 
     18 import android.os.Handler;
     19 import android.test.ActivityInstrumentationTestCase2;
     20 import android.test.UiThreadTest;
     21 import android.test.suitebuilder.annotation.MediumTest;
     22 import android.test.suitebuilder.annotation.SmallTest;
     23 
     24 import java.util.concurrent.TimeUnit;
     25 import java.util.concurrent.TimeoutException;
     26 
     27 /**
     28  * Tests for the various lifecycle events of Animators. This abstract class is subclassed by
     29  * concrete implementations that provide the actual Animator objects being tested. All of the
     30  * testing mechanisms are in this class; the subclasses are only responsible for providing
     31  * the mAnimator object.
     32  *
     33  * This test is more complicated than a typical synchronous test because much of the functionality
     34  * must happen on the UI thread. Some tests do this by using the UiThreadTest annotation to
     35  * automatically run the whole test on that thread. Other tests must run on the UI thread and also
     36  * wait for some later event to occur before ending. These tests use a combination of an
     37  * AbstractFuture mechanism and a delayed action to release that Future later.
     38  */
     39 public abstract class EventsTest
     40         extends ActivityInstrumentationTestCase2<BasicAnimatorActivity> {
     41 
     42     protected static final int ANIM_DURATION = 400;
     43     protected static final int ANIM_DELAY = 100;
     44     protected static final int ANIM_MID_DURATION = ANIM_DURATION / 2;
     45     protected static final int ANIM_MID_DELAY = ANIM_DELAY / 2;
     46     protected static final int ANIM_PAUSE_DURATION = ANIM_DELAY;
     47     protected static final int ANIM_PAUSE_DELAY = ANIM_DELAY / 2;
     48     protected static final int FUTURE_RELEASE_DELAY = 50;
     49     protected static final int ANIM_FULL_DURATION_SLOP = 100;
     50 
     51     private boolean mStarted;  // tracks whether we've received the onAnimationStart() callback
     52     protected boolean mRunning;  // tracks whether we've started the animator
     53     private boolean mCanceled; // tracks whether we've canceled the animator
     54     protected Animator.AnimatorListener mFutureListener; // mechanism for delaying end of the test
     55     protected FutureWaiter mFuture; // Mechanism for waiting for the UI test to complete
     56     private Animator.AnimatorListener mListener; // Listener that handles/tests the events
     57 
     58     protected Animator mAnimator; // The animator used in the tests. Must be set in subclass
     59                                   // setup() method prior to calling the superclass setup()
     60 
     61     /**
     62      * Cancels the given animator. Used to delay cancellation until some later time (after the
     63      * animator has started playing).
     64      */
     65     protected static class Canceler implements Runnable {
     66         Animator mAnim;
     67         FutureWaiter mFuture;
     68         public Canceler(Animator anim, FutureWaiter future) {
     69             mAnim = anim;
     70             mFuture = future;
     71         }
     72         @Override
     73         public void run() {
     74             try {
     75                 mAnim.cancel();
     76             } catch (junit.framework.AssertionFailedError e) {
     77                 mFuture.setException(new RuntimeException(e));
     78             }
     79         }
     80     };
     81 
     82     /**
     83      * Timeout length, based on when the animation should reasonably be complete.
     84      */
     85     protected long getTimeout() {
     86         return ANIM_DURATION + ANIM_DELAY + FUTURE_RELEASE_DELAY;
     87     }
     88 
     89     /**
     90      * Ends the given animator. Used to delay ending until some later time (after the
     91      * animator has started playing).
     92      */
     93     static class Ender implements Runnable {
     94         Animator mAnim;
     95         FutureWaiter mFuture;
     96         public Ender(Animator anim, FutureWaiter future) {
     97             mAnim = anim;
     98             mFuture = future;
     99         }
    100         @Override
    101         public void run() {
    102             try {
    103                 mAnim.end();
    104             } catch (junit.framework.AssertionFailedError e) {
    105                 mFuture.setException(new RuntimeException(e));
    106             }
    107         }
    108     };
    109 
    110     /**
    111      * Pauses the given animator. Used to delay pausing until some later time (after the
    112      * animator has started playing).
    113      */
    114     static class Pauser implements Runnable {
    115         Animator mAnim;
    116         FutureWaiter mFuture;
    117         public Pauser(Animator anim, FutureWaiter future) {
    118             mAnim = anim;
    119             mFuture = future;
    120         }
    121         @Override
    122         public void run() {
    123             try {
    124                 mAnim.pause();
    125             } catch (junit.framework.AssertionFailedError e) {
    126                 mFuture.setException(new RuntimeException(e));
    127             }
    128         }
    129     };
    130 
    131     /**
    132      * Resumes the given animator. Used to delay resuming until some later time (after the
    133      * animator has paused for some duration).
    134      */
    135     static class Resumer implements Runnable {
    136         Animator mAnim;
    137         FutureWaiter mFuture;
    138         public Resumer(Animator anim, FutureWaiter future) {
    139             mAnim = anim;
    140             mFuture = future;
    141         }
    142         @Override
    143         public void run() {
    144             try {
    145                 mAnim.resume();
    146             } catch (junit.framework.AssertionFailedError e) {
    147                 mFuture.setException(new RuntimeException(e));
    148             }
    149         }
    150     };
    151 
    152     /**
    153      * Releases the given Future object when the listener's end() event is called. Specifically,
    154      * it releases it after some further delay, to give the test time to do other things right
    155      * after an animation ends.
    156      */
    157     protected static class FutureReleaseListener extends AnimatorListenerAdapter {
    158         FutureWaiter mFuture;
    159 
    160         public FutureReleaseListener(FutureWaiter future) {
    161             mFuture = future;
    162         }
    163 
    164         /**
    165          * Variant constructor that auto-releases the FutureWaiter after the specified timeout.
    166          * @param future
    167          * @param timeout
    168          */
    169         public FutureReleaseListener(FutureWaiter future, long timeout) {
    170             mFuture = future;
    171             Handler handler = new Handler();
    172             handler.postDelayed(new Runnable() {
    173                 @Override
    174                 public void run() {
    175                     mFuture.release();
    176                 }
    177             }, timeout);
    178         }
    179 
    180         @Override
    181         public void onAnimationEnd(Animator animation) {
    182             Handler handler = new Handler();
    183             handler.postDelayed(new Runnable() {
    184                 @Override
    185                 public void run() {
    186                     mFuture.release();
    187                 }
    188             }, FUTURE_RELEASE_DELAY);
    189         }
    190     };
    191 
    192     public EventsTest() {
    193         super(BasicAnimatorActivity.class);
    194     }
    195 
    196     /**
    197      * Sets up the fields used by each test. Subclasses must override this method to create
    198      * the protected mAnimator object used in all tests. Overrides must create that animator
    199      * and then call super.setup(), where further properties are set on that animator.
    200      * @throws Exception
    201      */
    202     @Override
    203     public void setUp() throws Exception {
    204         super.setUp();
    205 
    206         // mListener is the main testing mechanism of this file. The asserts of each test
    207         // are embedded in the listener callbacks that it implements.
    208         mListener = new AnimatorListenerAdapter() {
    209             @Override
    210             public void onAnimationStart(Animator animation) {
    211                 // This should only be called on an animation that has not yet been started
    212                 assertFalse(mStarted);
    213                 assertTrue(mRunning);
    214                 mStarted = true;
    215             }
    216 
    217             @Override
    218             public void onAnimationCancel(Animator animation) {
    219                 // This should only be called on an animation that has been started and not
    220                 // yet canceled or ended
    221                 assertFalse(mCanceled);
    222                 assertTrue(mRunning || mStarted);
    223                 mCanceled = true;
    224             }
    225 
    226             @Override
    227             public void onAnimationEnd(Animator animation) {
    228                 // This should only be called on an animation that has been started and not
    229                 // yet ended
    230                 assertTrue(mRunning || mStarted);
    231                 mRunning = false;
    232                 mStarted = false;
    233                 super.onAnimationEnd(animation);
    234             }
    235         };
    236 
    237         mAnimator.addListener(mListener);
    238         mAnimator.setDuration(ANIM_DURATION);
    239 
    240         mFuture = new FutureWaiter();
    241 
    242         mRunning = false;
    243         mCanceled = false;
    244         mStarted = false;
    245     }
    246 
    247     /**
    248      * Verify that calling cancel on an unstarted animator does nothing.
    249      */
    250     @UiThreadTest
    251     @SmallTest
    252     public void testCancel() throws Exception {
    253         mAnimator.cancel();
    254     }
    255 
    256     /**
    257      * Verify that calling end on an unstarted animator starts/ends an animator.
    258      */
    259     @UiThreadTest
    260     @SmallTest
    261     public void testEnd() throws Exception {
    262         mRunning = true; // end() implicitly starts an unstarted animator
    263         mAnimator.end();
    264     }
    265 
    266     /**
    267      * Verify that calling cancel on a started animator does the right thing.
    268      */
    269     @UiThreadTest
    270     @SmallTest
    271     public void testStartCancel() throws Exception {
    272         mFutureListener = new FutureReleaseListener(mFuture);
    273         getActivity().runOnUiThread(new Runnable() {
    274             @Override
    275             public void run() {
    276                 try {
    277                     mRunning = true;
    278                     mAnimator.start();
    279                     mAnimator.cancel();
    280                     mFuture.release();
    281                 } catch (junit.framework.AssertionFailedError e) {
    282                     mFuture.setException(new RuntimeException(e));
    283                 }
    284             }
    285         });
    286         mFuture.get(getTimeout(), TimeUnit.MILLISECONDS);
    287     }
    288 
    289     /**
    290      * Verify that calling end on a started animator does the right thing.
    291      */
    292     @UiThreadTest
    293     @SmallTest
    294     public void testStartEnd() throws Exception {
    295         mFutureListener = new FutureReleaseListener(mFuture);
    296         getActivity().runOnUiThread(new Runnable() {
    297             @Override
    298             public void run() {
    299                 try {
    300                     mRunning = true;
    301                     mAnimator.start();
    302                     mAnimator.end();
    303                     mFuture.release();
    304                 } catch (junit.framework.AssertionFailedError e) {
    305                     mFuture.setException(new RuntimeException(e));
    306                 }
    307             }
    308         });
    309         mFuture.get(getTimeout(), TimeUnit.MILLISECONDS);
    310     }
    311 
    312     /**
    313      * Same as testStartCancel, but with a startDelayed animator
    314      */
    315     @SmallTest
    316     public void testStartDelayedCancel() throws Exception {
    317         mFutureListener = new FutureReleaseListener(mFuture);
    318         mAnimator.setStartDelay(ANIM_DELAY);
    319         getActivity().runOnUiThread(new Runnable() {
    320             @Override
    321             public void run() {
    322                 try {
    323                     mRunning = true;
    324                     mAnimator.start();
    325                     mAnimator.cancel();
    326                     mFuture.release();
    327                 } catch (junit.framework.AssertionFailedError e) {
    328                     mFuture.setException(new RuntimeException(e));
    329                 }
    330             }
    331         });
    332         mFuture.get(getTimeout(), TimeUnit.MILLISECONDS);
    333     }
    334 
    335     /**
    336      * Same as testStartEnd, but with a startDelayed animator
    337      */
    338     @SmallTest
    339     public void testStartDelayedEnd() throws Exception {
    340         mFutureListener = new FutureReleaseListener(mFuture);
    341         mAnimator.setStartDelay(ANIM_DELAY);
    342         getActivity().runOnUiThread(new Runnable() {
    343             @Override
    344             public void run() {
    345                 try {
    346                     mRunning = true;
    347                     mAnimator.start();
    348                     mAnimator.end();
    349                     mFuture.release();
    350                 } catch (junit.framework.AssertionFailedError e) {
    351                     mFuture.setException(new RuntimeException(e));
    352                 }
    353             }
    354         });
    355         mFuture.get(getTimeout(), TimeUnit.MILLISECONDS);
    356     }
    357 
    358     /**
    359      * Verify that canceling an animator that is playing does the right thing.
    360      */
    361     @MediumTest
    362     public void testPlayingCancel() throws Exception {
    363         mFutureListener = new FutureReleaseListener(mFuture);
    364         getActivity().runOnUiThread(new Runnable() {
    365             @Override
    366             public void run() {
    367                 try {
    368                     Handler handler = new Handler();
    369                     mAnimator.addListener(mFutureListener);
    370                     mRunning = true;
    371                     mAnimator.start();
    372                     handler.postDelayed(new Canceler(mAnimator, mFuture), ANIM_MID_DURATION);
    373                 } catch (junit.framework.AssertionFailedError e) {
    374                     mFuture.setException(new RuntimeException(e));
    375                 }
    376             }
    377         });
    378         mFuture.get(getTimeout(), TimeUnit.MILLISECONDS);
    379     }
    380 
    381     /**
    382      * Verify that ending an animator that is playing does the right thing.
    383      */
    384     @MediumTest
    385     public void testPlayingEnd() throws Exception {
    386         mFutureListener = new FutureReleaseListener(mFuture);
    387         getActivity().runOnUiThread(new Runnable() {
    388             @Override
    389             public void run() {
    390                 try {
    391                     Handler handler = new Handler();
    392                     mAnimator.addListener(mFutureListener);
    393                     mRunning = true;
    394                     mAnimator.start();
    395                     handler.postDelayed(new Ender(mAnimator, mFuture), ANIM_MID_DURATION);
    396                 } catch (junit.framework.AssertionFailedError e) {
    397                     mFuture.setException(new RuntimeException(e));
    398                 }
    399             }
    400         });
    401         mFuture.get(getTimeout(), TimeUnit.MILLISECONDS);
    402     }
    403 
    404     /**
    405      * Same as testPlayingCancel, but with a startDelayed animator
    406      */
    407     @MediumTest
    408     public void testPlayingDelayedCancel() throws Exception {
    409         mAnimator.setStartDelay(ANIM_DELAY);
    410         mFutureListener = new FutureReleaseListener(mFuture);
    411         getActivity().runOnUiThread(new Runnable() {
    412             @Override
    413             public void run() {
    414                 try {
    415                     Handler handler = new Handler();
    416                     mAnimator.addListener(mFutureListener);
    417                     mRunning = true;
    418                     mAnimator.start();
    419                     handler.postDelayed(new Canceler(mAnimator, mFuture), ANIM_MID_DURATION);
    420                 } catch (junit.framework.AssertionFailedError e) {
    421                     mFuture.setException(new RuntimeException(e));
    422                 }
    423             }
    424         });
    425         mFuture.get(getTimeout(),  TimeUnit.MILLISECONDS);
    426     }
    427 
    428     /**
    429      * Same as testPlayingEnd, but with a startDelayed animator
    430      */
    431     @MediumTest
    432     public void testPlayingDelayedEnd() throws Exception {
    433         mAnimator.setStartDelay(ANIM_DELAY);
    434         mFutureListener = new FutureReleaseListener(mFuture);
    435         getActivity().runOnUiThread(new Runnable() {
    436             @Override
    437             public void run() {
    438                 try {
    439                     Handler handler = new Handler();
    440                     mAnimator.addListener(mFutureListener);
    441                     mRunning = true;
    442                     mAnimator.start();
    443                     handler.postDelayed(new Ender(mAnimator, mFuture), ANIM_MID_DURATION);
    444                 } catch (junit.framework.AssertionFailedError e) {
    445                     mFuture.setException(new RuntimeException(e));
    446                 }
    447             }
    448         });
    449         mFuture.get(getTimeout(),  TimeUnit.MILLISECONDS);
    450     }
    451 
    452     /**
    453      * Same as testPlayingDelayedCancel, but cancel during the startDelay period
    454      */
    455     @MediumTest
    456     public void testPlayingDelayedCancelMidDelay() throws Exception {
    457         mAnimator.setStartDelay(ANIM_DELAY);
    458         getActivity().runOnUiThread(new Runnable() {
    459             @Override
    460             public void run() {
    461                 try {
    462                     // Set the listener to automatically timeout after an uncanceled animation
    463                     // would have finished. This tests to make sure that we're not calling
    464                     // the listeners with cancel/end callbacks since they won't be called
    465                     // with the start event.
    466                     mFutureListener = new FutureReleaseListener(mFuture, getTimeout());
    467                     Handler handler = new Handler();
    468                     mRunning = true;
    469                     mAnimator.start();
    470                     handler.postDelayed(new Canceler(mAnimator, mFuture), ANIM_MID_DELAY);
    471                 } catch (junit.framework.AssertionFailedError e) {
    472                     mFuture.setException(new RuntimeException(e));
    473                 }
    474             }
    475         });
    476         mFuture.get(getTimeout() + 100,  TimeUnit.MILLISECONDS);
    477     }
    478 
    479     /**
    480      * Same as testPlayingDelayedEnd, but end during the startDelay period
    481      */
    482     @MediumTest
    483     public void testPlayingDelayedEndMidDelay() throws Exception {
    484         mAnimator.setStartDelay(ANIM_DELAY);
    485         getActivity().runOnUiThread(new Runnable() {
    486             @Override
    487             public void run() {
    488                 try {
    489                     // Set the listener to automatically timeout after an uncanceled animation
    490                     // would have finished. This tests to make sure that we're not calling
    491                     // the listeners with cancel/end callbacks since they won't be called
    492                     // with the start event.
    493                     mFutureListener = new FutureReleaseListener(mFuture, getTimeout());
    494                     Handler handler = new Handler();
    495                     mRunning = true;
    496                     mAnimator.start();
    497                     handler.postDelayed(new Ender(mAnimator, mFuture), ANIM_MID_DELAY);
    498                 } catch (junit.framework.AssertionFailedError e) {
    499                     mFuture.setException(new RuntimeException(e));
    500                 }
    501             }
    502         });
    503         mFuture.get(getTimeout() + 100,  TimeUnit.MILLISECONDS);
    504     }
    505 
    506     /**
    507      * Verifies that canceling a started animation after it has already been canceled
    508      * does nothing.
    509      */
    510     @MediumTest
    511     public void testStartDoubleCancel() throws Exception {
    512         mFutureListener = new FutureReleaseListener(mFuture);
    513         getActivity().runOnUiThread(new Runnable() {
    514             @Override
    515             public void run() {
    516                 try {
    517                     mRunning = true;
    518                     mAnimator.start();
    519                     mAnimator.cancel();
    520                     mAnimator.cancel();
    521                     mFuture.release();
    522                 } catch (junit.framework.AssertionFailedError e) {
    523                     mFuture.setException(new RuntimeException(e));
    524                 }
    525             }
    526         });
    527         mFuture.get(getTimeout(),  TimeUnit.MILLISECONDS);
    528     }
    529 
    530     /**
    531      * Verifies that ending a started animation after it has already been ended
    532      * does nothing.
    533      */
    534     @MediumTest
    535     public void testStartDoubleEnd() throws Exception {
    536         mFutureListener = new FutureReleaseListener(mFuture);
    537         getActivity().runOnUiThread(new Runnable() {
    538             @Override
    539             public void run() {
    540                 try {
    541                     mRunning = true;
    542                     mAnimator.start();
    543                     mAnimator.end();
    544                     mRunning = true; // end() implicitly starts an unstarted animator
    545                     mAnimator.end();
    546                     mFuture.release();
    547                 } catch (junit.framework.AssertionFailedError e) {
    548                     mFuture.setException(new RuntimeException(e));
    549                 }
    550             }
    551         });
    552         mFuture.get(getTimeout(),  TimeUnit.MILLISECONDS);
    553     }
    554 
    555     /**
    556      * Same as testStartDoubleCancel, but with a startDelayed animator
    557      */
    558     @MediumTest
    559     public void testStartDelayedDoubleCancel() throws Exception {
    560         mAnimator.setStartDelay(ANIM_DELAY);
    561         mFutureListener = new FutureReleaseListener(mFuture);
    562         getActivity().runOnUiThread(new Runnable() {
    563             @Override
    564             public void run() {
    565                 try {
    566                     mRunning = true;
    567                     mAnimator.start();
    568                     mAnimator.cancel();
    569                     mAnimator.cancel();
    570                     mFuture.release();
    571                 } catch (junit.framework.AssertionFailedError e) {
    572                     mFuture.setException(new RuntimeException(e));
    573                 }
    574             }
    575         });
    576         mFuture.get(getTimeout(),  TimeUnit.MILLISECONDS);
    577      }
    578 
    579     /**
    580      * Same as testStartDoubleEnd, but with a startDelayed animator
    581      */
    582     @MediumTest
    583     public void testStartDelayedDoubleEnd() throws Exception {
    584         mAnimator.setStartDelay(ANIM_DELAY);
    585         mFutureListener = new FutureReleaseListener(mFuture);
    586         getActivity().runOnUiThread(new Runnable() {
    587             @Override
    588             public void run() {
    589                 try {
    590                     mRunning = true;
    591                     mAnimator.start();
    592                     mAnimator.end();
    593                     mRunning = true; // end() implicitly starts an unstarted animator
    594                     mAnimator.end();
    595                     mFuture.release();
    596                 } catch (junit.framework.AssertionFailedError e) {
    597                     mFuture.setException(new RuntimeException(e));
    598                 }
    599             }
    600         });
    601         mFuture.get(getTimeout(),  TimeUnit.MILLISECONDS);
    602      }
    603 
    604     /**
    605      * Verify that pausing and resuming an animator ends within
    606      * the appropriate timeout duration.
    607      */
    608     @MediumTest
    609     public void testPauseResume() throws Exception {
    610         mFutureListener = new FutureReleaseListener(mFuture);
    611         getActivity().runOnUiThread(new Runnable() {
    612             @Override
    613             public void run() {
    614                 try {
    615                     Handler handler = new Handler();
    616                     mAnimator.addListener(mFutureListener);
    617                     mRunning = true;
    618                     mAnimator.start();
    619                     handler.postDelayed(new Pauser(mAnimator, mFuture), ANIM_PAUSE_DELAY);
    620                     handler.postDelayed(new Resumer(mAnimator, mFuture),
    621                             ANIM_PAUSE_DELAY + ANIM_PAUSE_DURATION);
    622                 } catch (junit.framework.AssertionFailedError e) {
    623                     mFuture.setException(new RuntimeException(e));
    624                 }
    625             }
    626         });
    627         mFuture.get(getTimeout() + ANIM_PAUSE_DURATION, TimeUnit.MILLISECONDS);
    628     }
    629 
    630     /**
    631      * Verify that pausing and resuming a startDelayed animator ends within
    632      * the appropriate timeout duration.
    633      */
    634     @MediumTest
    635     public void testPauseResumeDelayed() throws Exception {
    636         mAnimator.setStartDelay(ANIM_DELAY);
    637         mFutureListener = new FutureReleaseListener(mFuture);
    638         getActivity().runOnUiThread(new Runnable() {
    639             @Override
    640             public void run() {
    641                 try {
    642                     Handler handler = new Handler();
    643                     mAnimator.addListener(mFutureListener);
    644                     mRunning = true;
    645                     mAnimator.start();
    646                     handler.postDelayed(new Pauser(mAnimator, mFuture), ANIM_PAUSE_DELAY);
    647                     handler.postDelayed(new Resumer(mAnimator, mFuture),
    648                             ANIM_PAUSE_DELAY + ANIM_PAUSE_DURATION);
    649                 } catch (junit.framework.AssertionFailedError e) {
    650                     mFuture.setException(new RuntimeException(e));
    651                 }
    652             }
    653         });
    654         mFuture.get(getTimeout() + ANIM_PAUSE_DURATION + ANIM_FULL_DURATION_SLOP,
    655                 TimeUnit.MILLISECONDS);
    656     }
    657 
    658     /**
    659      * Verify that pausing an animator without resuming it causes a timeout.
    660      */
    661     @MediumTest
    662     public void testPauseTimeout() throws Exception {
    663         mFutureListener = new FutureReleaseListener(mFuture);
    664         getActivity().runOnUiThread(new Runnable() {
    665             @Override
    666             public void run() {
    667                 try {
    668                     Handler handler = new Handler();
    669                     mAnimator.addListener(mFutureListener);
    670                     mRunning = true;
    671                     mAnimator.start();
    672                     handler.postDelayed(new Pauser(mAnimator, mFuture), ANIM_PAUSE_DELAY);
    673                 } catch (junit.framework.AssertionFailedError e) {
    674                     mFuture.setException(new RuntimeException(e));
    675                 }
    676             }
    677         });
    678         try {
    679             mFuture.get(getTimeout() + ANIM_PAUSE_DURATION + ANIM_FULL_DURATION_SLOP,
    680                     TimeUnit.MILLISECONDS);
    681         } catch (TimeoutException e) {
    682             // Expected behavior, swallow the exception
    683         }
    684     }
    685 
    686     /**
    687      * Verify that pausing a startDelayed animator without resuming it causes a timeout.
    688      */
    689     @MediumTest
    690     public void testPauseTimeoutDelayed() throws Exception {
    691         mAnimator.setStartDelay(ANIM_DELAY);
    692         mFutureListener = new FutureReleaseListener(mFuture);
    693         getActivity().runOnUiThread(new Runnable() {
    694             @Override
    695             public void run() {
    696                 try {
    697                     Handler handler = new Handler();
    698                     mAnimator.addListener(mFutureListener);
    699                     mRunning = true;
    700                     mAnimator.start();
    701                     handler.postDelayed(new Pauser(mAnimator, mFuture), ANIM_PAUSE_DELAY);
    702                 } catch (junit.framework.AssertionFailedError e) {
    703                     mFuture.setException(new RuntimeException(e));
    704                 }
    705             }
    706         });
    707         try {
    708             mFuture.get(getTimeout() + ANIM_PAUSE_DURATION + ANIM_FULL_DURATION_SLOP,
    709                     TimeUnit.MILLISECONDS);
    710         } catch (TimeoutException e) {
    711             // Expected behavior, swallow the exception
    712         }
    713     }
    714 }
    715