这篇博客我们主要分析下,窗口位置排序的一些原理。
一、添加窗口的时候 调整窗口位置
上篇博客我们分析了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 space for multiple
-
// windows in the same type layer.
-
mBaseLayer = mPolicy.windowTypeToLayerLw(
//使用依附窗口的类型
-
attachedWindow.mAttrs.type) * WindowManagerService.TYPE_LAYER_MULTIPLIER
-
+ WindowManagerService.TYPE_LAYER_OFFSET;
-
mSubLayer = mPolicy.subWindowTypeToLayerLw(a.type);
//计算mSubLayer
-
......
-
}
else {
//非子窗口
-
// The multiplier here is to reserve space for multiple
-
// windows in the same type layer.
-
mBaseLayer = mPolicy.windowTypeToLayerLw(a.type)
-
* WindowManagerService.TYPE_LAYER_MULTIPLIER
-
+ WindowManagerService.TYPE_LAYER_OFFSET;
-
mSubLayer =
0;
-
......
-
}
如果窗口类型是子窗口,则使用它所依附的窗口类型来计算mBaseLayer,否则使用窗口类型来计算mBaseLayer。计算的方法是先调用mPolicy.windowTypeToLayerLw方法将窗口的类型转化成一个基数,然后再乘以TYPE_LAYER_MULTIPLIER(10000),最后加上TYPE_LAYER_OFFSET(1000),我们先来看看windowTypeToLayerLw函数是如果根据类型返回一个基数的。
-
public int windowTypeToLayerLw(int type) {
-
if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
//应用窗口
-
return
2;
-
}
-
switch (type) {
-
case TYPE_PRIVATE_PRESENTATION:
-
return
2;
-
case TYPE_WALLPAPER:
-
// wallpaper is at the bottom, though the window manager may move it.
-
return
2;
-
case TYPE_PHONE:
-
return
3;
-
case TYPE_SEARCH_BAR:
-
case TYPE_VOICE_INTERACTION_STARTING:
-
return
4;
-
case TYPE_VOICE_INTERACTION:
-
// voice interaction layer is almost immediately above apps.
-
return
5;
-
case TYPE_INPUT_CONSUMER:
-
return
6;
-
case TYPE_SYSTEM_DIALOG:
-
return
7;
-
case TYPE_TOAST:
-
// toasts and the plugged-in battery thing
-
return
8;
-
case TYPE_PRIORITY_PHONE:
-
// SIM errors and unlock. Not sure if this really should be in a high layer.
-
return
9;
-
case TYPE_DREAM:
-
// used for Dreams (screensavers with TYPE_DREAM windows)
-
return
10;
-
case TYPE_SYSTEM_ALERT:
-
// like the ANR / app crashed dialogs
-
return
11;
-
case TYPE_INPUT_METHOD:
-
// on-screen keyboards and other such input method user interfaces go here.
-
return
12;
-
case TYPE_INPUT_METHOD_DIALOG:
-
// on-screen keyboards and other such input method user interfaces go here.
-
return
13;
-
case TYPE_KEYGUARD_SCRIM:
-
// the safety window that shows behind keyguard while keyguard is starting
-
return
14;
-
case TYPE_STATUS_BAR_SUB_PANEL:
-
return
15;
-
case TYPE_STATUS_BAR:
-
return
16;
-
case TYPE_STATUS_BAR_PANEL:
-
return
17;
-
case TYPE_KEYGUARD_DIALOG:
-
return
18;
-
case TYPE_VOLUME_OVERLAY:
-
// the on-screen volume indicator and controller shown when the user
-
// changes the device volume
-
return
19;
-
case TYPE_SYSTEM_OVERLAY:
-
// the on-screen volume indicator and controller shown when the user
-
// changes the device volume
-
return
20;
-
case TYPE_NAVIGATION_BAR:
-
// the navigation bar, if available, shows atop most things
-
return
21;
-
case TYPE_NAVIGATION_BAR_PANEL:
-
// some panels (e.g. search) need to show on top of the navigation bar
-
return
22;
-
case TYPE_SYSTEM_ERROR:
-
// system-level error dialogs
-
return
23;
-
case TYPE_MAGNIFICATION_OVERLAY:
-
// used to highlight the magnified portion of a display
-
return
24;
-
case TYPE_DISPLAY_OVERLAY:
-
// used to simulate secondary display devices
-
return
25;
-
case TYPE_DRAG:
-
// the drag layer: input for drag-and-drop is associated with this window,
-
// which sits above all other focusable windows
-
return
26;
-
case TYPE_ACCESSIBILITY_OVERLAY:
-
// overlay put by accessibility services to intercept user interaction
-
return
27;
-
case TYPE_SECURE_SYSTEM_OVERLAY:
-
return
28;
-
case TYPE_BOOT_PROGRESS:
-
return
29;
-
case TYPE_POINTER:
-
// the (mouse) pointer layer
-
return
30;
-
}
-
Log.e(TAG,
"Unknown window type: " + type);
-
return
2;
-
}
这个方法很简单就是根据类型返回一个基数。
WindowState中的成员变量mSubLayer只有在窗口是子窗口的时候才有作用,它表示在窗口和父窗口之间的相对位置。代码如下
-
public int subWindowTypeToLayerLw(int type) {
-
switch (type) {
-
case TYPE_APPLICATION_PANEL:
-
case TYPE_APPLICATION_ATTACHED_DIALOG:
-
return APPLICATION_PANEL_SUBLAYER;
//等于1
-
case TYPE_APPLICATION_MEDIA:
-
return APPLICATION_MEDIA_SUBLAYER;
//等于-2
-
case TYPE_APPLICATION_MEDIA_OVERLAY:
-
return APPLICATION_MEDIA_OVERLAY_SUBLAYER;
//等于-1
-
case TYPE_APPLICATION_SUB_PANEL:
-
return APPLICATION_SUB_PANEL_SUBLAYER;
//等于2
-
case TYPE_APPLICATION_ABOVE_SUB_PANEL:
-
return APPLICATION_ABOVE_SUB_PANEL_SUBLAYER;
//等于3
-
}
-
Log.e(TAG,
"Unknown sub-window type: " + type);
-
return
0;
-
}
理解了mBaseLayer和mSubLayer后,我们再来看看mLayer是如何计算出来的,是通过assignLayersLocked方法:
-
private final void assignLayersLocked(WindowList windows) {
-
int N = windows.size();
-
int curBaseLayer =
0;
-
int curLayer =
0;
-
int i;
-
-
boolean anyLayerChanged =
false;
-
-
for (i=
0; i<N; i++) {
-
final WindowState w = windows.get(i);
-
final WindowStateAnimator winAnimator = w.mWinAnimator;
-
boolean layerChanged =
false;
-
int oldLayer = w.mLayer;
-
if (w.mBaseLayer == curBaseLayer || w.mIsImWindow
-
|| (i >
0 && w.mIsWallpaper)) {
//如果窗口的mBaseLayer和前一个相同、或者是输入法和壁纸窗口
-
curLayer += WINDOW_LAYER_MULTIPLIER;
-
w.mLayer = curLayer;
-
}
else {
-
curBaseLayer = curLayer = w.mBaseLayer;
-
w.mLayer = curLayer;
-
}
-
if (w.mLayer != oldLayer) {
//层级发生改变
-
layerChanged =
true;
-
anyLayerChanged =
true;
-
}
-
final AppWindowToken wtoken = w.mAppToken;
-
oldLayer = winAnimator.mAnimLayer;
//后面都是调整mAnimLayerd的值
-
if (w.mTargetAppToken != null) {
-
winAnimator.mAnimLayer =
-
w.mLayer + w.mTargetAppToken.mAppAnimator.animLayerAdjustment;
-
}
else
if (wtoken != null) {
-
winAnimator.mAnimLayer =
-
w.mLayer + wtoken.mAppAnimator.animLayerAdjustment;
-
}
else {
-
winAnimator.mAnimLayer = w.mLayer;
-
}
-
if (w.mIsImWindow) {
-
winAnimator.mAnimLayer += mInputMethodAnimLayerAdjustment;
-
}
else
if (w.mIsWallpaper) {
-
winAnimator.mAnimLayer += mWallpaperAnimLayerAdjustment;
-
}
-
if (winAnimator.mAnimLayer != oldLayer) {
-
layerChanged =
true;
-
anyLayerChanged =
true;
-
}
-
final TaskStack
stack = w.getStack();
-
if (layerChanged &&
stack != null &&
stack.isDimming(winAnimator)) {
-
// Force an animation pass just to update the mDimLayer layer.
-
scheduleAnimationLocked();
-
}
-
}
-
-
if (mAccessibilityController != null && anyLayerChanged
-
&& windows.get(windows.size() -
1).getDisplayId() == Display.DEFAULT_DISPLAY) {
-
mAccessibilityController.onWindowLayersChangedLocked();
-
}
-
}
在调用assignLayersLocked函数之前,WindowList中的窗口其实已经排好序了,前面调用的函数addWindowToListInOrderLocked就是插入窗口到合适的位置,assignLayersLocked函数并不会改变窗口的位置,只是根据窗口的位置计算mLayer的值。
调整方法是从最底层的窗口开始,具有相同的mBaseLayer的值作为一组,每组窗口的mLayer的值从mBaseLayer的值开始,依次加上WINDOW_LAYER_MULTIPLIER(等于5),这样做的目的是在同层的窗口中每隔一个窗口就留下4个空位,方便下次插入新窗口。
这个方法还对输入法和壁纸窗口做了特殊处理。这两类窗口和它插入位置前面的窗口处于一个层级,而不是根据他们的mBaseLayer值计算。(就是前面说的当输入法和壁纸出现是在当前Activity的窗口之间的)。
三、插入窗口的位置
在addWindow函数中我们会调用addAppWindowToListLocked来确定窗口的位置,现在我们来看下这个函数。
-
private void addWindowToListInOrderLocked(final WindowState win, boolean addToToken) {
-
if (win.mAttachedWindow == null) {
//非子窗口
-
final WindowToken token = win.mToken;
-
int tokenWindowsPos =
0;
-
if (token.appWindowToken != null) {
//应用窗口的顶层窗口
-
tokenWindowsPos = addAppWindowToListLocked(win);
-
}
else {
-
addFreeWindowToListLocked(win);
//系统窗口
-
}
-
if (addToToken) {
-
if (DEBUG_ADD_REMOVE) Slog.v(TAG,
"Adding " + win +
" to " + token);
-
token.windows.add(tokenWindowsPos, win);
-
}
-
}
else {
-
addAttachedWindowToListLocked(win, addToToken);
//添加子窗口
-
}
-
-
if (win.mAppToken != null && addToToken) {
-
win.mAppToken.allAppWindows.add(win);
-
}
-
}
上面这个函数根据窗口的类型,应用顶层窗口,系统窗口,子窗口。
我们现在分别对这三类窗口的处理方法进行解析,先来看插入Activity顶层窗口的addAppWindowToListLocked
1.插入Activity顶层方法的addAppWindowToListLocked方法
addAppWindowToListLocked方法先判断系统中是否存在和待插入的窗口是否有相同的Token,如果有代表它不是Activity的第一个窗口,因此再判断这个窗口的类型是不是TYPE_BASE_APPLICATION,如果是这类窗口需要放在所有和它相同Token的窗口下面,否则在判断这个应用的启动窗口是否位于最前面(说明正在启动),如果是放在启动窗口的下面。如果不是下面两种情况,则寻找同一应用中位置最高的窗口,然后插在它上面,这表示加入的窗口将覆盖在前面的窗口之上。
下面是部分代码,
-
private int addAppWindowToListLocked(final WindowState win) {
-
final IWindow client = win.mClient;
-
final WindowToken token = win.mToken;
-
final DisplayContent displayContent = win.getDisplayContent();
-
if (displayContent == null) {
-
// It doesn't matter this display is going away.
-
return
0;
-
}
-
-
final WindowList windows = win.getWindowList();
-
final
int N = windows.size();
-
WindowList tokenWindowList = getTokenWindowsOnDisplay(token, displayContent);
-
int tokenWindowsPos =
0;
-
int windowListPos = tokenWindowList.size();
-
if (!tokenWindowList.isEmpty()) {
//如果有,说明它不是第一个窗口
-
// If this application has existing windows, we
-
// simply place the new window on top of them... but
-
// keep the starting window on top.
-
if (win.mAttrs.type == TYPE_BASE_APPLICATION) {
//放在和它相同Token的窗口下面
-
// Base windows go behind everything else.
-
WindowState lowestWindow = tokenWindowList.get(
0);
//第一个0,代表最底层的window
-
placeWindowBefore(lowestWindow, win);
//放在这个window前面
-
tokenWindowsPos = indexOfWinInWindowList(lowestWindow, token.windows);
-
}
else {
-
AppWindowToken atoken = win.mAppToken;
-
WindowState lastWindow = tokenWindowList.get(windowListPos -
1);
-
if (atoken != null && lastWindow == atoken.startingWindow) {
-
placeWindowBefore(lastWindow, win);
-
tokenWindowsPos = indexOfWinInWindowList(lastWindow, token.windows);
-
}
else {
-
int newIdx = findIdxBasedOnAppTokens(win);
//寻找同一token位置最前面的window
-
//there is a window above this one associated with the same
-
//apptoken note that the window could be a floating window
-
//that was created later or a window at the top of the list of
-
//windows associated with this token.
-
windows.add(newIdx +
1, win);
//插在它前面
-
if (newIdx <
0) {
-
// No window from token found on win's display.
-
tokenWindowsPos =
0;
-
}
else {
-
tokenWindowsPos = indexOfWinInWindowList(
-
windows.get(newIdx), token.windows) +
1;
-
}
-
mWindowsChanged =
true;
-
}
-
}
-
return tokenWindowsPos;
-
}
我们再来看几个函数
placeWindowBefore函数就是插入到windows这个位置前
-
private void placeWindowBefore(WindowState pos, WindowState window) {
-
final WindowList windows = pos.getWindowList();
-
int i = windows.indexOf(pos);
-
if (i <
0) {
-
Slog.w(TAG,
"placeWindowBefore: Unable to find " + pos +
" in " + windows);
-
i =
0;
-
}
-
windows.add(i, window);
-
mWindowsChanged =
true;
-
}
findIdxBasedOnAppTokens函数就是寻找相同token的最前面的window,所以要注意遍历循环的时候是从window的size最大的时候反过来遍历的。
-
private int findIdxBasedOnAppTokens(WindowState win) {
-
WindowList windows = win.getWindowList();
-
for(
int j = windows.size() -
1; j >=
0; j--) {
-
WindowState wentry = windows.get(j);
-
if(wentry.mAppToken == win.mAppToken) {
-
return j;
-
}
-
}
-
return
-1;
-
}
继续看这个函数,如果系统中不存在和窗口具有相同token的窗口(说明Activity刚启动,第一个窗口还没有创建完成),这时就会遍历系统所有的task以及task中包含的AppWindowToken,找到窗口的位置,再在task中排在本窗口前面的窗口中,找出离自己最近的,并且APPWindowToken的窗口列表不为NULL的窗口,插入到它的最后一个子窗口后面。如果前面的窗口的列表也都为NULL,则寻找排在本窗口后面的第一个包含有窗口对象的APPWindowToken,把本窗口插在前面。
-
WindowState pos = null;
-
-
final ArrayList<Task> tasks = displayContent.getTasks();
-
int taskNdx;
-
int tokenNdx =
-1;
-
for (taskNdx = tasks.size() -
1; taskNdx >=
0; --taskNdx) {
-
AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
-
for (tokenNdx = tokens.size() -
1; tokenNdx >=
0; --tokenNdx) {
-
final AppWindowToken t = tokens.get(tokenNdx);
-
if (t == token) {
-
--tokenNdx;
-
if (tokenNdx <
0) {
-
--taskNdx;
-
if (taskNdx >=
0) {
-
tokenNdx = tasks.get(taskNdx).mAppTokens.size() -
1;
-
}
-
}
-
break;
-
}
-
-
// We haven't reached the token yet; if this token
-
// is not going to the bottom and has windows on this display, we can
-
// use it as an anchor for when we do reach the token.
-
tokenWindowList = getTokenWindowsOnDisplay(t, displayContent);
-
if (!t.sendingToBottom && tokenWindowList.size() >
0) {
-
pos = tokenWindowList.get(
0);
-
}
-
}
-
if (tokenNdx >=
0) {
-
// early exit
-
break;
-
}
-
}
-
-
// We now know the index into the apps. If we found
-
// an app window above, that gives us the position; else
-
// we need to look some more.
-
if (pos != null) {
-
// Move behind any windows attached to this one.
-
WindowToken atoken = mTokenMap.get(pos.mClient.asBinder());
-
if (atoken != null) {
-
tokenWindowList =
-
getTokenWindowsOnDisplay(atoken, displayContent);
-
final
int NC = tokenWindowList.size();
-
if (NC >
0) {
-
WindowState bottom = tokenWindowList.get(
0);
-
if (bottom.mSubLayer <
0) {
-
pos = bottom;
-
}
-
}
-
}
-
placeWindowBefore(pos, win);
-
return tokenWindowsPos;
-
}
-
-
// Continue looking down until we find the first
-
// token that has windows on this display.
-
for ( ; taskNdx >=
0; --taskNdx) {
-
AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
-
for ( ; tokenNdx >=
0; --tokenNdx) {
-
final AppWindowToken t = tokens.get(tokenNdx);
-
tokenWindowList = getTokenWindowsOnDisplay(t, displayContent);
-
final
int NW = tokenWindowList.size();
-
if (NW >
0) {
-
pos = tokenWindowList.get(NW
-1);
-
break;
-
}
-
}
-
if (tokenNdx >=
0) {
-
// found
-
break;
-
}
-
}
-
-
if (pos != null) {
-
// Move in front of any windows attached to this
-
// one.
-
WindowToken atoken = mTokenMap.get(pos.mClient.asBinder());
-
if (atoken != null) {
-
final
int NC = atoken.windows.size();
-
if (NC >
0) {
-
WindowState top = atoken.windows.get(NC
-1);
-
if (top.mSubLayer >=
0) {
-
pos = top;
-
}
-
}
-
}
-
placeWindowAfter(pos, win);
-
return tokenWindowsPos;
-
}
-
-
......
如果前面窗口的APPWindowToken的窗口列表也为空,则重新遍历整个窗口,然后根据mBaseLayer的值来确定窗口的位置。
-
final
int myLayer = win.mBaseLayer;
-
int i;
-
for (i = N -
1; i >=
0; --i) {
-
WindowState w = windows.get(i);
-
if (w.mBaseLayer <= myLayer) {
-
break;
-
}
-
}
-
if (DEBUG_FOCUS_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG,
-
"Based on layer: Adding window " + win +
" at " + (i +
1) +
" of " + N);
-
windows.add(i +
1, win);
-
mWindowsChanged =
true;
-
return tokenWindowsPos;
2. 插入子窗口的addAttachedWindowToListLocked函数
addAttachedWindowToListLocked方法,如果mSubLayer大于0的子窗口,按mSubLayer的值大小插入到有相同WindowToken的子窗口的合适位置中,如果mSubLayer相同,插入已插入窗口的下层位置,如果mSubLayer小于0,如果还存在mSubLayer小于0,并且大于等于该窗口的mSubLayer的值的子窗口,则插入到该子窗口之下,否则插入到子窗口所依附的窗口下面。
-
private void addAttachedWindowToListLocked(final WindowState win, boolean addToToken) {
-
final WindowToken token = win.mToken;
-
final DisplayContent displayContent = win.getDisplayContent();
-
if (displayContent == null) {
-
return;
-
}
-
final WindowState attached = win.mAttachedWindow;
-
-
WindowList tokenWindowList = getTokenWindowsOnDisplay(token, displayContent);
-
-
// Figure out this window's ordering relative to the window
-
// it is attached to.
-
final
int NA = tokenWindowList.size();
-
final
int sublayer = win.mSubLayer;
-
int largestSublayer = Integer.MIN_VALUE;
-
WindowState windowWithLargestSublayer = null;
-
int i;
-
for (i =
0; i < NA; i++) {
-
WindowState w = tokenWindowList.get(i);
-
final
int wSublayer = w.mSubLayer;
-
if (wSublayer >= largestSublayer) {
-
largestSublayer = wSublayer;
-
windowWithLargestSublayer = w;
-
}
-
if (sublayer <
0) {
-
// For negative sublayers, we go below all windows
-
// in the same sublayer.
-
if (wSublayer >= sublayer) {
-
if (addToToken) {
-
if (DEBUG_ADD_REMOVE) Slog.v(TAG,
"Adding " + win +
" to " + token);
-
token.windows.add(i, win);
-
}
-
placeWindowBefore(wSublayer >=
0 ? attached : w, win);
-
break;
-
}
-
}
else {
-
// For positive sublayers, we go above all windows
-
// in the same sublayer.
-
if (wSublayer > sublayer) {
-
if (addToToken) {
-
if (DEBUG_ADD_REMOVE) Slog.v(TAG,
"Adding " + win +
" to " + token);
-
token.windows.add(i, win);
-
}
-
placeWindowBefore(w, win);
-
break;
-
}
-
}
-
}
-
if (i >= NA) {
-
if (addToToken) {
-
if (DEBUG_ADD_REMOVE) Slog.v(TAG,
"Adding " + win +
" to " + token);
-
token.windows.add(win);
-
}
-
if (sublayer <
0) {
-
placeWindowBefore(attached, win);
-
}
else {
-
placeWindowAfter(largestSublayer >=
0
-
? windowWithLargestSublayer
-
: attached,
-
win);
-
}
-
}
-
}
3.插入系统窗口的addFreeWindowToListLocked
addFreeWindowToListLocked方法简单,只是遍历同一显示设备上的Windows,比较mBaseLayer值的大小,插入合适位置。
-
private void addFreeWindowToListLocked(final WindowState win) {
-
final WindowList windows = win.getWindowList();
-
-
// Figure out where window should go, based on layer.
-
final
int myLayer = win.mBaseLayer;
-
int i;
-
for (i = windows.size() -
1; i >=
0; i--) {
-
if (windows.get(i).mBaseLayer <= myLayer) {
-
break;
-
}
-
}
-
i++;
-
if (DEBUG_FOCUS_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG,
-
"Free window: Adding window " + win +
" at " + i +
" of " + windows.size());
-
windows.add(i, win);
-
mWindowsChanged =
true;
-
}
这篇博客我们分析了window插入到什么位置,以及mLayer的计算。但是具体里面有很多变量,stack task windows等,不是很熟悉,下篇博客我们主要分析这。