当前位置:   article > 正文

Android 13 WMS-动画流程_android13 apptransition

android13 apptransition
 

动画的类型如下

  1. @IntDef(flag = true, prefix = { "ANIMATION_TYPE_" }, value = {
  2. ANIMATION_TYPE_NONE,
  3. ANIMATION_TYPE_APP_TRANSITION,
  4. ANIMATION_TYPE_SCREEN_ROTATION,
  5. ANIMATION_TYPE_DIMMER,
  6. ANIMATION_TYPE_RECENTS,
  7. ANIMATION_TYPE_WINDOW_ANIMATION,
  8. ANIMATION_TYPE_INSETS_CONTROL,
  9. ANIMATION_TYPE_TOKEN_TRANSFORM,
  10. ANIMATION_TYPE_STARTING_REVEAL
  11. })

ANIMATION_TYPE_APP_TRANSITION动画

当点击一个二级页面时, 会有如下调用栈

动画的type = ANIMATION_TYPE_APP_TRANSITION

  1. 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: SurfaceAnimator startAnimation mAnimation:com.android.server.wm.LocalAnimationAdapter@71444ae
  2. 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: SurfaceAnimator startAnimation mLeash:Surface(name=Surface(name=ActivityRecord{8b5f0f2 u0 com.android.settings/.MainSettings} t76})/@0xaa929f3 - animation-leash of app_transition)/@0x9c116b0
  3. 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: SurfaceAnimator startAnimation t:android.view.SurfaceControl$Transaction@8d14824
  4. 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: SurfaceAnimator startAnimation type:1
  5. 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: SurfaceAnimator startAnimation mInnerAnimationFinishedCallback:com.android.server.wm.SurfaceAnimator$$ExternalSyntheticLambda0@d22724f
  6. 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: java.lang.RuntimeException: jinyanmeianimation
  7. 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: at com.android.server.wm.SurfaceAnimator.startAnimation(SurfaceAnimator.java:200)
  8. 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: at com.android.server.wm.WindowContainer.startAnimation(WindowContainer.java:2912)
  9. 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: at com.android.server.wm.WindowContainer$AnimationRunnerBuilder.lambda$build$4$com-android-server-wm-WindowContainer$AnimationRunnerBuilder(WindowContainer.java:4257)
  10. 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: at com.android.server.wm.WindowContainer$AnimationRunnerBuilder$$ExternalSyntheticLambda4.startAnimation(Unknown Source:7)
  11. 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: at com.android.server.wm.WindowContainer.applyAnimationUnchecked(WindowContainer.java:3384)
  12. 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: at com.android.server.wm.WindowContainer.applyAnimation(WindowContainer.java:3072)
  13. 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: at com.android.server.wm.ActivityRecord.applyAnimation(ActivityRecord.java:6074)
  14. 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: at com.android.server.wm.AppTransitionController.applyAnimations(AppTransitionController.java:876)
  15. 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: at com.android.server.wm.AppTransitionController.applyAnimations(AppTransitionController.java:1083)
  16. 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: at com.android.server.wm.AppTransitionController.handleAppTransitionReady(AppTransitionController.java:293)
  17. 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: at com.android.server.wm.RootWindowContainer.checkAppTransitionReady(RootWindowContainer.java:1070)
  18. 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: at com.android.server.wm.RootWindowContainer.performSurfacePlacementNoTrace(RootWindowContainer.java:937)
  19. 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: at com.android.server.wm.RootWindowContainer.performSurfacePlacement(RootWindowContainer.java:877)
  20. 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementLoop(WindowSurfacePlacer.java:199)
  21. 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:148)
  22. 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:137)
  23. 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: at com.android.server.wm.WindowSurfacePlacer$Traverser.run(WindowSurfacePlacer.java:79)
  24. 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: at android.os.Handler.handleCallback(Handler.java:942)
  25. 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: at android.os.Handler.dispatchMessage(Handler.java:99)
  26. 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: at android.os.Looper.loopOnce(Looper.java:211)
  27. 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: at android.os.Looper.loop(Looper.java:300)
  28. 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: at android.os.HandlerThread.run(HandlerThread.java:67)

