Android 过渡动画启动过程总结 -- 基于S版本

3,066 阅读5分钟

过渡动画总结

本文主要是基于android S版本来整理下过渡动画的初始化过程以及启动过程,过渡动画是指在Activity切换过程中或者是从桌面打开app过程中出现的切换动画。
首先,看下目前android存在的几种动画,这里直接参考了源远大佬的图
目标WindowContainer名称示例
WindowState窗口动画Toast弹出动画、dialog弹出动画
AppWindowToken过渡动画Activity切换动画、app启动动画
TaskTask动画Recents动画
DisplayContent全屏动画旋转屏动画

本文的主要目录结构如下:

image.png

1.Activity的切换过程

Activity的切换过程主要就是指之前的activity从resumed状态-> paused状态,新打开的activity从start状态->resume状态,并将前一个窗口设置为不可见,新打开的窗口设置为可见,而过渡动画的初始化也是在Activity切换过程中完成的。

我们先来跟一下Activity的切换过程,然后会在该过程中去preareApptransition。

Android在S版本上取消了ActivityStack的定义,而是采用了更高级的抽象Task直接来代替stack(区分时可以通过asTask方法进行判断),resume新的Activity会经历如下流程:

Task#resumeTopActivityUncheckedLocked -> Task#resumeTopActivityInnerLocked -> DisplayContent#prepareApptransition -> ... -> apply过渡动画

1.1 Task#resumeTopActivityUncheckedLocked

boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options,
        boolean deferPause) {
    if (mInResumeTopActivity) {  //已经resume 直接退出
        // Don't even start recursing.
        return false;
    }

    boolean someActivityResumed = false;
    try {
        // Protect against recursion.
        mInResumeTopActivity = true;

        if (isLeafTask()) {  //就是判断是ActivityRecord还是task  不是task则进入
            if (isFocusableAndVisible()) { //判断是否是顶部focus的Activity以及其是否应该可见
                someActivityResumed = resumeTopActivityInnerLocked(prev, options, deferPause);  //继续resume流程
            }
        } else {
        //如果当前是task  则获取其child开始resume流程
            int idx = mChildren.size() - 1;
            while (idx >= 0) {
                final Task child = getChildAt(idx--).asTask();
                if (child == null) {
                    continue;
                }
                // END
                if (!child.isTopActivityFocusable()) {
                    continue;
                }
                if (child.getVisibility(null /* starting */) != TASK_VISIBILITY_VISIBLE) {
                    break;
                }

                someActivityResumed |= child.resumeTopActivityUncheckedLocked(prev, options,
                        deferPause);
                // Doing so in order to prevent IndexOOB since hierarchy might changes while
                // resuming activities, for example dismissing split-screen while starting
                // non-resizeable activity.
                if (idx >= mChildren.size()) {
                    idx = mChildren.size() - 1;
                }
            }
        }

        // When resuming the top activity, it may be necessary to pause the top activity (for
        // example, returning to the lock screen. We suppress the normal pause logic in
        // {@link #resumeTopActivityUncheckedLocked}, since the top activity is resumed at the
        // end. We call the {@link ActivityTaskSupervisor#checkReadyForSleepLocked} again here
        // to ensure any necessary pause logic occurs. In the case where the Activity will be
        // shown regardless of the lock screen, the call to
        // {@link ActivityTaskSupervisor#checkReadyForSleepLocked} is skipped.
        final ActivityRecord next = topRunningActivity(true /* focusableOnly */);

        if (next == null || !next.canTurnScreenOn()) {
            checkReadyForSleep();
        }
    } finally {
        mInResumeTopActivity = false;
    }

    return someActivityResumed;
}

1.2 Task#resumeTopActivityInnerLocked

在Activity切换过程中会触发两次resumeTopActivityInnerLocked,第一次是在startActivity过程中,此时之前的Activity 仍未paused,因此prev不等于null,所以在判断isPausing时返回true,然后直接返回;

而第二次是在activityPaused触发的,此时之前的activity已经pause了,所以prev为null,会进入后续的prepareAppTransition流程

Task#resumeTopActivityInnerLocked

private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options,
        boolean deferPause) {
  .....
  
// We are starting up the next activity, so tell the window manager
// that the previous one will be hidden soon.  This way it can know
// to ignore it when computing the desired screen orientation.
boolean anim = true;
final DisplayContent dc = taskDisplayArea.mDisplayContent;
if (prev != null) {  //prev 为null
    if (prev.finishing) {

        if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
                "Prepare close transition: prev=" + prev);
        if (mTaskSupervisor.mNoAnimActivities.contains(prev)) {
            anim = false;
            dc.prepareAppTransition(TRANSIT_NONE);
        } else {
            dc.prepareAppTransition(TRANSIT_CLOSE);
        }
        prev.setVisibility(false);
    } else {
        if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
                "Prepare open transition: prev=" + prev);
        if (mTaskSupervisor.mNoAnimActivities.contains(next)) {
            anim = false;
            dc.prepareAppTransition(TRANSIT_NONE);
        } else {
            dc.prepareAppTransition(TRANSIT_OPEN,
                    next.mLaunchTaskBehind ? TRANSIT_FLAG_OPEN_BEHIND : 0);
        }
    }
} else {  //进入该分支
    if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare open transition: no previous");
    if (mTaskSupervisor.mNoAnimActivities.contains(next)) {
        anim = false;
        dc.prepareAppTransition(TRANSIT_NONE);
    } else {
        dc.prepareAppTransition(TRANSIT_OPEN);  //准备start过渡动画
    }
}

if (anim) {
    next.applyOptionsAnimation();
} else {
    next.abortAndClearOptionsAnimation();
}

}       

1.2.1 DisplayContent#prepareAppTransition、AppTransition#prepareAppTransition

