赞
踩
动画的类型如下
- @IntDef(flag = true, prefix = { "ANIMATION_TYPE_" }, value = {
- ANIMATION_TYPE_NONE,
- ANIMATION_TYPE_APP_TRANSITION,
- ANIMATION_TYPE_SCREEN_ROTATION,
- ANIMATION_TYPE_DIMMER,
- ANIMATION_TYPE_RECENTS,
- ANIMATION_TYPE_WINDOW_ANIMATION,
- ANIMATION_TYPE_INSETS_CONTROL,
- ANIMATION_TYPE_TOKEN_TRANSFORM,
- ANIMATION_TYPE_STARTING_REVEAL
- })
动画的type = ANIMATION_TYPE_APP_TRANSITION
- 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: SurfaceAnimator startAnimation mAnimation:com.android.server.wm.LocalAnimationAdapter@71444ae
- 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
- 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: SurfaceAnimator startAnimation t:android.view.SurfaceControl$Transaction@8d14824
- 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: SurfaceAnimator startAnimation type:1
- 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: SurfaceAnimator startAnimation mInnerAnimationFinishedCallback:com.android.server.wm.SurfaceAnimator$$ExternalSyntheticLambda0@d22724f
- 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: java.lang.RuntimeException: jinyanmeianimation
- 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: at com.android.server.wm.SurfaceAnimator.startAnimation(SurfaceAnimator.java:200)
- 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: at com.android.server.wm.WindowContainer.startAnimation(WindowContainer.java:2912)
- 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)
- 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: at com.android.server.wm.WindowContainer$AnimationRunnerBuilder$$ExternalSyntheticLambda4.startAnimation(Unknown Source:7)
- 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: at com.android.server.wm.WindowContainer.applyAnimationUnchecked(WindowContainer.java:3384)
- 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: at com.android.server.wm.WindowContainer.applyAnimation(WindowContainer.java:3072)
- 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: at com.android.server.wm.ActivityRecord.applyAnimation(ActivityRecord.java:6074)
- 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: at com.android.server.wm.AppTransitionController.applyAnimations(AppTransitionController.java:876)
- 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: at com.android.server.wm.AppTransitionController.applyAnimations(AppTransitionController.java:1083)
- 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: at com.android.server.wm.AppTransitionController.handleAppTransitionReady(AppTransitionController.java:293)
- 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: at com.android.server.wm.RootWindowContainer.checkAppTransitionReady(RootWindowContainer.java:1070)
- 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: at com.android.server.wm.RootWindowContainer.performSurfacePlacementNoTrace(RootWindowContainer.java:937)
- 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: at com.android.server.wm.RootWindowContainer.performSurfacePlacement(RootWindowContainer.java:877)
- 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementLoop(WindowSurfacePlacer.java:199)
- 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:148)
- 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:137)
- 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: at com.android.server.wm.WindowSurfacePlacer$Traverser.run(WindowSurfacePlacer.java:79)
- 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: at android.os.Handler.handleCallback(Handler.java:942)
- 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: at android.os.Handler.dispatchMessage(Handler.java:99)
- 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: at android.os.Looper.loopOnce(Looper.java:211)
- 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: at android.os.Looper.loop(Looper.java:300)
- 03-05 14:55:37.752 3059 3163 D jinyanmeianimation: at android.os.HandlerThread.run(HandlerThread.java:67)
- void handleAppTransitionReady() {
- 183 mTempTransitionReasons.clear();
- // //检查app transition是否已经准备好
-
- 184 if (!transitionGoodToGo(mDisplayContent.mOpeningApps, mTempTransitionReasons)
- 185 || !transitionGoodToGo(mDisplayContent.mChangingContainers, mTempTransitionReasons)
- 186 || !transitionGoodToGoForTaskFragments()) {
- 187 return;
- 188 }
- 189 Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "AppTransitionReady");
- 190
- 191 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "**** GOOD TO GO");
- 192 // TODO(b/205335975): Remove window which stuck in animatingExit status. Find actual cause.
- 193 mDisplayContent.forAllWindows(WindowState::cleanupAnimatingExitWindow,
- 194 true /* traverseTopToBottom */);
- 195 // TODO(new-app-transition): Remove code using appTransition.getAppTransition()
- 196 final AppTransition appTransition = mDisplayContent.mAppTransition;
- 197
- 198 mDisplayContent.mNoAnimationNotifyOnTransitionFinished.clear();
- 199
- 200 appTransition.removeAppTransitionTimeoutCallbacks();
- 201
- 202 mDisplayContent.mWallpaperMayChange = false;
- 203
- 204 int appCount = mDisplayContent.mOpeningApps.size();
- 205 for (int i = 0; i < appCount; ++i) {
- 206 // Clearing the mAnimatingExit flag before entering animation. It's set to true if app
- 207 // window is removed, or window relayout to invisible. This also affects window
- 208 // visibility. We need to clear it *before* maybeUpdateTransitToWallpaper() as the
- 209 // transition selection depends on wallpaper target visibility.
- 210 mDisplayContent.mOpeningApps.valueAtUnchecked(i).clearAnimatingFlags();
- 211 }
- 212 appCount = mDisplayContent.mChangingContainers.size();
- 213 for (int i = 0; i < appCount; ++i) {
- 214 // Clearing for same reason as above.
- 215 final ActivityRecord activity = getAppFromContainer(
- 216 mDisplayContent.mChangingContainers.valueAtUnchecked(i));
- 217 if (activity != null) {
- 218 activity.clearAnimatingFlags();
- 219 }
- 220 }
- 221
- 222 // Adjust wallpaper before we pull the lower/upper target, since pending changes
- 223 // (like the clearAnimatingFlags() above) might affect wallpaper target result.
- 224 // Or, the opening app window should be a wallpaper target.
- 225 mWallpaperControllerLocked.adjustWallpaperWindowsForAppTransitionIfNeeded(
- 226 mDisplayContent.mOpeningApps);
- 227
- 228 // Remove launcher from app transition animation while recents is running. Recents animation
- 229 // is managed outside of app transition framework, so we just need to commit visibility.
- 230 final boolean excludeLauncherFromAnimation =
- 231 mDisplayContent.mOpeningApps.stream().anyMatch(
- 232 (app) -> app.isAnimating(PARENTS, ANIMATION_TYPE_RECENTS))
- 233 || mDisplayContent.mClosingApps.stream().anyMatch(
- 234 (app) -> app.isAnimating(PARENTS, ANIMATION_TYPE_RECENTS));
- 235 final ArraySet<ActivityRecord> openingAppsForAnimation = getAppsForAnimation(
- 236 mDisplayContent.mOpeningApps, excludeLauncherFromAnimation);
- 237 final ArraySet<ActivityRecord> closingAppsForAnimation = getAppsForAnimation(
- 238 mDisplayContent.mClosingApps, excludeLauncherFromAnimation);
- 239
- 240 @TransitionOldType final int transit = getTransitCompatType(
- 241 mDisplayContent.mAppTransition, openingAppsForAnimation, closingAppsForAnimation,
- 242 mDisplayContent.mChangingContainers,
- 243 mWallpaperControllerLocked.getWallpaperTarget(), getOldWallpaper(),
- 244 mDisplayContent.mSkipAppTransitionAnimation);
- 245 mDisplayContent.mSkipAppTransitionAnimation = false;
- 246
- 247 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
- 248 "handleAppTransitionReady: displayId=%d appTransition={%s}"
- 249 + " excludeLauncherFromAnimation=%b openingApps=[%s] closingApps=[%s] transit=%s",
- 250 mDisplayContent.mDisplayId, appTransition.toString(), excludeLauncherFromAnimation,
- 251 mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
- 252 AppTransition.appTransitionOldToString(transit));
- 253
- 254 // Find the layout params of the top-most application window in the tokens, which is
- 255 // what will control the animation theme. If all closing windows are obscured, then there is
- 256 // no need to do an animation. This is the case, for example, when this transition is being
- 257 // done behind a dream window.
- 258 final ArraySet<Integer> activityTypes = collectActivityTypes(openingAppsForAnimation,
- 259 closingAppsForAnimation, mDisplayContent.mChangingContainers);
- //首先会获取当前需要opening和closing的app window列表(ActivityRecord类型)
- 260 final ActivityRecord animLpActivity = findAnimLayoutParamsToken(transit, activityTypes,
- 261 openingAppsForAnimation, closingAppsForAnimation,
- 262 mDisplayContent.mChangingContainers);
- 263 final ActivityRecord topOpeningApp =
- 264 getTopApp(openingAppsForAnimation, false /* ignoreHidden */);
- 265 final ActivityRecord topClosingApp =
- 266 getTopApp(closingAppsForAnimation, false /* ignoreHidden */);
- 267 final ActivityRecord topChangingApp =
- 268 getTopApp(mDisplayContent.mChangingContainers, false /* ignoreHidden */);
- 269 final WindowManager.LayoutParams animLp = getAnimLp(animLpActivity);
- 270
- 271 // Check if there is any override
- 272 if (!overrideWithTaskFragmentRemoteAnimation(transit, activityTypes)) {
- 273 // Unfreeze the windows that were previously frozen for TaskFragment animation.
- 274 unfreezeEmbeddedChangingWindows();
- 275 overrideWithRemoteAnimationIfSet(animLpActivity, transit, activityTypes);
- 276 }
- 277
- 278 final boolean voiceInteraction = containsVoiceInteraction(closingAppsForAnimation)
- 279 || containsVoiceInteraction(openingAppsForAnimation);
- 280
- 281 final int layoutRedo;
- 282 mService.mSurfaceAnimationRunner.deferStartingAnimations();
- 283 try {
- //然后在applyAnimations方法里面对window列表进行遍历WindowContainer的动画applyAnimation方法的调用
- 284 applyAnimations(openingAppsForAnimation, closingAppsForAnimation, transit, animLp,
- 285 voiceInteraction);
- 286 handleClosingApps();
- 287 handleOpeningApps();
- 288 handleChangingApps(transit);
- 289
- 290 appTransition.setLastAppTransition(transit, topOpeningApp,
- 291 topClosingApp, topChangingApp);
- 292
- 293 final int flags = appTransition.getTransitFlags();
- 294 layoutRedo = appTransition.goodToGo(transit, topOpeningApp);
- 295 handleNonAppWindowsInTransition(transit, flags);
- 296 appTransition.postAnimationCallback();
- 297 appTransition.clear();
- 298 } finally {
- 299 mService.mSurfaceAnimationRunner.continueStartingAnimations();
- 300 }
- 301
- 302 mService.mTaskSnapshotController.onTransitionStarting(mDisplayContent);
- 303
- 304 mDisplayContent.mOpeningApps.clear();
- 305 mDisplayContent.mClosingApps.clear();
- 306 mDisplayContent.mChangingContainers.clear();
- 307 mDisplayContent.mUnknownAppVisibilityController.clear();
- 308
- 309 // This has changed the visibility of windows, so perform
- 310 // a new layout to get them all up-to-date.
- 311 mDisplayContent.setLayoutNeeded();
- 312
- 313 mDisplayContent.computeImeTarget(true /* updateImeTarget */);
- 314
- 315 mService.mAtmService.mTaskSupervisor.getActivityMetricsLogger().notifyTransitionStarting(
- 316 mTempTransitionReasons);
- 317
- 318 Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
- 319
- 320 mDisplayContent.pendingLayoutChanges |=
- 321 layoutRedo | FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_CONFIG;
- 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
第二开始动画
- protected void applyAnimationUnchecked(WindowManager.LayoutParams lp, boolean enter,
- 2994 @TransitionOldType int transit, boolean isVoiceInteraction,
- 2995 @Nullable ArrayList<WindowContainer> sources) {
- 2996 final Task task = asTask();
- 2997 if (task != null && !enter && !task.isActivityTypeHomeOrRecents()) {
- 2998 final InsetsControlTarget imeTarget = mDisplayContent.getImeTarget(IME_TARGET_LAYERING);
- 2999 final boolean isImeLayeringTarget = imeTarget != null && imeTarget.getWindow() != null
- 3000 && imeTarget.getWindow().getTask() == task;
- 3001 // Attach and show the IME screenshot when the task is the IME target and performing
- 3002 // task closing transition to the next task.
- 3003 if (isImeLayeringTarget && AppTransition.isTaskCloseTransitOld(transit)) {
- 3004 mDisplayContent.showImeScreenshot();
- 3005 }
- 3006 }
- 3007 final Pair<AnimationAdapter, AnimationAdapter> adapters = getAnimationAdapter(lp,
- 3008 transit, enter, isVoiceInteraction);
- 3009 AnimationAdapter adapter = adapters.first;
- 3010 AnimationAdapter thumbnailAdapter = adapters.second;
- 3011 if (adapter != null) {
- 3012 if (sources != null) {
- 3013 mSurfaceAnimationSources.addAll(sources);
- 3014 }
- 3015
- 3016 AnimationRunnerBuilder animationRunnerBuilder = new AnimationRunnerBuilder();
- 3017
- 3018 if (isTaskTransitOld(transit)) {
- 3019 animationRunnerBuilder.setTaskBackgroundColor(getTaskAnimationBackgroundColor());
- 3020 // TODO: Remove when we migrate to shell (b/202383002)
- 3021 if (mWmService.mTaskTransitionSpec != null) {
- 3022 animationRunnerBuilder.hideInsetSourceViewOverflows(
- 3023 mWmService.mTaskTransitionSpec.animationBoundInsets);
- 3024 }
- 3025 }
- 3026
- 3027 final ActivityRecord activityRecord = asActivityRecord();
- 3028 if (activityRecord != null && isActivityTransitOld(transit)
- 3029 && adapter.getShowBackground()) {
- 3030 final @ColorInt int backgroundColorForTransition;
- 3031 if (adapter.getBackgroundColor() != 0) {
- 3032 // If available use the background color provided through getBackgroundColor
- 3033 // which if set originates from a call to overridePendingAppTransition.
- 3034 backgroundColorForTransition = adapter.getBackgroundColor();
- 3035 } else {
- 3036 // Otherwise default to the window's background color if provided through
- 3037 // the theme as the background color for the animation - the top most window
- 3038 // with a valid background color and showBackground set takes precedence.
- 3039 final Task arTask = activityRecord.getTask();
- 3040 backgroundColorForTransition = ColorUtils.setAlphaComponent(
- 3041 arTask.getTaskDescription().getBackgroundColor(), 255);
- 3042 }
- 3043 animationRunnerBuilder.setTaskBackgroundColor(backgroundColorForTransition);
- 3044 }
- 3045
- 3046 animationRunnerBuilder.build()
- 3047 .startAnimation(getPendingTransaction(), adapter, !isVisible(),
- 3048 ANIMATION_TYPE_APP_TRANSITION, thumbnailAdapter);
- 3049
- 3050 if (adapter.getShowWallpaper()) {
- 3051 getDisplayContent().pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
- 3052 }
- 3053 }
- 3054 }
- 3055
在getTransitCompatType中会对动画做转换,将动画转化为old类型的动画
- @TransitionOldType static int getTransitCompatType(AppTransition appTransition,
- ArraySet<ActivityRecord> openingApps, ArraySet<ActivityRecord> closingApps,
- ArraySet<WindowContainer> changingContainers, @Nullable WindowState wallpaperTarget,
- @Nullable WindowState oldWallpaper, boolean skipAppTransitionAnimation) {
- Slog.d("jinyanmeianimation","getTransitCompatType appTransition :" + appTransition );
-
- Slog.d("jinyanmeianimation","getTransitCompatType appTransition :" + appTransition , new RuntimeException("jinyanmeianimation"));
-
-
- // Determine if closing and opening app token sets are wallpaper targets, in which case
- // special animations are needed.
- final boolean openingAppHasWallpaper = canBeWallpaperTarget(openingApps)
- && wallpaperTarget != null;
- final boolean closingAppHasWallpaper = canBeWallpaperTarget(closingApps)
- && wallpaperTarget != null;
-
- // Keyguard transit has highest priority.
- switch (appTransition.getKeyguardTransition()) {
- case TRANSIT_KEYGUARD_GOING_AWAY:
- return openingAppHasWallpaper ? TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER
- : TRANSIT_OLD_KEYGUARD_GOING_AWAY;
- case TRANSIT_KEYGUARD_OCCLUDE:
- // When there is a closing app, the keyguard has already been occluded by an
- // activity, and another activity has started on top of that activity, so normal
- // app transition animation should be used.
- return closingApps.isEmpty() ? TRANSIT_OLD_KEYGUARD_OCCLUDE
- : TRANSIT_OLD_ACTIVITY_OPEN;
- case TRANSIT_KEYGUARD_UNOCCLUDE:
- return TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
- }
-
- // This is not keyguard transition and one of the app has request to skip app transition.
- // MIUI MOD: START
- // For Stage Split Screen: Drag to enter split-screen feature.
- // if (skipAppTransitionAnimation) {
- if (skipAppTransitionAnimation ||
- ActivityTaskManagerServiceStub.get().removeSplitTaskShotIfNeed()) {
- // END
- return WindowManager.TRANSIT_OLD_UNSET;
- }
- @TransitionFlags final int flags = appTransition.getTransitFlags();
- @TransitionType final int firstTransit = appTransition.getFirstAppTransition();
-
- // Special transitions
- // TODO(new-app-transitions): Revisit if those can be rewritten by using flags.
- if (appTransition.containsTransitRequest(TRANSIT_CHANGE) && !changingContainers.isEmpty()) {
- // MIUI ADD: START Activity Embedding Resizing
- if (MiuiEmbeddingWindowServiceStub.get()
- .skipAppTransitionAnimationForEmbeddingDivider()) {
- return WindowManager.TRANSIT_OLD_UNSET;
- }
- // END
- @TransitContainerType int changingType =
- getTransitContainerType(changingContainers.valueAt(0));
- switch (changingType) {
- case TYPE_TASK:
- return TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE;
- case TYPE_TASK_FRAGMENT:
- return TRANSIT_OLD_TASK_FRAGMENT_CHANGE;
- default:
- throw new IllegalStateException(
- "TRANSIT_CHANGE with unrecognized changing type=" + changingType);
- }
- }
- if ((flags & TRANSIT_FLAG_APP_CRASHED) != 0) {
- return TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE;
- }
- if (firstTransit == TRANSIT_NONE) {
- return TRANSIT_OLD_NONE;
- }
-
- /*
- * There are cases where we open/close a new task/activity, but in reality only a
- * translucent activity on top of existing activities is opening/closing. For that one, we
- * have a different animation because non of the task/activity animations actually work well
- * with translucent apps.
- */
- if (isNormalTransit(firstTransit)) {
- boolean allOpeningVisible = true;
- boolean allTranslucentOpeningApps = !openingApps.isEmpty();
- for (int i = openingApps.size() - 1; i >= 0; i--) {
- final ActivityRecord activity = openingApps.valueAt(i);
- if (!activity.isVisible()) {
- allOpeningVisible = false;
- if (activity.fillsParent()) {
- allTranslucentOpeningApps = false;
- }
- }
- }
- boolean allTranslucentClosingApps = !closingApps.isEmpty();
- for (int i = closingApps.size() - 1; i >= 0; i--) {
- if (closingApps.valueAt(i).fillsParent()) {
- allTranslucentClosingApps = false;
- break;
- }
- }
-
- if (allTranslucentClosingApps && allOpeningVisible) {
- return TRANSIT_OLD_TRANSLUCENT_ACTIVITY_CLOSE;
- }
- if (allTranslucentOpeningApps && closingApps.isEmpty()) {
- return TRANSIT_OLD_TRANSLUCENT_ACTIVITY_OPEN;
- }
- }
-
- final ActivityRecord topOpeningApp = getTopApp(openingApps,
- false /* ignoreHidden */);
- final ActivityRecord topClosingApp = getTopApp(closingApps,
- true /* ignoreHidden */);
-
- if (closingAppHasWallpaper && openingAppHasWallpaper) {
- ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Wallpaper animation!");
- switch (firstTransit) {
- case TRANSIT_OPEN:
- case TRANSIT_TO_FRONT:
- return TRANSIT_OLD_WALLPAPER_INTRA_OPEN;
- case TRANSIT_CLOSE:
- case TRANSIT_TO_BACK:
- return TRANSIT_OLD_WALLPAPER_INTRA_CLOSE;
- }
- } else if (oldWallpaper != null && !openingApps.isEmpty()
- && !openingApps.contains(oldWallpaper.mActivityRecord)
- && closingApps.contains(oldWallpaper.mActivityRecord)
- && topClosingApp == oldWallpaper.mActivityRecord) {
- // We are transitioning from an activity with a wallpaper to one without.
- return TRANSIT_OLD_WALLPAPER_CLOSE;
- } else if (wallpaperTarget != null && wallpaperTarget.isVisible()
- && openingApps.contains(wallpaperTarget.mActivityRecord)
- && topOpeningApp == wallpaperTarget.mActivityRecord
- /* && transit != TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE */) {
- // We are transitioning from an activity without
- // a wallpaper to now showing the wallpaper
- return TRANSIT_OLD_WALLPAPER_OPEN;
- }
-
- final ArraySet<WindowContainer> openingWcs = getAnimationTargets(
- openingApps, closingApps, true /* visible */);
- final ArraySet<WindowContainer> closingWcs = getAnimationTargets(
- openingApps, closingApps, false /* visible */);
- final WindowContainer<?> openingContainer = !openingWcs.isEmpty()
- ? openingWcs.valueAt(0) : null;
- final WindowContainer<?> closingContainer = !closingWcs.isEmpty()
- ? closingWcs.valueAt(0) : null;
- @TransitContainerType int openingType = getTransitContainerType(openingContainer);
- @TransitContainerType int closingType = getTransitContainerType(closingContainer);
- if (appTransition.containsTransitRequest(TRANSIT_TO_FRONT) && openingType == TYPE_TASK) {
- return TRANSIT_OLD_TASK_TO_FRONT;
- }
- if (appTransition.containsTransitRequest(TRANSIT_TO_BACK) && closingType == TYPE_TASK) {
- return TRANSIT_OLD_TASK_TO_BACK;
- }
- if (appTransition.containsTransitRequest(TRANSIT_OPEN)) {
- if (openingType == TYPE_TASK) {
- return (appTransition.getTransitFlags() & TRANSIT_FLAG_OPEN_BEHIND) != 0
- ? TRANSIT_OLD_TASK_OPEN_BEHIND : TRANSIT_OLD_TASK_OPEN;
- }
- if (openingType == TYPE_ACTIVITY) {
- return TRANSIT_OLD_ACTIVITY_OPEN;
- }
- if (openingType == TYPE_TASK_FRAGMENT) {
- return TRANSIT_OLD_TASK_FRAGMENT_OPEN;
- }
- }
- if (appTransition.containsTransitRequest(TRANSIT_CLOSE)) {
- if (closingType == TYPE_TASK) {
- return TRANSIT_OLD_TASK_CLOSE;
- }
- if (closingType == TYPE_TASK_FRAGMENT) {
- return TRANSIT_OLD_TASK_FRAGMENT_CLOSE;
- }
- if (closingType == TYPE_ACTIVITY) {
- for (int i = closingApps.size() - 1; i >= 0; i--) {
- if (closingApps.valueAt(i).visibleIgnoringKeyguard) {
- return TRANSIT_OLD_ACTIVITY_CLOSE;
- }
- }
- // Skip close activity transition since no closing app can be visible
- return WindowManager.TRANSIT_OLD_UNSET;
- }
- }
- if (appTransition.containsTransitRequest(TRANSIT_RELAUNCH)
- && !openingWcs.isEmpty() && !openingApps.isEmpty()) {
- return TRANSIT_OLD_ACTIVITY_RELAUNCH;
- }
- return TRANSIT_OLD_NONE;
- }
首先遍历所有的windowContainer 调用applyAnimation
- private void applyAnimations(ArraySet<WindowContainer> wcs, ArraySet<ActivityRecord> apps,
- @TransitionOldType int transit, boolean visible, LayoutParams animLp,
- boolean voiceInteraction) {
- final int wcsCount = wcs.size();
- for (int i = 0; i < wcsCount; i++) {
- final WindowContainer wc = wcs.valueAt(i);
- // If app transition animation target is promoted to higher level, SurfaceAnimator
- // triggers WC#onAnimationFinished only on the promoted target. So we need to take care
- // of triggering AR#onAnimationFinished on each ActivityRecord which is a part of the
- // app transition.
- final ArrayList<ActivityRecord> transitioningDescendants = new ArrayList<>();
- for (int j = 0; j < apps.size(); ++j) {
- final ActivityRecord app = apps.valueAt(j);
- if (app.isDescendantOf(wc)) {
- transitioningDescendants.add(app);
- }
- }
- wc.applyAnimation(animLp, transit, visible, voiceInteraction, transitioningDescendants);
- }
- }
然后调用getAnimationAdapter 根据窗口层次结构中给定的窗口布局属性获取动画适配器
- SurfaceAnimation.java
- 166 void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
- 167 @AnimationType int type,
- 168 @Nullable OnAnimationFinishedCallback animationFinishedCallback,
- 169 @Nullable Runnable animationCancelledCallback,
- 170 @Nullable AnimationAdapter snapshotAnim, @Nullable SurfaceFreezer freezer) {
- 171 cancelAnimation(t, true /* restarting */, true /* forwardCancel */);
- 172 mAnimation = anim;
- 173 mAnimationType = type;
- 174 mSurfaceAnimationFinishedCallback = animationFinishedCallback;
- 175 mAnimationCancelledCallback = animationCancelledCallback;
- 176 final SurfaceControl surface = mAnimatable.getSurfaceControl();
- 177 if (surface == null) {
- 178 Slog.w(TAG, "Unable to start animation, surface is null or no children.");
- 179 cancelAnimation();
- 180 return;
- 181 }
- 182 mLeash = freezer != null ? freezer.takeLeashForAnimation() : null;
- 183 if (mLeash == null) {
- 184 mLeash = createAnimationLeash(mAnimatable, surface, t, type,
- 185 mAnimatable.getSurfaceWidth(), mAnimatable.getSurfaceHeight(), 0 /* x */,
- 186 0 /* y */, hidden, mService.mTransactionFactory);
- 187 mAnimatable.onAnimationLeashCreated(t, mLeash);
- 188 }
- 189 mAnimatable.onLeashAnimationStarting(t, mLeash);
- 190 if (mAnimationStartDelayed) {
- 191 ProtoLog.i(WM_DEBUG_ANIM, "Animation start delayed for %s", mAnimatable);
- 192 return;
- 193 }
- 194 mAnimation.startAnimation(mLeash, t, type, mInnerAnimationFinishedCallback);
- 195 if (ProtoLogImpl.isEnabled(WM_DEBUG_ANIM)) {
- 196 StringWriter sw = new StringWriter();
- 197 PrintWriter pw = new PrintWriter(sw);
- 198 mAnimation.dump(pw, "");
- 199 ProtoLog.d(WM_DEBUG_ANIM, "Animation start for %s, anim=%s", mAnimatable, sw);
- 200 }
- 201 if (snapshotAnim != null) {
- 202 mSnapshot = freezer.takeSnapshotForAnimation();
- 203 if (mSnapshot == null) {
- 204 Slog.e(TAG, "No snapshot target to start animation on for " + mAnimatable);
- 205 return;
- 206 }
- 207 mSnapshot.startAnimation(t, snapshotAnim, type);
- 208 }
- 209 }
可见创建一个SuefaceControl, 然后把 WindowContainer的surface挂在了leash上面, 然后对leash做动画
- 455 static SurfaceControl createAnimationLeash(Animatable animatable, SurfaceControl surface,
- 456 Transaction t, @AnimationType int type, int width, int height, int x, int y,
- 457 boolean hidden, Supplier<Transaction> transactionFactory) {
- 458 ProtoLog.i(WM_DEBUG_ANIM, "Reparenting to leash for %s", animatable);
- 459 final SurfaceControl.Builder builder = animatable.makeAnimationLeash()
- 460 .setParent(animatable.getAnimationLeashParent())
- 461 .setName(surface + " - animation-leash of " + animationTypeToString(type))
- 462 // TODO(b/151665759) Defer reparent calls
- 463 // We want the leash to be visible immediately because the transaction which shows
- 464 // the leash may be deferred but the reparent will not. This will cause the leashed
- 465 // surface to be invisible until the deferred transaction is applied. If this
- 466 // doesn't work, you will can see the 2/3 button nav bar flicker during seamless
- 467 // rotation.
- 468 .setHidden(hidden)
- 469 .setEffectLayer()
- 470 .setCallsite("SurfaceAnimator.createAnimationLeash");
- 471 final SurfaceControl leash = builder.build();
- 472 t.setWindowCrop(leash, width, height);
- 473 t.setPosition(leash, x, y);
- 474 t.show(leash);
- 475 t.setAlpha(leash, hidden ? 0 : 1);
- 476
- 477 t.reparent(surface, leash);
- 478 return leash;
- 479 }
- SurfaceAnimationRunner.java
-
- 171 void startAnimation(AnimationSpec a, SurfaceControl animationLeash, Transaction t,
- 172 Runnable finishCallback) {
- 173 synchronized (mLock) {
- 174 final RunningAnimation runningAnim = new RunningAnimation(a, animationLeash,
- 175 finishCallback);
- 176 boolean requiresEdgeExtension = requiresEdgeExtension(a);
- 177
- 178 if (requiresEdgeExtension) {
- 179 final ArrayList<SurfaceControl> extensionSurfaces = new ArrayList<>();
- 180 synchronized (mEdgeExtensionLock) {
- 181 mEdgeExtensions.put(animationLeash, extensionSurfaces);
- 182 }
- 183
- 184 mPreProcessingAnimations.put(animationLeash, runningAnim);
- 185
- 186 // We must wait for t to be committed since otherwise the leash doesn't have the
- 187 // windows we want to screenshot and extend as children.
- 188 t.addTransactionCommittedListener(mEdgeExtensionExecutor, () -> {
- 189 final WindowAnimationSpec animationSpec = a.asWindowAnimationSpec();
- 190
- 191 final Transaction edgeExtensionCreationTransaction = new Transaction();
- 192 edgeExtendWindow(animationLeash,
- 193 animationSpec.getRootTaskBounds(), animationSpec.getAnimation(),
- 194 edgeExtensionCreationTransaction);
- 195
- 196 synchronized (mLock) {
- 197 // only run if animation is not yet canceled by this point
- 198 if (mPreProcessingAnimations.get(animationLeash) == runningAnim) {
- 199 // In the case the animation is cancelled, edge extensions are removed
- 200 // onAnimationLeashLost which is called before onAnimationCancelled.
- 201 // So we need to check if the edge extensions have already been removed
- 202 // or not, and if so we don't want to apply the transaction.
- 203 synchronized (mEdgeExtensionLock) {
- 204 if (!mEdgeExtensions.isEmpty()) {
- 205 edgeExtensionCreationTransaction.apply();
- 206 }
- 207 }
- 208
- 209 mPreProcessingAnimations.remove(animationLeash);
- 210 mPendingAnimations.put(animationLeash, runningAnim);
- 211 if (!mAnimationStartDeferred && mPreProcessingAnimations.isEmpty()) {
- 212 mChoreographer.postFrameCallback(this::startAnimations);
- 213 }
- 214 }
- 215 }
- 216 });
- 217 }
- 218
- 219 if (!requiresEdgeExtension) {
- 220 mPendingAnimations.put(animationLeash, runningAnim);
- 221 if (!mAnimationStartDeferred && mPreProcessingAnimations.isEmpty()) {
- 222 mChoreographer.postFrameCallback(this::startAnimations);
- 223 }
- 224 }
- 225
- 226 // Some animations (e.g. move animations) require the initial transform to be
- 227 // applied immediately.
- 228 applyTransformation(runningAnim, t, 0 /* currentPlayTime */);
- 229 }
- 230 }
- scheduleFrameLocked:862, Choreographer (android.view)
- postCallbackDelayedInternal:605, Choreographer (android.view)
- postFrameCallbackDelayed:702, Choreographer (android.view)
- postFrameCallback:682, Choreographer (android.view)
- continueStartingAnimations:173, SurfaceAnimationRunner (com.android.server.wm)
- handleAppTransitionReady:312, AppTransitionController (com.android.server.wm)
- checkAppTransitionReady:1070, RootWindowContainer (com.android.server.wm)
- performSurfacePlacementNoTrace:937, RootWindowContainer (com.android.server.wm)
- performSurfacePlacement:877, RootWindowContainer (com.android.server.wm)
- performSurfacePlacementLoop:199, WindowSurfacePlacer (com.android.server.wm)
- performSurfacePlacement:148, WindowSurfacePlacer (com.android.server.wm)
- performSurfacePlacement:137, WindowSurfacePlacer (com.android.server.wm)
- handleAppTransitionTimeout:1814, AppTransition (com.android.server.wm)
- lambda$new$0$com-android-server-wm-AppTransition:243, AppTransition (com.android.server.wm)
- run:-1, AppTransition$$ExternalSyntheticLambda3 (com.android.server.wm)
- handleCallback:942, Handler (android.os)
- dispatchMessage:99, Handler (android.os)
- loopOnce:211, Looper (android.os)
- loop:300, Looper (android.os)
- run:67, HandlerThread (android.os)
- run:46, ServiceThread (com.android.server)
- SurfaceAnimationRunner.java
- private void startAnimationLocked(RunningAnimation a) {
- 270 final ValueAnimator anim = mAnimatorFactory.makeAnimator();
- 271
- 272 // Animation length is already expected to be scaled.
- 273 anim.overrideDurationScale(1.0f);
- 274 anim.setDuration(a.mAnimSpec.getDuration());
- 275 anim.addUpdateListener(animation -> {
- 276 synchronized (mCancelLock) {
- 277 if (!a.mCancelled) {
- 278 final long duration = anim.getDuration();
- 279 long currentPlayTime = anim.getCurrentPlayTime();
- 280 if (currentPlayTime > duration) {
- 281 currentPlayTime = duration;
- 282 }
- 283 applyTransformation(a, mFrameTransaction, currentPlayTime);
- 284 }
- 285 }
- 286
- 287 // Transaction will be applied in the commit phase.
- 288 scheduleApplyTransaction();
- 289 });
- 290
- 291 anim.addListener(new AnimatorListenerAdapter() {
- 292 @Override
- 293 public void onAnimationStart(Animator animation) {
- 294 synchronized (mCancelLock) {
- 295 if (!a.mCancelled) {
- 296 // TODO: change this back to use show instead of alpha when b/138459974 is
- 297 // fixed.
- 298 mFrameTransaction.setAlpha(a.mLeash, 1);
- 299 }
- 300 }
- 301 }
- 302
- 303 @Override
- 304 public void onAnimationEnd(Animator animation) {
- 305 synchronized (mLock) {
- 306 mRunningAnimations.remove(a.mLeash);
- 307 synchronized (mCancelLock) {
- 308 if (!a.mCancelled) {
- 309
- 310 // Post on other thread that we can push final state without jank.
- 311 mAnimationThreadHandler.post(a.mFinishCallback);
- 312 }
- 313 }
- 314 }
- 315 }
- 316 });
- 317 a.mAnim = anim;
- 318 mRunningAnimations.put(a.mLeash, a);
- 319
- 320 anim.start();
- 321 if (a.mAnimSpec.canSkipFirstFrame()) {
- 322 // If we can skip the first frame, we start one frame later.
- 323 anim.setCurrentPlayTime(mChoreographer.getFrameIntervalNanos() / NANOS_PER_MS);
- 324 }
- 325
- 326 // Immediately start the animation by manually applying an animation frame. Otherwise, the
- 327 // start time would only be set in the next frame, leading to a delay.
- 328 anim.doAnimationFrame(mChoreographer.getFrameTime());
- 329 }
- 330
放vsync到来后, 执行onAnimationUpdate
- private void applyTransformation(RunningAnimation a, Transaction t, long currentPlayTime) {
- a.mAnimSpec.apply(t, a.mLeash, currentPlayTime);
- }
再来看下apply方法的具体实现,通过之前以具体xml资源创建的mAnimation对象,根据当前时间片currentPlayTime获取到当前的tmp.transformation,对leash对象实现了Matrix(大小,位置),Alpha,Crop等transformation变化,再通过Transaction 交给surfaceflinger显示,从而实现了动画当前时间片的显示效果。对比旧动画机制,这个transformation变化是在WindowStateAnimator类里面实现的。为什么要重点关注这个方法呢?因为如果窗口动画出bug了(位置大小不对?透明度异常?),就可以在这个方法里面打印window的相关参数来初步定位原因。
- 119 @Override
- 120 public void apply(Transaction t, SurfaceControl leash, long currentPlayTime) {
- 121 final TmpValues tmp = mThreadLocalTmps.get();
- 122 tmp.transformation.clear();
- 123 mAnimation.getTransformation(currentPlayTime, tmp.transformation);
- 124 tmp.transformation.getMatrix().postTranslate(mPosition.x, mPosition.y);
- 125 t.setMatrix(leash, tmp.transformation.getMatrix(), tmp.floats);
- 126 t.setAlpha(leash, tmp.transformation.getAlpha());
- 127
- 128 boolean cropSet = false;
- 129 if (mRootTaskClipMode == ROOT_TASK_CLIP_NONE) {
- 130 if (tmp.transformation.hasClipRect()) {
- 131 final Rect clipRect = tmp.transformation.getClipRect();
- 132 accountForExtension(tmp.transformation, clipRect);
- 133 t.setWindowCrop(leash, clipRect);
- 134 cropSet = true;
- 135 }
- 136 } else {
- 137 mTmpRect.set(mRootTaskBounds);
- 138 if (tmp.transformation.hasClipRect()) {
- 139 mTmpRect.intersect(tmp.transformation.getClipRect());
- 140 }
- 141 accountForExtension(tmp.transformation, mTmpRect);
- 142 t.setWindowCrop(leash, mTmpRect);
- 143 cropSet = true;
- 144 }
- 145
- 146 // We can only apply rounded corner if a crop is set, as otherwise the value is meaningless,
- 147 // since it doesn't have anything it's relative to.
- 148 if (cropSet && mAnimation.hasRoundedCorners() && mWindowCornerRadius > 0) {
- 149 t.setCornerRadius(leash, mWindowCornerRadius);
- 150 }
- 151 }
6、ValueAnimator类,从上面的介绍可以得知,窗口动画的最终本质就是一个ValueAnimator属性动画,理解了这一点,就相当于把窗口动画简单化了,最终的实现就类比于我们普通app的属性动画的实现(app属性动画的对象是view,窗口属性动画的对象是window),只不过整个流程比较复杂而已,但是最终的实现原理是一样的,殊途同归,这个才是android窗口动画机制的精髓所在
1. 根据sensor导致的旋转动画
最终也会到SurfaceAnimation
拿到动画适配器:
- FadeAnimationController.java
-
- public void fadeWindowToken(boolean show, WindowToken windowToken, int animationType) {
- if (windowToken == null || windowToken.getParent() == null) {
- return;
- }
-
- final Animation animation = show ? getFadeInAnimation() : getFadeOutAnimation();
- final FadeAnimationAdapter animationAdapter = animation != null
- ? createAdapter(createAnimationSpec(animation), show, windowToken) : null;
- if (animationAdapter == null) {
- return;
- }
-
- windowToken.startAnimation(windowToken.getPendingTransaction(), animationAdapter,
- show /* hidden */, animationType, null /* finishedCallback */);
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。