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 android.util.TimeUtils.NANOS_PER_MS; 20 import static android.view.Choreographer.CALLBACK_TRAVERSAL; 21 import static android.view.Choreographer.getSfInstance; 22 23 import android.animation.AnimationHandler; 24 import android.animation.AnimationHandler.AnimationFrameCallbackProvider; 25 import android.animation.Animator; 26 import android.animation.AnimatorListenerAdapter; 27 import android.animation.ValueAnimator; 28 import android.annotation.Nullable; 29 import android.hardware.power.V1_0.PowerHint; 30 import android.os.PowerManagerInternal; 31 import android.util.ArrayMap; 32 import android.view.Choreographer; 33 import android.view.SurfaceControl; 34 import android.view.SurfaceControl.Transaction; 35 36 import com.android.internal.annotations.GuardedBy; 37 import com.android.internal.annotations.VisibleForTesting; 38 import com.android.internal.graphics.SfVsyncFrameCallbackProvider; 39 import com.android.server.AnimationThread; 40 import com.android.server.wm.LocalAnimationAdapter.AnimationSpec; 41 42 /** 43 * Class to run animations without holding the window manager lock. 44 */ 45 class SurfaceAnimationRunner { 46 47 private final Object mLock = new Object(); 48 49 /** 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 55 @VisibleForTesting 56 Choreographer mChoreographer; 57 58 private final Runnable mApplyTransactionRunnable = this::applyTransaction; 59 private final AnimationHandler mAnimationHandler; 60 private final Transaction mFrameTransaction; 61 private final AnimatorFactory mAnimatorFactory; 62 private final PowerManagerInternal mPowerManagerInternal; 63 private boolean mApplyScheduled; 64 65 @GuardedBy("mLock") 66 @VisibleForTesting 67 final ArrayMap<SurfaceControl, RunningAnimation> mPendingAnimations = new ArrayMap<>(); 68 69 @GuardedBy("mLock") 70 @VisibleForTesting 71 final ArrayMap<SurfaceControl, RunningAnimation> mRunningAnimations = new ArrayMap<>(); 72 73 @GuardedBy("mLock") 74 private boolean mAnimationStartDeferred; 75 SurfaceAnimationRunner(PowerManagerInternal powerManagerInternal)76 SurfaceAnimationRunner(PowerManagerInternal powerManagerInternal) { 77 this(null /* callbackProvider */, null /* animatorFactory */, new Transaction(), 78 powerManagerInternal); 79 } 80 81 @VisibleForTesting SurfaceAnimationRunner(@ullable AnimationFrameCallbackProvider callbackProvider, AnimatorFactory animatorFactory, Transaction frameTransaction, PowerManagerInternal powerManagerInternal)82 SurfaceAnimationRunner(@Nullable AnimationFrameCallbackProvider callbackProvider, 83 AnimatorFactory animatorFactory, Transaction frameTransaction, 84 PowerManagerInternal powerManagerInternal) { 85 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)); 92 mAnimatorFactory = animatorFactory != null 93 ? animatorFactory 94 : SfValueAnimator::new; 95 mPowerManagerInternal = powerManagerInternal; 96 } 97 98 /** 99 * Defers starting of animations until {@link #continueStartingAnimations} is called. This 100 * method is NOT nestable. 101 * 102 * @see #continueStartingAnimations 103 */ deferStartingAnimations()104 void deferStartingAnimations() { 105 synchronized (mLock) { 106 mAnimationStartDeferred = true; 107 } 108 } 109 110 /** 111 * Continues starting of animations. 112 * 113 * @see #deferStartingAnimations 114 */ continueStartingAnimations()115 void continueStartingAnimations() { 116 synchronized (mLock) { 117 mAnimationStartDeferred = false; 118 if (!mPendingAnimations.isEmpty()) { 119 mChoreographer.postFrameCallback(this::startAnimations); 120 } 121 } 122 } 123 startAnimation(AnimationSpec a, SurfaceControl animationLeash, Transaction t, Runnable finishCallback)124 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); 130 if (!mAnimationStartDeferred) { 131 mChoreographer.postFrameCallback(this::startAnimations); 132 } 133 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 onAnimationCancelled(SurfaceControl leash)140 void onAnimationCancelled(SurfaceControl leash) { 141 synchronized (mLock) { 142 if (mPendingAnimations.containsKey(leash)) { 143 mPendingAnimations.remove(leash); 144 return; 145 } 146 final RunningAnimation anim = mRunningAnimations.get(leash); 147 if (anim != null) { 148 mRunningAnimations.remove(leash); 149 synchronized (mCancelLock) { 150 anim.mCancelled = true; 151 } 152 SurfaceAnimationThread.getHandler().post(() -> { 153 anim.mAnim.cancel(); 154 applyTransaction(); 155 }); 156 } 157 } 158 } 159 160 @GuardedBy("mLock") startPendingAnimationsLocked()161 private void startPendingAnimationsLocked() { 162 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) { 163 startAnimationLocked(mPendingAnimations.valueAt(i)); 164 } 165 mPendingAnimations.clear(); 166 } 167 168 @GuardedBy("mLock") startAnimationLocked(RunningAnimation a)169 private void startAnimationLocked(RunningAnimation a) { 170 final ValueAnimator anim = mAnimatorFactory.makeAnimator(); 171 172 // Animation length is already expected to be scaled. 173 anim.overrideDurationScale(1.0f); 174 anim.setDuration(a.mAnimSpec.getDuration()); 175 anim.addUpdateListener(animation -> { 176 synchronized (mCancelLock) { 177 if (!a.mCancelled) { 178 final long duration = anim.getDuration(); 179 long currentPlayTime = anim.getCurrentPlayTime(); 180 if (currentPlayTime > duration) { 181 currentPlayTime = duration; 182 } 183 applyTransformation(a, mFrameTransaction, currentPlayTime); 184 } 185 } 186 187 // Transaction will be applied in the commit phase. 188 scheduleApplyTransaction(); 189 }); 190 191 anim.addListener(new AnimatorListenerAdapter() { 192 @Override 193 public void onAnimationStart(Animator animation) { 194 synchronized (mCancelLock) { 195 if (!a.mCancelled) { 196 mFrameTransaction.show(a.mLeash); 197 } 198 } 199 } 200 201 @Override 202 public void onAnimationEnd(Animator animation) { 203 synchronized (mLock) { 204 mRunningAnimations.remove(a.mLeash); 205 synchronized (mCancelLock) { 206 if (!a.mCancelled) { 207 208 // Post on other thread that we can push final state without jank. 209 AnimationThread.getHandler().post(a.mFinishCallback); 210 } 211 } 212 } 213 } 214 }); 215 a.mAnim = anim; 216 mRunningAnimations.put(a.mLeash, a); 217 218 anim.start(); 219 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()); 227 } 228 applyTransformation(RunningAnimation a, Transaction t, long currentPlayTime)229 private void applyTransformation(RunningAnimation a, Transaction t, long currentPlayTime) { 230 if (a.mAnimSpec.needsEarlyWakeup()) { 231 t.setEarlyWakeup(); 232 } 233 a.mAnimSpec.apply(t, a.mLeash, currentPlayTime); 234 } 235 startAnimations(long frameTimeNanos)236 private void startAnimations(long frameTimeNanos) { 237 synchronized (mLock) { 238 startPendingAnimationsLocked(); 239 } 240 mPowerManagerInternal.powerHint(PowerHint.INTERACTION, 0); 241 } 242 scheduleApplyTransaction()243 private void scheduleApplyTransaction() { 244 if (!mApplyScheduled) { 245 mChoreographer.postCallback(CALLBACK_TRAVERSAL, mApplyTransactionRunnable, 246 null /* token */); 247 mApplyScheduled = true; 248 } 249 } 250 applyTransaction()251 private void applyTransaction() { 252 mFrameTransaction.setAnimationTransaction(); 253 mFrameTransaction.apply(); 254 mApplyScheduled = false; 255 } 256 257 private static final class RunningAnimation { 258 final AnimationSpec mAnimSpec; 259 final SurfaceControl mLeash; 260 final Runnable mFinishCallback; 261 ValueAnimator mAnim; 262 263 @GuardedBy("mCancelLock") 264 private boolean mCancelled; 265 RunningAnimation(AnimationSpec animSpec, SurfaceControl leash, Runnable finishCallback)266 RunningAnimation(AnimationSpec animSpec, SurfaceControl leash, Runnable finishCallback) { 267 mAnimSpec = animSpec; 268 mLeash = leash; 269 mFinishCallback = finishCallback; 270 } 271 } 272 273 @VisibleForTesting 274 interface AnimatorFactory { makeAnimator()275 ValueAnimator makeAnimator(); 276 } 277 278 /** 279 * Value animator that uses sf-vsync signal to tick. 280 */ 281 private class SfValueAnimator extends ValueAnimator { 282 SfValueAnimator()283 SfValueAnimator() { 284 setFloatValues(0f, 1f); 285 } 286 287 @Override getAnimationHandler()288 public AnimationHandler getAnimationHandler() { 289 return mAnimationHandler; 290 } 291 } 292 } 293