void prepareAppTransition(@WindowManager.TransitionType int transit,
        @WindowManager.TransitionFlags int flags) {
    final boolean prepared = mAppTransition.prepareAppTransition(transit, flags);   //继续进入AppTransition的prepareAppTransition
    if (prepared && okToAnimate()) {
        mSkipAppTransitionAnimation = false;
    }
}


boolean prepareAppTransition(@TransitionType int transit, @TransitionFlags int flags) {
    if (mService.mAtmService.getTransitionController().getTransitionPlayer() != null) {
        return false;
    }
    mNextAppTransitionRequests.add(transit);
    mNextAppTransitionFlags |= flags;
    updateBooster();
    removeAppTransitionTimeoutCallbacks();
    mHandler.postDelayed(mHandleAppTransitionTimeoutRunnable,
            APP_TRANSITION_TIMEOUT_MS);
    return prepare();
}

prepareAppTransition方法中,S版本和R版本还是有一些不同的,R版本是在该方法内通过设置mNextAppTransition来指定下一次transition的类型,在S上是通过mNextAppTransitionRequests来保存下一次transit的类型,具体会在后面handleAppTransitionReady方法内通过getTransitCompatType方法来获取当前transition的类型</font>(见2.3.2)

appTransition的准备过程如下:

(Activity的创建会在create的时候会通过setContentView方法将当前view添加RootView上,而在addView方法内会去创建窗口并将当前rootView添加到该窗口上)

在新Activity resume过程中会去添加当前窗口(addView的时候实现),然后继续走measure、layout、draw的流程,在这一系列完成之后会调用wms.finishDrawingWindow,然后就开始调用WindowSurfacePlacer#requestTraversal方法了

2.AppTransition动画的触发过程

2.1 RootWindowContainer#performSurfacePlacementNoTrace

app的transition过程都会从RootWindowContainer#performSurfacePlacementNoTrace方法内开始调用

handleAppTransitionReady:160, AppTransitionController (com.android.server.wm)
checkAppTransitionReady:1044, RootWindowContainer (com.android.server.wm)
performSurfacePlacementNoTrace:879, RootWindowContainer (com.android.server.wm)
performSurfacePlacement:813, RootWindowContainer (com.android.server.wm)
performSurfacePlacementLoop:199, WindowSurfacePlacer (com.android.server.wm)
performSurfacePlacement:148, WindowSurfacePlacer (com.android.server.wm)
relayoutWindow:2675, WindowManagerService (com.android.server.wm)
relayout:241, Session (com.android.server.wm) //或者是activityPaused方法的触发
onTransact:747, IWindowSession$Stub (android.view)
onTransact:171, Session (com.android.server.wm)
execTransactInternal:1187, Binder (android.os)
execTransact:1146, Binder (android.os)

performSurfacePlacementNoTrace方法源头都是触发窗口重新绘制,然后再去设置activity或者窗口的transition过程(窗口动画的入口也是performSurfacePlacementNoTrace)

我们来看下该方法 RootWindowContainer#performSurfacePlacementNoTrace

void performSurfacePlacementNoTrace() {

    int i;

    if (mWmService.mFocusMayChange) {
        mWmService.mFocusMayChange = false;
        mWmService.updateFocusedWindowLocked(
                UPDATE_FOCUS_WILL_PLACE_SURFACES, false /*updateInputWindows*/);
    }

    // Initialize state of exiting tokens.
    final int numDisplays = mChildren.size();
    for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
        final DisplayContent displayContent = mChildren.get(displayNdx);
        displayContent.setExitingTokensHasVisible(false);
    }

    mHoldScreen = null;
    mScreenBrightnessOverride = PowerManager.BRIGHTNESS_INVALID_FLOAT;
    mUserActivityTimeout = -1;
    mObscureApplicationContentOnSecondaryDisplays = false;
    mSustainedPerformanceModeCurrent = false;
    mWmService.mTransactionSequence++;
   
    // TODO(multi-display): recents animation & wallpaper need support multi-display.
    final DisplayContent defaultDisplay = mWmService.getDefaultDisplayContentLocked();
    final WindowSurfacePlacer surfacePlacer = mWmService.mWindowPlacerLocked;

    if (SHOW_LIGHT_TRANSACTIONS) {
        Slog.i(TAG,
                ">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");
    }
    Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "applySurfaceChanges");
    mWmService.openSurfaceTransaction();
    try {
        applySurfaceChangesTransaction();  //更新surface变化
    } catch (RuntimeException e) {
        Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
    } finally {
        mWmService.closeSurfaceTransaction("performLayoutAndPlaceSurfaces");
        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        if (SHOW_LIGHT_TRANSACTIONS) {
            Slog.i(TAG,
                    "<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces");
        }
    }

    // Send any pending task-info changes that were queued-up during a layout deferment
    mWmService.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
    mWmService.mSyncEngine.onSurfacePlacement();
    mWmService.mAnimator.executeAfterPrepareSurfacesRunnables();
    
    
    checkAppTransitionReady(surfacePlacer);   //开始transition动画的设置

2.2 RootWindowContainer#checkAppTransitionReady

