小工具知识网

当前位置: 首页 > 行业知识 > Android 13 WMS-动画流程

行业知识

Android 13 WMS-动画流程

2026-11-15 12:45:48 来源:互联网转载
 

动���的类型如下

    @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    })

ANIMATION_TYPE_APP_TRANSITION动画

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

动画的type = ANIMATION_TYPE_APP_TRANSITION

03-05 14:55:37.752  3059  3163 D jinyanmeianimation: SurfaceAnimator startAnimation mAnimation:com.android.server.wm.LocalAnimationAdapter@71444ae03-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)/@0x9c116b003-05 14:55:37.752  3059  3163 D jinyanmeianimation: SurfaceAnimator startAnimation t:android.view.SurfaceControl$Transaction@8d1482403-05 14:55:37.752  3059  3163 D jinyanmeianimation: SurfaceAnimator startAnimation type:103-05 14:55:37.752  3059  3163 D jinyanmeianimation: SurfaceAnimator startAnimation mInnerAnimationFinishedCallback:com.android.server.wm.SurfaceAnimator$$ExternalSyntheticLambda0@d22724f03-05 14:55:37.752  3059  3163 D jinyanmeianimation: java.lang.RuntimeException: jinyanmeianimation03-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$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  app.isAnimating(PARENTS, ANIMATION_TYPE_RECENTS))233                  || mDisplayContent.mClosingApps.stream().anyMatch(234                          (app) -> app.isAnimating(PARENTS, ANIMATION_TYPE_RECENTS));235          final ArraySet openingAppsForAnimation = getAppsForAnimation(236                  mDisplayContent.mOpeningApps, excludeLauncherFromAnimation);237          final ArraySet 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 is255          // what will control the animation theme. If all closing windows are obscured, then there is256          // no need to do an animation. This is the case, for example, when this transition is being257          // done behind a dream window.258          final ArraySet 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 override272          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 perform310          // 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 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() != null3000                      && imeTarget.getWindow().getTask() == task;3001              // Attach and show the IME screenshot when the task is the IME target and performing3002              // task closing transition to the next task.3003              if (isImeLayeringTarget && AppTransition.isTaskCloseTransitOld(transit)) {3004                  mDisplayContent.showImeScreenshot();3005              }3006          }3007          final Pair 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 getBackgroundColor3033                      // 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 through3037                      // the theme as the background color for the animation - the top most window3038                      // 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  

 计算transition的类型

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

 @TransitionOldType static int getTransitCompatType(AppTransition appTransition,            ArraySet openingApps, ArraySet closingApps,            ArraySet 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 openingWcs = getAnimationTargets(                openingApps, closingApps, true /* visible */);        final ArraySet 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;    }

加载和开始动画

getAnimationAdapter加载动画

 

首先遍历所有的windowContainer 调用applyAnimation

    private void applyAnimations(ArraySet wcs, ArraySet apps,            @TransitionOldType int transit, boolean visible, LayoutParams animLp,            boolean voiceInteraction) {        final int wcsCount = wcs.size();        for (int i = 0; i  

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

startAnimation 创建leash开始动画

 

SurfaceAnimation.java166      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 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 calls463                  // We want the leash to be visible immediately because the transaction which shows464                  // the leash may be deferred but the reparent will not. This will cause the leashed465                  // surface to be invisible until the deferred transaction is applied. If this466                  // doesn't work, you will can see the 2/3 button nav bar flicker during seamless467                  // 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.java171      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 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 the187                  // 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 point198                          if (mPreProcessingAnimations.get(animationLeash) == runningAnim) {199                              // In the case the animation is cancelled, edge extensions are removed200                              // onAnimationLeashLost which is called before onAnimationCancelled.201                              // So we need to check if the edge extensions have already been removed202                              // 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 be227              // 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

为动画添加listener

$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              @Override293              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 is297                          // fixed.298                          mFrameTransaction.setAlpha(a.mLeash, 1);299                      }300                  }301              }302  303              @Override304              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, the327          // start time would only be set in the next frame, leading to a delay.328          anim.doAnimationFrame(mChoreographer.getFrameTime());329      }330  

doFrame时更新动画位置

 

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

放vsync到来后, 执行onAnimationUpdate

119      @Override120      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      }

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

Rotation动画 ANIMATION_TYPE_SCREEN_ROTATION

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

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 */);    }

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

最终也会到SurfaceAnimation

 拿到动画适配器:

上一篇:超聚变存储服务器怎么用?

下一篇:王者怎么换服务器失败状态?