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();
// 获取默认屏幕的 DefaultTaskDisplayArea
final TaskDisplayArea defaultTaskDisplayArea = getDefaultTaskDisplayArea();
// 创建home的task
defaultTaskDisplayArea.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
// 添加多一个 TaskDisplayArea
private 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.
// 如果是输入法层级直接赋值对应的 mImeContainer
leafArea.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 layers
fillAreaForLayers(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。这样层技术也就构建完成。