国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Android T 遠(yuǎn)程動(dòng)畫(huà)顯示流程其二——系統(tǒng)側(cè)動(dòng)畫(huà)啟動(dòng)流程

這篇具有很好參考價(jià)值的文章主要介紹了Android T 遠(yuǎn)程動(dòng)畫(huà)顯示流程其二——系統(tǒng)側(cè)動(dòng)畫(huà)啟動(dòng)流程。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

前言

接著上篇文章分析
Android T 遠(yuǎn)程動(dòng)畫(huà)顯示流程其一

切入點(diǎn)——處理應(yīng)用的顯示過(guò)渡

下面,我們以從桌面點(diǎn)擊一個(gè)應(yīng)用啟動(dòng)的場(chǎng)景來(lái)分析遠(yuǎn)程動(dòng)畫(huà)的流程,窗口添加的流程見(jiàn)Android T WMS窗口相關(guān)流程
這里我們從AppTransitionController.handleAppTransitionReady方法開(kāi)始跟蹤代碼流程

代碼路徑:framework/services/core/java/com/android/server/wm/AppTransitionController.java

    /**
     * Handle application transition for given display.
     */
    void handleAppTransitionReady() {
        ......
        //通過(guò)getTransitCompatType方法獲取transit的值
        @TransitionOldType final int transit = getTransitCompatType(
                mDisplayContent.mAppTransition, mDisplayContent.mOpeningApps,
                mDisplayContent.mClosingApps, mDisplayContent.mChangingContainers,
                mWallpaperControllerLocked.getWallpaperTarget(), getOldWallpaper(),
                mDisplayContent.mSkipAppTransitionAnimation);
    	......
    	//方法收集正在打開(kāi) (mOpeningApps)、關(guān)閉 (mClosingApps) 和切換 (mChangingContainers) 的應(yīng)用的activity類型
    	//并將它們存儲(chǔ)在 activityTypes 集合中。
    	final ArraySet<Integer> activityTypes = collectActivityTypes(mDisplayContent.mOpeningApps,
                mDisplayContent.mClosingApps, mDisplayContent.mChangingContainers);
        //被用于查找與給定transit和activityTypes相關(guān)的 ActivityRecord
        //也就是我們當(dāng)前打開(kāi)的應(yīng)用的ActivityRecord
        final ActivityRecord animLpActivity = findAnimLayoutParamsToken(transit, activityTypes,
                mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
                mDisplayContent.mChangingContainers);
        //獲取正在打開(kāi)的應(yīng)用列表 (mOpeningApps) 中的頂層應(yīng)用。
        //ignoreHidden 參數(shù)設(shè)置為 false,意味著即使應(yīng)用是隱藏的,也會(huì)被考慮在內(nèi)
        final ActivityRecord topOpeningApp =
                getTopApp(mDisplayContent.mOpeningApps, false /* ignoreHidden */);
        //獲取正在關(guān)閉的應(yīng)用列表 (mClosingApps) 中的頂層應(yīng)用
        final ActivityRecord topClosingApp =
                getTopApp(mDisplayContent.mClosingApps, false /* ignoreHidden */);
        //獲取正在切換的應(yīng)用列表 (mChangingContainers) 中的頂層應(yīng)用
        //其取決于參數(shù)DisplayContent.mChangingContainers中是否有值
        /** 
        有三種情況會(huì)給DisplayContent.mChangingContainers中添加值
        1.{@link Task}在全屏和浮窗之間發(fā)生切換
        2.{@link TaskFragment}已組織好并且正在更改窗口邊界
        3.{@link ActivityRecord}被重新分配到一個(gè)有組織的{@link TaskFragment}中
        **/
        final ActivityRecord topChangingApp =
                getTopApp(mDisplayContent.mChangingContainers, false /* ignoreHidden */);
        //從之前找到的animLpActivity(正在打開(kāi)的應(yīng)用的ActivityRecord)的窗口中獲取布局參數(shù)
        final WindowManager.LayoutParams animLp = getAnimLp(animLpActivity);
    	......
        try {
            /*1.1應(yīng)用app transition動(dòng)畫(huà)(遠(yuǎn)程動(dòng)畫(huà))*/
            applyAnimations(mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, transit,
                    animLp, voiceInteraction);
            /*1.2.1處理closing activity可見(jiàn)性*/
            handleClosingApps();
            /*1.2.2處理opening actvity可見(jiàn)性*/
            handleOpeningApps();
            //處理用于處理正在切換的應(yīng)用
            handleChangingApps(transit);
            //處理正在關(guān)閉或更改的容器
            handleClosingChangingContainers();

            //設(shè)置與最后一次應(yīng)用過(guò)渡動(dòng)畫(huà)相關(guān)的信息
            appTransition.setLastAppTransition(transit, topOpeningApp,
                    topClosingApp, topChangingApp);

            final int flags = appTransition.getTransitFlags();
            /*1.3播放遠(yuǎn)程動(dòng)畫(huà)*/
            layoutRedo = appTransition.goodToGo(transit, topOpeningApp);
            //處理非應(yīng)用窗口的過(guò)渡動(dòng)畫(huà)
            handleNonAppWindowsInTransition(transit, flags);
            //執(zhí)行動(dòng)畫(huà)回調(diào)
            appTransition.postAnimationCallback()
        } finally {
            mService.mSurfaceAnimationRunner.continueStartingAnimations();
        }
        ......

        // This has changed the visibility of windows, so perform
        // a new layout to get them all up-to-date.
        /*2.由于activity的可見(jiàn)性變更,將DisplayContent.mLayoutNeeded標(biāo)志位置為true*/
        mDisplayContent.setLayoutNeeded();
        ......
    }

這個(gè)方法主要處理這三件事:
1.處理activity的過(guò)渡動(dòng)畫(huà)(遠(yuǎn)程動(dòng)畫(huà))
2.分別調(diào)用 handleClosingApps以及handleOpeningApps對(duì)要關(guān)閉的和要打開(kāi)的Activity進(jìn)行可見(jiàn)性更新。
3.調(diào)用AppTransition.goodToGo方法走播放遠(yuǎn)程動(dòng)畫(huà)流程。
4.由于activity的可見(jiàn)性變更,將DisplayContent.mLayoutNeeded設(shè)置為true,該標(biāo)志位在DisplayContent.performLayoutNoTrace中用來(lái)判斷是否對(duì)當(dāng)前DisplayContent下的所有窗口進(jìn)行刷新。
這里我們主要關(guān)注遠(yuǎn)程動(dòng)畫(huà)的流程,主要分為兩個(gè)部分。

  1. 處理并創(chuàng)建遠(yuǎn)程動(dòng)畫(huà)流程
    applyAnimations(mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, transit, animLp, voiceInteraction);
  2. 播放顯示遠(yuǎn)程動(dòng)畫(huà)流程
    layoutRedo = appTransition.goodToGo(transit, topOpeningApp);

動(dòng)畫(huà)創(chuàng)建流程

applyAnimations(mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, transit, animLp, voiceInteraction);

基于一組ActivityRecord來(lái)應(yīng)用動(dòng)畫(huà),這些ActivityRecord表示正在進(jìn)行切換的應(yīng)用。
mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps這兩個(gè)參數(shù)分別代表正在打開(kāi)和關(guān)閉的應(yīng)用;
transit通過(guò)前面getTransitCompatType方法中獲取,是TRANSIT_OLD_WALLPAPER_CLOSE(12);
animLp通過(guò)前面getAnimLp方法中獲取,用于定義窗口的布局參數(shù)。這里就是代表正在打開(kāi)的應(yīng)用的ActivityRecord的窗口布局參數(shù);
voiceInteraction:表示是否為語(yǔ)音交互。

處理并創(chuàng)建遠(yuǎn)程動(dòng)畫(huà)

代碼路徑:framework/services/core/java/com/android/server/wm/AppTransitionController.java

    /**
     * Apply an app transition animation based on a set of {@link ActivityRecord}
     *
     * @param openingApps The list of opening apps to which an app transition animation applies.
     * @param closingApps The list of closing apps to which an app transition animation applies.
     * @param transit The current transition type.
     * @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<ActivityRecord> openingApps,
            ArraySet<ActivityRecord> closingApps, @TransitionOldType int transit,
            LayoutParams animLp, boolean voiceInteraction) {
        //方法檢查過(guò)渡類型是否未設(shè)置,或者打開(kāi)和關(guān)閉的應(yīng)用程序是否都為空。如果是,則方法直接返回,不執(zhí)行任何動(dòng)畫(huà)。
        if (transit == WindowManager.TRANSIT_OLD_UNSET
                || (openingApps.isEmpty() && closingApps.isEmpty())) {
            return;
        }

        //調(diào)用getAnimationTargets方法獲取打開(kāi)和關(guān)閉的應(yīng)用的窗口容器(WindowContainer)
        final ArraySet<WindowContainer> openingWcs = getAnimationTargets(
                openingApps, closingApps, true /* visible */);
        final ArraySet<WindowContainer> closingWcs = getAnimationTargets(
                openingApps, closingApps, false /* visible */);
        //打開(kāi)和關(guān)閉的窗口應(yīng)用動(dòng)畫(huà)。這是通過(guò)調(diào)重載的applyAnimations方法完成的,傳遞相應(yīng)的參數(shù),如動(dòng)畫(huà)的目標(biāo)、過(guò)渡類型等。
        applyAnimations(openingWcs, openingApps, transit, true /* visible */, animLp,
                voiceInteraction);
        applyAnimations(closingWcs, closingApps, transit, false /* visible */, animLp,
                voiceInteraction);
        //如果存在最近任務(wù)動(dòng)畫(huà)控制器(RecentsAnimationController),則發(fā)送任務(wù)出現(xiàn)任務(wù)
        final RecentsAnimationController rac = mService.getRecentsAnimationController();
        if (rac != null) {
            rac.sendTasksAppeared();
        }

        //遍歷打開(kāi)和關(guān)閉的應(yīng)用,并設(shè)置mOverrideTaskTransition為false
        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;
        }

        //如果存在輔助功能控制器(AccessibilityController)且有回調(diào),則調(diào)用其onAppWindowTransition方法。
        final AccessibilityController accessibilityController =
                mDisplayContent.mWmService.mAccessibilityController;
        if (accessibilityController.hasCallbacks()) {
            accessibilityController.onAppWindowTransition(mDisplayContent.getDisplayId(), transit);
        }
    }

傳遞關(guān)鍵參數(shù),處理應(yīng)用程序窗口的打開(kāi)和關(guān)閉動(dòng)畫(huà)。
通過(guò)getAnimationTargets方法獲取當(dāng)前打開(kāi)和關(guān)閉的應(yīng)用的容器,即ActivityRecord的容器。
最關(guān)鍵的方法是調(diào)用的applyAnimations方法:

        applyAnimations(openingWcs, openingApps, transit, true /* visible */, animLp,
                voiceInteraction);
        applyAnimations(closingWcs, closingApps, transit, false /* visible */, animLp,
                voiceInteraction);

我們這里openingWcsclosingWcs實(shí)際上表示的是應(yīng)用的容器,即Task;openingAppsclosingApps就是前面?zhèn)鬟f的mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,分別代表正在打開(kāi)和關(guān)閉的應(yīng)用,也是掛在對(duì)應(yīng)Task下面的ActivityRecord。并且傳遞了應(yīng)用的可見(jiàn)性visible,true可見(jiàn),false不可見(jiàn)。
因此在我們桌面點(diǎn)擊打開(kāi)應(yīng)用的流程中,openingWcs實(shí)際上指的是應(yīng)用的Task,openingApps是應(yīng)用的ActivityRecord(其實(shí)就是應(yīng)用的主界面),其可見(jiàn)性為true;closingWcs對(duì)應(yīng)的是桌面的Task,closingApps是桌面的ActivityRecord,其可見(jiàn)性為false。

這也對(duì)應(yīng)了我們前面創(chuàng)建動(dòng)畫(huà)圖層的堆棧中所打印的,先創(chuàng)建了應(yīng)用的動(dòng)畫(huà)圖層,后創(chuàng)建桌面的動(dòng)畫(huà)圖層。

注:
從這里開(kāi)始后續(xù)流程執(zhí)行了兩次,第一次是打開(kāi)的應(yīng)用流程,第二次是關(guān)閉的應(yīng)用流程(一個(gè)應(yīng)用的啟動(dòng),伴隨這另一個(gè)應(yīng)用的退出,浮窗等特殊場(chǎng)景除外)。
從桌面點(diǎn)擊開(kāi)啟應(yīng)用的場(chǎng)景來(lái)說(shuō),一次是啟動(dòng)的應(yīng)用角度執(zhí)行流程,另一次是桌面角度執(zhí)行流程。
從代碼邏輯上來(lái)說(shuō),唯一的不同點(diǎn)是傳遞的可見(jiàn)性的值不同。

這個(gè)方法調(diào)用的是重載的applyAnimations方法

