Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2012 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 
     17 package android.view.cts;
     18 
     19 import android.test.AndroidTestCase;
     20 import android.view.Choreographer;
     21 
     22 public class ChoreographerTest extends AndroidTestCase {
     23     private static final long NOMINAL_VSYNC_PERIOD = 16;
     24     private static final long DELAY_PERIOD = NOMINAL_VSYNC_PERIOD * 5;
     25     private static final long NANOS_PER_MS = 1000000;
     26     private static final Object TOKEN = new Object();
     27 
     28     private Choreographer mChoreographer = Choreographer.getInstance();
     29 
     30     public void testFrameDelay() {
     31         assertTrue(Choreographer.getFrameDelay() > 0);
     32 
     33         long oldFrameDelay = Choreographer.getFrameDelay();
     34         long newFrameDelay = oldFrameDelay * 2;
     35         Choreographer.setFrameDelay(newFrameDelay);
     36         assertEquals(newFrameDelay, Choreographer.getFrameDelay());
     37 
     38         Choreographer.setFrameDelay(oldFrameDelay);
     39     }
     40 
     41     public void testPostCallbackWithoutDelayEventuallyRunsCallbacks() {
     42         MockRunnable addedCallback1 = new MockRunnable();
     43         MockRunnable addedCallback2 = new MockRunnable();
     44         MockRunnable removedCallback = new MockRunnable();
     45         try {
     46             // Add and remove a few callbacks.
     47             mChoreographer.postCallback(
     48                     Choreographer.CALLBACK_ANIMATION, addedCallback1, null);
     49             mChoreographer.postCallback(
     50                     Choreographer.CALLBACK_ANIMATION, addedCallback2, null);
     51             mChoreographer.postCallback(
     52                     Choreographer.CALLBACK_ANIMATION, removedCallback, null);
     53             mChoreographer.removeCallbacks(
     54                     Choreographer.CALLBACK_ANIMATION, removedCallback, null);
     55 
     56             // Sleep for a couple of frames.
     57             sleep(NOMINAL_VSYNC_PERIOD * 3);
     58 
     59             // We expect the remaining callbacks to have been invoked once.
     60             assertEquals(1, addedCallback1.invocationCount);
     61             assertEquals(1, addedCallback2.invocationCount);
     62             assertEquals(0, removedCallback.invocationCount);
     63 
     64             // If we post a callback again, then it should be invoked again.
     65             mChoreographer.postCallback(
     66                     Choreographer.CALLBACK_ANIMATION, addedCallback1, null);
     67             sleep(NOMINAL_VSYNC_PERIOD * 3);
     68 
     69             assertEquals(2, addedCallback1.invocationCount);
     70             assertEquals(1, addedCallback2.invocationCount);
     71             assertEquals(0, removedCallback.invocationCount);
     72 
     73             // If the token matches, the the callback should be removed.
     74             mChoreographer.postCallback(
     75                     Choreographer.CALLBACK_ANIMATION, addedCallback1, null);
     76             mChoreographer.postCallback(
     77                     Choreographer.CALLBACK_ANIMATION, removedCallback, TOKEN);
     78             mChoreographer.removeCallbacks(
     79                     Choreographer.CALLBACK_ANIMATION, null, TOKEN);
     80             sleep(NOMINAL_VSYNC_PERIOD * 3);
     81             assertEquals(3, addedCallback1.invocationCount);
     82             assertEquals(0, removedCallback.invocationCount);
     83 
     84             // If the action and token matches, then the callback should be removed.
     85             // If only the token matches, then the callback should not be removed.
     86             mChoreographer.postCallback(
     87                     Choreographer.CALLBACK_ANIMATION, addedCallback1, TOKEN);
     88             mChoreographer.postCallback(
     89                     Choreographer.CALLBACK_ANIMATION, removedCallback, TOKEN);
     90             mChoreographer.removeCallbacks(
     91                     Choreographer.CALLBACK_ANIMATION, removedCallback, TOKEN);
     92             sleep(NOMINAL_VSYNC_PERIOD * 3);
     93             assertEquals(4, addedCallback1.invocationCount);
     94             assertEquals(0, removedCallback.invocationCount);
     95         } finally {
     96             mChoreographer.removeCallbacks(
     97                     Choreographer.CALLBACK_ANIMATION, addedCallback1, null);
     98             mChoreographer.removeCallbacks(
     99                     Choreographer.CALLBACK_ANIMATION, addedCallback2, null);
    100             mChoreographer.removeCallbacks(
    101                     Choreographer.CALLBACK_ANIMATION, removedCallback, null);
    102         }
    103     }
    104 
    105     public void testPostCallbackWithDelayEventuallyRunsCallbacksAfterDelay() {
    106         MockRunnable addedCallback = new MockRunnable();
    107         MockRunnable removedCallback = new MockRunnable();
    108         try {
    109             // Add and remove a few callbacks.
    110             mChoreographer.postCallbackDelayed(
    111                     Choreographer.CALLBACK_ANIMATION, addedCallback, null, DELAY_PERIOD);
    112             mChoreographer.postCallbackDelayed(
    113                     Choreographer.CALLBACK_ANIMATION, removedCallback, null, DELAY_PERIOD);
    114             mChoreographer.removeCallbacks(
    115                     Choreographer.CALLBACK_ANIMATION, removedCallback, null);
    116 
    117             // Sleep for a couple of frames.
    118             sleep(NOMINAL_VSYNC_PERIOD * 3);
    119 
    120             // The callbacks should not have been invoked yet because of the delay.
    121             assertEquals(0, addedCallback.invocationCount);
    122             assertEquals(0, removedCallback.invocationCount);
    123 
    124             // Sleep for the rest of the delay time.
    125             sleep(DELAY_PERIOD);
    126 
    127             // We expect the remaining callbacks to have been invoked.
    128             assertEquals(1, addedCallback.invocationCount);
    129             assertEquals(0, removedCallback.invocationCount);
    130 
    131             // If the token matches, the the callback should be removed.
    132             mChoreographer.postCallbackDelayed(
    133                     Choreographer.CALLBACK_ANIMATION, addedCallback, null, DELAY_PERIOD);
    134             mChoreographer.postCallbackDelayed(
    135                     Choreographer.CALLBACK_ANIMATION, removedCallback, TOKEN, DELAY_PERIOD);
    136             mChoreographer.removeCallbacks(
    137                     Choreographer.CALLBACK_ANIMATION, null, TOKEN);
    138             sleep(NOMINAL_VSYNC_PERIOD * 3 + DELAY_PERIOD);
    139             assertEquals(2, addedCallback.invocationCount);
    140             assertEquals(0, removedCallback.invocationCount);
    141 
    142             // If the action and token matches, then the callback should be removed.
    143             // If only the token matches, then the callback should not be removed.
    144             mChoreographer.postCallbackDelayed(
    145                     Choreographer.CALLBACK_ANIMATION, addedCallback, TOKEN, DELAY_PERIOD);
    146             mChoreographer.postCallbackDelayed(
    147                     Choreographer.CALLBACK_ANIMATION, removedCallback, TOKEN, DELAY_PERIOD);
    148             mChoreographer.removeCallbacks(
    149                     Choreographer.CALLBACK_ANIMATION, removedCallback, TOKEN);
    150             sleep(NOMINAL_VSYNC_PERIOD * 3 + DELAY_PERIOD);
    151             assertEquals(3, addedCallback.invocationCount);
    152             assertEquals(0, removedCallback.invocationCount);
    153         } finally {
    154             mChoreographer.removeCallbacks(
    155                     Choreographer.CALLBACK_ANIMATION, addedCallback, null);
    156             mChoreographer.removeCallbacks(
    157                     Choreographer.CALLBACK_ANIMATION, removedCallback, null);
    158         }
    159     }
    160 
    161     public void testPostCallbackThrowsIfRunnableIsNull() {
    162         try {
    163             mChoreographer.postCallback(
    164                     Choreographer.CALLBACK_ANIMATION, null, TOKEN);
    165             fail("Expected IllegalArgumentException");
    166         } catch (IllegalArgumentException ex) {
    167             // expected
    168         }
    169     }
    170 
    171     public void testPostCallbackDelayedThrowsIfRunnableIsNull() {
    172         try {
    173             mChoreographer.postCallbackDelayed(
    174                     Choreographer.CALLBACK_ANIMATION, null, TOKEN, DELAY_PERIOD);
    175             fail("Expected IllegalArgumentException");
    176         } catch (IllegalArgumentException ex) {
    177             // expected
    178         }
    179     }
    180 
    181     public void testPostFrameCallbackWithoutDelayEventuallyRunsFrameCallbacks() {
    182         MockFrameCallback addedFrameCallback1 = new MockFrameCallback();
    183         MockFrameCallback addedFrameCallback2 = new MockFrameCallback();
    184         MockFrameCallback removedFrameCallback = new MockFrameCallback();
    185         try {
    186             // Add and remove a few callbacks.
    187             long postTimeNanos = System.nanoTime();
    188             mChoreographer.postFrameCallback(addedFrameCallback1);
    189             mChoreographer.postFrameCallback(addedFrameCallback2);
    190             mChoreographer.postFrameCallback(removedFrameCallback);
    191             mChoreographer.removeFrameCallback(removedFrameCallback);
    192 
    193             // Sleep for a couple of frames.
    194             sleep(NOMINAL_VSYNC_PERIOD * 3);
    195 
    196             // We expect the remaining callbacks to have been invoked once.
    197             assertEquals(1, addedFrameCallback1.invocationCount);
    198             assertEquals(1, addedFrameCallback2.invocationCount);
    199             assertEquals(0, removedFrameCallback.invocationCount);
    200             assertTimeDeltaLessThan(addedFrameCallback1.frameTimeNanos - postTimeNanos,
    201                     NOMINAL_VSYNC_PERIOD * 3 * NANOS_PER_MS);
    202             assertTimeDeltaLessThan(addedFrameCallback2.frameTimeNanos - postTimeNanos,
    203                     NOMINAL_VSYNC_PERIOD * 3 * NANOS_PER_MS);
    204             assertTimeDeltaLessThan(Math.abs(addedFrameCallback2.frameTimeNanos
    205                     - addedFrameCallback1.frameTimeNanos), NOMINAL_VSYNC_PERIOD * NANOS_PER_MS);
    206 
    207             // If we post a callback again, then it should be invoked again.
    208             postTimeNanos = System.nanoTime();
    209             mChoreographer.postFrameCallback(addedFrameCallback1);
    210             sleep(NOMINAL_VSYNC_PERIOD * 3);
    211 
    212             assertEquals(2, addedFrameCallback1.invocationCount);
    213             assertEquals(1, addedFrameCallback2.invocationCount);
    214             assertEquals(0, removedFrameCallback.invocationCount);
    215             assertTimeDeltaLessThan(addedFrameCallback1.frameTimeNanos - postTimeNanos,
    216                     NOMINAL_VSYNC_PERIOD * 3 * NANOS_PER_MS);
    217         } finally {
    218             mChoreographer.removeFrameCallback(addedFrameCallback1);
    219             mChoreographer.removeFrameCallback(addedFrameCallback2);
    220             mChoreographer.removeFrameCallback(removedFrameCallback);
    221         }
    222     }
    223 
    224     public void testPostFrameCallbackWithDelayEventuallyRunsFrameCallbacksAfterDelay() {
    225         MockFrameCallback addedFrameCallback = new MockFrameCallback();
    226         MockFrameCallback removedFrameCallback = new MockFrameCallback();
    227         try {
    228             // Add and remove a few callbacks.
    229             long postTimeNanos = System.nanoTime();
    230             mChoreographer.postFrameCallbackDelayed(addedFrameCallback, DELAY_PERIOD);
    231             mChoreographer.postFrameCallbackDelayed(removedFrameCallback, DELAY_PERIOD);
    232             mChoreographer.removeFrameCallback(removedFrameCallback);
    233 
    234             // Sleep for a couple of frames.
    235             sleep(NOMINAL_VSYNC_PERIOD * 3);
    236 
    237             // The callbacks should not have been invoked yet because of the delay.
    238             assertEquals(0, addedFrameCallback.invocationCount);
    239             assertEquals(0, removedFrameCallback.invocationCount);
    240 
    241             // Sleep for the rest of the delay time.
    242             sleep(DELAY_PERIOD);
    243 
    244             // We expect the remaining callbacks to have been invoked.
    245             assertEquals(1, addedFrameCallback.invocationCount);
    246             assertEquals(0, removedFrameCallback.invocationCount);
    247             assertTimeDeltaLessThan(addedFrameCallback.frameTimeNanos - postTimeNanos,
    248                     (NOMINAL_VSYNC_PERIOD * 3 + DELAY_PERIOD) * NANOS_PER_MS);
    249         } finally {
    250             mChoreographer.removeFrameCallback(addedFrameCallback);
    251             mChoreographer.removeFrameCallback(removedFrameCallback);
    252         }
    253     }
    254 
    255     private void assertTimeDeltaLessThan(long deltaNanos, long thresholdNanos) {
    256         if (deltaNanos >= thresholdNanos) {
    257             fail("Expected time delta less than " + thresholdNanos + " nanos, actually "
    258                     + " was " + deltaNanos + " nanos.");
    259         }
    260     }
    261 
    262     public void testPostFrameCallbackThrowsIfCallbackIsNull() {
    263         try {
    264             mChoreographer.postFrameCallback(null);
    265             fail("Expected IllegalArgumentException");
    266         } catch (IllegalArgumentException ex) {
    267             // expected
    268         }
    269     }
    270 
    271     public void testPostFrameCallbackDelayedThrowsIfCallbackIsNull() {
    272         try {
    273             mChoreographer.postFrameCallbackDelayed(null, DELAY_PERIOD);
    274             fail("Expected IllegalArgumentException");
    275         } catch (IllegalArgumentException ex) {
    276             // expected
    277         }
    278     }
    279 
    280     public void testRemoveFrameCallbackThrowsIfCallbackIsNull() {
    281         try {
    282             mChoreographer.removeFrameCallback(null);
    283             fail("Expected IllegalArgumentException");
    284         } catch (IllegalArgumentException ex) {
    285             // expected
    286         }
    287     }
    288 
    289     private void sleep(long time) {
    290         try {
    291             Thread.sleep(time);
    292         } catch (InterruptedException e) {
    293             fail(e.getMessage());
    294         }
    295     }
    296 
    297     private static final class MockRunnable implements Runnable {
    298         public int invocationCount;
    299 
    300         @Override
    301         public void run() {
    302             invocationCount += 1;
    303         }
    304     }
    305 
    306     private static final class MockFrameCallback implements Choreographer.FrameCallback {
    307         public long frameTimeNanos;
    308         public int invocationCount;
    309 
    310         @Override
    311         public void doFrame(long frameTimeNanos) {
    312             this.frameTimeNanos = frameTimeNanos;
    313             invocationCount += 1;
    314         }
    315     }
    316 }
    317