Android11 WMS 之 AppTransition

目录

一.AppTransition过渡类型

二.AppTransition设置过渡类型调用栈信息

     * 新活动中的窗口正在同一任务中的现有窗口之上打开。    int TRANSIT_ACTIVITY_OPEN = 6;

     * 最顶层活动中的窗口正在关闭以显示同一任务中的前一个活动。    int TRANSIT_ACTIVITY_CLOSE = 7;

     * 新任务中的窗口正在另一个活动任务中的现有窗口之上打开。    int TRANSIT_TASK_OPEN = 8;

     * 最顶层活动中的一个窗口正在关闭,以显示不同任务中的前一个活动。    int TRANSIT_TASK_CLOSE = 9;

     * 现有任务中的窗口显示在另一个活动任务中现有任务的顶部。    int TRANSIT_TASK_TO_FRONT = 10;

     * 现有任务中的窗口被放置在所有其他任务下方。    int TRANSIT_TASK_TO_BACK = 11;

     * Keyguard 即将消失。    int TRANSIT_KEYGUARD_GOING_AWAY = 20;

三.AppTransition 执行前的调用栈信息

(1)非冷启动应用

(2)锁屏消失时

(3)最近任务显示已有堆栈的Actiivty

(4)冷启动应用

四.AppTransition的过渡动画的启动

(1)AppTransitionController.handleAppTransitionReady 准备过渡动画

(2)AppTransitionController.applyAnimations 设置过渡动画

(3)WindowContainer.applyAnimation 启动动画

(4)WindowContainer.getAnimationAdapter 获取远程/窗口/应用过渡动画

(5)AppTransition.loadAnimation 获取动画实例

五.总结


一.AppTransition过渡类型

    * 未设置过渡。
    int TRANSIT_UNSET = -1;

     * 没有过渡动画。
    int TRANSIT_NONE = 0;

     * 新活动中的窗口正在同一任务中的现有窗口之上打开。
    int TRANSIT_ACTIVITY_OPEN = 6;

     * 最顶层活动中的窗口正在关闭以显示同一任务中的前一个活动。
    int TRANSIT_ACTIVITY_CLOSE = 7;

     * 新任务中的窗口正在另一个活动任务中的现有窗口之上打开。
    int TRANSIT_TASK_OPEN = 8;

     * 最顶层活动中的一个窗口正在关闭,以显示不同任务中的前一个活动。
    int TRANSIT_TASK_CLOSE = 9;

     * 现有任务中的窗口显示在另一个活动任务中现有任务的顶部。
    int TRANSIT_TASK_TO_FRONT = 10;

     * 现有任务中的窗口被放置在所有其他任务下方。
    int TRANSIT_TASK_TO_BACK = 11;

     * 新活动中没有墙纸的窗口会在有墙纸的窗口之上打开,从而有效地关闭墙纸。
    int TRANSIT_WALLPAPER_CLOSE = 12;

     * 新活动中带有墙纸的窗口会在没有墙纸的窗口上打开,从而有效地打开墙纸。
    int TRANSIT_WALLPAPER_OPEN = 13;

     * 新活动中的一个窗口在现有活动的顶部打开,并且两者都在墙纸的顶部。
    int TRANSIT_WALLPAPER_INTRA_OPEN = 14;

     * 最顶部活动中的窗口正在关闭以显示之前的活动,并且两者都位于墙纸的顶部。
    int TRANSIT_WALLPAPER_INTRA_CLOSE = 15;

     * 新任务中的一个窗口在另一个活动的任务中的现有窗口后面打开。新窗口将短暂显示,然后消失。
    int TRANSIT_TASK_OPEN_BEHIND = 16;

     * 正在重新启动活动(例如,由于配置更改)。
    int TRANSIT_ACTIVITY_RELAUNCH = 18;

     * 正在对接最近的任务。
    int TRANSIT_DOCK_TASK_FROM_RECENTS = 19;

     * Keyguard 即将消失。
    int TRANSIT_KEYGUARD_GOING_AWAY = 20;

     * Keyguard 将消失,显示背后请求墙纸的活动。
    int TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER = 21;

     * Keyguard 被遮挡。
    int TRANSIT_KEYGUARD_OCCLUDE = 22;

     * Keyguard 未被遮挡。
    int TRANSIT_KEYGUARD_UNOCCLUDE = 23;

     * 正在打开一个半透明的活动。
    int TRANSIT_TRANSLUCENT_ACTIVITY_OPEN = 24;

     * 一个半透明的活动正在关闭。
    int TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE = 25;

     * 正在关闭崩溃的活动。
    int TRANSIT_CRASHING_ACTIVITY_CLOSE = 26;

     * 一项任务正在改变窗口模式
    int TRANSIT_TASK_CHANGE_WINDOWING_MODE = 27;

     * 由于第一个活动已启动或正在打开,因此正在显示只能包含一个任务的显示。
    int TRANSIT_SHOW_SINGLE_TASK_DISPLAY = 28; 

