Window窗口概述
WindowContainer及子类
/**
* Defines common functionality for classes that can hold windows directly or through their
* children in a hierarchy form.
* The test class is {@link WindowContainerTests} which must be kept up-to-date and ran anytime
* changes are made to this class.
*/
class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<E>
implements Comparable<WindowContainer>, Animatable, SurfaceFreezer.Freezable,
InsetsControlTarget {…}
给自己以及子窗口定义公共方法和属性。
WindowContainer子类及继承树如下:

| 类 | 说明 |
|---|---|
| RootWindowContainer | 根窗口容器,可以通过它遍历找到窗口树上的窗口。 |
| WindowState | WindowState是对应着一个窗口的 |
| WindowToken | |
| DisplayArea | 表示显示区域的抽象概念。它通常用于多屏设备或显示设备管理,以便将屏幕分成不同的区域,并在每个区域内显示不同的内容。这个概念可以在多屏设备或分屏模式下非常有用。 |
| Dimmable | |
| Tokens | |
| TaskDisplayArea | DisplayContent的子类。表示任务(Task)的显示区域的概念。它通常用于多窗口、分屏模式和多任务管理,以便将任务组织到不同的显示区域中。 |
| RootDisplayArea | |
| ImeContainer | 输入法窗口的容器 |
| DisplayContent | 表示一个显示屏,Android是支持多屏的,所以可能存在多个DisplayContent对象。 |
| DisplayAreaGroup | DisplayAreaGroup就是一组DisplayArea,用来表示屏幕的一部分内容(这部分由DisplayArea组成)。之所以添加DisplayAreaGroup,主要还是为了功能拓展。 |
| TaskFragment | |
| Task | |
| ActivityRecord | WindowToken的子类,表示一个 Activity |
| WallpaperWindowToken | 表示壁纸 |
为什么需要DisplayAreaGroup?
DisplayAreaGroup就是一组DisplayArea,用来表示屏幕的一部分内容(这部分由DisplayArea组成)。之所以添加DisplayAreaGroup,主要还是为了功能拓展。