每次循环都要检查是否开始一个动画

  1. void handleAppTransitionReady() {
  2. 183 mTempTransitionReasons.clear();
  3. // //检查app transition是否已经准备好
  4. 184 if (!transitionGoodToGo(mDisplayContent.mOpeningApps, mTempTransitionReasons)
  5. 185 || !transitionGoodToGo(mDisplayContent.mChangingContainers, mTempTransitionReasons)
  6. 186 || !transitionGoodToGoForTaskFragments()) {
  7. 187 return;
  8. 188 }
  9. 189 Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "AppTransitionReady");
  10. 190
  11. 191 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "**** GOOD TO GO");
  12. 192 // TODO(b/205335975): Remove window which stuck in animatingExit status. Find actual cause.
  13. 193 mDisplayContent.forAllWindows(WindowState::cleanupAnimatingExitWindow,
  14. 194 true /* traverseTopToBottom */);
  15. 195 // TODO(new-app-transition): Remove code using appTransition.getAppTransition()
  16. 196 final AppTransition appTransition = mDisplayContent.mAppTransition;
  17. 197
  18. 198 mDisplayContent.mNoAnimationNotifyOnTransitionFinished.clear();
  19. 199
  20. 200 appTransition.removeAppTransitionTimeoutCallbacks();
  21. 201
  22. 202 mDisplayContent.mWallpaperMayChange = false;
  23. 203
  24. 204 int appCount = mDisplayContent.mOpeningApps.size();
  25. 205 for (int i = 0; i < appCount; ++i) {
  26. 206 // Clearing the mAnimatingExit flag before entering animation. It's set to true if app
  27. 207 // window is removed, or window relayout to invisible. This also affects window
  28. 208 // visibility. We need to clear it *before* maybeUpdateTransitToWallpaper() as the
  29. 209 // transition selection depends on wallpaper target visibility.
  30. 210 mDisplayContent.mOpeningApps.valueAtUnchecked(i).clearAnimatingFlags();
  31. 211 }
  32. 212 appCount = mDisplayContent.mChangingContainers.size();
  33. 213 for (int i = 0; i < appCount; ++i) {
  34. 214 // Clearing for same reason as above.
  35. 215 final ActivityRecord activity = getAppFromContainer(
  36. 216 mDisplayContent.mChangingContainers.valueAtUnchecked(i));
  37. 217 if (activity != null) {
  38. 218 activity.clearAnimatingFlags();
  39. 219 }
  40. 220 }
  41. 221
  42. 222 // Adjust wallpaper before we pull the lower/upper target, since pending changes
  43. 223 // (like the clearAnimatingFlags() above) might affect wallpaper target result.
  44. 224 // Or, the opening app window should be a wallpaper target.
  45. 225 mWallpaperControllerLocked.adjustWallpaperWindowsForAppTransitionIfNeeded(
  46. 226 mDisplayContent.mOpeningApps);
  47. 227
  48. 228 // Remove launcher from app transition animation while recents is running. Recents animation
  49. 229 // is managed outside of app transition framework, so we just need to commit visibility.
  50. 230 final boolean excludeLauncherFromAnimation =
  51. 231 mDisplayContent.mOpeningApps.stream().anyMatch(
  52. 232 (app) -> app.isAnimating(PARENTS, ANIMATION_TYPE_RECENTS))
  53. 233 || mDisplayContent.mClosingApps.stream().anyMatch(
  54. 234 (app) -> app.isAnimating(PARENTS, ANIMATION_TYPE_RECENTS));
  55. 235 final ArraySet<ActivityRecord> openingAppsForAnimation = getAppsForAnimation(
  56. 236 mDisplayContent.mOpeningApps, excludeLauncherFromAnimation);
  57. 237 final ArraySet<ActivityRecord> closingAppsForAnimation = getAppsForAnimation(
  58. 238 mDisplayContent.mClosingApps, excludeLauncherFromAnimation);
  59. 239
  60. 240 @TransitionOldType final int transit = getTransitCompatType(
  61. 241 mDisplayContent.mAppTransition, openingAppsForAnimation, closingAppsForAnimation,
  62. 242 mDisplayContent.mChangingContainers,
  63. 243 mWallpaperControllerLocked.getWallpaperTarget(), getOldWallpaper(),
  64. 244 mDisplayContent.mSkipAppTransitionAnimation);
  65. 245 mDisplayContent.mSkipAppTransitionAnimation = false;
  66. 246
  67. 247 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
  68. 248 "handleAppTransitionReady: displayId=%d appTransition={%s}"
  69. 249 + " excludeLauncherFromAnimation=%b openingApps=[%s] closingApps=[%s] transit=%s",
  70. 250 mDisplayContent.mDisplayId, appTransition.toString(), excludeLauncherFromAnimation,
  71. 251 mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
  72. 252 AppTransition.appTransitionOldToString(transit));
  73. 253
  74. 254 // Find the layout params of the top-most application window in the tokens, which is
  75. 255 // what will control the animation theme. If all closing windows are obscured, then there is
  76. 256 // no need to do an animation. This is the case, for example, when this transition is being
  77. 257 // done behind a dream window.
  78. 258 final ArraySet<Integer> activityTypes = collectActivityTypes(openingAppsForAnimation,
  79. 259 closingAppsForAnimation, mDisplayContent.mChangingContainers);
  80. //首先会获取当前需要opening和closing的app window列表(ActivityRecord类型)
  81. 260 final ActivityRecord animLpActivity = findAnimLayoutParamsToken(transit, activityTypes,
  82. 261 openingAppsForAnimation, closingAppsForAnimation,
  83. 262 mDisplayContent.mChangingContainers);
  84. 263 final ActivityRecord topOpeningApp =
  85. 264 getTopApp(openingAppsForAnimation, false /* ignoreHidden */);
  86. 265 final ActivityRecord topClosingApp =
  87. 266 getTopApp(closingAppsForAnimation, false /* ignoreHidden */);
  88. 267 final ActivityRecord topChangingApp =
  89. 268 getTopApp(mDisplayContent.mChangingContainers, false /* ignoreHidden */);
  90. 269 final WindowManager.LayoutParams animLp = getAnimLp(animLpActivity);
  91. 270
  92. 271 // Check if there is any override
  93. 272 if (!overrideWithTaskFragmentRemoteAnimation(transit, activityTypes)) {
  94. 273 // Unfreeze the windows that were previously frozen for TaskFragment animation.
  95. 274 unfreezeEmbeddedChangingWindows();
  96. 275 overrideWithRemoteAnimationIfSet(animLpActivity, transit, activityTypes);
  97. 276 }
  98. 277
  99. 278 final boolean voiceInteraction = containsVoiceInteraction(closingAppsForAnimation)
  100. 279 || containsVoiceInteraction(openingAppsForAnimation);
  101. 280
  102. 281 final int layoutRedo;
  103. 282 mService.mSurfaceAnimationRunner.deferStartingAnimations();
  104. 283 try {
  105. //然后在applyAnimations方法里面对window列表进行遍历WindowContainer的动画applyAnimation方法的调用
  106. 284 applyAnimations(openingAppsForAnimation, closingAppsForAnimation, transit, animLp,
  107. 285 voiceInteraction);
  108. 286 handleClosingApps();
  109. 287 handleOpeningApps();
  110. 288 handleChangingApps(transit);
  111. 289
  112. 290 appTransition.setLastAppTransition(transit, topOpeningApp,
  113. 291 topClosingApp, topChangingApp);
  114. 292
  115. 293 final int flags = appTransition.getTransitFlags();
  116. 294 layoutRedo = appTransition.goodToGo(transit, topOpeningApp);
  117. 295 handleNonAppWindowsInTransition(transit, flags);
  118. 296 appTransition.postAnimationCallback();
  119. 297 appTransition.clear();
  120. 298 } finally {
  121. 299 mService.mSurfaceAnimationRunner.continueStartingAnimations();
  122. 300 }
  123. 301
  124. 302 mService.mTaskSnapshotController.onTransitionStarting(mDisplayContent);
  125. 303
  126. 304 mDisplayContent.mOpeningApps.clear();
  127. 305 mDisplayContent.mClosingApps.clear();
  128. 306 mDisplayContent.mChangingContainers.clear();
  129. 307 mDisplayContent.mUnknownAppVisibilityController.clear();
  130. 308
  131. 309 // This has changed the visibility of windows, so perform
  132. 310 // a new layout to get them all up-to-date.
  133. 311 mDisplayContent.setLayoutNeeded();
  134. 312
  135. 313 mDisplayContent.computeImeTarget(true /* updateImeTarget */);
  136. 314
  137. 315 mService.mAtmService.mTaskSupervisor.getActivityMetricsLogger().notifyTransitionStarting(
  138. 316 mTempTransitionReasons);
  139. 317
  140. 318 Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
  141. 319
  142. 320 mDisplayContent.pendingLayoutChanges |=
  143. 321 layoutRedo | FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_CONFIG;
  144. 322 }

