Android窗口管理服务WindowManagerService计算窗口Z轴位置的过程分析
文章轉(zhuǎn)載至CSDN社區(qū)羅升陽(yáng)的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/8570428
通過(guò)前面幾篇文章的學(xué)習(xí),我們知道了在 Android系統(tǒng)中,無(wú)論是普通的Activity窗口,還是特殊的輸入法窗口和壁紙窗口,它們都是被WindowManagerService服務(wù)組 織在一個(gè)窗口堆棧中的,其中,Z軸位置較大的窗口排列在Z軸位置較小的窗口的上面。有了這個(gè)窗口堆棧之后,WindowManagerService服務(wù) 就可以按照一定的規(guī)則計(jì)算每一個(gè)窗口的Z軸位置了,本文就詳細(xì)分析這個(gè)計(jì)算過(guò)程。
? ? ? ? 基于窗口堆棧來(lái)計(jì)算窗口的Z軸位置是比較有意思的。按照一般的理解,應(yīng)該是先計(jì)算好窗口的Z軸位置,然后再按照Z(yǔ)軸位置的大小來(lái)將各個(gè)窗口排列在堆棧中。 但是,事實(shí)上,窗口是按照其它規(guī)則排列在堆棧中。這些規(guī)則與窗口的類型、創(chuàng)建順序和運(yùn)行狀態(tài)等有關(guān)。例如,狀態(tài)欄窗口總是位于堆棧的頂端,輸入法窗口總是 位于需要輸入法的窗口的上面,而壁紙窗口總是位于需要顯示壁紙的窗口的下面。又如,當(dāng)一個(gè)Activity組件從后臺(tái)激活到前臺(tái)時(shí),與它所對(duì)應(yīng)的窗口就會(huì) 被相應(yīng)地移動(dòng)到窗口堆棧的上面去。
? ? ? ? 從前面Android應(yīng)用程序與SurfaceFlinger服務(wù)的關(guān)系概述和學(xué)習(xí)計(jì)劃和Android系統(tǒng)Surface機(jī)制的SurfaceFlinger服務(wù)簡(jiǎn)要介紹和學(xué)習(xí)計(jì)劃這 兩個(gè)系列的文章可以知道,窗口的UI最終是需要通過(guò)SurfaceFlinger服務(wù)來(lái)統(tǒng)一渲染的,而SurfaceFlinger服務(wù)在渲染窗口的UI 之前,需要計(jì)算基于各個(gè)窗口的Z軸位置來(lái)計(jì)算它們的可見(jiàn)區(qū)域。因此,WindowManagerService服務(wù)計(jì)算好每一個(gè)窗口的Z軸位置之后,還需 要將它們?cè)O(shè)置到SurfaceFlinger服務(wù)中去,以便SurfaceFlinger服務(wù)可以正確地渲染每一個(gè)窗口的UI。
? ? ? ? 上述窗口的Z軸位置計(jì)算和設(shè)置過(guò)程如圖1所示:
圖1 窗口Z軸位置的計(jì)算和設(shè)置過(guò)程
? ? ? ? 接下來(lái),我們就首先分析兩個(gè)需要重新計(jì)算窗口Z軸位置的情景,接著再分析窗口的Z軸位置的計(jì)算過(guò)程,最后分析WindowManagerService服務(wù)將窗口的Z軸設(shè)置到SurfaceFlinger服務(wù)中去的過(guò)程。
? ? ? ? 一.?需要重新計(jì)算窗口Z軸位置的情景
? ? ? ? 這里主要分析兩個(gè)需要重新計(jì)算窗口Z軸位置的情景:應(yīng)用程序增加一個(gè)窗口到WindowManagerService服務(wù)和應(yīng)用程序請(qǐng)求WindowManagerService服務(wù)重新布局一個(gè)窗口。
? ? ? ??從前面Android應(yīng)用程序窗口(Activity)與WindowManagerService服務(wù)的連接過(guò)程分析一文可以知道,應(yīng)用程序請(qǐng)求增加一個(gè)窗口到WindowManagerService服務(wù)的時(shí)候,最終會(huì)調(diào)用到WindowManagerService類的成員函數(shù)addWindow。接下來(lái)我們就主要分析這個(gè)函數(shù)與重新計(jì)算窗口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();????
- ????
- ????????????......????
- ????????}????
- ????
- ????????......????
- ????}????
- ????
- ????......????
- }??????
? ? ? ??這個(gè)函數(shù)定義在文件frameworks/base/services/java/com/android/server/WindowManagerService.java中。
? ? ? ??WindowManagerService類的成員函數(shù)addWindow的具體實(shí)現(xiàn)可以參考Android窗口管理服務(wù)WindowManagerService對(duì)壁紙窗口(Wallpaper Window)的管理分析和Android窗口管理服務(wù)WindowManagerService對(duì)輸入法窗口(Input Method Window)的管理分析這兩篇文章。我們注意到,WindowManagerService類的成員函數(shù)addWindow會(huì)根據(jù)當(dāng)前正在添加的窗口的類型來(lái)調(diào)用不同的成員函數(shù)來(lái)向窗口堆棧的合適位置插入一個(gè)WindowState對(duì)象,即:
? ? ? ? 1. 如果添加的是一個(gè)輸入法窗口,那么就調(diào)用成員函數(shù)addInputMethodWindowToListLocked將它放置在需要顯示輸入法的窗口的上面去;
? ? ? ? 2. 如果添加的是一個(gè)輸入法對(duì)話框,那么就先調(diào)用成員函數(shù)addWindowToListInOrderLocked來(lái)將它插入到窗口堆棧中,接著再調(diào)用成員 函數(shù)adjustInputMethodDialogsLocked來(lái)將它放置在輸入法窗口的上面;
? ? ? ? 3. 如果添加的是一個(gè)普通窗口,那么就直接調(diào)用成員函數(shù)addWindowToListInOrderLocked來(lái)將它插入到窗口堆棧中;
? ? ? ? 4.?如果添加的是一個(gè)普通窗口,并且這個(gè)窗口需要顯示壁紙,那么就先調(diào)用成員函數(shù)addWindowToListInOrderLocked來(lái)將它插入 到窗口堆棧中,接著再調(diào)用成員函數(shù)adjustWallpaperWindowsLocked來(lái)將壁紙窗口放置在它的下面。
? ? ? ? 5.?如果添加的是一個(gè)壁紙窗口,那么就先調(diào)用成員函數(shù)addWindowToListInOrderLocked來(lái)將它插入到窗口堆棧中,接著再調(diào)用成 員函數(shù)adjustWallpaperWindowsLocked來(lái)將它放置在需要顯示壁紙的窗口的下面。
? ? ? ? 無(wú)論如何,WindowManagerService類的成員函數(shù)addWindow最終都會(huì)調(diào)用成員函數(shù)assignLayersLocked來(lái)重新計(jì)算系統(tǒng)中所有窗口的Z軸位置,這是因?yàn)榍懊嫱翱诙褩T黾恿艘粋€(gè)新的窗口。
? ? ? ??從前面Android窗口管理服務(wù)WindowManagerService計(jì)算Activity窗口大小的過(guò)程分析一 文可以知道,應(yīng)用程序進(jìn)程請(qǐng)求WindowManagerService服務(wù)重新布局一個(gè)窗口的時(shí)候,最終會(huì)調(diào)用到 WindowManagerService類的成員函數(shù)relayoutWindow。接下來(lái)我們就主要分析這個(gè)函數(shù)與重新計(jì)算窗口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);??????
- ????}??????
- ??????
- ????......??????
- }??????
? ? ? ??這個(gè)函數(shù)定義在文件frameworks/base/services/java/com/android/server/WindowManagerService.java中。
? ? ? ??WindowManagerService類的成員函數(shù)relayoutWindow具體實(shí)現(xiàn)可以參考Android窗口管理服務(wù)WindowManagerService對(duì)壁紙窗口(Wallpaper Window)的管理分析和Android窗口管理服務(wù)WindowManagerService對(duì)輸入法窗口(Input Method Window)的管理分析這兩篇文章,與窗口Z軸位置計(jì)算相關(guān)的邏輯大概是這樣的:
? ? ? ? 1. 如果系統(tǒng)當(dāng)前獲得焦點(diǎn)的窗口可能發(fā)生了變化,那么就會(huì)調(diào)用成員函數(shù)updateFocusedWindowLocked來(lái)重新計(jì)算系統(tǒng)當(dāng)前應(yīng)該獲得焦點(diǎn)的 窗口。如果系統(tǒng)當(dāng)前獲得焦點(diǎn)的窗口真的發(fā)生了變化,即窗口堆棧的窗口排列發(fā)生了變化,那么在調(diào)用成員函數(shù) updateFocusedWindowLocked的時(shí)候,就會(huì)調(diào)用成員函數(shù)assignLayersLocked來(lái)重新計(jì)算系統(tǒng)中所有窗口的Z軸位 置。
? ? ? ? 2. 如果系統(tǒng)中的輸入法窗口可能需要移動(dòng),那么就會(huì)調(diào)用成員函數(shù)moveInputMethodWindowsIfNeededLocked來(lái)檢查是否真的需 要移動(dòng)輸入法窗口。如果需要移動(dòng),那么成員函數(shù)moveInputMethodWindowsIfNeededLocked的返回值就會(huì)等于true,這 時(shí)候就說(shuō)明輸入法窗口在窗口堆棧中的位置發(fā)生了變化,因此,就會(huì)將變量assignLayers的值設(shè)置為true,表示接下來(lái)需要重新計(jì)算系統(tǒng)中所有窗 口的Z軸位置。
? ? ? ? 3. 如果當(dāng)前正在請(qǐng)求調(diào)整其布局的窗口是由不可見(jiàn)變化可見(jiàn)的,即變量displayed的值等于true,那么接下來(lái)也是需要重新計(jì)算系統(tǒng)中所有窗口的Z軸位置的,因此,就會(huì)將assignLayers的值設(shè)置為true。
? ? ? ? 4.?如果系統(tǒng)中的壁紙窗口可能需要移動(dòng),那么就會(huì)調(diào)用成員函數(shù)adjustWallpaperWindowsLocked來(lái)檢查是否真的需要移動(dòng)壁紙窗 口。如果需要移動(dòng),那么成員函數(shù)adjustWallpaperWindowsLocked的返回值的 ADJUST_WALLPAPER_LAYERS_CHANGED位就會(huì)等于1,這時(shí)候就說(shuō)明壁紙窗口在窗口堆棧中的位置發(fā)生了變化,因此,就會(huì)將變量 assignLayers的值設(shè)置為true,表示接下來(lái)需要重新計(jì)算系統(tǒng)中所有窗口的Z軸位置。
? ? ? ? 經(jīng)過(guò)上述的一系列操作后,如果得到的變量assignLayers的值設(shè)置等于true,那么WindowManagerService類的成員函數(shù) relayoutWindow就會(huì)調(diào)用成員函數(shù)assignLayersLocked來(lái)重新計(jì)算系統(tǒng)中所有窗口的Z軸位置。
? ? ? ? 二.?計(jì)算系統(tǒng)中所有窗口的Z軸位置
? ? ? ? 從前面第一部分的內(nèi)容可以知道,一旦窗口堆棧中的窗口發(fā)生了變化,那么WindowManagerService類的成員函數(shù)assignLayersLocked就會(huì)調(diào)用來(lái)計(jì)算系統(tǒng)中所有窗口的Z軸位置。
? ? ? ? 窗口的Z軸位置除了與它在窗口堆棧中的位置有關(guān)之外,還與窗口的類型有關(guān)。窗口的類型在創(chuàng)建的時(shí)候就已經(jīng)是確定了 的,WindowManagerService服務(wù)在為它創(chuàng)建一個(gè)WindowState對(duì)象的時(shí)候,就會(huì)根據(jù)它的類型得到一個(gè)BaseLayer值,這 個(gè)BaseLayer值在計(jì)算它的Z軸位置的時(shí)候會(huì)用到。
? ? ? ? 接下來(lái)我們就通過(guò)WindowState類的構(gòu)造函數(shù)來(lái)分析一個(gè)窗口的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;??
- ????????????????......??
- ????????????}??
- ??
- ????????????......??
- ????????}??
- ??
- ????????......??
- ????}??
- ??
- ????......??
- }??
? ? ? ??這個(gè)函數(shù)定義在文件frameworks/base/services/java/com/android/server/WindowManagerService.java中。
? ? ? ??一個(gè)窗口除了有一個(gè)BaseLayer值之外,還有一個(gè)SubLayer值,分別保存在一個(gè)對(duì)應(yīng)的WindowState對(duì)象的成員變量mBaseLayer和mSubLayer。SubLayer值是用來(lái)描述一個(gè)窗口是否是另外一個(gè)窗口的子窗口的。
? ? ? ? 假設(shè)一個(gè)窗口是另外一個(gè)窗口的子窗口,那么參數(shù)attachedWindow所描述的窗口就是父窗口,這時(shí)候子窗口的BaseLayer值就等于父窗口的BaseLayer值,而SubLayer值要么大于0,要么小于0,這與它自己的具體類型有關(guān)。
? ? ? ??假設(shè)一個(gè)窗口不是另外一個(gè)窗口的子窗口,那么這個(gè)窗口的BaseLayer值就與它自己的具體類型有關(guān),而SubLayer值就等于0。
? ? ? ? 現(xiàn)在的關(guān)鍵就是要根據(jù)窗口的類型來(lái)計(jì)算它的BaseLayer值和SubLayer值,它們分別是通過(guò)調(diào)用WindowManagerService類的 成員變量mPolicy所指向的一個(gè)PhoneWindowManager對(duì)象的成員函數(shù)windowTypeToLayerLw和 subWindowTypeToLayerLw來(lái)計(jì)算得到的。這里有兩個(gè)地方是需要注意的。
? ? ? ? 第一個(gè)地方是PhoneWindowManager對(duì)象的成員函數(shù)windowTypeToLayerLw的返回值并且不是一個(gè)窗口的最終的 BaseLayer值,而是要將它的返回值乘以一個(gè)常量TYPE_LAYER_MULTIPLIER,再加上另外一個(gè)常量 TYPE_LAYER_OFFSET之后,才得到最終的BaseLayer值。這是因?yàn)樵贏ndroid系統(tǒng)中,相同類型的窗口的Z軸位置都是有著相同的 值域,而不同類型的窗口的Z軸位置都是處于兩個(gè)不相交的值域。例如,假設(shè)有兩種不同類型的窗口,它們的Z軸位置的值域分別為[a, b]和[c, d],那么[a, b]和[c, d]的交集一定等于空。又由于每一種類型的窗口的數(shù)量是不確定的,因此,WindowManagerService服務(wù)就需要為每一種類型的窗口都預(yù)留一 個(gè)范圍足夠大的值域,以便可以滿足要求。
? ? ? ?WindowManagerService服務(wù)是如何為類型相同的窗口的Z軸位置預(yù)留一個(gè)范圍足夠大的值域的呢?我們假設(shè)類型為t的窗口的Z軸位置的值 域?yàn)閇a, b],并且以t為參數(shù)調(diào)用PhoneWindowManager對(duì)象的成員函數(shù)windowTypeToLayerLw的返回值為T(mén),那么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開(kāi)始,一共預(yù)留了TYPE_LAYER_MULTIPLIER個(gè)值作為類型為t窗口的Z軸位置。由于 TYPE_LAYER_MULTIPLIER的值定義為10000,而TYPE_LAYER_OFFSET的值定義為1000,因此,每一種類型的窗口都 預(yù)留有一個(gè)足夠大的值域來(lái)作為Z軸位置。
? ? ? ?第二個(gè)地方是窗口的SubLayer值并不直接參與窗口的Z軸位置的計(jì)算,但是它會(huì)影響到窗口在窗口堆棧的位置。接下來(lái)我們就會(huì)看到,窗口在窗口堆棧的位置是會(huì)影響到它的Z軸位置的計(jì)算的,因此,窗口的SubLayer間接地參與了窗口的Z軸位置的計(jì)算。
? ? ? ?窗口的SubLayer值是如何影響到窗口在窗口堆棧的位置的呢?在前面Android窗口管理服務(wù)WindowManagerService對(duì)窗口的組織方式分析一 文中,在分析WindowManagerService類的成員函數(shù)addWindowToListInOrderLocked的實(shí)現(xiàn)時(shí)提到,如果一個(gè)窗 口是另外一個(gè)窗口的子窗口,那么當(dāng)它的SubLayer值小于0的時(shí)候,它就會(huì)位于父窗口的下面,否則的話,就會(huì)位于父窗口的上面。
? ? ? ?在繼續(xù)分析WindowManagerService類的成員函數(shù)assignLayersLocked之前,我們首先分析 PhoneWindowManager類的成員函數(shù)windowTypeToLayerLw和subWindowTypeToLayerLw的實(shí)現(xiàn),以便 可以了解一個(gè)窗口的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;??
- ????}??
- ??
- ????......??
- }??
? ? ? ?這個(gè)函數(shù)定義在frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java文件中。
? ? ? ?從這里就可以看出,每一種窗口類型type都對(duì)應(yīng)有一個(gè)BaseLayer值,即每一個(gè)TYPE_XXX值都對(duì)應(yīng)有一個(gè)XXX_LAYER值,其 中,TYPE_XXX值定義在WindowManager.LayoutParams類中,而XXX_LAYER值就定義在 PhoneWindowManager類中,它們的對(duì)應(yīng)關(guān)系如圖2所示:
圖2 窗口類型與窗口BaseLayer值的對(duì)應(yīng)關(guān)系
? ? ? ?注意,如果參數(shù)type的值小于FIRST_APPLICATION_WINDOW,或者大于LAST_APPLICATION_WINDOW,或者不 是圖2列出來(lái)的其中一個(gè)值,那么PhoneWindowManager類的成員函數(shù)windowTypeToLayerLw就會(huì)返回一個(gè) 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;??
- ????}??
- ??
- ????......??
- }??
? ? ? ??這個(gè)函數(shù)定義在frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java文件中。
? ? ? ??從這里就可以看出,只有類型為T(mén)YPE_APPLICATION_PANEL、TYPE_APPLICATION_MEDIA、 TYPE_APPLICATION_MEDIA_OVERLAY和TYPE_APPLICATION_SUB_PANEL的窗口才對(duì)應(yīng)有一個(gè) SubLayer值,它們的對(duì)應(yīng)關(guān)系如圖3所示:
圖3 窗口類型與窗口SubLayer值的對(duì)應(yīng)關(guān)系
? ? ? ? 在圖3中,TYPE_XXX值定義在WindowManager.LayoutParams類中,而XXX_LAYER值就定義在 PhoneWindowManager類中。注意,有兩種特殊的多媒體窗口TYPE_APPLICATION_MEDIA和 TYPE_APPLICATION_MEDIA_OVERLAY,它們是用來(lái)顯示多媒體的,例如,用來(lái)顯示視頻,并且它們都是附加在應(yīng)用程序窗口之上的, 但是由于它們的SubLayer值為負(fù)數(shù),因此它們實(shí)際上是位于宿主窗口之下的。類型為T(mén)YPE_APPLICATION_MEDIA的窗口有一個(gè)魔術(shù), 它會(huì)在宿主窗口里面挖一個(gè)洞,以便可以將自己顯示出來(lái),而類型為T(mén)YPE_APPLICATION_MEDIA_OVERLAY背景一般都是透明的,位于 類型為T(mén)YPE_APPLICATION_MEDIA的窗口,可以用來(lái)顯示視頻的字幕之類的東西。實(shí)際上,類型為 TYPE_APPLICATION_MEDIA和TYPE_APPLICATION_MEDIA_OVERLAY的窗口也稱為SurfaceView。 SurfaceView很特殊,它與普通的View的最大區(qū)別就在于它們有獨(dú)立的繪圖表面,于是它們就可以在一個(gè)獨(dú)立的子線程里面進(jìn)行UI渲染。
? ? ? ? 理解了窗口的BaseLayer值和SubLayer值的計(jì)算過(guò)程之外,接下來(lái)我們就可以分析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;??
- ????????????}??
- ????????????......??
- ????????}??
- ????}??
- ???
- ????......??
- }??
? ? ? ??這個(gè)函數(shù)定義在文件frameworks/base/services/java/com/android/server/WindowManagerService.java中。
? ? ? ? 注意,在調(diào)用WindowManagerService類的成員函數(shù)assignLayersLocked之前,系統(tǒng)中的所有窗口在窗口堆棧中的位置都是 已經(jīng)排列好了的,這時(shí)候WindowManagerService類的成員函數(shù)assignLayersLocked就從下往上遍歷窗口堆棧,以連排列在 一起的類型相同的窗口為單位來(lái)計(jì)算每一個(gè)窗口的Z位置,即:
? ? ? ? 1. 每次遇到一個(gè)窗口,它的BaseLayer值與上一次計(jì)算的窗口的BaseLayer值不相等,就開(kāi)始一個(gè)新的計(jì)算單元。
? ? ? ? 2. 在每一個(gè)計(jì)算單元中,第一個(gè)窗口的Z軸位置就等于它的BaseLayer值,而之后的每一個(gè)窗口的Z軸位置都比前一個(gè)窗口的Z軸位置大WINDOW_LAYER_MULTIPLIER。
? ? ? ? 這個(gè)窗口的Z軸位置計(jì)算方法有三個(gè)地方是需要注意的。 ? ? ? ?
? ? ? ? 第一個(gè)地方是從第2點(diǎn)可以看出,每一個(gè)窗口的Z軸位置值都不是連續(xù)的,這樣就在每?jī)蓚€(gè)窗口之間都保留了一定的位置來(lái)插入其它窗口。
? ? ? ? 第二個(gè)地方是由于系統(tǒng)中所有類型相同的窗口不一定都是排列在一起的,因此,就有可能出現(xiàn)有些類型相同的窗口具有相同的Z軸位置。 WindowManagerService服務(wù)并不關(guān)心兩個(gè)不同窗口的Z軸位置是否相同,但是SurfaceFlinger服務(wù)就需要關(guān)心了,因?yàn)?SurfaceFlinger服務(wù)需要是按照Z(yǔ)軸從大到小的順序來(lái)計(jì)算窗口的可見(jiàn)性。那么SurfaceFlinger服務(wù)是如何確定兩個(gè)Z軸位置相同的 窗口的次序的呢?從前面Android應(yīng)用程序與SurfaceFlinger服務(wù)的關(guān)系概述和學(xué)習(xí)計(jì)劃和Android系統(tǒng)Surface機(jī)制的SurfaceFlinger服務(wù)簡(jiǎn)要介紹和學(xué)習(xí)計(jì)劃這 兩個(gè)系列的文章可以知道,每一個(gè)窗口在SurfaceFlinger服務(wù)都對(duì)應(yīng)有一個(gè)Layer對(duì)象,而每一個(gè)Layer對(duì)象都有一個(gè)sequence 值,其中,先創(chuàng)建的Layer對(duì)象的sequence值大于后創(chuàng)建的Layer對(duì)象的sequence值。這樣,SurfaceFlinger服務(wù)在計(jì)算 對(duì)于兩個(gè)Z軸位置相同的窗口的可見(jiàn)性的時(shí)候,就會(huì)比較它們所對(duì)應(yīng)的Layer對(duì)象的sequence值,其中,sequence值大的窗口的可見(jiàn)性會(huì)先于 sequence值小的窗口得到計(jì)算,即先計(jì)算后創(chuàng)建的窗口的可見(jiàn)性,再計(jì)算先創(chuàng)建的窗口的可見(jiàn)性。
? ? ? ? 第三個(gè)地方是有兩種特殊的窗口,即輸入法窗口和壁紙窗口,當(dāng)它們不是窗口堆棧底部的第一個(gè)窗口時(shí),它們所在的計(jì)算單元不是以窗口類型來(lái)劃分的,而靠近在哪 個(gè)窗口,就與哪個(gè)窗口在同一個(gè)計(jì)算單元中。當(dāng)輸入法窗口是窗口堆棧底部的第一個(gè)窗口時(shí),它的Z軸位置就等于 WINDOW_LAYER_MULTIPLIER,而當(dāng)壁紙窗口是窗口堆棧底部的第一個(gè)窗口時(shí),它的Z軸位置就等于它的BaseLayer值。
? ? ? ??前面計(jì)算得到的窗口的Z軸位置保存在WindowState類的成員變量mLayer中。事實(shí)上,保存在WindowState類的成員變量 mLayer中的Z軸位置還不是窗口的最終Z軸位置,因?yàn)檫€沒(méi)有考慮到窗口與窗口令牌之間的關(guān)系。每一個(gè)窗口令牌都可以設(shè)置一個(gè)Z軸調(diào)整值,而每一個(gè)窗口 要加上它所對(duì)應(yīng)的窗口令牌所設(shè)置的Z軸調(diào)整值之后,才能得到最終的Z軸位置。注意,只有類型為AppWindowToken的窗口令牌才可以設(shè)置Z軸調(diào)整 值,這個(gè)Z軸調(diào)整值就保存在AppWindowToken類的成員變量animLayerAdjustment中。
? ? ? ? 有時(shí)候,一個(gè)窗口會(huì)有一個(gè)目標(biāo)窗口。例如,輸入法窗口的目標(biāo)窗口是系統(tǒng)當(dāng)前需要顯示輸入法的窗口。在這種情況下,我們要使用目標(biāo)窗口所對(duì)應(yīng)的窗口令牌所設(shè)置的Z軸調(diào)整值來(lái)調(diào)整窗口的的Z軸位置。
? ? ? ? 那么,WindowManagerService服務(wù)是如何知道一個(gè)窗口所對(duì)應(yīng)的窗口令牌的類型是AppWindowToken,或者一個(gè)窗口有沒(méi)有目標(biāo) 窗口的呢?當(dāng)用來(lái)描述一個(gè)窗口的WindowState對(duì)象成員變量mAppToken的值不等于null的時(shí)候,那么就說(shuō)明該窗口所對(duì)應(yīng)的窗口令牌的類 型是AppWindowToken,而當(dāng)用來(lái)描述一個(gè)窗口的WindowState對(duì)象成員變量mTargetAppToken的值不等于null的時(shí) 候,那么就說(shuō)明該窗口有一個(gè)目標(biāo)窗口。
? ? ? ? 經(jīng)過(guò)上面的調(diào)整之后,窗口的Z軸位置就保存在WindowState類的成員變量mAnimLayer中。對(duì)于非輸入法窗口和非壁紙窗口來(lái)說(shuō),這時(shí)候保存 在用來(lái)描述它們的WindowState對(duì)象的成員變量mAnimLayer中的Z軸位置就是它們最終的Z軸位置了,但是對(duì)于輸入法窗口和壁紙窗口來(lái)說(shuō), 還需要繼續(xù)判斷它們的目標(biāo)窗口是否需要調(diào)整它們的Z軸位置。
? ? ? ? 從前面Android窗口管理服務(wù)WindowManagerService對(duì)壁紙窗口(Wallpaper Window)的管理分析和Android窗口管理服務(wù)WindowManagerService對(duì)輸入法窗口(Input Method Window)的管理分析這 兩篇文章知道,如果一個(gè)窗口要調(diào)整它所關(guān)聯(lián)的輸入法窗口和壁紙窗口的Z軸位置,那么要調(diào)整的值就會(huì)保存在WindowManagerService類的成 員變量mInputMethodAnimLayerAdjustment和mWallpaperAnimLayerAdjustment中,因此,只要將 WindowManagerService類的成員變量mInputMethodAnimLayerAdjustment和 mWallpaperAnimLayerAdjustment的值分別增加到前面所計(jì)算得到的輸入法窗口和壁紙窗口的Z軸位置上去,就可以得到輸入法窗口 和壁紙窗口的最終Z軸位置,并且保存到用來(lái)對(duì)應(yīng)的WindowState對(duì)象的成員變量mAnimLayer中。
? ? ? ? 從上面的計(jì)算過(guò)程就可以知道,系統(tǒng)中所有類型的窗口的最終Z軸位置都保存在WindowState類的成員變量mAnimLayer中。
? ? ? ? 三. 設(shè)置窗口的Z軸位置到SurfaceFlinger服務(wù)中去
? ? ? ? WindowManagerService服務(wù)在刷新系統(tǒng)的UI的時(shí)候,就會(huì)將系統(tǒng)中已經(jīng)計(jì)算好了的窗口Z軸位置設(shè)置到SurfaceFlinger服務(wù)中去,以便SurfaceFlinger服務(wù)可以對(duì)系統(tǒng)中的窗口進(jìn)行可見(jiàn)性計(jì)算以及合成和渲染等操作。
? ? ? ? 從前面Android窗口管理服務(wù)WindowManagerService計(jì)算Activity窗口大小的過(guò)程分析一 文可以知道,刷新系統(tǒng)UI是通過(guò)調(diào)用WindowManagerService類的成員函數(shù) performLayoutAndPlaceSurfacesLockedInner來(lái)實(shí)現(xiàn)的,接下來(lái)我們就分析這個(gè)成員函數(shù)與設(shè)置窗口的Z軸位置到 SurfaceFlinger服務(wù)中去相關(guān)的邏輯。
? ? ? ? 為了方便描述設(shè)置窗口的Z軸位置到SurfaceFlinger服務(wù)中去的過(guò)程,我們先列出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?????
- ????????......????
- ????}????
- ????
- ????......????
- }????
? ? ? ??這個(gè)函數(shù)定義在文件frameworks/base/services/java/com/android/server/WindowManagerService.java中。
? ? ? ? 在前面Android窗口管理服務(wù)WindowManagerService計(jì)算Activity窗口大小的過(guò)程分析一 文中,我們已經(jīng)分析過(guò)WindowManagerService類的成員函數(shù) performLayoutAndPlaceSurfacesLockedInner的實(shí)現(xiàn)架構(gòu)了,其中,設(shè)置窗口的Z軸位置到 SurfaceFlinger服務(wù)中去是在更新窗口的繪圖表面的操作中進(jìn)行的,即是在THIRD LOOP中進(jìn)行的,同時(shí)設(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;??
- ????????????????}???
- ????????}????
- ??
- ????????......??
- ????}??
- ??
- ????......????????????????????????????
- }??
? ? ? ? 這段代碼通過(guò)一個(gè)for循環(huán)來(lái)遍歷保存在窗口堆棧的每一個(gè)WindowState對(duì)象,以便可以對(duì)系統(tǒng)中的每一個(gè)窗口的繪圖表面進(jìn)行更新。注意,只有那些 成員變量mSurface的值不等于null的WindowState對(duì)象,它們所描述的窗口才具有繪圖表面,因此需要對(duì)它們進(jìn)行更新。
? ? ? ? 在更新WindowState對(duì)象w所描述的窗口的繪圖表面之前,首先要調(diào)用它的成員函數(shù)computeShownFrameLocked來(lái)確定該窗口實(shí)際要顯示的大小、位置、Alpha通道和變換矩陣等信息,其中:
? ? ? ? 1.?窗口實(shí)際要顯示的大小和X軸、Y軸位置保存在WindowState對(duì)象w的成員變量mShownFrame中。
? ? ? ? 2.?窗口實(shí)際要顯示的Alpha通道保存在WindowState對(duì)象w的成員變量mShownAlpha中。
? ? ? ? 3.?窗口實(shí)際要顯示的Z軸位置保存在WindowState對(duì)象w的成員變量mAnimLayer中。
? ? ? ? 4.?窗口實(shí)際要使用的變換矩陣保存在WindowState對(duì)象w的成員變量mDsDx、mDtDx、mDsDy和mDtDy中。
? ? ? ? 有了上述信息之后,我們就可以將WindowState對(duì)象w所描述的窗口實(shí)際要顯示的大小、位置、Alpha通道和變換矩陣等信息設(shè)置到SurfaceFlinger服務(wù)中去了。
? ? ? ? 我們首先分析WindowState對(duì)象w所描述的窗口實(shí)際要顯示的大小、X軸和Y軸位置的設(shè)置過(guò)程,接著再分析WindowState對(duì)象w所描述的窗口實(shí)際要顯示的Alpha通道、Z軸位置以及實(shí)際要使用的變換矩陣的設(shè)置過(guò)程。
? ? ? ? 在調(diào)用WindowState對(duì)象w的成員函數(shù)computeShownFrameLocked來(lái)計(jì)算它所描述的窗口的大小的時(shí)候,是沒(méi)有考慮該窗口的大小是否設(shè)置有縮放因子的。
? ? ? ? 當(dāng)WindowState對(duì)象w所描述的窗口的大小設(shè)置有縮放因子的時(shí)候,那么WindowState對(duì)象w的成員變量mAttrs所指向的一個(gè) WindowManager.LayoutParams對(duì)象的成員變量flags的FLAG_SCALED位就會(huì)等于1,這時(shí)候WindowState對(duì) 象w所描述的窗口實(shí)際要顯示的大小是保存在它的成員變量mRequestedWidth和mRequestedHeight中的。在這種情況下,這段代碼 就會(huì)執(zhí)行以下操作:
? ? ? ? 1. 計(jì)算WindowState對(duì)象w所描述的窗口實(shí)際要顯示的大小是否發(fā)生了變化。如果發(fā)生了變化,那么就將變量resize的值設(shè)置為true。注 意,WindowState對(duì)象w所描述的窗口上一次實(shí)際要顯示的大小保存在成員變量mLastRequestedWidth和 mLastRequestedHeight中,因此,當(dāng)這兩個(gè)成員變量與其它兩個(gè)成員變量mRequestedWidth和 mRequestedHeight的值不相等于時(shí),就說(shuō)明WindowState對(duì)象w所描述的窗口實(shí)際要顯示的大小是否發(fā)生了變化。
? ? ? ? 2. 將WindowState對(duì)象w所描述的窗口實(shí)際要顯示的大小分別更新到成員變量mLastRequestedWidth和mLastRequestedHeight中,以及變量width和height中。
? ? ? ? 3. 將WindowState對(duì)象w的成員變量mShownFrame的值保存在另外一個(gè)成員變量mLastShownFrame中,以便可以記錄WindowState對(duì)象w所描述的窗口上一次實(shí)際要顯示的大小和X軸、Y軸位置。
? ? ? ? 4. 將WindowState對(duì)象w所描述的窗口的X軸和Y軸位置分別保存到成員變量mSurfaceX和mSurfaceY中,并且調(diào)用 WindowState對(duì)象w的成員變量mSurface所指向的一個(gè)Surface對(duì)象的成員函數(shù)setPosition來(lái)將這兩個(gè)位置值設(shè)置到 SurfaceFlinger服務(wù)中去。
? ? ? ? 5. 在設(shè)置WindowState對(duì)象w所描述的窗口的X軸和Y軸位置到SurfaceFlinger服務(wù)中去的過(guò)程中,如果出現(xiàn)了異常,那么就說(shuō)明系統(tǒng)內(nèi)存 資源不足。在這種情況下,如果參數(shù)recoveringMemory的值等于false,那么就說(shuō)明WindowManagerService服務(wù)目前不 是處于內(nèi)存資源的回收過(guò)程中,于是就會(huì)調(diào)用WindowManagerService類的成員函數(shù) reclaimSomeSurfaceMemoryLocked來(lái)執(zhí)行回收系統(tǒng)內(nèi)存資源的操作。
? ? ? ??當(dāng)WindowState對(duì)象w所描述的窗口的大小沒(méi)有設(shè)置有縮放因子的時(shí)候,那么WindowState對(duì)象w的成員變量mAttrs所指向的一個(gè) WindowManager.LayoutParams對(duì)象的成員變量flags的FLAG_SCALED位就會(huì)等于0,這時(shí)候WindowState對(duì) 象w所描述的窗口實(shí)際要顯示的大小是保存在它的成員變量mShownFrame中的。在這種情況下,這段代碼就會(huì)執(zhí)行以下操作:
? ? ? ? 1.?計(jì)算WindowState對(duì)象w所描述的窗口實(shí)際要顯示的大小是否發(fā)生了變化。如果發(fā)生了變化,那么就將變量resize的值設(shè)置為true。注 意,這時(shí)候只要比較WindowState對(duì)象w的成員變量mLastShownFrame和mShownFrame所描述的兩個(gè)矩形區(qū)域的大小是否相 等,就可以知道WindowState對(duì)象w所描述的窗口實(shí)際要顯示的大小是否發(fā)生了變化,因?yàn)閃indowState對(duì)象w的成員變量 mLastShownFrame保存的是窗口上一次實(shí)際要顯示的大小。
? ? ? ? 2.?將WindowState對(duì)象w所描述的窗口實(shí)際要顯示的大小分別保存在變量width和height中。
? ? ? ? 3.?將WindowState對(duì)象w的成員變量mShownFrame的值保存在另外一個(gè)成員變量mLastShownFrame中,以便可以記錄WindowState對(duì)象w所描述的窗口上一次實(shí)際要顯示的大小和X軸、Y軸位置。
? ? ? ? 執(zhí)行完成以上操作之后,WindowState對(duì)象w所描述的窗口實(shí)際要顯示的X軸和Y軸位置就保存在成員變量mShownFrame所描述的一個(gè) Rect對(duì)象的成員變量left和top中,而實(shí)際要顯示的大小就顯示在變量width和height中。這時(shí)候如果變量resize的值等于true, 那么就說(shuō)明WindowState對(duì)象w所描述的窗口的大小發(fā)生了變化。在這種情況下,就需要執(zhí)行以下操作:
? ? ? ? 1. 重新設(shè)置WindowState對(duì)象w所描述的窗口的大小到SurfaceFlinger服務(wù)中去,這是通過(guò)調(diào)用WindowState對(duì)象w的成員變量 mSurface所指向的一個(gè)Surface對(duì)象的成員函數(shù)setSize來(lái)實(shí)現(xiàn)的。注意,如果前面計(jì)算得到WindowState對(duì)象w所描述的窗口的 寬度width和高度height的值小于1,那么就需要將它們的值設(shè)置為1,因?yàn)橐粋€(gè)窗口的寬度和高度值是不能小于1的。
? ? ? ? 2. 重新設(shè)置WindowState對(duì)象w所描述的窗口在X軸和Y軸上的位置到SurfaceFlinger服務(wù)中去,這是通過(guò)調(diào)用WindowState對(duì) 象w的成員變量mSurface所指向的一個(gè)Surface對(duì)象的成員函數(shù)setPosition來(lái)實(shí)現(xiàn)的。注意,在設(shè)置之前,還會(huì)將 WindowState對(duì)象w所描述的窗口在X軸和Y軸上的位置保存在成員變量mSurfaceX和mSurfaceY中。
? ? ? ? 3.?在設(shè)置WindowState對(duì)象w所描述的窗口的大小以及在X軸和Y軸上的位置到SurfaceFlinger服務(wù)中去的過(guò)程中,如果出現(xiàn)了異 常,那么同樣需要判斷參數(shù)recoveringMemory的值來(lái)決定是否需要WindowManagerService類的成員函數(shù) reclaimSomeSurfaceMemoryLocked來(lái)回收系統(tǒng)內(nèi)存資源。
? ? ? ? 設(shè)置好WindowState對(duì)象w所描述的窗口實(shí)際要顯示的大小、X軸和Y軸位置到SurfaceFlinger服務(wù)中去之后,接下來(lái)就要繼續(xù)設(shè)置它實(shí) 際要顯示的Alpha通道、Z軸位置以及實(shí)際要使用的變換矩陣了,不過(guò)只有當(dāng)WindowState對(duì)象w所描述的窗口當(dāng)前是處于可見(jiàn)狀態(tài)、并且這些值沒(méi) 有發(fā)生變化的情況下才需要這樣做。
? ? ? ? 當(dāng)WindowState對(duì)象w的成員函數(shù)isReadyForDisplay的返回值等于false時(shí),就說(shuō)明WindowState對(duì)象w所描述的窗 口當(dāng)前是處于不可見(jiàn)狀態(tài)的。還有另外一種情況,即當(dāng)WindowState對(duì)象w所描述的窗口是附加在另外一個(gè)窗口之上、并且這個(gè)被附加的窗口是不可見(jiàn) 時(shí),即WindowState對(duì)象w的成員變量mAttachedHidden的值等于true時(shí),也是說(shuō)明WindowState對(duì)象w所描述的窗口當(dāng) 前是處于不可見(jiàn)狀態(tài)的。
? ? ? ? 在WindowState對(duì)象w所描述的窗口當(dāng)前是處于不可見(jiàn)狀態(tài)的情況下,如果該窗口在上一次系統(tǒng)UI刷新時(shí)是處于可見(jiàn)狀態(tài)的,即 WindowState對(duì)象w的成員變量mLastHidden的值等于true,那么這時(shí)候就需要將WindowState對(duì)象w所描述的窗口隱藏起 來(lái),這是通過(guò)調(diào)用WindowState對(duì)象w的成員變量mSurface所指向的一個(gè)Surface對(duì)象的成員函數(shù)hide來(lái)實(shí)現(xiàn)的。注意,在調(diào)用 WindowState對(duì)象w的成員變量mSurface所指向的一個(gè)Surface對(duì)象的成員函數(shù)hide來(lái)隱藏窗口之前,需要分別將 WindowState對(duì)象w的成員變量mLastHidden和mSurfaceShown的值設(shè)置為true和false,以便可以正確描述窗口的不 可見(jiàn)狀態(tài)。
? ? ? ??在WindowState對(duì)象w所描述的窗口當(dāng)前是處于可見(jiàn)狀態(tài)的情況下,如果該窗口實(shí)際要顯示的Alpha通道、Z軸位置以及實(shí)際要使用的變換矩陣發(fā)生了變化,那么就需要將新的值設(shè)置到SurfaceFlinger服務(wù)中去,其中:
? ? ? ? 1.?WindowState對(duì)象w的成員變量mLastLayer與mAnimLayer的值不相等說(shuō)明它描述的窗口的Z軸位置發(fā)生了變化。
? ? ? ? 2.?WindowState對(duì)象w的成員變量mLastAlpha與mShownAlpha的值不相等說(shuō)明它描述的窗口的Alpha通道發(fā)生了變化。
? ? ? ? 3.?WindowState對(duì)象w的成員變量mLastDsDx、mLastDtDx、mLastDsDy、 mLastDtDy、mLastHScale、mLastVScale與成員變量mDsDx、mDtDx、mDsDy、?mDtDy、mHScale、 mVScale的值不相等說(shuō)明它描述的窗口的變換矩陣發(fā)生了變化。
? ? ? ??在WindowState對(duì)象w所描述的窗口當(dāng)前是處于可見(jiàn)狀態(tài)的情況下,如果該窗口在上一次系統(tǒng)UI刷新時(shí)是處于可見(jiàn)狀態(tài)的,即 WindowState對(duì)象w的成員變量mLastHidden的值等于true,那么也是需要重新設(shè)置WindowState對(duì)象w所描述的窗口實(shí)際要 顯示的Alpha通道、Z軸位置以及實(shí)際要使用的變換矩陣到SurfaceFlinger服務(wù)中去的。
? ? ? ? 無(wú)論如何,當(dāng)需要重新設(shè)置WindowState對(duì)象w所描述的窗口實(shí)際要顯示的Alpha通道、Z軸位置以及實(shí)際要使用的變換矩陣到SurfaceFlinger服務(wù)中去時(shí),就需要執(zhí)行以下操作:
? ? ? ? 1. 重新設(shè)置WindowState對(duì)象w所描述的窗口的Alpha通道到SurfaceFlinger服務(wù)中去,這是通過(guò)調(diào)用WindowState對(duì)象w 的成員變量mSurface所指向的一個(gè)Surface對(duì)象的成員函數(shù)setAlpha來(lái)實(shí)現(xiàn)的。在設(shè)置之前,還會(huì)將WindowState對(duì)象w的成員 變量mShownAlpha的值同時(shí)保存在成員變量mLastAlpha和mSurfaceAlpha中,以便可以記錄WindowState對(duì)象w所描 述的窗口上一次所使用的Alpha通道。
? ? ? ? 2.?重新設(shè)置WindowState對(duì)象w所描述的窗口的Z軸位置到SurfaceFlinger服務(wù)中去,這是通過(guò)調(diào)用WindowState對(duì)象w 的成員變量mSurface所指向的一個(gè)Surface對(duì)象的成員函數(shù)setLayer來(lái)實(shí)現(xiàn)的。在設(shè)置之前,還會(huì)將WindowState對(duì)象w的成員 變量mAnimLayer的值同時(shí)保存在成員變量mLastLayer和mSurfaceLayer中,以便可以記錄WindowState對(duì)象w所描述 的窗口上一次所使用的Z軸位置。
? ? ? ? 3.?重新設(shè)置WindowState對(duì)象w所描述的窗口的變換矩陣到SurfaceFlinger服務(wù)中去,這是通過(guò)調(diào)用WindowState對(duì)象w 的成員變量mSurface所指向的一個(gè)Surface對(duì)象的成員函數(shù)setMatrix來(lái)實(shí)現(xiàn)的。在設(shè)置之前,還會(huì)將WindowState對(duì)象w的成 員變量成員變量mDsDx、mDtDx、mDsDy、?mDtDy、mHScale、mVScale的值分別保存在成員變量mLastDsDx、 mLastDtDx、mLastDsDy、?mLastDtDy、mLastHScale、mLastVScale中,以便可以記錄 WindowState對(duì)象w所描述的窗口上一次所使用的變換矩陣。注意,WindowState對(duì)象的成員變量mHScale和mVScale描述的窗 口在寬度和高度上的縮放因子,因此,在設(shè)置窗口的變換矩陣時(shí),需要乘以這些因子才可以得到正確的變換矩陣參數(shù)。
? ? ? ? 4.?在設(shè)置WindowState對(duì)象w所描述的窗口的Alpha通道、Z軸位置以及實(shí)際要使用的變換矩陣到SurfaceFlinger服務(wù)的過(guò)程 中,如果出現(xiàn)了異常,那么同樣需要判斷參數(shù)recoveringMemory的值來(lái)決定是否需要WindowManagerService類的成員函數(shù) reclaimSomeSurfaceMemoryLocked來(lái)回收系統(tǒng)內(nèi)存資源。
? ? ? ? 將WindowState對(duì)象w所描述的窗口實(shí)際要顯示的Alpha通道、Z軸位置以及實(shí)際要使用的變換矩陣設(shè)置到SurfaceFlinger服務(wù)之后,如果WindowState對(duì)象w所描述的窗口滿足以下條件:
? ? ? ? 1. 上一次處于不可見(jiàn)狀態(tài),即WindowState對(duì)象w的成員變量mLastHidden的值等于true;
? ? ? ? 2. UI已經(jīng)繪制完成,即WindowState對(duì)象w的成員變量mDrawPending和mCommitDrawPending值等于false;
? ? ? ? 3. 不是處于等待同一個(gè)窗口令牌的其它窗口的完成UI繪制的狀態(tài),即WindowState對(duì)象w的成員變量mReadyToShow的值等于false;
? ? ? ? 那么就說(shuō)明現(xiàn)在就是時(shí)候要將WindowState對(duì)象w所描述的窗口顯示出來(lái)了,這是通過(guò)調(diào)用WindowManagerService類的成員函數(shù) showSurfaceRobustlyLocked來(lái)實(shí)現(xiàn)的。如果WindowManagerService類的成員函數(shù) showSurfaceRobustlyLocked的返回值等于true,那么就說(shuō)明WindowManagerService服務(wù)已經(jīng)成功地通知 SurfaceFlinger服務(wù)將WindowState對(duì)象w所描述的窗口顯示出來(lái),于是就會(huì)分別將WindowState對(duì)象w的成員變量 mHasDrawn和mLastHidden的值設(shè)置為true和false,以便可以表示W(wǎng)indowState對(duì)象w所描述的窗口的UI已經(jīng)繪制完 成,并且已經(jīng)顯示出來(lái)。
? ? ? ??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;??
- ????}??
- ????
- ????......????
- }????
? ? ? ??這個(gè)函數(shù)定義在文件frameworks/base/services/java/com/android/server/WindowManagerService.java中。
? ? ? ??WindowManagerService類的成員函數(shù)showSurfaceRobustlyLocked用來(lái)通知SurfaceFlinger服 務(wù)將參數(shù)win所描述的窗口顯示出來(lái),這是通過(guò)調(diào)用WindowState對(duì)象win的成員變量mSurface所指向的一個(gè)Surface對(duì)象的成員函 數(shù)show來(lái)實(shí)現(xiàn)的。注意,在通知SurfaceFlinger服務(wù)將WindowState對(duì)象win所描述的窗口顯示出來(lái)之前,還會(huì)將它的成員變量 mSurfaceShown的值設(shè)置為true。
? ? ? ? 如果在通知SurfaceFlinger服務(wù)將WindowState對(duì)象win所描述的窗口顯示出來(lái)的過(guò)程出現(xiàn)了異常,那么 WindowManagerService類的成員函數(shù)showSurfaceRobustlyLocked就會(huì)調(diào)用另外一個(gè)成員函數(shù) reclaimSomeSurfaceMemoryLocked來(lái)回收系統(tǒng)內(nèi)存資源。
? ? ? ? 從上面分析可以知道,一個(gè)窗口的顯示和隱藏,以及大小、X軸和Y軸位置、Z軸位置、Alpha通道和變換矩陣設(shè)置,是通過(guò)調(diào)用Java層的Surface 類的成員函數(shù)show、hide、setSize、setPosition、setLayer、setAlpha和setMatrix來(lái)實(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來(lái) 實(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都有一個(gè)共同的特點(diǎn),即先調(diào)用函數(shù)getSurfaceControl來(lái)獲得與參數(shù)clazz所描述的一個(gè)Java層的Surface對(duì)象所對(duì) 應(yīng)的一個(gè)SurfaceControl對(duì)象。有了這個(gè)SurfaceControl對(duì)象之后,就可以分別調(diào)用它的成員函數(shù)show、hide、 setSize、setPosition、setLayer、setAlpha和setMatrix來(lái)通知SurfaceFlinger服務(wù)來(lái)顯示和隱藏 一個(gè)窗口,以及設(shè)置一個(gè)窗口大小、X軸和Y軸位置、Z軸位置、Alpha通道和變換矩陣。
? ? ? ? 從前面Android應(yīng)用程序窗口(Activity)的繪圖表面(Surface)的創(chuàng)建過(guò)程分析一 文可以知道,每一個(gè)Activity窗口在Java層都對(duì)應(yīng)有兩個(gè)Surface對(duì)象,其中一個(gè)位于應(yīng)用程序進(jìn)程這一側(cè),而另外一個(gè)位于 WindowManagerService服務(wù)這一側(cè)。每一個(gè)位于應(yīng)用程序進(jìn)程這一側(cè)的Java層的Surface對(duì)象在C++層中都對(duì)應(yīng)有一個(gè) Surface對(duì)象,而每一個(gè)位于WindowManagerService服務(wù)這一側(cè)的Java層的Surface對(duì)象在C++層中都對(duì)應(yīng)有一個(gè) SurfaceControl對(duì)象,這個(gè)C++層的SurfaceControl對(duì)象的地址就保存在Java層的Surface對(duì)象的成員變量 mSurfaceControl中。
? ? ? ?從上面的分析可以知道,我們目前正在操作的是正在位于WindowManagerService服務(wù)這一側(cè)的Java層的Surface對(duì)象,因此,通 過(guò)調(diào)用函數(shù)getSurfaceControl就可以在C++層中獲得一個(gè)對(duì)應(yīng)的SurfaceControl對(duì)象,而有了這個(gè) SurfaceControl對(duì)象之后,就可以用來(lái)通知SurfaceFlinger服務(wù)更新一個(gè)窗口的屬性,這一點(diǎn)可以參考前面Android應(yīng)用程序與SurfaceFlinger服務(wù)的關(guān)系概述和學(xué)習(xí)計(jì)劃和Android系統(tǒng)Surface機(jī)制的SurfaceFlinger服務(wù)簡(jiǎn)要介紹和學(xué)習(xí)計(jì)劃兩個(gè)系列的文章。
? ? ? ?至此,WindowManagerService服務(wù)計(jì)算窗口Z軸位置的過(guò)程就分析完成了,這個(gè)過(guò)程如下所示:
? ? ? ?1.?WindowManagerService服務(wù)將窗口排列在一個(gè)窗口堆棧中;
? ? ? ?2.?WindowManagerService服務(wù)根據(jù)窗口類型以及窗口在窗口堆棧的位置來(lái)計(jì)算得窗口的Z軸位置;
? ? ? ?3.?WindowManagerService服務(wù)通過(guò)Java層的Surface類的成員函數(shù)setLayer來(lái)將窗口的Z軸位置設(shè)置到SurfaceFlinger服務(wù)中去;
? ? ? ?4. Java層的Surface類的成員函數(shù)setLayer又是通過(guò)調(diào)用C++層的SurfaceControl類的成員函數(shù)setLayer來(lái)將窗口的Z軸位置設(shè)置到SurfaceFlinger服務(wù)中去的;
? ? ? ?通過(guò)這篇文章以及前面三篇文章(窗口組織、輸入法窗口、壁紙窗口) 的學(xué)習(xí),我們對(duì)WindowManagerService服務(wù)對(duì)窗口的管理就有一個(gè)比較深刻的認(rèn)識(shí)了,在接下來(lái)的文章中,我們還將繼續(xù)分析 ActivityWindowManager服務(wù)和WindowManagerService服務(wù)是如何協(xié)作來(lái)完成Activity窗口的顯示過(guò)程的,敬 請(qǐng)關(guān)注!
老羅的新浪微博:http://weibo.com/shengyangluo,歡迎關(guān)注!
轉(zhuǎn)載于:https://www.cnblogs.com/Free-Thinker/p/4143189.html
總結(jié)
以上是生活随笔為你收集整理的Android窗口管理服务WindowManagerService计算窗口Z轴位置的过程分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: GitHub上整理的一些工具【转载】
- 下一篇: android xUtils的使用