獲取需要做動(dòng)畫(huà)的容器

	  /**
     * 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) {
        //獲取窗口容器的數(shù)量
        final int wcsCount = wcs.size();
        //遍歷每一個(gè)應(yīng)用的窗口容器
        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.
            //對(duì)于每一個(gè)應(yīng)用的窗口容器,檢查正在進(jìn)行切換的應(yīng)用(apps)中哪些是該窗口容器的后代。
            //就比如應(yīng)用的ActivityRecord是是應(yīng)用的Task的后代
            final ArrayList<ActivityRecord> transitioningDescendants = new ArrayList<>();
            for (int j = 0; j < apps.size(); ++j) {
                final ActivityRecord app = apps.valueAt(j);
                //app如果是wc的后代,將其添加到一個(gè)列表中。
                if (app.isDescendantOf(wc)) {
                    transitioningDescendants.add(app);
                }
            }
            //調(diào)用每個(gè)應(yīng)用的窗口容器的applyAnimation方法,傳入相應(yīng)的參數(shù)
            //這些參數(shù)包含動(dòng)畫(huà)的布局、過(guò)渡類型、是否可見(jiàn)、是否有語(yǔ)音交互以及需要做動(dòng)畫(huà)的ActivityRecord應(yīng)用的列表。
            wc.applyAnimation(animLp, transit, visible, voiceInteraction, transitioningDescendants);
        }
    }

入?yún)⒑x:
wcs: 一個(gè)WindowContainer對(duì)象的集合,這些對(duì)象是需要應(yīng)用動(dòng)畫(huà)的窗口容器。
apps: 一個(gè)ActivityRecord對(duì)象的集合,這些對(duì)象表示正在進(jìn)行切換的應(yīng)用程序。
transit: 當(dāng)前的過(guò)渡類型,例如淡入淡出、滑動(dòng)等。
visible: 一個(gè)布爾值,表示應(yīng)用是否變?yōu)榭梢?jiàn)。
animLp: 布局參數(shù),定義了動(dòng)畫(huà)運(yùn)行時(shí)的布局。
voiceInteraction: 一個(gè)布爾值,表示是否有語(yǔ)音交互。

關(guān)鍵代碼解讀:

  • final WindowContainer wc = wcs.valueAt(i);獲取窗口容器
    wcs是前面?zhèn)鬟f過(guò)來(lái)的是Task,wc就是依次獲取當(dāng)前應(yīng)用的Task和桌面Task。

  • transitioningDescendants存儲(chǔ)的就是需要做動(dòng)畫(huà)的ActivityRecord。

  • 傳遞動(dòng)畫(huà)參數(shù)
    通過(guò)wc.applyAnimation(animLp, transit, visible, voiceInteraction, transitioningDescendants);方法,傳遞參數(shù)動(dòng)畫(huà)的布局、過(guò)渡類型、是否可見(jiàn)、是否有語(yǔ)音交互以及需要做動(dòng)畫(huà)的ActivityRecord應(yīng)用的列表。
    wc就是Task,其沒(méi)有applyAnimation方法,向上找父類WindowContainer.applyAnimation方法調(diào)用。

判斷是否應(yīng)用動(dòng)畫(huà),傳遞相關(guān)參數(shù)

代碼路徑:frameworks/base/services/core/java/com/android/server/wm/WindowContainer.java

/**
     * Applies the app transition animation according the given the layout properties in the
     * window hierarchy.
     *
     * @param lp The layout parameters of the window.
     * @param transit The app transition type indicates what kind of transition to be applied.
     * @param enter Whether the app transition is entering transition or not.
     * @param isVoiceInteraction Whether the container is participating in voice interaction or not.
     * @param sources {@link ActivityRecord}s which causes this app transition animation.
     *
     * @return {@code true} when the container applied the app transition, {@code false} if the
     *         app transition is disabled or skipped.
     *
     * @see #getAnimationAdapter
     */
    boolean applyAnimation(WindowManager.LayoutParams lp, @TransitionOldType int transit,
            boolean enter, boolean isVoiceInteraction,
            @Nullable ArrayList<WindowContainer> sources) {
        //判斷是否禁用過(guò)渡動(dòng)畫(huà)
        if (mWmService.mDisableTransitionAnimation) {
            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
                    "applyAnimation: transition animation is disabled or skipped. "
                            + "container=%s", this);
            //取消當(dāng)前動(dòng)畫(huà)
            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");
            //會(huì)判斷是否有凍結(jié),屏幕是否開(kāi)啟
            if (okToAnimate()) {
                ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
                        "applyAnimation: transit=%s, enter=%b, wc=%s",
                        AppTransition.appTransitionOldToString(transit), enter, this);
                //傳遞相關(guān)參數(shù),創(chuàng)建AnimationAdapter和AnimationRunnerBuilder,準(zhǔn)備啟動(dòng)動(dòng)畫(huà)
                applyAnimationUnchecked(lp, enter, transit, isVoiceInteraction, sources);
            } else {
                //取消當(dāng)前動(dòng)畫(huà)
                cancelAnimation();
            }
        } finally {
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        }
        //檢查指定的窗口容器是否正在進(jìn)行動(dòng)畫(huà)
        return isAnimating();
    }

下面說(shuō)說(shuō)里面的幾個(gè)關(guān)鍵點(diǎn):

  • 判斷是否禁用過(guò)渡動(dòng)畫(huà)
    mWmService.mDisableTransitionAnimation
    這個(gè)變量是在WindowManagerService的構(gòu)造方法中初始化的

    mDisableTransitionAnimation = context.getResources().getBoolean(
             com.android.internal.R.bool.config_disableTransitionAnimation);
    

    可以發(fā)現(xiàn)是讀取config_disableTransitionAnimation配置項(xiàng)
    代碼路徑:frameworks/base/core/res/res/values/symbols.xml

     <java-symbol type="bool" name="config_disableTransitionAnimation" />
    

    定義了這個(gè)symbol
    代碼路徑:frameworks/base/core/res/res/values/config.xml

        <!-- Flag to disable all transition animations -->
        <bool name="config_disableTransitionAnimation">false</bool>
    

    定義了默認(rèn)值為false,不禁用過(guò)渡動(dòng)畫(huà)

  • 取消當(dāng)前動(dòng)畫(huà)
    cancelAnimation();

        void cancelAnimation() {
            //處理動(dòng)畫(huà)結(jié)束時(shí)的一些后續(xù)操作
            doAnimationFinished(mSurfaceAnimator.getAnimationType(), mSurfaceAnimator.getAnimation());
            //調(diào)用SurfaceAnimator.cancelAnimation方法來(lái)取消當(dāng)前正在進(jìn)行的動(dòng)畫(huà)
            mSurfaceAnimator.cancelAnimation();
            //調(diào)用unfreeze方法解除對(duì)顯示的凍結(jié)狀態(tài),允許顯示繼續(xù)正常更新和渲染
            mSurfaceFreezer.unfreeze(getSyncTransaction());
        }
    

    doAnimationFinished方法在動(dòng)畫(huà)播放結(jié)束時(shí)處理回調(diào)邏輯中會(huì)調(diào)用到。

  • 準(zhǔn)備動(dòng)畫(huà)
    applyAnimationUnchecked(lp, enter, transit, isVoiceInteraction, sources);
    把前面?zhèn)鬟f的參數(shù)動(dòng)畫(huà)的布局、過(guò)渡類型、是否可見(jiàn)、是否有語(yǔ)音交互以及需要做動(dòng)畫(huà)的ActivityRecord應(yīng)用的列表,再次傳遞到applyAnimationUnchecked方法中。
    注意,這里調(diào)用的是Task中重寫的applyAnimationUnchecked方法,而不是直接調(diào)用的WindowContainer中的applyAnimationUnchecked方法。
    因?yàn)槲覀兦懊媸峭ㄟ^(guò)前面AppTransitionController.applyAnimations中wc.applyAnimation(animLp, transit, visible, voiceInteraction, transitioningDescendants);調(diào)用過(guò)來(lái)的,因此此時(shí)的this指針指的是變量wc,即應(yīng)用對(duì)應(yīng)的Task。
    后面細(xì)講applyAnimationUnchecked方法。

  • 檢查動(dòng)畫(huà)
    代碼路徑:frameworks/base/services/core/java/com/android/server/wm/WindowContainer.java

        final boolean isAnimating(int flags, int typesToCheck) {
            return getAnimatingContainer(flags, typesToCheck) != null;
        }
    

    flags 用于確定要檢查的動(dòng)畫(huà)類型和范圍。
    typesToCheck 用于確定哪些類型的動(dòng)畫(huà)需要檢查。
    方法內(nèi)部調(diào)用 getAnimatingContainer 方法來(lái)獲取正在進(jìn)行動(dòng)畫(huà)的窗口容器,并根據(jù)返回值判斷是否存在符合條件和目標(biāo)標(biāo)志的動(dòng)畫(huà)。
    如果返回值為 true,則說(shuō)明存在符合條件的動(dòng)畫(huà);如果返回值為 false,則說(shuō)明不存在符合條件的動(dòng)畫(huà)。

處理最近任務(wù)狀態(tài)的動(dòng)畫(huà)

applyAnimationUnchecked(lp, enter, transit, isVoiceInteraction, sources);
其中參數(shù)enter代表的其實(shí)就應(yīng)用的可見(jiàn)性,從前面AppTransitionController.applyAnimations方法中逐步傳遞過(guò)來(lái)值有兩個(gè)

applyAnimations(openingWcs, openingApps, transit, true /* visible */, animLp, voiceInteraction);
applyAnimations(closingWcs, closingApps, transit, false /* visible */, animLp, voiceInteraction);

啟動(dòng)的應(yīng)用的可見(jiàn)性為true,桌面的可見(jiàn)性為false
代碼路徑:frameworks/base/services/core/java/com/android/server/wm/Task.java

@Override
    protected void applyAnimationUnchecked(WindowManager.LayoutParams lp, boolean enter,
            @TransitionOldType int transit, boolean isVoiceInteraction,
            @Nullable ArrayList<WindowContainer> sources) {
        //獲取RecentsAnimationController
        //只有在最近任務(wù)中,切換到另一個(gè)應(yīng)用時(shí)才會(huì)創(chuàng)建
        final RecentsAnimationController control = mWmService.getRecentsAnimationController();
        //RecentsAnimationController不為空
        if (control != null) {
            // We let the transition to be controlled by RecentsAnimation, and callback task's
            // RemoteAnimationTarget for remote runner to animate.
            //應(yīng)用可見(jiàn)性為true,且當(dāng)前activity不是桌面或者最近任務(wù)
            if (enter && !isActivityTypeHomeOrRecents()) {
                ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
                        "applyAnimationUnchecked, control: %s, task: %s, transit: %s",
                        control, asTask(), AppTransition.appTransitionOldToString(transit));
                //執(zhí)行最近任務(wù)動(dòng)畫(huà)邏輯
                control.addTaskToTargets(this, (type, anim) -> {
                    for (int i = 0; i < sources.size(); ++i) {
                        sources.get(i).onAnimationFinished(type, anim);
                    }
                });
            }
        //判斷是否有返回手勢(shì)
        } else if (mBackGestureStarted) {
            // Cancel playing transitions if a back navigation animation is in progress.
            // This bit is set by {@link BackNavigationController} when a back gesture is started.
            // It is used as a one-off transition overwrite that is cleared when the back gesture
            // is committed and triggers a transition, or when the gesture is cancelled.
            //返回手勢(shì)mBackGestureStarted標(biāo)志位置為false
            mBackGestureStarted = false;
            //設(shè)置一個(gè)標(biāo)志為true,表示應(yīng)跳過(guò)應(yīng)用的過(guò)渡動(dòng)畫(huà)。
            mDisplayContent.mSkipAppTransitionAnimation = true;
            ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "Skipping app transition animation. task=%s", this);
        } else {
            //調(diào)用父類WindowContainer的applyAnimationUnchecked方法
            super.applyAnimationUnchecked(lp, enter, transit, isVoiceInteraction, sources);
        }
    }

只有在最近任務(wù)中,切換到另一個(gè)應(yīng)用時(shí)才會(huì)創(chuàng)建RecentsAnimationController,因此control的值為空。如果不為空,應(yīng)用可見(jiàn)性為true,且當(dāng)前activity不是桌面或者最近任務(wù),則會(huì)進(jìn)入到最近任務(wù)的動(dòng)畫(huà)處理邏輯。
我們?cè)诓僮鬟^(guò)程中也沒(méi)有返回手勢(shì),因此mBackGestureStarted為false。
所以調(diào)用了父類WindowContainer的applyAnimationUnchecked方法。

獲取AnimationAdapter并創(chuàng)建動(dòng)畫(huà)圖層

