<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                回到WMS的addWindow()函數中,繼續往下看: **WindowManagerService.java::WindowManagerService.addWindow()** ``` public int addWindow(Session session, IWindowclient, int seq, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, RectoutContentInsets, InputChannel outInputChannel) { ...... synchronized(mWindowMap){ //在前面的代碼中,WMS驗證了添加窗口的令牌的有效性,并為新窗口創建了新的WindowState對象 // 新的WindowState對象在其構造函數中根據窗口類型初始化了其主序mBaseLayer和mSubLayer ...... // 接下來,將新的WindowState按照顯示次序插入到當前DisplayContent的mWindows列表中 // 為了代碼結構的清晰,不考慮輸入法窗口和壁紙窗口的處理 if (type== TYPE_INPUT_METHOD) { ...... }else if (type == TYPE_INPUT_METHOD_DIALOG) { }else { // 將新的WindowState按顯示次序插入到當前DisplayContent的mWindows列表中 addWindowToListInOrderLocked(win,true); if(type == TYPE_WALLPAPER) { ...... } } ...... // 根據窗口的排序結果,為DisplayContent的所有窗口分配最終的顯示次序 assignLayersLocked(displayContent.getWindowList()); ...... } ...... returnres; } ``` 這里有兩個關鍵點: - addWindowToListInOrderLocked()將新建的WindowState按照一定的順序插入到當前DisplayContent的mWindows列表中。在分析WMS的重要成員時提到過這個列表。它嚴格地按照顯示順序存儲了所有窗口的WindowState。 - assignLayersLocked()將根據mWindows的存儲順序對所有的WindowState的主序和子序進行調整。 接下來分別分析一下這兩個函數。 #### 1.addWindowToListInOrderLocked()分析 addWindowToListInOrderLocked()的代碼很長,不過其排序原則卻比較清晰。這里直接給出其處理原則,感興趣的讀者可根據這些原則自行深究相關代碼。 **注意** :再次強調一下,mWindows列表是按照主序與子序的升序進行排序的,所以顯示靠前的窗口放在列表靠后的位置,而顯示靠前的窗口,則位于列表的前面。也就是說,列表順序與顯示順序是相反的。這點在閱讀代碼時要牢記,以免混淆。 在后面的敘述中,非特別強調,所謂的前后都是指顯示順序而不是在列表的存儲順序。 **子窗口的排序規則**:子窗口的位置計算是相對父窗口的,并根據其子序進行排序。由于父窗口的子序為0,所以子序為負數的窗口會放置在父窗口的后面,而子序為正數的窗口會放置在父窗口的前面。如果新窗口與現有窗口子序相等,則正數子序的新窗口位于現有窗口的前面,負數子序的新窗口位于現有窗口的后面。 非子窗口的排序則是依據主序進行的,但是其規則較為復雜,分為應用窗口和非應用窗口兩種情況。之所以要區別處理應用窗口是因為所有的應用窗口的初始主序都是21000,并且應用窗口的位置應該與它所屬的應用的其他窗口放在一起。例如應用A顯示于應用B的后方,當應用A因為某個動作打開一個新的窗口時,新窗口應該位于應用A其他窗口的前面,但是不得覆蓋應用B的窗口。只依據主序進行排序是無法實現這個管理邏輯的,還需要依賴Activity的順序。在WindowToken一節的講解中,曾經簡單分析了mAppTokens列表的性質,它所保存的AppWindowToken的順序與AMS中ActivityRecord的順序時刻保持一致。因此,AppWindowToken在mAppTokens的順序就是Activity的順序。 **非應用窗口的排序規則**:依照主序進行排序,主序高者排在前面,當現有窗口的主序與新窗口相同時,新窗口位于現有窗口的前面。 **應用窗口的排序規則**:如上所述,同一個應用的窗口的顯示位置必須相鄰。如果當前應用已有窗口在顯示(當前應用的窗口存儲在其WindowState.appWindowToken.windows中),新窗口將插入到其所屬應用其他窗口的前面,但是保證STARTING\_WINDOW永遠位于最前方,BASE\_APPLICATION永遠位于最后方。如果新窗口是當前應用的第一個窗口,則參照其他應用的窗口順序,將新窗口插入到位于前面的最后一個應用的最后一個窗口的后方,或者位于后面的第一個應用的最前一個窗口的前方。如果當前沒有其他應用的窗口可以參照,則直接根據主序將新窗口插入到列表中。 窗口排序的總結如下: - 子窗口依據子序相對于其父窗口進行排序。相同子序的窗體,正子序則越新越靠前,負子序則越新越靠后。 - 應用窗口參照本應用其他窗口或相鄰應用的窗口進行排序。如果沒有任何窗口可以參照,則根據主序進行排序。 - 非應用窗口根據主序進行排序。 經過addWindowToListInOrderLocked()函數的處理之后,當前DisplayContent的窗口列表被插入了一個新的窗口。然后等待assignLayersLocked()的進一步處理。 #### 2.assignLayersLocked分析 assignLayersLocked()函數將根據每個窗口的主序以及它們在窗口列表中的位置重新計算最終的顯示次序mLayer。 **WindowManagerService.java::WindowManagerService.assignLayersLocked()** ``` privatefinal void assignLayersLocked(WindowList windows) { int N = windows.size(); int curBaseLayer = 0; // curLayer表示當前分配到的Layer序號 int curLayer = 0; int i; // 遍歷列表中的所有的窗口,逐個分配顯示次序 for (i=0; i<N; i++) { final WindowState w = windows.get(i); final WindowStateAnimator winAnimator =w.mWinAnimator; boolean layerChanged = false; int oldLayer = w.mLayer; if (w.mBaseLayer == curBaseLayer ||w.mIsImWindow || (i > 0 &&w.mIsWallpaper)) { // 為具有相同主序的窗口在curLayer上增加一個偏移量,并將curLayer作為最終的顯示次序 curLayer +=WINDOW_LAYER_MULTIPLIER; w.mLayer = curLayer; } else { // 此窗口擁有不同的主序,直接將主序作為其顯示次序并更新curLayer curBaseLayer = curLayer =w.mBaseLayer; w.mLayer = curLayer; } // 如果現實次序發生了變化則進行標記 if (w.mLayer != oldLayer) { layerChanged = true; anyLayerChanged = true; } ...... } ...... // 向當前DisplayContent的監聽者通知顯示次序的更新 if (anyLayerChanged) { scheduleNotifyWindowLayersChangedIfNeededLocked( getDefaultDisplayContentLocked()); } } ``` assignLayersLocked()的工作原理比較繞,簡單來說,如果某個窗口在整個列表中擁有唯一的主序,則該主序就是其最終的顯示次序。如果若干個窗口擁有相同的主序(注意經過addWindowToListInOrderLocked()函數的處理后,擁有相同主序的窗口都是相鄰的),則第i個相同主序的窗口的顯示次序為在主序的基礎上增加i \* WINDOW\_LAYER\_MULTIPLIER的偏移。 經過assignLayersLocked()之后,一個擁有9個窗口的系統的現實次序的信息如表4-3所示。 :-: 表4- 3 窗口最終的顯示次序信息 | | 窗口1 | 窗口2 | 窗口3 | 窗口4 | 窗口5 | 窗口6 | 窗口7 | 窗口8 | 窗口9 | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | | 主序mBaseLayer | 11000 | 11000 | 21000 | 21000 | 21000 | 21000 | 71000 | 71000 | 101000 | | 子序mSubLayer | 0 | 0 | 0 | -1 | 0 | 0 | 0 | 0 | 0 | | 顯示次序mLayer | 11000 |11005 | 21000 | 21005 | 21010 | 21015 | 71000 | 71005 | 101000 | 在確定了最終的顯示次序mLayer后,又計算了WindowStateAnimator另一個屬性:mAnimLayer。如下所示: **WindowManagerService.java::assignLayersLocked()** ``` finalWindowStateAnimator winAnimator = w.mWinAnimator; ...... if (w.mTargetAppToken != null) { // 輸入目標為Activity的輸入法窗口,其mTargetAppToken是其輸入目標所屬的AppToken winAnimator.mAnimLayer = w.mLayer + w.mTargetAppToken.mAppAnimator.animLayerAdjustment; } elseif (w.mAppToken != null) { // 屬于一個Activity的窗口 winAnimator.mAnimLayer = w.mLayer + w.mAppToken.mAppAnimator.animLayerAdjustment; } else { winAnimator.mAnimLayer = w.mLayer; } ...... ``` 對于絕大多數窗口而言,其對應的WindowStateAnimator的mAnimLayer就是mLayer。而當窗口附屬為一個Activity時,mAnimLayer會加入一個來自AppWindowAnimator的矯正:animLayerAdjustment。 WindowStateAnimator和AppWindowAnimator是動畫系統中的兩員大將,它們負責渲染窗口動畫以及最終的Surface顯示次序的修改。回顧一下4.1.2中的WMS的組成結構圖,WindowState屬于窗口管理體系的類,因此其所保存的mLayer的意義偏向于窗口管理。WindowStateAnimator/AppWindowAnimator則是動畫體系的類,其mAnimLayer的意義偏向于動畫,而且由于動畫系統維護著窗口的Surface,因此**mAnimLayer是Surface的實際顯示次序**。 在沒有動畫的情況下,mAnimLayer與mLayer是相等的,而當窗口附屬為一個Activity時,則會根據AppTokenAnimator的需要適當地增加一個矯正值。這個矯正值來自AppTokenAnimator所使用的Animation。當Animation要求動畫對象的ZOrder必須位于其他對象之上時(Animation.getZAdjustment()的返回值為Animation.ZORDER\_TOP),這個矯正是一個正數WindowManagerService.TYPE\_LAYER\_OFFSET(1000),這個矯正值很大,于是窗口在動畫過程中會顯示在其他同主序的窗口之上。相反,如果要求ZOrder必須位于其他對象之下時,矯正為-WindowManagerService.TYPE\_LAYER\_OFFSET(-1000),于是窗口會顯示在其他同主序的窗口之下。在動畫完結后,mAnimLayer會被重新賦值為WindowState.mLayer,使得窗口回到其應有的位置。 動畫系統的工作原理將在4.5節詳細探討。 **注意** 矯正值為常數1000,也就出現一個隱藏的bug:當同主序的窗口的數量大于200時,APPLICATION窗口的mLayer值可能超過22000。此時,在對于mLayer值為21000的窗口應用矯正后,仍然無法保證動畫窗口位于同主序的窗口之上。不過超過200個應用窗口的情況非常少見,而且僅在動畫過程中才會出現bug,所以google貌似也懶得解決這個問題。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看