blob: 2c2f43392eca7922a981ee4655d5f2e89b120199 [file] [log] [blame]
Adrian Roos81163582020-01-08 23:21:16 +01001/*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.wm;
18
19import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
20import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
21import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
22import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
23import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
24import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
25import static android.view.WindowManagerPolicyConstants.APPLICATION_LAYER;
26
27import com.android.internal.annotations.VisibleForTesting;
28import com.android.server.policy.WindowManagerPolicy;
29
30import java.util.ArrayList;
31import java.util.Arrays;
32import java.util.Comparator;
33import java.util.HashMap;
34import java.util.List;
35import java.util.Map;
36
37/**
38 * A builder for instantiating a complex {@link DisplayAreaPolicy}
39 *
40 * <p>Given a set of features (that each target a set of window types), it builds the necessary
41 * DisplayArea hierarchy.
42 *
43 * <p>Example: <br />
44 *
45 * <pre>
46 * // Feature for targeting everything below the magnification overlay:
47 * new DisplayAreaPolicyBuilder(...)
48 * .addFeature(new Feature.Builder(..., "Magnification")
49 * .upTo(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
50 * .build())
51 * .build(...)
52 *
53 * // Builds a policy with the following hierarchy:
54 * - DisplayArea.Root
55 * - Magnification
56 * - DisplayArea.Tokens (Wallpapers are attached here)
Andrii Kulian4c0fd0d2020-03-29 13:32:14 -070057 * - TaskDisplayArea
Adrian Roos81163582020-01-08 23:21:16 +010058 * - DisplayArea.Tokens (windows above Tasks up to IME are attached here)
59 * - ImeContainers
60 * - DisplayArea.Tokens (windows above IME up to TYPE_ACCESSIBILITY_OVERLAY attached here)
61 * - DisplayArea.Tokens (TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY and up are attached here)
62 *
63 * </pre>
64 *
65 * // TODO(display-area): document more complex scenarios where we need multiple areas per feature.
66 */
67class DisplayAreaPolicyBuilder {
68
69 private final ArrayList<Feature> mFeatures = new ArrayList<>();
70
71 /**
72 * A feature that requires {@link DisplayArea DisplayArea(s)}.
73 */
74 static class Feature {
75 private final String mName;
Wale Ogunwaledec34082020-03-22 09:45:00 -070076 private final int mId;
Adrian Roos81163582020-01-08 23:21:16 +010077 private final boolean[] mWindowLayers;
78
Wale Ogunwaledec34082020-03-22 09:45:00 -070079 private Feature(String name, int id, boolean[] windowLayers) {
Adrian Roos81163582020-01-08 23:21:16 +010080 mName = name;
Wale Ogunwaledec34082020-03-22 09:45:00 -070081 mId = id;
Adrian Roos81163582020-01-08 23:21:16 +010082 mWindowLayers = windowLayers;
83 }
84
Wale Ogunwaledec34082020-03-22 09:45:00 -070085 /**
86 * Returns the id of the feature.
87 *
88 * Must be unique among the features added to a {@link DisplayAreaPolicyBuilder}.
89 *
Wale Ogunwaleadf116e2020-03-27 16:36:01 -070090 * @see android.window.DisplayAreaOrganizer#FEATURE_SYSTEM_FIRST
91 * @see android.window.DisplayAreaOrganizer#FEATURE_VENDOR_FIRST
Wale Ogunwaledec34082020-03-22 09:45:00 -070092 */
93 public int getId() {
94 return mId;
95 }
96
97 @Override
98 public String toString() {
99 return "Feature(\"" + mName + "\", " + mId + '}';
100 }
101
Adrian Roos81163582020-01-08 23:21:16 +0100102 static class Builder {
103 private final WindowManagerPolicy mPolicy;
104 private final String mName;
Wale Ogunwaledec34082020-03-22 09:45:00 -0700105 private final int mId;
Adrian Roos81163582020-01-08 23:21:16 +0100106 private final boolean[] mLayers;
107
108 /**
109 * Build a new feature that applies to a set of window types as specified by the builder
110 * methods.
111 *
112 * <p>The set of types is updated iteratively in the order of the method invocations.
113 * For example, {@code all().except(TYPE_STATUS_BAR)} expresses that a feature should
114 * apply to all types except TYPE_STATUS_BAR.
115 *
116 * The builder starts out with the feature not applying to any types.
117 *
118 * @param name the name of the feature.
Wale Ogunwaledec34082020-03-22 09:45:00 -0700119 * @param id of the feature. {@see Feature#getId}
Adrian Roos81163582020-01-08 23:21:16 +0100120 */
Wale Ogunwaledec34082020-03-22 09:45:00 -0700121 Builder(WindowManagerPolicy policy, String name, int id) {
Adrian Roos81163582020-01-08 23:21:16 +0100122 mPolicy = policy;
123 mName = name;
Wale Ogunwaledec34082020-03-22 09:45:00 -0700124 mId = id;
Adrian Roos81163582020-01-08 23:21:16 +0100125 mLayers = new boolean[mPolicy.getMaxWindowLayer()];
126 }
127
128 /**
129 * Set that the feature applies to all window types.
130 */
131 Builder all() {
132 Arrays.fill(mLayers, true);
133 return this;
134 }
135
136 /**
137 * Set that the feature applies to the given window types.
138 */
139 Builder and(int... types) {
140 for (int i = 0; i < types.length; i++) {
141 int type = types[i];
142 set(type, true);
143 }
144 return this;
145 }
146
147 /**
148 * Set that the feature does not apply to the given window types.
149 */
150 Builder except(int... types) {
151 for (int i = 0; i < types.length; i++) {
152 int type = types[i];
153 set(type, false);
154 }
155 return this;
156 }
157
158 /**
159 * Set that the feature applies window types that are layerd at or below the layer of
160 * the given window type.
161 */
162 Builder upTo(int typeInclusive) {
163 final int max = layerFromType(typeInclusive, false);
164 for (int i = 0; i < max; i++) {
165 mLayers[i] = true;
166 }
167 set(typeInclusive, true);
168 return this;
169 }
170
171 Feature build() {
Wale Ogunwaledec34082020-03-22 09:45:00 -0700172 return new Feature(mName, mId, mLayers.clone());
Adrian Roos81163582020-01-08 23:21:16 +0100173 }
174
175 private void set(int type, boolean value) {
176 mLayers[layerFromType(type, true)] = value;
177 if (type == TYPE_APPLICATION_OVERLAY) {
178 mLayers[layerFromType(type, true)] = value;
179 mLayers[layerFromType(TYPE_SYSTEM_ALERT, false)] = value;
180 mLayers[layerFromType(TYPE_SYSTEM_OVERLAY, false)] = value;
181 mLayers[layerFromType(TYPE_SYSTEM_ERROR, false)] = value;
182 }
183 }
184
185 private int layerFromType(int type, boolean internalWindows) {
186 return mPolicy.getWindowLayerFromTypeLw(type, internalWindows);
187 }
188 }
189 }
190
191 static class Result extends DisplayAreaPolicy {
192 private static final int LEAF_TYPE_TASK_CONTAINERS = 1;
193 private static final int LEAF_TYPE_IME_CONTAINERS = 2;
194 private static final int LEAF_TYPE_TOKENS = 0;
195
196 private final int mMaxWindowLayer = mWmService.mPolicy.getMaxWindowLayer();
197
198 private final ArrayList<Feature> mFeatures;
199 private final Map<Feature, List<DisplayArea<? extends WindowContainer>>> mAreas;
200 private final DisplayArea.Tokens[] mAreaForLayer = new DisplayArea.Tokens[mMaxWindowLayer];
201
202 Result(WindowManagerService wmService, DisplayContent content, DisplayArea.Root root,
203 DisplayArea<? extends WindowContainer> imeContainer,
Andrii Kulian44b3c562020-04-01 12:49:56 -0700204 List<TaskDisplayArea> taskDisplayAreas, ArrayList<Feature> features) {
205 super(wmService, content, root, imeContainer, taskDisplayAreas);
Adrian Roos81163582020-01-08 23:21:16 +0100206 mFeatures = features;
207 mAreas = new HashMap<>(features.size());
208 for (int i = 0; i < mFeatures.size(); i++) {
209 mAreas.put(mFeatures.get(i), new ArrayList<>());
210 }
211 }
212
213 @Override
214 public void attachDisplayAreas() {
215 // This method constructs the layer hierarchy with the following properties:
216 // (1) Every feature maps to a set of DisplayAreas
217 // (2) After adding a window, for every feature the window's type belongs to,
218 // it is a descendant of one of the corresponding DisplayAreas of the feature.
219 // (3) Z-order is maintained, i.e. if z-range(area) denotes the set of layers of windows
220 // within a DisplayArea:
221 // for every pair of DisplayArea siblings (a,b), where a is below b, it holds that
222 // max(z-range(a)) <= min(z-range(b))
223 //
224 // The algorithm below iteratively creates such a hierarchy:
225 // - Initially, all windows are attached to the root.
226 // - For each feature we create a set of DisplayAreas, by looping over the layers
227 // - if the feature does apply to the current layer, we need to find a DisplayArea
228 // for it to satisfy (2)
229 // - we can re-use the previous layer's area if:
230 // the current feature also applies to the previous layer, (to satisfy (3))
231 // and the last feature that applied to the previous layer is the same as
232 // the last feature that applied to the current layer (to satisfy (2))
233 // - otherwise we create a new DisplayArea below the last feature that applied
234 // to the current layer
235
236
237 PendingArea[] areaForLayer = new PendingArea[mMaxWindowLayer];
238 final PendingArea root = new PendingArea(null, 0, null);
239 Arrays.fill(areaForLayer, root);
240
241 final int size = mFeatures.size();
242 for (int i = 0; i < size; i++) {
243 PendingArea featureArea = null;
244 for (int layer = 0; layer < mMaxWindowLayer; layer++) {
245 final Feature feature = mFeatures.get(i);
246 if (feature.mWindowLayers[layer]) {
247 if (featureArea == null || featureArea.mParent != areaForLayer[layer]) {
248 // No suitable DisplayArea - create a new one under the previous area
249 // for this layer.
250 featureArea = new PendingArea(feature, layer, areaForLayer[layer]);
251 areaForLayer[layer].mChildren.add(featureArea);
252 }
253 areaForLayer[layer] = featureArea;
254 } else {
255 featureArea = null;
256 }
257 }
258 }
259
260 PendingArea leafArea = null;
261 int leafType = LEAF_TYPE_TOKENS;
262 for (int layer = 0; layer < mMaxWindowLayer; layer++) {
263 int type = typeOfLayer(mWmService.mPolicy, layer);
264 if (leafArea == null || leafArea.mParent != areaForLayer[layer]
265 || type != leafType) {
266 leafArea = new PendingArea(null, layer, areaForLayer[layer]);
267 areaForLayer[layer].mChildren.add(leafArea);
268 leafType = type;
269 if (leafType == LEAF_TYPE_TASK_CONTAINERS) {
Andrii Kulian44b3c562020-04-01 12:49:56 -0700270 addTaskDisplayAreasToLayer(areaForLayer[layer], layer);
Adrian Roos81163582020-01-08 23:21:16 +0100271 } else if (leafType == LEAF_TYPE_IME_CONTAINERS) {
272 leafArea.mExisting = mImeContainer;
273 }
274 }
275 leafArea.mMaxLayer = layer;
276 }
277 root.computeMaxLayer();
278 root.instantiateChildren(mRoot, mAreaForLayer, 0, mAreas);
279 }
280
Andrii Kulian44b3c562020-04-01 12:49:56 -0700281 /** Adds all task display areas to the specified layer */
282 private void addTaskDisplayAreasToLayer(PendingArea parentPendingArea, int layer) {
283 final int count = mTaskDisplayAreas.size();
284 for (int i = 0; i < count; i++) {
285 PendingArea leafArea = new PendingArea(null, layer, parentPendingArea);
286 leafArea.mExisting = mTaskDisplayAreas.get(i);
287 leafArea.mMaxLayer = layer;
288 parentPendingArea.mChildren.add(leafArea);
289 }
290 }
291
Adrian Roos81163582020-01-08 23:21:16 +0100292 @Override
293 public void addWindow(WindowToken token) {
294 DisplayArea.Tokens area = findAreaForToken(token);
295 area.addChild(token);
296 }
297
298 @VisibleForTesting
299 DisplayArea.Tokens findAreaForToken(WindowToken token) {
300 int windowLayerFromType = token.getWindowLayerFromType();
301 if (windowLayerFromType == APPLICATION_LAYER) {
302 // TODO(display-area): Better handle AboveAppWindows in APPLICATION_LAYER
303 windowLayerFromType += 1;
304 } else if (token.mRoundedCornerOverlay) {
305 windowLayerFromType = mMaxWindowLayer - 1;
306 }
307 return mAreaForLayer[windowLayerFromType];
308 }
309
310 public List<DisplayArea<? extends WindowContainer>> getDisplayAreas(Feature feature) {
311 return mAreas.get(feature);
312 }
313
314 private static int typeOfLayer(WindowManagerPolicy policy, int layer) {
315 if (layer == APPLICATION_LAYER) {
316 return LEAF_TYPE_TASK_CONTAINERS;
317 } else if (layer == policy.getWindowLayerFromTypeLw(TYPE_INPUT_METHOD)
318 || layer == policy.getWindowLayerFromTypeLw(TYPE_INPUT_METHOD_DIALOG)) {
319 return LEAF_TYPE_IME_CONTAINERS;
320 } else {
321 return LEAF_TYPE_TOKENS;
322 }
323 }
324 }
325
326 DisplayAreaPolicyBuilder addFeature(Feature feature) {
327 mFeatures.add(feature);
328 return this;
329 }
330
Andrii Kulian44b3c562020-04-01 12:49:56 -0700331 protected List<Feature> getFeatures() {
332 return mFeatures;
333 }
334
Adrian Roos81163582020-01-08 23:21:16 +0100335 Result build(WindowManagerService wmService,
336 DisplayContent content, DisplayArea.Root root,
337 DisplayArea<? extends WindowContainer> imeContainer,
Andrii Kulian44b3c562020-04-01 12:49:56 -0700338 List<TaskDisplayArea> taskDisplayAreas) {
Adrian Roos81163582020-01-08 23:21:16 +0100339
Andrii Kulian44b3c562020-04-01 12:49:56 -0700340 return new Result(wmService, content, root, imeContainer, taskDisplayAreas, new ArrayList<>(
Adrian Roos81163582020-01-08 23:21:16 +0100341 mFeatures));
342 }
343
344 static class PendingArea {
345 final int mMinLayer;
346 final ArrayList<PendingArea> mChildren = new ArrayList<>();
347 final Feature mFeature;
348 final PendingArea mParent;
349 int mMaxLayer;
350 DisplayArea mExisting;
351
352 PendingArea(Feature feature,
353 int minLayer,
354 PendingArea parent) {
355 mMinLayer = minLayer;
356 mFeature = feature;
357 mParent = parent;
358 }
359
360 int computeMaxLayer() {
361 for (int i = 0; i < mChildren.size(); i++) {
362 mMaxLayer = Math.max(mMaxLayer, mChildren.get(i).computeMaxLayer());
363 }
364 return mMaxLayer;
365 }
366
367 void instantiateChildren(DisplayArea<DisplayArea> parent,
368 DisplayArea.Tokens[] areaForLayer, int level, Map<Feature, List<DisplayArea<?
369 extends WindowContainer>>> areas) {
370 mChildren.sort(Comparator.comparingInt(pendingArea -> pendingArea.mMinLayer));
371 for (int i = 0; i < mChildren.size(); i++) {
372 final PendingArea child = mChildren.get(i);
373 final DisplayArea area = child.createArea(parent, areaForLayer);
374 parent.addChild(area, WindowContainer.POSITION_TOP);
375 if (mFeature != null) {
376 areas.get(mFeature).add(area);
377 }
378 child.instantiateChildren(area, areaForLayer, level + 1, areas);
379 }
380 }
381
382 private DisplayArea createArea(DisplayArea<DisplayArea> parent,
383 DisplayArea.Tokens[] areaForLayer) {
384 if (mExisting != null) {
385 return mExisting;
386 }
387 DisplayArea.Type type;
388 if (mMinLayer > APPLICATION_LAYER) {
389 type = DisplayArea.Type.ABOVE_TASKS;
390 } else if (mMaxLayer < APPLICATION_LAYER) {
391 type = DisplayArea.Type.BELOW_TASKS;
392 } else {
393 type = DisplayArea.Type.ANY;
394 }
395 if (mFeature == null) {
396 final DisplayArea.Tokens leaf = new DisplayArea.Tokens(parent.mWmService, type,
397 "Leaf:" + mMinLayer + ":" + mMaxLayer);
398 for (int i = mMinLayer; i <= mMaxLayer; i++) {
399 areaForLayer[i] = leaf;
400 }
401 return leaf;
402 } else {
403 return new DisplayArea(parent.mWmService, type, mFeature.mName + ":"
Wale Ogunwaledec34082020-03-22 09:45:00 -0700404 + mMinLayer + ":" + mMaxLayer, mFeature.mId);
Adrian Roos81163582020-01-08 23:21:16 +0100405 }
406 }
407 }
408}