private void checkAppTransitionReady(WindowSurfacePlacer surfacePlacer) {
    // Trace all displays app transition by Z-order for pending layout change.
    for (int i = mChildren.size() - 1; i >= 0; --i) {
        final DisplayContent curDisplay = mChildren.get(i);

        //check当前display的apptransition是否是准备好的状态(dc会通过setReady方法设置该状态)
        if (curDisplay.mAppTransition.isReady()) {
            // handleAppTransitionReady may modify curDisplay.pendingLayoutChanges.
            //处理app transition
            curDisplay.mAppTransitionController.handleAppTransitionReady();
            if (DEBUG_LAYOUT_REPEATS) {
                surfacePlacer.debugLayoutRepeats("after handleAppTransitionReady",
                        curDisplay.pendingLayoutChanges);
            }
        }

2.3 ApptransitionController#handleAppTransitionReady

这里是对transition动画的一些初始化工作。

void handleAppTransitionReady() {
    mTempTransitionReasons.clear();
    //本次transition过程是否已准备好 过程见2.3.1
    if (!transitionGoodToGo(mDisplayContent.mOpeningApps, mTempTransitionReasons)
            || !transitionGoodToGo(mDisplayContent.mChangingContainers,
                    mTempTransitionReasons)) {
        return;  //未准备好 返回
    }
    Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "AppTransitionReady");

    ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "**** GOOD TO GO");
    //获取dc之前准备好的transition
    final AppTransition appTransition = mDisplayContent.mAppTransition;

    mDisplayContent.mNoAnimationNotifyOnTransitionFinished.clear();

    appTransition.removeAppTransitionTimeoutCallbacks();

    mDisplayContent.mWallpaperMayChange = false;

    int appCount = mDisplayContent.mOpeningApps.size();

    for (int i = 0; i < appCount; ++i) {
        // 这里先直译备注下:具体还不太了解 后续再跟下这块逻辑
        // 在进入动画之前清除 mAnimatingExit这个flag
        // 这个flag会在窗口被移除或者relayout变为不可见是被设置为true
        // 这个flag同样会影响窗口的可见性 
        // 我们需要在maybeUpdateTransitToWallpaper方法前清楚这个flag,因为transition的选择取决于wallpaper target的可见性
        mDisplayContent.mOpeningApps.valueAtUnchecked(i).clearAnimatingFlags();
    }
    appCount = mDisplayContent.mChangingContainers.size();
    for (int i = 0; i < appCount; ++i) {
        // Clearing for same reason as above.
        final ActivityRecord activity = getAppFromContainer(
                mDisplayContent.mChangingContainers.valueAtUnchecked(i));
        if (activity != null) {
            activity.clearAnimatingFlags();
        }
    }

    // Adjust wallpaper before we pull the lower/upper target, since pending changes
    // (like the clearAnimatingFlags() above) might affect wallpaper target result.
    // Or, the opening app window should be a wallpaper target.
    mWallpaperControllerLocked.adjustWallpaperWindowsForAppTransitionIfNeeded(
            mDisplayContent.mOpeningApps);
    //S版本重新定义了transition的类型 这里需要获取下兼容后的type 详细见2.3.2
    final @TransitionOldType int transit = getTransitCompatType(
            mDisplayContent.mAppTransition,
            mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
            mWallpaperControllerLocked.getWallpaperTarget(), getOldWallpaper(),
            mDisplayContent.mSkipAppTransitionAnimation);
    mDisplayContent.mSkipAppTransitionAnimation = false;

    //当我们打开一个具有动画的activity时 这里的transit就是 TRANSIT_OLD_ACTIVITY_OPEN
    ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
            "handleAppTransitionReady: displayId=%d appTransition={%s}"
            + " openingApps=[%s] closingApps=[%s] transit=%s",
            mDisplayContent.mDisplayId,
            appTransition.toString(),
            mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
            AppTransition.appTransitionOldToString(transit));

    // Find the layout params of the top-most application window in the tokens, which is
    // what will control the animation theme. If all closing windows are obscured, then there is
    // no need to do an animation. This is the case, for example, when this transition is being
    // done behind a dream window.
    final ArraySet<Integer> activityTypes = collectActivityTypes(mDisplayContent.mOpeningApps,
            mDisplayContent.mClosingApps, mDisplayContent.mChangingContainers);
    final ActivityRecord animLpActivity = findAnimLayoutParamsToken(transit, activityTypes);
    //当前要打开的app
    final ActivityRecord topOpeningApp =
            getTopApp(mDisplayContent.mOpeningApps, false /* ignoreHidden */);
    //当前要close的app
    final ActivityRecord topClosingApp =
            getTopApp(mDisplayContent.mClosingApps, false /* ignoreHidden */);
    final ActivityRecord topChangingApp =
            getTopApp(mDisplayContent.mChangingContainers, false /* ignoreHidden */);
     //根据该Activity 窗口的attrs获取动画参数
    final WindowManager.LayoutParams animLp = getAnimLp(animLpActivity);
    //如果存在RemoteAnimationAdapter(App端可能会定义) 那么覆盖这个transition
    overrideWithRemoteAnimationIfSet(animLpActivity, transit, activityTypes);

    final boolean voiceInteraction = containsVoiceInteraction(mDisplayContent.mOpeningApps)
            || containsVoiceInteraction(mDisplayContent.mOpeningApps);

    final int layoutRedo;
    //defer start动画
    mService.mSurfaceAnimationRunner.deferStartingAnimations();
    try {
        //创建启动动画 见2.4
        applyAnimations(mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, transit,
                animLp, voiceInteraction);
        handleClosingApps();
        handleOpeningApps();
        handleChangingApps(transit);
        appTransition.setLastAppTransition(transit, topOpeningApp,
                topClosingApp, topChangingApp);

        final int flags = appTransition.getTransitFlags();
        layoutRedo = appTransition.goodToGo(transit, topOpeningApp);
        handleNonAppWindowsInTransition(transit, flags);
        appTransition.postAnimationCallback();
        appTransition.clear();
    } finally {
    //这里继续开始start动画
        mService.mSurfaceAnimationRunner.continueStartingAnimations();
    }

    //回调通知TaskSnapshotController对close的app进行snapshot截屏
    mService.mTaskSnapshotController.onTransitionStarting(mDisplayContent);
       
     //一些清理工作
    mDisplayContent.mOpeningApps.clear();
    mDisplayContent.mClosingApps.clear();
    mDisplayContent.mChangingContainers.clear();
    mDisplayContent.mUnknownAppVisibilityController.clear();

    // This has changed the visibility of windows, so perform
    // a new layout to get them all up-to-date.
    mDisplayContent.setLayoutNeeded();
    
    //transition执行完之后 需要重新计算当前的ime ttarget
    mDisplayContent.computeImeTarget(true /* updateImeTarget */);

    mService.mAtmService.mTaskSupervisor.getActivityMetricsLogger().notifyTransitionStarting(
            mTempTransitionReasons);

    Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
    mDisplayContent.pendingLayoutChanges |=
            layoutRedo | FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_CONFIG;
}