一个屏幕上想显示多个Display的内容,我们想针对某一Display做旋转要求的时候,在没有DisplayAreaGroup的存在下,很难做到Configuration正确更新,就算能做,我们也要在一致性代码里面加上很多的特殊性判断,这个根本就不符合Google manline的要求。在DisplayAreaGroup的加持下,这个要求变的就十分简单。只要针对DisplayAreaGroup做对应的Configuration更新即可。
即DisplayArea是在Z轴维度进行分割窗口层次,而DisplayAreaGroup是在平面层次分割窗口层次。
dumpsys activity containers
命令:adb shell dumpsys activity containers
说明:查看当前系统内所有的窗口层级相关信息
Base on: Android 13
Branch: android-13.0.0_r30
在系统中无任何用户APP运行的情况下,执行dumpsys activity containers,输出如下:
ACTIVITY MANAGER CONTAINERS (dumpsys activity containers)
ROOT type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 Display 0 name="内置屏幕" type=undefined mode=fullscreen override-mode=fullscreen requested-bounds=[0,0][1080,2340] bounds=[0,0][1080,2340]
#2 Leaf:36:36 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#1 WindowToken{e67a4f4 type=2024 android.os.BinderProxy@c1bb6c7} type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 f1bc41d ScreenDecorOverlayBottom type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 WindowToken{256e65c type=2024 android.os.BinderProxy@eb2fccf} type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 584d65 ScreenDecorOverlay type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#1 HideDisplayCutout:32:35 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#2 OneHanded:34:35 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 FullscreenMagnification:34:35 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 Leaf:34:35 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#1 FullscreenMagnification:33:33 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 Leaf:33:33 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 OneHanded:32:32 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 Leaf:32:32 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 WindowedMagnification:0:31 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#6 HideDisplayCutout:26:31 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 OneHanded:26:31 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#2 FullscreenMagnification:29:31 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 Leaf:29:31 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#1 Leaf:28:28 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 FullscreenMagnification:26:27 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 Leaf:26:27 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#5 Leaf:24:25 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#3 WindowToken{cbaebae type=2024 android.os.BinderProxy@d4d5c29} type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 5f98d4f pip-dismiss-overlay type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#2 WindowToken{beee86d type=2024 android.os.BinderProxy@dda6884} type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 d85ca2 SecondaryHomeHandle0 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#1 WindowToken{164b6d8 type=2024 android.os.BinderProxy@f2411bb} type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 aa7da31 EdgeBackGestureHandler0 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 WindowToken{1cc5297 type=2019 android.os.BinderProxy@a297e31} type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 be6cc6d NavigationBar0 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#4 HideDisplayCutout:18:23 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 OneHanded:18:23 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 FullscreenMagnification:18:23 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 Leaf:18:23 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#3 OneHanded:17:17 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 FullscreenMagnification:17:17 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 Leaf:17:17 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 WindowToken{9bf6ce4 type=2040 android.os.BinderProxy@a059a76} type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 607054d NotificationShade type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#2 HideDisplayCutout:16:16 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 OneHanded:16:16 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 FullscreenMagnification:16:16 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 Leaf:16:16 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#1 OneHanded:15:15 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 FullscreenMagnification:15:15 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 Leaf:15:15 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 WindowToken{678d26 type=2000 android.os.BinderProxy@d275c68} type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 a7cdd67 StatusBar type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 HideDisplayCutout:0:14 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 OneHanded:0:14 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#1 ImePlaceholder:13:14 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 ImeContainer type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 WindowToken{8b65397 type=2011 android.os.Binder@5413e16} type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 cd97f76 InputMethod type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 FullscreenMagnification:0:12 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#2 Leaf:3:12 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 WindowToken{2ea6e76 type=2038 android.os.BinderProxy@602e669} type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 69119b ShellDropTarget type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#1 DefaultTaskDisplayArea type=undefined mode=fullscreen override-mode=fullscreen requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#1 Task=1 type=home mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 Task=13 type=home mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 ActivityRecord{b8a7420 u0 com.android.launcher3/.uioverrides.QuickstepLauncher} t13} type=home mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 1f16c6 com.android.launcher3/com.android.launcher3.uioverrides.QuickstepLauncher type=home mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 Task=2 type=undefined mode=fullscreen override-mode=fullscreen requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#1 Task=4 type=undefined mode=multi-window override-mode=multi-window requested-bounds=[0,2340][1080,3510] bounds=[0,2340][1080,3510]
#0 Task=3 type=undefined mode=multi-window override-mode=multi-window requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 Leaf:0:1 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 WallpaperWindowToken{8bd7702 token=android.os.Binder@7e8704d} type=undefined mode=fullscreen override-mode=fullscreen requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 c079fcb com.android.systemui.wallpapers.ImageWallpaper type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
绘制出其树形图为:

以上信息表示在Display 0 name=”内置屏幕”,这个屏幕下,将窗口层级分为[0,36]一共37层。每层可以放置多个窗口,上层窗口(数值大的)覆盖下层窗口。 如” HideDisplayCutout:0:14”表示HideDisplayCutout占用了0~14这15个层级。
其中一些常见的层级如下:
Wallpaper位于Leaf:0:1
Activity位于DefaultTaskDisplayArea,即第2层
InputMethod位于ImePlaceholder:13:14
StatusBar位于FullscreenMagnification:15:15
NotificationShade位于Leaf:17:17
NavigationBar0位于Leaf:24:25
这和我们平时看到的一样,如状态栏StatusBar在Activity之上,输入法InputMethod在Activity之上,而Activity在壁纸Wallpaper之上。
而且我们平时打开Activity,窗口是在DefaultTaskDisplayArea节点中添加的,比如打开com.android.settings/.Settings和com.demoapp.activitydemo/.MainActivity,DefaultTaskDisplayArea节点变化如下:
y,DefaultTaskDisplayArea节点变化如下:
#1 DefaultTaskDisplayArea type=undefined mode=fullscreen override-mode=fullscreen requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#3 Task=1 type=home mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 Task=13 type=home mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 ActivityRecord{b8a7420 u0 com.android.launcher3/.uioverrides.QuickstepLauncher} t13} type=home mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 1f16c6 com.android.launcher3/com.android.launcher3.uioverrides.QuickstepLauncher type=home mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#2 Task=20 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 ActivityRecord{73e75f2 u0 com.demoapp.activitydemo/.MainActivity} t20} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 f0d508f com.demoapp.activitydemo/com.demoapp.activitydemo.MainActivity type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#1 Task=19 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 ActivityRecord{43bb45 u0 com.android.settings/.Settings} t19} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 dc5c533 com.android.settings/com.android.settings.Settings type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#0 Task=2 type=undefined mode=fullscreen override-mode=fullscreen requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
#1 Task=4 type=undefined mode=multi-window override-mode=multi-window requested-bounds=[0,2340][1080,3510] bounds=[0,2340][1080,3510]
#0 Task=3 type=undefined mode=multi-window override-mode=multi-window requested-bounds=[0,0][0,0] bounds=[0,0][1080,2340]
可以发现在DefaultTaskDisplayArea下新增了Task=19和Task=20的两个节点,分别为以上两个Activity。
Window窗口层级
Window Type
Window Type表示窗口的类型,其中应用窗口值[1-99],子窗口值[100-1999],系统窗口值[2000,2999]。
定义于WindowManager.java中:
/**
* Start of window types that represent normal application windows.
*/
public static final int FIRST_APPLICATION_WINDOW = 1;
/**
* End of types of application windows.
*/
public static final int LAST_APPLICATION_WINDOW = 99;
/**
* Start of types of sub-windows. The {@link #token} of these windows
* must be set to the window they are attached to. These types of
* windows are kept next to their attached window in Z-order, and their
* coordinate space is relative to their attached window.
*/
public static final int FIRST_SUB_WINDOW = 1000;
/**
* End of types of sub-windows.
*/
public static final int LAST_SUB_WINDOW = 1999;
/**
* Start of system-specific window types. These are not normally
* created by applications.
*/
public static final int FIRST_SYSTEM_WINDOW = 2000;
/**
* End of types of system windows.
*/
public static final int LAST_SYSTEM_WINDOW = 2999;
常用的Type值如下:
| APP Window | 说明 |
|---|---|
| FIRST_APPLICATION_WINDOW = 1 | 表示应用窗口类型的开始值 |
| TYPE_BASE_APPLICATION = 1 | 所有程序窗口的base窗口,其它APP窗口都显示在它上面 |
| TYPE_APPLICATION = 2 | 普通应用程序窗口 |
| TYPE_APPLICATION_STARTING = 3 | 应用程序启动时显示的窗口 |
| TYPE_DRAWN_APPLICATION = 4 | |
| LAST_APPLICATION_WINDOW = 99 |
| Sub Window | 说明 |
|---|---|
| FIRST_SUB_WINDOW = 1000 | 子窗口的开始值 |
| TYPE_APPLICATION_PANEL = 1000 | 面板窗口,显示于宿主窗口上层 |
| TYPE_APPLICATION_MEDIA = 1001 | |
| TYPE_APPLICATION_SUB_PANEL = 1002 | |
| TYPE_APPLICATION_ATTACHED_DIALOG = 1003 | |
| TYPE_APPLICATION_MEDIA_OVERLAY = 1004 | |
| TYPE_APPLICATION_ABOVE_SUB_PANEL = 1005 | |
| LAST_SUB_WINDOW = 1999 | 子窗口的结束值 |
| System Window | 说明 |
|---|---|
| FIRST_SYSTEM_WINDOW = 2000 | |
| TYPE_STATUS_BAR = 2000 | 状态栏 |
| TYPE_SEARCH_BAR = 2001 | 搜索栏 |
| TYPE_SYSTEM_ALERT = 2003 | 系统窗口,如低电量提示 |
| TYPE_KEYGUARD = 2004 | 锁屏窗口 |
| TYPE_TOAST = 2005 | 显示Toast |
| TYPE_PRIORITY_PHONE = 2007 | 锁屏时的来电UI窗口 |
| … | |
| TYPE_INPUT_METHOD = 2011 | 输入法窗口 |
| TYPE_VOLUME_OVERLAY = 2020 | 系统音量 |
| LAST_SYSTEM_WINDOW = 2999 | 系统窗口结束值 |
Window Layer
而Window Layer则表示Window的显示层级,值越高就距用户越近。Window Layer的最大值如上dumpsys activity containers所示的为36,其值来源如下。
在窗口层级树的构造过程中(见文档”Windoow层级树构建”),相关类如下:
- DisplayAreaPolicyBuilder:层级树的构造器
- Feature:层级树中有多个层(DisplayArea),每一层都有一个Feature,表示DisplayArea对象的特征
- Builder:Feature对象的构造类
DisplayAreaPolicyBuilder.Feature.Builder类中一个boolean[] mLayers成员,定义如下:
private final boolean[] mLayers;
mLayers[]表示持有该Feature的DisplayArea对象可以在层级树中的哪些Layer中存在,如ImePlaceholder:13:14表示输入法位于Layer 13和Layer 14,即Feature.mName=”ImePlaceholder”的Feature,其mLayers[13]=true、mLayers[14]=true,即该Feature作用于13和14层。
而mLayers[]的初始化如下,+1是因为层数没有第0层,最高第n层为mLayers[n],所以数组大小为n+1:
Builder(WindowManagerPolicy policy, String name, int id) {
mPolicy = policy;
mName = name;
mId = id;
mLayers = new boolean[mPolicy.getMaxWindowLayer() + 1];
}
// WindowManagerPolicy.java
// 这里的36表示一个显示屏的层级数目,如注释,它的值应该比getWindowLayerFromTypeLw()中的最大值更大
/**
* Returns the max window layer.
* <p>Note that the max window layer should be higher that the maximum value which reported
* by {@link #getWindowLayerFromTypeLw(int, boolean)} to contain rounded corner overlay.</p>
*
* @see WindowManager.LayoutParams#PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY
*/
default int getMaxWindowLayer() {
return 36;
}
继续看一下WindowManagerPolicy.getWindowLayerFromTypeLw()
default int getWindowLayerFromTypeLw(int type, boolean canAddInternalSystemWindow) {
return getWindowLayerFromTypeLw(type, canAddInternalSystemWindow,
false /* roundedCornerOverlay */);
}
这里返回的最大值为case TYPE_POINTER的35,所以getMaxWindowLayer()设为36
default int getWindowLayerFromTypeLw(int type, boolean canAddInternalSystemWindow,
boolean roundedCornerOverlay) {
// Always put the rounded corner layer to the top most.
if (roundedCornerOverlay && canAddInternalSystemWindow) {
return getMaxWindowLayer();
}
if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
return APPLICATION_LAYER;
}
switch (type) {
case TYPE_WALLPAPER:
// wallpaper is at the bottom, though the window manager may move it.
return 1;
case TYPE_PRESENTATION:
case TYPE_PRIVATE_PRESENTATION:
case TYPE_DOCK_DIVIDER:
case TYPE_QS_DIALOG:
case TYPE_PHONE:
return 3;
case TYPE_SEARCH_BAR:
return 4;
case TYPE_INPUT_CONSUMER:
return 5;
case TYPE_SYSTEM_DIALOG:
return 6;
case TYPE_TOAST:
// toasts and the plugged-in battery thing
return 7;
case TYPE_PRIORITY_PHONE:
// SIM errors and unlock. Not sure if this really should be in a high layer.
return 8;
case TYPE_SYSTEM_ALERT:
// like the ANR / app crashed dialogs
// Type is deprecated for non-system apps. For system apps, this type should be
// in a higher layer than TYPE_APPLICATION_OVERLAY.
return canAddInternalSystemWindow ? 12 : 9;
case TYPE_APPLICATION_OVERLAY:
return 11;
case TYPE_INPUT_METHOD:
// on-screen keyboards and other such input method user interfaces go here.
return 13;
case TYPE_INPUT_METHOD_DIALOG:
// on-screen keyboards and other such input method user interfaces go here.
return 14;
case TYPE_STATUS_BAR:
return 15;
case TYPE_STATUS_BAR_ADDITIONAL:
return 16;
case TYPE_NOTIFICATION_SHADE:
return 17;
case TYPE_STATUS_BAR_SUB_PANEL:
return 18;
case TYPE_KEYGUARD_DIALOG:
return 19;
case TYPE_VOICE_INTERACTION_STARTING:
return 20;
case TYPE_VOICE_INTERACTION:
// voice interaction layer should show above the lock screen.
return 21;
case TYPE_VOLUME_OVERLAY:
// the on-screen volume indicator and controller shown when the user
// changes the device volume
return 22;
case TYPE_SYSTEM_OVERLAY:
// the on-screen volume indicator and controller shown when the user
// changes the device volume
return canAddInternalSystemWindow ? 23 : 10;
case TYPE_NAVIGATION_BAR:
// the navigation bar, if available, shows atop most things
return 24;
case TYPE_NAVIGATION_BAR_PANEL:
// some panels (e.g. search) need to show on top of the navigation bar
return 25;
case TYPE_SCREENSHOT:
// screenshot selection layer shouldn't go above system error, but it should cover
// navigation bars at the very least.
return 26;
case TYPE_SYSTEM_ERROR:
// system-level error dialogs
return canAddInternalSystemWindow ? 27 : 9;
case TYPE_MAGNIFICATION_OVERLAY:
// used to highlight the magnified portion of a display
return 28;
case TYPE_DISPLAY_OVERLAY:
// used to simulate secondary display devices
return 29;
case TYPE_DRAG:
// the drag layer: input for drag-and-drop is associated with this window,
// which sits above all other focusable windows
return 30;
case TYPE_ACCESSIBILITY_OVERLAY:
// overlay put by accessibility services to intercept user interaction
return 31;
case TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY:
return 32;
case TYPE_SECURE_SYSTEM_OVERLAY:
return 33;
case TYPE_BOOT_PROGRESS:
return 34;
case TYPE_POINTER:
// the (mouse) pointer layer
return 35;
default:
Slog.e("WindowManager", "Unknown window type: " + type);
return 3;
}
}
而窗口层级36个Layer,为了显示更多图层,又可细分为WindowState.mBaseLayer和WindowState.mSubLayer。mBaseLayer和mSubLayer是在WindowState的构造函数中赋值的。
mBaseLayer与mSubLayer
(1) 说明
final int mBaseLayer;
mBaseLayer:是一个final类型的固定不变的值,只和窗口Type有关。它在WindowState的构造方法中赋值。mBaseLayer越大,窗口及其子窗口显示就越靠前。
final int mSubLayer;
mSubLayer:也是一个final类型的固定不变的值,SubLayer值是用来确定子窗口和父窗口之间的相对位置的。mSubLayer越大,该窗口相对于其兄弟窗口(同一父窗口下的其它子窗口)就越靠前。
(2) mBaseLayer与mSubLayer的初始化
mBaseLayer和mSubLayer是在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和主窗口一致,这里传入WindowState parentWindow,也就是父窗口获取mBaseLayer
// 然后通过自身的窗口Type获取到mSubLayer
mBaseLayer = mPolicy.getWindowLayerLw(parentWindow)
* TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
mSubLayer = mPolicy.getSubWindowLayerFromTypeLw(a.type);
mIsChildWindow = true;
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 {
// The multiplier here is to reserve space for multiple
// windows in the same type layer.
// 当前窗口不是子窗口,所以传入自身WindowState获取mBaseLayer
// 并且主窗口的mSubLayer=0
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的计算
// 对子窗口,其mBaseLayer和父窗口一样,所以传入parentWindow即可
mBaseLayer = mPolicy.getWindowLayerLw(parentWindow)
* TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
// 对主窗口,传入自身即可
mBaseLayer = mPolicy.getWindowLayerLw(this)
* TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
// 传入WindowState,win.getBaseType()获取到该WindowState的Type值
default int getWindowLayerLw(WindowState win) {
return getWindowLayerFromTypeLw(win.getBaseType(), win.canAddInternalSystemWindow());
}
// 继续调用重载的getWindowLayerFromTypeLw()
default int getWindowLayerFromTypeLw(int type, boolean canAddInternalSystemWindow) {
return getWindowLayerFromTypeLw(type, canAddInternalSystemWindow,
false /* roundedCornerOverlay */);
}
// 最终在这里通过窗口Type返回一个值赋给mBaseLayer,值的范围为[1,35],不包含2
default int getWindowLayerFromTypeLw(int type, boolean canAddInternalSystemWindow,
boolean roundedCornerOverlay) {
// Always put the rounded corner layer to the top most.
if (roundedCornerOverlay && canAddInternalSystemWindow) {
return getMaxWindowLayer();
}
if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
return APPLICATION_LAYER;
}
switch (type) {
case TYPE_WALLPAPER:
// wallpaper is at the bottom, though the window manager may move it.
return 1;
case TYPE_PRESENTATION:
case TYPE_PRIVATE_PRESENTATION:
case TYPE_DOCK_DIVIDER:
case TYPE_QS_DIALOG:
case TYPE_PHONE:
return 3;
case TYPE_SEARCH_BAR:
return 4;
case TYPE_INPUT_CONSUMER:
return 5;
case TYPE_SYSTEM_DIALOG:
return 6;
case TYPE_TOAST:
// toasts and the plugged-in battery thing
return 7;
case TYPE_PRIORITY_PHONE:
// SIM errors and unlock. Not sure if this really should be in a high layer.
return 8;
case TYPE_SYSTEM_ALERT:
// like the ANR / app crashed dialogs
// Type is deprecated for non-system apps. For system apps, this type should be
// in a higher layer than TYPE_APPLICATION_OVERLAY.
return canAddInternalSystemWindow ? 12 : 9;
case TYPE_APPLICATION_OVERLAY:
return 11;
case TYPE_INPUT_METHOD:
// on-screen keyboards and other such input method user interfaces go here.
return 13;
case TYPE_INPUT_METHOD_DIALOG:
// on-screen keyboards and other such input method user interfaces go here.
return 14;
case TYPE_STATUS_BAR:
return 15;
case TYPE_STATUS_BAR_ADDITIONAL:
return 16;
case TYPE_NOTIFICATION_SHADE:
return 17;
case TYPE_STATUS_BAR_SUB_PANEL:
return 18;
case TYPE_KEYGUARD_DIALOG:
return 19;
case TYPE_VOICE_INTERACTION_STARTING:
return 20;
case TYPE_VOICE_INTERACTION:
// voice interaction layer should show above the lock screen.
return 21;
case TYPE_VOLUME_OVERLAY:
// the on-screen volume indicator and controller shown when the user
// changes the device volume
return 22;
case TYPE_SYSTEM_OVERLAY:
// the on-screen volume indicator and controller shown when the user
// changes the device volume
return canAddInternalSystemWindow ? 23 : 10;
case TYPE_NAVIGATION_BAR:
// the navigation bar, if available, shows atop most things
return 24;
case TYPE_NAVIGATION_BAR_PANEL:
// some panels (e.g. search) need to show on top of the navigation bar
return 25;
case TYPE_SCREENSHOT:
// screenshot selection layer shouldn't go above system error, but it should cover
// navigation bars at the very least.
return 26;
case TYPE_SYSTEM_ERROR:
// system-level error dialogs
return canAddInternalSystemWindow ? 27 : 9;
case TYPE_MAGNIFICATION_OVERLAY:
// used to highlight the magnified portion of a display
return 28;
case TYPE_DISPLAY_OVERLAY:
// used to simulate secondary display devices
return 29;
case TYPE_DRAG:
// the drag layer: input for drag-and-drop is associated with this window,
// which sits above all other focusable windows
return 30;
case TYPE_ACCESSIBILITY_OVERLAY:
// overlay put by accessibility services to intercept user interaction
return 31;
case TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY:
return 32;
case TYPE_SECURE_SYSTEM_OVERLAY:
return 33;
case TYPE_BOOT_PROGRESS:
return 34;
case TYPE_POINTER:
// the (mouse) pointer layer
return 35;
default:
Slog.e("WindowManager", "Unknown window type: " + type);
return 3;
}
}
通过:
mBaseLayer = mPolicy.getWindowLayerLw(this)
* TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
/**
* 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.
*/
int TYPE_LAYER_MULTIPLIER = 10000;
/**
* Offset from TYPE_LAYER_MULTIPLIER for moving a group of windows above
* or below others in the same layer.
*/
int TYPE_LAYER_OFFSET = 1000;
可以得知,mBaseLayer = WindowLayer * 10000 + 1000。
乘以10000是为了在不同类型的窗口之间有足够的差值,以容纳同一类型的多个窗口。
mSubLayer的计算
只有子窗口才会有mSubLayer值,主窗口的mSubLayer=0
// 子窗口调用WindowManagerPolicy.getSubWindowLayerFromTypeLw()
mSubLayer = mPolicy.getSubWindowLayerFromTypeLw(a.type);
// 返回具体值
default int getSubWindowLayerFromTypeLw(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
}
Slog.e("WindowManager", "Unknown sub-window type: " + type);
return 0;
}
其中APPLICATION_MEDIA_SUBLAYER = -2,说明子窗口是可以在主窗口下方,主窗口如果可以看到子窗口,必须透明。
窗口Layer的调整
但是如果当前系统中有10个应用程序窗口,那么它们的窗口Type是系统的,所以其mBaseLayer也是相同的。显然不可能全部显示,于是就需要进行后期调整。