1 /* 2 * Copyright (C) 2014 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.view.Display.DEFAULT_DISPLAY; 20 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE; 21 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS; 22 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; 23 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 24 import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE; 25 import static com.android.server.wm.WindowSurfacePlacer.SET_UPDATE_ROTATION; 26 27 import android.content.Context; 28 import android.os.Trace; 29 import android.util.Slog; 30 import android.util.SparseArray; 31 import android.util.TimeUtils; 32 import android.view.Choreographer; 33 import android.view.SurfaceControl; 34 35 import com.android.server.AnimationThread; 36 import com.android.server.policy.WindowManagerPolicy; 37 38 import java.io.PrintWriter; 39 import java.util.ArrayList; 40 41 /** 42 * Singleton class that carries out the animations and Surface operations in a separate task 43 * on behalf of WindowManagerService. 44 */ 45 public class WindowAnimator { 46 private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowAnimator" : TAG_WM; 47 48 final WindowManagerService mService; 49 final Context mContext; 50 final WindowManagerPolicy mPolicy; 51 52 /** Is any window animating? */ 53 private boolean mAnimating; 54 private boolean mLastRootAnimating; 55 56 final Choreographer.FrameCallback mAnimationFrameCallback; 57 58 /** Time of current animation step. Reset on each iteration */ 59 long mCurrentTime; 60 61 boolean mAppWindowAnimating; 62 /** Skip repeated AppWindowTokens initialization. Note that AppWindowsToken's version of this 63 * is a long initialized to Long.MIN_VALUE so that it doesn't match this value on startup. */ 64 int mAnimTransactionSequence; 65 66 /** Window currently running an animation that has requested it be detached 67 * from the wallpaper. This means we need to ensure the wallpaper is 68 * visible behind it in case it animates in a way that would allow it to be 69 * seen. If multiple windows satisfy this, use the lowest window. */ 70 WindowState mWindowDetachedWallpaper = null; 71 72 int mBulkUpdateParams = 0; 73 Object mLastWindowFreezeSource; 74 75 SparseArray<DisplayContentsAnimator> mDisplayContentsAnimators = new SparseArray<>(2); 76 77 private boolean mInitialized = false; 78 79 // When set to true the animator will go over all windows after an animation frame is posted and 80 // check if some got replaced and can be removed. 81 private boolean mRemoveReplacedWindows = false; 82 83 private Choreographer mChoreographer; 84 85 /** 86 * Indicates whether we have an animation frame callback scheduled, which will happen at 87 * vsync-app and then schedule the animation tick at the right time (vsync-sf). 88 */ 89 private boolean mAnimationFrameCallbackScheduled; 90 91 /** 92 * A list of runnable that need to be run after {@link WindowContainer#prepareSurfaces} is 93 * executed and the corresponding transaction is closed and applied. 94 */ 95 private final ArrayList<Runnable> mAfterPrepareSurfacesRunnables = new ArrayList<>(); 96 private boolean mInExecuteAfterPrepareSurfacesRunnables; 97 98 private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction(); 99 WindowAnimator(final WindowManagerService service)100 WindowAnimator(final WindowManagerService service) { 101 mService = service; 102 mContext = service.mContext; 103 mPolicy = service.mPolicy; 104 AnimationThread.getHandler().runWithScissors( 105 () -> mChoreographer = Choreographer.getSfInstance(), 0 /* timeout */); 106 107 mAnimationFrameCallback = frameTimeNs -> { 108 synchronized (mService.mWindowMap) { 109 mAnimationFrameCallbackScheduled = false; 110 } 111 animate(frameTimeNs); 112 }; 113 } 114 addDisplayLocked(final int displayId)115 void addDisplayLocked(final int displayId) { 116 // Create the DisplayContentsAnimator object by retrieving it if the associated 117 // {@link DisplayContent} exists. 118 getDisplayContentsAnimatorLocked(displayId); 119 if (displayId == DEFAULT_DISPLAY) { 120 mInitialized = true; 121 } 122 } 123 removeDisplayLocked(final int displayId)124 void removeDisplayLocked(final int displayId) { 125 final DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.get(displayId); 126 if (displayAnimator != null) { 127 if (displayAnimator.mScreenRotationAnimation != null) { 128 displayAnimator.mScreenRotationAnimation.kill(); 129 displayAnimator.mScreenRotationAnimation = null; 130 } 131 } 132 133 mDisplayContentsAnimators.delete(displayId); 134 } 135 136 /** 137 * DO NOT HOLD THE WINDOW MANAGER LOCK WHILE CALLING THIS METHOD. Reason: the method closes 138 * an animation transaction, that might be blocking until the next sf-vsync, so we want to make 139 * sure other threads can make progress if this happens. 140 */ animate(long frameTimeNs)141 private void animate(long frameTimeNs) { 142 143 synchronized (mService.mWindowMap) { 144 if (!mInitialized) { 145 return; 146 } 147 148 // Schedule next frame already such that back-pressure happens continuously 149 scheduleAnimation(); 150 } 151 152 synchronized (mService.mWindowMap) { 153 mCurrentTime = frameTimeNs / TimeUtils.NANOS_PER_MS; 154 mBulkUpdateParams = SET_ORIENTATION_CHANGE_COMPLETE; 155 mAnimating = false; 156 if (DEBUG_WINDOW_TRACE) { 157 Slog.i(TAG, "!!! animate: entry time=" + mCurrentTime); 158 } 159 160 if (SHOW_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION animate"); 161 mService.openSurfaceTransaction(); 162 try { 163 final AccessibilityController accessibilityController = 164 mService.mAccessibilityController; 165 final int numDisplays = mDisplayContentsAnimators.size(); 166 for (int i = 0; i < numDisplays; i++) { 167 final int displayId = mDisplayContentsAnimators.keyAt(i); 168 final DisplayContent dc = mService.mRoot.getDisplayContent(displayId); 169 DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.valueAt(i); 170 171 final ScreenRotationAnimation screenRotationAnimation = 172 displayAnimator.mScreenRotationAnimation; 173 if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) { 174 if (screenRotationAnimation.stepAnimationLocked(mCurrentTime)) { 175 setAnimating(true); 176 } else { 177 mBulkUpdateParams |= SET_UPDATE_ROTATION; 178 screenRotationAnimation.kill(); 179 displayAnimator.mScreenRotationAnimation = null; 180 181 //TODO (multidisplay): Accessibility supported only for the default 182 // display. 183 if (accessibilityController != null && dc.isDefaultDisplay) { 184 // We just finished rotation animation which means we did not 185 // announce the rotation and waited for it to end, announce now. 186 accessibilityController.onRotationChangedLocked( 187 mService.getDefaultDisplayContentLocked()); 188 } 189 } 190 } 191 192 // Update animations of all applications, including those 193 // associated with exiting/removed apps 194 ++mAnimTransactionSequence; 195 dc.updateWindowsForAnimator(this); 196 dc.updateWallpaperForAnimator(this); 197 dc.prepareSurfaces(); 198 } 199 200 for (int i = 0; i < numDisplays; i++) { 201 final int displayId = mDisplayContentsAnimators.keyAt(i); 202 final DisplayContent dc = mService.mRoot.getDisplayContent(displayId); 203 204 dc.checkAppWindowsReadyToShow(); 205 206 final ScreenRotationAnimation screenRotationAnimation = 207 mDisplayContentsAnimators.valueAt(i).mScreenRotationAnimation; 208 if (screenRotationAnimation != null) { 209 screenRotationAnimation.updateSurfaces(mTransaction); 210 } 211 orAnimating(dc.getDockedDividerController().animate(mCurrentTime)); 212 //TODO (multidisplay): Magnification is supported only for the default display. 213 if (accessibilityController != null && dc.isDefaultDisplay) { 214 accessibilityController.drawMagnifiedRegionBorderIfNeededLocked(); 215 } 216 } 217 218 if (!mAnimating) { 219 cancelAnimation(); 220 } 221 222 if (mService.mWatermark != null) { 223 mService.mWatermark.drawIfNeeded(); 224 } 225 226 SurfaceControl.mergeToGlobalTransaction(mTransaction); 227 } catch (RuntimeException e) { 228 Slog.wtf(TAG, "Unhandled exception in Window Manager", e); 229 } finally { 230 mService.closeSurfaceTransaction("WindowAnimator"); 231 if (SHOW_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION animate"); 232 } 233 234 boolean hasPendingLayoutChanges = mService.mRoot.hasPendingLayoutChanges(this); 235 boolean doRequest = false; 236 if (mBulkUpdateParams != 0) { 237 doRequest = mService.mRoot.copyAnimToLayoutParams(); 238 } 239 240 if (hasPendingLayoutChanges || doRequest) { 241 mService.mWindowPlacerLocked.requestTraversal(); 242 } 243 244 final boolean rootAnimating = mService.mRoot.isSelfOrChildAnimating(); 245 if (rootAnimating && !mLastRootAnimating) { 246 247 // Usually app transitions but quite a load onto the system already (with all the 248 // things happening in app), so pause task snapshot persisting to not increase the 249 // load. 250 mService.mTaskSnapshotController.setPersisterPaused(true); 251 Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0); 252 } 253 if (!rootAnimating && mLastRootAnimating) { 254 mService.mWindowPlacerLocked.requestTraversal(); 255 mService.mTaskSnapshotController.setPersisterPaused(false); 256 Trace.asyncTraceEnd(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0); 257 } 258 259 mLastRootAnimating = rootAnimating; 260 261 if (mRemoveReplacedWindows) { 262 mService.mRoot.removeReplacedWindows(); 263 mRemoveReplacedWindows = false; 264 } 265 266 mService.destroyPreservedSurfaceLocked(); 267 268 executeAfterPrepareSurfacesRunnables(); 269 270 if (DEBUG_WINDOW_TRACE) { 271 Slog.i(TAG, "!!! animate: exit mAnimating=" + mAnimating 272 + " mBulkUpdateParams=" + Integer.toHexString(mBulkUpdateParams) 273 + " mPendingLayoutChanges(DEFAULT_DISPLAY)=" 274 + Integer.toHexString(getPendingLayoutChanges(DEFAULT_DISPLAY))); 275 } 276 } 277 } 278 bulkUpdateParamsToString(int bulkUpdateParams)279 private static String bulkUpdateParamsToString(int bulkUpdateParams) { 280 StringBuilder builder = new StringBuilder(128); 281 if ((bulkUpdateParams & WindowSurfacePlacer.SET_UPDATE_ROTATION) != 0) { 282 builder.append(" UPDATE_ROTATION"); 283 } 284 if ((bulkUpdateParams & WindowSurfacePlacer.SET_WALLPAPER_MAY_CHANGE) != 0) { 285 builder.append(" WALLPAPER_MAY_CHANGE"); 286 } 287 if ((bulkUpdateParams & WindowSurfacePlacer.SET_FORCE_HIDING_CHANGED) != 0) { 288 builder.append(" FORCE_HIDING_CHANGED"); 289 } 290 if ((bulkUpdateParams & WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE) != 0) { 291 builder.append(" ORIENTATION_CHANGE_COMPLETE"); 292 } 293 return builder.toString(); 294 } 295 dumpLocked(PrintWriter pw, String prefix, boolean dumpAll)296 public void dumpLocked(PrintWriter pw, String prefix, boolean dumpAll) { 297 final String subPrefix = " " + prefix; 298 final String subSubPrefix = " " + subPrefix; 299 300 for (int i = 0; i < mDisplayContentsAnimators.size(); i++) { 301 pw.print(prefix); pw.print("DisplayContentsAnimator #"); 302 pw.print(mDisplayContentsAnimators.keyAt(i)); 303 pw.println(":"); 304 final DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.valueAt(i); 305 final DisplayContent dc = 306 mService.mRoot.getDisplayContent(mDisplayContentsAnimators.keyAt(i)); 307 dc.dumpWindowAnimators(pw, subPrefix); 308 if (displayAnimator.mScreenRotationAnimation != null) { 309 pw.print(subPrefix); pw.println("mScreenRotationAnimation:"); 310 displayAnimator.mScreenRotationAnimation.printTo(subSubPrefix, pw); 311 } else if (dumpAll) { 312 pw.print(subPrefix); pw.println("no ScreenRotationAnimation "); 313 } 314 pw.println(); 315 } 316 317 pw.println(); 318 319 if (dumpAll) { 320 pw.print(prefix); pw.print("mAnimTransactionSequence="); 321 pw.print(mAnimTransactionSequence); 322 pw.print(prefix); pw.print("mCurrentTime="); 323 pw.println(TimeUtils.formatUptime(mCurrentTime)); 324 } 325 if (mBulkUpdateParams != 0) { 326 pw.print(prefix); pw.print("mBulkUpdateParams=0x"); 327 pw.print(Integer.toHexString(mBulkUpdateParams)); 328 pw.println(bulkUpdateParamsToString(mBulkUpdateParams)); 329 } 330 if (mWindowDetachedWallpaper != null) { 331 pw.print(prefix); pw.print("mWindowDetachedWallpaper="); 332 pw.println(mWindowDetachedWallpaper); 333 } 334 } 335 getPendingLayoutChanges(final int displayId)336 int getPendingLayoutChanges(final int displayId) { 337 if (displayId < 0) { 338 return 0; 339 } 340 final DisplayContent displayContent = mService.mRoot.getDisplayContent(displayId); 341 return (displayContent != null) ? displayContent.pendingLayoutChanges : 0; 342 } 343 setPendingLayoutChanges(final int displayId, final int changes)344 void setPendingLayoutChanges(final int displayId, final int changes) { 345 if (displayId < 0) { 346 return; 347 } 348 final DisplayContent displayContent = mService.mRoot.getDisplayContent(displayId); 349 if (displayContent != null) { 350 displayContent.pendingLayoutChanges |= changes; 351 } 352 } 353 getDisplayContentsAnimatorLocked(int displayId)354 private DisplayContentsAnimator getDisplayContentsAnimatorLocked(int displayId) { 355 if (displayId < 0) { 356 return null; 357 } 358 359 DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.get(displayId); 360 361 // It is possible that this underlying {@link DisplayContent} has been removed. In this 362 // case, we do not want to create an animator associated with it as {link #animate} will 363 // fail. 364 if (displayAnimator == null && mService.mRoot.getDisplayContent(displayId) != null) { 365 displayAnimator = new DisplayContentsAnimator(); 366 mDisplayContentsAnimators.put(displayId, displayAnimator); 367 } 368 return displayAnimator; 369 } 370 setScreenRotationAnimationLocked(int displayId, ScreenRotationAnimation animation)371 void setScreenRotationAnimationLocked(int displayId, ScreenRotationAnimation animation) { 372 final DisplayContentsAnimator animator = getDisplayContentsAnimatorLocked(displayId); 373 374 if (animator != null) { 375 animator.mScreenRotationAnimation = animation; 376 } 377 } 378 getScreenRotationAnimationLocked(int displayId)379 ScreenRotationAnimation getScreenRotationAnimationLocked(int displayId) { 380 if (displayId < 0) { 381 return null; 382 } 383 384 DisplayContentsAnimator animator = getDisplayContentsAnimatorLocked(displayId); 385 return animator != null? animator.mScreenRotationAnimation : null; 386 } 387 requestRemovalOfReplacedWindows(WindowState win)388 void requestRemovalOfReplacedWindows(WindowState win) { 389 mRemoveReplacedWindows = true; 390 } 391 scheduleAnimation()392 void scheduleAnimation() { 393 if (!mAnimationFrameCallbackScheduled) { 394 mAnimationFrameCallbackScheduled = true; 395 mChoreographer.postFrameCallback(mAnimationFrameCallback); 396 } 397 } 398 cancelAnimation()399 private void cancelAnimation() { 400 if (mAnimationFrameCallbackScheduled) { 401 mAnimationFrameCallbackScheduled = false; 402 mChoreographer.removeFrameCallback(mAnimationFrameCallback); 403 } 404 } 405 406 private class DisplayContentsAnimator { 407 ScreenRotationAnimation mScreenRotationAnimation = null; 408 } 409 isAnimating()410 boolean isAnimating() { 411 return mAnimating; 412 } 413 isAnimationScheduled()414 boolean isAnimationScheduled() { 415 return mAnimationFrameCallbackScheduled; 416 } 417 getChoreographer()418 Choreographer getChoreographer() { 419 return mChoreographer; 420 } 421 setAnimating(boolean animating)422 void setAnimating(boolean animating) { 423 mAnimating = animating; 424 } 425 orAnimating(boolean animating)426 void orAnimating(boolean animating) { 427 mAnimating |= animating; 428 } 429 430 /** 431 * Adds a runnable to be executed after {@link WindowContainer#prepareSurfaces} is called and 432 * the corresponding transaction is closed and applied. 433 */ addAfterPrepareSurfacesRunnable(Runnable r)434 void addAfterPrepareSurfacesRunnable(Runnable r) { 435 // If runnables are already being handled in executeAfterPrepareSurfacesRunnable, then just 436 // immediately execute the runnable passed in. 437 if (mInExecuteAfterPrepareSurfacesRunnables) { 438 r.run(); 439 return; 440 } 441 442 mAfterPrepareSurfacesRunnables.add(r); 443 scheduleAnimation(); 444 } 445 executeAfterPrepareSurfacesRunnables()446 void executeAfterPrepareSurfacesRunnables() { 447 448 // Don't even think about to start recursing! 449 if (mInExecuteAfterPrepareSurfacesRunnables) { 450 return; 451 } 452 mInExecuteAfterPrepareSurfacesRunnables = true; 453 454 // Traverse in order they were added. 455 final int size = mAfterPrepareSurfacesRunnables.size(); 456 for (int i = 0; i < size; i++) { 457 mAfterPrepareSurfacesRunnables.get(i).run(); 458 } 459 mAfterPrepareSurfacesRunnables.clear(); 460 mInExecuteAfterPrepareSurfacesRunnables = false; 461 } 462 } 463