2.3.1 ApptransitionController#transitionGoodToGo

private boolean transitionGoodToGo(ArraySet<? extends WindowContainer> apps,
        ArrayMap<WindowContainer, Integer> outReasons) {
    ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
            "Checking %d opening apps (frozen=%b timeout=%b)...", apps.size(),
            mService.mDisplayFrozen, mDisplayContent.mAppTransition.isTimeout());

    final ScreenRotationAnimation screenRotationAnimation = mService.mRoot.getDisplayContent(
            Display.DEFAULT_DISPLAY).getRotationAnimation();
    //如果动画没有设置暂停
    if (!mDisplayContent.mAppTransition.isTimeout()) {
        //一种特殊情况:如果当前正在做屏幕旋转动画 同时当前确实有待转屏的变化
        //当前返回false ,defer 本次transition
        if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()
                && mDisplayContent.getDisplayRotation().needsUpdate()) {
            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
                    "Delaying app transition for screen rotation animation to finish");
            return false;
        }
        for (int i = 0; i < apps.size(); i++) {
            WindowContainer wc = apps.valueAt(i);
            final ActivityRecord activity = getAppFromContainer(wc);
            if (activity == null) {
                continue;
            }
            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
                    "Check opening app=%s: allDrawn=%b startingDisplayed=%b "
                            + "startingMoved=%b isRelaunching()=%b startingWindow=%s",
                    activity, activity.allDrawn, activity.startingDisplayed,
                    activity.startingMoved, activity.isRelaunching(),
                    activity.mStartingWindow);


            final boolean allDrawn = activity.allDrawn && !activity.isRelaunching();
            if (!allDrawn && !activity.startingDisplayed && !activity.startingMoved) {
                return false;
            }
            if (allDrawn) {
                outReasons.put(activity, APP_TRANSITION_WINDOWS_DRAWN);
            } else {
                outReasons.put(activity,
                        activity.mStartingData instanceof SplashScreenStartingData
                                ? APP_TRANSITION_SPLASH_SCREEN
                                : APP_TRANSITION_SNAPSHOT);
            }
        }
        //其他一些原因 有兴趣的可以继续跟下 :)
        // We also need to wait for the specs to be fetched, if needed.
        if (mDisplayContent.mAppTransition.isFetchingAppTransitionsSpecs()) {
            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "isFetchingAppTransitionSpecs=true");
            return false;
        }

        if (!mDisplayContent.mUnknownAppVisibilityController.allResolved()) {
            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "unknownApps is not empty: %s",
                        mDisplayContent.mUnknownAppVisibilityController.getDebugMessage());
            return false;
        }

        // If the wallpaper is visible, we need to check it's ready too.
        boolean wallpaperReady = !mWallpaperControllerLocked.isWallpaperVisible() ||
                mWallpaperControllerLocked.wallpaperTransitionReady();
        if (wallpaperReady) {
            return true;
        }
        return false;
    }
    return true;
}

2.3.2 ApptransitionController#getTransitCompatType

S上重构了Transition的相关逻辑,但是S上还是不完全的,因为他仍然要通过getTransitCompatType将新的transtionType转换为之前的TransitionOldType,再根据TransitionOldType来确定当前的transition类别,应该在T版本会有完全重构的逻辑了。

新旧type对应关系如下:

之前的TRANSIT_ACTIVITY_OPEN 就变成了 TRANSIT_OLD_ACTIVITY_OPEN

