窗口层级树的构建
参考:
- android 13 WMS/AMS系统开发-窗口层级相关DisplayArea,WindowContainer第二节
在上一节dumpsys activity containers中,层级树中有如下的标识符:
WindowedMagnification
HideDisplayCutout
OneHanded
HideDisplayCutout
ImePlaceholder
这些标识符在哪里呢?
DisplayContent
路径为frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java
在DisplayContent
的构造方法中,会调用configureSurfaces
方法,其调用过程大概如下
会进入DisplayAreaPolicy
(路径为frameworks/base/services/core/java/com/android/server/wm/DisplayAreaPolicy.java
)的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, "OneHanded",
FEATURE_ONE_HANDED)
.all()
.except(TYPE_NAVIGATION_BAR, TYPE_NAVIGATION_BAR_PANEL,
TYPE_SECURE_SYSTEM_OVERLAY)
.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的层级情况:
Feature名字 | 层级情况 |
---|---|
WindowedMagnification | 0-31 |
HideDisplayCutout | 0-14 16 18-23 26-35 |
OneHanded | 0-23 26-32 34-35 |
FullscreenMagnification | 0-12 15-23 26-27 29-31 33-35 |
ImePlaceholder | 13-14 |
构建层级树
Feature的层级清楚后,就可以构建层级树
调用DisplayAreaPolicyBuilder
的build
方法,然后会调用其内部类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; //37
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++) { //mFeatures有5个
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];//37个PendingArea
final PendingArea root = new PendingArea(null, 0, null);//root
Arrays.fill(areaForLayer, root);//填充
// Create DisplayAreas to cover all defined features.
final int size = mFeatures.size();//5
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);//获取Feature
PendingArea featureArea = null;
for (int layer = 0; layer < maxWindowLayerCount; layer++) {//37次
if (feature.mWindowLayers[layer]) {//判断true还是false
//比如WindowedMagnification,0-31都是true
// 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;
}
}
}
创建Token作为Leaf节点
之后,基于上面的树,创建Token节点
// 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;
}
但是要除去TaskDisplayArea
和ImeContainer
的两个部分
具体可参考上面的参考文档