前言
上一章中通过添加Window为例,介绍了WMS的第一种职责——窗口管理,今天我们以上一章内容为基础,深入探索一下。众所周知,每个Window被添加或者更新后,WMS是怎样处理它们的显示次序呢?
窗口的显示次序
在addWindow()函数的前半部分中,WMS为窗口创建了用于描述窗口状态的WindowState,接下来便会为新建的窗口确定显示次序。为了方便窗口显示次序的管理,手机屏幕用X、Y、Z轴来表示,很奇怪的是,明明手机只有长宽的平面,为什么会有Z轴呢?这里就要简要说明一下WMS的窗口次序管理机制了,Z轴垂直于屏幕,从里指向外,这个次序也称作Z-Oder。前面章节中讲到的Type就是根据Z-Oder为依据定义的,理论上Type的值越大Z-Oder排序越靠前,窗口越靠近用户。
主序与子序
又回到上一章中提到的WindowState,这里看一下它的构造方法:
WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
WindowState parentWindow, int appOp, int seq, WindowManager.LayoutParams a,
int viewVisibility, int ownerId, boolean ownerCanAddInternalSystemWindow,
PowerManagerWrapper powerManagerWrapper) {
...
// 为子窗口分配Z-Oder
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.getWindowLayerLw(parentWindow)
* TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
mSubLayer = mPolicy.getSubWindowLayerFromTypeLw(a.type);
mIsChildWindow = true;
if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + this + " to " + parentWindow);
parentWindow.addChild(this, sWindowSubLayerComparator);
mLayoutAttached = mAttrs.type !=
WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
mIsImWindow = parentWindow.mAttrs.type == TYPE_INPUT_METHOD
|| parentWindow.mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
mIsWallpaper = parentWindow.mAttrs.type == TYPE_WALLPAPER;
} else {
// 为普通窗口分配Z-Oder
// The multiplier here is to reserve space for multiple
// windows in the same type layer.
mBaseLayer = mPolicy.getWindowLayerLw(this)
* TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
mSubLayer = 0;
mIsChildWindow = false;
mLayoutAttached = false;
mIsImWindow = mAttrs.type == TYPE_INPUT_METHOD
|| mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
mIsWallpaper = mAttrs.type == TYPE_WALLPAPER;
}
...
}
窗口的显示次序由两个成员变量描述:主序mBaseLayer和子序mSubLayer。主序用于描述窗口及其子窗口在所有窗口中的显示位置。而子序则描述了一个子窗口在其兄弟窗口中的显示位置。
- 主序越大,则窗口及其子窗口的显示位置相对于其他窗口的位置越靠前。
- 子序越大,则子窗口相对于其兄弟窗口的位置越靠前。
对于父窗口而言,其主序取决于其类型,其子序则保持为0。而子窗口的主序与其父窗口一样,子序则取决于其类型。从上述代码可以看到,主序与子序的分配工作是由WindowManagerPolicy的两个成员函数getWindowLayerLw和getSubWindowLayerFromTypeLw完成的。
窗口的主序:
窗口类型 | 主序 |
---|---|
TYPE_UNIVERSE_BACKGROUND | 11000 |
TYPE_PHONE | 31000 |
TYPE_RECENTS_OVERLAY | 51000 |
TYPE_TOAST | 61000 |
TYPE_DREAM | 81000 |
TYPE_INPUT_METHOD | 101000 |
TYPE_KEYGUARD | 121000 |
TYPE_STATUS_BAR_SUB_PANEL | 141000 |
TYPE_WALLPAPER | 21000 |
TYPE_SEARCH_BAR | 41000 |
TYPE_SYSTEM_DIALOG | 51000 |
TYPE_PRIORITY_PHONE | 71000 |
TYPE_SYSTEM_ALERT | 91000 |
TYPE_INPUT_METHOD_DIALOG | 111000 |
TYPE_KEYGUARD_DIALOG | 131000 |
应用窗口与未知类型的窗口 | 21000 |
窗口的子序:
窗口类型 | 主序 |
---|---|
TYPE_UNIVERSE_BACKGROUND | 11000 |
TYPE_PHONE | 31000 |
TYPE_RECENTS_OVERLAY | 51000 |
TYPE_TOAST | 61000 |
TYPE_DREAM | 81000 |
TYPE_INPUT_METHOD | 101000 |
TYPE_KEYGUARD | 121000 |
TYPE_STATUS_BAR_SUB_PANEL | 141000 |
TYPE_WALLPAPER | 21000 |
网友评论