static @TransitionOldType int getTransitCompatType(AppTransition appTransition,
        ArraySet<ActivityRecord> openingApps, ArraySet<ActivityRecord> closingApps,
        @Nullable WindowState wallpaperTarget, @Nullable WindowState oldWallpaper,
        boolean skipAppTransitionAnimation) {

//appTransition的type是根据之前1.2.1在prepareAppTransition方法设置的
//mNextAppTransitionRequests来确定当前类别,这个列表存储了已请求的appTransition
    
    // Determine if closing and opening app token sets are wallpaper targets, in which case
    // special animations are needed.
    //确定当前发生动画的是否是wallpaper target,在这种情况下需要特殊的动画
    final boolean openingAppHasWallpaper = canBeWallpaperTarget(openingApps)
            && wallpaperTarget != null;
    final boolean closingAppHasWallpaper = canBeWallpaperTarget(closingApps)
            && wallpaperTarget != null;

    
    //如果当前transition中有锁屏动画的 那么直接返回对应的动画
    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;
    }

    // dc内是否设置了 skipAppTransitionAnimation(app可能会请求跳过transition动画)
    if (skipAppTransitionAnimation) {
        return WindowManager.TRANSIT_OLD_UNSET;
    }
    final @TransitionFlags int flags = appTransition.getTransitFlags();
    final @TransitionType int firstTransit = appTransition.getFirstAppTransition();

    //处理特殊transition
    if (appTransition.containsTransitRequest(TRANSIT_CHANGE)) {
        return TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE;
    }
    if ((flags & TRANSIT_FLAG_APP_CRASHED) != 0) {
        return TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE;
    }
    if (firstTransit == TRANSIT_NONE) {
        return TRANSIT_OLD_NONE;
    }

    //实际上对一个位于已存在activities顶部的半透明activity,我们会选择使用不同的动画
    //因为没有task/activity动画能够很好处理这种半透明app
    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;
        }
    }

    //获取即将 要打开的app
    final ActivityRecord topOpeningApp = getTopApp(openingApps,
            false /* ignoreHidden */);
            //即将要关闭的app
    final ActivityRecord topClosingApp = getTopApp(closingApps,
            true /* ignoreHidden */);

    //如果是wallpaper target 返回wallpaper相关动画 下面也是处理wallpaperTarget相关场景
    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;
    }

    //处理普通task/Activity场景 根据task/Activity 以及open/close选择对应的动画
    final ArraySet<WindowContainer> openingWcs = getAnimationTargets(
            openingApps, closingApps, true /* visible */);
    final ArraySet<WindowContainer> closingWcs = getAnimationTargets(
            openingApps, closingApps, false /* visible */);
    final boolean isActivityOpening = !openingWcs.isEmpty()
            && openingWcs.valueAt(0).asActivityRecord() != null;
    final boolean isActivityClosing = !closingWcs.isEmpty()
            && closingWcs.valueAt(0).asActivityRecord() != null;
    final boolean isTaskOpening = !openingWcs.isEmpty() && !isActivityOpening;
    final boolean isTaskClosing = !closingWcs.isEmpty() && !isActivityClosing;

    //task进入前台
    if (appTransition.containsTransitRequest(TRANSIT_TO_FRONT) && isTaskOpening) {
        return TRANSIT_OLD_TASK_TO_FRONT;
    }
    //task进入后台
    if (appTransition.containsTransitRequest(TRANSIT_TO_BACK) && isTaskClosing) {
        return TRANSIT_OLD_TASK_TO_BACK;
    }
    if (appTransition.containsTransitRequest(TRANSIT_OPEN)) {
        if (isTaskOpening) {
            return (appTransition.getTransitFlags() & TRANSIT_FLAG_OPEN_BEHIND) != 0    
                    ? TRANSIT_OLD_TASK_OPEN_BEHIND : TRANSIT_OLD_TASK_OPEN;
                    //打开task动画
        }
        if (isActivityOpening) {
           //打开activity动画
            return TRANSIT_OLD_ACTIVITY_OPEN;
        }
    }
    if (appTransition.containsTransitRequest(TRANSIT_CLOSE)) {
        if (isTaskClosing) {
        //关闭task动画
            return TRANSIT_OLD_TASK_CLOSE;
        }
        if (isActivityClosing) {
            for (int i = closingApps.size() - 1; i >= 0; i--) {
                if (closingApps.valueAt(i).visibleIgnoringKeyguard) {
                //关闭activity动画
                    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;
}

2.4 ApptransitionController#applyAnimations

private void applyAnimations(ArraySet<ActivityRecord> openingApps,
        ArraySet<ActivityRecord> closingApps, @TransitionOldType int transit,
        LayoutParams animLp, boolean voiceInteraction) {
    if (transit == WindowManager.TRANSIT_OLD_UNSET
            || (openingApps.isEmpty() && closingApps.isEmpty())) {
        return;
    }
    
    final ArraySet<WindowContainer> openingWcs = getAnimationTargets(
            openingApps, closingApps, true /* visible */);
    final ArraySet<WindowContainer> closingWcs = getAnimationTargets(
            openingApps, closingApps, false /* visible */);
    //对对应的窗口容器应用对应的transition动画  见2.5
    applyAnimations(openingWcs, openingApps, transit, true /* visible */, animLp,
            voiceInteraction);
    applyAnimations(closingWcs, closingApps, transit, false /* visible */, animLp,
            voiceInteraction);

    for (int i = 0; i < openingApps.size(); ++i) {
        openingApps.valueAtUnchecked(i).mOverrideTaskTransition = false;
    }
    for (int i = 0; i < closingApps.size(); ++i) {
        closingApps.valueAtUnchecked(i).mOverrideTaskTransition = false;
    }

    final AccessibilityController accessibilityController =
            mDisplayContent.mWmService.mAccessibilityController;
    if (accessibilityController != null) {
        accessibilityController.onAppWindowTransition(mDisplayContent.getDisplayId(), transit);
    }
}

2.5 ApptransitionController#applyAnimations

/**
 * Apply animation to the set of window containers.
 *
 * @param wcs The list of {@link WindowContainer}s to which an app transition animation applies.
 * @param apps The list of {@link ActivityRecord}s being transitioning.
 * @param transit The current transition type.
 * @param visible {@code true} if the apps becomes visible, {@code false} if the apps becomes
 *                invisible.
 * @param animLp Layout parameters in which an app transition animation runs.
 * @param voiceInteraction {@code true} if one of the apps in this transition belongs to a voice
 *                         interaction session driving task.
 */
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是ActivityRecord 最终会调用其父类WindowContainer的applyAnimation
        wc.applyAnimation(animLp, transit, visible, voiceInteraction, transitioningDescendants);
    }
}

2.6 WindowContainer#applyAnimation、applyAnimationUnchecked

boolean applyAnimation(WindowManager.LayoutParams lp, @TransitionOldType int transit,
        boolean enter, boolean isVoiceInteraction,
        @Nullable ArrayList<WindowContainer> sources) {
    if (mWmService.mDisableTransitionAnimation) {
        ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
                "applyAnimation: transition animation is disabled or skipped. "
                        + "container=%s", this);
        cancelAnimation();
        return false;
    }
    //只有当屏幕没有被冻结的时候才能做动画 否则会产生奇怪的现象
    try {
        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "WC#applyAnimation");
        if (okToAnimate()) {
            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
                    "applyAnimation: transit=%s, enter=%b, wc=%s",
                    AppTransition.appTransitionOldToString(transit), enter, this);
            //继续调用
            applyAnimationUnchecked(lp, enter, transit, isVoiceInteraction, sources);
        } else {
            cancelAnimation();
        }
    } finally {
        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
    }

    return isAnimating();
}