二.AppTransition设置过渡类型调用栈信息

     * 新活动中的窗口正在同一任务中的现有窗口之上打开。
    int TRANSIT_ACTIVITY_OPEN = 6;


    (1)锁屏消失出现Activity时
        com.android.server.wm.DisplayContent.prepareAppTransition
        com.android.server.wm.DisplayContent.prepareAppTransition
        com.android.server.wm.ActivityStack.resumeTopActivityInnerLocked
        com.android.server.wm.ActivityStack.resumeTopActivityUncheckedLocked
        com.android.server.wm.ActivityRecord.makeActiveIfNeeded
        com.android.server.wm.RootWindowContainer.resumeFocusedStacksTopActivities
        com.android.server.wm.RootWindowContainer.resumeFocusedStacksTopActivities
        com.android.server.wm.RootWindowContainer.applySleepTokens
        com.android.server.wm.ActivityTaskManagerService.updateSleepIfNeededLocked
        com.android.server.wm.RootWindowContainer.removeSleepToken
        com.android.server.wm.RootWindowContainer.access$200
        com.android.server.wm.RootWindowContainer$SleepTokenImpl.release
        com.android.server.wm.KeyguardController$KeyguardDisplayState.releaseSleepToken
        com.android.server.wm.KeyguardController.updateKeyguardSleepToken
        com.android.server.wm.KeyguardController.updateKeyguardSleepToken
        com.android.server.wm.KeyguardController.keyguardGoingAway
        com.android.server.wm.ActivityTaskManagerService.keyguardGoingAway
        android.app.IActivityTaskManager$Stub.onTransact
    (2)应用中进入新的Activity时
        com.android.server.wm.DisplayContent.prepareAppTransition
        com.android.server.wm.DisplayContent.prepareAppTransition
        com.android.server.wm.ActivityStack.startActivityLocked
        com.android.server.wm.ActivityStarter.startActivityInner
        com.android.server.wm.ActivityStarter.startActivityUnchecked
        com.android.server.wm.ActivityStarter.executeRequest
        com.android.server.wm.ActivityStarter.execute
        com.android.server.wm.ActivityTaskManagerService.startActivityAsUser
        com.android.server.wm.ActivityTaskManagerService.startActivityAsUser
        com.android.server.wm.ActivityTaskManagerService.startActivity
        android.app.IActivityTaskManager$Stub.onTransact
    (3)应用中新的Activity OnResume时
        com.android.server.wm.DisplayContent.prepareAppTransition
        com.android.server.wm.DisplayContent.prepareAppTransition
        com.android.server.wm.ActivityStack.resumeTopActivityInnerLocked
        com.android.server.wm.ActivityStack.resumeTopActivityUncheckedLocked
        com.android.server.wm.RootWindowContainer.resumeFocusedStacksTopActivities
        com.android.server.wm.ActivityStack.completePauseLocked
        com.android.server.wm.ActivityRecord.activityPaused
        com.android.server.wm.ActivityTaskManagerService.activityPaused
        android.app.IActivityTaskManager$Stub.onTransact
    (4)前台应用被杀死时,需要显示的Activity OnResume时
        com.android.server.wm.DisplayContent.prepareAppTransition
        com.android.server.wm.DisplayContent.prepareAppTransition
        com.android.server.wm.ActivityStack.resumeTopActivityInnerLocked
        com.android.server.wm.ActivityStack.resumeTopActivityUncheckedLocked
        com.android.server.wm.ActivityRecord.makeActiveIfNeeded
        com.android.server.wm.RootWindowContainer.resumeFocusedStacksTopActivities
        com.android.server.wm.RootWindowContainer.resumeFocusedStacksTopActivities
        com.android.server.wm.ActivityTaskManagerService$LocalService.handleAppDied
        com.android.server.am.ActivityManagerService.handleAppDiedLocked
        com.android.server.am.ActivityManagerService.appDiedLocked
        com.android.server.am.ActivityManagerService$AppDeathRecipient.binderDied

     * 最顶层活动中的窗口正在关闭以显示同一任务中的前一个活动。
    int TRANSIT_ACTIVITY_CLOSE = 7;


    (1)应用中按back键推出Activity时
        com.android.server.wm.DisplayContent.prepareAppTransition
        com.android.server.wm.DisplayContent.prepareAppTransition
        com.android.server.wm.ActivityRecord.finishIfPossible
        com.android.server.wm.ActivityTaskManagerService.finishActivity
        android.app.IActivityTaskManager$Stub.onTransact
    (2)应用中按back键需要显示的Activity OnResume时
        com.android.server.wm.DisplayContent.prepareAppTransition
        com.android.server.wm.DisplayContent.prepareAppTransition
        com.android.server.wm.ActivityStack.resumeTopActivityInnerLocked
        com.android.server.wm.ActivityStack.resumeTopActivityUncheckedLocked
        com.android.server.wm.RootWindowContainer.resumeFocusedStacksTopActivities
        com.android.server.wm.ActivityStack.completePauseLocked
        com.android.server.wm.ActivityRecord.activityPaused
        com.android.server.wm.ActivityTaskManagerService.activityPaused
        android.app.IActivityTaskManager$Stub.onTransact

     * 新任务中的窗口正在另一个活动任务中的现有窗口之上打开。
    int TRANSIT_TASK_OPEN = 8;


    (1)进入新的堆栈,新的Activity启动时
        com.android.server.wm.DisplayContent.prepareAppTransition
        com.android.server.wm.DisplayContent.prepareAppTransition
        com.android.server.wm.ActivityStack.startActivityLocked
        com.android.server.wm.ActivityStarter.startActivityInner
        com.android.server.wm.ActivityStarter.startActivityUnchecked
        com.android.server.wm.ActivityStarter.executeRequest
        com.android.server.wm.ActivityStarter.execute
        com.android.server.wm.ActivityTaskManagerService.startActivityAsUser
        com.android.server.wm.ActivityTaskManagerService.startActivityAsUser
        com.android.server.wm.ActivityTaskManagerService.startActivity
        android.app.IActivityTaskManager$Stub.onTransact
    (2)进入新的堆栈,新的Activity OnResume时
        com.android.server.wm.DisplayContent.prepareAppTransition
        com.android.server.wm.DisplayContent.prepareAppTransition
        com.android.server.wm.ActivityStack.resumeTopActivityInnerLocked
        com.android.server.wm.ActivityStack.resumeTopActivityUncheckedLocked
        com.android.server.wm.RootWindowContainer.resumeFocusedStacksTopActivities
        com.android.server.wm.ActivityStack.completePauseLocked
        com.android.server.wm.ActivityRecord.activityPaused
        com.android.server.wm.ActivityTaskManagerService.activityPaused
        android.app.IActivityTaskManager$Stub.onTransact


     * 最顶层活动中的一个窗口正在关闭,以显示不同任务中的前一个活动。
    int TRANSIT_TASK_CLOSE = 9;


    (1)应用中按back键推出Activity堆栈时
        com.android.server.wm.DisplayContent.prepareAppTransition
        com.android.server.wm.DisplayContent.prepareAppTransition
        com.android.server.wm.ActivityRecord.finishIfPossible
        com.android.server.wm.ActivityTaskManagerService.finishActivity
        android.app.IActivityTaskManager$Stub.onTransact
    (2)应用中按back键新的堆栈Activity OnResume时
        com.android.server.wm.DisplayContent.prepareAppTransition
        com.android.server.wm.DisplayContent.prepareAppTransition
        com.android.server.wm.ActivityStack.resumeTopActivityInnerLocked
        com.android.server.wm.ActivityStack.resumeTopActivityUncheckedLocked
        com.android.server.wm.RootWindowContainer.resumeFocusedStacksTopActivities
        com.android.server.wm.ActivityStack.completePauseLocked
        com.android.server.wm.ActivityRecord.activityPaused
        com.android.server.wm.ActivityTaskManagerService.activityPaused
        android.app.IActivityTaskManager$Stub.onTransact

     * 现有任务中的窗口显示在另一个活动任务中现有任务的顶部。
    int TRANSIT_TASK_TO_FRONT = 10;


    (1)最近任务进入已有的堆栈
        com.android.server.wm.DisplayContent.prepareAppTransition
        com.android.server.wm.ActivityStack.updateTransitLocked
        com.android.server.wm.ActivityStack.moveTaskToFront
        com.android.server.wm.ActivityStack.moveTaskToFront
        com.android.server.wm.ActivityStackSupervisor.findTaskToMoveToFront
        com.android.server.wm.ActivityTaskManagerService.moveTaskToFrontLocked
        com.android.server.wm.ActivityStackSupervisor.startActivityFromRecents
        com.android.server.wm.ActivityTaskManagerService.startActivityFromRecents
        android.app.IActivityTaskManager$Stub.onTransact
    (2)桌面点击进入已有的堆栈
        com.android.server.wm.DisplayContent.prepareAppTransition
        com.android.server.wm.ActivityStack.updateTransitLocked
        com.android.server.wm.ActivityStack.moveTaskToFront
        com.android.server.wm.ActivityStarter.setTargetStackIfNeeded
        com.android.server.wm.ActivityStarter.recycleTask
        com.android.server.wm.ActivityStarter.startActivityInner
        com.android.server.wm.ActivityStarter.startActivityUnchecked
        com.android.server.wm.ActivityStarter.executeRequest
        com.android.server.wm.ActivityStarter.execute
        com.android.server.wm.ActivityTaskManagerService.startActivityAsUser
        com.android.server.wm.ActivityTaskManagerService.startActivityAsUser
        com.android.server.wm.ActivityTaskManagerService.startActivity
        android.app.IActivityTaskManager$Stub.onTransact
    (3)应用中点击Home键时
        com.android.server.wm.DisplayContent.prepareAppTransition
        com.android.server.wm.ActivityStack.updateTransitLocked
        com.android.server.wm.ActivityStack.moveTaskToFront
        com.android.server.wm.ActivityStarter.setTargetStackIfNeeded
        com.android.server.wm.ActivityStarter.recycleTask
        com.android.server.wm.ActivityStarter.startActivityInner
        com.android.server.wm.ActivityStarter.startActivityUnchecked
        com.android.server.wm.ActivityStarter.executeRequest
        com.android.server.wm.ActivityStarter.execute
        com.android.server.wm.ActivityStartController.startHomeActivity
        com.android.server.wm.RootWindowContainer.startHomeOnTaskDisplayArea
        com.android.server.wm.RootWindowContainer.startHomeOnDisplay
        com.android.server.wm.ActivityTaskManagerService$LocalService.startHomeOnDisplay
        com.android.server.policy.PhoneWindowManager.startDockOrHome
        com.android.server.policy.PhoneWindowManager.launchHomeFromHotKey
        com.android.server.policy.PhoneWindowManager.launchHomeFromHotKey
        com.android.server.policy.PhoneWindowManager.handleShortPressOnHome
        com.android.server.policy.PhoneWindowManager.access$2700
        com.android.server.policy.PhoneWindowManager$DisplayHomeButtonHandler.lambda$handleHomeButton$0$PhoneWindowManager$DisplayHomeButtonHandler


     * 现有任务中的窗口被放置在所有其他任务下方。
    int TRANSIT_TASK_TO_BACK = 11;


    (1)应用主动调用Activity.moveTaskToBack()时出现(这个方法不会改变task中的activity中的顺序,效果基本等同于home键)
        com.android.server.wm.DisplayContent.prepareAppTransition
        com.android.server.wm.DisplayContent.prepareAppTransition
        com.android.server.wm.ActivityStack.moveTaskToBack
        com.android.server.wm.ActivityTaskManagerService.moveActivityTaskToBack
        android.app.IActivityTaskManager$Stub.onTransact

     * Keyguard 即将消失。
    int TRANSIT_KEYGUARD_GOING_AWAY = 20;


        com.android.server.wm.DisplayContent.prepareAppTransition
        com.android.server.wm.KeyguardController.keyguardGoingAway
        com.android.server.wm.ActivityTaskManagerService.keyguardGoingAway
        android.app.IActivityTaskManager$Stub.onTransact