接著前面super.applyAnimationUnchecked(lp, enter, transit, isVoiceInteraction, sources);進(jìn)行分析
代碼路徑:frameworks/base/services/core/java/com/android/server/wm/WindowContainer.java

    protected void applyAnimationUnchecked(WindowManager.LayoutParams lp, boolean enter,
            @TransitionOldType int transit, boolean isVoiceInteraction,
            @Nullable ArrayList<WindowContainer> sources) {
        //獲取當(dāng)前Task
        final Task task = asTask();
        //當(dāng)前Task不為空,應(yīng)用變?yōu)椴豢梢?jiàn)狀態(tài),且應(yīng)用Task不為桌面或者最近任務(wù)
        //可以理解為應(yīng)用按home鍵回到桌面的場(chǎng)景
        if (task != null && !enter && !task.isActivityTypeHomeOrRecents()) {
            //對(duì)輸入法相關(guān)insets做處理
            final InsetsControlTarget imeTarget = mDisplayContent.getImeTarget(IME_TARGET_LAYERING);
            final boolean isImeLayeringTarget = imeTarget != null && imeTarget.getWindow() != null
                    && imeTarget.getWindow().getTask() == task;
            // Attach and show the IME screenshot when the task is the IME target and performing
            // task closing transition to the next task.
            if (isImeLayeringTarget && AppTransition.isTaskCloseTransitOld(transit)) {
                mDisplayContent.showImeScreenshot();
            }
        }
        //創(chuàng)建AnimationAdapter
        final Pair<AnimationAdapter, AnimationAdapter> adapters = getAnimationAdapter(lp,
                transit, enter, isVoiceInteraction);
        //adapters.first指的是創(chuàng)建startBounds為空情況RemoteAnimationAdapterWrapper的對(duì)象
        AnimationAdapter adapter = adapters.first;
        //adapters.second指的是創(chuàng)建startBounds不為空情況RemoteAnimationAdapterWrapper的對(duì)象
        AnimationAdapter thumbnailAdapter = adapters.second;
        if (adapter != null) {
            if (sources != null) {
                //把需要做的動(dòng)畫(huà)的ActivityRecord添加到mSurfaceAnimationSources
                mSurfaceAnimationSources.addAll(sources);
            }

            //創(chuàng)建AnimationRunnerBuilder
            AnimationRunnerBuilder animationRunnerBuilder = new AnimationRunnerBuilder();
             
            //isTaskTransitOld方法中根據(jù)transit的值判斷返回值,
            //從桌面啟動(dòng)應(yīng)用時(shí)transit為12,表示TRANSIT_OLD_WALLPAPER_CLOSE
            if (isTaskTransitOld(transit)) {
                //設(shè)置過(guò)渡動(dòng)畫(huà)背景色
                animationRunnerBuilder.setTaskBackgroundColor(getTaskAnimationBackgroundColor());
                // TODO: Remove when we migrate to shell (b/202383002)
                //mTaskTransitionSpec不為null
                if (mWmService.mTaskTransitionSpec != null) {
                    //隱藏Insets溢出的部分
                    animationRunnerBuilder.hideInsetSourceViewOverflows(
                            mWmService.mTaskTransitionSpec.animationBoundInsets);
                }
            }

            // Check if the animation requests to show background color for Activity and embedded
            // TaskFragment.
            //獲取當(dāng)前Activity,但我們當(dāng)前只有Task,因此為空
            final ActivityRecord activityRecord = asActivityRecord();
            //TaskFragment為Task父類,獲取到了當(dāng)前Task
            final TaskFragment taskFragment = asTaskFragment();
            //設(shè)置過(guò)渡動(dòng)動(dòng)畫(huà)背景色邏輯
            if (adapter.getShowBackground()
                    // Check if it is Activity transition.
                    && ((activityRecord != null && isActivityTransitOld(transit))
                    // Check if it is embedded TaskFragment transition.
                    || (taskFragment != null && taskFragment.isEmbedded()
                    && isTaskFragmentTransitOld(transit)))) {
                final @ColorInt int backgroundColorForTransition;
                if (adapter.getBackgroundColor() != 0) {
                    // If available use the background color provided through getBackgroundColor
                    // which if set originates from a call to overridePendingAppTransition.
                    backgroundColorForTransition = adapter.getBackgroundColor();
                } else {
                    ......
                }
                animationRunnerBuilder.setTaskBackgroundColor(backgroundColorForTransition);
            }

            //進(jìn)入創(chuàng)建動(dòng)畫(huà)圖層邏輯
            animationRunnerBuilder.build()
                    .startAnimation(getPendingTransaction(), adapter, !isVisible(),
                            ANIMATION_TYPE_APP_TRANSITION, thumbnailAdapter);

            //判斷是否在動(dòng)畫(huà)中顯示壁紙
            if (adapter.getShowWallpaper()) {
                //更新pendingLayoutChanges添加標(biāo)志FINISH_LAYOUT_REDO_WALLPAPER,表示需要重新處理壁紙布局。
                getDisplayContent().pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
            }
        }
    }

這個(gè)方法主要就是獲取AnimationAdapter,創(chuàng)建對(duì)應(yīng)的動(dòng)畫(huà)圖層,我們下面主要討論這兩個(gè)點(diǎn)。

創(chuàng)建RemoteAnimationRecord

創(chuàng)建RemoteAnimationRecord,并在其中創(chuàng)建RemoteAnimationAdapterWrapper,在通過(guò)RemoteAnimationAdapterWrapper實(shí)現(xiàn)AnimationAdapter接口

final Pair<AnimationAdapter, AnimationAdapter> adapters = getAnimationAdapter(lp,
                transit, enter, isVoiceInteraction);

調(diào)用的是WindowContainer中的getAnimationAdapter方法,傳遞了參數(shù)動(dòng)畫(huà)的布局、過(guò)渡類型、是否可見(jiàn)、是否有語(yǔ)音交互。

/**
     * Gets the {@link AnimationAdapter} according the given window layout properties in the window
     * hierarchy.
     *
     * @return The return value will always contain two elements, one for normal animations and the
     * other for thumbnail animation, both can be {@code null}.
     * @See com.android.server.wm.RemoteAnimationController.RemoteAnimationRecord
     * @See LocalAnimationAdapter
     */
    Pair<AnimationAdapter, AnimationAdapter> getAnimationAdapter(WindowManager.LayoutParams lp,
                                                                 @TransitionOldType int transit, boolean enter, boolean isVoiceInteraction) {
        final Pair<AnimationAdapter, AnimationAdapter> resultAdapters;
        //獲取當(dāng)前窗口的裁剪模式
        final int appRootTaskClipMode = getDisplayContent().mAppTransition.getAppRootTaskClipMode();

        // Separate position and size for use in animators.
        //獲取屏幕大小,參數(shù)appRootTaskClipMode在這個(gè)方法中無(wú)實(shí)際意義
        final Rect screenBounds = getAnimationBounds(appRootTaskClipMode);
        //mTmpRect大小賦值為屏幕大小
        mTmpRect.set(screenBounds);
        //transit值為12,TRANSIT_OLD_WALLPAPER_CLOSE,不進(jìn)入該流程
        if (this.asTask() != null && isTaskTransitOld(transit)) {
            this.asTask().adjustAnimationBoundsForTransition(mTmpRect);
        }
        //設(shè)置動(dòng)畫(huà)位置為左上角頂點(diǎn)(0, 0)
        getAnimationPosition(mTmpPoint);
        mTmpRect.offsetTo(0, 0);

        final AppTransition appTransition = getDisplayContent().mAppTransition;
        //創(chuàng)建RemoteAnimationController
        final RemoteAnimationController controller = appTransition.getRemoteAnimationController();
        //AppTransition.isChangeTransitOld(transit),transit值為12,返回false
        //enter 應(yīng)用可見(jiàn)性,啟動(dòng)應(yīng)用的可見(jiàn)性為true,桌面可見(jiàn)性為false
        //isChangingAppTransition(),判斷當(dāng)前應(yīng)用是否切換過(guò)渡,
        //其取決于參數(shù)DisplayContent.mChangingContainers中是否有值
        /** 
        有三種情況會(huì)給DisplayContent.mChangingContainers中添加值
        1.{@link Task}在全屏和浮窗之間發(fā)生切換
        2.{@link TaskFragment}已組織好并且正在更改窗口邊界
        3.{@link ActivityRecord}被重新分配到一個(gè)有組織的{@link TaskFragment}中
        **/
        //這里我們isChangingAppTransition()值為false,即isChanging值為false
        final boolean isChanging = AppTransition.isChangeTransitOld(transit) && enter
                && isChangingAppTransition();

        // Delaying animation start isn't compatible with remote animations at all.
        //mSurfaceAnimator.isAnimationStartDelayed()判斷動(dòng)畫(huà)是否延遲開(kāi)啟,
        //false表示不延遲,true表示延遲,我們這里值為false
        if (controller != null && !mSurfaceAnimator.isAnimationStartDelayed()) {
            // Here we load App XML in order to read com.android.R.styleable#Animation_showBackdrop.
            boolean showBackdrop = false;
            // Optionally set backdrop color if App explicitly provides it through
            // {@link Activity#overridePendingTransition(int, int, int)}.
            @ColorInt int backdropColor = 0;
            //isFromActivityEmbedding(),返回的是RemoteAnimationController中的變量mIsActivityEmbedding
            //我們這里前面通過(guò)getRemoteAnimationController()創(chuàng)建RemoteAnimationController會(huì)對(duì)其賦值為false
            //因此下面流程不進(jìn)行
            if (controller.isFromActivityEmbedding()) {
                ......
            }
            //創(chuàng)建一個(gè)和mTmpRect相同大小和位置的矩陣
            final Rect localBounds = new Rect(mTmpRect);
            localBounds.offsetTo(mTmpPoint.x, mTmpPoint.y);
            final RemoteAnimationController.RemoteAnimationRecord adapters;
            //前面isChanging的值為false,因此!isChanging為true
            //enter 應(yīng)用可見(jiàn)性,啟動(dòng)應(yīng)用的可見(jiàn)性為true,桌面可見(jiàn)性為false
            //這里主要判斷的是isClosingWhenResizing()方法的值,
            //這個(gè)值同樣取決于參數(shù)DisplayContent.mChangingContainers中是否有值
            //這里我們isClosingWhenResizing()值為false
            if (!isChanging && !enter && isClosingWhenResizing()) {
                // Container that is closing while resizing. Pass in the closing start bounds, so
                // the animation can start with the correct bounds, there won't be a snapshot.
                // Cleanup the mClosingChangingContainers so that when the animation is finished, it
                // will reset the surface.
                //調(diào)整大小時(shí)正在關(guān)閉的容器。傳入關(guān)閉的開(kāi)始邊界,這樣動(dòng)畫(huà)就可以從正確的邊界開(kāi)始,不會(huì)有快照。
                //清理mClosingChangingContainers,以便在動(dòng)畫(huà)完成時(shí)重置surface。
                final Rect closingStartBounds = getDisplayContent().mClosingChangingContainers
                        .remove(this);
                adapters = controller.createRemoteAnimationRecord(
                        this, mTmpPoint, localBounds, screenBounds, closingStartBounds,
                        showBackdrop, false /* shouldCreateSnapshot */);
            } else {
                //isChanging為false,所以startBounds為null
                final Rect startBounds = isChanging ? mSurfaceFreezer.mFreezeBounds : null;
                //創(chuàng)建RemoteAnimationRecord,之后創(chuàng)建RemoteAnimationAdapterWrapper
                //RemoteAnimationAdapterWrapper實(shí)現(xiàn)了AnimationAdapter接口
                adapters = controller.createRemoteAnimationRecord(
                        this, mTmpPoint, localBounds, screenBounds, startBounds, showBackdrop);
            }
            if (backdropColor != 0) {
                adapters.setBackDropColor(backdropColor);
            }
            if (!isChanging) {
                //根據(jù)enter的值設(shè)置RemoteAnimationRecord中的mMode的值
                adapters.setMode(enter
                        ? RemoteAnimationTarget.MODE_OPENING
                        : RemoteAnimationTarget.MODE_CLOSING);
            }
            //RemoteAnimationAdapterWrapper會(huì)根據(jù)startBounds變量是否為空進(jìn)行不同的創(chuàng)建方式
            //startBounds變量為空的情況,保存到Pair類的first變量中
            //startBounds變量不為空的情況,保存到Pair類的second變量中
            resultAdapters = new Pair<>(adapters.mAdapter, adapters.mThumbnailAdapter);
        } else if (isChanging) {
            //創(chuàng)建的是LocalAnimationAdapter,非遠(yuǎn)程動(dòng)畫(huà)流程
            ......
        } else {
            //創(chuàng)建的是LocalAnimationAdapter,非遠(yuǎn)程動(dòng)畫(huà)流程
            ......
        }
        return resultAdapters;
    }

通過(guò)創(chuàng)建RemoteAnimationRecord來(lái)創(chuàng)建RemoteAnimationAdapterWrapper

adapters = controller.createRemoteAnimationRecord(
                        this, mTmpPoint, localBounds, screenBounds, startBounds, showBackdrop);

根據(jù)前面設(shè)置的參數(shù)我們可以知道傳遞的值分別為:
this指的是應(yīng)用Task,以及桌面Task;
startBounds為 null ;mTmpPoint為(0,0) ;localBounds為屏幕分辨率的矩形; showBackdrop為false。

代碼路徑:frameworks/base/services/core/java/com/android/server/wm/RemoteAnimationController.java

    /**
     * Creates an animation record for each individual {@link WindowContainer}.
     *
     * @param windowContainer The windows to animate.
     * @param position        The position app bounds relative to its parent.
     * @param localBounds     The bounds of the app relative to its parent.
     * @param endBounds       The end bounds after the transition, in screen coordinates.
     * @param startBounds     The start bounds before the transition, in screen coordinates.
     * @param showBackdrop    To show background behind a window during animation.
     * @return The record representing animation(s) to run on the app.
     */
    RemoteAnimationRecord createRemoteAnimationRecord(WindowContainer windowContainer,
            Point position, Rect localBounds, Rect endBounds, Rect startBounds,
            boolean showBackdrop) {
        return createRemoteAnimationRecord(windowContainer, position, localBounds, endBounds,
                startBounds, showBackdrop, startBounds != null /* shouldCreateSnapshot */);
    }
    
    /**
     * Creates an animation record for each individual {@link WindowContainer}.
     *
     * @param windowContainer The windows to animate.
     * @param position        The position app bounds relative to its parent.
     * @param localBounds     The bounds of the app relative to its parent.
     * @param endBounds       The end bounds after the transition, in screen coordinates.
     * @param startBounds     The start bounds before the transition, in screen coordinates.
     * @param showBackdrop    To show background behind a window during animation.
     * @param shouldCreateSnapshot   Whether this target should create a snapshot animation.
     * @return The record representing animation(s) to run on the app.
     */
    RemoteAnimationRecord createRemoteAnimationRecord(WindowContainer windowContainer,
            Point position, Rect localBounds, Rect endBounds, Rect startBounds,
            boolean showBackdrop, boolean shouldCreateSnapshot) {
        ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "createAnimationAdapter(): container=%s",
                windowContainer);
        final RemoteAnimationRecord adapters = new RemoteAnimationRecord(windowContainer, position,
                localBounds, endBounds, startBounds, showBackdrop, shouldCreateSnapshot);
        //添加RemoteAnimationRecord對(duì)象到mPendingAnimations中
        mPendingAnimations.add(adapters);
        return adapters;
    }