WindowContainer#applyAnimationUnchecked

protected void applyAnimationUnchecked(WindowManager.LayoutParams lp, boolean enter,
        @TransitionOldType int transit, boolean isVoiceInteraction,
        @Nullable ArrayList<WindowContainer> sources) {
    final Task task = asTask();  //如果即将打开的容器是activity 那么这里就为null
    //task不为null 且是close当前task 同时该task不是home以及最近任务task
    //那么会根据ime相关属性 显示输入法的screenShot (S新增特性,优化输入法transition的体验)
    if (task != null && !enter && !task.isHomeOrRecentsRootTask()) {
        final InsetsControlTarget imeTarget = mDisplayContent.getImeTarget(IME_TARGET_LAYERING);
        final boolean isImeLayeringTarget = imeTarget != null && imeTarget.getWindow() != null
                && imeTarget.getWindow().getTask() == task;
        //当前是在closetask同时当前imetarget不为null
        if (isImeLayeringTarget && AppTransition.isTaskCloseTransitOld(transit)) {
            mDisplayContent.showImeScreenshot();
        }
    }
    final Pair<AnimationAdapter, AnimationAdapter> adapters = getAnimationAdapter(lp,
            transit, enter, isVoiceInteraction);
    AnimationAdapter adapter = adapters.first;
    AnimationAdapter thumbnailAdapter = adapters.second;
    if (adapter != null) {
        if (sources != null) {
            mSurfaceAnimationSources.addAll(sources);
        }
        //执行动画  见2.7
        startAnimation(getPendingTransaction(), adapter, !isVisible(),
                ANIMATION_TYPE_APP_TRANSITION);
        if (adapter.getShowWallpaper()) {
            getDisplayContent().pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
        }
        if (thumbnailAdapter != null) {
            mSurfaceFreezer.mSnapshot.startAnimation(getPendingTransaction(),
                    thumbnailAdapter, ANIMATION_TYPE_APP_TRANSITION, (type, anim) -> { });
        }
    }
}

2.6.1 WindowContainer#getAnimationAdapter

窗口动画的显示过程中同样会加载到这里,根据窗口的layoutParams加载动画

Pair<AnimationAdapter, AnimationAdapter> getAnimationAdapter(WindowManager.LayoutParams lp,
        @TransitionOldType int transit, boolean enter, boolean isVoiceInteraction) {
    final Pair<AnimationAdapter, AnimationAdapter> resultAdapters;
    final int appRootTaskClipMode = getDisplayContent().mAppTransition.getAppRootTaskClipMode();

    // Separate position and size for use in animators.
    final Rect screenBounds = getAnimationBounds(appRootTaskClipMode);
    mTmpRect.set(screenBounds);
    getAnimationPosition(mTmpPoint);
    mTmpRect.offsetTo(0, 0);
 
    // 如果当前存在RemoteAnimationAdapter 这里controller就不为null
    final RemoteAnimationController controller =
            getDisplayContent().mAppTransition.getRemoteAnimationController();
    //判断apptransition是否发生变化
    final boolean isChanging = AppTransition.isChangeTransitOld(transit) && enter
            && isChangingAppTransition();

    //RemoteAnimation情况
    if (controller != null && !mSurfaceAnimator.isAnimationStartDelayed()) {
        final Rect localBounds = new Rect(mTmpRect);
        localBounds.offsetTo(mTmpPoint.x, mTmpPoint.y);
        final RemoteAnimationController.RemoteAnimationRecord adapters =
                controller.createRemoteAnimationRecord(this, mTmpPoint, localBounds,
                        screenBounds, (isChanging ? mSurfaceFreezer.mFreezeBounds : null));
        resultAdapters = new Pair<>(adapters.mAdapter, adapters.mThumbnailAdapter);
        //apptransition发生变化情况
    } else if (isChanging) {
        final float durationScale = mWmService.getTransitionAnimationScaleLocked();
        final DisplayInfo displayInfo = getDisplayContent().getDisplayInfo();
        mTmpRect.offsetTo(mTmpPoint.x, mTmpPoint.y);

        final AnimationAdapter adapter = new LocalAnimationAdapter(
                new WindowChangeAnimationSpec(mSurfaceFreezer.mFreezeBounds, mTmpRect,
                        displayInfo, durationScale, true /* isAppAnimation */,
                        false /* isThumbnail */),
                getSurfaceAnimationRunner());

        final AnimationAdapter thumbnailAdapter = mSurfaceFreezer.mSnapshot != null
                ? new LocalAnimationAdapter(new WindowChangeAnimationSpec(
                mSurfaceFreezer.mFreezeBounds, mTmpRect, displayInfo, durationScale,
                true /* isAppAnimation */, true /* isThumbnail */), getSurfaceAnimationRunner())
                : null;
        resultAdapters = new Pair<>(adapter, thumbnailAdapter);
        mTransit = transit;
        mTransitFlags = getDisplayContent().mAppTransition.getTransitFlags();
    } else {
    //普通transition进入这里
        mNeedsAnimationBoundsLayer = (appRootTaskClipMode == ROOT_TASK_CLIP_AFTER_ANIM);
        //根据窗口的layoutParams加载出动画 
        final Animation a = loadAnimation(lp, transit, enter, isVoiceInteraction);

        if (a != null) {
          
            float windowCornerRadius = !inMultiWindowMode()
                    ? getDisplayContent().getWindowCornerRadius()
                    : 0;

            //将动画的相关信息封装到WindowAnimationSpec类内
            WindowAnimationSpec spec = new WindowAnimationSpec(
                    a, mTmpPoint, mTmpRect,
                    getDisplayContent().mAppTransition.canSkipFirstFrame(),
                    appRootTaskClipMode,
                    true /* isAppAnimation */,
                    windowCornerRadius);

            //创建AnimationAdapter 后续会调用其startAniamtion方法
            //用来执行显示动画、回调动画取消等操作
            AnimationAdapter adapter = new LocalAnimationAdapter(spec,
                    getSurfaceAnimationRunner());

            spec.mShouldActivityTransitionRoundCorner =
                    getDisplayContent().mAppTransition.
                            shouldActivityTransitionRoundCorner();

            if(this.asActivityRecord() != null) {
                this.asActivityRecord().mWindowAnimationSpec = spec;
            }

            resultAdapters = new Pair<>(adapter, null);
            mNeedsZBoost = a.getZAdjustment() == Animation.ZORDER_TOP
                    || AppTransition.isClosingTransitOld(transit);
            mTransit = transit;
            mTransitFlags = getDisplayContent().mAppTransition.getTransitFlags();
        } else {
            resultAdapters = new Pair<>(null, null);
        }
    }
    return resultAdapters;  //返回adapter
}