注意:有时会一次Activity切换时会出现多个过渡类型的设置,例如startActivity时会设置一个,Activity OnResume时会出现一次,所以真正的过渡类型,还需要AppTransition.prepareAppTransitionLocked筛选。

    /**
     * @return true if transition is not running and should not be skipped, false if transition is
     *         already running
     */
    boolean prepareAppTransitionLocked(@TransitionType int transit, boolean alwaysKeepCurrent,
            @TransitionFlags int flags, boolean forceOverride) {
        ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
                "Prepare app transition: transit=%s %s alwaysKeepCurrent=%b displayId=%d "
                        + "Callers=%s",
                appTransitionToString(transit), this, alwaysKeepCurrent,
                mDisplayContent.getDisplayId(), Debug.getCallers(20));
        final boolean allowSetCrashing = !isKeyguardTransit(mNextAppTransition)
                && transit == TRANSIT_CRASHING_ACTIVITY_CLOSE;
        if (forceOverride || isKeyguardTransit(transit) || !isTransitionSet()
                || mNextAppTransition == TRANSIT_NONE || allowSetCrashing) {
            setAppTransition(transit, flags);
        }
        // We never want to change from a Keyguard transit to a non-Keyguard transit, as our logic
        // relies on the fact that we always execute a Keyguard transition after preparing one. We
        // also don't want to change away from a crashing transition.
        else if (!alwaysKeepCurrent && !isKeyguardTransit(mNextAppTransition)
                && mNextAppTransition != TRANSIT_CRASHING_ACTIVITY_CLOSE) {
            if (transit == TRANSIT_TASK_OPEN && isTransitionEqual(TRANSIT_TASK_CLOSE)) {
                // Opening a new task always supersedes a close for the anim.
                setAppTransition(transit, flags);
            } else if (transit == TRANSIT_ACTIVITY_OPEN
                    && isTransitionEqual(TRANSIT_ACTIVITY_CLOSE)) {
                // Opening a new activity always supersedes a close for the anim.
                setAppTransition(transit, flags);
            } else if (isTaskTransit(transit) && isActivityTransit(mNextAppTransition)) {
                // Task animations always supersede activity animations, because if we have both, it
                // usually means that activity transition were just trampoline activities.
                setAppTransition(transit, flags);
            }
        }
        boolean prepared = prepare();
        if (isTransitionSet()) {
            removeAppTransitionTimeoutCallbacks();
            mHandler.postDelayed(mHandleAppTransitionTimeoutRunnable, APP_TRANSITION_TIMEOUT_MS);
        }
        return prepared;
    }

三.AppTransition 执行前的调用栈信息

DisplayContent中是应用过渡转化的过程:

    void executeAppTransition() {
        if (mAppTransition.isTransitionSet()) {
            ProtoLog.w(WM_DEBUG_APP_TRANSITIONS,
                    "Execute app transition: %s, displayId: %d Callers=%s",
                    mAppTransition, mDisplayId, Debug.getCallers(20));
            mAppTransition.setReady();
            mWmService.mWindowPlacerLocked.requestTraversal();
        }
    }

此过程会设置AppTransition的状态为准备状态,同时调用WindowSurfacePlacer.requestTraversal对WMS状态做刷新。

(1)非冷启动应用


com.android.server.wm.RootWindowContainer.executeAppTransitionForAllDisplay
com.android.server.wm.ActivityStackSupervisor.reportResumedActivityLocked
com.android.server.wm.ActivityRecord.completeResumeLocked
com.android.server.wm.ActivityStack.resumeTopActivityInnerLocked
com.android.server.wm.ActivityStack.resumeTopActivityUncheckedLocked
com.android.server.wm.RootWindowContainer.resumeFocusedStacksTopActivities
com.android.server.wm.ActivityStack.completePauseLocked
com.android.server.wm.ActivityRecord.activityPaused
com.android.server.wm.ActivityTaskManagerService.activityPaused
android.app.IActivityTaskManager$Stub.onTransact

(2)锁屏消失时


com.android.server.wm.WindowManagerService.executeAppTransition
com.android.server.wm.KeyguardController.keyguardGoingAway
com.android.server.wm.ActivityTaskManagerService.keyguardGoingAway
android.app.IActivityTaskManager$Stub.onTransact

(3)最近任务显示已有堆栈的Actiivty


