frameworks 之 WMS层级树
- 1. 容器类
- 1. WindowContainer
- 2. RootWindowContainer
- 3. DisplayContent
- 4. DisplayAreas
- 4. 1 DisplayArea.Tokens
- 4. 2 TaskDisplayArea
- 4. 3 DisplayArea.Dimmable
- 5. WindowToken
- 5.1 WallpaperWindowToken
- 5.2 ActivityRecord
- 6. TaskFragment
- 6.1 Task
- 7 WindowState
- 2. 层级树构建
- 2.1 层级命令
- 2.2 构建入口
- 2.3 构建 DisplayContent
- 2.4 构建对应屏幕的层级树入口
- 2.5 层级树构建
- 2.5.1 构建特征
- 2.5.1 构建层级树
android 系统 为了方便各个层级的view管理。创建了对应的层级树。
涉及到的类如下
- frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
- frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java
- frameworks/base/services/core/java/com/android/server/wm/DisplayAreaPolicy.java
- frameworks/base/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
- frameworks/base/services/core/java/com/android/server/policy/WindowManagerPolicy.java
- frameworks/base/core/java/android/window/DisplayAreaOrganizer.java
1. 容器类
1. WindowContainer
android 所有的容器类最终父类都都为 WindowContainer ,负责对view的添加和移除。他的子类通过泛型指定,各个子类重写一些的方法,实现对应的特有逻辑。一些重要属性如下
方法/属性 | 意义 |
---|---|
mParent | 父容器 |
mChildren | 添加到该容器子容器。列表的顺序也就是子容器出现在屏幕上的顺序,最顶层的子容器位于队尾 |
addChild | 添加子容器 |
2. RootWindowContainer
根窗口容器,树的开始节点。通过它遍历寻找,可以找到窗口树上的窗口。它的孩子是DisplayContent
public class RootWindowContainer extends WindowContainer<DisplayContent>
3. DisplayContent
该容器作用是对应着显示屏幕的,Android是支持多屏幕的,所以可能存在多个DisplayContent对象。
通过 【View】-【Tool Windows】-【Hierarchy】 , ctrl + h 打开面板 可以看到对应继承关系
4. DisplayAreas
DisplayArea由 DisplayAreaPolicy 管理,能够复写Configuration和被绑定到leash上。
DisplayArea可以包含嵌套的DisplayArea。
DisplayAreas有三种风格,以确保窗口具有正确的Z顺序:
BELOW_TASKS:只能包含位于任务下方的BELLOW_TASK显示区域和WindowToken。
ABOVE_TASKS:只能包含位于任务上方的ABOVE_TASK显示区域和WindowToken。
ANY:可以包含任何类型的DisplayArea,以及任何类型的WindowToken或Task容器。
@param<T>DisplayArea的子项的类型。
DisplayArea有三个直接子类,TaskDisplayArea,DisplayArea.Tokens和DisplayArea.Dimmable
4. 1 DisplayArea.Tokens
Tokens 负责装载 WindowToken 容器。他还有子类为 ImeContainer。所以他的容器也为tokens。
public static class Tokens extends DisplayArea<WindowToken>
4. 2 TaskDisplayArea
TaskDisplayArea代表了屏幕上的一个包含App类型的WindowContainer的区域。它的子节点可以是Task,或者是TaskDisplayArea。TaskDisplayArea为DisplayContent的孩子,对应着窗口层次的第2层。第2层作为应用层,看它的定义:int APPLICATION_LAYER = 2。DefaultTaskDisplay是TaskDisplayArea的别名
final class TaskDisplayArea extends DisplayArea<WindowContainer>
4. 3 DisplayArea.Dimmable
Dimmable是DisplayArea的内部类,该容器添加模糊效果,并且Dimmable也是一个DisplayArea类型的DisplayArea容器。
可以通过Dimmer对象mDimmer施加模糊效果,模糊图层可以插入到以该Dimmable对象为根节点的层级结构之下的任意两个图层之间。
且它有一个直接子类,RootDisplayArea
static class Dimmable extends DisplayArea<DisplayArea> {
5. WindowToken
:窗口管理器中一组相关窗口的容器。这通常是一个AppWindowToken,它是用于显示窗口的“活动”的句柄。对于嵌套窗口,会为父窗口创建一个WindowToken来管理其子窗口。
总而言之就是用WindowToken来管理WindowState。他的管理的容器是 winowState,管理他的容器是 Tokens。他的子类有ActivityRecord, wallpaperwindowToken。
class WindowToken extends WindowContainer<WindowState> {
5.1 WallpaperWindowToken
WallpaperWindowToken继承WindowToken,是用来存放和Wallpaper相关的窗口。
5.2 ActivityRecord
ActivityRecord是WindowToken的子类,在WMS中一个ActivityRecord对象就代表一个Activity对象
6. TaskFragment
TaskFragment继承WindowContainer,一个基本容器,可用于包含Activity或其他TaskFragment,管理Activity生命周期并更新其中活动的可见性。
从层级结构角度来说,与Activity嵌入(Activity Embedding)、平行视界等场景有关。平行视界的分屏模式时,两个Activity将同时显示,而Task本身不提供这个能力,而是由TaskFragment来实现。TaskFragment插入到Task和Activity之间,分割了Task在屏幕上的显示区域,提供给平行视界的两个Activity。
6.1 Task
Task的孩子可以是Task,也可以是ActivityRecord类型。是一个TaskFragment,它可以包含一组执行特定作业的Activity。具有相同任务相似性的Activity通常在同一任务中分组。任务也可以是显示在用户交互的作业的最近屏幕中的实体。任务还可以包含其他任务。
这些Activity可以是来自同一个App,也可以是来自不同的Apps,Activity之间不一定非得相关联。当我们按home键旁边那个方形键(recent-apps)时,屏幕上展示的就是一个个Task。
7 WindowState
作为最底层的容器,一个WindowState对象就代表了一个窗口,其继承WindowContainer,这就说明WindowState同样可以作为其他窗口的父容器,例如我们常见的PopupWindow
最终显示的对应容器大概关系如下图
2. 层级树构建
2.1 层级命令
如何查看当前系统的层级,可以用 如下命令获取。#号前面数字表示该层级有多少个,启始从0开始。每缩进代表归属的下个层级。
adb shell dumpsys activity containers
2.2 构建入口
我们可以从dump出来的日志搜索关键字DefaultTaskDisplayArea 查找入口,或者我们从上面知道最顶层为 RootWindowContainer 查找该类添加入口。
grep "\"DefaultTaskDisplayArea" ./ -rn
找到后一直往上推或在在该位置打印日志堆栈可以知道。构建时机为 startOtherServices 里面的 AMS 的 setWindowManager 方法。
frameworks/base/services/java/com/android/server/SystemServer.java
mActivityManagerService.setWindowManager(wm);
AMS 会获取 WMS的 rootWindowContainer 并调用 setWindowManager 方法。
public void setWindowManager(WindowManagerService wm) {synchronized (mGlobalLock) {mWindowManager = wm;mRootWindowContainer = wm.mRoot;...mRootWindowContainer.setWindowManager(wm);}}
2.3 构建 DisplayContent
rootWindowContainer 的 setWindowManager
- 调用 DisplayManager 的 getDisplays 方法获取屏幕数组
- 遍历创建对应 DisplayContent,并通过 addChild 添加到 rootWindowContainer 中
- 获取默认屏幕的DefaultTaskDisplayArea
- 调用 getOrCreateRootHomeTask 创建home的task
void setWindowManager(WindowManagerService wm) {mWindowManager = wm;mDisplayManager = mService.mContext.getSystemService(DisplayManager.class);mDisplayManager.registerDisplayListener(this, mService.mUiHandler);mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);// 遍历每个屏幕,构造层级树 在DisplayContent的构造方法里 DefaultTaskDisplayArea 在里面添加final Display[] displays = mDisplayManager.getDisplays();for (int displayNdx = 0; displayNdx < displays.length; ++displayNdx) {final Display display = displays[displayNdx];final DisplayContent displayContent = new DisplayContent(display, this);addChild(displayContent, POSITION_BOTTOM);if (displayContent.mDisplayId == DEFAULT_DISPLAY) {mDefaultDisplay = displayContent;}}calculateDefaultMinimalSizeOfResizeableTasks();// 获取默认屏幕的 DefaultTaskDisplayAreafinal TaskDisplayArea defaultTaskDisplayArea = getDefaultTaskDisplayArea();// 创建home的taskdefaultTaskDisplayArea.getOrCreateRootHomeTask(ON_TOP);positionChildAt(POSITION_TOP, defaultTaskDisplayArea.mDisplayContent,false /* includingParents */);}
2.4 构建对应屏幕的层级树入口
DisplayContent 初始化在其构造方法的内,会开始构建对应的层级树。
构建方法 在 configureSurfaces
DisplayContent(Display display, RootWindowContainer root) {super(root.mWindowManager, "DisplayContent", FEATURE_ROOT);...// 开始创建窗口树configureSurfaces(pendingTransaction);...}
configureSurfaces 主要内容
- 构建对应的SurfaceControl
- 判断构建显示策略mDisplayAreaPolicy 是否为空,为空创建,作为第一次肯定为空,调用WMS构造方法创建好的进行返回,通过方法 DisplayAreaPolicy.Provider.fromResources 读取的是资源字符串string的config_deviceSpecificDisplayAreaPolicyProvider值是否为空,为空则返回默认的 isplayAreaPolicy.DefaultProvider 构建,不为空则反射创建。
- 调用 instantiate 方法进行初始化
private void configureSurfaces(Transaction transaction) {final SurfaceControl.Builder b = mWmService.makeSurfaceBuilder(mSession).setOpaque(true).setContainerLayer().setCallsite("DisplayContent");mSurfaceControl = b.setName(getName()).setContainerLayer().build();if (mDisplayAreaPolicy == null) {// Setup the policy and build the display area hierarchy.// Build the hierarchy only after creating the surface so it is reparented correctly// 第一次为空,创建mDisplayAreaPolicy = mWmService.getDisplayAreaPolicyProvider().instantiate(mWmService, this /* content */, this /* root */,mImeWindowsContainer);}...}
2.5 层级树构建
instantiate 方法传进参数 DisplayContent 和 RootDisplayArea 都为this当前的对象,并传进已构建好的 imeContainer 。方法具体内容
- 创建对应的 TaskDisplayArea ,名称为 DefaultTaskDisplayArea
- 创建 TaskDisplayArea 的数组并将其添加进去
- 传建对应的分层构建对象 HierarchyBuilder ,传进入的root 为 当前的DisplayContent,并设置 输入法容器 和显示区域容器
- 调用 configureTrustedHierarchyBuilder 开始配置特征(2.5.1)
- 将创建好的特征放到 通过 setRootHierarchy 方法放到 DisplayAreaPolicyBuilder 对象,并调用build方法进村构建(2.5.2)
public DisplayAreaPolicy instantiate(WindowManagerService wmService,DisplayContent content, RootDisplayArea root,DisplayArea.Tokens imeContainer) {final TaskDisplayArea defaultTaskDisplayArea = new TaskDisplayArea(content, wmService,"DefaultTaskDisplayArea", FEATURE_DEFAULT_TASK_CONTAINER);final List<TaskDisplayArea> tdaList = new ArrayList<>();tdaList.add(defaultTaskDisplayArea);// Define the features that will be supported under the root of the whole logical// display. The policy will build the DisplayArea hierarchy based on this.final HierarchyBuilder rootHierarchy = new HierarchyBuilder(root);// Set the essential containers (even if the display doesn't support IME).rootHierarchy.setImeContainer(imeContainer).setTaskDisplayAreas(tdaList);if (content.isTrusted()) {// Only trusted display can have system decorations.// 进行创建configureTrustedHierarchyBuilder(rootHierarchy, wmService, content);}// Instantiate the policy with the hierarchy defined above. This will create and attach// all the necessary DisplayAreas to the root.return new DisplayAreaPolicyBuilder().setRootHierarchy(rootHierarchy).build(wmService);}
2.5.1 构建特征
configureTrustedHierarchyBuilder 方法 不断通过 addFeature,将对应的特征加入里面的 mFeatures 数组
Feature.Builder 的类负责构建对应的内容,并通过 build 方法创建。
- 里面的 mLayers 数组大小根据 WindowManagerPolicy 的 getMaxWindowLayer 最大的层级获取,默认为36 。该数组值 false 表示该特征不占用这层,true则为是。
- 调用方法Build 传建feature的时候会将最大的层级置为 false。
Feature build() {if (mExcludeRoundedCorner) {// Always put the rounded corner layer to the top most layer.// 创建的时候将最大的层级排除mLayers[mPolicy.getMaxWindowLayer()] = false;}return new Feature(mName, mId, mLayers.clone(), mNewDisplayAreaSupplier);}
涉及主要方法如下
方法 | 意义 |
---|---|
all | 将数组全部置为true,表示全部可用 |
and | 将指定的层级置为true |
except | 将指定的层级置为false,表示不可用 |
upTo | 将从0到指定的层级置为true |
set | 将对应的层级,设置为指定的属性,控制可用不可用 |
对应特征的创建代码范围标注如下
private void configureTrustedHierarchyBuilder(HierarchyBuilder rootHierarchy,WindowManagerService wmService, DisplayContent content) {// WindowedMagnification should be on the top so that there is only one surface// to be magnified.rootHierarchy.addFeature(new Feature.Builder(wmService.mPolicy, "WindowedMagnification",FEATURE_WINDOWED_MAGNIFICATION).upTo(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY) // [0,32].except(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY) //32// Make the DA dimmable so that the magnify window also mirrors the dim layer..setNewDisplayAreaSupplier(DisplayArea.Dimmable::new).build()); // [0, 31]if (content.isDefaultDisplay) {// Only default display can have cutout.// See LocalDisplayAdapter.LocalDisplayDevice#getDisplayDeviceInfoLocked.rootHierarchy.addFeature(new Feature.Builder(wmService.mPolicy, "HideDisplayCutout",FEATURE_HIDE_DISPLAY_CUTOUT).all() // [0 ,36].except(TYPE_NAVIGATION_BAR, TYPE_NAVIGATION_BAR_PANEL, TYPE_STATUS_BAR,TYPE_NOTIFICATION_SHADE) // 24, 25, 20, 19.build()) // [0, 18] [21, 23] [26 35].addFeature(new Feature.Builder(wmService.mPolicy,"OneHandedBackgroundPanel",FEATURE_ONE_HANDED_BACKGROUND_PANEL).upTo(TYPE_WALLPAPER) //1.build()) // 1.addFeature(new Feature.Builder(wmService.mPolicy, "OneHanded",FEATURE_ONE_HANDED).all() // [0 ,36].except(TYPE_NAVIGATION_BAR, TYPE_NAVIGATION_BAR_PANEL) // 24, 25.build()); // [0, 23] [26, 35]}rootHierarchy.addFeature(new Feature.Builder(wmService.mPolicy, "FullscreenMagnification",FEATURE_FULLSCREEN_MAGNIFICATION).all() // [0 ,36].except(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY, TYPE_INPUT_METHOD,TYPE_INPUT_METHOD_DIALOG, TYPE_MAGNIFICATION_OVERLAY,TYPE_NAVIGATION_BAR, TYPE_NAVIGATION_BAR_PANEL) // 32 15 16 28 25 26.build()) // [0, 14] [17 ,24] [27, 27] [29, 31] [33, 35].addFeature(new Feature.Builder(wmService.mPolicy, "ImePlaceholder",FEATURE_IME_PLACEHOLDER).and(TYPE_INPUT_METHOD, TYPE_INPUT_METHOD_DIALOG) // 15 , 16.build()); //[15, 16]}
2.5.1 构建层级树
创建完特征后会传建 DisplayAreaPolicyBuilder 并调用setRootHierarchy 传进入 HierarchyBuilder对象,在调用 build方法。最主要是调用对应 HierarchyBuilder 的buld 方法开始创建。
- 根据getMaxWindowLayer 最大层级数量,创建 DisplayArea.Tokens 数组
- 创建 featureAreas map key为Feature,value为 DisplayArea 数组。
- 定一个个36位数组 areaForLayer,用于存放意向 , 并将全部填充为0 即根节点
- 传建临时变量 featureArea,用于接下来遍历判断是否和上一个层级一样,不是则创建并添加到对应的childs。避免重复添加一样的。
- 开始遍历对应的特征,每个特征遍历之前设置好的 windowLayers 布尔数组。如果为true代表该层级可用
private void build(@Nullable List<HierarchyBuilder> displayAreaGroupHierarchyBuilders) {final WindowManagerPolicy policy = mRoot.mWmService.mPolicy;final int maxWindowLayerCount = policy.getMaxWindowLayer() + 1;final DisplayArea.Tokens[] displayAreaForLayer =new DisplayArea.Tokens[maxWindowLayerCount];final Map<Feature, List<DisplayArea<WindowContainer>>> featureAreas =new ArrayMap<>(mFeatures.size());for (int i = 0; i < mFeatures.size(); i++) {featureAreas.put(mFeatures.get(i), new ArrayList<>());}...// 定一个个36位数组,用于存放构建树, 先将全部填充为0 即根节点PendingArea[] areaForLayer = new PendingArea[maxWindowLayerCount];final PendingArea root = new PendingArea(null, 0, null);Arrays.fill(areaForLayer, root);// Create DisplayAreas to cover all defined features.final int size = mFeatures.size();// 遍历上面添加的对应的特征for (int i = 0; i < size; i++) {// Traverse the features with the order they are defined, so that the early defined// feature will be on the top in the hierarchy.final Feature feature = mFeatures.get(i);PendingArea featureArea = null;// 遍历每个特征里面每个层级的允许情况for (int layer = 0; layer < maxWindowLayerCount; layer++) {if (feature.mWindowLayers[layer]) {// This feature will be applied to this window layer.//// We need to find a DisplayArea for it:// We can reuse the existing one if it was created for this feature for the// previous layer AND the last feature that applied to the previous layer is// the same as the feature that applied to the current layer (so they are ok// to share the same parent DisplayArea).// 如果不为空,或在上一个的父节点和当前的每个层级的节点不一样,就要新建并放到对应的儿节点// 好比特征区间是 0到31 不会root下面添加多个该节点只会添加1个// 如果区间 是 0到31 33到35 则会添加2个,中间因为为false featureArea会被置为空// 但是数组areaForLayer从0到31都会放该特征,始终维持该数组为树的最下层数据,为下次特征遍历添加子节点if (featureArea == null || featureArea.mParent != areaForLayer[layer]) {// No suitable DisplayArea:// Create a new one under the previous area (as parent) for this layer.// 创建关联对应的父节点featureArea = new PendingArea(feature, layer, areaForLayer[layer]);// 父节点添加他areaForLayer[layer].mChildren.add(featureArea);}areaForLayer[layer] = featureArea;} else {// This feature won't be applied to this window layer. If it needs to be// applied to the next layer, we will need to create a new DisplayArea for// that.featureArea = null;}}}...}
- 特征添加完毕后,就开始添加叶子节点,构建临时 leafArea 用于判断。
- 根据最大层级树开始遍历
- 遍历的开始调用 typeOfLayer 区分特殊的层级,TYPE_INPUT_METHOD 和 TYPE_INPUT_METHOD_DIALOG 返回 LEAF_TYPE_IME_CONTAINERS,APPLICATION_LAYER 返回 LEAF_TYPE_TASK_CONTAINERS
private static int typeOfLayer(WindowManagerPolicy policy, int layer) {if (layer == APPLICATION_LAYER) {return LEAF_TYPE_TASK_CONTAINERS;} else if (layer == policy.getWindowLayerFromTypeLw(TYPE_INPUT_METHOD)|| layer == policy.getWindowLayerFromTypeLw(TYPE_INPUT_METHOD_DIALOG)) {return LEAF_TYPE_IME_CONTAINERS;} else {return LEAF_TYPE_TOKENS;}}
- 跟上面特征一样,也是通过判断 叶子和上一个层级是否一样,不一样则创建新的叶子节点并添加到 mChildren 中,特殊的是还判断了叶子的类型是否一样,不一样也传建新的。
- 判断不一样后,在传建的时候还会判断该叶子节点属于什么类型。
` 如果是 应用层级 LEAF_TYPE_TASK_CONTAINERS 类型,则通过 addTaskDisplayAreasToApplicationLayer 方法,遍历显示区域,因为设置进去只有一个(DefaultTaskDisplayArea),所以则会添加一个 PendingArea 并将 DefaultTaskDisplayArea 赋值给 mExisting 属性。通过 addDisplayAreaGroupsToApplicationLayer 方法 添加 PendingArea,不过目前数组为0 所以不会添加。最后设置对应叶子节点 mSkipTokens 为 true
// 添加多一个 TaskDisplayAreaprivate void addTaskDisplayAreasToApplicationLayer(PendingArea parentPendingArea) {final int count = mTaskDisplayAreas.size();for (int i = 0; i < count; i++) {PendingArea leafArea =new PendingArea(null /* feature */, APPLICATION_LAYER, parentPendingArea);leafArea.mExisting = mTaskDisplayAreas.get(i);leafArea.mMaxLayer = APPLICATION_LAYER;parentPendingArea.mChildren.add(leafArea);}}
如果是 输入法层级 LEAF_TYPE_IME_CONTAINERS ,则将传进入的 mImeContainer 赋值给 mSkipTokens。并mSkipTokens 为 true。
private void build(@Nullable List<HierarchyBuilder> displayAreaGroupHierarchyBuilders) {...// Create Tokens as leaf for every layer.// 为每个层级添加一个叶子节点PendingArea leafArea = null;int leafType = LEAF_TYPE_TOKENS;for (int layer = 0; layer < maxWindowLayerCount; layer++) {// 对输入法和应用层级返回特殊的判断int type = typeOfLayer(policy, layer);// Check whether we can reuse the same Tokens with the previous layer. This happens// if the previous layer is the same type as the current layer AND there is no// feature that applies to only one of them.if (leafArea == null || leafArea.mParent != areaForLayer[layer]|| type != leafType) {// Create a new Tokens for this layer.leafArea = new PendingArea(null /* feature */, layer, areaForLayer[layer]);areaForLayer[layer].mChildren.add(leafArea);leafType = type;// 特殊层级会将 mSkipTokens 置为true 构建时候会跳过该对象if (leafType == LEAF_TYPE_TASK_CONTAINERS) {// We use the passed in TaskDisplayAreas for task container type of layer.// Skip creating Tokens even if there is no TDA.// 如果是应用层级会添加一个TaskDisplayArea层级addTaskDisplayAreasToApplicationLayer(areaForLayer[layer]);addDisplayAreaGroupsToApplicationLayer(areaForLayer[layer],displayAreaGroupHierarchyBuilders);leafArea.mSkipTokens = true;} else if (leafType == LEAF_TYPE_IME_CONTAINERS) {// We use the passed in ImeContainer for ime container type of layer.// Skip creating Tokens even if there is no ime container.// 如果是输入法层级直接赋值对应的 mImeContainerleafArea.mExisting = mImeContainer;leafArea.mSkipTokens = true;}}leafArea.mMaxLayer = layer;}...}
- 调用 computeMaxLayer 递归 获取最大层级,并保存到 mMaxLayer 变量。
- 调用 instantiateChildren 方法将对应 pendingArea 转化为 DisplayArea,通过遍历递归对应 mChildren。调用createArea方法创建对象,并通过 addChild 添加到 RootDisplayArea 中, 也根据特征放到对应的map 中。 方法一开始传进去的为 displayContent 。
void instantiateChildren(DisplayArea<DisplayArea> parent, DisplayArea.Tokens[] areaForLayer,int level, Map<Feature, List<DisplayArea<WindowContainer>>> areas) {mChildren.sort(Comparator.comparingInt(pendingArea -> pendingArea.mMinLayer));for (int i = 0; i < mChildren.size(); i++) {final PendingArea child = mChildren.get(i);final DisplayArea area = child.createArea(parent, areaForLayer);if (area == null) {// TaskDisplayArea and ImeContainer can be set at different hierarchy, so it can// be null.continue;}// 创建parent.addChild(area, WindowContainer.POSITION_TOP);if (child.mFeature != null) {areas.get(child.mFeature).add(area);}// 循环递归child.instantiateChildren(area, areaForLayer, level + 1, areas);}}
createArea 方法 步骤
- 判断 mExisting 是否为空,并且为 tokens 则调用 fillAreaForLayers,将该属于该层级的赋值给传进来的 DisplayArea.Tokens[] areaForLayer 数组。为 ImeContainer
- 判断 mSkipTokens 是否为true, 之前的 应用层级 返回 null 。
- 判断对应的层级跟 APPLICATION_LAYER 相比。定义对应的类型。
- 判断 mFeature 是否为 null 。为null为叶子节点 为 DisplayArea.Tokens。 不为null 为特征节点。根据 mNewDisplayAreaSupplier 进行创建,调用的是对应的构造函数,大部分为 DisplayArea。WindowedMagnification 为 DisplayArea.Dimmable
private DisplayArea createArea(DisplayArea<DisplayArea> parent,DisplayArea.Tokens[] areaForLayer) {// 特殊层级的赋值 mExisting 不为空if (mExisting != null) {// 输入法的不为空 走这里if (mExisting.asTokens() != null) {// Store the WindowToken container for layersfillAreaForLayers(mExisting.asTokens(), areaForLayer);}return mExisting;}// 之前特殊层级设置了为true,就会直接跳过if (mSkipTokens) {return null;}DisplayArea.Type type;if (mMinLayer > APPLICATION_LAYER) {type = DisplayArea.Type.ABOVE_TASKS;} else if (mMaxLayer < APPLICATION_LAYER) {type = DisplayArea.Type.BELOW_TASKS;} else {type = DisplayArea.Type.ANY;}if (mFeature == null) {final DisplayArea.Tokens leaf = new DisplayArea.Tokens(parent.mWmService, type,"Leaf:" + mMinLayer + ":" + mMaxLayer);fillAreaForLayers(leaf, areaForLayer);return leaf;} else {return mFeature.mNewDisplayAreaSupplier.create(parent.mWmService, type,mFeature.mName + ":" + mMinLayer + ":" + mMaxLayer, mFeature.mId);}}
- 调用 onHierarchyBuilt 将填充好的参数 赋值给 mRoot 也即为 displayContent。这样层技术也就构建完成。