2.7 WindowContainer#startAnimation、SurfaceAnimator#startAnimation

void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
        @AnimationType int type,
        @Nullable OnAnimationFinishedCallback animationFinishedCallback) {
    if (DEBUG_ANIM) {
        Slog.v(TAG, "Starting animation on " + this + ": type=" + type + ", anim=" + anim);
    }

    // TODO: This should use isVisible() but because isVisible has a really weird meaning at
    // the moment this doesn't work for all animatable window containers.
    mSurfaceAnimator.startAnimation(t, anim, hidden, type, animationFinishedCallback,
            mSurfaceFreezer);
}


void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
        @AnimationType int type,
        @Nullable OnAnimationFinishedCallback animationFinishedCallback,
        @Nullable SurfaceFreezer freezer) {
    cancelAnimation(t, true /* restarting */, true /* forwardCancel */);
    mAnimation = anim;
    mAnimationType = type;
    mAnimationFinishedCallback = animationFinishedCallback;
    final SurfaceControl surface = mAnimatable.getSurfaceControl();
    if (surface == null) {
        Slog.w(TAG, "Unable to start animation, surface is null or no children.");
        cancelAnimation();
        return;
    }
    mLeash = freezer != null ? freezer.takeLeashForAnimation() : null;
    if (mLeash == null) {
    //创建leash
        mLeash = createAnimationLeash(mAnimatable, surface, t, type,
                mAnimatable.getSurfaceWidth(), mAnimatable.getSurfaceHeight(), 0 /* x */,
                0 /* y */, hidden, mService.mTransactionFactory);
        mAnimatable.onAnimationLeashCreated(t, mLeash);
    }
    mAnimatable.onLeashAnimationStarting(t, mLeash);
    if (mAnimationStartDelayed) {
        if (DEBUG_ANIM) Slog.i(TAG, "Animation start delayed");
        return;
    }
    //调用LocalAnimationAdaper的startAnimation(如果不存在RemoteAnimationAdapter)
    mAnimation.startAnimation(mLeash, t, type, mInnerAnimationFinishedCallback);
}

该方法内会根据当前动画创建leash(译为:绳子,也就是捆绑了一组surface),最后执行LocalAnimationAdaper的startAnimation方法(假如app没有指定RemoteAnimationAdapter,例如桌面会设置)

2.8 LocalAnimationAdaper#startAnimation

public void startAnimation(SurfaceControl animationLeash, Transaction t,
        @AnimationType int type, OnAnimationFinishedCallback finishCallback) {
    mAnimator.startAnimation(mSpec, animationLeash, t,
            () -> finishCallback.onAnimationFinished(type, this));
}

这里的mAnimator是SurfaceAnimationRunner类,继续看下SurfaceAnimationRunner#startAnimation方法

2.9 SurfaceAnimationRunner#startAnimation

void startAnimation(AnimationSpec a, SurfaceControl animationLeash, Transaction t,
        Runnable finishCallback) {
    synchronized (mLock) {
        final RunningAnimation runningAnim = new RunningAnimation(a, animationLeash,
                finishCallback);
        mPendingAnimations.put(animationLeash, runningAnim);
        //该值是在2.3 applyAnimation方法前通过deferStartingAnimations设置的
        if (!mAnimationStartDeferred) {
            mChoreographer.postFrameCallback(this::startAnimations);
        }

        //对一些动画立即进行初始变换
        applyTransformation(runningAnim, t, 0 /* currentPlayTime */);
    }
}

首先这里根据描述动画的AnimationSpec类、leash、动画的callback构造了一个RunningAnimation

然后将这个animation以及leash添加到待显示的动画列表mPendingAnimations内,然后该动画会在下一帧显示前通过回调被启动。

接下来就是判断mAnimationStartDeferred值,该值是在2.3的handleAppTransitionReady方法内设置的,他在applyAnimation方法前调用了deferStartingAnimations方法(设为true),然后在执行完applyAnimations方法后在finally块内调用了continueStartingAnimations(设为false)。

这里在apply动画之前进行defer操作是为了统一当doframe回调的时候才去执行动画。

那么Choreographer内的开启动画的callback是在哪里设置进去的呢?

其实还是在上述continueStartingAnimations方法内进行调用的,可以看到当动画添加到mPendingAnimations之后,在该方法内会将SufaceAnimationRunner的startAnimations方法作为callback添加到演舞者Choreographer内。

void continueStartingAnimations() {
    synchronized (mLock) {
        mAnimationStartDeferred = false;  
        if (!mPendingAnimations.isEmpty()) {
            mChoreographer.postFrameCallback(this::startAnimations);
        }
    }
}

到这里的堆栈调用情况如下:

startAnimation:145, SurfaceAnimationRunner (com.android.server.wm)
startAnimation:55, LocalAnimationAdapter (com.android.server.wm)
startAnimation:161, SurfaceAnimator (com.android.server.wm)
startAnimation:2565, WindowContainer (com.android.server.wm)
startAnimation:2571, WindowContainer (com.android.server.wm)
applyAnimationUnchecked:2830, WindowContainer (com.android.server.wm)
applyAnimation:2669, WindowContainer (com.android.server.wm)
applyAnimation:5230, ActivityRecord (com.android.server.wm)
applyAnimations:598, AppTransitionController (com.android.server.wm)
applyAnimations:757, AppTransitionController (com.android.server.wm)
handleAppTransitionReady:233, AppTransitionController (com.android.server.wm)
checkAppTransitionReady:1044, RootWindowContainer (com.android.server.wm)
performSurfacePlacementNoTrace:879, RootWindowContainer (com.android.server.wm)
performSurfacePlacement:813, 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)
run:79, WindowSurfacePlacer$Traverser (com.android.server.wm)
handleCallback:938, Handler (android.os)
dispatchMessage:99, Handler (android.os)
loopOnce:210, Looper (android.os)
loop:299, Looper (android.os)
run:67, HandlerThread (android.os)
run:46, ServiceThread (com.android.server)

2.10 SurfaceAnimationRunner#startAnimations

当新的一帧正在被渲染的时候会回调到Choreographer的doCallback方法,最终会回调到之前SurfaceAnimationRunner添加到Choreographer的startAniamtions方法的回调,具体堆栈如下:

startPendingAnimationsLocked:191, SurfaceAnimationRunner (com.android.server.wm)
startAnimations:265, SurfaceAnimationRunner (com.android.server.wm)
$r8$lambda$u1Jh9N5fY2HKNOPRKT57txOp8-s:-1, SurfaceAnimationRunner (com.android.server.wm)
doFrame:-1, SurfaceAnimationRunner$$ExternalSyntheticLambda1 (com.android.server.wm)
run:1127, Choreographer$CallbackRecord (android.view)
doCallbacks:918, Choreographer (android.view)
doFrame:828, Choreographer (android.view)
run:1114, Choreographer$FrameDisplayEventReceiver (android.view)
handleCallback:938, Handler (android.os)
dispatchMessage:99, Handler (android.os)
loopOnce:210, Looper (android.os)
loop:299, Looper (android.os)
run:67, HandlerThread (android.os)
run:46, ServiceThread (com.android.server)

我们来看下SurfaceAnimationRunner#startAnimations、startPendingAnimationsLocked方法

private void startAnimations(long frameTimeNanos) {
    synchronized (mLock) {
        startPendingAnimationsLocked();
    }
    mPowerManagerInternal.setPowerBoost(Boost.INTERACTION, 0);
}


private void startPendingAnimationsLocked() {
    for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
    //从mPendingAnimations取出待执行的动画
        startAnimationLocked(mPendingAnimations.valueAt(i));
    }
    mPendingAnimations.clear();
}

2.11 SurfaceAnimationRunner#startAnimationLocked

这里就是最终动画执行的地方了

private void startAnimationLocked(RunningAnimation a) {
    //通过AnimatorFactory构建一个动画驱动器
    final ValueAnimator anim = mAnimatorFactory.makeAnimator();

    // Animation length is already expected to be scaled.
    anim.overrideDurationScale(1.0f);
    anim.setDuration(a.mAnimSpec.getDuration());
    //设置updateListener来处理每一帧动画
    anim.addUpdateListener(animation -> {
        synchronized (mCancelLock) {
            if (!a.mCancelled) {
                final long duration = anim.getDuration();
                long currentPlayTime = anim.getCurrentPlayTime();
                if (currentPlayTime > duration) {
                    currentPlayTime = duration;
                }
                applyTransformation(a, mFrameTransaction, currentPlayTime);
            }
        }

        // Transaction will be applied in the commit phase.
        scheduleApplyTransaction();
    });

    //设置动画开始、结束的监听器
    anim.addListener(new AnimatorListenerAdapter() {
        @Override
        public void onAnimationStart(Animator animation) {
            synchronized (mCancelLock) {
                if (!a.mCancelled) {
                    // TODO: change this back to use show instead of alpha when b/138459974 is
                    // fixed.
                    mFrameTransaction.setAlpha(a.mLeash, 1);
                }
            }
        }

        @Override
        public void onAnimationEnd(Animator animation) {
            synchronized (mLock) {
                mRunningAnimations.remove(a.mLeash);
                synchronized (mCancelLock) {
                    if (!a.mCancelled) {

                        // Post on other thread that we can push final state without jank.
                        mAnimationThreadHandler.post(a.mFinishCallback);
                    }
                }
            }
        }
    });
    a.mAnim = anim;
    //添加该ValueAnimator到mRunningAnimations内
    mRunningAnimations.put(a.mLeash, a);
    //开启动画
    anim.start();
    if (a.mAnimSpec.canSkipFirstFrame()) {
        // If we can skip the first frame, we start one frame later.
        anim.setCurrentPlayTime(mChoreographer.getFrameIntervalNanos() / NANOS_PER_MS);
    }

    
    //手动控制动画框架 立即开始应用动画,否则动画开始时间就是下一帧渲染的时间(就会有延迟的问题)
    anim.doAnimationFrame(mChoreographer.getFrameTime());
}

AppTransition动画的触发时序图如下:

总结

Activity动画过程总结就到这了,本文针对对transition动画流程(准备阶段、触发过程)进行了整理总结,对于一些细节性的可能还不太够,后期会继续整理总结窗口动画等相关流程以及Choreographer、绘制这些原理性的知识。

如有错误,欢迎指正!! :)