com.android.server.wm.RootWindowContainer.executeAppTransitionForAllDisplay
com.android.server.wm.ActivityStackSupervisor.reportResumedActivityLocked
com.android.server.wm.ActivityRecord.completeResumeLocked
com.android.server.wm.ActivityStack.resumeTopActivityInnerLocked
com.android.server.wm.ActivityStack.resumeTopActivityUncheckedLocked
com.android.server.wm.RootWindowContainer.resumeFocusedStacksTopActivities
com.android.server.wm.ActivityStarter.resumeTargetStackIfNeeded
com.android.server.wm.ActivityStarter.recycleTask
com.android.server.wm.ActivityStarter.startActivityInner
com.android.server.wm.ActivityStarter.startActivityUnchecked
com.android.server.wm.ActivityStarter.executeRequest
com.android.server.wm.ActivityStarter.execute
com.android.server.wm.ActivityTaskManagerService.startActivityAsUser
com.android.server.wm.ActivityTaskManagerService.startActivityAsUser
com.android.server.wm.ActivityTaskManagerService.startActivity
android.app.IActivityTaskManager$Stub.onTransact

(4)冷启动应用


com.android.server.wm.RootWindowContainer.executeAppTransitionForAllDisplay
com.android.server.wm.ActivityStackSupervisor.reportResumedActivityLocked
com.android.server.wm.ActivityRecord.completeResumeLocked
com.android.server.wm.ActivityStack.minimalResumeActivityLocked
com.android.server.wm.ActivityStackSupervisor.realStartActivityLocked
com.android.server.wm.RootWindowContainer.startActivityForAttachedApplicationIfNeeded
com.android.server.wm.RootWindowContainer.lambda$5fbF65VSmaJkPHxEhceOGTat7JE
com.android.server.wm.-$$Lambda$RootWindowContainer$5fbF65VSmaJkPHxEhceOGTat7JE.apply
com.android.internal.util.function.pooled.PooledLambdaImpl.doInvoke
com.android.internal.util.function.pooled.PooledLambdaImpl.invoke
com.android.internal.util.function.pooled.OmniFunction.apply
com.android.server.wm.ActivityRecord.forAllActivities
com.android.server.wm.WindowContainer.forAllActivities
com.android.server.wm.WindowContainer.forAllActivities
com.android.server.wm.RootWindowContainer.attachApplication
com.android.server.wm.ActivityTaskManagerService$LocalService.attachApplication
com.android.server.am.ActivityManagerService.attachApplicationLocked
com.android.server.am.ActivityManagerService.attachApplication
android.app.IActivityManager$Stub.onTransact
com.android.server.am.ActivityManagerService.onTransact

四.AppTransition的过渡动画的启动

com.android.server.wm.RootWindowContainer.checkAppTransitionReady
com.android.server.wm.RootWindowContainer.performSurfacePlacement
com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementLoop
com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement

    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);

            // If we are ready to perform an app transition, check through all of the app tokens
            // to be shown and see if they are ready to go.
            if (curDisplay.mAppTransition.isReady()) {
                // handleAppTransitionReady may modify curDisplay.pendingLayoutChanges.
                curDisplay.mAppTransitionController.handleAppTransitionReady();
                if (DEBUG_LAYOUT_REPEATS) {
                    surfacePlacer.debugLayoutRepeats("after handleAppTransitionReady",
                            curDisplay.pendingLayoutChanges);
                }
            }

            if (curDisplay.mAppTransition.isRunning() && !curDisplay.isAppTransitioning()) {
                // We have finished the animation of an app transition. To do this, we have
                // delayed a lot of operations like showing and hiding apps, moving apps in
                // Z-order, etc.
                // The app token list reflects the correct Z-order, but the window list may now
                // be out of sync with it. So here we will just rebuild the entire app window
                // list. Fun!
                curDisplay.handleAnimatingStoppedAndTransition();
                if (DEBUG_LAYOUT_REPEATS) {
                    surfacePlacer.debugLayoutRepeats("after handleAnimStopAndXitionLock",
                            curDisplay.pendingLayoutChanges);
                }
            }
        }
    }

如上源码,checkAppTransitionReady会判断DisplayContent的AppTransition是否处于准备状态,处于准备状态的时候就调用AppTransitionController.handleAppTransitionReady。

(1)AppTransitionController.handleAppTransitionReady 准备过渡动画

    /**
     * Handle application transition for given display.
     */
    void handleAppTransitionReady() {
        mTempTransitionReasons.clear();
        /*  对即将打开或者改变的组件做判断是否需要开始过渡
            主要有:屏幕旋转时推迟,组件未准备好时推迟,远程动画时推迟,壁纸未准备好时推迟 */

        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");

        /*判断是否需要跳过过渡
        */
        final AppTransition appTransition = mDisplayContent.mAppTransition;
        int transit = appTransition.getAppTransition();
        if (mDisplayContent.mSkipAppTransitionAnimation && !isKeyguardGoingAwayTransit(transit)) {
            transit = WindowManager.TRANSIT_UNSET;
        }

        /*清理环境属性
        */
        mDisplayContent.mSkipAppTransitionAnimation = false;
        mDisplayContent.mNoAnimationNotifyOnTransitionFinished.clear();

        appTransition.removeAppTransitionTimeoutCallbacks();

        mDisplayContent.mWallpaperMayChange = false;

        /*清理发生变化的组件的动画属性
        */
        int appCount = mDisplayContent.mOpeningApps.size();
        for (int i = 0; i < appCount; ++i) {
            // Clearing the mAnimatingExit flag before entering animation. It's set to true if app
            // window is removed, or window relayout to invisible. This also affects window
            // visibility. We need to clear it *before* maybeUpdateTransitToWallpaper() as the
            // transition selection depends on wallpaper target visibility.
            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);

        /*变化的组件为壁纸目标时
        */
        // Determine if closing and opening app token sets are wallpaper targets, in which case
        // special animations are needed.
        final boolean hasWallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget() != null;
        final boolean openingAppHasWallpaper = canBeWallpaperTarget(mDisplayContent.mOpeningApps)
                && hasWallpaperTarget;
        final boolean closingAppHasWallpaper = canBeWallpaperTarget(mDisplayContent.mClosingApps)
                && hasWallpaperTarget;

        /*变化的组件为透明时做特殊处理
            TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE
            TRANSIT_TRANSLUCENT_ACTIVITY_OPEN
        */
        transit = maybeUpdateTransitToTranslucentAnim(transit);

        /*变化的组件为壁纸目标时做特殊处理,改变过渡方式
            TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER
            TRANSIT_WALLPAPER_INTRA_OPEN
            TRANSIT_WALLPAPER_INTRA_CLOSE
            TRANSIT_WALLPAPER_CLOSE
            TRANSIT_WALLPAPER_OPEN
        */
        transit = maybeUpdateTransitToWallpaper(transit, openingAppHasWallpaper,
                closingAppHasWallpaper);

        // 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.

        /*获取各个变化的组件的TOP,适配远程动画
        */
        final ArraySet<Integer> activityTypes = collectActivityTypes(mDisplayContent.mOpeningApps,
                mDisplayContent.mClosingApps, mDisplayContent.mChangingContainers);
        final ActivityRecord animLpActivity = findAnimLayoutParamsToken(transit, activityTypes);
        final ActivityRecord topOpeningApp =
                getTopApp(mDisplayContent.mOpeningApps, false /* ignoreHidden */);
        final ActivityRecord topClosingApp =
                getTopApp(mDisplayContent.mClosingApps, false /* ignoreHidden */);
        final ActivityRecord topChangingApp =
                getTopApp(mDisplayContent.mChangingContainers, false /* ignoreHidden */);
        final WindowManager.LayoutParams animLp = getAnimLp(animLpActivity);
        overrideWithRemoteAnimationIfSet(animLpActivity, transit, activityTypes);

        /*获取变化组件是否为语音交互
            咦! ||前后两个函数参数都相同
        */
        final boolean voiceInteraction = containsVoiceInteraction(mDisplayContent.mOpeningApps)
                || containsVoiceInteraction(mDisplayContent.mOpeningApps);

        /*暂停系统界面动画,开始设置过渡动画
        */
        final int layoutRedo;
        mService.mSurfaceAnimationRunner.deferStartingAnimations();
        try {
            /*对待关闭/待打开的组件启动过渡动画,此函数较复杂,下面会有详细说明:
            */
            applyAnimations(mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, transit,
                    animLp, voiceInteraction);

            /*处理待关闭的组件,设置其属性使,其满足运行过渡动画的条件:
            */
            handleClosingApps();

            /*处理待打开的组件,设置其属性使,其满足运行过渡动画的条件:
            */
            handleOpeningApps();

            /*对待改变的窗口启动过渡动画,流程上和上面applyAnimations会有重合
            */
            handleChangingApps(transit);

            /*设置AppTransition最新属性
            */
            appTransition.setLastAppTransition(transit, topOpeningApp,
                    topClosingApp, topChangingApp);
            
            /*AppTransition通知监听者是否需要重新布局
            */
            final int flags = appTransition.getTransitFlags();
            layoutRedo = appTransition.goodToGo(transit, topOpeningApp,
                    mDisplayContent.mOpeningApps);

            /*针对非应用基础组件的窗口的过渡动画,如壁纸,状态栏,虚拟按键,悬浮窗等
            */
            handleNonAppWindowsInTransition(transit, flags);

            /*清理环境属性
            */
            appTransition.postAnimationCallback();
            appTransition.clear();
        } finally {
            /*恢复系统界面动画
            */
            mService.mSurfaceAnimationRunner.continueStartingAnimations();
        }
        /*系统缩略图界面动画
        */
        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();

        /*重新计算输入法目标窗口
        */
        mDisplayContent.computeImeTarget(true /* updateImeTarget */);

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

        if (transit == TRANSIT_SHOW_SINGLE_TASK_DISPLAY) {
            mService.mAnimator.addAfterPrepareSurfacesRunnable(() -> {
                mService.mAtmInternal.notifySingleTaskDisplayDrawn(mDisplayContent.getDisplayId());
            });
        }

        Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);

        mDisplayContent.pendingLayoutChanges |=
                layoutRedo | FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_CONFIG;
    }