傳遞參數(shù),創(chuàng)建RemoteAnimationRecord,其中shouldCreateSnapshot參數(shù)的值取決于startBounds是否為空,我們這里startBounds為空,所以shouldCreateSnapshot為false。
需要注意的是,這里把創(chuàng)建的RemoteAnimationRecord對(duì)保存到了mPendingAnimations列表中,先添加的是應(yīng)用的RemoteAnimationRecord,第二次添加的是桌面的RemoteAnimationRecord。

/**
     * Contains information about a remote-animation for one WindowContainer. This keeps track of,
     * potentially, multiple animating surfaces (AdapterWrappers) associated with one
     * Window/Transition. For example, a change transition has an adapter controller for the
     * main window and an adapter controlling the start-state snapshot.
     * <p>
     * This can be thought of as a bridge between the information that the remote animator sees (via
     * {@link RemoteAnimationTarget}) and what the server sees (the
     * {@link RemoteAnimationAdapterWrapper}(s) interfacing with the moving surfaces).
     */
    public class RemoteAnimationRecord {
        //RemoteAnimationAdapterWrapper用來(lái)實(shí)現(xiàn)AnimationAdapter接口
        RemoteAnimationAdapterWrapper mAdapter;
        RemoteAnimationAdapterWrapper mThumbnailAdapter = null;
        //RemoteAnimationTarget主要用來(lái)存放動(dòng)畫(huà)圖層
        RemoteAnimationTarget mTarget;
        //mWindowContainer保存當(dāng)前容器
        final WindowContainer mWindowContainer;
        final Rect mStartBounds;
        final boolean mShowBackdrop;
        @ColorInt int mBackdropColor = 0;
        private @RemoteAnimationTarget.Mode int mMode = RemoteAnimationTarget.MODE_CHANGING;
        
        RemoteAnimationRecord(WindowContainer windowContainer, Point endPos, Rect localBounds,
                Rect endBounds, @Nullable Rect startBounds, boolean showBackdrop,
                boolean shouldCreateSnapshot) {
            mWindowContainer = windowContainer;
            mShowBackdrop = showBackdrop;
            if (startBounds != null) {
                ......
            } else {
                mAdapter = new RemoteAnimationAdapterWrapper(this, endPos, localBounds, endBounds,
                        new Rect(), mShowBackdrop);
                mStartBounds = null;
            }
        }
        ......
    }

在RemoteAnimationRecord構(gòu)造方法中創(chuàng)建RemoteAnimationAdapterWrapper。
RemoteAnimationAdapterWrapper會(huì)根據(jù)startBounds變量是否為空進(jìn)行不同的創(chuàng)建方式,我們這里主要關(guān)注其為空的流程。
startBounds為空,走else流程

 mAdapter = new RemoteAnimationAdapterWrapper(this, endPos, localBounds, endBounds,
                        new Rect(), mShowBackdrop);

這里通過(guò)new Rect()空矩陣(上下左右四點(diǎn)均為0),創(chuàng)建了一個(gè)startBounds

    class RemoteAnimationAdapterWrapper implements AnimationAdapter {
        ......

        RemoteAnimationAdapterWrapper(RemoteAnimationRecord record, Point position,
                Rect localBounds, Rect endBounds, Rect startBounds, boolean showBackdrop) {
            mRecord = record;
            mPosition.set(position.x, position.y);
            mLocalBounds = localBounds;
            mEndBounds.set(endBounds);
            mStartBounds.set(startBounds);
            mShowBackdrop = showBackdrop;
        }
        ......

把傳遞的參數(shù)賦值給了RemoteAnimationAdapterWrapper的成員變量。
這里我們的RemoteAnimationAdapterWrapper實(shí)現(xiàn)了AnimationAdapter接口。

通過(guò)startAnimation方法創(chuàng)建動(dòng)畫(huà)圖層

            animationRunnerBuilder.build()
                    .startAnimation(getPendingTransaction(), adapter, !isVisible(),
                            ANIMATION_TYPE_APP_TRANSITION, thumbnailAdapter);

getPendingTransaction():指的是一個(gè)事務(wù)。
adapter:是前面賦值AnimationAdapter adapter = adapters.first;,即創(chuàng)建的startBounds變量為空情況的RemoteAnimationAdapterWrapper對(duì)象。
!isVisible():獲取當(dāng)前可見(jiàn)性后取反。應(yīng)用當(dāng)前可見(jiàn)性為false,即傳遞true;桌面當(dāng)前可見(jiàn)性為true,即傳遞false。
ANIMATION_TYPE_APP_TRANSITION:過(guò)渡動(dòng)畫(huà)類型。
thumbnailAdapter:是前面賦值AnimationAdapter thumbnailAdapter = adapters.second;,即創(chuàng)建的startBounds變量不為空情況的RemoteAnimationAdapterWrapper對(duì)象。

animationRunnerBuilder是AnimationRunnerBuilder對(duì)象,調(diào)用了其build方法中的startAnimation方法。我們這里調(diào)用的startAnimation方法是一個(gè)函數(shù)式接口。

    private interface IAnimationStarter {
        void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
                            @AnimationType int type, @Nullable AnimationAdapter snapshotAnim);
    }

startAnimation方法的實(shí)現(xiàn)在AnimationRunnerBuilder中的build方法中return的 (Transaction t, AnimationAdapter adapter, boolean hidden, AnimationType int type, @Nullable AnimationAdapter snapshotAnim) -> {......}。

    private class AnimationRunnerBuilder {
        /**
         * Runs when the surface stops animating
         */
        private final List<Runnable> mOnAnimationFinished = new LinkedList<>();
        /**
         * Runs when the animation is cancelled but the surface is still animating
         */
        private final List<Runnable> mOnAnimationCancelled = new LinkedList<>();
        ......
        private IAnimationStarter build() {
            return (Transaction t, AnimationAdapter adapter, boolean hidden,
                    @AnimationType int type, @Nullable AnimationAdapter snapshotAnim) -> {
                startAnimation(getPendingTransaction(), adapter, !isVisible(), type,
                        (animType, anim) -> mOnAnimationFinished.forEach(Runnable::run),
                        () -> mOnAnimationCancelled.forEach(Runnable::run), snapshotAnim);
            };
        }
    }

除了傳遞之前的參數(shù)之外,在return的(Transaction t, AnimationAdapter adapter, boolean hidden, AnimationType int type, @Nullable AnimationAdapter snapshotAnim) -> {......}中調(diào)用了startAnimation方法,傳遞了回調(diào)函數(shù)(animType, anim) -> mOnAnimationFinished.forEach(Runnable::run)() -> mOnAnimationCancelled.forEach(Runnable::run),會(huì)執(zhí)行mOnAnimationFinished和mOnAnimationCancelled這兩個(gè)變量中的Runnable。

繼續(xù)查看startAnimation方法

    /**
     * Starts an animation on the container.
     *
     * @param anim                       The animation to run.
     * @param hidden                     Whether our container is currently hidden. TODO This should use isVisible at
     *                                   some point but the meaning is too weird to work for all containers.
     * @param type                       The type of animation defined as {@link AnimationType}.
     * @param animationFinishedCallback  The callback being triggered when the animation finishes.
     * @param animationCancelledCallback The callback is triggered after the SurfaceAnimator sends a
     *                                   cancel call to the underlying AnimationAdapter.
     * @param snapshotAnim               The animation to run for the snapshot. {@code null} if there is no
     *                                   snapshot.
     */
    void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
                        @AnimationType int type,
                        @Nullable OnAnimationFinishedCallback animationFinishedCallback,
                        @Nullable Runnable animationCancelledCallback,
                        @Nullable AnimationAdapter snapshotAnim) {
        ProtoLog.v(WM_DEBUG_ANIM, "Starting animation on %s: type=%d, anim=%s",
                this, type, 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,
                animationCancelledCallback, snapshotAnim, mSurfaceFreezer);
    }
  • 入?yún)⒑x
    t:這是一個(gè)對(duì)象,用于描述一系列的窗口操作,例如移動(dòng)、調(diào)整大小、繪制等。這些操作在WMS中排隊(duì),并在適當(dāng)?shù)臅r(shí)機(jī)應(yīng)用到窗口上。
    anim:這是對(duì)動(dòng)畫(huà)進(jìn)行封裝的類。它包含了一些關(guān)于如何開(kāi)始、更新和結(jié)束動(dòng)畫(huà)的信息。傳遞的也就是前面WindowContainer.getAnimationAdapter中創(chuàng)建startBounds變量為空情況的RemoteAnimationAdapterWrapper對(duì)象。
    hidden:這個(gè)布爾值表示窗口是否隱藏。如果窗口是隱藏的,那么就不會(huì)顯示動(dòng)畫(huà)。前面?zhèn)鬟f的!isVisible()值為false。
    type:這個(gè)整數(shù)代表了動(dòng)畫(huà)的類型。這里我們傳遞的是ANIMATION_TYPE_APP_TRANSITION,即圖層上顯示的app_transition。
    animationFinishedCallbackanimationCancelledCallback:這兩個(gè)是回調(diào)函數(shù),分別在動(dòng)畫(huà)完成和動(dòng)畫(huà)取消時(shí)被調(diào)用。
    snapshotAnim:這個(gè)參數(shù)是給定動(dòng)畫(huà)的快照。如果參數(shù)為null,那么就表示沒(méi)有快照。傳遞過(guò)來(lái)的是變量thumbnailAdapter,即startBounds變量不為空情況的RemoteAnimationAdapterWrapper對(duì)象。

  • 代碼含義
    關(guān)鍵的代碼只有這一句mSurfaceAnimator.startAnimation(t, anim, hidden, type, animationFinishedCallback, animationCancelledCallback, snapshotAnim, mSurfaceFreezer);
    這行代碼調(diào)用了SurfaceAnimator的startAnimation方法來(lái)啟動(dòng)動(dòng)畫(huà)。SurfaceAnimator的作用主要是控制窗口動(dòng)畫(huà),它是窗口動(dòng)畫(huà)的中控,通過(guò)操控mLeash對(duì)象來(lái)實(shí)現(xiàn)窗口的大小、位置、透明度等動(dòng)畫(huà)屬性的改變。這個(gè)方法需要一系列參數(shù),包括上面解釋的所有參數(shù),還有一個(gè)SurfaceFreezer對(duì)象mSurfaceFreezer,它可以在動(dòng)畫(huà)開(kāi)始時(shí)凍結(jié)窗口的更新,以防止在動(dòng)畫(huà)過(guò)程中窗口的內(nèi)容閃爍。
    mSurfaceAnimator和mSurfaceFreezer是在WindowContainer的構(gòu)造方法中初始化的

    class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<E>
        implements Comparable<WindowContainer>, Animatable, SurfaceFreezer.Freezable,
        InsetsControlTarget {
        ......
    	WindowContainer(WindowManagerService wms) {
    	     mWmService = wms;
    	     mTransitionController = mWmService.mAtmService.getTransitionController();
    	     mPendingTransaction = wms.mTransactionFactory.get();
    	     mSyncTransaction = wms.mTransactionFactory.get();
    	     mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished, wms);
    	     mSurfaceFreezer = new SurfaceFreezer(this, wms);
    	 }
    	 ......
    }
    

通過(guò)SurfaceAnimator中創(chuàng)建leash

代碼路徑:frameworks/base/services/core/java/com/android/server/wm/SurfaceAnimator.java

    /**
     * Starts an animation.
     *
     * @param anim The object that bridges the controller, {@link SurfaceAnimator}, with the
     *             component responsible for running the animation. It runs the animation with
     *             {@link AnimationAdapter#startAnimation} once the hierarchy with
     *             the Leash has been set up.
     * @param hidden Whether the container holding the child surfaces is currently visible or not.
     *               This is important as it will start with the leash hidden or visible before
     *               handing it to the component that is responsible to run the animation.
     * @param animationFinishedCallback The callback being triggered when the animation finishes.
     * @param animationCancelledCallback The callback is triggered after the SurfaceAnimator sends a
     *                                   cancel call to the underlying AnimationAdapter.
     * @param snapshotAnim The animation to run for the snapshot. {@code null} if there is no
     *                     snapshot.
     */
    void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
            @AnimationType int type,
            @Nullable OnAnimationFinishedCallback animationFinishedCallback,
            @Nullable Runnable animationCancelledCallback,
            @Nullable AnimationAdapter snapshotAnim, @Nullable SurfaceFreezer freezer) {
        //開(kāi)始新的動(dòng)畫(huà)之前,取消之前的動(dòng)畫(huà)
        //參數(shù)含義:t(是一個(gè)事務(wù)對(duì)象),true(表示動(dòng)畫(huà)正在重新啟動(dòng)),和true(表示向前取消)
        cancelAnimation(t, true /* restarting */, true /* forwardCancel */);
        //初始化參數(shù),把WindowContainer.startAnimation中傳遞的參數(shù)賦值給對(duì)應(yīng)變量
        mAnimation = anim;
        mAnimationType = type;
        mSurfaceAnimationFinishedCallback = animationFinishedCallback;
        mAnimationCancelledCallback = animationCancelledCallback;
        //獲取當(dāng)前窗口的SurfaceControl
        final SurfaceControl surface = mAnimatable.getSurfaceControl();
        //沒(méi)有surface,則取消當(dāng)前的動(dòng)畫(huà)
        if (surface == null) {
            Slog.w(TAG, "Unable to start animation, surface is null or no children.");
            cancelAnimation();
            return;
        }
        //調(diào)用SurfaceFreezer中takeLeashForAnimation()獲取mLeash,但是SurfaceFreezer中沒(méi)有被初始化,所以這里的mLeash還是為null
        mLeash = freezer != null ? freezer.takeLeashForAnimation() : null;
        if (mLeash == null) {
        	//創(chuàng)建mLeash
            mLeash = createAnimationLeash(mAnimatable, surface, t, type,
                    mAnimatable.getSurfaceWidth(), mAnimatable.getSurfaceHeight(), 0 /* x */,
                    0 /* y */, hidden, mService.mTransactionFactory);
            //創(chuàng)建動(dòng)畫(huà)“l(fā)eash”后執(zhí)行的一些操作,包括重置圖層、重新分配圖層以及重置Surface的位置
            mAnimatable.onAnimationLeashCreated(t, mLeash);
        }
        //處理動(dòng)畫(huà)開(kāi)始時(shí)進(jìn)行一些設(shè)置和準(zhǔn)備工作
        mAnimatable.onLeashAnimationStarting(t, mLeash);
        if (mAnimationStartDelayed) {
            ProtoLog.i(WM_DEBUG_ANIM, "Animation start delayed for %s", mAnimatable);
            return;
        }
        //將leash傳給AnimationAdapter
        mAnimation.startAnimation(mLeash, t, type, mInnerAnimationFinishedCallback);
        if (ProtoLogImpl.isEnabled(WM_DEBUG_ANIM)) {
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            mAnimation.dump(pw, "");
            ProtoLog.d(WM_DEBUG_ANIM, "Animation start for %s, anim=%s", mAnimatable, sw);
        }
        //獲取一個(gè)快照,并使用該快照來(lái)執(zhí)行動(dòng)畫(huà),我們這里snapshotAnim為null,因此不涉及
        if (snapshotAnim != null) {
            mSnapshot = freezer.takeSnapshotForAnimation();
            if (mSnapshot == null) {
                Slog.e(TAG, "No snapshot target to start animation on for " + mAnimatable);
                return;
            }
            mSnapshot.startAnimation(t, snapshotAnim, type);
        }
    }

