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.Boost; 30 import android.os.Handler; 31 import android.os.PowerManagerInternal; 32 import android.util.ArrayMap; 33 import android.view.Choreographer; 34 import android.view.SurfaceControl; 35 import android.view.SurfaceControl.Transaction; 36 37 import com.android.internal.annotations.GuardedBy; 38 import com.android.internal.annotations.VisibleForTesting; 39 import com.android.internal.graphics.SfVsyncFrameCallbackProvider; 40 import com.android.server.AnimationThread; 41 import com.android.server.wm.LocalAnimationAdapter.AnimationSpec; 42 43 import java.util.function.Supplier; 44 45 /** 46 * Class to run animations without holding the window manager lock. 47 */ 48 class SurfaceAnimationRunner { 49 50 private final Object mLock = new Object(); 51 52 /** 53 * Lock for cancelling animations. Must be acquired on it's own, or after acquiring 54 * {@link #mLock} 55 */ 56 private final Object mCancelLock = new Object(); 57 58 @VisibleForTesting 59 Choreographer mChoreographer; 60 61 private final Handler mAnimationThreadHandler = AnimationThread.getHandler(); 62 private final Handler mSurfaceAnimationHandler = SurfaceAnimationThread.getHandler(); 63 private final Runnable mApplyTransactionRunnable = this::applyTransaction; 64 private final AnimationHandler mAnimationHandler; 65 private final Transaction mFrameTransaction; 66 private final AnimatorFactory mAnimatorFactory; 67 private final PowerManagerInternal mPowerManagerInternal; 68 private boolean mApplyScheduled; 69 70 @GuardedBy("mLock") 71 @VisibleForTesting 72 final ArrayMap<SurfaceControl, RunningAnimation> mPendingAnimations = new ArrayMap<>(); 73 74 @GuardedBy("mLock") 75 @VisibleForTesting 76 final ArrayMap<SurfaceControl, RunningAnimation> mRunningAnimations = new ArrayMap<>(); 77 78 @GuardedBy("mLock") 79 private boolean mAnimationStartDeferred; 80 81 /** 82 * There should only ever be one instance of this class. Usual spot for it is with 83 * {@link WindowManagerService} 84 */ SurfaceAnimationRunner(Supplier<Transaction> transactionFactory, PowerManagerInternal powerManagerInternal)85 SurfaceAnimationRunner(Supplier<Transaction> transactionFactory, 86 PowerManagerInternal powerManagerInternal) { 87 this(null /* callbackProvider */, null /* animatorFactory */, 88 transactionFactory.get(), powerManagerInternal); 89 } 90 91 @VisibleForTesting SurfaceAnimationRunner(@ullable AnimationFrameCallbackProvider callbackProvider, AnimatorFactory animatorFactory, Transaction frameTransaction, PowerManagerInternal powerManagerInternal)92 SurfaceAnimationRunner(@Nullable AnimationFrameCallbackProvider callbackProvider, 93 AnimatorFactory animatorFactory, Transaction frameTransaction, 94 PowerManagerInternal powerManagerInternal) { 95 mSurfaceAnimationHandler.runWithScissors(() -> mChoreographer = getSfInstance(), 96 0 /* timeout */); 97 mFrameTransaction = frameTransaction; 98 mAnimationHandler = new AnimationHandler(); 99 mAnimationHandler.setProvider(callbackProvider != null 100 ? callbackProvider 101 : new SfVsyncFrameCallbackProvider(mChoreographer)); 102 mAnimatorFactory = animatorFactory != null 103 ? animatorFactory 104 : SfValueAnimator::new; 105 mPowerManagerInternal = powerManagerInternal; 106 } 107 108 /** 109 * Defers starting of animations until {@link #continueStartingAnimations} is called. This 110 * method is NOT nestable. 111 * 112 * @see #continueStartingAnimations 113 */ deferStartingAnimations()114 void deferStartingAnimations() { 115 synchronized (mLock) { 116 mAnimationStartDeferred = true; 117 } 118 } 119 120 /** 121 * Continues starting of animations. 122 * 123 * @see #deferStartingAnimations 124 */ continueStartingAnimations()125 void continueStartingAnimations() { 126 synchronized (mLock) { 127 mAnimationStartDeferred = false; 128 if (!mPendingAnimations.isEmpty()) { 129 mChoreographer.postFrameCallback(this::startAnimations); 130 } 131 } 132 } 133 startAnimation(AnimationSpec a, SurfaceControl animationLeash, Transaction t, Runnable finishCallback)134 void startAnimation(AnimationSpec a, SurfaceControl animationLeash, Transaction t, 135 Runnable finishCallback) { 136 synchronized (mLock) { 137 final RunningAnimation runningAnim = new RunningAnimation(a, animationLeash, 138 finishCallback); 139 mPendingAnimations.put(animationLeash, runningAnim); 140 if (!mAnimationStartDeferred) { 141 mChoreographer.postFrameCallback(this::startAnimations); 142 } 143 144 // Some animations (e.g. move animations) require the initial transform to be applied 145 // immediately. 146 applyTransformation(runningAnim, t, 0 /* currentPlayTime */); 147 } 148 } 149 onAnimationCancelled(SurfaceControl leash)150 void onAnimationCancelled(SurfaceControl leash) { 151 synchronized (mLock) { 152 if (mPendingAnimations.containsKey(leash)) { 153 mPendingAnimations.remove(leash); 154 return; 155 } 156 final RunningAnimation anim = mRunningAnimations.get(leash); 157 if (anim != null) { 158 mRunningAnimations.remove(leash); 159 synchronized (mCancelLock) { 160 anim.mCancelled = true; 161 } 162 mSurfaceAnimationHandler.post(() -> { 163 anim.mAnim.cancel(); 164 applyTransaction(); 165 }); 166 } 167 } 168 } 169 170 @GuardedBy("mLock") startPendingAnimationsLocked()171 private void startPendingAnimationsLocked() { 172 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) { 173 startAnimationLocked(mPendingAnimations.valueAt(i)); 174 } 175 mPendingAnimations.clear(); 176 } 177 178 @GuardedBy("mLock") startAnimationLocked(RunningAnimation a)179 private void startAnimationLocked(RunningAnimation a) { 180 final ValueAnimator anim = mAnimatorFactory.makeAnimator(); 181 182 // Animation length is already expected to be scaled. 183 anim.overrideDurationScale(1.0f); 184 anim.setDuration(a.mAnimSpec.getDuration()); 185 anim.addUpdateListener(animation -> { 186 synchronized (mCancelLock) { 187 if (!a.mCancelled) { 188 final long duration = anim.getDuration(); 189 long currentPlayTime = anim.getCurrentPlayTime(); 190 if (currentPlayTime > duration) { 191 currentPlayTime = duration; 192 } 193 applyTransformation(a, mFrameTransaction, currentPlayTime); 194 } 195 } 196 197 // Transaction will be applied in the commit phase. 198 scheduleApplyTransaction(); 199 }); 200 201 anim.addListener(new AnimatorListenerAdapter() { 202 @Override 203 public void onAnimationStart(Animator animation) { 204 synchronized (mCancelLock) { 205 if (!a.mCancelled) { 206 // TODO: change this back to use show instead of alpha when b/138459974 is 207 // fixed. 208 mFrameTransaction.setAlpha(a.mLeash, 1); 209 } 210 } 211 } 212 213 @Override 214 public void onAnimationEnd(Animator animation) { 215 synchronized (mLock) { 216 mRunningAnimations.remove(a.mLeash); 217 synchronized (mCancelLock) { 218 if (!a.mCancelled) { 219 220 // Post on other thread that we can push final state without jank. 221 mAnimationThreadHandler.post(a.mFinishCallback); 222 } 223 } 224 } 225 } 226 }); 227 a.mAnim = anim; 228 mRunningAnimations.put(a.mLeash, a); 229 230 anim.start(); 231 if (a.mAnimSpec.canSkipFirstFrame()) { 232 // If we can skip the first frame, we start one frame later. 233 anim.setCurrentPlayTime(mChoreographer.getFrameIntervalNanos() / NANOS_PER_MS); 234 } 235 236 // Immediately start the animation by manually applying an animation frame. Otherwise, the 237 // start time would only be set in the next frame, leading to a delay. 238 anim.doAnimationFrame(mChoreographer.getFrameTime()); 239 } 240 applyTransformation(RunningAnimation a, Transaction t, long currentPlayTime)241 private void applyTransformation(RunningAnimation a, Transaction t, long currentPlayTime) { 242 a.mAnimSpec.apply(t, a.mLeash, currentPlayTime); 243 } 244 startAnimations(long frameTimeNanos)245 private void startAnimations(long frameTimeNanos) { 246 synchronized (mLock) { 247 startPendingAnimationsLocked(); 248 } 249 mPowerManagerInternal.setPowerBoost(Boost.INTERACTION, 0); 250 } 251 scheduleApplyTransaction()252 private void scheduleApplyTransaction() { 253 if (!mApplyScheduled) { 254 mChoreographer.postCallback(CALLBACK_TRAVERSAL, mApplyTransactionRunnable, 255 null /* token */); 256 mApplyScheduled = true; 257 } 258 } 259 applyTransaction()260 private void applyTransaction() { 261 mFrameTransaction.setAnimationTransaction(); 262 mFrameTransaction.setFrameTimelineVsync(mChoreographer.getVsyncId()); 263 mFrameTransaction.apply(); 264 mApplyScheduled = false; 265 } 266 267 private static final class RunningAnimation { 268 final AnimationSpec mAnimSpec; 269 final SurfaceControl mLeash; 270 final Runnable mFinishCallback; 271 ValueAnimator mAnim; 272 273 @GuardedBy("mCancelLock") 274 private boolean mCancelled; 275 RunningAnimation(AnimationSpec animSpec, SurfaceControl leash, Runnable finishCallback)276 RunningAnimation(AnimationSpec animSpec, SurfaceControl leash, Runnable finishCallback) { 277 mAnimSpec = animSpec; 278 mLeash = leash; 279 mFinishCallback = finishCallback; 280 } 281 } 282 283 @VisibleForTesting 284 interface AnimatorFactory { makeAnimator()285 ValueAnimator makeAnimator(); 286 } 287 288 /** 289 * Value animator that uses sf-vsync signal to tick. 290 */ 291 private class SfValueAnimator extends ValueAnimator { 292 SfValueAnimator()293 SfValueAnimator() { 294 setFloatValues(0f, 1f); 295 } 296 297 @Override getAnimationHandler()298 public AnimationHandler getAnimationHandler() { 299 return mAnimationHandler; 300 } 301 } 302 } 303