(2)AppTransitionController.applyAnimations 设置过渡动画

    /*
      * @param openingApps 应用过渡动画的打开应用列表。
      * @param closedApps 应用程序过渡动画所应用的关闭应用程序列表。
      * @param trans 当前过渡类型。
      * @param animLp 应用程序过渡动画在其中运行的布局参数。
      * @param voiceInteraction {@code true} 如果此转换中的应用程序之一属于语音交互会话驱动任务。 
    被handleAppTransitionReady调用
    */
    private void applyAnimations(ArraySet<ActivityRecord> openingApps,
            ArraySet<ActivityRecord> closingApps, @TransitionType int transit,
            LayoutParams animLp, boolean voiceInteraction) {

        /*跳过应用动画
        */
        if (transit == WindowManager.TRANSIT_UNSET
                || (openingApps.isEmpty() && closingApps.isEmpty())) {
            return;
        }

        /*获取openingApps过渡动画的目标,会根据其openingApps和closingApps的关系,向上找寻父类,直到同一父类时停止
            同一应用时为ActivityRecord
            不同应用时为Task
            解锁时无closingApps则为DefaultTaskDisplayArea
        */
        final ArraySet<WindowContainer> openingWcs = getAnimationTargets(
                openingApps, closingApps, true /* visible */);

        /*获取closingApps过渡动画的目标,会根据其openingApps和closingApps的关系,向上找寻父类,直到同一父类时停止
            同一应用时为ActivityRecord
            不同应用时为Task
            解锁时无closingApps则为DefaultTaskDisplayArea
        */
        final ArraySet<WindowContainer> closingWcs = getAnimationTargets(
                openingApps, closingApps, false /* visible */);

        /*将过渡动画应用于openingWcs
        */
        applyAnimations(openingWcs, openingApps, transit, true /* visible */, animLp,
                voiceInteraction);

        /*将过渡动画应用于closingWcs
        */
        applyAnimations(closingWcs, closingApps, transit, false /* visible */, animLp,
                voiceInteraction);

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

    /*将过渡动画应用于目标容器
    */
    private void applyAnimations(ArraySet<WindowContainer> wcs, ArraySet<ActivityRecord> apps,
            @TransitionType 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.

            /*目标组件可能会被抬升至较高级的组件(如:DefaultTaskDisplayArea),onAnimationFinished只会传递到最高的组件
                无法向下传播,故添加目标至高级的组件中使其能够调用到onAnimationFinished
            */
            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);
                }
            }

            /*目标组件应用过渡动画
                (applyAnimation函数不仅在WindowContainer实现,
                也在ActivityRecord中实现了,ActivityRecord是涉及到StartingWindow,此处就不分析了)
            */
            wc.applyAnimation(animLp, transit, visible, voiceInteraction, transitioningDescendants);
        }
    }

(3)WindowContainer.applyAnimation 启动动画

    /*
      * 根据窗口层次结构中给定的布局属性应用过渡动画。
      *
      * @param lp 窗口的布局参数。
      * @param trans 应用程序转换类型指示要应用的转换类型。
      * @param enter 应用过渡是否进入过渡(visible)。
      * @param isVoiceInteraction 容器是否参与语音交互。
      * @param sources {@link ActivityRecord}s which causes this app transition animation.
      *
      * @return {@code true} 当容器应用应用转换时,{@code false} 如果应用转换被禁用或跳过。
    被AppTransitionController.applyAnimations调用
    */
    boolean applyAnimation(WindowManager.LayoutParams lp, 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;
        }

        // Only apply an animation if the display isn't frozen. If it is frozen, there is no reason
        // to animate and it can cause strange artifacts when we unfreeze the display if some
        // different animation is running.

        /*屏幕固定时不允许过渡动画
        */
        try {
            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "WC#applyAnimation");
            if (okToAnimate()) {
                applyAnimationUnchecked(lp, enter, transit, isVoiceInteraction, sources);
            } else {
                cancelAnimation();
            }
        } finally {
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        }

        return isAnimating();
    }

    protected void applyAnimationUnchecked(WindowManager.LayoutParams lp, boolean enter,
            int transit, boolean isVoiceInteraction,
            @Nullable ArrayList<WindowContainer> sources) {

        /*获取两个动画元素,一个用于普通动画,另一个用于缩略图动画
        */
        final Pair<AnimationAdapter, AnimationAdapter> adapters = getAnimationAdapter(lp,
                transit, enter, isVoiceInteraction);
        /*普通动画
        */
        AnimationAdapter adapter = adapters.first;
        /*缩略图动画
        */
        AnimationAdapter thumbnailAdapter = adapters.second;

        if (adapter != null) {

            /*添加onAnimationFinished回调
            */
            if (sources != null) {
                mSurfaceAnimationSources.addAll(sources);
            }

            /*在容器上启动动画
            */
            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) -> { });
            }
        }
    }