applyAnimationUnchecked包含两部分, 

第一先通过getAnimationAdapter加载合适的动画

如果是普通的窗口动画,比如app内部activity的切换,当前的场景是设置主菜单跳转子菜单,根据当前场景获取到具体的transit,transit=TRANSIT_OLD_ACTIVITY_OPEN,然后再结合enter为true或者false,可以最终可以找到设置主菜单的动画xml资源是activity_open_exit.xml,设置子菜单的动画xml资源是activity_open_enter.xml,在获取到具体xml资源名字后,通过AnimationUtils.loadAnimation方法把xml资源转成Animation对象。
之后就会创建一个WindowAnimationSpec对象,并把Animation对象作为构造方法的第一个参数传给了WindowAnimationSpec

第二开始动画 

  1. protected void applyAnimationUnchecked(WindowManager.LayoutParams lp, boolean enter,
  2. 2994 @TransitionOldType int transit, boolean isVoiceInteraction,
  3. 2995 @Nullable ArrayList<WindowContainer> sources) {
  4. 2996 final Task task = asTask();
  5. 2997 if (task != null && !enter && !task.isActivityTypeHomeOrRecents()) {
  6. 2998 final InsetsControlTarget imeTarget = mDisplayContent.getImeTarget(IME_TARGET_LAYERING);
  7. 2999 final boolean isImeLayeringTarget = imeTarget != null && imeTarget.getWindow() != null
  8. 3000 && imeTarget.getWindow().getTask() == task;
  9. 3001 // Attach and show the IME screenshot when the task is the IME target and performing
  10. 3002 // task closing transition to the next task.
  11. 3003 if (isImeLayeringTarget && AppTransition.isTaskCloseTransitOld(transit)) {
  12. 3004 mDisplayContent.showImeScreenshot();
  13. 3005 }
  14. 3006 }
  15. 3007 final Pair<AnimationAdapter, AnimationAdapter> adapters = getAnimationAdapter(lp,
  16. 3008 transit, enter, isVoiceInteraction);
  17. 3009 AnimationAdapter adapter = adapters.first;
  18. 3010 AnimationAdapter thumbnailAdapter = adapters.second;
  19. 3011 if (adapter != null) {
  20. 3012 if (sources != null) {
  21. 3013 mSurfaceAnimationSources.addAll(sources);
  22. 3014 }
  23. 3015
  24. 3016 AnimationRunnerBuilder animationRunnerBuilder = new AnimationRunnerBuilder();
  25. 3017
  26. 3018 if (isTaskTransitOld(transit)) {
  27. 3019 animationRunnerBuilder.setTaskBackgroundColor(getTaskAnimationBackgroundColor());
  28. 3020 // TODO: Remove when we migrate to shell (b/202383002)
  29. 3021 if (mWmService.mTaskTransitionSpec != null) {
  30. 3022 animationRunnerBuilder.hideInsetSourceViewOverflows(
  31. 3023 mWmService.mTaskTransitionSpec.animationBoundInsets);
  32. 3024 }
  33. 3025 }
  34. 3026
  35. 3027 final ActivityRecord activityRecord = asActivityRecord();
  36. 3028 if (activityRecord != null && isActivityTransitOld(transit)
  37. 3029 && adapter.getShowBackground()) {
  38. 3030 final @ColorInt int backgroundColorForTransition;
  39. 3031 if (adapter.getBackgroundColor() != 0) {
  40. 3032 // If available use the background color provided through getBackgroundColor
  41. 3033 // which if set originates from a call to overridePendingAppTransition.
  42. 3034 backgroundColorForTransition = adapter.getBackgroundColor();
  43. 3035 } else {
  44. 3036 // Otherwise default to the window's background color if provided through
  45. 3037 // the theme as the background color for the animation - the top most window
  46. 3038 // with a valid background color and showBackground set takes precedence.
  47. 3039 final Task arTask = activityRecord.getTask();
  48. 3040 backgroundColorForTransition = ColorUtils.setAlphaComponent(
  49. 3041 arTask.getTaskDescription().getBackgroundColor(), 255);
  50. 3042 }
  51. 3043 animationRunnerBuilder.setTaskBackgroundColor(backgroundColorForTransition);
  52. 3044 }
  53. 3045
  54. 3046 animationRunnerBuilder.build()
  55. 3047 .startAnimation(getPendingTransaction(), adapter, !isVisible(),
  56. 3048 ANIMATION_TYPE_APP_TRANSITION, thumbnailAdapter);
  57. 3049
  58. 3050 if (adapter.getShowWallpaper()) {
  59. 3051 getDisplayContent().pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
  60. 3052 }
  61. 3053 }
  62. 3054 }
  63. 3055

 计算transition的类型

