blob: cb504607420cc2d60311cef648210319994a5984 [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 Jaggi2d74faf2017-12-18 19:21:27 +010019import static android.util.TimeUtils.NANOS_PER_MS;
Jorim Jaggi21c39a72017-10-20 15:47:51 +020020import static android.view.Choreographer.CALLBACK_TRAVERSAL;
21import static android.view.Choreographer.getSfInstance;
22
23import android.animation.AnimationHandler;
24import android.animation.AnimationHandler.AnimationFrameCallbackProvider;
25import android.animation.Animator;
26import android.animation.AnimatorListenerAdapter;
27import android.animation.ValueAnimator;
28import android.annotation.Nullable;
Jorim Jaggib6ba4332018-07-10 00:36:57 +020029import android.hardware.power.V1_0.PowerHint;
30import android.os.PowerManagerInternal;
Jorim Jaggi21c39a72017-10-20 15:47:51 +020031import android.util.ArrayMap;
32import android.view.Choreographer;
33import android.view.SurfaceControl;
34import android.view.SurfaceControl.Transaction;
Jorim Jaggi21c39a72017-10-20 15:47:51 +020035
36import com.android.internal.annotations.GuardedBy;
37import com.android.internal.annotations.VisibleForTesting;
38import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
39import com.android.server.AnimationThread;
40import com.android.server.wm.LocalAnimationAdapter.AnimationSpec;
41
42/**
43 * Class to run animations without holding the window manager lock.
44 */
45class SurfaceAnimationRunner {
46
47 private final Object mLock = new Object();
48
Jorim Jaggi6c7e5612017-12-12 02:17:10 +010049 /**
50 * Lock for cancelling animations. Must be acquired on it's own, or after acquiring
51 * {@link #mLock}
52 */
53 private final Object mCancelLock = new Object();
54
Jorim Jaggi21c39a72017-10-20 15:47:51 +020055 @VisibleForTesting
56 Choreographer mChoreographer;
57
58 private final Runnable mApplyTransactionRunnable = this::applyTransaction;
59 private final AnimationHandler mAnimationHandler;
60 private final Transaction mFrameTransaction;
Jorim Jaggi6c7e5612017-12-12 02:17:10 +010061 private final AnimatorFactory mAnimatorFactory;
Jorim Jaggib6ba4332018-07-10 00:36:57 +020062 private final PowerManagerInternal mPowerManagerInternal;
Jorim Jaggi21c39a72017-10-20 15:47:51 +020063 private boolean mApplyScheduled;
64
65 @GuardedBy("mLock")
66 @VisibleForTesting
67 final ArrayMap<SurfaceControl, RunningAnimation> mPendingAnimations = new ArrayMap<>();
68
69 @GuardedBy("mLock")
70 @VisibleForTesting
Jorim Jaggi6c7e5612017-12-12 02:17:10 +010071 final ArrayMap<SurfaceControl, RunningAnimation> mRunningAnimations = new ArrayMap<>();
Jorim Jaggi21c39a72017-10-20 15:47:51 +020072
Jorim Jaggid6d97162018-01-05 18:28:36 +010073 @GuardedBy("mLock")
74 private boolean mAnimationStartDeferred;
75
Jorim Jaggib6ba4332018-07-10 00:36:57 +020076 SurfaceAnimationRunner(PowerManagerInternal powerManagerInternal) {
77 this(null /* callbackProvider */, null /* animatorFactory */, new Transaction(),
78 powerManagerInternal);
Jorim Jaggi21c39a72017-10-20 15:47:51 +020079 }
80
81 @VisibleForTesting
82 SurfaceAnimationRunner(@Nullable AnimationFrameCallbackProvider callbackProvider,
Jorim Jaggib6ba4332018-07-10 00:36:57 +020083 AnimatorFactory animatorFactory, Transaction frameTransaction,
84 PowerManagerInternal powerManagerInternal) {
Jorim Jaggi21c39a72017-10-20 15:47:51 +020085 SurfaceAnimationThread.getHandler().runWithScissors(() -> mChoreographer = getSfInstance(),
86 0 /* timeout */);
87 mFrameTransaction = frameTransaction;
88 mAnimationHandler = new AnimationHandler();
89 mAnimationHandler.setProvider(callbackProvider != null
90 ? callbackProvider
91 : new SfVsyncFrameCallbackProvider(mChoreographer));
Jorim Jaggi6c7e5612017-12-12 02:17:10 +010092 mAnimatorFactory = animatorFactory != null
93 ? animatorFactory
94 : SfValueAnimator::new;
Jorim Jaggib6ba4332018-07-10 00:36:57 +020095 mPowerManagerInternal = powerManagerInternal;
Jorim Jaggi21c39a72017-10-20 15:47:51 +020096 }
97
Jorim Jaggid6d97162018-01-05 18:28:36 +010098 /**
99 * Defers starting of animations until {@link #continueStartingAnimations} is called. This
100 * method is NOT nestable.
101 *
102 * @see #continueStartingAnimations
103 */
104 void deferStartingAnimations() {
105 synchronized (mLock) {
106 mAnimationStartDeferred = true;
107 }
108 }
109
110 /**
111 * Continues starting of animations.
112 *
113 * @see #deferStartingAnimations
114 */
115 void continueStartingAnimations() {
116 synchronized (mLock) {
117 mAnimationStartDeferred = false;
118 if (!mPendingAnimations.isEmpty()) {
119 mChoreographer.postFrameCallback(this::startAnimations);
120 }
121 }
122 }
123
Jorim Jaggi21c39a72017-10-20 15:47:51 +0200124 void startAnimation(AnimationSpec a, SurfaceControl animationLeash, Transaction t,
125 Runnable finishCallback) {
126 synchronized (mLock) {
127 final RunningAnimation runningAnim = new RunningAnimation(a, animationLeash,
128 finishCallback);
129 mPendingAnimations.put(animationLeash, runningAnim);
Jorim Jaggid6d97162018-01-05 18:28:36 +0100130 if (!mAnimationStartDeferred) {
131 mChoreographer.postFrameCallback(this::startAnimations);
132 }
Jorim Jaggi21c39a72017-10-20 15:47:51 +0200133
134 // Some animations (e.g. move animations) require the initial transform to be applied
135 // immediately.
136 applyTransformation(runningAnim, t, 0 /* currentPlayTime */);
137 }
138 }
139
140 void onAnimationCancelled(SurfaceControl leash) {
141 synchronized (mLock) {
142 if (mPendingAnimations.containsKey(leash)) {
143 mPendingAnimations.remove(leash);
Jorim Jaggi21c39a72017-10-20 15:47:51 +0200144 return;
145 }
Jorim Jaggi6c7e5612017-12-12 02:17:10 +0100146 final RunningAnimation anim = mRunningAnimations.get(leash);
Jorim Jaggi21c39a72017-10-20 15:47:51 +0200147 if (anim != null) {
148 mRunningAnimations.remove(leash);
Jorim Jaggi6c7e5612017-12-12 02:17:10 +0100149 synchronized (mCancelLock) {
150 anim.mCancelled = true;
151 }
Jorim Jaggi21c39a72017-10-20 15:47:51 +0200152 SurfaceAnimationThread.getHandler().post(() -> {
Jorim Jaggi6c7e5612017-12-12 02:17:10 +0100153 anim.mAnim.cancel();
Jorim Jaggi21c39a72017-10-20 15:47:51 +0200154 applyTransaction();
Jorim Jaggi21c39a72017-10-20 15:47:51 +0200155 });
156 }
157 }
158 }
159
Andreas Gampea36dc622018-02-05 17:19:22 -0800160 @GuardedBy("mLock")
Jorim Jaggi21c39a72017-10-20 15:47:51 +0200161 private void startPendingAnimationsLocked() {
162 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
163 startAnimationLocked(mPendingAnimations.valueAt(i));
164 }
165 mPendingAnimations.clear();
166 }
167
Andreas Gampea36dc622018-02-05 17:19:22 -0800168 @GuardedBy("mLock")
Jorim Jaggi21c39a72017-10-20 15:47:51 +0200169 private void startAnimationLocked(RunningAnimation a) {
Jorim Jaggi6c7e5612017-12-12 02:17:10 +0100170 final ValueAnimator anim = mAnimatorFactory.makeAnimator();
Jorim Jaggi21c39a72017-10-20 15:47:51 +0200171
172 // Animation length is already expected to be scaled.
Jorim Jaggi6c7e5612017-12-12 02:17:10 +0100173 anim.overrideDurationScale(1.0f);
174 anim.setDuration(a.mAnimSpec.getDuration());
175 anim.addUpdateListener(animation -> {
176 synchronized (mCancelLock) {
177 if (!a.mCancelled) {
chaviw4d133722018-02-09 14:36:10 -0800178 final long duration = anim.getDuration();
179 long currentPlayTime = anim.getCurrentPlayTime();
180 if (currentPlayTime > duration) {
181 currentPlayTime = duration;
182 }
183 applyTransformation(a, mFrameTransaction, currentPlayTime);
Jorim Jaggi6c7e5612017-12-12 02:17:10 +0100184 }
185 }
Jorim Jaggi21c39a72017-10-20 15:47:51 +0200186
187 // Transaction will be applied in the commit phase.
188 scheduleApplyTransaction();
189 });
Jorim Jaggi2e3c31d2017-11-20 19:49:00 +0100190
Jorim Jaggi6c7e5612017-12-12 02:17:10 +0100191 anim.addListener(new AnimatorListenerAdapter() {
Jorim Jaggi21c39a72017-10-20 15:47:51 +0200192 @Override
193 public void onAnimationStart(Animator animation) {
Jorim Jaggi6c7e5612017-12-12 02:17:10 +0100194 synchronized (mCancelLock) {
195 if (!a.mCancelled) {
196 mFrameTransaction.show(a.mLeash);
197 }
198 }
Jorim Jaggi21c39a72017-10-20 15:47:51 +0200199 }
200
201 @Override
202 public void onAnimationEnd(Animator animation) {
203 synchronized (mLock) {
Jorim Jaggia5e10572017-11-15 14:36:26 +0100204 mRunningAnimations.remove(a.mLeash);
Jorim Jaggi6c7e5612017-12-12 02:17:10 +0100205 synchronized (mCancelLock) {
206 if (!a.mCancelled) {
Jorim Jaggi980c9de2017-11-17 01:41:37 +0100207
Jorim Jaggi6c7e5612017-12-12 02:17:10 +0100208 // Post on other thread that we can push final state without jank.
209 AnimationThread.getHandler().post(a.mFinishCallback);
210 }
211 }
Jorim Jaggi21c39a72017-10-20 15:47:51 +0200212 }
213 }
214 });
chaviwc5eb8162018-05-25 16:18:42 -0700215 a.mAnim = anim;
216 mRunningAnimations.put(a.mLeash, a);
217
Jorim Jaggi6c7e5612017-12-12 02:17:10 +0100218 anim.start();
Jorim Jaggi2d74faf2017-12-18 19:21:27 +0100219 if (a.mAnimSpec.canSkipFirstFrame()) {
220 // If we can skip the first frame, we start one frame later.
221 anim.setCurrentPlayTime(mChoreographer.getFrameIntervalNanos() / NANOS_PER_MS);
222 }
223
224 // Immediately start the animation by manually applying an animation frame. Otherwise, the
225 // start time would only be set in the next frame, leading to a delay.
226 anim.doAnimationFrame(mChoreographer.getFrameTime());
Jorim Jaggi21c39a72017-10-20 15:47:51 +0200227 }
228
229 private void applyTransformation(RunningAnimation a, Transaction t, long currentPlayTime) {
Jorim Jaggiaa763cd2018-03-22 23:20:36 +0100230 if (a.mAnimSpec.needsEarlyWakeup()) {
231 t.setEarlyWakeup();
232 }
Jorim Jaggia5e10572017-11-15 14:36:26 +0100233 a.mAnimSpec.apply(t, a.mLeash, currentPlayTime);
Jorim Jaggi21c39a72017-10-20 15:47:51 +0200234 }
235
Jorim Jaggid6d97162018-01-05 18:28:36 +0100236 private void startAnimations(long frameTimeNanos) {
Jorim Jaggi21c39a72017-10-20 15:47:51 +0200237 synchronized (mLock) {
238 startPendingAnimationsLocked();
239 }
Jorim Jaggib6ba4332018-07-10 00:36:57 +0200240 mPowerManagerInternal.powerHint(PowerHint.INTERACTION, 0);
Jorim Jaggi21c39a72017-10-20 15:47:51 +0200241 }
242
243 private void scheduleApplyTransaction() {
244 if (!mApplyScheduled) {
245 mChoreographer.postCallback(CALLBACK_TRAVERSAL, mApplyTransactionRunnable,
246 null /* token */);
247 mApplyScheduled = true;
248 }
249 }
250
251 private void applyTransaction() {
Jorim Jaggi32fd84a2017-11-20 19:59:42 +0100252 mFrameTransaction.setAnimationTransaction();
Jorim Jaggi21c39a72017-10-20 15:47:51 +0200253 mFrameTransaction.apply();
254 mApplyScheduled = false;
255 }
256
257 private static final class RunningAnimation {
Jorim Jaggia5e10572017-11-15 14:36:26 +0100258 final AnimationSpec mAnimSpec;
259 final SurfaceControl mLeash;
260 final Runnable mFinishCallback;
Jorim Jaggi6c7e5612017-12-12 02:17:10 +0100261 ValueAnimator mAnim;
262
263 @GuardedBy("mCancelLock")
264 private boolean mCancelled;
Jorim Jaggi21c39a72017-10-20 15:47:51 +0200265
266 RunningAnimation(AnimationSpec animSpec, SurfaceControl leash, Runnable finishCallback) {
Jorim Jaggia5e10572017-11-15 14:36:26 +0100267 mAnimSpec = animSpec;
268 mLeash = leash;
269 mFinishCallback = finishCallback;
Jorim Jaggi21c39a72017-10-20 15:47:51 +0200270 }
271 }
272
Jorim Jaggi6c7e5612017-12-12 02:17:10 +0100273 @VisibleForTesting
274 interface AnimatorFactory {
275 ValueAnimator makeAnimator();
276 }
277
Jorim Jaggi21c39a72017-10-20 15:47:51 +0200278 /**
279 * Value animator that uses sf-vsync signal to tick.
280 */
281 private class SfValueAnimator extends ValueAnimator {
282
283 SfValueAnimator() {
284 setFloatValues(0f, 1f);
285 }
286
287 @Override
288 public AnimationHandler getAnimationHandler() {
289 return mAnimationHandler;
290 }
291 }
292}