1 DisplayArea类的继承关系
DisplayArea类的继承关系,之前已经分析过,这里用一张简单的类图总结:
2 DisplayArea层级结构的生成
既然DisplayContent是作为其代表的屏幕的DisplayArea层级结构的根节点,那么从DisplayContent出发,看一下这棵以DisplayContent为根节点的DisplayArea树是如何生成的。
2.1 DisplayContent.init
/**
* Create new {@link DisplayContent} instance, add itself to the root window container and
* initialize direct children.
* @param display May not be null.
* @param root {@link RootWindowContainer}
*/
DisplayContent(Display display, RootWindowContainer root) {
// ......
// Setup the policy and build the display area hierarchy.
mDisplayAreaPolicy = mWmService.getDisplayAreaPolicyProvider().instantiate(
mWmService, this /* content */, this /* root */, mImeWindowsContainer);
// ......
}
在DisplayContent的构造方法中,调用DisplayAreaPolicy.Provider.instantiate方法,去初始化一个DisplayArea层级结构。
2.2 DisplayAreaPolicy.DefaultProvider.instantiate
DisplayAreaPolicy.Provider只是一个接口,instantiate定义为:
/**
* Instantiates a new {@link DisplayAreaPolicy}. It should set up the {@link DisplayArea}
* hierarchy.
*
* @see DisplayAreaPolicy#DisplayAreaPolicy
*/
DisplayAreaPolicy instantiate(WindowManagerService wmService, DisplayContent content,
RootDisplayArea root, DisplayArea.Tokens imeContainer);
用来实例化一个DisplayAreaPolicy对象,这个对象应该建立起DisplayArea层级结构,实际走到的则是DisplayAreaPolicy.Provider的实现类DisplayAreaPolicy.DefaultProvider.instantiate方法:
@Override
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.2.1 创建HierarchyBuilder
首先注意到,这里的RootDisplayArea类型的传参root即是一个DisplayContent对象,毕竟它是要作为后续创建的DisplayArea层阶结构的根节点。然后根据这个传入的DisplayContent,创建一个HierarchyBuilder对象:
// 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);
HierarchyBuilder定义在DisplayAreaPolicyBuilder中:
/**
* Builder to define {@link Feature} and {@link DisplayArea} hierarchy under a
* {@link RootDisplayArea}
*/
static class HierarchyBuilder {
HierarchyBuilder用来构建一个DisplayArea层级结构,该层级结构的根节点,则是HierarchyBuilder构造方法中传入的RootDisplayArea:
private final RootDisplayArea mRoot;
// ......
HierarchyBuilder(RootDisplayArea root) {
mRoot = root;
}
这里传入的则是一个DisplayContent对象,那么HierarchyBuilder要以这个DisplayContent对象为根节点,生成一个DisplayArea层级结构。
2.2.2 保存ImeContainer到HierarchyBuilder内部
传参imeContainer,则是DisplayContent的成员变量:
// Contains all IME window containers. Note that the z-ordering of the IME windows will depend
// on the IME target. We mainly have this container grouping so we can keep track of all the IME
// window containers together and move them in-sync if/when needed. We use a subclass of
// WindowContainer which is omitted from screen magnification, as the IME is never magnified.
// TODO(display-area): is "no magnification" in the comment still true?
private final ImeContainer mImeWindowsContainer = new ImeContainer(mWmService);
即ImeContainer类型的DisplayArea,在定义的时候已经初始化。
通过HierarchyBuilder.setImeContainer方法:
@Nullable
private DisplayArea.Tokens mImeContainer;
// ......
/** Sets IME container as a child of this hierarchy root. */
HierarchyBuilder setImeContainer(DisplayArea.Tokens imeContainer) {
mImeContainer = imeContainer;
return this;
}
将DisplayContent的mImeWindowsContainer保存在了HierarchyBuilder的mImeContainer成员变量中,后续创建DisplayArea层级结构时可以直接拿来使用。
2.2.3 创建并保存默认TaskDisplayArea到HierarchyBuilder内部
创建一个名为“DefaultTaskDisplayArea”的TaskDisplayArea:
final TaskDisplayArea defaultTaskDisplayArea = new TaskDisplayArea(content, wmService,
"DefaultTaskDisplayArea", FEATURE_DEFAULT_TASK_CONTAINER);
然后将该TaskDisplayArea添加到一个局部List中,调用HierarchyBuilder.setTaskDisplayAreas方法,将该对象保存在了HierarchyBuilder.mTaskDisplayAreas中。
private final ArrayList<TaskDisplayArea> mTaskDisplayAreas = new ArrayList<>();
// ......
/**
* Sets {@link TaskDisplayArea} that are children of this hierarchy root.
* {@link DisplayArea} group must have at least one {@link TaskDisplayArea}.
*/
HierarchyBuilder setTaskDisplayAreas(List<TaskDisplayArea> taskDisplayAreas) {
mTaskDisplayAreas.clear();
mTaskDisplayAreas.addAll(taskDisplayAreas);
return this;
}
另外看到,虽然TaskDisplayArea是支持嵌套的,并且这里也采用了一个ArrayList来管理TaskDisplayArea,但是目前TaskDisplayArea只在这里被创建,即目前一个DisplayContent只有一个名为“DefaultTaskDisplayArea”的TaskDisplayArea。
因为TaskDisplayArea是用来管理Task的,而Task本身就支持嵌套,再加上TaskOrgnizerController,光这两者已经可以为TaskDisplayArea建立起一个比较复杂的Task层级结构了,因此TaskDisplayArea的嵌套目前显得没有必要。
2.2.4 为HierarchyBuilder添加Feature
调用DisplayAreaPolicy.DefaultProvider.configureTrustedHierarchyBuilder为HierarchyBuilder添加Feature:
if (content.isTrusted()) {
// Only trusted display can have system decorations.
configureTrustedHierarchyBuilder(rootHierarchy, wmService, content);
}
接着来看DisplayAreaPolicy.DefaultProvider.configureTrustedHierarchyBuilder方法的具体内容:
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)
.except(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
// Make the DA dimmable so that the magnify window also mirrors the dim layer.
.setNewDisplayAreaSupplier(DisplayArea.Dimmable::new)
.build());
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()
.except(TYPE_NAVIGATION_BAR, TYPE_NAVIGATION_BAR_PANEL, TYPE_STATUS_BAR,
TYPE_NOTIFICATION_SHADE)
.build())
.addFeature(new Feature.Builder(wmService.mPolicy,
"OneHandedBackgroundPanel",
FEATURE_ONE_HANDED_BACKGROUND_PANEL)
.upTo(TYPE_WALLPAPER)
.build())
.addFeature(new Feature.Builder(wmService.mPolicy, "OneHanded",
FEATURE_ONE_HANDED)
.all()
.except(TYPE_NAVIGATION_BAR, TYPE_NAVIGATION_BAR_PANEL)
.build());
}
rootHierarchy
.addFeature(new Feature.Builder(wmService.mPolicy, "FullscreenMagnification",
FEATURE_FULLSCREEN_MAGNIFICATION)
.all()
.except(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY, TYPE_INPUT_METHOD,
TYPE_INPUT_METHOD_DIALOG, TYPE_MAGNIFICATION_OVERLAY,
TYPE_NAVIGATION_BAR, TYPE_NAVIGATION_BAR_PANEL)
.build())
.addFeature(new Feature.Builder(wmService.mPolicy, "ImePlaceholder",
FEATURE_IME_PLACEHOLDER)
.and(TYPE_INPUT_METHOD, TYPE_INPUT_METHOD_DIALOG)
.build());
}
如果当前DisplayContent是默认屏幕,那么会为HierarchyBuilder添加6种Feature,否则是3种,我们只分析一般情况,即当前屏幕是默认屏幕的情况。
Feature是DisplayAreaPolicyBuilder的内部类:
/**
* A feature that requires {@link DisplayArea DisplayArea(s)}.
*/
static class Feature {
private final String mName;
private final int mId;
private final boolean[] mWindowLayers;
private final NewDisplayAreaSupplier mNewDisplayAreaSupplier;
首先Feature代表的是DisplayArea的一个特征,可以根据Feature来对不同的DisplayArea进行划分。
看一下它的成员变量:
- mName,很好理解,这个Feature的名字,如上面的“WindowedMagnification”,“HideDisplayCutout”之类的,后续DisplayArea层级结构建立起来后,每个DisplayArea的名字用的就是当前DisplayArea对应的那个Feature的名字。
- mId,Feature的ID,如上面的FEATURE_WINDOWED_MAGNIFICATION和FEATURE_HIDE_DISPLAY_CUTOUT,虽说是Feature的ID,因为Feature又是DisplayArea的特征,所以这个ID也可以直接代表DisplayArea的一种特征。
- mWindowLayers,代表了这个DisplayArea可以包含哪些层级对应的窗口,后续会分析到。
- mNewDisplayAreaSupplier,
先看第一个Feature:
// 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)
.except(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
// Make the DA dimmable so that the magnify window also mirrors the dim layer.
.setNewDisplayAreaSupplier(DisplayArea.Dimmable::new)
.build());
1)、设置Feature的mName为"WindowedMagnification"。
2)、设置Feature的mId为FEATURE_WINDOWED_MAGNIFICATION,FEATURE_WINDOWED_MAGNIFICATION定义在DisplayAreaOrganizer中:
/**
* Display area that can be magnified in
* {@link Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW}. It contains all windows
* below {@link WindowManager.LayoutParams#TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY}.
*/
public static final int FEATURE_WINDOWED_MAGNIFICATION = FEATURE_SYSTEM_FIRST + 4;
代表了该DisplayArea在ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW模式下可以进行放大,该DisplayArea包含了所有比TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY类型的窗口层级低的窗口,为什么这么说,继续看下面。
3)、设置Feature的mWindowLayers:
.upTo(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
.except(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
首先TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY代表的是一种窗口类型:
/**
* Window type: Window for adding accessibility window magnification above other windows.
* This will place the window in the overlay windows.
* @hide
*/
public static final int TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 39;
接着看下upTo方法:
/**
* Set that the feature applies window types that are layerd at or below the layer of
* the given window type.
*/
Builder upTo(int typeInclusive) {
final int max = layerFromType(typeInclusive, false);
for (int i = 0; i < max; i++) {
mLayers[i] = true;
}
set(typeInclusive, true);
return this;
}
继续看下layerFromType方法:
private int layerFromType(int type, boolean internalWindows) {
return mPolicy.getWindowLayerFromTypeLw(type, internalWindows);
}
调用的是WindowManagerPolicy.getWindowLayerFromTypeLw方法:
/**
* Returns the layer assignment for the window type. Allows you to control how different
* kinds of windows are ordered on-screen.
*
* @param type The type of window being assigned.
* @param canAddInternalSystemWindow If the owner window associated with the type we are
* evaluating can add internal system windows. I.e they have
* {@link Manifest.permission#INTERNAL_SYSTEM_WINDOW}. If true, alert window
* types {@link android.view.WindowManager.LayoutParams#isSystemAlertWindowType(int)}
* can be assigned layers greater than the layer for
* {@link android.view.WindowManager.LayoutParams#TYPE_APPLICATION_OVERLAY} Else, their
* layers would be lesser.
* @return int An arbitrary integer used to order windows, with lower numbers below higher ones.
*/
default int getWindowLayerFromTypeLw(int type, boolean canAddInternalSystemWindow) {
return getWindowLayerFromTypeLw(type, canAddInternalSystemWindow,
false /* roundedCornerOverlay */);
}
/**
* Returns the layer assignment for the window type. Allows you to control how different
* kinds of windows are ordered on-screen.
*
* @param type The type of window being assigned.
* @param canAddInternalSystemWindow If the owner window associated with the type we are
* evaluating can add internal system windows. I.e they have
* {@link Manifest.permission#INTERNAL_SYSTEM_WINDOW}. If true, alert window
* types {@link android.view.WindowManager.LayoutParams#isSystemAlertWindowType(int)}
* can be assigned layers greater than the layer for
* {@link android.view.WindowManager.LayoutParams#TYPE_APPLICATION_OVERLAY} Else, their
* layers would be lesser.
* @param roundedCornerOverlay {#code true} to indicate that the owner window is rounded corner
* overlay.
* @return int An arbitrary integer used to order windows, with lower numbers below higher ones.
*/
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:
case TYPE_VOICE_INTERACTION_STARTING:
return 4;
case TYPE_VOICE_INTERACTION:
// voice interaction layer is almost immediately above apps.
return 5;
case TYPE_INPUT_CONSUMER:
return 6;
case TYPE_SYSTEM_DIALOG:
return 7;
case TYPE_TOAST:
// toasts and the plugged-in battery thing
return 8;
case TYPE_PRIORITY_PHONE:
// SIM errors and unlock. Not sure if this really should be in a high layer.
return 9;
case TYPE_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 ? 13 : 10;
case TYPE_APPLICATION_OVERLAY:
return 12;
case TYPE_INPUT_METHOD:
// on-screen keyboards and other such input method user interfaces go here.
return 15;
case TYPE_INPUT_METHOD_DIALOG:
// on-screen keyboards and other such input method user interfaces go here.
return 16;
case TYPE_STATUS_BAR:
return 17;
case TYPE_STATUS_BAR_ADDITIONAL:
return 18;
case TYPE_NOTIFICATION_SHADE:
return 19;
case TYPE_STATUS_BAR_SUB_PANEL:
return 20;
case TYPE_KEYGUARD_DIALOG:
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 : 11;
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 : 10;
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;
}
}
这个方法返回给定窗口类型对应的层级值。允许你控制不同类型的窗口在屏幕上的排序方式。
看方法内容很简单,对每一种类型的窗口,都规定了一个层级值。层级值反映了这些窗口在Z轴上的排序方式,层级值越高在Z轴上的位置也就越高。但是层级值的大小和窗口类型对应的那个值的大小并没有关系,窗口类型值大的窗口,对应的层级值不一定大。
另外,大部分层级值都唯一对应一种窗口类型,比较特殊的是:
- 层级值2,所有App窗口会被归类到这一个层级。
- 层级值3,该方法中没有提到的窗口类型会被归类到这一个层级。
知道了这些内容再回头看upTo方法,就很容易理解了:
首先找到TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY这个窗口类型对应的层级值,也就是32,接着将mLayers数组从0到32的元素,全部赋值为true。
看下Feature.mBuilder的成员变量mLayers的定义:
static class Builder {
// ......
private final boolean[] mLayers;
// ......
/**
* Builds a new feature that applies to a set of window types as specified by the
* builder methods.
*
* <p>The set of types is updated iteratively in the order of the method invocations.
* For example, {@code all().except(TYPE_STATUS_BAR)} expresses that a feature should
* apply to all types except TYPE_STATUS_BAR.
*
* <p>The builder starts out with the feature not applying to any types.
*
* @param name the name of the feature.
* @param id of the feature. {@see Feature#getId}
*/
Builder(WindowManagerPolicy policy, String name, int id) {
mPolicy = policy;
mName = name;
mId = id;
mLayers = new boolean[mPolicy.getMaxWindowLayer() + 1];
}
// ......
}
WindowManagerPolicy.getMaxWindowLayer方法是:
// TODO(b/155340867): consider to remove the logic after using pure Surface for rounded corner
// overlay.
/**
* 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定义的最大层级值,36。
那么Feature.Builder.mLayers数组初始化为:
mLayers = new boolean[37];
Feature.mWindowLayers则是在Feature.Builder.build方法中完全由Feature.Builder.mLayers的值复制过来:
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);
}
将Feature.Builde.mLayer数组中的每个元素设置为true的意思是什么呢?打个比方,将Feature.Builde.mLayer[32]设置为true,后续调用Feature.Builder.build后,Feature.mWindowLayers[32]也会被设置true。而Feature.mWindowLayers[32]为true,则表示该Feature对应的DisplayArea,可以包含层级值为32,也就是窗口类型为TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY的窗口。
另外目前看到mExcludeRoundedCorner是始终为true的,也就是说,mLayers[36]始终为false。
看下都有哪些方法来设置Feature.Builde.mLayer:
/**
* Set that the feature applies to all window types.
*/
Builder all() {
Arrays.fill(mLayers, true);
return this;
}
/**
* Set that the feature applies to the given window types.
*/
Builder and(int... types) {
for (int i = 0; i < types.length; i++) {
int type = types[i];
set(type, true);
}
return this;
}
/**
* Set that the feature does not apply to the given window types.
*/
Builder except(int... types) {
for (int i = 0; i < types.length; i++) {
int type = types[i];
set(type, false);
}
return this;
}
/**
* Set that the feature applies window types that are layerd at or below the layer of
* the given window type.
*/
Builder upTo(int typeInclusive) {
final int max = layerFromType(typeInclusive, false);
for (int i = 0; i < max; i++) {
mLayers[i] = true;
}
set(typeInclusive, true);
return this;
}
- all,将mLayers数组中的所有元素都设置为true,表示当前DisplayArea可以包含所有类型的窗口。
- and,先将传入的窗口类型先转换为对应的层级值,然后将mLayers数组中与该层级值对应的元素设置为true,表示该DisplayArea可以包含传入的窗口类型对应的窗口。
- except,先将传入的窗口类型先转换为对应的层级值,然后将mLayers数组中与该层级值对应的元素设置为false,表示该DisplayArea不再包含传入的窗口类型对应的窗口。
- upTo,先将传入的窗口类型先转换为对应的层级值,然后将mLayers数组中与该层级值对应的的元素之前的所有元素(包含该元素)设置为true,表示当前DisplayArea可以包含比传入的窗口类型层级值低的所有窗口。
最后,总结一下这一节的内容。
rootHierarchy.addFeature(new Feature.Builder(wmService.mPolicy, "WindowedMagnification",
FEATURE_WINDOWED_MAGNIFICATION)
.upTo(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
.except(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
// Make the DA dimmable so that the magnify window also mirrors the dim layer.
.setNewDisplayAreaSupplier(DisplayArea.Dimmable::new)
.build());
以上代码,为HierarchyBuilder添加了一个Feature,Feature名字是"WindowedMagnification",ID为FEATURE_WINDOWED_MAGNIFICATION,符合这个Feature的DisplayArea可以包含层级值为0~31的窗口。
后续添加其他的Feature和这个WindowedMagnification类似,将指定的窗口类型转换为层级值,可以得到:
Feature.mName | Feature.mID | Feature.mWindowLayers |
---|---|---|
WindowedMagnification | FEATURE_WINDOWED_MAGNIFICATION | 0-31 |
HideDisplayCutout | FEATURE_HIDE_DISPLAY_CUTOUT | 0-16,18,20-23,26-35 |
OneHandedBackgroundPanel | FEATURE_ONE_HANDED_BACKGROUND_PANEL | 0-1 |
OneHanded | FEATURE_ONE_HANDED | 0-23,26-35 |
FullscreenMagnification | FEATURE_FULLSCREEN_MAGNIFICATION | 0-14,17-23,26-27,29-31,33-35 |
ImePlaceholder | FEATURE_IME_PLACEHOLDER | 15-16 |
2.2.5 生成DisplayArea层级结构
// 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);
先调用DisplayAreaPolicyBuilder.setRootHierarchy将上面创建的HierarchyBuilder对象保存在DisplayAreaPolicyBuilder的成员变量mRootHierarchyBuilder中。
/** Defines the root hierarchy for the whole logical display. */
DisplayAreaPolicyBuilder setRootHierarchy(HierarchyBuilder rootHierarchyBuilder) {
mRootHierarchyBuilder = rootHierarchyBuilder;
return this;
}
最后调用了DisplayAreaPolicyBuilder.build方法去生成了一个DisplayArea层级结构。
Result build(WindowManagerService wmService) {
validate();
// Attach DA group roots to screen hierarchy before adding windows to group hierarchies.
mRootHierarchyBuilder.build(mDisplayAreaGroupHierarchyBuilders);
List<RootDisplayArea> displayAreaGroupRoots = new ArrayList<>(
mDisplayAreaGroupHierarchyBuilders.size());
for (int i = 0; i < mDisplayAreaGroupHierarchyBuilders.size(); i++) {
HierarchyBuilder hierarchyBuilder = mDisplayAreaGroupHierarchyBuilders.get(i);
hierarchyBuilder.build();
displayAreaGroupRoots.add(hierarchyBuilder.mRoot);
}
// Use the default function if it is not specified otherwise.
if (mSelectRootForWindowFunc == null) {
mSelectRootForWindowFunc = new DefaultSelectRootForWindowFunction(
mRootHierarchyBuilder.mRoot, displayAreaGroupRoots);
}
return new Result(wmService, mRootHierarchyBuilder.mRoot, displayAreaGroupRoots,
mSelectRootForWindowFunc);
}
这里调用了HierarchyBuilder.build去生成DisplayArea层级结构,并且有一个传参mDisplayAreaGroupHierarchyBuilders。目前我看到对于mDisplayAreaGroupHierarchyBuilders来说,没有添加子元素的地方,因此传入的mDisplayAreaGroupHierarchyBuilders是一个空的列表,接着分析HierarchyBuilder.build。
2.3 DisplayAreaPolicyBuilder.HierarchyBuilder.build
/**
* Builds the {@link DisplayArea} hierarchy below root. And adds the roots of those
* {@link HierarchyBuilder} as children.
*/
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<>());
}
// This method constructs the layer hierarchy with the following properties:
// (1) Every feature maps to a set of DisplayAreas
// (2) After adding a window, for every feature the window's type belongs to,
// it is a descendant of one of the corresponding DisplayAreas of the feature.
// (3) Z-order is maintained, i.e. if z-range(area) denotes the set of layers of windows
// within a DisplayArea:
// for every pair of DisplayArea siblings (a,b), where a is below b, it holds that
// max(z-range(a)) <= min(z-range(b))
//
// The algorithm below iteratively creates such a hierarchy:
// - Initially, all windows are attached to the root.
// - For each feature we create a set of DisplayAreas, by looping over the layers
// - if the feature does apply to the current layer, we need to find a DisplayArea
// for it to satisfy (2)
// - we can re-use the previous layer's area if:
// the current feature also applies to the previous layer, (to satisfy (3))
// and the last feature that applied to the previous layer is the same as
// the last feature that applied to the current layer (to satisfy (2))
// - otherwise we create a new DisplayArea below the last feature that applied
// to the current layer
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).
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;
}
}
}
// 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;
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.
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.
leafArea.mExisting = mImeContainer;
leafArea.mSkipTokens = true;
}
}
leafArea.mMaxLayer = layer;
}
root.computeMaxLayer();
// We built a tree of PendingAreas above with all the necessary info to represent the
// hierarchy, now create and attach real DisplayAreas to the root.
root.instantiateChildren(mRoot, displayAreaForLayer, 0, featureAreas);
// Notify the root that we have finished attaching all the DisplayAreas. Cache all the
// feature related collections there for fast access.
mRoot.onHierarchyBuilt(mFeatures, displayAreaForLayer, featureAreas);
}
这个方法虽然很长,但是明显可以分成几部分来看。
2.3.1 PendingArea数组
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<>());
}
// This method constructs the layer hierarchy with the following properties:
// (1) Every feature maps to a set of DisplayAreas
// (2) After adding a window, for every feature the window's type belongs to,
// it is a descendant of one of the corresponding DisplayAreas of the feature.
// (3) Z-order is maintained, i.e. if z-range(area) denotes the set of layers of windows
// within a DisplayArea:
// for every pair of DisplayArea siblings (a,b), where a is below b, it holds that
// max(z-range(a)) <= min(z-range(b))
//
// The algorithm below iteratively creates such a hierarchy:
// - Initially, all windows are attached to the root.
// - For each feature we create a set of DisplayAreas, by looping over the layers
// - if the feature does apply to the current layer, we need to find a DisplayArea
// for it to satisfy (2)
// - we can re-use the previous layer's area if:
// the current feature also applies to the previous layer, (to satisfy (3))
// and the last feature that applied to the previous layer is the same as
// the last feature that applied to the current layer (to satisfy (2))
// - otherwise we create a new DisplayArea below the last feature that applied
// to the current layer
PendingArea[] areaForLayer = new PendingArea[maxWindowLayerCount];
final PendingArea root = new PendingArea(null, 0, null);
Arrays.fill(areaForLayer, root);
1)、maxWindowLayerCount根据我们之前的分析,为37,目前我们定义的窗口层级值为0~36。
2)、创建了一个大小为37的PendingArea数组:
PendingArea[] areaForLayer = new PendingArea[maxWindowLayerCount];
创建了一个PendingArea对象,填充到areaForLayer数组中:
final PendingArea root = new PendingArea(null, 0, null);
Arrays.fill(areaForLayer, root);
PendingArea对象定义在DisplayAreaPolicyBuilder中:
static class PendingArea {
final int mMinLayer;
final ArrayList<PendingArea> mChildren = new ArrayList<>();
final Feature mFeature;
final PendingArea mParent;
int mMaxLayer;
我们正在分析的这个方法,就是首先要生成一个PendingArea树,然后根据这个PendingArea树去生成一个DisplayArea树,一个PendingArea对应着一个DisplayArea:
-
PendingArea是一个树节点的话,那么PendingArea的mParent则代表当前节点的父节点,mChildren则表示的是当前节点的子节点。
-
mFeature对应的则是这个PendingArea的特征。
-
mMinLayer和mMaxLayer代表的是当前PendingArea可以容纳的窗口层级值的一个范围。
为了接下来的分析,根据PendingArea的成员变量,可以将PendingArea表述为以下形式:
mFeature.mName:mMinLayer:mMaxLayer
比如,“OneHandedBackgroundPanel:0:1”,表示名为OneHandedBackgroundPanel的PendingArea,可以容纳层级值从0到1的窗口。
root现在没有一个Feature,因此名字暂时认为是Root,此时为“Root:0:0”。
那么areaForLayer数组,初始情况为:
areaForLayer[37] | 初始 |
---|---|
areaForLayer[0] | Root:0:0 |
areaForLayer[1] | Root:0:0 |
areaForLayer[2] | Root:0:0 |
areaForLayer[3] | Root:0:0 |
areaForLayer[4] | Root:0:0 |
areaForLayer[5] | Root:0:0 |
areaForLayer[6] | Root:0:0 |
areaForLayer[7] | Root:0:0 |
areaForLayer[8] | Root:0:0 |
areaForLayer[9] | Root:0:0 |
areaForLayer[10] | Root:0:0 |
areaForLayer[11] | Root:0:0 |
areaForLayer[12] | Root:0:0 |
areaForLayer[13] | Root:0:0 |
areaForLayer[14] | Root:0:0 |
areaForLayer[15] | Root:0:0 |
areaForLayer[16] | Root:0:0 |
areaForLayer[17] | Root:0:0 |
areaForLayer[18] | Root:0:0 |
areaForLayer[19] | Root:0:0 |
areaForLayer[20] | Root:0:0 |
areaForLayer[21] | Root:0:0 |
areaForLayer[22] | Root:0:0 |
areaForLayer[23] | Root:0:0 |
areaForLayer[24] | Root:0:0 |
areaForLayer[25] | Root:0:0 |
areaForLayer[26] | Root:0:0 |
areaForLayer[27] | Root:0:0 |
areaForLayer[28] | Root:0:0 |
areaForLayer[29] | Root:0:0 |
areaForLayer[30] | Root:0:0 |
areaForLayer[31] | Root:0:0 |
areaForLayer[32] | Root:0:0 |
areaForLayer[33] | Root:0:0 |
areaForLayer[34] | Root:0:0 |
areaForLayer[35] | Root:0:0 |
areaForLayer[36] | Root:0:0 |
2.3.2 PendingArea数组的生成
// 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).
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;
}
}
}
针对每一种Feature,都会走一次流程,根据2.2.4可知,mFeatures中有6个Feature,并且Feature添加到HierarchyBuilder的顺序,其实已经代表了这几种Feature对应的DisplayArea的层级高低。
Feature.mName | Feature.mID | Feature.mWindowLayers |
---|---|---|
WindowedMagnification | FEATURE_WINDOWED_MAGNIFICATION | 0-31 |
HideDisplayCutout | FEATURE_HIDE_DISPLAY_CUTOUT | 0-16,18,20-23,26-35 |
OneHandedBackgroundPanel | FEATURE_ONE_HANDED_BACKGROUND_PANEL | 0-1 |
OneHanded | FEATURE_ONE_HANDED | 0-23,26-35 |
FullscreenMagnification | FEATURE_FULLSCREEN_MAGNIFICATION | 0-14,17-23,26-27,29-31,33-35 |
ImePlaceholder | FEATURE_IME_PLACEHOLDER | 15-16 |
2.3.2.1 WindowedMagnification
先看WindowedMagnification。
1)、layer为0,此时feature.mWindowLayers[0]为true,featureArea为null,那么创建一个PendingArea对象,“WindowedMagnification:0:0”,这个新创建的“WindowedMagnification:0:0“,parent为”Root:0:0“,并且将这个新创建的“WindowedMagnification:0:0“添加到”Root:0:0“的子节点中,最后将areaForLayer[0]指向这个新创建的“WindowedMagnification:0:0”。
2)、layer为1,此时feature.mWindowLayers[1]为true,featureArea为“WindowedMagnification:0:0”,featureArea.mParent为”Root:0:0“,areaForLayer[1]也是”Root:0:0“,那么不创建PendingArea对象,将areaForLayer[1]指向“WindowedMagnification:0:0”。
3)、后续直到layer为32之前,都是如此。当layer为32时,feature.mWindowLayers[32]为false,不会走到这些逻辑中。
那么经过第一轮循环,areaForLayer数组的情况是:
areaForLayer[37] | 初始 | WindowedMagnification |
---|---|---|
areaForLayer[0] | Root:0:0 | WindowedMagnification:0:0 |
areaForLayer[1] | Root:0:0 | WindowedMagnification:0:0 |
areaForLayer[2] | Root:0:0 | WindowedMagnification:0:0 |
areaForLayer[3] | Root:0:0 | WindowedMagnification:0:0 |
areaForLayer[4] | Root:0:0 | WindowedMagnification:0:0 |
areaForLayer[5] | Root:0:0 | WindowedMagnification:0:0 |
areaForLayer[6] | Root:0:0 | WindowedMagnification:0:0 |
areaForLayer[7] | Root:0:0 | WindowedMagnification:0:0 |
areaForLayer[8] | Root:0:0 | WindowedMagnification:0:0 |
areaForLayer[9] | Root:0:0 | WindowedMagnification:0:0 |
areaForLayer[10] | Root:0:0 | WindowedMagnification:0:0 |
areaForLayer[11] | Root:0:0 | WindowedMagnification:0:0 |
areaForLayer[12] | Root:0:0 | WindowedMagnification:0:0 |
areaForLayer[13] | Root:0:0 | WindowedMagnification:0:0 |
areaForLayer[14] | Root:0:0 | WindowedMagnification:0:0 |
areaForLayer[15] | Root:0:0 | WindowedMagnification:0:0 |
areaForLayer[16] | Root:0:0 | WindowedMagnification:0:0 |
areaForLayer[17] | Root:0:0 | WindowedMagnification:0:0 |
areaForLayer[18] | Root:0:0 | WindowedMagnification:0:0 |
areaForLayer[19] | Root:0:0 | WindowedMagnification:0:0 |
areaForLayer[20] | Root:0:0 | WindowedMagnification:0:0 |
areaForLayer[21] | Root:0:0 | WindowedMagnification:0:0 |
areaForLayer[22] | Root:0:0 | WindowedMagnification:0:0 |
areaForLayer[23] | Root:0:0 | WindowedMagnification:0:0 |
areaForLayer[24] | Root:0:0 | WindowedMagnification:0:0 |
areaForLayer[25] | Root:0:0 | WindowedMagnification:0:0 |
areaForLayer[26] | Root:0:0 | WindowedMagnification:0:0 |
areaForLayer[27] | Root:0:0 | WindowedMagnification:0:0 |
areaForLayer[28] | Root:0:0 | WindowedMagnification:0:0 |
areaForLayer[29] | Root:0:0 | WindowedMagnification:0:0 |
areaForLayer[30] | Root:0:0 | WindowedMagnification:0:0 |
areaForLayer[31] | Root:0:0 | WindowedMagnification:0:0 |
areaForLayer[32] | Root:0:0 | |
areaForLayer[33] | Root:0:0 | |
areaForLayer[34] | Root:0:0 | |
areaForLayer[35] | Root:0:0 | |
areaForLayer[36] | Root:0:0 |
转换为树状图:
2.3.2.2 HideDisplayCutout
1)、layer为0,此时feature.mWindowLayers[0]为true,featureArea为null,那么创建一个PendingArea对象,“HideDisplayCutout:0:0”,这个新创建的“HideDisplayCutout:0:0“,parent为areaForLayer[0],但是经过第一步,areaForLayer[0]此时已经从"Root:0:0"被替换为了”WindowedMagnification:0:0“。接着将这个新创建的“HideDisplayCutout:0:0“添加到”WindowedMagnification:0:0“的子节点中,最后将areaForLayer[0]指向这个新创建的“HideDisplayCutout:0:0”。
2)、layer为1,此时feature.mWindowLayers[1]为true,featureArea为“HideDisplayCutout:0:0”,featureArea.mParent为”WindowedMagnification:0:0“,areaForLayer[1]也是”WindowedMagnification:0:0“,那么不创建PendingArea对象,将areaForLayer[1]指向“HideDisplayCutout:0:0”。
3)、后续直到layer为16,都是如此。
4)、layer为17,此时feature.mWindowLayers[17]为false,将featureArea重置为null。
5)、layer为18,此时feature.mWindowLayers[18]为true,重新创建了一个PendingArea:”HideDisplayCutout:18:0“,接着将这个新创建的“HideDisplayCutout:18:0“添加到”WindowedMagnification:0:0“的子节点中,最后将areaForLayer[18]指向这个新创建的“HideDisplayCutout:18:0”。
6)、layer为19,此时feature.mWindowLayers[19]为false,将featureArea重置为null。
7)、laye为20,此时feature.mWindowLayers[20]为true,重新创建了一个PendingArea:”HideDisplayCutout:20:0“,接着将这个新创建的“HideDisplayCutout:20:0“添加到”WindowedMagnification:0:0“的子节点中,最后将areaForLayer[20]指向这个新创建的“HideDisplayCutout:20:0”。
8)、后续直到layer为23,都是复用的”HideDisplayCutout:20:0“。
9)、layer为24,此时feature.mWindowLayers[24]为false,将featureArea重置为null。
10)、layer为25,此时feature.mWindowLayers[25]为false,将featureArea重置为null。
11)、layer为26,此时feature.mWindowLayers[26]为true,重新创建了一个PendingArea:”HideDisplayCutout:26:0“,接着将这个新创建的“HideDisplayCutout:26:0“添加到”WindowedMagnification:0:0“的子节点中,最后将areaForLayer[26]指向这个新创建的“HideDisplayCutout:26:0”。
12)、直到layer为31,都是复用的”HideDisplayCutout:26:0“。
13)、layer为32,此时feature.mWindowLayers[32]为true,此时featureArea为“HideDisplayCutout:26:0“,parent为”WindowedMagnification:0:0“,但是此时areaForLayer[32]是”Root:0:0“,那么此时会重新创建一个PendingArea:“HideDisplayCutout:32:0“,接着将这个新创建的“HideDisplayCutout:32:0“添加到”Root:0:0“的子节点中,最后将areaForLayer[32]指向这个新创建的“HideDisplayCutout:32:0”。
14)、后续直到layer为36,都是复用的“HideDisplayCutout:32:”。
那么经过第二轮循环,areaForLayer数组的情况是:
areaForLayer[37] | 初始 | WindowedMagnification | HideDisplayCutout |
---|---|---|---|
areaForLayer[0] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 |
areaForLayer[1] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 |
areaForLayer[2] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 |
areaForLayer[3] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 |
areaForLayer[4] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 |
areaForLayer[5] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 |
areaForLayer[6] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 |
areaForLayer[7] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 |
areaForLayer[8] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 |
areaForLayer[9] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 |
areaForLayer[10] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 |
areaForLayer[11] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 |
areaForLayer[12] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 |
areaForLayer[13] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 |
areaForLayer[14] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 |
areaForLayer[15] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 |
areaForLayer[16] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 |
areaForLayer[17] | Root:0:0 | WindowedMagnification:0:0 | |
areaForLayer[18] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:18:0 |
areaForLayer[19] | Root:0:0 | WindowedMagnification:0:0 | |
areaForLayer[20] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:20:0 |
areaForLayer[21] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:20:0 |
areaForLayer[22] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:20:0 |
areaForLayer[23] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:20:0 |
areaForLayer[24] | Root:0:0 | WindowedMagnification:0:0 | |
areaForLayer[25] | Root:0:0 | WindowedMagnification:0:0 | |
areaForLayer[26] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:26:0 |
areaForLayer[27] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:26:0 |
areaForLayer[28] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:26:0 |
areaForLayer[29] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:26:0 |
areaForLayer[30] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:26:0 |
areaForLayer[31] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:26:0 |
areaForLayer[32] | Root:0:0 | HideDisplayCutout:32:0 | |
areaForLayer[33] | Root:0:0 | HideDisplayCutout:32:0 | |
areaForLayer[34] | Root:0:0 | HideDisplayCutout:32:0 | |
areaForLayer[35] | Root:0:0 | HideDisplayCutout:32:0 | |
areaForLayer[36] | Root:0:0 |
转换为树状图:
2.3.2.3 最终结果
后续的分析类似,不再赘述,最终的结果是:
areaForLayer[37] | 初始 | WindowedMagnification | HideDisplayCutout | OneHandedBackgroundPanel | OneHanded | FullscreenMagnification | ImePlaceholder |
---|---|---|---|---|---|---|---|
areaForLayer[0] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 | OneHandedBackgroundPanel:0:0 | OneHanded:0:0 | FullscreenMagnification:0:0 | |
areaForLayer[1] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 | OneHandedBackgroundPanel:0:0 | OneHanded:0:0 | FullscreenMagnification:0:0 | |
areaForLayer[2] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 | OneHanded:2:0 | FullscreenMagnification:2:0 | ||
areaForLayer[3] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 | OneHanded:2:0 | FullscreenMagnification:2:0 | ||
areaForLayer[4] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 | OneHanded:2:0 | FullscreenMagnification:2:0 | ||
areaForLayer[5] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 | OneHanded:2:0 | FullscreenMagnification:2:0 | ||
areaForLayer[6] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 | OneHanded:2:0 | FullscreenMagnification:2:0 | ||
areaForLayer[7] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 | OneHanded:2:0 | FullscreenMagnification:2:0 | ||
areaForLayer[8] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 | OneHanded:2:0 | FullscreenMagnification:2:0 | ||
areaForLayer[9] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 | OneHanded:2:0 | FullscreenMagnification:2:0 | ||
areaForLayer[10] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 | OneHanded:2:0 | FullscreenMagnification:2:0 | ||
areaForLayer[11] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 | OneHanded:2:0 | FullscreenMagnification:2:0 | ||
areaForLayer[12] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 | OneHanded:2:0 | FullscreenMagnification:2:0 | ||
areaForLayer[13] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 | OneHanded:2:0 | FullscreenMagnification:2:0 | ||
areaForLayer[14] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 | OneHanded:2:0 | FullscreenMagnification:2:0 | ||
areaForLayer[15] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 | OneHanded:2:0 | ImePlaceholder:15:0 | ||
areaForLayer[16] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 | OneHanded:2:0 | ImePlaceholder:15:0 | ||
areaForLayer[17] | Root:0:0 | WindowedMagnification:0:0 | OneHanded:17:0 | FullscreenMagnification:17:0 | |||
areaForLayer[18] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:18:0 | OneHanded:18:0 | FullscreenMagnification:18:0 | ||
areaForLayer[19] | Root:0:0 | WindowedMagnification:0:0 | OneHanded:19:0 | FullscreenMagnification:19:0 | |||
areaForLayer[20] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:20:0 | OneHanded:20:0 | FullscreenMagnification:20:0 | ||
areaForLayer[21] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:20:0 | OneHanded:20:0 | FullscreenMagnification:20:0 | ||
areaForLayer[22] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:20:0 | OneHanded:20:0 | FullscreenMagnification:20:0 | ||
areaForLayer[23] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:20:0 | OneHanded:20:0 | FullscreenMagnification:20:0 | ||
areaForLayer[24] | Root:0:0 | WindowedMagnification:0:0 | |||||
areaForLayer[25] | Root:0:0 | WindowedMagnification:0:0 | |||||
areaForLayer[26] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:26:0 | OneHanded:26:0 | FullscreenMagnification:26:0 | ||
areaForLayer[27] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:26:0 | OneHanded:26:0 | FullscreenMagnification:26:0 | ||
areaForLayer[28] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:26:0 | OneHanded:26:0 | |||
areaForLayer[29] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:26:0 | OneHanded:26:0 | FullscreenMagnification:29:0 | ||
areaForLayer[30] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:26:0 | OneHanded:26:0 | FullscreenMagnification:29:0 | ||
areaForLayer[31] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:26:0 | OneHanded:26:0 | FullscreenMagnification:29:0 | ||
areaForLayer[32] | Root:0:0 | HideDisplayCutout:32:0 | OneHanded:32:0 | ||||
areaForLayer[33] | Root:0:0 | HideDisplayCutout:32:0 | OneHanded:32:0 | FullscreenMagnification:33:0 | |||
areaForLayer[34] | Root:0:0 | HideDisplayCutout:32:0 | OneHanded:32:0 | FullscreenMagnification:33:0 | |||
areaForLayer[35] | Root:0:0 | HideDisplayCutout:32:0 | OneHanded:32:0 | FullscreenMagnification:33:0 | |||
areaForLayer[36] | Root:0:0 |
转换为树状图:
2.3.3 为PendingArea数组添加Leaf
// 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;
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.
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.
leafArea.mExisting = mImeContainer;
leafArea.mSkipTokens = true;
}
}
leafArea.mMaxLayer = layer;
}
这个方法比上面的那个简单,继续往PendingArea层级结构向下添加leafArea,最后设置了leafArea的mMaxLayer。
Leaf有3种:
private static final int LEAF_TYPE_TASK_CONTAINERS = 1;
private static final int LEAF_TYPE_IME_CONTAINERS = 2;
private static final int LEAF_TYPE_TOKENS = 0;
根据Leaf的父节点的层级值得到:
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;
}
}
总结为:
- 层级值为APPLICATION_LAYER,即2,Leaf的类型为LEAF_TYPE_TASK_CONTAINERS。
- 层级值为15,16,Leaf的类型为LEAF_TYPE_IME_CONTAINERS。
- 其他层级值对应的Leaf类型为LEAF_TYPE_TOKENS。
看一下这里针对LEAF_TYPE_TASK_CONTAINERS和LEAF_TYPE_IME_CONTAINERS做的特殊处理:
1)、LEAF_TYPE_TASK_CONTAINERS
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.
addTaskDisplayAreasToApplicationLayer(areaForLayer[layer]);
addDisplayAreaGroupsToApplicationLayer(areaForLayer[layer],
displayAreaGroupHierarchyBuilders);
leafArea.mSkipTokens = true;
}
根据之前的分析,我们知道displayAreaGroupHierarchyBuilders是一个空的列表,所以只看addTaskDisplayAreasToApplicationLayer方法。
/** Adds all {@link TaskDisplayArea} to the application layer. */
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);
}
}
根据2.2.3可知,此时的mTaskDisplayAreas中只有一个元素,即名为”DefaultTaskDisplayArea“的TaskDisplayArea对象,这里是为该对象创建了一个对应的PendingArea对象,并且将创建的PendingArea添加到areaForLayer[2]节点之下,然后将PendingArea.mExisting设置为true
/** If not {@code null}, use this instead of creating a {@link DisplayArea.Tokens}. */
@Nullable DisplayArea mExisting;
那么后续根据PendingArea生成DisplayArea.Tokens的时候,如果mExisting不为空,那么直接用mExisting,而不会再重新创建一个DisplayArea.Tokens对象。
另外这里:
leafArea.mSkipTokens = true;
将为当前节点创建的leafArea的mSkipTokens设置为true,那么后续在根据PendingArea数组生成DisplayArea层级结构的时候,就不会为这个PendingArea对象生成一个DisplayArea对象了。
一顿操作的最后结果相当于是,用TaskDisplayArea对象替换了为当前节点生成的Leaf。
2)、LEAF_TYPE_IME_CONTAINERS,和上面分析类似,不再为当前节点生成DisplayArea.Tokens,而是用之前保存在HierarchyBuilder.mImeContainer的ImeContainer。
那么为2.3.2生成的PendingArea数组添加Leaf后,PendingArea数组为:
areaForLayer[37] | 初始 | WindowedMagnification | HideDisplayCutout | OneHandedBackgroundPanel | OneHanded | FullscreenMagnification | ImePlaceholder | Leaf |
---|---|---|---|---|---|---|---|---|
areaForLayer[0] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 | OneHandedBackgroundPanel:0:0 | OneHanded:0:0 | FullscreenMagnification:0:0 | Leaf:0:1 | |
areaForLayer[1] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 | OneHandedBackgroundPanel:0:0 | OneHanded:0:0 | FullscreenMagnification:0:0 | Leaf:0:1 | |
areaForLayer[2] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 | OneHanded:2:0 | FullscreenMagnification:2:0 | DefaultTaskDisplayArea | ||
areaForLayer[3] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 | OneHanded:2:0 | FullscreenMagnification:2:0 | Leaf:3:14 | ||
areaForLayer[4] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 | OneHanded:2:0 | FullscreenMagnification:2:0 | Leaf:3:14 | ||
areaForLayer[5] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 | OneHanded:2:0 | FullscreenMagnification:2:0 | Leaf:3:14 | ||
areaForLayer[6] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 | OneHanded:2:0 | FullscreenMagnification:2:0 | Leaf:3:14 | ||
areaForLayer[7] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 | OneHanded:2:0 | FullscreenMagnification:2:0 | Leaf:3:14 | ||
areaForLayer[8] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 | OneHanded:2:0 | FullscreenMagnification:2:0 | Leaf:3:14 | ||
areaForLayer[9] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 | OneHanded:2:0 | FullscreenMagnification:2:0 | Leaf:3:14 | ||
areaForLayer[10] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 | OneHanded:2:0 | FullscreenMagnification:2:0 | Leaf:3:14 | ||
areaForLayer[11] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 | OneHanded:2:0 | FullscreenMagnification:2:0 | Leaf:3:14 | ||
areaForLayer[12] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 | OneHanded:2:0 | FullscreenMagnification:2:0 | Leaf:3:14 | ||
areaForLayer[13] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 | OneHanded:2:0 | FullscreenMagnification:2:0 | Leaf:3:14 | ||
areaForLayer[14] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 | OneHanded:2:0 | FullscreenMagnification:2:0 | Leaf:3:14 | ||
areaForLayer[15] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 | OneHanded:2:0 | ImePlaceholder:15:0 | ImeContainer | ||
areaForLayer[16] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:0:0 | OneHanded:2:0 | ImePlaceholder:15:0 | ImeContainer | ||
areaForLayer[17] | Root:0:0 | WindowedMagnification:0:0 | OneHanded:17:0 | FullscreenMagnification:17:0 | Leaf:17:17 | |||
areaForLayer[18] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:18:0 | OneHanded:18:0 | FullscreenMagnification:18:0 | Leaf:18:18 | ||
areaForLayer[19] | Root:0:0 | WindowedMagnification:0:0 | OneHanded:19:0 | FullscreenMagnification:19:0 | Leaf:19:19 | |||
areaForLayer[20] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:20:0 | OneHanded:20:0 | FullscreenMagnification:20:0 | Leaf:20:23 | ||
areaForLayer[21] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:20:0 | OneHanded:20:0 | FullscreenMagnification:20:0 | Leaf:20:23 | ||
areaForLayer[22] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:20:0 | OneHanded:20:0 | FullscreenMagnification:20:0 | Leaf:20:23 | ||
areaForLayer[23] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:20:0 | OneHanded:20:0 | FullscreenMagnification:20:0 | Leaf:20:23 | ||
areaForLayer[24] | Root:0:0 | WindowedMagnification:0:0 | Leaf:24:25 | |||||
areaForLayer[25] | Root:0:0 | WindowedMagnification:0:0 | Leaf:24:25 | |||||
areaForLayer[26] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:26:0 | OneHanded:26:0 | FullscreenMagnification:26:0 | Leaf:26:27 | ||
areaForLayer[27] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:26:0 | OneHanded:26:0 | FullscreenMagnification:26:0 | Leaf:26:27 | ||
areaForLayer[28] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:26:0 | OneHanded:26:0 | Leaf:28:28 | |||
areaForLayer[29] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:26:0 | OneHanded:26:0 | FullscreenMagnification:29:0 | Leaf:29:31 | ||
areaForLayer[30] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:26:0 | OneHanded:26:0 | FullscreenMagnification:29:0 | Leaf:29:31 | ||
areaForLayer[31] | Root:0:0 | WindowedMagnification:0:0 | HideDisplayCutout:26:0 | OneHanded:26:0 | FullscreenMagnification:29:0 | Leaf:29:31 | ||
areaForLayer[32] | Root:0:0 | HideDisplayCutout:32:0 | OneHanded:32:0 | Leaf:32:32 | ||||
areaForLayer[33] | Root:0:0 | HideDisplayCutout:32:0 | OneHanded:32:0 | FullscreenMagnification:33:0 | Leaf:33:35 | |||
areaForLayer[34] | Root:0:0 | HideDisplayCutout:32:0 | OneHanded:32:0 | FullscreenMagnification:33:0 | Leaf:33:35 | |||
areaForLayer[35] | Root:0:0 | HideDisplayCutout:32:0 | OneHanded:32:0 | FullscreenMagnification:33:0 | Leaf:33:35 | |||
areaForLayer[36] | Root:0:0 | Leaf:36:36 |
转换为树状图:
2.3.4 计算MaxLayer
2.2.3只设置了叶节点的mMaxLayer,这部分计算父节点的mMaxLayer。
root.computeMaxLayer();
调用PendingArea.computeMaxLayer方法去计算PendingArea.mMaxLayer的值:
int computeMaxLayer() {
for (int i = 0; i < mChildren.size(); i++) {
mMaxLayer = Math.max(mMaxLayer, mChildren.get(i).computeMaxLayer());
}
return mMaxLayer;
}
以当前节点为起点,向下查找最大的那个节点mMaxLayer作为当前节点的mMaxLayer。
最终的PendingArea数组为:
areaForLayer[37] | 初始 | WindowedMagnification | HideDisplayCutout | OneHandedBackgroundPanel | OneHanded | FullscreenMagnification | ImePlaceholder | Leaf |
---|---|---|---|---|---|---|---|---|
areaForLayer[0] | Root:0:0 | WindowedMagnification:0:31 | HideDisplayCutout:0:16 | OneHandedBackgroundPanel:0:1 | OneHanded:0:1 | FullscreenMagnification:0:1 | Leaf:0:1 | |
areaForLayer[1] | Root:0:0 | WindowedMagnification:0:31 | HideDisplayCutout:0:16 | OneHandedBackgroundPanel:0:1 | OneHanded:0:1 | FullscreenMagnification:0:1 | Leaf:0:1 | |
areaForLayer[2] | Root:0:0 | WindowedMagnification:0:31 | HideDisplayCutout:0:16 | OneHanded:2:16 | FullscreenMagnification:2:14 | DefaultTaskDisplayArea | ||
areaForLayer[3] | Root:0:0 | WindowedMagnification:0:31 | HideDisplayCutout:0:16 | OneHanded:2:16 | FullscreenMagnification:2:14 | Leaf:3:14 | ||
areaForLayer[4] | Root:0:0 | WindowedMagnification:0:31 | HideDisplayCutout:0:16 | OneHanded:2:16 | FullscreenMagnification:2:14 | Leaf:3:14 | ||
areaForLayer[5] | Root:0:0 | WindowedMagnification:0:31 | HideDisplayCutout:0:16 | OneHanded:2:16 | FullscreenMagnification:2:14 | Leaf:3:14 | ||
areaForLayer[6] | Root:0:0 | WindowedMagnification:0:31 | HideDisplayCutout:0:16 | OneHanded:2:16 | FullscreenMagnification:2:14 | Leaf:3:14 | ||
areaForLayer[7] | Root:0:0 | WindowedMagnification:0:31 | HideDisplayCutout:0:16 | OneHanded:2:16 | FullscreenMagnification:2:14 | Leaf:3:14 | ||
areaForLayer[8] | Root:0:0 | WindowedMagnification:0:31 | HideDisplayCutout:0:16 | OneHanded:2:16 | FullscreenMagnification:2:14 | Leaf:3:14 | ||
areaForLayer[9] | Root:0:0 | WindowedMagnification:0:31 | HideDisplayCutout:0:16 | OneHanded:2:16 | FullscreenMagnification:2:14 | Leaf:3:14 | ||
areaForLayer[10] | Root:0:0 | WindowedMagnification:0:31 | HideDisplayCutout:0:16 | OneHanded:2:16 | FullscreenMagnification:2:14 | Leaf:3:14 | ||
areaForLayer[11] | Root:0:0 | WindowedMagnification:0:31 | HideDisplayCutout:0:16 | OneHanded:2:16 | FullscreenMagnification:2:14 | Leaf:3:14 | ||
areaForLayer[12] | Root:0:0 | WindowedMagnification:0:31 | HideDisplayCutout:0:16 | OneHanded:2:16 | FullscreenMagnification:2:14 | Leaf:3:14 | ||
areaForLayer[13] | Root:0:0 | WindowedMagnification:0:31 | HideDisplayCutout:0:16 | OneHanded:2:16 | FullscreenMagnification:2:14 | Leaf:3:14 | ||
areaForLayer[14] | Root:0:0 | WindowedMagnification:0:31 | HideDisplayCutout:0:16 | OneHanded:2:16 | FullscreenMagnification:2:14 | Leaf:3:14 | ||
areaForLayer[15] | Root:0:0 | WindowedMagnification:0:31 | HideDisplayCutout:0:16 | OneHanded:2:16 | ImePlaceholder:15:16 | ImeContainer | ||
areaForLayer[16] | Root:0:0 | WindowedMagnification:0:31 | HideDisplayCutout:0:16 | OneHanded:2:16 | ImePlaceholder:15:16 | ImeContainer | ||
areaForLayer[17] | Root:0:0 | WindowedMagnification:0:31 | OneHanded:17:17 | FullscreenMagnification:17:17 | Leaf:17:17 | |||
areaForLayer[18] | Root:0:0 | WindowedMagnification:0:31 | HideDisplayCutout:18:18 | OneHanded:18:18 | FullscreenMagnification:18:18 | Leaf:18:18 | ||
areaForLayer[19] | Root:0:0 | WindowedMagnification:0:31 | OneHanded:19:19 | FullscreenMagnification:19:19 | Leaf:19:19 | |||
areaForLayer[20] | Root:0:0 | WindowedMagnification:0:31 | HideDisplayCutout:20:23 | OneHanded:20:23 | FullscreenMagnification:20:23 | Leaf:20:23 | ||
areaForLayer[21] | Root:0:0 | WindowedMagnification:0:31 | HideDisplayCutout:20:23 | OneHanded:20:23 | FullscreenMagnification:20:23 | Leaf:20:23 | ||
areaForLayer[22] | Root:0:0 | WindowedMagnification:0:31 | HideDisplayCutout:20:23 | OneHanded:20:23 | FullscreenMagnification:20:23 | Leaf:20:23 | ||
areaForLayer[23] | Root:0:0 | WindowedMagnification:0:31 | HideDisplayCutout:20:23 | OneHanded:20:23 | FullscreenMagnification:20:23 | Leaf:20:23 | ||
areaForLayer[24] | Root:0:0 | WindowedMagnification:0:31 | Leaf:24:25 | |||||
areaForLayer[25] | Root:0:0 | WindowedMagnification:0:31 | Leaf:24:25 | |||||
areaForLayer[26] | Root:0:0 | WindowedMagnification:0:31 | HideDisplayCutout:26:31 | OneHanded:26:31 | FullscreenMagnification:26:27 | Leaf:26:27 | ||
areaForLayer[27] | Root:0:0 | WindowedMagnification:0:31 | HideDisplayCutout:26:31 | OneHanded:26:31 | FullscreenMagnification:26:27 | Leaf:26:27 | ||
areaForLayer[28] | Root:0:0 | WindowedMagnification:0:31 | HideDisplayCutout:26:31 | OneHanded:26:31 | Leaf:28:28 | |||
areaForLayer[29] | Root:0:0 | WindowedMagnification:0:31 | HideDisplayCutout:26:31 | OneHanded:26:31 | FullscreenMagnification:29:31 | Leaf:29:31 | ||
areaForLayer[30] | Root:0:0 | WindowedMagnification:0:31 | HideDisplayCutout:26:31 | OneHanded:26:31 | FullscreenMagnification:29:31 | Leaf:29:31 | ||
areaForLayer[31] | Root:0:0 | WindowedMagnification:0:31 | HideDisplayCutout:26:31 | OneHanded:26:31 | FullscreenMagnification:29:31 | Leaf:29:31 | ||
areaForLayer[32] | Root:0:0 | HideDisplayCutout:32:35 | OneHanded:32:35 | Leaf:32:32 | ||||
areaForLayer[33] | Root:0:0 | HideDisplayCutout:32:35 | OneHanded:32:35 | FullscreenMagnification:33:35 | Leaf:33:35 | |||
areaForLayer[34] | Root:0:0 | HideDisplayCutout:32:35 | OneHanded:32:35 | FullscreenMagnification:33:35 | Leaf:33:35 | |||
areaForLayer[35] | Root:0:0 | HideDisplayCutout:32:35 | OneHanded:32:35 | FullscreenMagnification:33:35 | Leaf:33:35 | |||
areaForLayer[36] | Root:0:0 | Leaf:36:36 |
转换为树状图:
2.3.5 生成DisplayArea层级结构
// We built a tree of PendingAreas above with all the necessary info to represent the
// hierarchy, now create and attach real DisplayAreas to the root.
root.instantiateChildren(mRoot, displayAreaForLayer, 0, featureAreas);
调用DisplayAreaPolicyBuilder.PendingArea.instantiateChildren方法生成DisplayArea层级结构。
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);
}
}
当前root是上面的生成的PendingArea层级结构的根节点,传入的parent则是一个DisplayContent对象,那么这里按照root的mChildren的层级结构,以parent为根节点,生成一个DisplayArea层级结构。
重点看一下这里创建DisplayArea的DisplayAreaPolicyBuilder.PendingArea.createArea方法:
private DisplayArea createArea(DisplayArea<DisplayArea> parent,
DisplayArea.Tokens[] areaForLayer) {
if (mExisting != null) {
if (mExisting.asTokens() != null) {
// Store the WindowToken container for layers
fillAreaForLayers(mExisting.asTokens(), areaForLayer);
}
return mExisting;
}
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);
}
}
1)、当mExisting不为null,即2.3.3中分析的TaskDisplayArea和ImeContainer的情况,此时不需要再创建DisplayArea对象,直接用mExisting。
2)、mSkipTokens为true,直接return,mSkipTokens是和mExisting是同一个逻辑下设置的。
3)、这里根据mMinLayer和mMaxLayer的值,将DisplayArea分为三种:
- mMaxLayer小于APPLICATION_LAYER,即2,这类DisplayArea类型为ABOVE_TASKS。
- mMinLayer大于APPLICATION_LAYER,这类DisplayArea类型为BELOW_TASKS。
- 剩余情况下的DisplayArea类型为ANY。
4)、mFeature为null,那么创建一个DisplayArea.Tokens对象,这种情况对应2.3.3节分析的添加Leaf节点。
5)、如果mFeature不为null,那么创建一个DisplayArea对象。
那么最终生成的DisplayArea层级结构为:
DisplayContent
#2 Leaf:36:36
#1 HideDisplayCutout:32:35
#0 OneHanded:32:35
#1 FullscreenMagnification:33:35
#0 Leaf:33:35
# 0Leaf:32:32
#0 WindowedMagnification:0:31
#6 HideDisplayCutout:26:31
#0 OneHanded:26:31
#2 FullscreenMagnification:29:31
#0 Leaf:29:31
#1 Leaf:28:28
#0 FullscreenMagnification:26:27
#0 Leaf:26:27
#5 Leaf:24:25
#4 HideDisplayCutout:20:23
#0 OneHanded:20:23
#0 FullscreenMagnification:20:23
#0 Leaf:20:23
#3 OneHanded:19:19
#0 FullscreenMagnification:19:19
#0 Leaf:19:19
#2 HideDisplayCutout:18:18
#0 OneHanded:18:18
#0 FullscreenMagnification:18:18
#0 Leaf:18:18
#1 OneHanded:17:17
#0 FullscreenMagnification:17:17
#0 Leaf:17:17
#0 HideDisplayCutout:0:16
#1 OneHanded:2:16
#1 ImePlaceholder:15:16
#0 ImeContainer
#0 FullscreenMagnification:2:14
#1 Leaf:3:14
#0 DefaultTaskisplayArea
#0 OneHandedBackgroundPanel:0:1
#0 OneHanded:0:1
#0 FullscreenMagnification:0:1
#0 Leaf:0:1
对比adb shell dumpsys activity containers:
ROOT type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
#0 Display 0 name="Built-in Screen" type=undefined mode=fullscreen override-mode=fullscreen requested-bounds=[0,0][1440,2960] bounds=[0,0][1440,2960]
#2 Leaf:36:36 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
#1 HideDisplayCutout:32:35 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
#0 OneHanded:32:35 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
#1 FullscreenMagnification:33:35 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
#0 Leaf:33:35 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
#0 Leaf:32:32 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
#0 WindowedMagnification:0:31 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
#6 HideDisplayCutout:26:31 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
#0 OneHanded:26:31 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
#2 FullscreenMagnification:29:31 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
#0 Leaf:29:31 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
#1 Leaf:28:28 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
#0 FullscreenMagnification:26:27 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
#0 Leaf:26:27 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
#5 Leaf:24:25 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
#4 HideDisplayCutout:20:23 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
#0 OneHanded:20:23 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
#0 FullscreenMagnification:20:23 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
#0 Leaf:20:23 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
#3 OneHanded:19:19 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
#0 FullscreenMagnification:19:19 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
#0 Leaf:19:19 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
#2 HideDisplayCutout:18:18 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
#0 OneHanded:18:18 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
#0 FullscreenMagnification:18:18 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
#0 Leaf:18:18 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
#1 OneHanded:17:17 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
#0 FullscreenMagnification:17:17 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
#0 Leaf:17:17 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
#0 HideDisplayCutout:0:16 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
#1 OneHanded:2:16 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
#1 ImePlaceholder:15:16 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
#0 ImeContainer type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
#0 FullscreenMagnification:2:14 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
#1 Leaf:3:14 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
#0 DefaultTaskDisplayArea type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
#0 OneHandedBackgroundPanel:0:1 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
#0 OneHanded:0:1 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
#0 FullscreenMagnification:0:1 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
#0 Leaf:0:1 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
是一致的。
2.3.6 保存Leaf数组
// Notify the root that we have finished attaching all the DisplayAreas. Cache all the
// feature related collections there for fast access.
mRoot.onHierarchyBuilt(mFeatures, displayAreaForLayer, featureAreas);
回调RootDisplayArea.onHierarchyBuilt:
/** Callback after {@link DisplayArea} hierarchy has been built. */
void onHierarchyBuilt(ArrayList<Feature> features, DisplayArea.Tokens[] areaForLayer,
Map<Feature, List<DisplayArea<WindowContainer>>> featureToDisplayAreas) {
if (mHasBuiltHierarchy) {
throw new IllegalStateException("Root should only build the hierarchy once");
}
mHasBuiltHierarchy = true;
mFeatures = Collections.unmodifiableList(features);
mAreaForLayer = areaForLayer;
mFeatureToDisplayAreas = featureToDisplayAreas;
}
重点看一下第二个参数areaForLayer,是DisplayArea.Tokens[]类型的数组,看一下它的数据是如何得到的。
经过分析看到是在2.3.5,创建DisplayArea.Tokens的时候向areaForLayer里填充数据的:
if (mFeature == null) {
final DisplayArea.Tokens leaf = new DisplayArea.Tokens(parent.mWmService, type,
"Leaf:" + mMinLayer + ":" + mMaxLayer);
fillAreaForLayers(leaf, areaForLayer);
return leaf;
}
再看一下fillAreaForLayers方法:
private void fillAreaForLayers(DisplayArea.Tokens leaf, DisplayArea.Tokens[] areaForLayer) {
for (int i = mMinLayer; i <= mMaxLayer; i++) {
areaForLayer[i] = leaf;
}
}
也很简单,areaForLayer数组包含了每一个层级值对应的那个Leaf,即一个DisplayArea.Tokens对象。
3 向DisplayArea层级结构添加窗口
根据之前的分析,我们知道了:
-
每种窗口类型,都可以通过WindowManagerPolicy.getWindowLayerFromTypeLw方法,返回一个相应的层级值。
-
DisplayArea层级结构中的每一个DisplayArea,都包含着一个层级值范围,这个层级值范围表明了这个DisplayArea可以容纳哪些类型的窗口。
那么我们可以合理进行推断添加窗口的一般流程:
WMS启动的时候添加DisplayContent的时候,首先是以该DisplayContent为根节点,创建了一个完整的DisplayArea层级结构。后续每次添加窗口的时候,都根据该窗口的类型,在DisplayArea层级结构中为该窗口寻找一个合适的父节点,然后将这个窗口添加到该父节点之下。
另外根据上面的分析还可以知道,在DisplayArea层级结构中,可以直接容纳窗口的父节点,有三种类型:
-
容纳App窗口的TaskDisplayArea
-
容纳输入法窗口的ImeContainer
-
容纳其他非App类型窗口的DisplayArea.Tokens
这里我们分析一般流程,看下非App类型的窗口,如StatusBar、NavigationBar等窗口,是如何添加到DisplayArea中的。
注意,我们说的每一个窗口,指的是WindowState。但是DisplayArea.Tokens的定义是:
/**
* DisplayArea that contains WindowTokens, and orders them according to their type.
*/
public static class Tokens extends DisplayArea<WindowToken> {
DisplayArea.Tokens是WindowToken的容器,因此DisplayArea.Tokens无法直接添加WindowState。
WindowToken则是WindowState的容器,每次新WindowState创建的时候,都会为这个WindowState创建一个WindowToken对象,然后将这个新创建的WindowState放入其中。
因此我们实际分析的,是WindowToken如何添加到DisplayArea层级结构中的。
最后需要修正一下说法,因为WindowToken不再是一个DisplayArea,而是一个WindowContainer。我们之前分析的DisplayArea层级结构,其中每一个节点都是一个DisplayArea,但是现在随着WindowToken的加入,DisplayArea层级结构这个说法需要转化为更通用的结构,也就是WindowContainer层级结构。
3.1 WindowManagerService.addWindow
public int addWindow(Session session, IWindow client, LayoutParams attrs, int viewVisibility,
int displayId, int requestUserId, InsetsState requestedVisibility,
InputChannel outInputChannel, InsetsState outInsetsState,
InsetsSourceControl[] outActiveControls) {
// ......
synchronized (mGlobalLock) {
// ......
WindowToken token = displayContent.getWindowToken(
hasParent ? parentWindow.mAttrs.token : attrs.token);
// ......
if (token == null) {
// ......
if (hasParent) {
// ......
} else {
final IBinder binder = attrs.token != null ? attrs.token : client.asBinder();
token = new WindowToken.Builder(this, binder, type)
.setDisplayContent(displayContent)
.setOwnerCanManageAppTokens(session.mCanAddInternalSystemWindow)
.setRoundedCornerOverlay(isRoundedCornerOverlay)
.build();
}
}
// ......
}
// ......
}
调用WindowToken.Builder.build创建一个WindowToken对象。
3.2 WindowToken.Builder.build
WindowToken build() {
return new WindowToken(mService, mToken, mType, mPersistOnEmpty, mDisplayContent,
mOwnerCanManageAppTokens, mRoundedCornerOverlay, mFromClientToken, mOptions);
}
3.3 WindowToken.init
protected WindowToken(WindowManagerService service, IBinder _token, int type,
boolean persistOnEmpty, DisplayContent dc, boolean ownerCanManageAppTokens,
boolean roundedCornerOverlay, boolean fromClientToken, @Nullable Bundle options) {
super(service);
token = _token;
windowType = type;
mOptions = options;
mPersistOnEmpty = persistOnEmpty;
mOwnerCanManageAppTokens = ownerCanManageAppTokens;
mRoundedCornerOverlay = roundedCornerOverlay;
mFromClientToken = fromClientToken;
if (dc != null) {
dc.addWindowToken(token, this);
}
}
在WindowToken构造方法中,调用DisplayContent.addWindowToken将WindowToken添加到以DisplayContent为根节点的WindowContainer层级结构中。
3.4 DisplayContent.addWindowToken
void addWindowToken(IBinder binder, WindowToken token) {
final DisplayContent dc = mWmService.mRoot.getWindowTokenDisplay(token);
// ......
mTokenMap.put(binder, token);
if (token.asActivityRecord() == null) {
// Set displayContent for non-app token to prevent same token will add twice after
// onDisplayChanged.
// TODO: Check if it's fine that super.onDisplayChanged of WindowToken
// (WindowsContainer#onDisplayChanged) may skipped when token.mDisplayContent assigned.
token.mDisplayContent = this;
// Add non-app token to container hierarchy on the display. App tokens are added through
// the parent container managing them (e.g. Tasks).
final DisplayArea.Tokens da = findAreaForToken(token).asTokens();
da.addChild(token);
}
}
窗口可以分为App窗口和非App窗口。对于App窗口,则是由更细致的WindowToken的子类,ActivityRecord来存放。这里我们分析非App窗口的流程。
分两步走:
1)、调用DisplayContent.findAreaForToken为当前WindowToken寻找一个合适的父容器,DisplayArea.Tokens对象。
2)、将WindowToken添加到父容器中。
3.5 DisplayContent.findAreaForToken
/**
* Finds the {@link DisplayArea} for the {@link WindowToken} to attach to.
* <p>
* Note that the differences between this API and
* {@link RootDisplayArea#findAreaForTokenInLayer(WindowToken)} is that this API finds a
* {@link DisplayArea} in {@link DisplayContent} level, which may find a {@link DisplayArea}
* from multiple {@link RootDisplayArea RootDisplayAreas} under this {@link DisplayContent}'s
* hierarchy, while {@link RootDisplayArea#findAreaForTokenInLayer(WindowToken)} finds a
* {@link DisplayArea.Tokens} from a {@link DisplayArea.Tokens} list mapped to window layers.
* </p>
*
* @see DisplayContent#findAreaForTokenInLayer(WindowToken)
*/
DisplayArea findAreaForToken(WindowToken windowToken) {
return findAreaForWindowType(windowToken.getWindowType(), windowToken.mOptions,
windowToken.mOwnerCanManageAppTokens, windowToken.mRoundedCornerOverlay);
}
为传入的WindowToken找到一个DisplayArea对象来添加进去。
3.6 DisplayContent.findAreaForWindowType
DisplayArea findAreaForWindowType(int windowType, Bundle options,
boolean ownerCanManageAppToken, boolean roundedCornerOverlay) {
// TODO(b/159767464): figure out how to find an appropriate TDA.
if (windowType >= FIRST_APPLICATION_WINDOW && windowType <= LAST_APPLICATION_WINDOW) {
return getDefaultTaskDisplayArea();
}
// Return IME container here because it could be in one of sub RootDisplayAreas depending on
// the focused edit text. Also, the RootDisplayArea choosing strategy is implemented by
// the server side, but not mSelectRootForWindowFunc customized by OEM.
if (windowType == TYPE_INPUT_METHOD || windowType == TYPE_INPUT_METHOD_DIALOG) {
return getImeContainer();
}
return mDisplayAreaPolicy.findAreaForWindowType(windowType, options,
ownerCanManageAppToken, roundedCornerOverlay);
}
-
如果是App窗口,那么返回默认的TaskDisplayArea对象。
-
如果是输入法窗口,那么返回ImeContainer。
-
如果是其他类型,继续寻找。
和我们之前分析的逻辑一致。
3.7 DisplayAreaPolicyBuilder.Result.findAreaForWindowType
@Override
public DisplayArea.Tokens findAreaForWindowType(int type, Bundle options,
boolean ownerCanManageAppTokens, boolean roundedCornerOverlay) {
return mSelectRootForWindowFunc.apply(type, options).findAreaForWindowTypeInLayer(type,
ownerCanManageAppTokens, roundedCornerOverlay);
}
3.8 RootDisplayArea.findAreaForWindowTypeInLayer
/** @see #findAreaForTokenInLayer(WindowToken) */
@Nullable
DisplayArea.Tokens findAreaForWindowTypeInLayer(int windowType, boolean ownerCanManageAppTokens,
boolean roundedCornerOverlay) {
int windowLayerFromType = mWmService.mPolicy.getWindowLayerFromTypeLw(windowType,
ownerCanManageAppTokens, roundedCornerOverlay);
if (windowLayerFromType == APPLICATION_LAYER) {
throw new IllegalArgumentException(
"There shouldn't be WindowToken on APPLICATION_LAYER");
}
return mAreaForLayer[windowLayerFromType];
}
计算出该窗口的类型对应的层级值windowLayerFromType,然后从mAreaForLayer数组中,找到windowLayerFromType对应的那个DisplayArea.Tokens对象。
mAreaForLayer成员变量,定义为:
/** Mapping from window layer to {@link DisplayArea.Tokens} that holds windows on that layer. */
private DisplayArea.Tokens[] mAreaForLayer;
它里面的数据是在2.3.6节中填充,保存的是层级值到对应DisplayArea.Tokens对象的一个映射。
那么只要传入窗口类型,就可以通过WindowManagerPolicy.getWindowLayerFromTypeLw得到该窗口类型对应的层级值,然后根据该层级值从mAreaForLayer拿到容纳当前WindowToken的父容器,一个DisplayArea.Tokens对象。
3.9 DisplayArea.Tokens.addChild
void addChild(WindowToken token) {
addChild(token, mWindowComparator);
}
这里调用了WindowContainer.addChild:
/**
* Adds the input window container has a child of this container in order based on the input
* comparator.
* @param child The window container to add as a child of this window container.
* @param comparator Comparator to use in determining the position the child should be added to.
* If null, the child will be added to the top.
*/
@CallSuper
protected void addChild(E child, Comparator<E> comparator) {
if (!child.mReparenting && child.getParent() != null) {
throw new IllegalArgumentException("addChild: container=" + child.getName()
+ " is already a child of container=" + child.getParent().getName()
+ " can't add to container=" + getName());
}
int positionToAdd = -1;
if (comparator != null) {
final int count = mChildren.size();
for (int i = 0; i < count; i++) {
if (comparator.compare(child, mChildren.get(i)) < 0) {
positionToAdd = i;
break;
}
}
}
if (positionToAdd == -1) {
mChildren.add(child);
} else {
mChildren.add(positionToAdd, child);
}
// Set the parent after we've actually added a child in case a subclass depends on this.
child.setParent(this);
}
传入了一个Comparator:
private final Comparator<WindowToken> mWindowComparator =
Comparator.comparingInt(WindowToken::getWindowLayerFromType);
很明显,在将WindowToken添加到父容器的时候,将新添加的WindowToken的层级值和父容器中的其他WindowToken的层级值进行比较,保证新添加的WindowToken在父容器中能够按照层级值的大小插入到合适的位置。
4 总结
4.1 DisplayArea类型
4.1.1 根据类的继承关系分类
一种是从DisplayArea类的继承关系出发,有以下关系:
4.1.2 根据DisplayArea.Type类的定义分类
根据DisplayArea.Type类的定义:
enum Type {
/** Can only contain WindowTokens above the APPLICATION_LAYER. */
ABOVE_TASKS,
/** Can only contain WindowTokens below the APPLICATION_LAYER. */
BELOW_TASKS,
/** Can contain anything. */
ANY;
// ......
}
可以将DisplayArea分为三类,分类的依据当前DisplayArea和APPLICATION_LAYER的关系:
if (mMinLayer > APPLICATION_LAYER) {
type = DisplayArea.Type.ABOVE_TASKS;
} else if (mMaxLayer < APPLICATION_LAYER) {
type = DisplayArea.Type.BELOW_TASKS;
} else {
type = DisplayArea.Type.ANY;
}
这种分类,首先把窗口划分为了App窗口和非App窗口。
其次,对于非App窗口,再根据其层级与App窗口层级的高低关系,分为位于App窗口之上的非App窗口(即ABOVE_TASKS),和位于App窗口之下的非App窗口(即BELOW_TASKS)。
4.1.3 根据Feature分类
在上面分析DisplayArea层级结构的创建流程中,我们在DisplayAreaPolicy.DefaultProvider.configureTrustedHierarchyBuilder方法中看到了6种Feature的添加:
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)
.except(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
// Make the DA dimmable so that the magnify window also mirrors the dim layer.
.setNewDisplayAreaSupplier(DisplayArea.Dimmable::new)
.build());
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()
.except(TYPE_NAVIGATION_BAR, TYPE_NAVIGATION_BAR_PANEL, TYPE_STATUS_BAR,
TYPE_NOTIFICATION_SHADE)
.build())
.addFeature(new Feature.Builder(wmService.mPolicy,
"OneHandedBackgroundPanel",
FEATURE_ONE_HANDED_BACKGROUND_PANEL)
.upTo(TYPE_WALLPAPER)
.build())
.addFeature(new Feature.Builder(wmService.mPolicy, "OneHanded",
FEATURE_ONE_HANDED)
.all()
.except(TYPE_NAVIGATION_BAR, TYPE_NAVIGATION_BAR_PANEL)
.build());
}
rootHierarchy
.addFeature(new Feature.Builder(wmService.mPolicy, "FullscreenMagnification",
FEATURE_FULLSCREEN_MAGNIFICATION)
.all()
.except(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY, TYPE_INPUT_METHOD,
TYPE_INPUT_METHOD_DIALOG, TYPE_MAGNIFICATION_OVERLAY,
TYPE_NAVIGATION_BAR, TYPE_NAVIGATION_BAR_PANEL)
.build())
.addFeature(new Feature.Builder(wmService.mPolicy, "ImePlaceholder",
FEATURE_IME_PLACEHOLDER)
.and(TYPE_INPUT_METHOD, TYPE_INPUT_METHOD_DIALOG)
.build());
}
}
这些Feature都对应一个特定的的DisplayArea。
但是再看DisplayArea的层级结构图:
还有一些节点的对应Feature却没有看到,即根节点DisplayContent,叶节点TaskDisplayArea和叶节点Leaf对应的DisplayArea.Tokens。
但是每次创建DisplayArea的时候都会传入一个对应的FeatureId的,之前分析的时候可能没有注意:
1)、DisplayContent:
DisplayContent(Display display, RootWindowContainer root) {
super(root.mWindowManager, "DisplayContent", FEATURE_ROOT);
// ......
}
2)、TaskDisplayArea:
final TaskDisplayArea defaultTaskDisplayArea = new TaskDisplayArea(content, wmService,
"DefaultTaskDisplayArea", FEATURE_DEFAULT_TASK_CONTAINER);
3)、DisplayArea.Tokens:
Tokens(WindowManagerService wms, Type type, String name) {
super(wms, type, name, FEATURE_WINDOW_TOKENS);
}
这样,所有的FeatureID,都已经找到了使用的地方了:
/**
* The value in display area indicating that no value has been set.
*/
public static final int FEATURE_UNDEFINED = -1;
/**
* The Root display area on a display
*/
public static final int FEATURE_SYSTEM_FIRST = 0;
/**
* The Root display area on a display
*/
public static final int FEATURE_ROOT = FEATURE_SYSTEM_FIRST;
/**
* Display area hosting the default task container.
*/
public static final int FEATURE_DEFAULT_TASK_CONTAINER = FEATURE_SYSTEM_FIRST + 1;
/**
* Display area hosting non-activity window tokens.
*/
public static final int FEATURE_WINDOW_TOKENS = FEATURE_SYSTEM_FIRST + 2;
/**
* Display area for one handed feature
*/
public static final int FEATURE_ONE_HANDED = FEATURE_SYSTEM_FIRST + 3;
/**
* Display area that can be magnified in
* {@link Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW}. It contains all windows
* below {@link WindowManager.LayoutParams#TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY}.
*/
public static final int FEATURE_WINDOWED_MAGNIFICATION = FEATURE_SYSTEM_FIRST + 4;
/**
* Display area that can be magnified in
* {@link Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN}. This is different from
* {@link #FEATURE_WINDOWED_MAGNIFICATION} that the whole display will be magnified.
* @hide
*/
public static final int FEATURE_FULLSCREEN_MAGNIFICATION = FEATURE_SYSTEM_FIRST + 5;
/**
* Display area for hiding display cutout feature
* @hide
*/
public static final int FEATURE_HIDE_DISPLAY_CUTOUT = FEATURE_SYSTEM_FIRST + 6;
/**
* Display area that the IME container can be placed in. Should be enabled on every root
* hierarchy if IME container may be reparented to that hierarchy when the IME target changed.
* @hide
*/
public static final int FEATURE_IME_PLACEHOLDER = FEATURE_SYSTEM_FIRST + 7;
/**
* Display area for one handed background layer, which preventing when user
* turning the Dark theme on, they can not clearly identify the screen has entered
* one handed mode.
* @hide
*/
public static final int FEATURE_ONE_HANDED_BACKGROUND_PANEL = FEATURE_SYSTEM_FIRST + 8;
/**
* The last boundary of display area for system features
*/
public static final int FEATURE_SYSTEM_LAST = 10_000;
看一下这些Feature的含义都是什么:
-
FEATURE_ROOT,一个屏幕上的根DisplayArea,对应DisplayContent。
-
FEATURE_DEFAULT_TASK_CONTAINER,容纳默认Task容器的DisplayArea,对应TaskDisplayArea。
-
FEATURE_WINDOW_TOKENS,容纳非activity窗口的DisplayArea,对应DisplayArea.Tokens。
-
FEATURE_ONE_HANDED,用于单手模式的DisplayArea,对应名为“OneHanded”的DisplayArea。
-
FEATURE_WINDOWED_MAGNIFICATION,在ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW模式下可以对窗口的某些区域进行放大的DisplayArea,对应名为“WindowedMagnification”的DisplayArea。
-
FEATURE_FULLSCREEN_MAGNIFICATION,在ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN模式下可以对整个屏幕进行放大的DisplayArea,对应名为“FullscreenMagnification”的DisplayArea。
-
FEATURE_HIDE_DISPLAY_CUTOUT,隐藏DisplayCutout的DisplayArea,对应名为“HideDisplayCutout”的DisplayArea。
-
FEATURE_IME_PLACEHOLDER,存放输入法窗口的DisplayArea,对应名为“ImePlaceholder”的DisplayArea。
-
FEATURE_ONE_HANDED_BACKGROUND_PANEL,容纳单手背景图层的DisplayArea,避免用户开启暗黑模式后,无法分辨屏幕是否已经进入了单手模式,对应名为“OneHandedBackgroundPanel”的DisplayArea。
4.2 DisplayArea层级结构生成规则
这里想要讨论一下为什么DisplayArea层级结构呈现为这样的形式:
在2.3节中分析了生成DisplayArea树的流程,但是感觉不够直观,这里借鉴了:
https://blog.csdn.net/shensky711/article/details/121530510
的分析方式,用颜色对各个DisplayArea进行标记。
分析前我们需要知道几点前提:
- 属于同一层级值的窗口,统一由一个Leaf管理,这个Leaf可以是DisplayArea.Tokens,也可以是TaskDisplayArea或者ImeContainer,这里暂且认为一个Leaf代表的就是同一类型的窗口。
- 为DisplayArea定义的各种Feature,代表了这个DisplayArea属下的窗口所具有的特征。Leaf虽然本身拥有的Feature,如FEATURE_WINDOW_TOKENS,没有对应的一个具体的功能,但是Leaf又是被层级结构中的父节点所管理的,所以它也会拥有父节点DisplayArea对应的Feature代表的特征。比如一个Leaf的父节点是WindowedMagnification,那么这个Leaf管理的所有窗口都具有窗口放大功能。
- 另外虽然一个DisplayArea只有一个Feature,但是由于DisplayArea的互相嵌套,那么一个Leaf可能会处于多级DisplayArea之下,所以一个Leaf可能具备多个Feature,比如Leaf:33:35,它的父节点从下往上依次是FullscreenMagnification,OneHanded,HideDisplayCutout,那么这个Leaf下的所有窗口,都具备这些Feature带来的特征。
以此为基础,来分析一下DisplayArea层级结构的生成过程。
1)、由于定义的层级值是0~36,所以最初我们可能为每一个层级值都创建了一个Leaf对象。如果想要某一个Leaf拥有某一个Feature代表的特征,那么就为这个Leaf添加对应的父节点,那么最初的设计可能是这样的:
因为有37个Leaf,所以总共有37列。这里的每一个有颜色的格子都代表一个DisplayArea对象。空白格子说明该列的Leaf管理的窗口不希望有该Feature代表的功能,因此没有针对该Feature创建一个DisplayArea对象。
所以这里有37棵独立的DisplayArea树,每一个树的根节点都是一个DisplayContent对象,叶节点都是一个Leaf,然后中间节点则是有多有少,这取决于这棵树的leaf希望拥有哪些Feature。
2)、对于每一棵DisplayArea树,都是父节点连接子节点,中间不能有空白节点。但是上面的表格,我们能看到是有格子是空白的。我们这里是希望表格同样能够反映DisplayArea层级结构,所以我们需要去掉空白格子。
举个例子,看一下36列,该列下的Leaf不需要任何额外Feature,因此不需要再为该Leaf创建任何父DisplayArea,直接将该Leaf添加到DisplayContent的子节点数组中,在表格中就是将该Leaf对应的格子上移,直接移动到DisplayContent所代表的格子之下。
这也就意味着每一个有颜色的格子如果上方有空白格子,那么就将其上移,最终得到:
3)、现在每一棵树都是父节点连接子节点,且中间没有空白节点了,但是此时并不够成一个层级结构,而仍然是37棵独立的树,需要进一步优化。首先我们看到,每一个屏幕只对应一个DisplayContent对象,那么这37棵树,它们的根节点其实都是同一个DisplayContent。此外,对于表格中左右相邻的DisplayArea,如果它们的父DisplayArea是同类型的(拥有的Feature相同),那么这种情况下,就可以复用父DisplayArea,即没有必要创建多个DisplayArea,而是只创建一个父DisplayArea,然后将这些左右相邻的DisplayArea全部添加到该父DisplayArea的子节点数组之中,也能达到同样的效果,即这些DisplayArea都具有了父DisplayArea的Feature。此时,这些表格中左右相邻的DisplayArea,由同一个父节点管理,因此表格上看它们左右相邻,在实际的层级结构中,它们也是处于同一层级。
那么表格中如果一个相邻格子的颜色相同,就把这两个格子合并,即DisplayArea的复用。最终得到:
再对比之前的树状图:
也是符合的。
4.3 向DisplayArea层级结构添加窗口
根据DisplyArea树状图可知,对于0~36的每一个层级值,在DisplayArea层级结构中都有相应的Leaf对应。因此每次添加新窗口的时候,只需要将该窗口的窗口类型换算为相应的层级值,然后将该新窗口添加到该层级值对应的Leaf下即可。
层级值反映了一个Leaf在DisplayArea层级结构中的层级高低,层级值越大,该Leaf在DisplayArea层级结构中的层级也越高。而Leaf是窗口的容器,Leaf层级值越大,其管理的窗口在Z轴的顺序也就越高。这也说明了窗口类型值越大的窗口,其在Z轴上的顺序不一定越高,因为窗口类型值和层级值并不是一个正相关的关系。