在getTransitCompatType中会对动画做转换,将动画转化为old类型的动画

  1. @TransitionOldType static int getTransitCompatType(AppTransition appTransition,
  2. ArraySet<ActivityRecord> openingApps, ArraySet<ActivityRecord> closingApps,
  3. ArraySet<WindowContainer> changingContainers, @Nullable WindowState wallpaperTarget,
  4. @Nullable WindowState oldWallpaper, boolean skipAppTransitionAnimation) {
  5. Slog.d("jinyanmeianimation","getTransitCompatType appTransition :" + appTransition );
  6. Slog.d("jinyanmeianimation","getTransitCompatType appTransition :" + appTransition , new RuntimeException("jinyanmeianimation"));
  7. // Determine if closing and opening app token sets are wallpaper targets, in which case
  8. // special animations are needed.
  9. final boolean openingAppHasWallpaper = canBeWallpaperTarget(openingApps)
  10. && wallpaperTarget != null;
  11. final boolean closingAppHasWallpaper = canBeWallpaperTarget(closingApps)
  12. && wallpaperTarget != null;
  13. // Keyguard transit has highest priority.
  14. switch (appTransition.getKeyguardTransition()) {
  15. case TRANSIT_KEYGUARD_GOING_AWAY:
  16. return openingAppHasWallpaper ? TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER
  17. : TRANSIT_OLD_KEYGUARD_GOING_AWAY;
  18. case TRANSIT_KEYGUARD_OCCLUDE:
  19. // When there is a closing app, the keyguard has already been occluded by an
  20. // activity, and another activity has started on top of that activity, so normal
  21. // app transition animation should be used.
  22. return closingApps.isEmpty() ? TRANSIT_OLD_KEYGUARD_OCCLUDE
  23. : TRANSIT_OLD_ACTIVITY_OPEN;
  24. case TRANSIT_KEYGUARD_UNOCCLUDE:
  25. return TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
  26. }
  27. // This is not keyguard transition and one of the app has request to skip app transition.
  28. // MIUI MOD: START
  29. // For Stage Split Screen: Drag to enter split-screen feature.
  30. // if (skipAppTransitionAnimation) {
  31. if (skipAppTransitionAnimation ||
  32. ActivityTaskManagerServiceStub.get().removeSplitTaskShotIfNeed()) {
  33. // END
  34. return WindowManager.TRANSIT_OLD_UNSET;
  35. }
  36. @TransitionFlags final int flags = appTransition.getTransitFlags();
  37. @TransitionType final int firstTransit = appTransition.getFirstAppTransition();
  38. // Special transitions
  39. // TODO(new-app-transitions): Revisit if those can be rewritten by using flags.
  40. if (appTransition.containsTransitRequest(TRANSIT_CHANGE) && !changingContainers.isEmpty()) {
  41. // MIUI ADD: START Activity Embedding Resizing
  42. if (MiuiEmbeddingWindowServiceStub.get()
  43. .skipAppTransitionAnimationForEmbeddingDivider()) {
  44. return WindowManager.TRANSIT_OLD_UNSET;
  45. }
  46. // END
  47. @TransitContainerType int changingType =
  48. getTransitContainerType(changingContainers.valueAt(0));
  49. switch (changingType) {
  50. case TYPE_TASK:
  51. return TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE;
  52. case TYPE_TASK_FRAGMENT:
  53. return TRANSIT_OLD_TASK_FRAGMENT_CHANGE;
  54. default:
  55. throw new IllegalStateException(
  56. "TRANSIT_CHANGE with unrecognized changing type=" + changingType);
  57. }
  58. }
  59. if ((flags & TRANSIT_FLAG_APP_CRASHED) != 0) {
  60. return TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE;
  61. }
  62. if (firstTransit == TRANSIT_NONE) {
  63. return TRANSIT_OLD_NONE;
  64. }
  65. /*
  66. * There are cases where we open/close a new task/activity, but in reality only a
  67. * translucent activity on top of existing activities is opening/closing. For that one, we
  68. * have a different animation because non of the task/activity animations actually work well
  69. * with translucent apps.
  70. */
  71. if (isNormalTransit(firstTransit)) {
  72. boolean allOpeningVisible = true;
  73. boolean allTranslucentOpeningApps = !openingApps.isEmpty();
  74. for (int i = openingApps.size() - 1; i >= 0; i--) {
  75. final ActivityRecord activity = openingApps.valueAt(i);
  76. if (!activity.isVisible()) {
  77. allOpeningVisible = false;
  78. if (activity.fillsParent()) {
  79. allTranslucentOpeningApps = false;
  80. }
  81. }
  82. }
  83. boolean allTranslucentClosingApps = !closingApps.isEmpty();
  84. for (int i = closingApps.size() - 1; i >= 0; i--) {
  85. if (closingApps.valueAt(i).fillsParent()) {
  86. allTranslucentClosingApps = false;
  87. break;
  88. }
  89. }
  90. if (allTranslucentClosingApps && allOpeningVisible) {
  91. return TRANSIT_OLD_TRANSLUCENT_ACTIVITY_CLOSE;
  92. }
  93. if (allTranslucentOpeningApps && closingApps.isEmpty()) {
  94. return TRANSIT_OLD_TRANSLUCENT_ACTIVITY_OPEN;
  95. }
  96. }
  97. final ActivityRecord topOpeningApp = getTopApp(openingApps,
  98. false /* ignoreHidden */);
  99. final ActivityRecord topClosingApp = getTopApp(closingApps,
  100. true /* ignoreHidden */);
  101. if (closingAppHasWallpaper && openingAppHasWallpaper) {
  102. ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Wallpaper animation!");
  103. switch (firstTransit) {
  104. case TRANSIT_OPEN:
  105. case TRANSIT_TO_FRONT:
  106. return TRANSIT_OLD_WALLPAPER_INTRA_OPEN;
  107. case TRANSIT_CLOSE:
  108. case TRANSIT_TO_BACK:
  109. return TRANSIT_OLD_WALLPAPER_INTRA_CLOSE;
  110. }
  111. } else if (oldWallpaper != null && !openingApps.isEmpty()
  112. && !openingApps.contains(oldWallpaper.mActivityRecord)
  113. && closingApps.contains(oldWallpaper.mActivityRecord)
  114. && topClosingApp == oldWallpaper.mActivityRecord) {
  115. // We are transitioning from an activity with a wallpaper to one without.
  116. return TRANSIT_OLD_WALLPAPER_CLOSE;
  117. } else if (wallpaperTarget != null && wallpaperTarget.isVisible()
  118. && openingApps.contains(wallpaperTarget.mActivityRecord)
  119. && topOpeningApp == wallpaperTarget.mActivityRecord
  120. /* && transit != TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE */) {
  121. // We are transitioning from an activity without
  122. // a wallpaper to now showing the wallpaper
  123. return TRANSIT_OLD_WALLPAPER_OPEN;
  124. }
  125. final ArraySet<WindowContainer> openingWcs = getAnimationTargets(
  126. openingApps, closingApps, true /* visible */);
  127. final ArraySet<WindowContainer> closingWcs = getAnimationTargets(
  128. openingApps, closingApps, false /* visible */);
  129. final WindowContainer<?> openingContainer = !openingWcs.isEmpty()
  130. ? openingWcs.valueAt(0) : null;
  131. final WindowContainer<?> closingContainer = !closingWcs.isEmpty()
  132. ? closingWcs.valueAt(0) : null;
  133. @TransitContainerType int openingType = getTransitContainerType(openingContainer);
  134. @TransitContainerType int closingType = getTransitContainerType(closingContainer);
  135. if (appTransition.containsTransitRequest(TRANSIT_TO_FRONT) && openingType == TYPE_TASK) {
  136. return TRANSIT_OLD_TASK_TO_FRONT;
  137. }
  138. if (appTransition.containsTransitRequest(TRANSIT_TO_BACK) && closingType == TYPE_TASK) {
  139. return TRANSIT_OLD_TASK_TO_BACK;
  140. }
  141. if (appTransition.containsTransitRequest(TRANSIT_OPEN)) {
  142. if (openingType == TYPE_TASK) {
  143. return (appTransition.getTransitFlags() & TRANSIT_FLAG_OPEN_BEHIND) != 0
  144. ? TRANSIT_OLD_TASK_OPEN_BEHIND : TRANSIT_OLD_TASK_OPEN;
  145. }
  146. if (openingType == TYPE_ACTIVITY) {
  147. return TRANSIT_OLD_ACTIVITY_OPEN;
  148. }
  149. if (openingType == TYPE_TASK_FRAGMENT) {
  150. return TRANSIT_OLD_TASK_FRAGMENT_OPEN;
  151. }
  152. }
  153. if (appTransition.containsTransitRequest(TRANSIT_CLOSE)) {
  154. if (closingType == TYPE_TASK) {
  155. return TRANSIT_OLD_TASK_CLOSE;
  156. }
  157. if (closingType == TYPE_TASK_FRAGMENT) {
  158. return TRANSIT_OLD_TASK_FRAGMENT_CLOSE;
  159. }
  160. if (closingType == TYPE_ACTIVITY) {
  161. for (int i = closingApps.size() - 1; i >= 0; i--) {
  162. if (closingApps.valueAt(i).visibleIgnoringKeyguard) {
  163. return TRANSIT_OLD_ACTIVITY_CLOSE;
  164. }
  165. }
  166. // Skip close activity transition since no closing app can be visible
  167. return WindowManager.TRANSIT_OLD_UNSET;
  168. }
  169. }
  170. if (appTransition.containsTransitRequest(TRANSIT_RELAUNCH)
  171. && !openingWcs.isEmpty() && !openingApps.isEmpty()) {
  172. return TRANSIT_OLD_ACTIVITY_RELAUNCH;
  173. }
  174. return TRANSIT_OLD_NONE;
  175. }

