Android窗口管理服务WindowManagerService计算窗口Z轴位置的过程分析
文章轉(zhuǎn)載至CSDN社區(qū)羅升陽的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/8570428
通過前面幾篇文章的學(xué)習(xí),我們知道了在 Android系統(tǒng)中,無論是普通的Activity窗口,還是特殊的輸入法窗口和壁紙窗口,它們都是被WindowManagerService服務(wù)組 織在一個窗口堆棧中的,其中,Z軸位置較大的窗口排列在Z軸位置較小的窗口的上面。有了這個窗口堆棧之后,WindowManagerService服務(wù) 就可以按照一定的規(guī)則計算每一個窗口的Z軸位置了,本文就詳細(xì)分析這個計算過程。
? ? ? ? 基于窗口堆棧來計算窗口的Z軸位置是比較有意思的。按照一般的理解,應(yīng)該是先計算好窗口的Z軸位置,然后再按照Z軸位置的大小來將各個窗口排列在堆棧中。 但是,事實(shí)上,窗口是按照其它規(guī)則排列在堆棧中。這些規(guī)則與窗口的類型、創(chuàng)建順序和運(yùn)行狀態(tài)等有關(guān)。例如,狀態(tài)欄窗口總是位于堆棧的頂端,輸入法窗口總是 位于需要輸入法的窗口的上面,而壁紙窗口總是位于需要顯示壁紙的窗口的下面。又如,當(dāng)一個Activity組件從后臺激活到前臺時,與它所對應(yīng)的窗口就會 被相應(yīng)地移動到窗口堆棧的上面去。
? ? ? ? 從前面Android應(yīng)用程序與SurfaceFlinger服務(wù)的關(guān)系概述和學(xué)習(xí)計劃和Android系統(tǒng)Surface機(jī)制的SurfaceFlinger服務(wù)簡要介紹和學(xué)習(xí)計劃這 兩個系列的文章可以知道,窗口的UI最終是需要通過SurfaceFlinger服務(wù)來統(tǒng)一渲染的,而SurfaceFlinger服務(wù)在渲染窗口的UI 之前,需要計算基于各個窗口的Z軸位置來計算它們的可見區(qū)域。因此,WindowManagerService服務(wù)計算好每一個窗口的Z軸位置之后,還需 要將它們設(shè)置到SurfaceFlinger服務(wù)中去,以便SurfaceFlinger服務(wù)可以正確地渲染每一個窗口的UI。
? ? ? ? 上述窗口的Z軸位置計算和設(shè)置過程如圖1所示:
圖1 窗口Z軸位置的計算和設(shè)置過程
? ? ? ? 接下來,我們就首先分析兩個需要重新計算窗口Z軸位置的情景,接著再分析窗口的Z軸位置的計算過程,最后分析WindowManagerService服務(wù)將窗口的Z軸設(shè)置到SurfaceFlinger服務(wù)中去的過程。
? ? ? ? 一.?需要重新計算窗口Z軸位置的情景
? ? ? ? 這里主要分析兩個需要重新計算窗口Z軸位置的情景:應(yīng)用程序增加一個窗口到WindowManagerService服務(wù)和應(yīng)用程序請求WindowManagerService服務(wù)重新布局一個窗口。
? ? ? ??從前面Android應(yīng)用程序窗口(Activity)與WindowManagerService服務(wù)的連接過程分析一文可以知道,應(yīng)用程序請求增加一個窗口到WindowManagerService服務(wù)的時候,最終會調(diào)用到WindowManagerService類的成員函數(shù)addWindow。接下來我們就主要分析這個函數(shù)與重新計算窗口Z軸位置相關(guān)的邏輯,如下所示:
[java] view plaincopy- public?class?WindowManagerService?extends?IWindowManager.Stub????
- ????????implements?Watchdog.Monitor?{????
- ????......????
- ????
- ????public?int?addWindow(Session?session,?IWindow?client,????
- ????????????WindowManager.LayoutParams?attrs,?int?viewVisibility,????
- ????????????Rect?outContentInsets,?InputChannel?outInputChannel)?{????
- ????????......????
- ????
- ????????synchronized(mWindowMap)?{????
- ????????????......????
- ????
- ????????????WindowToken?token?=?mTokenMap.get(attrs.token);?????
- ????????????......????
- ????
- ????????????win?=?new?WindowState(session,?client,?token,????
- ????????????????????attachedWindow,?attrs,?viewVisibility);????
- ????????????......????
- ????
- ????????????if?(attrs.type?==?TYPE_INPUT_METHOD)?{????
- ????????????????mInputMethodWindow?=?win;??
- ????????????????addInputMethodWindowToListLocked(win);??
- ????????????????......????
- ????????????}?else?if?(attrs.type?==?TYPE_INPUT_METHOD_DIALOG)?{????
- ????????????????mInputMethodDialogs.add(win);??
- ????????????????addWindowToListInOrderLocked(win,?true);??
- ????????????????adjustInputMethodDialogsLocked();??
- ????????????????......????
- ????????????}?else?{????
- ????????????????addWindowToListInOrderLocked(win,?true);????
- ????????????????if?(attrs.type?==?TYPE_WALLPAPER)?{????
- ????????????????????......????
- ????????????????????adjustWallpaperWindowsLocked();????
- ????????????????}?else?if?((attrs.flags&FLAG_SHOW_WALLPAPER)?!=?0)?{????
- ????????????????????adjustWallpaperWindowsLocked();????
- ????????????????}????
- ????????????}????
- ????????????......????
- ????
- ????????????assignLayersLocked();????
- ????
- ????????????......????
- ????????}????
- ????
- ????????......????
- ????}????
- ????
- ????......????
- }??????
? ? ? ??這個函數(shù)定義在文件frameworks/base/services/java/com/android/server/WindowManagerService.java中。
? ? ? ??WindowManagerService類的成員函數(shù)addWindow的具體實(shí)現(xiàn)可以參考Android窗口管理服務(wù)WindowManagerService對壁紙窗口(Wallpaper Window)的管理分析和Android窗口管理服務(wù)WindowManagerService對輸入法窗口(Input Method Window)的管理分析這兩篇文章。我們注意到,WindowManagerService類的成員函數(shù)addWindow會根據(jù)當(dāng)前正在添加的窗口的類型來調(diào)用不同的成員函數(shù)來向窗口堆棧的合適位置插入一個WindowState對象,即:
? ? ? ? 1. 如果添加的是一個輸入法窗口,那么就調(diào)用成員函數(shù)addInputMethodWindowToListLocked將它放置在需要顯示輸入法的窗口的上面去;
? ? ? ? 2. 如果添加的是一個輸入法對話框,那么就先調(diào)用成員函數(shù)addWindowToListInOrderLocked來將它插入到窗口堆棧中,接著再調(diào)用成員 函數(shù)adjustInputMethodDialogsLocked來將它放置在輸入法窗口的上面;
? ? ? ? 3. 如果添加的是一個普通窗口,那么就直接調(diào)用成員函數(shù)addWindowToListInOrderLocked來將它插入到窗口堆棧中;
? ? ? ? 4.?如果添加的是一個普通窗口,并且這個窗口需要顯示壁紙,那么就先調(diào)用成員函數(shù)addWindowToListInOrderLocked來將它插入 到窗口堆棧中,接著再調(diào)用成員函數(shù)adjustWallpaperWindowsLocked來將壁紙窗口放置在它的下面。
? ? ? ? 5.?如果添加的是一個壁紙窗口,那么就先調(diào)用成員函數(shù)addWindowToListInOrderLocked來將它插入到窗口堆棧中,接著再調(diào)用成 員函數(shù)adjustWallpaperWindowsLocked來將它放置在需要顯示壁紙的窗口的下面。
? ? ? ? 無論如何,WindowManagerService類的成員函數(shù)addWindow最終都會調(diào)用成員函數(shù)assignLayersLocked來重新計算系統(tǒng)中所有窗口的Z軸位置,這是因?yàn)榍懊嫱翱诙褩T黾恿艘粋€新的窗口。
? ? ? ??從前面Android窗口管理服務(wù)WindowManagerService計算Activity窗口大小的過程分析一 文可以知道,應(yīng)用程序進(jìn)程請求WindowManagerService服務(wù)重新布局一個窗口的時候,最終會調(diào)用到 WindowManagerService類的成員函數(shù)relayoutWindow。接下來我們就主要分析這個函數(shù)與重新計算窗口Z軸位置相關(guān)的邏輯, 如下所示:
[java] view plaincopy- public?class?WindowManagerService?extends?IWindowManager.Stub??????????
- ????????implements?Watchdog.Monitor?{????????
- ????......??????
- ??????
- ????public?int?relayoutWindow(Session?session,?IWindow?client,??????
- ????????????WindowManager.LayoutParams?attrs,?int?requestedWidth,??????
- ????????????int?requestedHeight,?int?viewVisibility,?boolean?insetsPending,??????
- ????????????Rect?outFrame,?Rect?outContentInsets,?Rect?outVisibleInsets,??????
- ????????????Configuration?outConfig,?Surface?outSurface)?{??????
- ????????......??????
- ??????
- ????????synchronized(mWindowMap)?{??????
- ????????????WindowState?win?=?windowForClientLocked(session,?client,?false);??????
- ????????????......??????
- ??????
- ????????????int?attrChanges?=?0;??????
- ????????????int?flagChanges?=?0;??????
- ????????????if?(attrs?!=?null)?{??????
- ????????????????flagChanges?=?win.mAttrs.flags?^=?attrs.flags;??????
- ????????????????attrChanges?=?win.mAttrs.copyFrom(attrs);??????
- ????????????}??????
- ????????????......??????
- ??????
- ????????????boolean?imMayMove?=?(flagChanges&(??????
- ????????????????????WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM?|??????
- ????????????????????WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE))?!=?0;??????
- ??????
- ????????????boolean?focusMayChange?=?win.mViewVisibility?!=?viewVisibility??????
- ????????????????????||?((flagChanges&WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)?!=?0)??????
- ????????????????????||?(!win.mRelayoutCalled);??????
- ??
- ????????????boolean?wallpaperMayMove?=?win.mViewVisibility?!=?viewVisibility??
- ????????????????????&&?(win.mAttrs.flags?&?FLAG_SHOW_WALLPAPER)?!=?0;??
- ????????????......??????
- ??????
- ??????
- ????????????if?(focusMayChange)?{??????
- ????????????????......??????
- ????????????????if?(updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES))?{??????
- ????????????????????imMayMove?=?false;??????
- ????????????????}??????
- ????????????????......??????
- ????????????}??????
- ??????
- ????????????//?updateFocusedWindowLocked()?already?assigned?layers?so?we?only?need?to??????
- ????????????//?reassign?them?at?this?point?if?the?IM?window?state?gets?shuffled??????
- ????????????boolean?assignLayers?=?false;??????
- ??????
- ????????????if?(imMayMove)?{??????
- ????????????????if?(moveInputMethodWindowsIfNeededLocked(false)?||?displayed)?{??????
- ????????????????????//?Little?hack?here?--?we?-should-?be?able?to?rely?on?the??????
- ????????????????????//?function?to?return?true?if?the?IME?has?moved?and?needs??????
- ????????????????????//?its?layer?recomputed.??However,?if?the?IME?was?hidden??????
- ????????????????????//?and?isn't?actually?moved?in?the?list,?its?layer?may?be??????
- ????????????????????//?out?of?data?so?we?make?sure?to?recompute?it.??????
- ????????????????????assignLayers?=?true;??????
- ????????????????}??????
- ????????????}??
- ????????????if?(wallpaperMayMove)?{??
- ????????????????if?((adjustWallpaperWindowsLocked()&ADJUST_WALLPAPER_LAYERS_CHANGED)?!=?0)?{??
- ????????????????????assignLayers?=?true;??
- ????????????????}??
- ????????????}??????
- ????????????......??????
- ??????
- ????????????if?(assignLayers)?{??????
- ????????????????assignLayersLocked();??????
- ????????????}??????
- ??????
- ????????????......??????
- ????????}??????
- ??????
- ????????......??????
- ??????
- ????????return?(inTouchMode???WindowManagerImpl.RELAYOUT_IN_TOUCH_MODE?:?0)??????
- ????????????????|?(displayed???WindowManagerImpl.RELAYOUT_FIRST_TIME?:?0);??????
- ????}??????
- ??????
- ????......??????
- }??????
? ? ? ??這個函數(shù)定義在文件frameworks/base/services/java/com/android/server/WindowManagerService.java中。
? ? ? ??WindowManagerService類的成員函數(shù)relayoutWindow具體實(shí)現(xiàn)可以參考Android窗口管理服務(wù)WindowManagerService對壁紙窗口(Wallpaper Window)的管理分析和Android窗口管理服務(wù)WindowManagerService對輸入法窗口(Input Method Window)的管理分析這兩篇文章,與窗口Z軸位置計算相關(guān)的邏輯大概是這樣的:
? ? ? ? 1. 如果系統(tǒng)當(dāng)前獲得焦點(diǎn)的窗口可能發(fā)生了變化,那么就會調(diào)用成員函數(shù)updateFocusedWindowLocked來重新計算系統(tǒng)當(dāng)前應(yīng)該獲得焦點(diǎn)的 窗口。如果系統(tǒng)當(dāng)前獲得焦點(diǎn)的窗口真的發(fā)生了變化,即窗口堆棧的窗口排列發(fā)生了變化,那么在調(diào)用成員函數(shù) updateFocusedWindowLocked的時候,就會調(diào)用成員函數(shù)assignLayersLocked來重新計算系統(tǒng)中所有窗口的Z軸位 置。
? ? ? ? 2. 如果系統(tǒng)中的輸入法窗口可能需要移動,那么就會調(diào)用成員函數(shù)moveInputMethodWindowsIfNeededLocked來檢查是否真的需 要移動輸入法窗口。如果需要移動,那么成員函數(shù)moveInputMethodWindowsIfNeededLocked的返回值就會等于true,這 時候就說明輸入法窗口在窗口堆棧中的位置發(fā)生了變化,因此,就會將變量assignLayers的值設(shè)置為true,表示接下來需要重新計算系統(tǒng)中所有窗 口的Z軸位置。
? ? ? ? 3. 如果當(dāng)前正在請求調(diào)整其布局的窗口是由不可見變化可見的,即變量displayed的值等于true,那么接下來也是需要重新計算系統(tǒng)中所有窗口的Z軸位置的,因此,就會將assignLayers的值設(shè)置為true。
? ? ? ? 4.?如果系統(tǒng)中的壁紙窗口可能需要移動,那么就會調(diào)用成員函數(shù)adjustWallpaperWindowsLocked來檢查是否真的需要移動壁紙窗 口。如果需要移動,那么成員函數(shù)adjustWallpaperWindowsLocked的返回值的 ADJUST_WALLPAPER_LAYERS_CHANGED位就會等于1,這時候就說明壁紙窗口在窗口堆棧中的位置發(fā)生了變化,因此,就會將變量 assignLayers的值設(shè)置為true,表示接下來需要重新計算系統(tǒng)中所有窗口的Z軸位置。
? ? ? ? 經(jīng)過上述的一系列操作后,如果得到的變量assignLayers的值設(shè)置等于true,那么WindowManagerService類的成員函數(shù) relayoutWindow就會調(diào)用成員函數(shù)assignLayersLocked來重新計算系統(tǒng)中所有窗口的Z軸位置。
? ? ? ? 二.?計算系統(tǒng)中所有窗口的Z軸位置
? ? ? ? 從前面第一部分的內(nèi)容可以知道,一旦窗口堆棧中的窗口發(fā)生了變化,那么WindowManagerService類的成員函數(shù)assignLayersLocked就會調(diào)用來計算系統(tǒng)中所有窗口的Z軸位置。
? ? ? ? 窗口的Z軸位置除了與它在窗口堆棧中的位置有關(guān)之外,還與窗口的類型有關(guān)。窗口的類型在創(chuàng)建的時候就已經(jīng)是確定了 的,WindowManagerService服務(wù)在為它創(chuàng)建一個WindowState對象的時候,就會根據(jù)它的類型得到一個BaseLayer值,這 個BaseLayer值在計算它的Z軸位置的時候會用到。
? ? ? ? 接下來我們就通過WindowState類的構(gòu)造函數(shù)來分析一個窗口的BaseLayer值是如何確定的,如下所示:
[java] view plaincopy- public?class?WindowManagerService?extends?IWindowManager.Stub??
- ????????implements?Watchdog.Monitor?{??
- ????......??
- ??
- ????/**?How?much?to?multiply?the?policy's?type?layer,?to?reserve?room?
- ?????*?for?multiple?windows?of?the?same?type?and?Z-ordering?adjustment?
- ?????*?with?TYPE_LAYER_OFFSET.?*/??
- ????static?final?int?TYPE_LAYER_MULTIPLIER?=?10000;??
- ??
- ????/**?Offset?from?TYPE_LAYER_MULTIPLIER?for?moving?a?group?of?windows?above?
- ?????*?or?below?others?in?the?same?layer.?*/??
- ????static?final?int?TYPE_LAYER_OFFSET?=?1000;??
- ????......??
- ??
- ????private?final?class?WindowState?implements?WindowManagerPolicy.WindowState?{??
- ????????......??
- ??
- ????????final?int?mBaseLayer;??
- ????????final?int?mSubLayer;??
- ????????......??
- ??
- ????????WindowState(Session?s,?IWindow?c,?WindowToken?token,??
- ???????????????WindowState?attachedWindow,?WindowManager.LayoutParams?a,??
- ???????????????int?viewVisibility)?{??
- ????????????......??
- ??
- ????????????if?((mAttrs.type?>=?FIRST_SUB_WINDOW?&&??
- ????????????????????mAttrs.type?<=?LAST_SUB_WINDOW))?{??
- ????????????????//?The?multiplier?here?is?to?reserve?space?for?multiple??
- ????????????????//?windows?in?the?same?type?layer.??
- ????????????????mBaseLayer?=?mPolicy.windowTypeToLayerLw(??
- ????????????????????????attachedWindow.mAttrs.type)?*?TYPE_LAYER_MULTIPLIER??
- ????????????????????????+?TYPE_LAYER_OFFSET;??
- ????????????????mSubLayer?=?mPolicy.subWindowTypeToLayerLw(a.type);??
- ????????????????......??
- ????????????}?else?{??
- ????????????????//?The?multiplier?here?is?to?reserve?space?for?multiple??
- ????????????????//?windows?in?the?same?type?layer.??
- ????????????????mBaseLayer?=?mPolicy.windowTypeToLayerLw(a.type)??
- ????????????????????????*?TYPE_LAYER_MULTIPLIER??
- ????????????????????????+?TYPE_LAYER_OFFSET;??
- ????????????????mSubLayer?=?0;??
- ????????????????......??
- ????????????}??
- ??
- ????????????......??
- ????????}??
- ??
- ????????......??
- ????}??
- ??
- ????......??
- }??
? ? ? ??這個函數(shù)定義在文件frameworks/base/services/java/com/android/server/WindowManagerService.java中。
? ? ? ??一個窗口除了有一個BaseLayer值之外,還有一個SubLayer值,分別保存在一個對應(yīng)的WindowState對象的成員變量mBaseLayer和mSubLayer。SubLayer值是用來描述一個窗口是否是另外一個窗口的子窗口的。
? ? ? ? 假設(shè)一個窗口是另外一個窗口的子窗口,那么參數(shù)attachedWindow所描述的窗口就是父窗口,這時候子窗口的BaseLayer值就等于父窗口的BaseLayer值,而SubLayer值要么大于0,要么小于0,這與它自己的具體類型有關(guān)。
? ? ? ??假設(shè)一個窗口不是另外一個窗口的子窗口,那么這個窗口的BaseLayer值就與它自己的具體類型有關(guān),而SubLayer值就等于0。
? ? ? ? 現(xiàn)在的關(guān)鍵就是要根據(jù)窗口的類型來計算它的BaseLayer值和SubLayer值,它們分別是通過調(diào)用WindowManagerService類的 成員變量mPolicy所指向的一個PhoneWindowManager對象的成員函數(shù)windowTypeToLayerLw和 subWindowTypeToLayerLw來計算得到的。這里有兩個地方是需要注意的。
? ? ? ? 第一個地方是PhoneWindowManager對象的成員函數(shù)windowTypeToLayerLw的返回值并且不是一個窗口的最終的 BaseLayer值,而是要將它的返回值乘以一個常量TYPE_LAYER_MULTIPLIER,再加上另外一個常量 TYPE_LAYER_OFFSET之后,才得到最終的BaseLayer值。這是因?yàn)樵贏ndroid系統(tǒng)中,相同類型的窗口的Z軸位置都是有著相同的 值域,而不同類型的窗口的Z軸位置都是處于兩個不相交的值域。例如,假設(shè)有兩種不同類型的窗口,它們的Z軸位置的值域分別為[a, b]和[c, d],那么[a, b]和[c, d]的交集一定等于空。又由于每一種類型的窗口的數(shù)量是不確定的,因此,WindowManagerService服務(wù)就需要為每一種類型的窗口都預(yù)留一 個范圍足夠大的值域,以便可以滿足要求。
? ? ? ?WindowManagerService服務(wù)是如何為類型相同的窗口的Z軸位置預(yù)留一個范圍足夠大的值域的呢?我們假設(shè)類型為t的窗口的Z軸位置的值 域?yàn)閇a, b],并且以t為參數(shù)調(diào)用PhoneWindowManager對象的成員函數(shù)windowTypeToLayerLw的返回值為T,那么a的值就等于T *?TYPE_LAYER_MULTIPLIER +?TYPE_LAYER_OFFSET,而b的值就等于(T - 1) *?TYPE_LAYER_MULTIPLIER +?TYPE_LAYER_OFFSET - 1,即從T *?TYPE_LAYER_MULTIPLIER +?TYPE_LAYER_OFFSET開始,一共預(yù)留了TYPE_LAYER_MULTIPLIER個值作為類型為t窗口的Z軸位置。由于 TYPE_LAYER_MULTIPLIER的值定義為10000,而TYPE_LAYER_OFFSET的值定義為1000,因此,每一種類型的窗口都 預(yù)留有一個足夠大的值域來作為Z軸位置。
? ? ? ?第二個地方是窗口的SubLayer值并不直接參與窗口的Z軸位置的計算,但是它會影響到窗口在窗口堆棧的位置。接下來我們就會看到,窗口在窗口堆棧的位置是會影響到它的Z軸位置的計算的,因此,窗口的SubLayer間接地參與了窗口的Z軸位置的計算。
? ? ? ?窗口的SubLayer值是如何影響到窗口在窗口堆棧的位置的呢?在前面Android窗口管理服務(wù)WindowManagerService對窗口的組織方式分析一 文中,在分析WindowManagerService類的成員函數(shù)addWindowToListInOrderLocked的實(shí)現(xiàn)時提到,如果一個窗 口是另外一個窗口的子窗口,那么當(dāng)它的SubLayer值小于0的時候,它就會位于父窗口的下面,否則的話,就會位于父窗口的上面。
? ? ? ?在繼續(xù)分析WindowManagerService類的成員函數(shù)assignLayersLocked之前,我們首先分析 PhoneWindowManager類的成員函數(shù)windowTypeToLayerLw和subWindowTypeToLayerLw的實(shí)現(xiàn),以便 可以了解一個窗口的BaseLayer值和SubLayer值是如何確定的。
? ? ? ?PhoneWindowManager類的成員函數(shù)windowTypeToLayerLw的實(shí)現(xiàn)如下所示:
[java] view plaincopy- public?class?PhoneWindowManager?implements?WindowManagerPolicy?{??
- ????......??
- ??
- ????public?int?windowTypeToLayerLw(int?type)?{??
- ????????if?(type?>=?FIRST_APPLICATION_WINDOW?&&?type?<=?LAST_APPLICATION_WINDOW)?{??
- ????????????return?APPLICATION_LAYER;??
- ????????}??
- ????????switch?(type)?{??
- ????????case?TYPE_STATUS_BAR:??
- ????????????return?STATUS_BAR_LAYER;??
- ????????case?TYPE_STATUS_BAR_PANEL:??
- ????????????return?STATUS_BAR_PANEL_LAYER;??
- ????????case?TYPE_SYSTEM_DIALOG:??
- ????????????return?SYSTEM_DIALOG_LAYER;??
- ????????case?TYPE_SEARCH_BAR:??
- ????????????return?SEARCH_BAR_LAYER;??
- ????????case?TYPE_PHONE:??
- ????????????return?PHONE_LAYER;??
- ????????case?TYPE_KEYGUARD:??
- ????????????return?KEYGUARD_LAYER;??
- ????????case?TYPE_KEYGUARD_DIALOG:??
- ????????????return?KEYGUARD_DIALOG_LAYER;??
- ????????case?TYPE_SYSTEM_ALERT:??
- ????????????return?SYSTEM_ALERT_LAYER;??
- ????????case?TYPE_SYSTEM_ERROR:??
- ????????????return?SYSTEM_ERROR_LAYER;??
- ????????case?TYPE_INPUT_METHOD:??
- ????????????return?INPUT_METHOD_LAYER;??
- ????????case?TYPE_INPUT_METHOD_DIALOG:??
- ????????????return?INPUT_METHOD_DIALOG_LAYER;??
- ????????case?TYPE_SYSTEM_OVERLAY:??
- ????????????return?SYSTEM_OVERLAY_LAYER;??
- ????????case?TYPE_SECURE_SYSTEM_OVERLAY:??
- ????????????return?SECURE_SYSTEM_OVERLAY_LAYER;??
- ????????case?TYPE_PRIORITY_PHONE:??
- ????????????return?PRIORITY_PHONE_LAYER;??
- ????????case?TYPE_TOAST:??
- ????????????return?TOAST_LAYER;??
- ????????case?TYPE_WALLPAPER:??
- ????????????return?WALLPAPER_LAYER;??
- ????????}??
- ????????Log.e(TAG,?"Unknown?window?type:?"?+?type);??
- ????????return?APPLICATION_LAYER;??
- ????}??
- ??
- ????......??
- }??
? ? ? ?這個函數(shù)定義在frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java文件中。
? ? ? ?從這里就可以看出,每一種窗口類型type都對應(yīng)有一個BaseLayer值,即每一個TYPE_XXX值都對應(yīng)有一個XXX_LAYER值,其 中,TYPE_XXX值定義在WindowManager.LayoutParams類中,而XXX_LAYER值就定義在 PhoneWindowManager類中,它們的對應(yīng)關(guān)系如圖2所示:
圖2 窗口類型與窗口BaseLayer值的對應(yīng)關(guān)系
? ? ? ?注意,如果參數(shù)type的值小于FIRST_APPLICATION_WINDOW,或者大于LAST_APPLICATION_WINDOW,或者不 是圖2列出來的其中一個值,那么PhoneWindowManager類的成員函數(shù)windowTypeToLayerLw就會返回一個 APPLICATION_LAYER(2)值給調(diào)用者。
? ? ? ?PhoneWindowManager類的成員函數(shù)subWindowTypeToLayerLw的實(shí)現(xiàn)如下所示:
[java] view plaincopy- public?class?PhoneWindowManager?implements?WindowManagerPolicy?{??
- ????......??
- ??
- ????public?int?subWindowTypeToLayerLw(int?type)?{??
- ????????switch?(type)?{??
- ????????case?TYPE_APPLICATION_PANEL:??
- ????????case?TYPE_APPLICATION_ATTACHED_DIALOG:??
- ????????????return?APPLICATION_PANEL_SUBLAYER;??
- ????????case?TYPE_APPLICATION_MEDIA:??
- ????????????return?APPLICATION_MEDIA_SUBLAYER;??
- ????????case?TYPE_APPLICATION_MEDIA_OVERLAY:??
- ????????????return?APPLICATION_MEDIA_OVERLAY_SUBLAYER;??
- ????????case?TYPE_APPLICATION_SUB_PANEL:??
- ????????????return?APPLICATION_SUB_PANEL_SUBLAYER;??
- ????????}??
- ????????Log.e(TAG,?"Unknown?sub-window?type:?"?+?type);??
- ????????return?0;??
- ????}??
- ??
- ????......??
- }??
? ? ? ??這個函數(shù)定義在frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java文件中。
? ? ? ??從這里就可以看出,只有類型為TYPE_APPLICATION_PANEL、TYPE_APPLICATION_MEDIA、 TYPE_APPLICATION_MEDIA_OVERLAY和TYPE_APPLICATION_SUB_PANEL的窗口才對應(yīng)有一個 SubLayer值,它們的對應(yīng)關(guān)系如圖3所示:
圖3 窗口類型與窗口SubLayer值的對應(yīng)關(guān)系
? ? ? ? 在圖3中,TYPE_XXX值定義在WindowManager.LayoutParams類中,而XXX_LAYER值就定義在 PhoneWindowManager類中。注意,有兩種特殊的多媒體窗口TYPE_APPLICATION_MEDIA和 TYPE_APPLICATION_MEDIA_OVERLAY,它們是用來顯示多媒體的,例如,用來顯示視頻,并且它們都是附加在應(yīng)用程序窗口之上的, 但是由于它們的SubLayer值為負(fù)數(shù),因此它們實(shí)際上是位于宿主窗口之下的。類型為TYPE_APPLICATION_MEDIA的窗口有一個魔術(shù), 它會在宿主窗口里面挖一個洞,以便可以將自己顯示出來,而類型為TYPE_APPLICATION_MEDIA_OVERLAY背景一般都是透明的,位于 類型為TYPE_APPLICATION_MEDIA的窗口,可以用來顯示視頻的字幕之類的東西。實(shí)際上,類型為 TYPE_APPLICATION_MEDIA和TYPE_APPLICATION_MEDIA_OVERLAY的窗口也稱為SurfaceView。 SurfaceView很特殊,它與普通的View的最大區(qū)別就在于它們有獨(dú)立的繪圖表面,于是它們就可以在一個獨(dú)立的子線程里面進(jìn)行UI渲染。
? ? ? ? 理解了窗口的BaseLayer值和SubLayer值的計算過程之外,接下來我們就可以分析WindowManagerService類的成員函數(shù)assignLayersLocked的實(shí)現(xiàn)了,如下所示:
[java] view plaincopy- public?class?WindowManagerService?extends?IWindowManager.Stub??
- ????????implements?Watchdog.Monitor?{??
- ????......??
- ??
- ????/**?How?much?to?increment?the?layer?for?each?window,?to?reserve?room?
- ?????*?for?effect?surfaces?between?them.?
- ?????*/??
- ????static?final?int?WINDOW_LAYER_MULTIPLIER?=?5;??
- ????......??
- ??
- ????private?final?void?assignLayersLocked()?{??
- ????????int?N?=?mWindows.size();??
- ????????int?curBaseLayer?=?0;??
- ????????int?curLayer?=?0;??
- ????????int?i;??
- ??
- ????????for?(i=0;?i<N;?i++)?{??
- ????????????WindowState?w?=?mWindows.get(i);??
- ????????????if?(w.mBaseLayer?==?curBaseLayer?||?w.mIsImWindow??
- ????????????????????||?(i?>?0?&&?w.mIsWallpaper))?{??
- ????????????????curLayer?+=?WINDOW_LAYER_MULTIPLIER;??
- ????????????????w.mLayer?=?curLayer;??
- ????????????}?else?{??
- ????????????????curBaseLayer?=?curLayer?=?w.mBaseLayer;??
- ????????????????w.mLayer?=?curLayer;??
- ????????????}??
- ????????????if?(w.mTargetAppToken?!=?null)?{??
- ????????????????w.mAnimLayer?=?w.mLayer?+?w.mTargetAppToken.animLayerAdjustment;??
- ????????????}?else?if?(w.mAppToken?!=?null)?{??
- ????????????????w.mAnimLayer?=?w.mLayer?+?w.mAppToken.animLayerAdjustment;??
- ????????????}?else?{??
- ????????????????w.mAnimLayer?=?w.mLayer;??
- ????????????}??
- ????????????if?(w.mIsImWindow)?{??
- ????????????????w.mAnimLayer?+=?mInputMethodAnimLayerAdjustment;??
- ????????????}?else?if?(w.mIsWallpaper)?{??
- ????????????????w.mAnimLayer?+=?mWallpaperAnimLayerAdjustment;??
- ????????????}??
- ????????????......??
- ????????}??
- ????}??
- ???
- ????......??
- }??
? ? ? ??這個函數(shù)定義在文件frameworks/base/services/java/com/android/server/WindowManagerService.java中。
? ? ? ? 注意,在調(diào)用WindowManagerService類的成員函數(shù)assignLayersLocked之前,系統(tǒng)中的所有窗口在窗口堆棧中的位置都是 已經(jīng)排列好了的,這時候WindowManagerService類的成員函數(shù)assignLayersLocked就從下往上遍歷窗口堆棧,以連排列在 一起的類型相同的窗口為單位來計算每一個窗口的Z位置,即:
? ? ? ? 1. 每次遇到一個窗口,它的BaseLayer值與上一次計算的窗口的BaseLayer值不相等,就開始一個新的計算單元。
? ? ? ? 2. 在每一個計算單元中,第一個窗口的Z軸位置就等于它的BaseLayer值,而之后的每一個窗口的Z軸位置都比前一個窗口的Z軸位置大WINDOW_LAYER_MULTIPLIER。
? ? ? ? 這個窗口的Z軸位置計算方法有三個地方是需要注意的。 ? ? ? ?
? ? ? ? 第一個地方是從第2點(diǎn)可以看出,每一個窗口的Z軸位置值都不是連續(xù)的,這樣就在每兩個窗口之間都保留了一定的位置來插入其它窗口。
? ? ? ? 第二個地方是由于系統(tǒng)中所有類型相同的窗口不一定都是排列在一起的,因此,就有可能出現(xiàn)有些類型相同的窗口具有相同的Z軸位置。 WindowManagerService服務(wù)并不關(guān)心兩個不同窗口的Z軸位置是否相同,但是SurfaceFlinger服務(wù)就需要關(guān)心了,因?yàn)?SurfaceFlinger服務(wù)需要是按照Z軸從大到小的順序來計算窗口的可見性。那么SurfaceFlinger服務(wù)是如何確定兩個Z軸位置相同的 窗口的次序的呢?從前面Android應(yīng)用程序與SurfaceFlinger服務(wù)的關(guān)系概述和學(xué)習(xí)計劃和Android系統(tǒng)Surface機(jī)制的SurfaceFlinger服務(wù)簡要介紹和學(xué)習(xí)計劃這 兩個系列的文章可以知道,每一個窗口在SurfaceFlinger服務(wù)都對應(yīng)有一個Layer對象,而每一個Layer對象都有一個sequence 值,其中,先創(chuàng)建的Layer對象的sequence值大于后創(chuàng)建的Layer對象的sequence值。這樣,SurfaceFlinger服務(wù)在計算 對于兩個Z軸位置相同的窗口的可見性的時候,就會比較它們所對應(yīng)的Layer對象的sequence值,其中,sequence值大的窗口的可見性會先于 sequence值小的窗口得到計算,即先計算后創(chuàng)建的窗口的可見性,再計算先創(chuàng)建的窗口的可見性。
? ? ? ? 第三個地方是有兩種特殊的窗口,即輸入法窗口和壁紙窗口,當(dāng)它們不是窗口堆棧底部的第一個窗口時,它們所在的計算單元不是以窗口類型來劃分的,而靠近在哪 個窗口,就與哪個窗口在同一個計算單元中。當(dāng)輸入法窗口是窗口堆棧底部的第一個窗口時,它的Z軸位置就等于 WINDOW_LAYER_MULTIPLIER,而當(dāng)壁紙窗口是窗口堆棧底部的第一個窗口時,它的Z軸位置就等于它的BaseLayer值。
? ? ? ??前面計算得到的窗口的Z軸位置保存在WindowState類的成員變量mLayer中。事實(shí)上,保存在WindowState類的成員變量 mLayer中的Z軸位置還不是窗口的最終Z軸位置,因?yàn)檫€沒有考慮到窗口與窗口令牌之間的關(guān)系。每一個窗口令牌都可以設(shè)置一個Z軸調(diào)整值,而每一個窗口 要加上它所對應(yīng)的窗口令牌所設(shè)置的Z軸調(diào)整值之后,才能得到最終的Z軸位置。注意,只有類型為AppWindowToken的窗口令牌才可以設(shè)置Z軸調(diào)整 值,這個Z軸調(diào)整值就保存在AppWindowToken類的成員變量animLayerAdjustment中。
? ? ? ? 有時候,一個窗口會有一個目標(biāo)窗口。例如,輸入法窗口的目標(biāo)窗口是系統(tǒng)當(dāng)前需要顯示輸入法的窗口。在這種情況下,我們要使用目標(biāo)窗口所對應(yīng)的窗口令牌所設(shè)置的Z軸調(diào)整值來調(diào)整窗口的的Z軸位置。
? ? ? ? 那么,WindowManagerService服務(wù)是如何知道一個窗口所對應(yīng)的窗口令牌的類型是AppWindowToken,或者一個窗口有沒有目標(biāo) 窗口的呢?當(dāng)用來描述一個窗口的WindowState對象成員變量mAppToken的值不等于null的時候,那么就說明該窗口所對應(yīng)的窗口令牌的類 型是AppWindowToken,而當(dāng)用來描述一個窗口的WindowState對象成員變量mTargetAppToken的值不等于null的時 候,那么就說明該窗口有一個目標(biāo)窗口。
? ? ? ? 經(jīng)過上面的調(diào)整之后,窗口的Z軸位置就保存在WindowState類的成員變量mAnimLayer中。對于非輸入法窗口和非壁紙窗口來說,這時候保存 在用來描述它們的WindowState對象的成員變量mAnimLayer中的Z軸位置就是它們最終的Z軸位置了,但是對于輸入法窗口和壁紙窗口來說, 還需要繼續(xù)判斷它們的目標(biāo)窗口是否需要調(diào)整它們的Z軸位置。
? ? ? ? 從前面Android窗口管理服務(wù)WindowManagerService對壁紙窗口(Wallpaper Window)的管理分析和Android窗口管理服務(wù)WindowManagerService對輸入法窗口(Input Method Window)的管理分析這 兩篇文章知道,如果一個窗口要調(diào)整它所關(guān)聯(lián)的輸入法窗口和壁紙窗口的Z軸位置,那么要調(diào)整的值就會保存在WindowManagerService類的成 員變量mInputMethodAnimLayerAdjustment和mWallpaperAnimLayerAdjustment中,因此,只要將 WindowManagerService類的成員變量mInputMethodAnimLayerAdjustment和 mWallpaperAnimLayerAdjustment的值分別增加到前面所計算得到的輸入法窗口和壁紙窗口的Z軸位置上去,就可以得到輸入法窗口 和壁紙窗口的最終Z軸位置,并且保存到用來對應(yīng)的WindowState對象的成員變量mAnimLayer中。
? ? ? ? 從上面的計算過程就可以知道,系統(tǒng)中所有類型的窗口的最終Z軸位置都保存在WindowState類的成員變量mAnimLayer中。
? ? ? ? 三. 設(shè)置窗口的Z軸位置到SurfaceFlinger服務(wù)中去
? ? ? ? WindowManagerService服務(wù)在刷新系統(tǒng)的UI的時候,就會將系統(tǒng)中已經(jīng)計算好了的窗口Z軸位置設(shè)置到SurfaceFlinger服務(wù)中去,以便SurfaceFlinger服務(wù)可以對系統(tǒng)中的窗口進(jìn)行可見性計算以及合成和渲染等操作。
? ? ? ? 從前面Android窗口管理服務(wù)WindowManagerService計算Activity窗口大小的過程分析一 文可以知道,刷新系統(tǒng)UI是通過調(diào)用WindowManagerService類的成員函數(shù) performLayoutAndPlaceSurfacesLockedInner來實(shí)現(xiàn)的,接下來我們就分析這個成員函數(shù)與設(shè)置窗口的Z軸位置到 SurfaceFlinger服務(wù)中去相關(guān)的邏輯。
? ? ? ? 為了方便描述設(shè)置窗口的Z軸位置到SurfaceFlinger服務(wù)中去的過程,我們先列出WindowManagerService類的成員函數(shù)performLayoutAndPlaceSurfacesLockedInner的實(shí)現(xiàn)架構(gòu),如下所示:
[java] view plaincopy- public?class?WindowManagerService?extends?IWindowManager.Stub????
- ????????implements?Watchdog.Monitor?{????
- ????......????
- ????
- ????private?final?void?performLayoutAndPlaceSurfacesLockedInner(????
- ????????????boolean?recoveringMemory)?{????
- ????????......????
- ????
- ????????Surface.openTransaction();????
- ????????......????
- ????
- ????????try?{????
- ????????????......????
- ????????????int?repeats?=?0;????
- ????????????int?changes?=?0;????
- ????????????????
- ????????????do?{????
- ????????????????repeats++;????
- ????????????????if?(repeats?>?6)?{????
- ????????????????????......????
- ????????????????????break;????
- ????????????????}????
- ????
- ????????????????//?FIRST?LOOP:?Perform?a?layout,?if?needed.????
- ????????????????if?(repeats?<?4)?{????
- ????????????????????changes?=?performLayoutLockedInner();????
- ????????????????????if?(changes?!=?0)?{????
- ????????????????????????continue;????
- ????????????????????}????
- ????????????????}?else?{????
- ????????????????????Slog.w(TAG,?"Layout?repeat?skipped?after?too?many?iterations");????
- ????????????????????changes?=?0;????
- ????????????????}????
- ????
- ????????????????//?SECOND?LOOP:?Execute?animations?and?update?visibility?of?windows.????
- ????????????????......????
- ????????????????????
- ????????????}?while?(changes?!=?0);????
- ????
- ????????????//?THIRD?LOOP:?Update?the?surfaces?of?all?windows.???
- ????????????......??
- ??
- ????????????//更新窗口的繪圖表面的操作包括:??
- ????????????//1.?設(shè)置窗口的大小??
- ????????????//2.?設(shè)置窗口在X軸和Y軸上的位置??
- ????????????//3.?設(shè)置窗口在Z軸上的位置??
- ????????????//4.?設(shè)置窗口的Alpha通道??
- ????????????//5.?設(shè)置窗口的變換矩陣??
- ????????????......??
- ?????????????????????
- ????????}?catch?(RuntimeException?e)?{????
- ????????????......????
- ????????}????
- ????
- ????????......????
- ????
- ????????Surface.closeTransaction();????
- ????
- ????????......????
- ????
- ????????//?Destroy?the?surface?of?any?windows?that?are?no?longer?visible.????
- ????????......????
- ????
- ????????//?Time?to?remove?any?exiting?tokens?????
- ????????......????
- ????
- ????????//?Time?to?remove?any?exiting?applications?????
- ????????......????
- ????}????
- ????
- ????......????
- }????
? ? ? ??這個函數(shù)定義在文件frameworks/base/services/java/com/android/server/WindowManagerService.java中。
? ? ? ? 在前面Android窗口管理服務(wù)WindowManagerService計算Activity窗口大小的過程分析一 文中,我們已經(jīng)分析過WindowManagerService類的成員函數(shù) performLayoutAndPlaceSurfacesLockedInner的實(shí)現(xiàn)架構(gòu)了,其中,設(shè)置窗口的Z軸位置到 SurfaceFlinger服務(wù)中去是在更新窗口的繪圖表面的操作中進(jìn)行的,即是在THIRD LOOP中進(jìn)行的,同時設(shè)置的還包括窗口的大小、X軸和Y軸位置、Alpha通道和變換矩陣,這些代碼如下所示:
[java] view plaincopy- //更新窗口的繪圖表面的操作包括:??
- //1.?設(shè)置窗口的大小??
- //2.?設(shè)置窗口在X軸和Y軸上的位置??
- //3.?設(shè)置窗口在Z軸上的位置??
- //4.?設(shè)置窗口的Alpha通道值??
- //5.?設(shè)置窗口的變換矩陣??
- final?int?N?=?mWindows.size();??
- ??
- for?(i=N-1;?i>=0;?i--)?{??
- ????WindowState?w?=?mWindows.get(i);???
- ????......??
- ??
- ????if?(w.mSurface?!=?null)?{??
- ????????......??
- ??
- ????????w.computeShownFrameLocked();??
- ????????......??
- ??
- ????????boolean?resize;??
- ????????int?width,?height;??
- ????????if?((w.mAttrs.flags?&?w.mAttrs.FLAG_SCALED)?!=?0)?{??
- ????????????resize?=?w.mLastRequestedWidth?!=?w.mRequestedWidth?||??
- ????????????w.mLastRequestedHeight?!=?w.mRequestedHeight;??
- ????????????//?for?a?scaled?surface,?we?just?want?to?use??
- ????????????//?the?requested?size.??
- ????????????width??=?w.mRequestedWidth;??
- ????????????height?=?w.mRequestedHeight;??
- ????????????w.mLastRequestedWidth?=?width;??
- ????????????w.mLastRequestedHeight?=?height;??
- ????????????w.mLastShownFrame.set(w.mShownFrame);??
- ????????????try?{??
- ????????????????......??
- ????????????????w.mSurfaceX?=?w.mShownFrame.left;??
- ????????????????w.mSurfaceY?=?w.mShownFrame.top;??
- ????????????????w.mSurface.setPosition(w.mShownFrame.left,?w.mShownFrame.top);??
- ????????????}?catch?(RuntimeException?e)?{??
- ????????????????......??
- ????????????????if?(!recoveringMemory)?{??
- ????????????????????reclaimSomeSurfaceMemoryLocked(w,?"position");??
- ????????????????}??
- ????????????}??
- ????????}?else?{??
- ????????????resize?=?!w.mLastShownFrame.equals(w.mShownFrame);??
- ????????????width?=?w.mShownFrame.width();??
- ????????????height?=?w.mShownFrame.height();??
- ????????????w.mLastShownFrame.set(w.mShownFrame);??
- ????????}??
- ??
- ????????if?(resize)?{??
- ????????????if?(width?<?1)?width?=?1;??
- ????????????if?(height?<?1)?height?=?1;??
- ????????????if?(w.mSurface?!=?null)?{??
- ????????????????try?{??
- ????????????????????......??
- ????????????????????w.mSurfaceResized?=?true;??
- ????????????????????w.mSurfaceW?=?width;??
- ????????????????????w.mSurfaceH?=?height;??
- ????????????????????w.mSurface.setSize(width,?height);??
- ????????????????????w.mSurfaceX?=?w.mShownFrame.left;??
- ????????????????????w.mSurfaceY?=?w.mShownFrame.top;??
- ????????????????????w.mSurface.setPosition(w.mShownFrame.left,??
- ????????????????????????????w.mShownFrame.top);??
- ????????????????}?catch?(RuntimeException?e)?{??
- ????????????????????......??
- ????????????????????if?(!recoveringMemory)?{??
- ????????????????????????reclaimSomeSurfaceMemoryLocked(w,?"size");??
- ????????????????????}??
- ????????????????}??
- ????????????}??
- ????????}??
- ??
- ????????......??
- ??
- ????????if?(w.mAttachedHidden?||?!w.isReadyForDisplay())?{??
- ????????????if?(!w.mLastHidden)?{??
- ????????????????w.mLastHidden?=?true;??
- ????????????????......??
- ??
- ????????????????if?(w.mSurface?!=?null)?{??
- ????????????????????w.mSurfaceShown?=?false;??
- ????????????????????try?{??
- ????????????????????????w.mSurface.hide();??
- ????????????????????}?catch?(RuntimeException?e)?{??
- ????????????????????????......??
- ????????????????????}??
- ????????????????}??
- ????????????}????
- ??
- ????????????......??
- ????????}?else?if?(w.mLastLayer?!=?w.mAnimLayer??
- ????????????????||?w.mLastAlpha?!=?w.mShownAlpha??
- ????????????????||?w.mLastDsDx?!=?w.mDsDx??
- ????????????????||?w.mLastDtDx?!=?w.mDtDx??
- ????????????????||?w.mLastDsDy?!=?w.mDsDy??
- ????????????????||?w.mLastDtDy?!=?w.mDtDy??
- ????????????????||?w.mLastHScale?!=?w.mHScale??
- ????????????????||?w.mLastVScale?!=?w.mVScale??
- ????????????????||?w.mLastHidden)?{??????
- ????????????......??
- ????????????w.mLastAlpha?=?w.mShownAlpha;??
- ????????????w.mLastLayer?=?w.mAnimLayer;??
- ????????????w.mLastDsDx?=?w.mDsDx;??
- ????????????w.mLastDtDx?=?w.mDtDx;??
- ????????????w.mLastDsDy?=?w.mDsDy;??
- ????????????w.mLastDtDy?=?w.mDtDy;??
- ????????????w.mLastHScale?=?w.mHScale;??
- ????????????w.mLastVScale?=?w.mVScale;??
- ????????????......??
- ????????????if?(w.mSurface?!=?null)?{??
- ???????????????try?{??
- ????????????????????w.mSurfaceAlpha?=?w.mShownAlpha;??
- ????????????????????w.mSurface.setAlpha(w.mShownAlpha);??
- ????????????????????w.mSurfaceLayer?=?w.mAnimLayer;??
- ????????????????????w.mSurface.setLayer(w.mAnimLayer);??
- ????????????????????w.mSurface.setMatrix(??
- ????????????????????????????w.mDsDx*w.mHScale,?w.mDtDx*w.mVScale,??
- ????????????????????????????w.mDsDy*w.mHScale,?w.mDtDy*w.mVScale);??
- ????????????????}?catch?(RuntimeException?e)?{??
- ????????????????????.....??
- ????????????????????if?(!recoveringMemory)?{??
- ????????????????????????reclaimSomeSurfaceMemoryLocked(w,?"update");??
- ????????????????????}??
- ????????????????}??
- ????????????}??
- ??
- ????????????if?(w.mLastHidden?&&?!w.mDrawPending??
- ????????????????????&&?!w.mCommitDrawPending??
- ????????????????????&&?!w.mReadyToShow)?{??
- ????????????????......??
- ????????????????if?(showSurfaceRobustlyLocked(w))?{??
- ????????????????????w.mHasDrawn?=?true;??
- ????????????????????w.mLastHidden?=?false;??
- ????????????????}???
- ????????}????
- ??
- ????????......??
- ????}??
- ??
- ????......????????????????????????????
- }??
? ? ? ? 這段代碼通過一個for循環(huán)來遍歷保存在窗口堆棧的每一個WindowState對象,以便可以對系統(tǒng)中的每一個窗口的繪圖表面進(jìn)行更新。注意,只有那些 成員變量mSurface的值不等于null的WindowState對象,它們所描述的窗口才具有繪圖表面,因此需要對它們進(jìn)行更新。
? ? ? ? 在更新WindowState對象w所描述的窗口的繪圖表面之前,首先要調(diào)用它的成員函數(shù)computeShownFrameLocked來確定該窗口實(shí)際要顯示的大小、位置、Alpha通道和變換矩陣等信息,其中:
? ? ? ? 1.?窗口實(shí)際要顯示的大小和X軸、Y軸位置保存在WindowState對象w的成員變量mShownFrame中。
? ? ? ? 2.?窗口實(shí)際要顯示的Alpha通道保存在WindowState對象w的成員變量mShownAlpha中。
? ? ? ? 3.?窗口實(shí)際要顯示的Z軸位置保存在WindowState對象w的成員變量mAnimLayer中。
? ? ? ? 4.?窗口實(shí)際要使用的變換矩陣保存在WindowState對象w的成員變量mDsDx、mDtDx、mDsDy和mDtDy中。
? ? ? ? 有了上述信息之后,我們就可以將WindowState對象w所描述的窗口實(shí)際要顯示的大小、位置、Alpha通道和變換矩陣等信息設(shè)置到SurfaceFlinger服務(wù)中去了。
? ? ? ? 我們首先分析WindowState對象w所描述的窗口實(shí)際要顯示的大小、X軸和Y軸位置的設(shè)置過程,接著再分析WindowState對象w所描述的窗口實(shí)際要顯示的Alpha通道、Z軸位置以及實(shí)際要使用的變換矩陣的設(shè)置過程。
? ? ? ? 在調(diào)用WindowState對象w的成員函數(shù)computeShownFrameLocked來計算它所描述的窗口的大小的時候,是沒有考慮該窗口的大小是否設(shè)置有縮放因子的。
? ? ? ? 當(dāng)WindowState對象w所描述的窗口的大小設(shè)置有縮放因子的時候,那么WindowState對象w的成員變量mAttrs所指向的一個 WindowManager.LayoutParams對象的成員變量flags的FLAG_SCALED位就會等于1,這時候WindowState對 象w所描述的窗口實(shí)際要顯示的大小是保存在它的成員變量mRequestedWidth和mRequestedHeight中的。在這種情況下,這段代碼 就會執(zhí)行以下操作:
? ? ? ? 1. 計算WindowState對象w所描述的窗口實(shí)際要顯示的大小是否發(fā)生了變化。如果發(fā)生了變化,那么就將變量resize的值設(shè)置為true。注 意,WindowState對象w所描述的窗口上一次實(shí)際要顯示的大小保存在成員變量mLastRequestedWidth和 mLastRequestedHeight中,因此,當(dāng)這兩個成員變量與其它兩個成員變量mRequestedWidth和 mRequestedHeight的值不相等于時,就說明WindowState對象w所描述的窗口實(shí)際要顯示的大小是否發(fā)生了變化。
? ? ? ? 2. 將WindowState對象w所描述的窗口實(shí)際要顯示的大小分別更新到成員變量mLastRequestedWidth和mLastRequestedHeight中,以及變量width和height中。
? ? ? ? 3. 將WindowState對象w的成員變量mShownFrame的值保存在另外一個成員變量mLastShownFrame中,以便可以記錄WindowState對象w所描述的窗口上一次實(shí)際要顯示的大小和X軸、Y軸位置。
? ? ? ? 4. 將WindowState對象w所描述的窗口的X軸和Y軸位置分別保存到成員變量mSurfaceX和mSurfaceY中,并且調(diào)用 WindowState對象w的成員變量mSurface所指向的一個Surface對象的成員函數(shù)setPosition來將這兩個位置值設(shè)置到 SurfaceFlinger服務(wù)中去。
? ? ? ? 5. 在設(shè)置WindowState對象w所描述的窗口的X軸和Y軸位置到SurfaceFlinger服務(wù)中去的過程中,如果出現(xiàn)了異常,那么就說明系統(tǒng)內(nèi)存 資源不足。在這種情況下,如果參數(shù)recoveringMemory的值等于false,那么就說明WindowManagerService服務(wù)目前不 是處于內(nèi)存資源的回收過程中,于是就會調(diào)用WindowManagerService類的成員函數(shù) reclaimSomeSurfaceMemoryLocked來執(zhí)行回收系統(tǒng)內(nèi)存資源的操作。
? ? ? ??當(dāng)WindowState對象w所描述的窗口的大小沒有設(shè)置有縮放因子的時候,那么WindowState對象w的成員變量mAttrs所指向的一個 WindowManager.LayoutParams對象的成員變量flags的FLAG_SCALED位就會等于0,這時候WindowState對 象w所描述的窗口實(shí)際要顯示的大小是保存在它的成員變量mShownFrame中的。在這種情況下,這段代碼就會執(zhí)行以下操作:
? ? ? ? 1.?計算WindowState對象w所描述的窗口實(shí)際要顯示的大小是否發(fā)生了變化。如果發(fā)生了變化,那么就將變量resize的值設(shè)置為true。注 意,這時候只要比較WindowState對象w的成員變量mLastShownFrame和mShownFrame所描述的兩個矩形區(qū)域的大小是否相 等,就可以知道WindowState對象w所描述的窗口實(shí)際要顯示的大小是否發(fā)生了變化,因?yàn)閃indowState對象w的成員變量 mLastShownFrame保存的是窗口上一次實(shí)際要顯示的大小。
? ? ? ? 2.?將WindowState對象w所描述的窗口實(shí)際要顯示的大小分別保存在變量width和height中。
? ? ? ? 3.?將WindowState對象w的成員變量mShownFrame的值保存在另外一個成員變量mLastShownFrame中,以便可以記錄WindowState對象w所描述的窗口上一次實(shí)際要顯示的大小和X軸、Y軸位置。
? ? ? ? 執(zhí)行完成以上操作之后,WindowState對象w所描述的窗口實(shí)際要顯示的X軸和Y軸位置就保存在成員變量mShownFrame所描述的一個 Rect對象的成員變量left和top中,而實(shí)際要顯示的大小就顯示在變量width和height中。這時候如果變量resize的值等于true, 那么就說明WindowState對象w所描述的窗口的大小發(fā)生了變化。在這種情況下,就需要執(zhí)行以下操作:
? ? ? ? 1. 重新設(shè)置WindowState對象w所描述的窗口的大小到SurfaceFlinger服務(wù)中去,這是通過調(diào)用WindowState對象w的成員變量 mSurface所指向的一個Surface對象的成員函數(shù)setSize來實(shí)現(xiàn)的。注意,如果前面計算得到WindowState對象w所描述的窗口的 寬度width和高度height的值小于1,那么就需要將它們的值設(shè)置為1,因?yàn)橐粋€窗口的寬度和高度值是不能小于1的。
? ? ? ? 2. 重新設(shè)置WindowState對象w所描述的窗口在X軸和Y軸上的位置到SurfaceFlinger服務(wù)中去,這是通過調(diào)用WindowState對 象w的成員變量mSurface所指向的一個Surface對象的成員函數(shù)setPosition來實(shí)現(xiàn)的。注意,在設(shè)置之前,還會將 WindowState對象w所描述的窗口在X軸和Y軸上的位置保存在成員變量mSurfaceX和mSurfaceY中。
? ? ? ? 3.?在設(shè)置WindowState對象w所描述的窗口的大小以及在X軸和Y軸上的位置到SurfaceFlinger服務(wù)中去的過程中,如果出現(xiàn)了異 常,那么同樣需要判斷參數(shù)recoveringMemory的值來決定是否需要WindowManagerService類的成員函數(shù) reclaimSomeSurfaceMemoryLocked來回收系統(tǒng)內(nèi)存資源。
? ? ? ? 設(shè)置好WindowState對象w所描述的窗口實(shí)際要顯示的大小、X軸和Y軸位置到SurfaceFlinger服務(wù)中去之后,接下來就要繼續(xù)設(shè)置它實(shí) 際要顯示的Alpha通道、Z軸位置以及實(shí)際要使用的變換矩陣了,不過只有當(dāng)WindowState對象w所描述的窗口當(dāng)前是處于可見狀態(tài)、并且這些值沒 有發(fā)生變化的情況下才需要這樣做。
? ? ? ? 當(dāng)WindowState對象w的成員函數(shù)isReadyForDisplay的返回值等于false時,就說明WindowState對象w所描述的窗 口當(dāng)前是處于不可見狀態(tài)的。還有另外一種情況,即當(dāng)WindowState對象w所描述的窗口是附加在另外一個窗口之上、并且這個被附加的窗口是不可見 時,即WindowState對象w的成員變量mAttachedHidden的值等于true時,也是說明WindowState對象w所描述的窗口當(dāng) 前是處于不可見狀態(tài)的。
? ? ? ? 在WindowState對象w所描述的窗口當(dāng)前是處于不可見狀態(tài)的情況下,如果該窗口在上一次系統(tǒng)UI刷新時是處于可見狀態(tài)的,即 WindowState對象w的成員變量mLastHidden的值等于true,那么這時候就需要將WindowState對象w所描述的窗口隱藏起 來,這是通過調(diào)用WindowState對象w的成員變量mSurface所指向的一個Surface對象的成員函數(shù)hide來實(shí)現(xiàn)的。注意,在調(diào)用 WindowState對象w的成員變量mSurface所指向的一個Surface對象的成員函數(shù)hide來隱藏窗口之前,需要分別將 WindowState對象w的成員變量mLastHidden和mSurfaceShown的值設(shè)置為true和false,以便可以正確描述窗口的不 可見狀態(tài)。
? ? ? ??在WindowState對象w所描述的窗口當(dāng)前是處于可見狀態(tài)的情況下,如果該窗口實(shí)際要顯示的Alpha通道、Z軸位置以及實(shí)際要使用的變換矩陣發(fā)生了變化,那么就需要將新的值設(shè)置到SurfaceFlinger服務(wù)中去,其中:
? ? ? ? 1.?WindowState對象w的成員變量mLastLayer與mAnimLayer的值不相等說明它描述的窗口的Z軸位置發(fā)生了變化。
? ? ? ? 2.?WindowState對象w的成員變量mLastAlpha與mShownAlpha的值不相等說明它描述的窗口的Alpha通道發(fā)生了變化。
? ? ? ? 3.?WindowState對象w的成員變量mLastDsDx、mLastDtDx、mLastDsDy、 mLastDtDy、mLastHScale、mLastVScale與成員變量mDsDx、mDtDx、mDsDy、?mDtDy、mHScale、 mVScale的值不相等說明它描述的窗口的變換矩陣發(fā)生了變化。
? ? ? ??在WindowState對象w所描述的窗口當(dāng)前是處于可見狀態(tài)的情況下,如果該窗口在上一次系統(tǒng)UI刷新時是處于可見狀態(tài)的,即 WindowState對象w的成員變量mLastHidden的值等于true,那么也是需要重新設(shè)置WindowState對象w所描述的窗口實(shí)際要 顯示的Alpha通道、Z軸位置以及實(shí)際要使用的變換矩陣到SurfaceFlinger服務(wù)中去的。
? ? ? ? 無論如何,當(dāng)需要重新設(shè)置WindowState對象w所描述的窗口實(shí)際要顯示的Alpha通道、Z軸位置以及實(shí)際要使用的變換矩陣到SurfaceFlinger服務(wù)中去時,就需要執(zhí)行以下操作:
? ? ? ? 1. 重新設(shè)置WindowState對象w所描述的窗口的Alpha通道到SurfaceFlinger服務(wù)中去,這是通過調(diào)用WindowState對象w 的成員變量mSurface所指向的一個Surface對象的成員函數(shù)setAlpha來實(shí)現(xiàn)的。在設(shè)置之前,還會將WindowState對象w的成員 變量mShownAlpha的值同時保存在成員變量mLastAlpha和mSurfaceAlpha中,以便可以記錄WindowState對象w所描 述的窗口上一次所使用的Alpha通道。
? ? ? ? 2.?重新設(shè)置WindowState對象w所描述的窗口的Z軸位置到SurfaceFlinger服務(wù)中去,這是通過調(diào)用WindowState對象w 的成員變量mSurface所指向的一個Surface對象的成員函數(shù)setLayer來實(shí)現(xiàn)的。在設(shè)置之前,還會將WindowState對象w的成員 變量mAnimLayer的值同時保存在成員變量mLastLayer和mSurfaceLayer中,以便可以記錄WindowState對象w所描述 的窗口上一次所使用的Z軸位置。
? ? ? ? 3.?重新設(shè)置WindowState對象w所描述的窗口的變換矩陣到SurfaceFlinger服務(wù)中去,這是通過調(diào)用WindowState對象w 的成員變量mSurface所指向的一個Surface對象的成員函數(shù)setMatrix來實(shí)現(xiàn)的。在設(shè)置之前,還會將WindowState對象w的成 員變量成員變量mDsDx、mDtDx、mDsDy、?mDtDy、mHScale、mVScale的值分別保存在成員變量mLastDsDx、 mLastDtDx、mLastDsDy、?mLastDtDy、mLastHScale、mLastVScale中,以便可以記錄 WindowState對象w所描述的窗口上一次所使用的變換矩陣。注意,WindowState對象的成員變量mHScale和mVScale描述的窗 口在寬度和高度上的縮放因子,因此,在設(shè)置窗口的變換矩陣時,需要乘以這些因子才可以得到正確的變換矩陣參數(shù)。
? ? ? ? 4.?在設(shè)置WindowState對象w所描述的窗口的Alpha通道、Z軸位置以及實(shí)際要使用的變換矩陣到SurfaceFlinger服務(wù)的過程 中,如果出現(xiàn)了異常,那么同樣需要判斷參數(shù)recoveringMemory的值來決定是否需要WindowManagerService類的成員函數(shù) reclaimSomeSurfaceMemoryLocked來回收系統(tǒng)內(nèi)存資源。
? ? ? ? 將WindowState對象w所描述的窗口實(shí)際要顯示的Alpha通道、Z軸位置以及實(shí)際要使用的變換矩陣設(shè)置到SurfaceFlinger服務(wù)之后,如果WindowState對象w所描述的窗口滿足以下條件:
? ? ? ? 1. 上一次處于不可見狀態(tài),即WindowState對象w的成員變量mLastHidden的值等于true;
? ? ? ? 2. UI已經(jīng)繪制完成,即WindowState對象w的成員變量mDrawPending和mCommitDrawPending值等于false;
? ? ? ? 3. 不是處于等待同一個窗口令牌的其它窗口的完成UI繪制的狀態(tài),即WindowState對象w的成員變量mReadyToShow的值等于false;
? ? ? ? 那么就說明現(xiàn)在就是時候要將WindowState對象w所描述的窗口顯示出來了,這是通過調(diào)用WindowManagerService類的成員函數(shù) showSurfaceRobustlyLocked來實(shí)現(xiàn)的。如果WindowManagerService類的成員函數(shù) showSurfaceRobustlyLocked的返回值等于true,那么就說明WindowManagerService服務(wù)已經(jīng)成功地通知 SurfaceFlinger服務(wù)將WindowState對象w所描述的窗口顯示出來,于是就會分別將WindowState對象w的成員變量 mHasDrawn和mLastHidden的值設(shè)置為true和false,以便可以表示W(wǎng)indowState對象w所描述的窗口的UI已經(jīng)繪制完 成,并且已經(jīng)顯示出來。
? ? ? ??WindowManagerService類的成員函數(shù)showSurfaceRobustlyLocked的實(shí)現(xiàn)如下所示:
[java] view plaincopy- public?class?WindowManagerService?extends?IWindowManager.Stub????
- ????????implements?Watchdog.Monitor?{????
- ????......????
- ????
- ????boolean?showSurfaceRobustlyLocked(WindowState?win)?{??
- ????????try?{??
- ????????????if?(win.mSurface?!=?null)?{??
- ????????????????win.mSurfaceShown?=?true;??
- ????????????????win.mSurface.show();??
- ????????????????......??
- ????????????}??
- ????????????return?true;??
- ????????}?catch?(RuntimeException?e)?{??
- ????????????......??
- ????????}??
- ??
- ????????reclaimSomeSurfaceMemoryLocked(win,?"show");??
- ??
- ????????return?false;??
- ????}??
- ????
- ????......????
- }????
? ? ? ??這個函數(shù)定義在文件frameworks/base/services/java/com/android/server/WindowManagerService.java中。
? ? ? ??WindowManagerService類的成員函數(shù)showSurfaceRobustlyLocked用來通知SurfaceFlinger服 務(wù)將參數(shù)win所描述的窗口顯示出來,這是通過調(diào)用WindowState對象win的成員變量mSurface所指向的一個Surface對象的成員函 數(shù)show來實(shí)現(xiàn)的。注意,在通知SurfaceFlinger服務(wù)將WindowState對象win所描述的窗口顯示出來之前,還會將它的成員變量 mSurfaceShown的值設(shè)置為true。
? ? ? ? 如果在通知SurfaceFlinger服務(wù)將WindowState對象win所描述的窗口顯示出來的過程出現(xiàn)了異常,那么 WindowManagerService類的成員函數(shù)showSurfaceRobustlyLocked就會調(diào)用另外一個成員函數(shù) reclaimSomeSurfaceMemoryLocked來回收系統(tǒng)內(nèi)存資源。
? ? ? ? 從上面分析可以知道,一個窗口的顯示和隱藏,以及大小、X軸和Y軸位置、Z軸位置、Alpha通道和變換矩陣設(shè)置,是通過調(diào)用Java層的Surface 類的成員函數(shù)show、hide、setSize、setPosition、setLayer、setAlpha和setMatrix來實(shí)現(xiàn)的,它們都是 一些JNI方法,定義在文件frameworks/base/core/java/android/view/Surface.java中,如下所示:
[java] view plaincopy- public?class?Surface?implements?Parcelable?{??
- ????......??
- ??
- ????private?int?mSurfaceControl;??
- ????......??
- ??
- ????/**?
- ?????*?set?surface?parameters.?
- ?????*?needs?to?be?inside?open/closeTransaction?block?
- ?????*/??
- ????public?native???void?setLayer(int?zorder);??
- ????public?native???void?setPosition(int?x,?int?y);??
- ????public?native???void?setSize(int?w,?int?h);??
- ??
- ????public?native???void?hide();??
- ????public?native???void?show();??
- ????......??
- ????public?native???void?setAlpha(float?alpha);??
- ????public?native???void?setMatrix(float?dsdx,?float?dtdx,??
- ???????????????????????????????????float?dsdy,?float?dtdy);??
- ????......??
- ??
- }??
? ? ? ?這些JNI方法是由C++層中的函數(shù)Surface_show、Surface_hide、Surface_setSize、 Surface_setPosition、Surface_setLayer、Surface_setAlpha和Surface_setMatrix來 實(shí)現(xiàn)的,如下所示:
[cpp] view plaincopy- static?void?Surface_setLayer(??
- ????????JNIEnv*?env,?jobject?clazz,?jint?zorder)??
- {??
- ????const?sp<SurfaceControl>&?surface(getSurfaceControl(env,?clazz));??
- ????if?(surface?==?0)?return;??
- ????status_t?err?=?surface->setLayer(zorder);??
- ????if?(err<0?&&?err!=NO_INIT)??
- ????????doThrow(env,?"java/lang/IllegalArgumentException",?NULL);??
- }??
- ??
- static?void?Surface_setPosition(??
- ????????JNIEnv*?env,?jobject?clazz,?jint?x,?jint?y)??
- {??
- ????const?sp<SurfaceControl>&?surface(getSurfaceControl(env,?clazz));??
- ????if?(surface?==?0)?return;??
- ????status_t?err?=?surface->setPosition(x,?y);??
- ????if?(err<0?&&?err!=NO_INIT)??
- ????????doThrow(env,?"java/lang/IllegalArgumentException",?NULL);??
- }??
- ??
- static?void?Surface_setSize(??
- ????????JNIEnv*?env,?jobject?clazz,?jint?w,?jint?h)??
- {??
- ????const?sp<SurfaceControl>&?surface(getSurfaceControl(env,?clazz));??
- ????if?(surface?==?0)?return;??
- ????status_t?err?=?surface->setSize(w,?h);??
- ????if?(err<0?&&?err!=NO_INIT)??
- ????????doThrow(env,?"java/lang/IllegalArgumentException",?NULL);??
- }??
- ??
- static?void?Surface_hide(??
- ????????JNIEnv*?env,?jobject?clazz)??
- {??
- ????const?sp<SurfaceControl>&?surface(getSurfaceControl(env,?clazz));??
- ????if?(surface?==?0)?return;??
- ????status_t?err?=?surface->hide();??
- ????if?(err<0?&&?err!=NO_INIT)??
- ????????doThrow(env,?"java/lang/IllegalArgumentException",?NULL);??
- }??
- ??
- static?void?Surface_show(??
- ????????JNIEnv*?env,?jobject?clazz)??
- {??
- ????const?sp<SurfaceControl>&?surface(getSurfaceControl(env,?clazz));??
- ????if?(surface?==?0)?return;??
- ????status_t?err?=?surface->show();??
- ????if?(err<0?&&?err!=NO_INIT)??
- ????????doThrow(env,?"java/lang/IllegalArgumentException",?NULL);??
- }??
- ??
- static?void?Surface_setAlpha(??
- ????????JNIEnv*?env,?jobject?clazz,?jfloat?alpha)??
- {??
- ????const?sp<SurfaceControl>&?surface(getSurfaceControl(env,?clazz));??
- ????if?(surface?==?0)?return;??
- ????status_t?err?=?surface->setAlpha(alpha);??
- ????if?(err<0?&&?err!=NO_INIT)??
- ????????doThrow(env,?"java/lang/IllegalArgumentException",?NULL);??
- }??
- ??
- static?void?Surface_setMatrix(??
- ????????JNIEnv*?env,?jobject?clazz,??
- ????????jfloat?dsdx,?jfloat?dtdx,?jfloat?dsdy,?jfloat?dtdy)??
- {??
- ????const?sp<SurfaceControl>&?surface(getSurfaceControl(env,?clazz));??
- ????if?(surface?==?0)?return;??
- ????status_t?err?=?surface->setMatrix(dsdx,?dtdx,?dsdy,?dtdy);??
- ????if?(err<0?&&?err!=NO_INIT)??
- ????????doThrow(env,?"java/lang/IllegalArgumentException",?NULL);??
- }??
? ? ? ? 這些JNI方法定義在文件frameworks/base/core/jni/android_view_Surface.cpp中。
? ? ? ? 這些JNI都有一個共同的特點(diǎn),即先調(diào)用函數(shù)getSurfaceControl來獲得與參數(shù)clazz所描述的一個Java層的Surface對象所對 應(yīng)的一個SurfaceControl對象。有了這個SurfaceControl對象之后,就可以分別調(diào)用它的成員函數(shù)show、hide、 setSize、setPosition、setLayer、setAlpha和setMatrix來通知SurfaceFlinger服務(wù)來顯示和隱藏 一個窗口,以及設(shè)置一個窗口大小、X軸和Y軸位置、Z軸位置、Alpha通道和變換矩陣。
? ? ? ? 從前面Android應(yīng)用程序窗口(Activity)的繪圖表面(Surface)的創(chuàng)建過程分析一 文可以知道,每一個Activity窗口在Java層都對應(yīng)有兩個Surface對象,其中一個位于應(yīng)用程序進(jìn)程這一側(cè),而另外一個位于 WindowManagerService服務(wù)這一側(cè)。每一個位于應(yīng)用程序進(jìn)程這一側(cè)的Java層的Surface對象在C++層中都對應(yīng)有一個 Surface對象,而每一個位于WindowManagerService服務(wù)這一側(cè)的Java層的Surface對象在C++層中都對應(yīng)有一個 SurfaceControl對象,這個C++層的SurfaceControl對象的地址就保存在Java層的Surface對象的成員變量 mSurfaceControl中。
? ? ? ?從上面的分析可以知道,我們目前正在操作的是正在位于WindowManagerService服務(wù)這一側(cè)的Java層的Surface對象,因此,通 過調(diào)用函數(shù)getSurfaceControl就可以在C++層中獲得一個對應(yīng)的SurfaceControl對象,而有了這個 SurfaceControl對象之后,就可以用來通知SurfaceFlinger服務(wù)更新一個窗口的屬性,這一點(diǎn)可以參考前面Android應(yīng)用程序與SurfaceFlinger服務(wù)的關(guān)系概述和學(xué)習(xí)計劃和Android系統(tǒng)Surface機(jī)制的SurfaceFlinger服務(wù)簡要介紹和學(xué)習(xí)計劃兩個系列的文章。
? ? ? ?至此,WindowManagerService服務(wù)計算窗口Z軸位置的過程就分析完成了,這個過程如下所示:
? ? ? ?1.?WindowManagerService服務(wù)將窗口排列在一個窗口堆棧中;
? ? ? ?2.?WindowManagerService服務(wù)根據(jù)窗口類型以及窗口在窗口堆棧的位置來計算得窗口的Z軸位置;
? ? ? ?3.?WindowManagerService服務(wù)通過Java層的Surface類的成員函數(shù)setLayer來將窗口的Z軸位置設(shè)置到SurfaceFlinger服務(wù)中去;
? ? ? ?4. Java層的Surface類的成員函數(shù)setLayer又是通過調(diào)用C++層的SurfaceControl類的成員函數(shù)setLayer來將窗口的Z軸位置設(shè)置到SurfaceFlinger服務(wù)中去的;
? ? ? ?通過這篇文章以及前面三篇文章(窗口組織、輸入法窗口、壁紙窗口) 的學(xué)習(xí),我們對WindowManagerService服務(wù)對窗口的管理就有一個比較深刻的認(rèn)識了,在接下來的文章中,我們還將繼續(xù)分析 ActivityWindowManager服務(wù)和WindowManagerService服務(wù)是如何協(xié)作來完成Activity窗口的顯示過程的,敬 請關(guān)注!
老羅的新浪微博:http://weibo.com/shengyangluo,歡迎關(guān)注!
轉(zhuǎn)載于:https://www.cnblogs.com/Free-Thinker/p/4143189.html
總結(jié)
以上是生活随笔為你收集整理的Android窗口管理服务WindowManagerService计算窗口Z轴位置的过程分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: GitHub上整理的一些工具【转载】
- 下一篇: 发出普通攻击是鱼的模样的武器叫什么?