入?yún)⒕褪乔懊鎃indowContainer.startAnimation中傳遞的參數(shù)。

獲取當(dāng)前窗口的surface

final SurfaceControl surface = mAnimatable.getSurfaceControl();
mAnimatable是Animatable接口的對(duì)象,WindowContainer實(shí)現(xiàn)了Animatable接口。
在WindowContainer構(gòu)造方法中初始化mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished, wms);
而SurfaceAnimator的構(gòu)造方法是

    SurfaceAnimator(Animatable animatable,
            @Nullable OnAnimationFinishedCallback staticAnimationFinishedCallback,
            WindowManagerService service) {
        mAnimatable = animatable;
        mService = service;
        mStaticAnimationFinishedCallback = staticAnimationFinishedCallback;
        mInnerAnimationFinishedCallback = getFinishedCallback(staticAnimationFinishedCallback);
    }

也就是說(shuō)實(shí)際上是把this賦值給了mAnimatable,因此mAnimatable就代表了當(dāng)前的窗口。

從前面的代碼可以看出遠(yuǎn)程動(dòng)畫(huà)涉及到打開(kāi)的應(yīng)用和關(guān)閉的應(yīng)用,這兩個(gè)應(yīng)用的動(dòng)畫(huà)。

        applyAnimations(openingWcs, openingApps, transit, true /* visible */, animLp,
                voiceInteraction);
        applyAnimations(closingWcs, closingApps, transit, false /* visible */, animLp,
                voiceInteraction);

即我們這里第一次獲取當(dāng)前窗口mAnimatable時(shí),代表的是正在打開(kāi)的應(yīng)用,即應(yīng)用Task;第二次獲取的則是桌面,即桌面Task。

獲取Leash

mLeash = freezer != null ? freezer.takeLeashForAnimation() : null;
根據(jù)freezer是否為null來(lái)確定mLeash的值,我們這里freezer是從WindowContainer.startAnimation方法中傳遞過(guò)來(lái)的mSurfaceFreezer,這個(gè)變量在WindowContainer的構(gòu)造方法中初始化mSurfaceFreezer = new SurfaceFreezer(this, wms);,因此mSurfaceFreezer不為null,即freezer不為null,freezer != null true,所以走freezer.takeLeashForAnimation()
代碼路徑:frameworks/base/services/core/java/com/android/server/wm/SurfaceFreezer.java

	SurfaceControl mLeash;
    /**
     * Used by {@link SurfaceAnimator}. This "transfers" the leash to be used for animation.
     * By transferring the leash, this will no longer try to clean-up the leash when finished.
     */
    SurfaceControl takeLeashForAnimation() {
        SurfaceControl out = mLeash;
        mLeash = null;
        return out;
    }

mLeash在SurfaceFreezer類中并沒(méi)有初始化,因此我們的mLeash值為null,所以out的值同樣為null,最終SurfaceAnimator類中的mLeash獲取到的值為null

創(chuàng)建Leash

mLeash為null,使用createAnimationLeash方法創(chuàng)建Leash

            mLeash = createAnimationLeash(mAnimatable, surface, t, type,
                    mAnimatable.getSurfaceWidth(), mAnimatable.getSurfaceHeight(), 0 /* x */,
                    0 /* y */, hidden, mService.mTransactionFactory);

入?yún)⒑x
mAnimatable:當(dāng)前窗口。
surface:當(dāng)前窗口的surface。
t:一個(gè)事務(wù)對(duì)象,用于執(zhí)行一系列操作。
type:動(dòng)畫(huà)類型。
mAnimatable.getSurfaceWidth()mAnimatable.getSurfaceHeight():窗口surface尺寸的參數(shù)。
0 /* x */0 /* y */:坐標(biāo)位置
hidden:一個(gè)布爾值,表示是否隱藏。
mService.mTransactionFactory:一個(gè)事務(wù)工廠對(duì)象,用于創(chuàng)建新的事務(wù)。

SurfaceAnimator.createAnimationLeash()
代碼路徑:frameworks/base/services/core/java/com/android/server/wm/SurfaceAnimator.java

    static SurfaceControl createAnimationLeash(Animatable animatable, SurfaceControl surface,
            Transaction t, @AnimationType int type, int width, int height, int x, int y,
            boolean hidden, Supplier<Transaction> transactionFactory) {
        /* log add start*/
        Slog.i("WindowManager:","createAnimationLeash type = " + animationTypeToString(type) , new Exception());
        /* log add end*/
        ProtoLog.i(WM_DEBUG_ANIM, "Reparenting to leash for %s", animatable);
        //通過(guò)SurfaceControl.Builder創(chuàng)建leash
        final SurfaceControl.Builder builder = animatable.makeAnimationLeash()
                .setParent(animatable.getAnimationLeashParent())
                .setName(surface + " - animation-leash of " + animationTypeToString(type))
                // TODO(b/151665759) Defer reparent calls
                // We want the leash to be visible immediately because the transaction which shows
                // the leash may be deferred but the reparent will not. This will cause the leashed
                // surface to be invisible until the deferred transaction is applied. If this
                // doesn't work, you will can see the 2/3 button nav bar flicker during seamless
                // rotation.
                .setHidden(hidden)
                .setEffectLayer()
                .setCallsite("SurfaceAnimator.createAnimationLeash");
        //通過(guò)前面的SurfaceControl.Builder創(chuàng)建leash
        final SurfaceControl leash = builder.build();
        //其他屬性設(shè)置
        t.setWindowCrop(leash, width, height);
        t.setPosition(leash, x, y);
        t.show(leash);
        t.setAlpha(leash, hidden ? 0 : 1);
        //當(dāng)前窗口的surface重新綁定到新創(chuàng)建的leash上
        t.reparent(surface, leash);
        return leash;
    }

傳遞當(dāng)前窗口animatable,為其和其父節(jié)點(diǎn)之間添加surface。第一次創(chuàng)建的是正在打開(kāi)的應(yīng)用的動(dòng)畫(huà),第二次是桌面關(guān)閉時(shí)的動(dòng)畫(huà)。

下面我們解讀一下,leash是如何創(chuàng)建并加入其中的

通過(guò)SurfaceControl.Builder創(chuàng)建leash
  • animatable.makeAnimationLeash()
    代碼路徑: frameworks/base/services/core/java/com/android/server/wm/WindowContainer.java

        public Builder makeAnimationLeash() {
            return makeSurface().setContainerLayer();
        }
    

    創(chuàng)建一個(gè)圖層作為容器layer

  • setParent(animatable.getAnimationLeashParent())
    這段代碼我們分成兩個(gè)部分來(lái)看,即setParent()getAnimationLeashParent()
    1.setParent()
    代碼路徑:frameworks/base/core/java/android/view/SurfaceControl.java

            /**
             * Set a parent surface for our new SurfaceControl.
             *
             * Child surfaces are constrained to the onscreen region of their parent.
             * Furthermore they stack relatively in Z order, and inherit the transformation
             * of the parent.
             *
             * @param parent The parent control.
             */
            @NonNull
            public Builder setParent(@Nullable SurfaceControl parent) {
                mParent = parent;
                return this;
            }
    

    這個(gè)段代碼很簡(jiǎn)單,就是給當(dāng)前SurfaceControl設(shè)置一個(gè)父SurfaceControl。
    2.getAnimationLeashParent()
    代碼路徑: frameworks/base/services/core/java/com/android/server/wm/WindowContainer.java

        @Override
        public SurfaceControl getAnimationLeashParent() {
            return getParentSurfaceControl();
        }
        
        /*
         * @return The SurfaceControl parent for this containers SurfaceControl.
         *         The SurfaceControl must be valid if non-null.
         */
        @Override
        public SurfaceControl getParentSurfaceControl() {
            final WindowContainer parent = getParent();
            if (parent == null) {
                return null;
            }
            return parent.getSurfaceControl();
        }
    
        /**
         * @return The SurfaceControl for this container.
         * The SurfaceControl must be valid if non-null.
         */
        @Override
        public SurfaceControl getSurfaceControl() {
            return mSurfaceControl;
        }
    

    簡(jiǎn)單來(lái)說(shuō),就是獲取當(dāng)前窗口父SurfaceControl。

    那么合起來(lái)setParent(animatable.getAnimationLeashParent())的意思就是,把當(dāng)前新創(chuàng)建的SurfaceControl(leash)的父親設(shè)置為當(dāng)前窗口父親的SurfaceControl。
    即此時(shí)leash圖層和當(dāng)前窗口應(yīng)用Task的父親均是DefaultTaskDsiplayArea,兩人還在當(dāng)兄弟。
    簡(jiǎn)圖如下:
    mchangingcontainers,Android Framework從入門到入土,Android 窗口動(dòng)畫(huà),Android 窗口相關(guān),android
    此時(shí)創(chuàng)建的是應(yīng)用Task的動(dòng)畫(huà),桌面Task的動(dòng)畫(huà)尚未創(chuàng)建,待應(yīng)用Task動(dòng)畫(huà)創(chuàng)建完成后,才會(huì)去走正在關(guān)閉的應(yīng)用(桌面)的動(dòng)畫(huà)邏輯。
    桌面Task是一直掛在DefaultTaskDsiplayArea上的,這里我們先不關(guān)注桌面Task節(jié)點(diǎn)。

  • setEffectLayer()
    代碼路徑:frameworks/base/core/java/android/view/SurfaceControl.java

            /**
             * Indicate whether an 'EffectLayer' is to be constructed.
             *
             * An effect layer behaves like a container layer by default but it can support
             * color fill, shadows and/or blur. These layers will not have an associated buffer.
             * When created, this layer has no effects set and will be transparent but the caller
             * can render an effect by calling:
             *  - {@link Transaction#setColor(SurfaceControl, float[])}
             *  - {@link Transaction#setBackgroundBlurRadius(SurfaceControl, int)}
             *  - {@link Transaction#setShadowRadius(SurfaceControl, float)}
             *
             * @hide
             */
            public Builder setEffectLayer() {
                mFlags |= NO_COLOR_FILL;
                //清空緩沖區(qū)設(shè)置
                unsetBufferSize();
                return setFlags(FX_SURFACE_EFFECT, FX_SURFACE_MASK);
            }
    

    設(shè)置為EffectLayer。它是一種特殊類型的SurfaceControl層,它默認(rèn)表現(xiàn)得像一個(gè)容器層,但可以支持顏色填充、陰影和/或模糊效果。
    這個(gè)EffectLayer主要就是用于實(shí)現(xiàn)一些視覺(jué)效果。
    默認(rèn)的注釋里面也說(shuō)明可以使用這些方法來(lái)渲染一個(gè)效果:
    Transaction#setColor(SurfaceControl, float[]):使用給定的顏色數(shù)組設(shè)置該層的顏色。
    Transaction#setBackgroundBlurRadius(SurfaceControl, int):設(shè)置背景模糊的半徑。
    Transaction#setShadowRadius(SurfaceControl, float):設(shè)置陰影的半徑。

final SurfaceControl leash = builder.build();
最后通過(guò)build()方法創(chuàng)建leash

當(dāng)前窗口的surface重新綁定到新創(chuàng)建的leash上