加载和开始动画

getAnimationAdapter加载动画

 

首先遍历所有的windowContainer 调用applyAnimation

  1. private void applyAnimations(ArraySet<WindowContainer> wcs, ArraySet<ActivityRecord> apps,
  2. @TransitionOldType int transit, boolean visible, LayoutParams animLp,
  3. boolean voiceInteraction) {
  4. final int wcsCount = wcs.size();
  5. for (int i = 0; i < wcsCount; i++) {
  6. final WindowContainer wc = wcs.valueAt(i);
  7. // If app transition animation target is promoted to higher level, SurfaceAnimator
  8. // triggers WC#onAnimationFinished only on the promoted target. So we need to take care
  9. // of triggering AR#onAnimationFinished on each ActivityRecord which is a part of the
  10. // app transition.
  11. final ArrayList<ActivityRecord> transitioningDescendants = new ArrayList<>();
  12. for (int j = 0; j < apps.size(); ++j) {
  13. final ActivityRecord app = apps.valueAt(j);
  14. if (app.isDescendantOf(wc)) {
  15. transitioningDescendants.add(app);
  16. }
  17. }
  18. wc.applyAnimation(animLp, transit, visible, voiceInteraction, transitioningDescendants);
  19. }
  20. }

然后调用getAnimationAdapter 根据窗口层次结构中给定的窗口布局属性获取动画适配器