(4)WindowContainer.getAnimationAdapter 获取远程/窗口/应用过渡动画

    Pair<AnimationAdapter, AnimationAdapter> getAnimationAdapter(WindowManager.LayoutParams lp,
            int transit, boolean enter, boolean isVoiceInteraction) {
        final Pair<AnimationAdapter, AnimationAdapter> resultAdapters;

        /*在动画期间窗口如何被堆栈边界裁剪
        */
        final int appStackClipMode = getDisplayContent().mAppTransition.getAppStackClipMode();


        // Separate position and size for use in animators.
        /*在动画期间的位置和大小
        */
        final Rect screenBounds = getAnimationBounds(appStackClipMode);
        mTmpRect.set(screenBounds);
        getAnimationPosition(mTmpPoint);
        if (!sHierarchicalAnimations) {
            // Non-hierarchical animation uses position in global coordinates.
            mTmpPoint.set(mTmpRect.left, mTmpRect.top);
        }
        mTmpRect.offsetTo(0, 0);

        /*远程过渡动画
        */
        final RemoteAnimationController controller =
                getDisplayContent().mAppTransition.getRemoteAnimationController();

        /*改变窗口的过渡动画
        */
        final boolean isChanging = AppTransition.isChangeTransit(transit) && enter
                && isChangingAppTransition();

        /*远程过渡动画,如通过Launcher3点击启动应用事,Launcher3会优先设置RemoteAnimationController
        */
        // Delaying animation start isn't compatible with remote animations at all.
        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);
        /*改变窗口的过渡动画
        */
        } 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 {
            /*是否需要创建 mAnimationBoundsLayer 来裁剪动画 
            */
            mNeedsAnimationBoundsLayer = (appStackClipMode == STACK_CLIP_AFTER_ANIM);

            /*装载合适的过渡动画
            */
            final Animation a = loadAnimation(lp, transit, enter, isVoiceInteraction);

            if (a != null) {
                // Only apply corner radius to animation if we're not in multi window mode.
                // We don't want rounded corners when in pip or split screen.
                final float windowCornerRadius = !inMultiWindowMode()
                        ? getDisplayContent().getWindowCornerRadius()
                        : 0;
                AnimationAdapter adapter = new LocalAnimationAdapter(
                        new WindowAnimationSpec(a, mTmpPoint, mTmpRect,
                                getDisplayContent().mAppTransition.canSkipFirstFrame(),
                                appStackClipMode, true /* isAppAnimation */, windowCornerRadius),
                        getSurfaceAnimationRunner());

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


    private Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
                                    boolean isVoiceInteraction) {
        if (isOrganized()) {
            // Defer to the task organizer to run animations
            return null;
        }

        /*显示信息
        */
        final DisplayContent displayContent = getDisplayContent();
        final DisplayInfo displayInfo = displayContent.getDisplayInfo();
        final int width = displayInfo.appWidth;
        final int height = displayInfo.appHeight;
        ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM, "applyAnimation: container=%s", this);

        // Determine the visible rect to calculate the thumbnail clip with
        // getAnimationFrames.

        /*  frame 进入动画结束或退出动画开始的边界。
            insets 被系统窗口覆盖的边界。
            stableInsets 确定稳定系统窗口覆盖的区域的边界。
            surfaceInsets 绘图表面和窗口内容之间的交集。
        */
        final Rect frame = new Rect(0, 0, width, height);
        final Rect displayFrame = new Rect(0, 0,
                displayInfo.logicalWidth, displayInfo.logicalHeight);
        final Rect insets = new Rect();
        final Rect stableInsets = new Rect();
        final Rect surfaceInsets = new Rect();
        getAnimationFrames(frame, insets, stableInsets, surfaceInsets);

        /*
        */
        if (mLaunchTaskBehind) {
            // Differentiate the two animations. This one which is briefly on the screen
            // gets the !enter animation, and the other one which remains on the
            // screen gets the enter animation. Both appear in the mOpeningApps set.
            enter = false;
        }
        ProtoLog.d(WM_DEBUG_APP_TRANSITIONS,
                "Loading animation for app transition. transit=%s enter=%b frame=%s insets=%s "
                        + "surfaceInsets=%s",
                AppTransition.appTransitionToString(transit), enter, frame, insets, surfaceInsets);

        /*获取过渡动画,指向了AppTransition.loadAnimation,会单独开一小节分析源码
        */
        final Configuration displayConfig = displayContent.getConfiguration();
        final Animation a = getDisplayContent().mAppTransition.loadAnimation(lp, transit, enter,
                displayConfig.uiMode, displayConfig.orientation, frame, displayFrame, insets,
                surfaceInsets, stableInsets, isVoiceInteraction, inFreeformWindowingMode(), this);
        if (a != null) {
            if (a != null) {
                // Setup the maximum app transition duration to prevent malicious app may set a long
                // animation duration or infinite repeat counts for the app transition through
                // ActivityOption#makeCustomAnimation or WindowManager#overridePendingTransition.
                a.restrictDuration(MAX_APP_TRANSITION_DURATION);
            }
            if (DEBUG_ANIM) {
                logWithStack(TAG, "Loaded animation " + a + " for " + this
                        + ", duration: " + ((a != null) ? a.getDuration() : 0));
            }
            final int containingWidth = frame.width();
            final int containingHeight = frame.height();
            /*设置动画的目标的尺寸以及目标的父项的尺寸来初始化。(支持相对于这些尺寸指定的动画尺寸)
            */
            a.initialize(containingWidth, containingHeight, width, height);
            a.scaleCurrentDuration(mWmService.getTransitionAnimationScaleLocked());
        }
        return a;
    }

