Android6.0 WMS(三) WMS窗口次序

这篇博客我们主要分析下,窗口位置排序的一些原理。


一、添加窗口的时候 调整窗口位置

上篇博客我们分析了WMS的addWindow函数,这里我们就窗口的次序问题继续分析。

            boolean imMayMove = true;

            if (type == TYPE_INPUT_METHOD) {//如果窗口类是输入法窗口
                win.mGivenInsetsPending = true;
                mInputMethodWindow = win;
                addInputMethodWindowToListLocked(win);//插入输入法窗口到应用窗口上层
                imMayMove = false;
            } else if (type == TYPE_INPUT_METHOD_DIALOG) {//如果窗口是输入法对话框
                mInputMethodDialogs.add(win);
                addWindowToListInOrderLocked(win, true);//插入到正常位置
                moveInputMethodDialogsLocked(findDesiredInputMethodWindowIndexLocked(true));//调整对话框位置
                imMayMove = false;
            } else {
                addWindowToListInOrderLocked(win, true);//插入正常位置
                if (type == TYPE_WALLPAPER) {
                    mLastWallpaperTimeoutTime = 0;
                    displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
                } else if ((attrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
                    displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
                } else if (mWallpaperTarget != null
                        && mWallpaperTarget.mLayer >= win.mBaseLayer) {
                    // If there is currently a wallpaper being shown, and
                    // the base layer of the new window is below the current
                    // layer of the target window, then adjust the wallpaper.
                    // This is to avoid a new window being placed between the
                    // wallpaper and its target.
                    displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
                }
            }

DisplayContent类的mWindows列表按Z序保存了每个窗口,这段代码就是在根据窗口类型把窗口加入到DisplayContent合适位置。

addInputMethodWindowToListLocked方法作用就是一个输入法窗口放子啊需要显示输入法窗口的上面。

addWindowToListInOrderLocked将一个窗口插入到窗口堆栈的当前位置。


我们继续看addWindow函数,

            final WindowStateAnimator winAnimator = win.mWinAnimator;
            winAnimator.mEnterAnimationPending = true;
            winAnimator.mEnteringAnimation = true;

            if (displayContent.isDefaultDisplay) {
                mPolicy.getInsetHintLw(win.mAttrs, mRotation, outContentInsets, outStableInsets,//计算窗口大小
                        outOutsets);
            } else {
                outContentInsets.setEmpty();
                outStableInsets.setEmpty();
            }

            if (mInTouchMode) {
                res |= WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE;//加入支持触屏的标志
            }
            if (win.mAppToken == null || !win.mAppToken.clientHidden) {
                res |= WindowManagerGlobal.ADD_FLAG_APP_VISIBLE;//加入应用可用的标志
            }

            mInputMonitor.setUpdateInputWindowsNeededLw();//设置更新输入法窗口的标志

            boolean focusChanged = false;
            if (win.canReceiveKeys()) {//如果窗口能接受输入计算是否引起焦点变化
                focusChanged = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS,
                        false /*updateInputWindows*/);
                if (focusChanged) {
                    imMayMove = false;
                }
            }

            if (imMayMove) {
                moveInputMethodWindowsIfNeededLocked(false);//调整输入法的窗口位置
            }

            assignLayersLocked(displayContent.getWindowList());//重新计算z轴的位置
            // Don't do layout here, the window must call
            // relayout to be displayed, so we'll do it there.

            if (focusChanged) {
                mInputMonitor.setInputFocusLw(mCurrentFocus, false /*updateInputWindows*/);
            }
            mInputMonitor.updateInputWindowsLw(false /*force*/);//更新输入法窗口的信息

            if (localLOGV || DEBUG_ADD_REMOVE) Slog.v(TAG, "addWindow: New client "
                    + client.asBinder() + ": window=" + win + " Callers=" + Debug.getCallers(5));

            if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked(false)) {
                reportNewConfig = true;//配置发生变化
            }
        }

        if (reportNewConfig) {
            sendNewConfiguration();//发送新的配置
        }

        Binder.restoreCallingIdentity(origId);

        return res;
    }

如果窗口显示在缺省的显示设备,调用mPolicy的getInsetHintLw函数来获得除了状态条、导航条所占区域后的窗口大小。

接下来如果窗口能接受输入,调用updateFocusedWindowLocked来重新确定系统的焦点位置。如果焦点发生变化,则将imMayMove置为false。

新加入的窗口的位置在前面调用addWindowToListInOrderLocked的时候位置已经确定了,所以这里调用assignLayersLocked只是重新计算Z轴的位置。如果调用updateOrientationFromAppTokensLocked函数计算窗口的配置发生变化,调用sendNewConfiguration函数发送配置。


二、确定窗口的mLayer值

显示设备的水平方向,垂直方向作为X轴Y轴,我们还可以想象有一个垂直于屏幕的Z轴,Z轴的值越来越靠近屏幕。系统中所有的窗口都按次序排列在Z轴上。窗口对象WindowState的成员变量mLayer表示窗口在Z轴的值,值越小越靠近底层。

WMS作用之一就是管理各个窗口Z轴位置,确保正确显示。在所有窗口中输入法和壁纸窗口比较特殊。输入法窗口出现时,需要显示在应用窗口的前面。壁纸窗口通常在底层,但是又不是位于所有窗口的底层,而是位于当前Activity窗口的下面。

因此,当系统调整某个应用窗口的位置时,如果需要也会调整输入法和壁纸窗口,使当前Activity的窗口位于输入法窗口和壁纸窗口之间。

WindowState的成员变量mLayer的值表示窗口在Z轴的位置,这个值越小,位置越靠下。mLayer是通过计算得到,会经常变化。WindowState的另一个成员变量mBaseLayer的值是固定不变的,只和窗口类型有关。mLayer的值是根据mBaseLayer的值计算而来。

下面我们先来看看mBaseLayer的值如何而来,在WindowState的构造函数中有如下代码:

        if ((mAttrs.type >= FIRST_SUB_WINDOW &&
                mAttrs.type <= LAST_SUB_WINDOW)) {//如果是子窗口
            // The multiplier here is to reserve 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值