窗口层级概述

Post on Feb 08, 2023 by Wei Lin

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子类及继承树如下:

image-20240226224053816

说明
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?

安卓12窗口层次: DisplayArea树——CSDN

DisplayAreaGroup就是一组DisplayArea,用来表示屏幕的一部分内容(这部分由DisplayArea组成)。之所以添加DisplayAreaGroup,主要还是为了功能拓展。

image-20240226224147510

一个屏幕上想显示多个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]

绘制出其树形图为:

image-20240226224301544

以上信息表示在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也是相同的。显然不可能全部显示,于是就需要进行后期调整。