Home | History | Annotate | Download | only in wm
      1 /*
      2  * Copyright (C) 2017 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 com.android.server.wm;
     18 
     19 import static java.util.concurrent.TimeUnit.SECONDS;
     20 import static org.junit.Assert.assertEquals;
     21 import static org.junit.Assert.assertFalse;
     22 import static org.junit.Assert.assertTrue;
     23 import static org.mockito.Mockito.any;
     24 import static org.mockito.Mockito.atLeast;
     25 import static org.mockito.Mockito.atLeastOnce;
     26 import static org.mockito.Mockito.eq;
     27 import static org.mockito.Mockito.times;
     28 import static org.mockito.Mockito.verify;
     29 import static org.mockito.Mockito.when;
     30 
     31 import android.animation.AnimationHandler;
     32 import android.animation.AnimationHandler.AnimationFrameCallbackProvider;
     33 import android.animation.ValueAnimator;
     34 import android.graphics.Matrix;
     35 import android.graphics.Point;
     36 import android.platform.test.annotations.Presubmit;
     37 import android.support.test.filters.FlakyTest;
     38 import android.support.test.filters.SmallTest;
     39 import android.support.test.runner.AndroidJUnit4;
     40 import android.util.Log;
     41 import android.view.Choreographer;
     42 import android.view.Choreographer.FrameCallback;
     43 import android.view.SurfaceControl;
     44 import android.view.SurfaceControl.Transaction;
     45 import android.view.animation.Animation;
     46 import android.view.animation.TranslateAnimation;
     47 
     48 import com.android.server.wm.LocalAnimationAdapter.AnimationSpec;
     49 import com.android.server.wm.SurfaceAnimationRunner.AnimatorFactory;
     50 
     51 import org.junit.Before;
     52 import org.junit.Rule;
     53 import org.junit.Test;
     54 import org.junit.runner.RunWith;
     55 import org.mockito.Mock;
     56 import org.mockito.junit.MockitoJUnit;
     57 import org.mockito.junit.MockitoRule;
     58 
     59 import java.util.concurrent.CountDownLatch;
     60 
     61 /**
     62  * Test class for {@link SurfaceAnimationRunner}.
     63  *
     64  * atest FrameworksServicesTests:com.android.server.wm.SurfaceAnimationRunnerTest
     65  */
     66 @SmallTest
     67 @Presubmit
     68 @RunWith(AndroidJUnit4.class)
     69 public class SurfaceAnimationRunnerTest extends WindowTestsBase {
     70 
     71     @Mock SurfaceControl mMockSurface;
     72     @Mock Transaction mMockTransaction;
     73     @Mock AnimationSpec mMockAnimationSpec;
     74     @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
     75 
     76     private SurfaceAnimationRunner mSurfaceAnimationRunner;
     77     private CountDownLatch mFinishCallbackLatch;
     78 
     79     @Before
     80     public void setUp() throws Exception {
     81         super.setUp();
     82         mFinishCallbackLatch = new CountDownLatch(1);
     83         mSurfaceAnimationRunner = new SurfaceAnimationRunner(null /* callbackProvider */, null,
     84                 mMockTransaction);
     85     }
     86 
     87     private void finishedCallback() {
     88         mFinishCallbackLatch.countDown();
     89     }
     90 
     91     @Test
     92     public void testAnimation() throws Exception {
     93         mSurfaceAnimationRunner
     94                 .startAnimation(createTranslateAnimation(), mMockSurface, mMockTransaction,
     95                 this::finishedCallback);
     96 
     97         // Ensure that the initial transformation has been applied.
     98         final Matrix m = new Matrix();
     99         m.setTranslate(-10, 0);
    100         verify(mMockTransaction, atLeastOnce()).setMatrix(eq(mMockSurface), eq(m), any());
    101         verify(mMockTransaction, atLeastOnce()).setAlpha(eq(mMockSurface), eq(1.0f));
    102 
    103         mFinishCallbackLatch.await(1, SECONDS);
    104         assertFinishCallbackCalled();
    105 
    106         m.setTranslate(10, 0);
    107         verify(mMockTransaction, atLeastOnce()).setMatrix(eq(mMockSurface), eq(m), any());
    108 
    109         // At least 3 times: After initialization, first frame, last frame.
    110         verify(mMockTransaction, atLeast(3)).setAlpha(eq(mMockSurface), eq(1.0f));
    111     }
    112 
    113     @Test
    114     public void testCancel_notStarted() throws Exception {
    115         mSurfaceAnimationRunner = new SurfaceAnimationRunner(new NoOpFrameCallbackProvider(), null,
    116                 mMockTransaction);
    117         mSurfaceAnimationRunner
    118                 .startAnimation(createTranslateAnimation(), mMockSurface, mMockTransaction,
    119                 this::finishedCallback);
    120         mSurfaceAnimationRunner.onAnimationCancelled(mMockSurface);
    121         waitUntilHandlersIdle();
    122         assertTrue(mSurfaceAnimationRunner.mPendingAnimations.isEmpty());
    123         assertFinishCallbackNotCalled();
    124     }
    125 
    126     @Test
    127     public void testCancel_running() throws Exception {
    128         mSurfaceAnimationRunner = new SurfaceAnimationRunner(new NoOpFrameCallbackProvider(), null,
    129                 mMockTransaction);
    130         mSurfaceAnimationRunner.startAnimation(createTranslateAnimation(), mMockSurface,
    131                 mMockTransaction, this::finishedCallback);
    132         waitUntilNextFrame();
    133         assertFalse(mSurfaceAnimationRunner.mRunningAnimations.isEmpty());
    134         mSurfaceAnimationRunner.onAnimationCancelled(mMockSurface);
    135         assertTrue(mSurfaceAnimationRunner.mRunningAnimations.isEmpty());
    136         waitUntilHandlersIdle();
    137         assertFinishCallbackNotCalled();
    138     }
    139 
    140     @FlakyTest(bugId = 71719744)
    141     @Test
    142     public void testCancel_sneakyCancelBeforeUpdate() throws Exception {
    143         mSurfaceAnimationRunner = new SurfaceAnimationRunner(null, () -> new ValueAnimator() {
    144             {
    145                 setFloatValues(0f, 1f);
    146             }
    147 
    148             @Override
    149             public void addUpdateListener(AnimatorUpdateListener listener) {
    150                 super.addUpdateListener(animation -> {
    151                     // Sneaky test cancels animation just before applying frame to simulate
    152                     // interleaving of multiple threads. Muahahaha
    153                     if (animation.getCurrentPlayTime() > 0) {
    154                         mSurfaceAnimationRunner.onAnimationCancelled(mMockSurface);
    155                     }
    156                     listener.onAnimationUpdate(animation);
    157                 });
    158             }
    159         }, mMockTransaction);
    160         when(mMockAnimationSpec.getDuration()).thenReturn(200L);
    161         mSurfaceAnimationRunner.startAnimation(mMockAnimationSpec, mMockSurface, mMockTransaction,
    162                 this::finishedCallback);
    163 
    164         // We need to wait for two frames: The first frame starts the animation, the second frame
    165         // actually cancels the animation.
    166         waitUntilNextFrame();
    167         waitUntilNextFrame();
    168         assertTrue(mSurfaceAnimationRunner.mRunningAnimations.isEmpty());
    169         verify(mMockAnimationSpec, atLeastOnce()).apply(any(), any(), eq(0L));
    170     }
    171 
    172     @FlakyTest(bugId = 74780584)
    173     @Test
    174     public void testDeferStartingAnimations() throws Exception {
    175         mSurfaceAnimationRunner.deferStartingAnimations();
    176         mSurfaceAnimationRunner.startAnimation(createTranslateAnimation(), mMockSurface,
    177                 mMockTransaction, this::finishedCallback);
    178         waitUntilNextFrame();
    179         assertTrue(mSurfaceAnimationRunner.mRunningAnimations.isEmpty());
    180         mSurfaceAnimationRunner.continueStartingAnimations();
    181         waitUntilNextFrame();
    182         assertFalse(mSurfaceAnimationRunner.mRunningAnimations.isEmpty());
    183         mFinishCallbackLatch.await(1, SECONDS);
    184         assertFinishCallbackCalled();
    185     }
    186 
    187     private void waitUntilNextFrame() throws Exception {
    188         final CountDownLatch latch = new CountDownLatch(1);
    189         mSurfaceAnimationRunner.mChoreographer.postCallback(Choreographer.CALLBACK_COMMIT,
    190                 latch::countDown, null /* token */);
    191         latch.await();
    192     }
    193 
    194     private void assertFinishCallbackCalled() {
    195         assertEquals(0, mFinishCallbackLatch.getCount());
    196     }
    197 
    198     private void assertFinishCallbackNotCalled() {
    199         assertEquals(1, mFinishCallbackLatch.getCount());
    200     }
    201 
    202     private AnimationSpec createTranslateAnimation() {
    203         final Animation a = new TranslateAnimation(-10, 10, 0, 0);
    204         a.initialize(0, 0, 0, 0);
    205         a.setDuration(50);
    206         return new WindowAnimationSpec(a, new Point(0, 0), false /* canSkipFirstFrame */);
    207     }
    208 
    209     /**
    210      * Callback provider that doesn't animate at all.
    211      */
    212     private static final class NoOpFrameCallbackProvider implements AnimationFrameCallbackProvider {
    213 
    214         @Override
    215         public void postFrameCallback(FrameCallback callback) {
    216         }
    217 
    218         @Override
    219         public void postCommitCallback(Runnable runnable) {
    220         }
    221 
    222         @Override
    223         public long getFrameTime() {
    224             return 0;
    225         }
    226 
    227         @Override
    228         public long getFrameDelay() {
    229             return 0;
    230         }
    231 
    232         @Override
    233         public void setFrameDelay(long delay) {
    234         }
    235     }
    236 }
    237