startAnimation 创建leash开始动画

 

  1. SurfaceAnimation.java
  2. 166 void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
  3. 167 @AnimationType int type,
  4. 168 @Nullable OnAnimationFinishedCallback animationFinishedCallback,
  5. 169 @Nullable Runnable animationCancelledCallback,
  6. 170 @Nullable AnimationAdapter snapshotAnim, @Nullable SurfaceFreezer freezer) {
  7. 171 cancelAnimation(t, true /* restarting */, true /* forwardCancel */);
  8. 172 mAnimation = anim;
  9. 173 mAnimationType = type;
  10. 174 mSurfaceAnimationFinishedCallback = animationFinishedCallback;
  11. 175 mAnimationCancelledCallback = animationCancelledCallback;
  12. 176 final SurfaceControl surface = mAnimatable.getSurfaceControl();
  13. 177 if (surface == null) {
  14. 178 Slog.w(TAG, "Unable to start animation, surface is null or no children.");
  15. 179 cancelAnimation();
  16. 180 return;
  17. 181 }
  18. 182 mLeash = freezer != null ? freezer.takeLeashForAnimation() : null;
  19. 183 if (mLeash == null) {
  20. 184 mLeash = createAnimationLeash(mAnimatable, surface, t, type,
  21. 185 mAnimatable.getSurfaceWidth(), mAnimatable.getSurfaceHeight(), 0 /* x */,
  22. 186 0 /* y */, hidden, mService.mTransactionFactory);
  23. 187 mAnimatable.onAnimationLeashCreated(t, mLeash);
  24. 188 }
  25. 189 mAnimatable.onLeashAnimationStarting(t, mLeash);
  26. 190 if (mAnimationStartDelayed) {
  27. 191 ProtoLog.i(WM_DEBUG_ANIM, "Animation start delayed for %s", mAnimatable);
  28. 192 return;
  29. 193 }
  30. 194 mAnimation.startAnimation(mLeash, t, type, mInnerAnimationFinishedCallback);
  31. 195 if (ProtoLogImpl.isEnabled(WM_DEBUG_ANIM)) {
  32. 196 StringWriter sw = new StringWriter();
  33. 197 PrintWriter pw = new PrintWriter(sw);
  34. 198 mAnimation.dump(pw, "");
  35. 199 ProtoLog.d(WM_DEBUG_ANIM, "Animation start for %s, anim=%s", mAnimatable, sw);
  36. 200 }
  37. 201 if (snapshotAnim != null) {
  38. 202 mSnapshot = freezer.takeSnapshotForAnimation();
  39. 203 if (mSnapshot == null) {
  40. 204 Slog.e(TAG, "No snapshot target to start animation on for " + mAnimatable);
  41. 205 return;
  42. 206 }
  43. 207 mSnapshot.startAnimation(t, snapshotAnim, type);
  44. 208 }
  45. 209 }