t.reparent(surface, leash);
這里的surface指的就是從前面?zhèn)鬟f的當(dāng)前窗口的SurfaceControl。
代碼路徑:frameworks/base/core/java/android/view/SurfaceControl.java

        /**
         * Re-parents a given layer to a new parent. Children inherit transform (position, scaling)
         * crop, visibility, and Z-ordering from their parents, as if the children were pixels within the
         * parent Surface.
         *
         * @param sc The SurfaceControl to reparent
         * @param newParent The new parent for the given control.
         * @return This Transaction
         */
        @NonNull
        public Transaction reparent(@NonNull SurfaceControl sc,
                @Nullable SurfaceControl newParent) {
            //檢查傳入的SurfaceControl對(duì)象是否滿足某些預(yù)設(shè)條件
            checkPreconditions(sc);
            long otherObject = 0;
            if (newParent != null) {
            	//檢查新父對(duì)象是否被釋放。如果已經(jīng)被釋放,那么它會(huì)拋出異常。
                newParent.checkNotReleased();
                //新父對(duì)象不為null且未被釋放,那么將新父對(duì)象的Native對(duì)象賦值給otherObject。
                otherObject = newParent.mNativeObject;
            }
            //傳入了三個(gè)參數(shù):1.當(dāng)前對(duì)象的Native對(duì)象 2.被重新設(shè)置父對(duì)象的SurfaceControl的Native對(duì)象 3.新父對(duì)象的Native對(duì)象。
            //用于實(shí)現(xiàn)重新設(shè)置父對(duì)象的具體操作。
            nativeReparent(mNativeObject, sc.mNativeObject, otherObject);
            //把被重新設(shè)置父對(duì)象的SurfaceControl和新父對(duì)象存儲(chǔ)到mReparentedSurfaces這個(gè)map中。
            mReparentedSurfaces.put(sc, newParent);
            return this;
        }

@NonNull SurfaceControl sc: 表示要被重新設(shè)置父對(duì)象的SurfaceControl對(duì)象。這個(gè)參數(shù)不能為null。
@Nullable SurfaceControl newParent: 表示新的父SurfaceControl對(duì)象。可以為null,表示沒(méi)有新的父對(duì)象。
這個(gè)方法主要就是把當(dāng)前窗口的SurfaceControl的父親,修改為leash
mReparentedSurfaces是ArrayMap對(duì)象,以鍵值對(duì)的形式臨時(shí)存儲(chǔ)父子關(guān)系,key值存儲(chǔ)SurfaceControl對(duì)象,value為其父SurfaceControl對(duì)象。

即此時(shí)leash圖層變成了當(dāng)前窗口應(yīng)用Task圖層的父親,如簡(jiǎn)易圖所示:
曾經(jīng)我們是兄弟,如今我是你爸爸~
mchangingcontainers,Android Framework從入門到入土,Android 窗口動(dòng)畫(huà),Android 窗口相關(guān),android

需要注意的是,Task和DefaultTaskDsiplayArea容器之前的關(guān)系并未改變,創(chuàng)建leash圖層的過(guò)程只是改變的是surface之間的關(guān)系。
即leash圖層是DefaultTaskDsiplayArea圖層的父親,Task的圖層是leash圖層的父親,但是Task的父親仍然是DefaultTaskDsiplayArea。
實(shí)際關(guān)系情況如下圖所示:
mchangingcontainers,Android Framework從入門到入土,Android 窗口動(dòng)畫(huà),Android 窗口相關(guān),android

所以DefaultTaskDsiplayArea和leash實(shí)際上是表面父子,leash和Task也是表面父子

leash的surface調(diào)整

mAnimatable.onAnimationLeashCreated(t, mLeash);
入?yún)⑹且粋€(gè)事務(wù)(用于操作窗口系統(tǒng)的底層API)和一個(gè)SurfaceControl對(duì)象(表示一個(gè)可以控制和操作Surface的接口)
把創(chuàng)建好的mLeash傳遞到onAnimationLeashCreated方法中,做一些Surface調(diào)整操作。
該方法實(shí)現(xiàn)在WindowContainer中。
代碼路徑:frameworks/base/services/core/java/com/android/server/wm/WindowContainer.java

    void reassignLayer(Transaction t) {
        final WindowContainer parent = getParent();
        if (parent != null) {
            parent.assignChildLayers(t);
        }
    }
    
    void resetSurfacePositionForAnimationLeash(Transaction t) {
        t.setPosition(mSurfaceControl, 0, 0);
        final SurfaceControl.Transaction syncTransaction = getSyncTransaction();
        if (t != syncTransaction) {
            // Avoid restoring to old position if the sync transaction is applied later.
            syncTransaction.setPosition(mSurfaceControl, 0, 0);
        }
        mLastSurfacePosition.set(0, 0);
    }

    @Override
    public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) {
        mLastLayer = -1;
        mAnimationLeash = leash;
        reassignLayer(t);

        // Leash is now responsible for position, so set our position to 0.
        resetSurfacePositionForAnimationLeash(t);
    }

這段代碼主要用于在創(chuàng)建新的leash時(shí),重置動(dòng)畫(huà)目標(biāo)的位置,并初始化一些動(dòng)畫(huà)相關(guān)的狀態(tài)。同時(shí),可能還用于重新分配或者設(shè)置子容器的圖層。
首先,在新的動(dòng)畫(huà)(leash)被創(chuàng)建時(shí)被調(diào)用。在這個(gè)方法中,首先將mLastLayer(可能表示上一個(gè)圖層或者上一個(gè)動(dòng)畫(huà)目標(biāo))設(shè)置為-1,然后保存?zhèn)魅氲?code>leash到mAnimationLeash(后面removeLeash流程中會(huì)用到mAnimationLeash)。
之后,調(diào)用reassignLayer(t)方法,這個(gè)方法獲取這個(gè)視圖的父容器,如果父容器存在,那么就調(diào)用父容器的assignChildLayers(t)方法(用于調(diào)整其所有child的z-order)。
最后,為了確保leash現(xiàn)在位置的控制,調(diào)用resetSurfacePositionForAnimationLeash(t)方法將Surface的位置重置為(0,0),重置界面元素的位置以便進(jìn)行動(dòng)畫(huà)。
注:Z-order也被稱為深度順序(depth order)或Z軸順序,它用于確定圖層(Layers)在屏幕上的堆疊順序。簡(jiǎn)單來(lái)說(shuō),Z-order就是圖層在Z軸上的位置,Z軸位置越低,圖層越在底層,Z軸位置越高,圖層越在頂層。

處理動(dòng)畫(huà)開(kāi)始時(shí)進(jìn)行一些設(shè)置和準(zhǔn)備工作

mAnimatable.onLeashAnimationStarting(t, mLeash);
入?yún)⑼瑯邮且粋€(gè)事務(wù)(用于操作窗口系統(tǒng)的底層API)和一個(gè)SurfaceControl對(duì)象(表示一個(gè)可以控制和操作Surface的接口)
onLeashAnimationStarting方法是在ActivityRecord中實(shí)現(xiàn)的。
代碼路徑:frameworks/base/services/core/java/com/android/server/wm/ActivityRecord.java

    @Override
    public void onLeashAnimationStarting(Transaction t, SurfaceControl leash) {
        if (mAnimatingActivityRegistry != null) {
        	//1.將正在啟動(dòng)或者有動(dòng)畫(huà)效果的Activity添加到列表中,以便于管理和控制這些Activity的動(dòng)畫(huà)效果。
            mAnimatingActivityRegistry.notifyStarting(this);
        }

        // If the animation needs to be cropped then an animation bounds layer is created as a
        // child of the root pinned task or animation layer. The leash is then reparented to this
        // new layer.
        //2.否需要?jiǎng)?chuàng)建一個(gè)動(dòng)畫(huà)邊界層
        if (mNeedsAnimationBoundsLayer) {
        	//設(shè)置臨時(shí)矩形為空
            mTmpRect.setEmpty();
            //調(diào)用方法檢查當(dāng)前的活動(dòng)轉(zhuǎn)移是否在任務(wù)內(nèi)部。
            //如果是,則獲取任務(wù)的邊界到臨時(shí)矩形mTmpRect。如果不是,則獲取RootTask的邊界。
            if (getDisplayContent().mAppTransitionController.isTransitWithinTask(
                    getTransit(), task)) {
                task.getBounds(mTmpRect);
            } else {
                final Task rootTask = getRootTask();
                if (rootTask == null) {
                    return;
                }
                // Set clip rect to root task bounds.
                rootTask.getBounds(mTmpRect);
            }
            //創(chuàng)建動(dòng)畫(huà)邊界層
            mAnimationBoundsLayer = createAnimationBoundsLayer(t);

            // Crop to root task bounds.
            //設(shè)置leash的層為0
            //leash將被放置在Z軸的最底層,如果有其他層級(jí)的SurfaceControl對(duì)象,它們將會(huì)覆蓋在leash之上。
            t.setLayer(leash, 0);
            //并設(shè)置AnimationBoundsLayer的層為上一個(gè)層的值,保證leash在AnimationBoundsLayer下面
            t.setLayer(mAnimationBoundsLayer, getLastLayer());

            // Reparent leash to animation bounds layer.
            //重新將leash的父節(jié)點(diǎn)設(shè)置為動(dòng)畫(huà)邊界層。
            t.reparent(leash, mAnimationBoundsLayer);
        }
    }

    private SurfaceControl createAnimationBoundsLayer(Transaction t) {
        ProtoLog.i(WM_DEBUG_APP_TRANSITIONS_ANIM, "Creating animation bounds layer");
        final SurfaceControl.Builder builder = makeAnimationLeash()
        		//給AnimationBoundsLayer設(shè)置父節(jié)點(diǎn)為L(zhǎng)eash的父節(jié)點(diǎn)
        		//即把動(dòng)畫(huà)邊界層的父節(jié)點(diǎn)設(shè)置為DefaultTaskDsiplayArea
                .setParent(getAnimationLeashParent())
                .setName(getSurfaceControl() + " - animation-bounds")
                .setCallsite("ActivityRecord.createAnimationBoundsLayer");
        final SurfaceControl boundsLayer = builder.build();
        t.show(boundsLayer);
        return boundsLayer;
    }

這個(gè)方法其實(shí)主要就是做了兩件事:
1.根據(jù)mAnimatingActivityRegistry的值判斷,是否需要把有動(dòng)畫(huà)效果的Activity添加到列表中
2.根據(jù)mNeedsAnimationBoundsLayer的值判斷,否需要?jiǎng)?chuàng)建一個(gè)動(dòng)畫(huà)邊界層

createAnimationBoundsLayer就是創(chuàng)建了一個(gè)SurfaceControl。
getLastLayer()用于返回當(dāng)前窗口的最高(或最后)層級(jí)。假設(shè)我們有一個(gè)窗口管理系統(tǒng)中,窗口的層級(jí)從0開(kāi)始編號(hào)。當(dāng)一個(gè)新窗口創(chuàng)建時(shí),它可能被賦予層級(jí)0。然后,如果這個(gè)新窗口被另一個(gè)窗口覆蓋,那么新窗口的層級(jí)可能會(huì)更新為1,依此類推。
通過(guò)使用AnimationBoundsLayer,可以定義一個(gè)矩形區(qū)域,該區(qū)域可以作為動(dòng)畫(huà)的邊界。當(dāng)動(dòng)畫(huà)開(kāi)始時(shí),它只在該定義的區(qū)域內(nèi)顯示,不會(huì)超出這個(gè)邊界。AnimationBoundsLayer的主要作用是限制動(dòng)畫(huà)的顯示區(qū)域,以確保動(dòng)畫(huà)不會(huì)影響到應(yīng)用程序的其他部分。

將leash傳給RemoteAnimationAdapterWrapper

mAnimation.startAnimation(mLeash, t, type, mInnerAnimationFinishedCallback);
mAnimation是AnimationAdapter接口的對(duì)象,調(diào)用其startAnimation方法,傳遞mLeash(動(dòng)畫(huà))、t(事務(wù))、type(動(dòng)畫(huà)類型)和mInnerAnimationFinishedCallback(回調(diào)函數(shù))。
mAnimation的值是前面WindowContainer.startAnimation傳遞的anim,這個(gè)anim實(shí)際上就是傳遞的也就是前面WindowContainer.getAnimationAdapter中創(chuàng)建startBounds變量為空情況的RemoteAnimationAdapterWrapper對(duì)象。因此這里調(diào)用接口AnimationAdapter的方法startAnimation正是在RemoteAnimationAdapterWrapper中實(shí)現(xiàn)的。
代碼路徑:frameworks/base/services/core/java/com/android/server/wm/RemoteAnimationController.java

 class RemoteAnimationAdapterWrapper implements AnimationAdapter {
        private final RemoteAnimationRecord mRecord;
        SurfaceControl mCapturedLeash;
        private OnAnimationFinishedCallback mCapturedFinishCallback;
        private @AnimationType int mAnimationType;
        
        ......
        
        @Override
        public void startAnimation(SurfaceControl animationLeash, Transaction t,
                @AnimationType int type, @NonNull OnAnimationFinishedCallback finishCallback) {
            ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "startAnimation");

            //設(shè)置動(dòng)畫(huà)的起始位置和窗口裁剪區(qū)域
            if (mStartBounds.isEmpty()) {
                // Restore position and stack crop until client has a chance to modify it.
                t.setPosition(animationLeash, mPosition.x, mPosition.y);
                t.setWindowCrop(animationLeash, mEndBounds.width(), mEndBounds.height());
            } else {
                // Offset the change animation leash to the relative start position in parent.
                // (mPosition) is the relative end position in parent container.
                // (mStartBounds - mEndBounds) is the position difference between start and end.
                // (mPosition + mStartBounds - mEndBounds) will be the relative start position.
                t.setPosition(animationLeash, mPosition.x + mStartBounds.left - mEndBounds.left,
                        mPosition.y + mStartBounds.top - mEndBounds.top);
                t.setWindowCrop(animationLeash, mStartBounds.width(), mStartBounds.height());
            }
            //保存動(dòng)畫(huà)圖層到mCapturedLeash
            mCapturedLeash = animationLeash;
            //當(dāng)動(dòng)畫(huà)完成時(shí)的回調(diào)函數(shù) finishCallback保存到mCapturedFinishCallback。
            mCapturedFinishCallback = finishCallback;
            //保存動(dòng)畫(huà)類型
            mAnimationType = type;
        }
        ......
    }

