blob: 4551c3611102c99656669550485e8284b93014c9 [file] [log] [blame]
Jorim Jaggi21c39a72017-10-20 15:47:51 +02001/*
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
17package com.android.server.wm;
18
Jorim Jaggi21c39a72017-10-20 15:47:51 +020019import static org.junit.Assert.assertEquals;
20import static org.junit.Assert.assertFalse;
21import static org.junit.Assert.assertTrue;
Jorim Jaggib6ba4332018-07-10 00:36:57 +020022import static org.mockito.ArgumentMatchers.anyInt;
Jorim Jaggi21c39a72017-10-20 15:47:51 +020023import static org.mockito.Mockito.any;
24import static org.mockito.Mockito.atLeast;
25import static org.mockito.Mockito.atLeastOnce;
26import static org.mockito.Mockito.eq;
27import static org.mockito.Mockito.verify;
Jorim Jaggi6c7e5612017-12-12 02:17:10 +010028import static org.mockito.Mockito.when;
Jorim Jaggi21c39a72017-10-20 15:47:51 +020029
30import android.animation.AnimationHandler.AnimationFrameCallbackProvider;
Jorim Jaggi6c7e5612017-12-12 02:17:10 +010031import android.animation.ValueAnimator;
Jorim Jaggi21c39a72017-10-20 15:47:51 +020032import android.graphics.Matrix;
33import android.graphics.Point;
Jorim Jaggib6ba4332018-07-10 00:36:57 +020034import android.os.PowerManagerInternal;
Jorim Jaggi21c39a72017-10-20 15:47:51 +020035import android.platform.test.annotations.Presubmit;
Jorim Jaggi21c39a72017-10-20 15:47:51 +020036import android.view.Choreographer;
37import android.view.Choreographer.FrameCallback;
38import android.view.SurfaceControl;
39import android.view.SurfaceControl.Transaction;
40import android.view.animation.Animation;
41import android.view.animation.TranslateAnimation;
42
Brett Chabota26eda92018-07-23 13:08:30 -070043import androidx.test.filters.FlakyTest;
44import androidx.test.filters.SmallTest;
45import androidx.test.runner.AndroidJUnit4;
46
Jorim Jaggi21c39a72017-10-20 15:47:51 +020047import com.android.server.wm.LocalAnimationAdapter.AnimationSpec;
48
49import org.junit.Before;
50import org.junit.Rule;
51import org.junit.Test;
52import org.junit.runner.RunWith;
53import org.mockito.Mock;
54import org.mockito.junit.MockitoJUnit;
55import org.mockito.junit.MockitoRule;
56
John Reck3d294e72018-09-21 20:26:48 +000057import static java.util.concurrent.TimeUnit.SECONDS;
58
Jorim Jaggi21c39a72017-10-20 15:47:51 +020059import java.util.concurrent.CountDownLatch;
60
61/**
62 * Test class for {@link SurfaceAnimationRunner}.
63 *
John Reck3d294e72018-09-21 20:26:48 +000064 * atest FrameworksServicesTests:com.android.server.wm.SurfaceAnimationRunnerTest
Jorim Jaggi21c39a72017-10-20 15:47:51 +020065 */
66@SmallTest
67@Presubmit
68@RunWith(AndroidJUnit4.class)
69public class SurfaceAnimationRunnerTest extends WindowTestsBase {
70
71 @Mock SurfaceControl mMockSurface;
72 @Mock Transaction mMockTransaction;
Jorim Jaggi6c7e5612017-12-12 02:17:10 +010073 @Mock AnimationSpec mMockAnimationSpec;
Jorim Jaggib6ba4332018-07-10 00:36:57 +020074 @Mock PowerManagerInternal mMockPowerManager;
Jorim Jaggi21c39a72017-10-20 15:47:51 +020075 @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
76
77 private SurfaceAnimationRunner mSurfaceAnimationRunner;
78 private CountDownLatch mFinishCallbackLatch;
79
80 @Before
81 public void setUp() throws Exception {
82 super.setUp();
83 mFinishCallbackLatch = new CountDownLatch(1);
Jorim Jaggi6c7e5612017-12-12 02:17:10 +010084 mSurfaceAnimationRunner = new SurfaceAnimationRunner(null /* callbackProvider */, null,
Jorim Jaggib6ba4332018-07-10 00:36:57 +020085 mMockTransaction, mMockPowerManager);
Jorim Jaggi21c39a72017-10-20 15:47:51 +020086 }
87
88 private void finishedCallback() {
89 mFinishCallbackLatch.countDown();
90 }
91
92 @Test
93 public void testAnimation() throws Exception {
94 mSurfaceAnimationRunner
95 .startAnimation(createTranslateAnimation(), mMockSurface, mMockTransaction,
96 this::finishedCallback);
97
98 // Ensure that the initial transformation has been applied.
99 final Matrix m = new Matrix();
100 m.setTranslate(-10, 0);
101 verify(mMockTransaction, atLeastOnce()).setMatrix(eq(mMockSurface), eq(m), any());
102 verify(mMockTransaction, atLeastOnce()).setAlpha(eq(mMockSurface), eq(1.0f));
103
104 mFinishCallbackLatch.await(1, SECONDS);
105 assertFinishCallbackCalled();
106
107 m.setTranslate(10, 0);
108 verify(mMockTransaction, atLeastOnce()).setMatrix(eq(mMockSurface), eq(m), any());
109
110 // At least 3 times: After initialization, first frame, last frame.
111 verify(mMockTransaction, atLeast(3)).setAlpha(eq(mMockSurface), eq(1.0f));
112 }
113
114 @Test
115 public void testCancel_notStarted() throws Exception {
Jorim Jaggi6c7e5612017-12-12 02:17:10 +0100116 mSurfaceAnimationRunner = new SurfaceAnimationRunner(new NoOpFrameCallbackProvider(), null,
Jorim Jaggib6ba4332018-07-10 00:36:57 +0200117 mMockTransaction, mMockPowerManager);
Jorim Jaggi21c39a72017-10-20 15:47:51 +0200118 mSurfaceAnimationRunner
119 .startAnimation(createTranslateAnimation(), mMockSurface, mMockTransaction,
120 this::finishedCallback);
121 mSurfaceAnimationRunner.onAnimationCancelled(mMockSurface);
122 waitUntilHandlersIdle();
123 assertTrue(mSurfaceAnimationRunner.mPendingAnimations.isEmpty());
124 assertFinishCallbackNotCalled();
Jorim Jaggi21c39a72017-10-20 15:47:51 +0200125 }
126
127 @Test
128 public void testCancel_running() throws Exception {
Jorim Jaggi6c7e5612017-12-12 02:17:10 +0100129 mSurfaceAnimationRunner = new SurfaceAnimationRunner(new NoOpFrameCallbackProvider(), null,
Jorim Jaggib6ba4332018-07-10 00:36:57 +0200130 mMockTransaction, mMockPowerManager);
Jorim Jaggi6c7e5612017-12-12 02:17:10 +0100131 mSurfaceAnimationRunner.startAnimation(createTranslateAnimation(), mMockSurface,
132 mMockTransaction, this::finishedCallback);
Jorim Jaggi21c39a72017-10-20 15:47:51 +0200133 waitUntilNextFrame();
134 assertFalse(mSurfaceAnimationRunner.mRunningAnimations.isEmpty());
135 mSurfaceAnimationRunner.onAnimationCancelled(mMockSurface);
136 assertTrue(mSurfaceAnimationRunner.mRunningAnimations.isEmpty());
137 waitUntilHandlersIdle();
138 assertFinishCallbackNotCalled();
Jorim Jaggi21c39a72017-10-20 15:47:51 +0200139 }
140
chaviw0fb741f2018-01-08 16:18:03 -0800141 @FlakyTest(bugId = 71719744)
Jorim Jaggi6c7e5612017-12-12 02:17:10 +0100142 @Test
143 public void testCancel_sneakyCancelBeforeUpdate() throws Exception {
144 mSurfaceAnimationRunner = new SurfaceAnimationRunner(null, () -> new ValueAnimator() {
145 {
146 setFloatValues(0f, 1f);
147 }
148
149 @Override
150 public void addUpdateListener(AnimatorUpdateListener listener) {
151 super.addUpdateListener(animation -> {
152 // Sneaky test cancels animation just before applying frame to simulate
153 // interleaving of multiple threads. Muahahaha
154 if (animation.getCurrentPlayTime() > 0) {
155 mSurfaceAnimationRunner.onAnimationCancelled(mMockSurface);
156 }
157 listener.onAnimationUpdate(animation);
158 });
159 }
Jorim Jaggib6ba4332018-07-10 00:36:57 +0200160 }, mMockTransaction, mMockPowerManager);
Jorim Jaggi6c7e5612017-12-12 02:17:10 +0100161 when(mMockAnimationSpec.getDuration()).thenReturn(200L);
162 mSurfaceAnimationRunner.startAnimation(mMockAnimationSpec, mMockSurface, mMockTransaction,
163 this::finishedCallback);
Jorim Jaggi4130a682018-01-09 14:28:44 +0100164
165 // We need to wait for two frames: The first frame starts the animation, the second frame
166 // actually cancels the animation.
Jorim Jaggi6c7e5612017-12-12 02:17:10 +0100167 waitUntilNextFrame();
Jorim Jaggi4130a682018-01-09 14:28:44 +0100168 waitUntilNextFrame();
169 assertTrue(mSurfaceAnimationRunner.mRunningAnimations.isEmpty());
Jorim Jaggi6c7e5612017-12-12 02:17:10 +0100170 verify(mMockAnimationSpec, atLeastOnce()).apply(any(), any(), eq(0L));
171 }
172
Jorim Jaggid0a94372018-03-15 12:58:49 +0100173 @FlakyTest(bugId = 74780584)
Jorim Jaggid6d97162018-01-05 18:28:36 +0100174 @Test
175 public void testDeferStartingAnimations() throws Exception {
176 mSurfaceAnimationRunner.deferStartingAnimations();
177 mSurfaceAnimationRunner.startAnimation(createTranslateAnimation(), mMockSurface,
178 mMockTransaction, this::finishedCallback);
179 waitUntilNextFrame();
180 assertTrue(mSurfaceAnimationRunner.mRunningAnimations.isEmpty());
181 mSurfaceAnimationRunner.continueStartingAnimations();
182 waitUntilNextFrame();
183 assertFalse(mSurfaceAnimationRunner.mRunningAnimations.isEmpty());
184 mFinishCallbackLatch.await(1, SECONDS);
185 assertFinishCallbackCalled();
186 }
187
Jorim Jaggib6ba4332018-07-10 00:36:57 +0200188 @Test
189 public void testPowerHint() throws Exception {
190 mSurfaceAnimationRunner = new SurfaceAnimationRunner(new NoOpFrameCallbackProvider(), null,
191 mMockTransaction, mMockPowerManager);
192 mSurfaceAnimationRunner.startAnimation(createTranslateAnimation(), mMockSurface,
193 mMockTransaction, this::finishedCallback);
194 waitUntilNextFrame();
195
196 // TODO: For some reason we don't have access to PowerHint definition from the tests. For
197 // now let's just verify that we got some kind of hint.
198 verify(mMockPowerManager).powerHint(anyInt(), anyInt());
199 }
200
Jorim Jaggi21c39a72017-10-20 15:47:51 +0200201 private void waitUntilNextFrame() throws Exception {
202 final CountDownLatch latch = new CountDownLatch(1);
203 mSurfaceAnimationRunner.mChoreographer.postCallback(Choreographer.CALLBACK_COMMIT,
204 latch::countDown, null /* token */);
205 latch.await();
206 }
207
208 private void assertFinishCallbackCalled() {
209 assertEquals(0, mFinishCallbackLatch.getCount());
210 }
211
212 private void assertFinishCallbackNotCalled() {
213 assertEquals(1, mFinishCallbackLatch.getCount());
214 }
215
216 private AnimationSpec createTranslateAnimation() {
217 final Animation a = new TranslateAnimation(-10, 10, 0, 0);
218 a.initialize(0, 0, 0, 0);
219 a.setDuration(50);
Jorim Jaggi2e3c31d2017-11-20 19:49:00 +0100220 return new WindowAnimationSpec(a, new Point(0, 0), false /* canSkipFirstFrame */);
Jorim Jaggi21c39a72017-10-20 15:47:51 +0200221 }
222
223 /**
224 * Callback provider that doesn't animate at all.
225 */
226 private static final class NoOpFrameCallbackProvider implements AnimationFrameCallbackProvider {
227
228 @Override
229 public void postFrameCallback(FrameCallback callback) {
230 }
231
232 @Override
233 public void postCommitCallback(Runnable runnable) {
234 }
235
236 @Override
237 public long getFrameTime() {
238 return 0;
239 }
240
241 @Override
242 public long getFrameDelay() {
243 return 0;
244 }
245
246 @Override
247 public void setFrameDelay(long delay) {
248 }
249 }
250}