可见创建一个SuefaceControl, 然后把 WindowContainer的surface挂在了leash上面, 然后对leash做动画

  1. 455 static SurfaceControl createAnimationLeash(Animatable animatable, SurfaceControl surface,
  2. 456 Transaction t, @AnimationType int type, int width, int height, int x, int y,
  3. 457 boolean hidden, Supplier<Transaction> transactionFactory) {
  4. 458 ProtoLog.i(WM_DEBUG_ANIM, "Reparenting to leash for %s", animatable);
  5. 459 final SurfaceControl.Builder builder = animatable.makeAnimationLeash()
  6. 460 .setParent(animatable.getAnimationLeashParent())
  7. 461 .setName(surface + " - animation-leash of " + animationTypeToString(type))
  8. 462 // TODO(b/151665759) Defer reparent calls
  9. 463 // We want the leash to be visible immediately because the transaction which shows
  10. 464 // the leash may be deferred but the reparent will not. This will cause the leashed
  11. 465 // surface to be invisible until the deferred transaction is applied. If this
  12. 466 // doesn't work, you will can see the 2/3 button nav bar flicker during seamless
  13. 467 // rotation.
  14. 468 .setHidden(hidden)
  15. 469 .setEffectLayer()
  16. 470 .setCallsite("SurfaceAnimator.createAnimationLeash");
  17. 471 final SurfaceControl leash = builder.build();
  18. 472 t.setWindowCrop(leash, width, height);
  19. 473 t.setPosition(leash, x, y);
  20. 474 t.show(leash);
  21. 475 t.setAlpha(leash, hidden ? 0 : 1);
  22. 476
  23. 477 t.reparent(surface, leash);
  24. 478 return leash;
  25. 479 }

 

  1. SurfaceAnimationRunner.java
  2. 171 void startAnimation(AnimationSpec a, SurfaceControl animationLeash, Transaction t,
  3. 172 Runnable finishCallback) {
  4. 173 synchronized (mLock) {
  5. 174 final RunningAnimation runningAnim = new RunningAnimation(a, animationLeash,
  6. 175 finishCallback);
  7. 176 boolean requiresEdgeExtension = requiresEdgeExtension(a);
  8. 177
  9. 178 if (requiresEdgeExtension) {
  10. 179 final ArrayList<SurfaceControl> extensionSurfaces = new ArrayList<>();
  11. 180 synchronized (mEdgeExtensionLock) {
  12. 181 mEdgeExtensions.put(animationLeash, extensionSurfaces);
  13. 182 }
  14. 183
  15. 184 mPreProcessingAnimations.put(animationLeash, runningAnim);
  16. 185
  17. 186 // We must wait for t to be committed since otherwise the leash doesn't have the
  18. 187 // windows we want to screenshot and extend as children.
  19. 188 t.addTransactionCommittedListener(mEdgeExtensionExecutor, () -> {
  20. 189 final WindowAnimationSpec animationSpec = a.asWindowAnimationSpec();
  21. 190
  22. 191 final Transaction edgeExtensionCreationTransaction = new Transaction();
  23. 192 edgeExtendWindow(animationLeash,
  24. 193 animationSpec.getRootTaskBounds(), animationSpec.getAnimation(),
  25. 194 edgeExtensionCreationTransaction);
  26. 195
  27. 196 synchronized (mLock) {
  28. 197 // only run if animation is not yet canceled by this point
  29. 198 if (mPreProcessingAnimations.get(animationLeash) == runningAnim) {
  30. 199 // In the case the animation is cancelled, edge extensions are removed
  31. 200 // onAnimationLeashLost which is called before onAnimationCancelled.
  32. 201 // So we need to check if the edge extensions have already been removed
  33. 202 // or not, and if so we don't want to apply the transaction.
  34. 203 synchronized (mEdgeExtensionLock) {
  35. 204 if (!mEdgeExtensions.isEmpty()) {
  36. 205 edgeExtensionCreationTransaction.apply();
  37. 206 }
  38. 207 }
  39. 208
  40. 209 mPreProcessingAnimations.remove(animationLeash);
  41. 210 mPendingAnimations.put(animationLeash, runningAnim);
  42. 211 if (!mAnimationStartDeferred && mPreProcessingAnimations.isEmpty()) {
  43. 212 mChoreographer.postFrameCallback(this::startAnimations);
  44. 213 }
  45. 214 }
  46. 215 }
  47. 216 });
  48. 217 }
  49. 218
  50. 219 if (!requiresEdgeExtension) {
  51. 220 mPendingAnimations.put(animationLeash, runningAnim);
  52. 221 if (!mAnimationStartDeferred && mPreProcessingAnimations.isEmpty()) {
  53. 222 mChoreographer.postFrameCallback(this::startAnimations);
  54. 223 }
  55. 224 }
  56. 225
  57. 226 // Some animations (e.g. move animations) require the initial transform to be
  58. 227 // applied immediately.
  59. 228 applyTransformation(runningAnim, t, 0 /* currentPlayTime */);
  60. 229 }
  61. 230 }

发送消息

  1. scheduleFrameLocked:862, Choreographer (android.view)
  2. postCallbackDelayedInternal:605, Choreographer (android.view)
  3. postFrameCallbackDelayed:702, Choreographer (android.view)
  4. postFrameCallback:682, Choreographer (android.view)
  5. continueStartingAnimations:173, SurfaceAnimationRunner (com.android.server.wm)
  6. handleAppTransitionReady:312, AppTransitionController (com.android.server.wm)
  7. checkAppTransitionReady:1070, RootWindowContainer (com.android.server.wm)
  8. performSurfacePlacementNoTrace:937, RootWindowContainer (com.android.server.wm)
  9. performSurfacePlacement:877, RootWindowContainer (com.android.server.wm)
  10. performSurfacePlacementLoop:199, WindowSurfacePlacer (com.android.server.wm)
  11. performSurfacePlacement:148, WindowSurfacePlacer (com.android.server.wm)
  12. performSurfacePlacement:137, WindowSurfacePlacer (com.android.server.wm)
  13. handleAppTransitionTimeout:1814, AppTransition (com.android.server.wm)
  14. lambda$new$0$com-android-server-wm-AppTransition:243, AppTransition (com.android.server.wm)
  15. run:-1, AppTransition$$ExternalSyntheticLambda3 (com.android.server.wm)
  16. handleCallback:942, Handler (android.os)
  17. dispatchMessage:99, Handler (android.os)
  18. loopOnce:211, Looper (android.os)
  19. loop:300, Looper (android.os)
  20. run:67, HandlerThread (android.os)
  21. run:46, ServiceThread (com.android.server)

