Android 過渡動畫啟動過程總結 -- 基於S版本

語言: CN / TW / HK

theme: juejin

過渡動畫總結

本文主要是基於android S版本來整理下過渡動畫的初始化過程以及啟動過程,過渡動畫是指在Activity切換過程中或者是從桌面打開app過程中出現的切換動畫。
首先,看下目前android存在的幾種動畫,這裏直接參考了源遠大佬的圖

|目標WindowContainer | 名稱 | 示例 | | :----:| :----: | :----: | | WindowState | 窗口動畫 | Toast彈出動畫、dialog彈出動畫 | | AppWindowToken | 過渡動畫 | Activity切換動畫、app啟動動畫 | | Task | Task動畫 | 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的類型`(見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 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 openingApps, ArraySet 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 openingApps, ArraySet 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 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 getAnimationAdapter(WindowManager.LayoutParams lp, @TransitionOldType int transit, boolean enter, boolean isVoiceInteraction) { final Pair 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、繪製這些原理性的知識。

如有錯誤,歡迎指正!! :)