WindowManagerService探索——窗口主次序

前言

上一章中通过添加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

你可能感兴趣的:(WindowManagerService探索——窗口主次序)