(5)AppTransition.loadAnimation 获取动画实例

    Animation loadAnimation(LayoutParams lp, int transit, boolean enter, int uiMode,
            int orientation, Rect frame, Rect displayFrame, Rect insets,
            @Nullable Rect surfaceInsets, @Nullable Rect stableInsets, boolean isVoiceInteraction,
            boolean freeform, WindowContainer container) {
        Animation a;

        /*锁屏消失时,进入应用界面的动画(包括两种,即将显示壁纸和不显示壁纸应用)*/
        if (isKeyguardGoingAwayTransit(transit) && enter) {
            a = loadKeyguardExitAnimation(transit);
        /*锁屏进入安全界面(紧急拨号,或者相机)时动画为无,一般此时动画由SystemUI处理*/
        } else if (transit == TRANSIT_KEYGUARD_OCCLUDE) {
            a = null;
        /*从安全界面进入锁屏的动画,针对的退出应用动画*/
        } else if (transit == TRANSIT_KEYGUARD_UNOCCLUDE && !enter) {
            a = loadAnimationRes(lp, com.android.internal.R.anim.wallpaper_open_exit);
        /*应用崩溃时动画为无*/
        } else if (transit == TRANSIT_CRASHING_ACTIVITY_CLOSE) {
            a = null;
        /*语音界面,进入前台时的动画*/
        } else if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_OPEN
                || transit == TRANSIT_TASK_OPEN
                || transit == TRANSIT_TASK_TO_FRONT)) {
            a = loadAnimationRes(lp, enter
                    ? com.android.internal.R.anim.voice_activity_open_enter
                    : com.android.internal.R.anim.voice_activity_open_exit);
            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
                    "applyAnimation voice: anim=%s transit=%s isEntrance=%b Callers=%s", a,
                    appTransitionToString(transit), enter, Debug.getCallers(3));
        /*语音界面,退出时的动画*/
        } else if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_CLOSE
                || transit == TRANSIT_TASK_CLOSE
                || transit == TRANSIT_TASK_TO_BACK)) {
            a = loadAnimationRes(lp, enter
                    ? com.android.internal.R.anim.voice_activity_close_enter
                    : com.android.internal.R.anim.voice_activity_close_exit);
            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
                    "applyAnimation voice: anim=%s transit=%s isEntrance=%b Callers=%s", a,
                    appTransitionToString(transit), enter, Debug.getCallers(3));
        /*Actiivty重新启动的动画,如配置修改时的重启*/
        } else if (transit == TRANSIT_ACTIVITY_RELAUNCH) {
            a = createRelaunchAnimation(frame, insets);
            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
                    "applyAnimation: anim=%s nextAppTransition=%d transit=%s Callers=%s", a,
                    mNextAppTransition, appTransitionToString(transit),
                    Debug.getCallers(3));
        /*ActivityOptions(ANIM_CUSTOM)相关过渡动画 ,或者Actiivty.overridePendingTransition设置的过渡动画*/
        } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) {
            a = loadAnimationRes(mNextAppTransitionPackage, enter ?
                    mNextAppTransitionEnter : mNextAppTransitionExit);
            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
                    "applyAnimation: anim=%s nextAppTransition=ANIM_CUSTOM transit=%s "
                            + "isEntrance=%b Callers=%s",
                    a, appTransitionToString(transit), enter, Debug.getCallers(3));
            setAppTransitionFinishedCallbackIfNeeded(a);
        /*ActivityOptions 相关过渡动画*/
        } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE) {
            a = loadAnimationRes(mNextAppTransitionPackage, mNextAppTransitionInPlace);
            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
                    "applyAnimation: anim=%s nextAppTransition=ANIM_CUSTOM_IN_PLACE "
                            + "transit=%s Callers=%s",
                    a, appTransitionToString(transit), Debug.getCallers(3));
        /*ActivityOptions(ANIM_CLIP_REVEAL)相关过渡动画*/
        } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CLIP_REVEAL) {
            a = createClipRevealAnimationLocked(transit, enter, frame, displayFrame);
            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
                    "applyAnimation: anim=%s nextAppTransition=ANIM_CLIP_REVEAL "
                            + "transit=%s Callers=%s",
                    a, appTransitionToString(transit), Debug.getCallers(3));
        /*ActivityOptions(ANIM_SCALE_UP)相关过渡动画*/
        } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_SCALE_UP) {
            a = createScaleUpAnimationLocked(transit, enter, frame);
            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
                    "applyAnimation: anim=%s nextAppTransition=ANIM_SCALE_UP transit=%s "
                            + "isEntrance=%s Callers=%s",
                    a, appTransitionToString(transit), enter, Debug.getCallers(3));
        /*ActivityOptions(ANIM_THUMBNAIL_SCALE_UP/ANIM_THUMBNAIL_SCALE_DOWN)相关过渡动画*/
        } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP ||
                mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN) {
            mNextAppTransitionScaleUp =
                    (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP);
            a = createThumbnailEnterExitAnimationLocked(getThumbnailTransitionState(enter),
                    frame, transit, container);
            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
                    "applyAnimation: anim=%s nextAppTransition=%s transit=%s isEntrance=%b "
                            + "Callers=%s",
                    a,  mNextAppTransitionScaleUp
                            ? "ANIM_THUMBNAIL_SCALE_UP" : "ANIM_THUMBNAIL_SCALE_DOWN",
                    appTransitionToString(transit), enter, Debug.getCallers(3));
        /*ActivityOptions(ANIM_THUMBNAIL_ASPECT_SCALE_UP/ANIM_THUMBNAIL_ASPECT_SCALE_DOWN)相关过渡动画*/
        } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP ||
                mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN) {
            mNextAppTransitionScaleUp =
                    (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP);
            a = createAspectScaledThumbnailEnterExitAnimationLocked(
                    getThumbnailTransitionState(enter), uiMode, orientation, transit, frame,
                    insets, surfaceInsets, stableInsets, freeform, container);
            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
                    "applyAnimation: anim=%s nextAppTransition=%s transit=%s isEntrance=%b "
                            + "Callers=%s",
                    a, mNextAppTransitionScaleUp
                            ? "ANIM_THUMBNAIL_ASPECT_SCALE_UP"
                        : "ANIM_THUMBNAIL_ASPECT_SCALE_DOWN",
                    appTransitionToString(transit), enter, Debug.getCallers(3));
        /*ActivityOptions(ANIM_OPEN_CROSS_PROFILE_APPS)相关过渡动画*/
        } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS && enter) {
            a = loadAnimationRes("android",
                    com.android.internal.R.anim.task_open_enter_cross_profile_apps);
            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
                    "applyAnimation NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS: "
                            + "anim=%s transit=%s isEntrance=true Callers=%s",
                    a, appTransitionToString(transit), Debug.getCallers(3));
        /*Activity WindowMode发生变化时,如自由模式变化为全屏模式*/
        } else if (transit == TRANSIT_TASK_CHANGE_WINDOWING_MODE) {
            // In the absence of a specific adapter, we just want to keep everything stationary.
            a = new AlphaAnimation(1.f, 1.f);
            a.setDuration(WindowChangeAnimationSpec.ANIMATION_DURATION);
            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
                    "applyAnimation: anim=%s transit=%s isEntrance=%b Callers=%s",
                    a, appTransitionToString(transit), enter, Debug.getCallers(3));
        } else {
            /* 见 frameworks/base/core/res/res/values/styles.xml
            */
            int animAttr = 0;
            switch (transit) {
                case TRANSIT_ACTIVITY_OPEN:
                case TRANSIT_TRANSLUCENT_ACTIVITY_OPEN:
                    animAttr = enter
                            ? WindowAnimation_activityOpenEnterAnimation
                            : WindowAnimation_activityOpenExitAnimation;
                    break;
                case TRANSIT_ACTIVITY_CLOSE:
                case TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE:
                    animAttr = enter
                            ? WindowAnimation_activityCloseEnterAnimation
                            : WindowAnimation_activityCloseExitAnimation;
                    break;
                case TRANSIT_DOCK_TASK_FROM_RECENTS:
                case TRANSIT_TASK_OPEN:
                    animAttr = enter
                            ? WindowAnimation_taskOpenEnterAnimation
                            : WindowAnimation_taskOpenExitAnimation;
                    break;
                case TRANSIT_TASK_CLOSE:
                    animAttr = enter
                            ? WindowAnimation_taskCloseEnterAnimation
                            : WindowAnimation_taskCloseExitAnimation;
                    break;
                case TRANSIT_TASK_TO_FRONT:
                    animAttr = enter
                            ? WindowAnimation_taskToFrontEnterAnimation
                            : WindowAnimation_taskToFrontExitAnimation;
                    break;
                case TRANSIT_TASK_TO_BACK:
                    animAttr = enter
                            ? WindowAnimation_taskToBackEnterAnimation
                            : WindowAnimation_taskToBackExitAnimation;
                    break;
                case TRANSIT_WALLPAPER_OPEN:
                    animAttr = enter
                            ? WindowAnimation_wallpaperOpenEnterAnimation
                            : WindowAnimation_wallpaperOpenExitAnimation;
                    break;
                case TRANSIT_WALLPAPER_CLOSE:
                    animAttr = enter
                            ? WindowAnimation_wallpaperCloseEnterAnimation
                            : WindowAnimation_wallpaperCloseExitAnimation;
                    break;
                case TRANSIT_WALLPAPER_INTRA_OPEN:
                    animAttr = enter
                            ? WindowAnimation_wallpaperIntraOpenEnterAnimation
                            : WindowAnimation_wallpaperIntraOpenExitAnimation;
                    break;
                case TRANSIT_WALLPAPER_INTRA_CLOSE:
                    animAttr = enter
                            ? WindowAnimation_wallpaperIntraCloseEnterAnimation
                            : WindowAnimation_wallpaperIntraCloseExitAnimation;
                    break;
                case TRANSIT_TASK_OPEN_BEHIND:
                    animAttr = enter
                            ? WindowAnimation_launchTaskBehindSourceAnimation
                            : WindowAnimation_launchTaskBehindTargetAnimation;
            }
            a = animAttr != 0 ? loadAnimationAttr(lp, animAttr, transit) : null;
            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
                    "applyAnimation: anim=%s animAttr=0x%x transit=%s isEntrance=%b "
                            + "Callers=%s",
                    a, animAttr, appTransitionToString(transit), enter,
                    Debug.getCallers(3));
        }
        return a;
    }

    Animation loadAnimationAttr(LayoutParams lp, int animAttr, int transit) {
        int resId = Resources.ID_NULL;
        Context context = mContext;

        /*依照包名从应用中获取过渡动画
        */
        if (animAttr >= 0) {
            AttributeCache.Entry ent = getCachedAnimations(lp);
            if (ent != null) {
                context = ent.context;
                resId = ent.array.getResourceId(animAttr, 0);
            }
        }

        /*对透明Activity做特殊处理
        */
        resId = updateToTranslucentAnimIfNeeded(resId, transit);

        /*加载过渡动画
        */
        if (ResourceId.isValid(resId)) {
            return loadAnimationSafely(context, resId);
        }
        return null;
    }