为动画添加listener

  1. SurfaceAnimationRunner.java
  2. private void startAnimationLocked(RunningAnimation a) {
  3. 270 final ValueAnimator anim = mAnimatorFactory.makeAnimator();
  4. 271
  5. 272 // Animation length is already expected to be scaled.
  6. 273 anim.overrideDurationScale(1.0f);
  7. 274 anim.setDuration(a.mAnimSpec.getDuration());
  8. 275 anim.addUpdateListener(animation -> {
  9. 276 synchronized (mCancelLock) {
  10. 277 if (!a.mCancelled) {
  11. 278 final long duration = anim.getDuration();
  12. 279 long currentPlayTime = anim.getCurrentPlayTime();
  13. 280 if (currentPlayTime > duration) {
  14. 281 currentPlayTime = duration;
  15. 282 }
  16. 283 applyTransformation(a, mFrameTransaction, currentPlayTime);
  17. 284 }
  18. 285 }
  19. 286
  20. 287 // Transaction will be applied in the commit phase.
  21. 288 scheduleApplyTransaction();
  22. 289 });
  23. 290
  24. 291 anim.addListener(new AnimatorListenerAdapter() {
  25. 292 @Override
  26. 293 public void onAnimationStart(Animator animation) {
  27. 294 synchronized (mCancelLock) {
  28. 295 if (!a.mCancelled) {
  29. 296 // TODO: change this back to use show instead of alpha when b/138459974 is
  30. 297 // fixed.
  31. 298 mFrameTransaction.setAlpha(a.mLeash, 1);
  32. 299 }
  33. 300 }
  34. 301 }
  35. 302
  36. 303 @Override
  37. 304 public void onAnimationEnd(Animator animation) {
  38. 305 synchronized (mLock) {
  39. 306 mRunningAnimations.remove(a.mLeash);
  40. 307 synchronized (mCancelLock) {
  41. 308 if (!a.mCancelled) {
  42. 309
  43. 310 // Post on other thread that we can push final state without jank.
  44. 311 mAnimationThreadHandler.post(a.mFinishCallback);
  45. 312 }
  46. 313 }
  47. 314 }
  48. 315 }
  49. 316 });
  50. 317 a.mAnim = anim;
  51. 318 mRunningAnimations.put(a.mLeash, a);
  52. 319
  53. 320 anim.start();
  54. 321 if (a.mAnimSpec.canSkipFirstFrame()) {
  55. 322 // If we can skip the first frame, we start one frame later.
  56. 323 anim.setCurrentPlayTime(mChoreographer.getFrameIntervalNanos() / NANOS_PER_MS);
  57. 324 }
  58. 325
  59. 326 // Immediately start the animation by manually applying an animation frame. Otherwise, the
  60. 327 // start time would only be set in the next frame, leading to a delay.
  61. 328 anim.doAnimationFrame(mChoreographer.getFrameTime());
  62. 329 }
  63. 330

 

doFrame时更新动画位置

放vsync到来后, 执行onAnimationUpdate

  1. private void applyTransformation(RunningAnimation a, Transaction t, long currentPlayTime) {
  2. a.mAnimSpec.apply(t, a.mLeash, currentPlayTime);
  3. }

再来看下apply方法的具体实现,通过之前以具体xml资源创建的mAnimation对象,根据当前时间片currentPlayTime获取到当前的tmp.transformation,对leash对象实现了Matrix(大小,位置),Alpha,Crop等transformation变化,再通过Transaction 交给surfaceflinger显示,从而实现了动画当前时间片的显示效果。对比旧动画机制,这个transformation变化是在WindowStateAnimator类里面实现的。为什么要重点关注这个方法呢?因为如果窗口动画出bug了(位置大小不对?透明度异常?),就可以在这个方法里面打印window的相关参数来初步定位原因。 

  1. 119 @Override
  2. 120 public void apply(Transaction t, SurfaceControl leash, long currentPlayTime) {
  3. 121 final TmpValues tmp = mThreadLocalTmps.get();
  4. 122 tmp.transformation.clear();
  5. 123 mAnimation.getTransformation(currentPlayTime, tmp.transformation);
  6. 124 tmp.transformation.getMatrix().postTranslate(mPosition.x, mPosition.y);
  7. 125 t.setMatrix(leash, tmp.transformation.getMatrix(), tmp.floats);
  8. 126 t.setAlpha(leash, tmp.transformation.getAlpha());
  9. 127
  10. 128 boolean cropSet = false;
  11. 129 if (mRootTaskClipMode == ROOT_TASK_CLIP_NONE) {
  12. 130 if (tmp.transformation.hasClipRect()) {
  13. 131 final Rect clipRect = tmp.transformation.getClipRect();
  14. 132 accountForExtension(tmp.transformation, clipRect);
  15. 133 t.setWindowCrop(leash, clipRect);
  16. 134 cropSet = true;
  17. 135 }
  18. 136 } else {
  19. 137 mTmpRect.set(mRootTaskBounds);
  20. 138 if (tmp.transformation.hasClipRect()) {
  21. 139 mTmpRect.intersect(tmp.transformation.getClipRect());
  22. 140 }
  23. 141 accountForExtension(tmp.transformation, mTmpRect);
  24. 142 t.setWindowCrop(leash, mTmpRect);
  25. 143 cropSet = true;
  26. 144 }
  27. 145
  28. 146 // We can only apply rounded corner if a crop is set, as otherwise the value is meaningless,
  29. 147 // since it doesn't have anything it's relative to.
  30. 148 if (cropSet && mAnimation.hasRoundedCorners() && mWindowCornerRadius > 0) {
  31. 149 t.setCornerRadius(leash, mWindowCornerRadius);
  32. 150 }
  33. 151 }

6、ValueAnimator类,从上面的介绍可以得知,窗口动画的最终本质就是一个ValueAnimator属性动画,理解了这一点,就相当于把窗口动画简单化了,最终的实现就类比于我们普通app的属性动画的实现(app属性动画的对象是view,窗口属性动画的对象是window),只不过整个流程比较复杂而已,但是最终的实现原理是一样的,殊途同归,这个才是android窗口动画机制的精髓所在

Rotation动画 ANIMATION_TYPE_SCREEN_ROTATION

1. 根据sensor导致的旋转动画

最终也会到SurfaceAnimation

 拿到动画适配器:

  1. FadeAnimationController.java
  2. public void fadeWindowToken(boolean show, WindowToken windowToken, int animationType) {
  3. if (windowToken == null || windowToken.getParent() == null) {
  4. return;
  5. }
  6. final Animation animation = show ? getFadeInAnimation() : getFadeOutAnimation();
  7. final FadeAnimationAdapter animationAdapter = animation != null
  8. ? createAdapter(createAnimationSpec(animation), show, windowToken) : null;
  9. if (animationAdapter == null) {
  10. return;
  11. }
  12. windowToken.startAnimation(windowToken.getPendingTransaction(), animationAdapter,
  13. show /* hidden */, animationType, null /* finishedCallback */);
  14. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/995997
推荐阅读
相关标签
  

闽ICP备14008679号