此時(shí)動(dòng)畫(huà)圖層到mCapturedLeash;

動(dòng)畫(huà)完成時(shí)的回調(diào)函數(shù)保存到mCapturedFinishCallbackmCapturedFinishCallback是前面?zhèn)鬟f的mInnerAnimationFinishedCallback,而mInnerAnimationFinishedCallback在SurfaceAnimator的構(gòu)造方法初始化的值是getFinishedCallback(staticAnimationFinishedCallback),即動(dòng)畫(huà)完成時(shí)的回調(diào)mCapturedFinishCallback對(duì)應(yīng)的就是getFinishedCallback(staticAnimationFinishedCallback),這一點(diǎn)和本地動(dòng)畫(huà)相同;

動(dòng)畫(huà)類型保存到了mAnimationType。

這個(gè)方法的主要目的是根據(jù)提供的起始和結(jié)束邊界來(lái)設(shè)置動(dòng)畫(huà)的起始位置和窗口裁剪區(qū)域,并保存相關(guān)信息到RemoteAnimationAdapterWrapper的成員變量中,以供后續(xù)使用。

啟動(dòng)動(dòng)畫(huà)流程

layoutRedo = appTransition.goodToGo(transit, topOpeningApp);
在最開(kāi)始的AppTransitionController.handleAppTransitionReady方法中調(diào)用AppTransition.goodToGo方法開(kāi)始啟動(dòng)并顯示動(dòng)畫(huà)的流程。
入?yún)⑼瑯佣际窃趆andleAppTransitionReady方法中初始化的:
參數(shù)transit的值通過(guò)getTransitCompatType方法中獲取,是TRANSIT_OLD_WALLPAPER_CLOSE(12);
參數(shù)topOpeningApp指的是正在打開(kāi)的應(yīng)用列表 (mOpeningApps) 中的頂層應(yīng)用,即應(yīng)用Task對(duì)應(yīng)的ActivityRecord,也就是我們?cè)谧烂鎲?dòng)的應(yīng)用的ActivityRecord。

判斷是否需要重新進(jìn)行布局,RemoteAnimationController狀態(tài)

代碼路徑:frameworks/base/services/core/java/com/android/server/wm/AppTransitionController.java

/**
     * @return bit-map of WindowManagerPolicy#FINISH_LAYOUT_REDO_* to indicate whether another
     *         layout pass needs to be done
     */
    int goodToGo(@TransitionOldType int transit, ActivityRecord topOpeningApp) {
        mNextAppTransitionFlags = 0;
        mNextAppTransitionRequests.clear();
        setAppTransitionState(APP_STATE_RUNNING);
        //如果topOpeningApp不為空,即應(yīng)用ActivityRecord不為空,
        //那么獲取其ActivityRecord的容器,即應(yīng)用Task
        final WindowContainer wc =
                topOpeningApp != null ? topOpeningApp.getAnimatingContainer() : null;
        //應(yīng)用ActivityRecord不為空,獲取AnimationAdapter,即RemoteAnimationAdapterWrapper
        final AnimationAdapter topOpeningAnim = wc != null ? wc.getAnimation() : null;

        //通知所有的AppTransitionListener,應(yīng)用過(guò)渡動(dòng)畫(huà)即將開(kāi)始
        //根據(jù)其返回值判斷是否需要重新進(jìn)行布局
        //我們這里所有的調(diào)用AppTransitionListener的redoLayout返回值都0
        //即redoLayout返回值都0
        int redoLayout = notifyAppTransitionStartingLocked(
                AppTransition.isKeyguardGoingAwayTransitOld(transit),
                AppTransition.isKeyguardOccludeTransitOld(transit),
                topOpeningAnim != null ? topOpeningAnim.getDurationHint() : 0,
                topOpeningAnim != null
                        ? topOpeningAnim.getStatusBarTransitionsStartTime()
                        : SystemClock.uptimeMillis(),
                AnimationAdapter.STATUS_BAR_TRANSITION_DURATION);
        //mRemoteAnimationController不為空
        if (mRemoteAnimationController != null) {
            mRemoteAnimationController.goodToGo(transit);
        }
         //如果mRemoteAnimationController為空
         //transit值為TRANSIT_OLD_WALLPAPER_CLOSE
         //topOpeningAnim,應(yīng)用ActivityRecord不為空時(shí)
         else if ((isTaskOpenTransitOld(transit) || transit == TRANSIT_OLD_WALLPAPER_CLOSE)
                && topOpeningAnim != null) {
            //shouldAttachNavBarToAppDuringTransition(),在動(dòng)畫(huà)過(guò)渡期間將導(dǎo)航欄附加到應(yīng)用程序
            //getRecentsAnimationController(),RecentsAnimationController為空
            if (mDisplayContent.getDisplayPolicy().shouldAttachNavBarToAppDuringTransition()
                    && mService.getRecentsAnimationController() == null) {
                //創(chuàng)建一個(gè)新的NavBarFadeAnimationController
                final NavBarFadeAnimationController controller =
                        new NavBarFadeAnimationController(mDisplayContent);
                // For remote animation case, the nav bar fades out and in is controlled by the
                // remote side. For non-remote animation case, we play the fade out/in animation
                // here. We play the nav bar fade-out animation when the app transition animation
                // starts and play the fade-in animation sequentially once the fade-out is finished.
                //使用fadeOutAndInSequentially方法使其淡出并淡入
                controller.fadeOutAndInSequentially(topOpeningAnim.getDurationHint(),
                        null /* fadeOutParent */, topOpeningApp.getSurfaceControl());
            }
        }
        return redoLayout;
    }

我們RemoteAnimationController已經(jīng)創(chuàng)建,所以mRemoteAnimationController != null為true,進(jìn)入該流程mRemoteAnimationController.goodToGo(transit);,調(diào)用RemoteAnimationController的goodToGo方法,傳遞的參數(shù)值為TRANSIT_OLD_WALLPAPER_CLOSE

傳遞動(dòng)畫(huà)信息到桌面進(jìn)程

代碼路徑:frameworks/base/services/core/java/com/android/server/wm/RemoteAnimationController.java

 /**
     * Called when the transition is ready to be started, and all leashes have been set up.
     */
    void goodToGo(@WindowManager.TransitionOldType int transit) {
        ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "goodToGo()");
        //如果動(dòng)畫(huà)已取消,進(jìn)入動(dòng)畫(huà)播放完成的流程
        if (mCanceled) {
            ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS,
                    "goodToGo(): Animation canceled already");
            onAnimationFinished();
            invokeAnimationCancelled("already_cancelled");
            return;
        }

        // Scale the timeout with the animator scale the controlling app is using.
        //一個(gè)定時(shí)器,超過(guò)TIMEOUT_MS則執(zhí)行mTimeoutRunnable
        //實(shí)際上就是執(zhí)行cancelAnimation方法取消動(dòng)畫(huà)
        mHandler.postDelayed(mTimeoutRunnable,
                (long) (TIMEOUT_MS * mService.getCurrentAnimatorScale()));
        //創(chuàng)建動(dòng)畫(huà)完成時(shí)的回調(diào)函數(shù)
        mFinishedCallback = new FinishedCallback(this);

        // Create the app targets
        //創(chuàng)建類型為App的RemoteAnimationTarget
        final RemoteAnimationTarget[] appTargets = createAppAnimations();
        //判斷如果appTargets為空,且transit的值與鎖屏相關(guān)
        //則取消動(dòng)畫(huà)播放進(jìn)入動(dòng)畫(huà)播放完成的流程
        if (appTargets.length == 0 && !AppTransition.isKeyguardOccludeTransitOld(transit)) {
            // Keyguard occlude transition can be executed before the occluding activity becomes
            // visible. Even in this case, KeyguardService expects to receive binder call, so we
            // don't cancel remote animation.
            ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS,
                    "goodToGo(): No apps to animate, mPendingAnimations=%d",
                    mPendingAnimations.size());
            onAnimationFinished();
            invokeAnimationCancelled("no_app_targets");
            return;
        }

        //運(yùn)行mOnRemoteAnimationReady,做一些播放動(dòng)畫(huà)前的檢查
        if (mOnRemoteAnimationReady != null) {
            mOnRemoteAnimationReady.run();
            mOnRemoteAnimationReady = null;
        }

        // Create the remote wallpaper animation targets (if any)
        //創(chuàng)建壁紙類型的RemoteAnimationTarget
        final RemoteAnimationTarget[] wallpaperTargets = createWallpaperAnimations();

        // Create the remote non app animation targets (if any)
        //創(chuàng)建非app類型的RemoteAnimationTarget,例如狀態(tài)欄,導(dǎo)航欄等
        final RemoteAnimationTarget[] nonAppTargets = createNonAppWindowAnimations(transit);

        //添加動(dòng)畫(huà)啟動(dòng)后的回調(diào)
        mService.mAnimator.addAfterPrepareSurfacesRunnable(() -> {
            try {
                //監(jiān)聽(tīng)綁定IRemoteAnimationRunner的服務(wù)是否死亡
                //綁定IRemoteAnimationRunner實(shí)際上就是LauncherAnimationRunner
                linkToDeathOfRunner();
                ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "goodToGo(): onAnimationStart,"
                                + " transit=%s, apps=%d, wallpapers=%d, nonApps=%d",
                        AppTransition.appTransitionOldToString(transit), appTargets.length,
                        wallpaperTargets.length, nonAppTargets.length);
                //進(jìn)入桌面進(jìn)程啟動(dòng)動(dòng)畫(huà)
                mRemoteAnimationAdapter.getRunner().onAnimationStart(transit, appTargets,
                        wallpaperTargets, nonAppTargets, mFinishedCallback);
            } catch (RemoteException e) {
                Slog.e(TAG, "Failed to start remote animation", e);
                onAnimationFinished();
            }
            if (ProtoLogImpl.isEnabled(WM_DEBUG_REMOTE_ANIMATIONS)) {
                ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "startAnimation(): Notify animation start:");
                writeStartDebugStatement();
            }
        });
        setRunningRemoteAnimation(true);
    }

這里我們主要講類型為App的遠(yuǎn)程動(dòng)畫(huà)

創(chuàng)建類型為App的RemoteAnimationTarget

final RemoteAnimationTarget[] wallpaperTargets = createWallpaperAnimations();

    private RemoteAnimationTarget[] createAppAnimations() {
        ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "createAppAnimations()");
        //創(chuàng)建一個(gè) ArrayList 來(lái)存儲(chǔ) RemoteAnimationTarget 對(duì)象。
        final ArrayList<RemoteAnimationTarget> targets = new ArrayList<>();
        //mPendingAnimations存放的是RemoteAnimationRecord對(duì)象
        //在前面createRemoteAnimationRecord方法中添加
        //注意這里是從列表的末尾開(kāi)始遍歷,這通常是為了在移除元素時(shí)避免索引問(wèn)題。
        //為桌面和應(yīng)用創(chuàng)建RemoteAnimationTarget
        for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
            //獲取對(duì)應(yīng)的RemoteAnimationRecord對(duì)象
            final RemoteAnimationRecord wrappers = mPendingAnimations.get(i);
            //為RemoteAnimationRecord對(duì)象創(chuàng)建createRemoteAnimationTarget
            final RemoteAnimationTarget target = wrappers.createRemoteAnimationTarget();
            if (target != null) {
                ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\tAdd container=%s",
                        wrappers.mWindowContainer);
                //把創(chuàng)建的RemoteAnimationTarget對(duì)象存放到targets列表中
                targets.add(target);
            } else {
                ......
            }
        }
        //返回一個(gè)RemoteAnimationTarget數(shù)組
        return targets.toArray(new RemoteAnimationTarget[targets.size()]);
    }

這個(gè)方法主要是為啟動(dòng)的應(yīng)用和桌面創(chuàng)建RemoteAnimationTarget對(duì)象,RemoteAnimationTarget用來(lái)保存前面創(chuàng)建的動(dòng)畫(huà)圖層、打開(kāi)還是關(guān)閉狀態(tài)的mode等信息。
下面我們看看RemoteAnimationTarget是如何創(chuàng)建的
final RemoteAnimationTarget target = wrappers.createRemoteAnimationTarget();
從對(duì)應(yīng)的RemoteAnimationRecord中調(diào)用createRemoteAnimationTarget方法。這里mPendingAnimations從末尾開(kāi)始遍歷,因此先創(chuàng)建的是桌面的RemoteAnimationTarget,之后創(chuàng)建應(yīng)用的RemoteAnimationTarget。

        RemoteAnimationTarget createRemoteAnimationTarget() {
            if (mAdapter == null
                    || mAdapter.mCapturedFinishCallback == null
                    || mAdapter.mCapturedLeash == null) {
                return null;
            }
            //調(diào)用對(duì)應(yīng)的createRemoteAnimationTarget方法
            mTarget = mWindowContainer.createRemoteAnimationTarget(this);
            return mTarget;
        }

當(dāng)前不論是桌面還是應(yīng)用的容器都是Task,因此當(dāng)前mWindowContainer是對(duì)應(yīng)的Task,而this代表的是當(dāng)前對(duì)應(yīng)的RemoteAnimationRecord。
我們這里調(diào)用mWindowContainer.createRemoteAnimationTarget(this);指的就是在Task類中重寫的createRemoteAnimationTarget方法,但是Task類中沒(méi)有重寫的createRemoteAnimationTarget方法,因此向上查找其父類,發(fā)現(xiàn)重寫的方法在TaskFragment中。

    @Override
    RemoteAnimationTarget createRemoteAnimationTarget(
            RemoteAnimationController.RemoteAnimationRecord record) {
        //根據(jù)當(dāng)前的RemoteAnimationRecord對(duì)象中的mMode值判斷activity的值
        final ActivityRecord activity = record.getMode() == RemoteAnimationTarget.MODE_OPENING
                // There may be a launching (e.g. trampoline or embedded) activity without a window
                // on top of the existing task which is moving to front. Exclude finishing activity
                // so the window of next activity can be chosen to create the animation target.
                ? getActivity(r -> !r.finishing && r.hasChild())
                : getTopMostActivity();
        //activity不為空就創(chuàng)建RemoteAnimationTarget
        return activity != null ? activity.createRemoteAnimationTarget(record) : null;
    }