注:系统内置动画frameworks/base/core/res/res/values/styles.xml


    <!-- Standard animations for a full-screen window or activity. -->
    <style name="Animation.Activity">
        <item name="activityOpenEnterAnimation">@anim/activity_open_enter</item>
        <item name="activityOpenExitAnimation">@anim/activity_open_exit</item>
        <item name="activityCloseEnterAnimation">@anim/activity_close_enter</item>
        <item name="activityCloseExitAnimation">@anim/activity_close_exit</item>
        <item name="taskOpenEnterAnimation">@anim/task_open_enter</item>
        <item name="taskOpenExitAnimation">@anim/task_open_exit</item>
        <item name="launchTaskBehindTargetAnimation">@anim/launch_task_behind_target</item>
        <item name="launchTaskBehindSourceAnimation">@anim/launch_task_behind_source</item>
        <item name="taskCloseEnterAnimation">@anim/task_close_enter</item>
        <item name="taskCloseExitAnimation">@anim/task_close_exit</item>
        <item name="taskToFrontEnterAnimation">@anim/task_open_enter</item>
        <item name="taskToFrontExitAnimation">@anim/task_open_exit</item>
        <item name="taskToBackEnterAnimation">@anim/task_close_enter</item>
        <item name="taskToBackExitAnimation">@anim/task_close_exit</item>
        <item name="wallpaperOpenEnterAnimation">@anim/wallpaper_open_enter</item>
        <item name="wallpaperOpenExitAnimation">@anim/wallpaper_open_exit</item>
        <item name="wallpaperCloseEnterAnimation">@anim/wallpaper_close_enter</item>
        <item name="wallpaperCloseExitAnimation">@anim/wallpaper_close_exit</item>
        <item name="wallpaperIntraOpenEnterAnimation">@anim/wallpaper_intra_open_enter</item>
        <item name="wallpaperIntraOpenExitAnimation">@anim/wallpaper_intra_open_exit</item>
        <item name="wallpaperIntraCloseEnterAnimation">@anim/wallpaper_intra_close_enter</item>
        <item name="wallpaperIntraCloseExitAnimation">@anim/wallpaper_intra_close_exit</item>
        <item name="fragmentOpenEnterAnimation">@animator/fragment_open_enter</item>
        <item name="fragmentOpenExitAnimation">@animator/fragment_open_exit</item>
        <item name="fragmentCloseEnterAnimation">@animator/fragment_close_enter</item>
        <item name="fragmentCloseExitAnimation">@animator/fragment_close_exit</item>
        <item name="fragmentFadeEnterAnimation">@animator/fragment_fade_enter</item>
        <item name="fragmentFadeExitAnimation">@animator/fragment_fade_exit</item>
    </style>

五.总结:


    AppTransition是系统窗口动画的重要部分,是启动应用,退出应用,切换Activity的过渡动画的管理者。AppTransition不仅支持系统的过渡动画,也可以通过定制style或者Actiivty中overridePendingTransition的方式设置过渡动画,而且也支持远程动画(如Launcher3设置RemoteAnimationController)。AppTransition会把需要的动画交给SurfaceAnimationRunner作处理,而SurfaceAnimationRunner则通过Choreographer在vsync下一帧到来时启动过渡动画。

过渡动画过程为:
    (1)AppTransition.prepareAppTransitionLocked 确定基础的过渡动画类型
    (2)DisplayContent.executeAppTransition 申请执行过渡动画
    (3)WindowSurfacePlacer.performSurfacePlacement 获取过渡动画实例,添加至系统动画系统
        RootWindowContainer.checkAppTransitionReady
        AppTransitionController.handleAppTransitionReady
        AppTransitionController.applyAnimations
        WindowContainer.applyAnimation
        WindowContainer.applyAnimationUnchecked
            WindowContainer.getAnimationAdapter
                AppTransition.loadAnimation
            WindowContainer.startAnimation
                SurfaceAnimator.startAnimation
                LocalAnimationAdapter.startAnimation
                SurfaceAnimationRunner.startAnimation
    (4)SurfaceAnimationRunner.startPendingAnimationsLocked 通过Choreographer.postFrameCallback调用,开启动画

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值