桌面的RemoteAnimationRecord對(duì)象中的mMode值是MODE_CLOSING,因此通過(guò)getActivity(r -> !r.finishing && r.hasChild())獲取Activity;
應(yīng)用的RemoteAnimationRecord對(duì)象中的mMode值是MODE_OPENING,因此通過(guò)getTopMostActivity()方法獲取Activity。
這兩種獲取方式唯一的差異就是參數(shù)區(qū)別,代碼邏輯變化不大。
我們這里activity的值都不為空,因此最后調(diào)用ActivityRecord中的createRemoteAnimationTarget方法創(chuàng)建RemoteAnimationTarget。
代碼路徑:frameworks/base/services/core/java/com/android/server/wm/ActivityRecord.java

    @Override
    RemoteAnimationTarget createRemoteAnimationTarget(
            RemoteAnimationController.RemoteAnimationRecord record) {
        final WindowState mainWindow = findMainWindow();
        if (task == null || mainWindow == null) {
            return null;
        }
        final Rect insets = mainWindow.getInsetsStateWithVisibilityOverride().calculateInsets(
                task.getBounds(), Type.systemBars(), false /* ignoreVisibility */).toRect();
        InsetUtils.addInsets(insets, getLetterboxInsets());

        final RemoteAnimationTarget target = new RemoteAnimationTarget(task.mTaskId,
                record.getMode(), record.mAdapter.mCapturedLeash, !fillsParent(),
                new Rect(), insets,
                getPrefixOrderIndex(), record.mAdapter.mPosition, record.mAdapter.mLocalBounds,
                record.mAdapter.mEndBounds, task.getWindowConfiguration(),
                false /*isNotInRecents*/,
                record.mThumbnailAdapter != null ? record.mThumbnailAdapter.mCapturedLeash : null,
                record.mStartBounds, task.getTaskInfo(), checkEnterPictureInPictureAppOpsState());
        target.setShowBackdrop(record.mShowBackdrop);
        target.setWillShowImeOnTarget(mStartingData != null && mStartingData.hasImeSurface());
        target.hasAnimatingParent = record.hasAnimatingParent();
        return target;
    }

主要就是把RemoteAnimationRecord和RemoteAnimationAdapterWrapper中的一些參數(shù)保存到RemoteAnimationTarget中,其中最為關(guān)鍵動(dòng)畫(huà)圖層信息record.mAdapter.mCapturedLeash保存到RemoteAnimationTarget對(duì)應(yīng)的變量leash中。

進(jìn)入桌面進(jìn)程啟動(dòng)動(dòng)畫(huà)

回調(diào)goodToGo方法中

mRemoteAnimationAdapter.getRunner().onAnimationStart(transit, appTargets,
                        wallpaperTargets, nonAppTargets, mFinishedCallback);

其中mRemoteAnimationAdapter.getRunner()指的是IRemoteAnimationRunner對(duì)象,通過(guò)跨進(jìn)程通信到桌面進(jìn)程調(diào)用onAnimationStart方法。
代碼路徑:frameworks/base/core/java/android/view/IRemoteAnimationRunner.aidl

oneway interface IRemoteAnimationRunner {

    /**
     * Called when the process needs to start the remote animation.
     *
     * @param transition The old transition type. Must be one of WindowManager.TRANSIT_OLD_* values.
     * @param apps The list of apps to animate.
     * @param wallpapers The list of wallpapers to animate.
     * @param nonApps The list of non-app windows such as Bubbles to animate.
     * @param finishedCallback The callback to invoke when the animation is finished.
     */
    @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
    void onAnimationStart(int transit, in RemoteAnimationTarget[] apps,
            in RemoteAnimationTarget[] wallpapers, in RemoteAnimationTarget[] nonApps,
            in IRemoteAnimationFinishedCallback finishedCallback);
    ......
    }

oneway類型接口,因此里面的方法都屬于異步binder調(diào)用。

這里傳遞的參數(shù)
transit的值是TRANSIT_OLD_WALLPAPER_CLOSE(12);
appTargets指的是前面通過(guò)createAppAnimations方法中獲取的桌面和應(yīng)用的RemoteAnimationTarget;
wallpaperTargets通過(guò)前面createWallpaperAnimations方法中獲取的壁紙的RemoteAnimationTarget;
nonAppTargets通過(guò)前面createNonAppWindowAnimations方法中獲取的非APP類型的RemoteAnimationTarget;
mFinishedCallback前面mFinishedCallback = new FinishedCallback(this);創(chuàng)建的FinishedCallback對(duì)象。
代碼路徑:frameworks/base/services/core/java/com/android/server/wm/RemoteAnimationController.java

private static final class FinishedCallback extends IRemoteAnimationFinishedCallback.Stub {

        RemoteAnimationController mOuter;

        FinishedCallback(RemoteAnimationController outer) {
            mOuter = outer;
        }
        ......
    }

實(shí)際上實(shí)現(xiàn)的就是IRemoteAnimationFinishedCallback,桌面處理完成動(dòng)畫(huà)后跨進(jìn)程回到系統(tǒng)進(jìn)程進(jìn)行回調(diào)。
后續(xù)流程見(jiàn)Android T 遠(yuǎn)程動(dòng)畫(huà)顯示流程其三文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-844073.html

到了這里,關(guān)于Android T 遠(yuǎn)程動(dòng)畫(huà)顯示流程其二——系統(tǒng)側(cè)動(dòng)畫(huà)啟動(dòng)流程的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 筆記:Android 9系統(tǒng)啟動(dòng)流程

    筆記:Android 9系統(tǒng)啟動(dòng)流程

    當(dāng)電源鍵按下時(shí),引導(dǎo)芯片代碼(匯編指令)會(huì)從預(yù)定的地方(固化在ROM)開(kāi)始執(zhí)行,將引導(dǎo)程序 BootLoader 加載到 RAM中,然后執(zhí)行 BootLoader 是在 Android 操作系統(tǒng)開(kāi)始前的一個(gè)小程序,主要作用是把系統(tǒng)OS拉起來(lái)并運(yùn)行 位置: bootablebootloader 當(dāng) Linux系統(tǒng)被 BootLoader 程序拉起,

    2024年02月14日
    瀏覽(27)
  • Android 12系統(tǒng)源碼_窗口管理(一)WindowManagerService的啟動(dòng)流程

    Android 12系統(tǒng)源碼_窗口管理(一)WindowManagerService的啟動(dòng)流程

    WindowManagerService是Android系統(tǒng)中重要的服務(wù),它是WindowManager的管理者,WindowManagerService無(wú)論對(duì)于應(yīng)用開(kāi)發(fā)還是Framework開(kāi)發(fā)都是重要的知識(shí)點(diǎn),究其原因是因?yàn)閃indowManagerService有很多職責(zé),每個(gè)職責(zé)都會(huì)涉及重要且復(fù)雜的系統(tǒng),這使得WindowManagerService就像一個(gè)十字路口的交通燈一樣

    2024年02月11日
    瀏覽(24)
  • 基于Android13的系統(tǒng)啟動(dòng)流程分析(三)之FirstStageMain階段

    基于Android13的系統(tǒng)啟動(dòng)流程分析(三)之FirstStageMain階段

    Android13系統(tǒng)啟動(dòng)階段大致分為FirstStageMain階段和SecondStageMain,此章主要講FirstStageMain階段 (若分析有誤敬請(qǐng)指教) 本章講解的方向和你將收獲的知識(shí): 用戶空間進(jìn)程的調(diào)用流程 當(dāng)進(jìn)程掛掉后該如何處理 何時(shí)掛載上的基本文件系統(tǒng)和文件系統(tǒng)小知識(shí) FirstStageMain階段會(huì)掛載上什

    2024年02月10日
    瀏覽(38)
  • 基于Android13的系統(tǒng)啟動(dòng)流程分析(四)之SecondStageMain階段

    基于Android13的系統(tǒng)啟動(dòng)流程分析(四)之SecondStageMain階段

    Android13系統(tǒng)啟動(dòng)階段大致分為FirstStageMain階段和SecondStageMain,此章主要講SecondStageMain階段 (若分析有誤敬請(qǐng)指教) 在基于Android13的系統(tǒng)啟動(dòng)流程分析(三)之FirstStageMain階段已經(jīng)講解過(guò)android系統(tǒng)啟動(dòng)的基本介紹了,這里不再單獨(dú)介紹了 我們先看是怎么進(jìn)入該階段的,仍然是

    2023年04月24日
    瀏覽(29)
  • 基于Android13的系統(tǒng)啟動(dòng)流程分析(一)之SeLinux權(quán)限介紹

    基于Android13的系統(tǒng)啟動(dòng)流程分析(一)之SeLinux權(quán)限介紹

    學(xué)習(xí)Android系統(tǒng)啟動(dòng)流程之前先學(xué)習(xí)一下SeLinux權(quán)限系統(tǒng),步入正題 本章講解的方向和你將收獲的知識(shí): 什么是SeLinux系統(tǒng),SeLinux的簡(jiǎn)介和介紹 SeLinux系統(tǒng)的主要作用和存在的意義,是基于哪個(gè)版本開(kāi)始推行該方案的 如果遇到了SeLinux權(quán)限問(wèn)題該如何解決,有幾種解決方案 SeLi

    2024年02月04日
    瀏覽(44)
  • 解決Mac系統(tǒng)android monitor啟動(dòng)時(shí)卡住,顯示白屏的問(wèn)題

    解決Mac系統(tǒng)android monitor啟動(dòng)時(shí)卡住,顯示白屏的問(wèn)題

    清安裝1.8版本的jdk,java1.8版本以上不支持android monitor;如果你電腦上安裝有java 11等高級(jí)別的版本,請(qǐng)自行搜索,如果在mac上安裝多jdk,以及如何切換到1.8版本上 請(qǐng)更新SWT插件,下載地址; 1.打開(kāi)網(wǎng)頁(yè),點(diǎn)擊4.9 跳轉(zhuǎn)到另外的網(wǎng)頁(yè) ?2.跳轉(zhuǎn)到的網(wǎng)頁(yè)如下所示意 ? 3. 點(diǎn)擊下載此版

    2024年02月12日
    瀏覽(30)
  • Android 10.0 系統(tǒng)systemui狀態(tài)欄下拉左滑顯示通知欄右滑顯示控制中心模塊的流程分析

    Android 10.0 系統(tǒng)systemui狀態(tài)欄下拉左滑顯示通知欄右滑顯示控制中心模塊的流程分析

    ? 在android10.0的系統(tǒng)rom定制化開(kāi)發(fā)中,在系統(tǒng)原生systemui進(jìn)行自定義下拉狀態(tài)欄布局的定制的時(shí)候,需要在systemui下拉狀態(tài)欄下滑的時(shí)候,根據(jù)下滑坐標(biāo)來(lái) 判斷當(dāng)前是滑出通知欄還是滑出控制中心模塊,所以就需要根據(jù)屏幕寬度,來(lái)區(qū)分x坐標(biāo)值為多少是左滑出通知欄或者右滑

    2023年04月09日
    瀏覽(93)
  • Android 12.0 系統(tǒng)systemui狀態(tài)欄下拉左滑顯示通知欄右滑顯示控制中心模塊的流程分析

    ? 在android12.0的系統(tǒng)rom定制化開(kāi)發(fā)中,在系統(tǒng)原生systemui進(jìn)行自定義下拉狀態(tài)欄布局的定制的時(shí)候,需要在systemui下拉狀態(tài)欄下滑的時(shí)候,根據(jù)下滑坐標(biāo)來(lái) 判斷當(dāng)前是滑出通知欄還是滑出控制中心模塊,所以就需要根據(jù)屏幕寬度,來(lái)區(qū)分x坐標(biāo)值為多少是左滑出通知欄或者右滑

    2024年02月09日
    瀏覽(127)
  • Android遠(yuǎn)程過(guò)渡動(dòng)畫(huà)

    Android的系統(tǒng)動(dòng)畫(huà)我分為三類:窗口動(dòng)畫(huà),過(guò)渡動(dòng)畫(huà),旋轉(zhuǎn)動(dòng)畫(huà)。而這篇文章將分析過(guò)渡動(dòng)畫(huà)。而過(guò)渡動(dòng)畫(huà)根據(jù)創(chuàng)建leash和運(yùn)行動(dòng)畫(huà)是否在同一個(gè)進(jìn)程可以分為本地過(guò)渡動(dòng)畫(huà)和遠(yuǎn)程過(guò)渡動(dòng)畫(huà),啟動(dòng)遠(yuǎn)程過(guò)渡動(dòng)畫(huà)流程相比于其他系統(tǒng)動(dòng)畫(huà)的過(guò)程,因?yàn)樯婕暗搅丝邕M(jìn)程,所以涉及到

    2024年01月21日
    瀏覽(24)
  • android studio啟動(dòng)頁(yè)面動(dòng)畫(huà)Lottie

    android studio啟動(dòng)頁(yè)面動(dòng)畫(huà)Lottie

    1.在build.gradle(app)中加入依賴 implementation\\\'com.airbnb.android:lottie:3.7.0\\\' ?2.在Java包下新建活動(dòng) ?3.在res下創(chuàng)建raw包 ?

    2023年04月08日
    瀏覽(20)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包