1 /*
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 
17 package com.android.server.wm;
18 
19 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
20 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
21 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
22 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
23 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
24 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
25 import static android.view.WindowManagerPolicyConstants.APPLICATION_LAYER;
26 import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER;
27 import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_LAST;
28 import static android.window.DisplayAreaOrganizer.KEY_ROOT_DISPLAY_AREA_ID;
29 
30 import android.annotation.Nullable;
31 import android.os.Bundle;
32 import android.util.ArrayMap;
33 import android.util.ArraySet;
34 
35 import com.android.internal.annotations.VisibleForTesting;
36 import com.android.server.policy.WindowManagerPolicy;
37 
38 import java.util.ArrayList;
39 import java.util.Arrays;
40 import java.util.Collections;
41 import java.util.Comparator;
42 import java.util.List;
43 import java.util.Map;
44 import java.util.Set;
45 import java.util.function.BiFunction;
46 
47 /**
48  * A builder for instantiating a complex {@link DisplayAreaPolicy}
49  *
50  * <p>Given a set of features (that each target a set of window types), it builds the necessary
51  * {@link DisplayArea} hierarchy.
52  *
53  * <p>Example:
54  *
55  * <pre class="prettyprint">
56  *      // Build root hierarchy of the logical display.
57  *      DisplayAreaPolicyBuilder.HierarchyBuilder rootHierarchy =
58  *          new DisplayAreaPolicyBuilder.HierarchyBuilder(root)
59  *              // Feature for targeting everything below the magnification overlay
60  *              .addFeature(new DisplayAreaPolicyBuilder.Feature.Builder(wmService.mPolicy,
61  *                             "WindowedMagnification", FEATURE_WINDOWED_MAGNIFICATION)
62  *                             .upTo(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
63  *                             .except(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
64  *                             // Make the DA dimmable so that the magnify window also mirrors the
65  *                             // dim layer
66  *                             .setNewDisplayAreaSupplier(DisplayArea.Dimmable::new)
67  *                             .build())
68  *              .setImeContainer(imeContainer)
69  *              .setTaskDisplayAreas(rootTdaList);
70  *
71  *      // Build root hierarchy of first and second DisplayAreaGroup.
72  *      RootDisplayArea firstRoot = new RootDisplayArea(wmService, "FirstRoot", FEATURE_FIRST_ROOT);
73  *      DisplayAreaPolicyBuilder.HierarchyBuilder firstGroupHierarchy =
74  *          new DisplayAreaPolicyBuilder.HierarchyBuilder(firstRoot)
75  *              // (Optional) .addFeature(...)
76  *              .setTaskDisplayAreas(firstTdaList);
77  *
78  *      RootDisplayArea secondRoot = new RootDisplayArea(wmService, "SecondRoot",
79  *          FEATURE_REAR_ROOT);
80  *      DisplayAreaPolicyBuilder.HierarchyBuilder secondGroupHierarchy =
81  *          new DisplayAreaPolicyBuilder.HierarchyBuilder(secondRoot)
82  *              // (Optional) .addFeature(...)
83  *              .setTaskDisplayAreas(secondTdaList);
84  *
85  *      // Define the function to select root for window to attach.
86  *      BiFunction<WindowToken, Bundle, RootDisplayArea> selectRootForWindowFunc =
87  *                (windowToken, options) -> {
88  *                    if (options == null) {
89  *                        return root;
90  *                    }
91  *                    // OEMs need to define the condition.
92  *                    if (...) {
93  *                        return firstRoot;
94  *                    }
95  *                    if (...) {
96  *                        return secondRoot;
97  *                    }
98  *                    return root;
99  *                };
100  *
101  *      return new DisplayAreaPolicyBuilder()
102  *                .setRootHierarchy(rootHierarchy)
103  *                .addDisplayAreaGroupHierarchy(firstGroupHierarchy)
104  *                .addDisplayAreaGroupHierarchy(secondGroupHierarchy)
105  *                .setSelectRootForWindowFunc(selectRootForWindowFunc)
106  *                .build(wmService, content);
107  * </pre>
108  *
109  * This builds a policy with the following hierarchy:
110  * <pre class="prettyprint">
111  *      - RootDisplayArea (DisplayContent)
112  *          - WindowedMagnification
113  *              - DisplayArea.Tokens (Wallpapers can be attached here)
114  *              - TaskDisplayArea
115  *              - RootDisplayArea (FirstRoot)
116  *                  - DisplayArea.Tokens (Wallpapers can be attached here)
117  *                  - TaskDisplayArea
118  *                  - DisplayArea.Tokens (windows above Tasks up to IME can be attached here)
119  *                  - DisplayArea.Tokens (windows above IME can be attached here)
120  *              - RootDisplayArea (SecondRoot)
121  *                  - DisplayArea.Tokens (Wallpapers can be attached here)
122  *                  - TaskDisplayArea
123  *                  - DisplayArea.Tokens (windows above Tasks up to IME can be attached here)
124  *                  - DisplayArea.Tokens (windows above IME can be attached here)
125  *              - DisplayArea.Tokens (windows above Tasks up to IME can be attached here)
126  *              - ImeContainers
127  *              - DisplayArea.Tokens (windows above IME up to TYPE_ACCESSIBILITY_OVERLAY can be
128  *                                    attached here)
129  *          - DisplayArea.Tokens (TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY and up can be attached
130  *                                here)
131  * </pre>
132  * When a {@link WindowToken} of Wallpaper needs to be attached, the policy will call the OEM
133  * defined {@link #mSelectRootForWindowFunc} to get a {@link RootDisplayArea}. It will then place
134  * the window to the corresponding {@link DisplayArea.Tokens} under the returned root
135  * {@link RootDisplayArea}.
136  */
137 class DisplayAreaPolicyBuilder {
138 
139     @Nullable private HierarchyBuilder mRootHierarchyBuilder;
140     private final ArrayList<HierarchyBuilder> mDisplayAreaGroupHierarchyBuilders =
141             new ArrayList<>();
142 
143     /**
144      * When a window is created, the policy will use this function, which takes window type and
145      * options, to select the {@link RootDisplayArea} to place that window in. The selected root
146      * can be either the one of the {@link #mRootHierarchyBuilder} or the one of any of the
147      * {@link #mDisplayAreaGroupHierarchyBuilders}.
148      * @see DefaultSelectRootForWindowFunction as an example.
149      **/
150     @Nullable private BiFunction<Integer, Bundle, RootDisplayArea> mSelectRootForWindowFunc;
151 
152     /** Defines the root hierarchy for the whole logical display. */
setRootHierarchy(HierarchyBuilder rootHierarchyBuilder)153     DisplayAreaPolicyBuilder setRootHierarchy(HierarchyBuilder rootHierarchyBuilder) {
154         mRootHierarchyBuilder = rootHierarchyBuilder;
155         return this;
156     }
157 
158     /**
159      * Defines a DisplayAreaGroup hierarchy. Its root will be added as a child of the root
160      * hierarchy.
161      */
addDisplayAreaGroupHierarchy( HierarchyBuilder displayAreaGroupHierarchy)162     DisplayAreaPolicyBuilder addDisplayAreaGroupHierarchy(
163             HierarchyBuilder displayAreaGroupHierarchy) {
164         mDisplayAreaGroupHierarchyBuilders.add(displayAreaGroupHierarchy);
165         return this;
166     }
167 
168     /**
169      * The policy will use this function to find the root to place windows in.
170      * @see DefaultSelectRootForWindowFunction as an example.
171      */
setSelectRootForWindowFunc( BiFunction<Integer, Bundle, RootDisplayArea> selectRootForWindowFunc)172     DisplayAreaPolicyBuilder setSelectRootForWindowFunc(
173             BiFunction<Integer, Bundle, RootDisplayArea> selectRootForWindowFunc) {
174         mSelectRootForWindowFunc = selectRootForWindowFunc;
175         return this;
176     }
177 
178     /**
179      * Makes sure the setting meets the requirement:
180      * 1. {@link #mRootHierarchyBuilder} must be set.
181      * 2. {@link RootDisplayArea} and {@link TaskDisplayArea} must have unique ids.
182      * 3. {@link Feature} below the same {@link RootDisplayArea} must have unique ids.
183      * 4. There must be exactly one {@link HierarchyBuilder} that contains the IME container.
184      * 5. There must be exactly one {@link HierarchyBuilder} that contains the default
185      *    {@link TaskDisplayArea} with id {@link FEATURE_DEFAULT_TASK_CONTAINER}.
186      * 6. None of the ids is greater than {@link FEATURE_VENDOR_LAST}.
187      */
validate()188     private void validate() {
189         if (mRootHierarchyBuilder == null) {
190             throw new IllegalStateException("Root must be set for the display area policy.");
191         }
192 
193         final Set<Integer> uniqueIdSet = new ArraySet<>();
194         final Set<Integer> allIdSet = new ArraySet<>();
195         validateIds(mRootHierarchyBuilder, uniqueIdSet, allIdSet);
196         boolean containsImeContainer = mRootHierarchyBuilder.mImeContainer != null;
197         boolean containsDefaultTda = containsDefaultTaskDisplayArea(mRootHierarchyBuilder);
198         for (int i = 0; i < mDisplayAreaGroupHierarchyBuilders.size(); i++) {
199             HierarchyBuilder hierarchyBuilder = mDisplayAreaGroupHierarchyBuilders.get(i);
200             validateIds(hierarchyBuilder, uniqueIdSet, allIdSet);
201 
202             if (hierarchyBuilder.mTaskDisplayAreas.isEmpty()) {
203                 throw new IllegalStateException(
204                         "DisplayAreaGroup must contain at least one TaskDisplayArea.");
205             }
206 
207             if (containsImeContainer) {
208                 if (hierarchyBuilder.mImeContainer != null) {
209                     throw new IllegalStateException(
210                             "Only one DisplayArea hierarchy can contain the IME container");
211                 }
212             } else {
213                 containsImeContainer = hierarchyBuilder.mImeContainer != null;
214             }
215 
216             if (containsDefaultTda) {
217                 if (containsDefaultTaskDisplayArea(hierarchyBuilder)) {
218                     throw new IllegalStateException("Only one TaskDisplayArea can have the feature "
219                             + "id of FEATURE_DEFAULT_TASK_CONTAINER");
220                 }
221             } else {
222                 containsDefaultTda = containsDefaultTaskDisplayArea(hierarchyBuilder);
223             }
224         }
225 
226         if (!containsImeContainer) {
227             throw new IllegalStateException("IME container must be set.");
228         }
229 
230         if (!containsDefaultTda) {
231             throw new IllegalStateException("There must be a default TaskDisplayArea with id of "
232                     + "FEATURE_DEFAULT_TASK_CONTAINER.");
233         }
234     }
235 
236     /** Checks if the given hierarchy contains the default {@link TaskDisplayArea}. */
containsDefaultTaskDisplayArea(HierarchyBuilder displayAreaHierarchy)237     private static boolean containsDefaultTaskDisplayArea(HierarchyBuilder displayAreaHierarchy) {
238         for (int i = 0; i < displayAreaHierarchy.mTaskDisplayAreas.size(); i++) {
239             if (displayAreaHierarchy.mTaskDisplayAreas.get(i).mFeatureId
240                     == FEATURE_DEFAULT_TASK_CONTAINER) {
241                 return true;
242             }
243         }
244         return false;
245     }
246 
247     /**
248      * Makes sure that ids meet requirement.
249      * {@link RootDisplayArea} and {@link TaskDisplayArea} must have unique ids.
250      * {@link Feature} below the same {@link RootDisplayArea} must have unique ids, but
251      * {@link Feature} below different {@link RootDisplayArea} can have the same id so that we can
252      * organize them together.
253      * None of the ids is greater than {@link FEATURE_VENDOR_LAST}
254      *
255      * @param uniqueIdSet ids of {@link RootDisplayArea} and {@link TaskDisplayArea} that must be
256      *                    unique,
257      * @param allIdSet ids of {@link RootDisplayArea}, {@link TaskDisplayArea} and {@link Feature}.
258      */
validateIds(HierarchyBuilder displayAreaHierarchy, Set<Integer> uniqueIdSet, Set<Integer> allIdSet)259     private static void validateIds(HierarchyBuilder displayAreaHierarchy,
260             Set<Integer> uniqueIdSet, Set<Integer> allIdSet) {
261         // Root must have unique id.
262         final int rootId = displayAreaHierarchy.mRoot.mFeatureId;
263         if (!allIdSet.add(rootId) || !uniqueIdSet.add(rootId)) {
264             throw new IllegalStateException(
265                     "RootDisplayArea must have unique id, but id=" + rootId + " is not unique.");
266         }
267         if (rootId > FEATURE_VENDOR_LAST) {
268             throw new IllegalStateException(
269                     "RootDisplayArea should not have an id greater than FEATURE_VENDOR_LAST.");
270         }
271 
272         // TDAs must have unique id.
273         for (int i = 0; i < displayAreaHierarchy.mTaskDisplayAreas.size(); i++) {
274             final int taskDisplayAreaId = displayAreaHierarchy.mTaskDisplayAreas.get(i).mFeatureId;
275             if (!allIdSet.add(taskDisplayAreaId) || !uniqueIdSet.add(taskDisplayAreaId)) {
276                 throw new IllegalStateException("TaskDisplayArea must have unique id, but id="
277                         + taskDisplayAreaId + " is not unique.");
278             }
279             if (taskDisplayAreaId > FEATURE_VENDOR_LAST) {
280                 throw new IllegalStateException("TaskDisplayArea declared in the policy should not"
281                         + "have an id greater than FEATURE_VENDOR_LAST.");
282             }
283         }
284 
285         // Features below the same root must have unique ids.
286         final Set<Integer> featureIdSet = new ArraySet<>();
287         for (int i = 0; i < displayAreaHierarchy.mFeatures.size(); i++) {
288             final int featureId = displayAreaHierarchy.mFeatures.get(i).getId();
289             if (uniqueIdSet.contains(featureId)) {
290                 throw new IllegalStateException("Feature must not have same id with any "
291                         + "RootDisplayArea or TaskDisplayArea, but id=" + featureId + " is used");
292             }
293             if (!featureIdSet.add(featureId)) {
294                 throw new IllegalStateException("Feature below the same root must have unique id, "
295                         + "but id=" + featureId + " is not unique.");
296             }
297             if (featureId > FEATURE_VENDOR_LAST) {
298                 throw new IllegalStateException(
299                         "Feature should not have an id greater than FEATURE_VENDOR_LAST.");
300             }
301         }
302 
303         // Features below different roots can have the same id so that we can organize them
304         // together.
305         allIdSet.addAll(featureIdSet);
306     }
307 
build(WindowManagerService wmService)308     Result build(WindowManagerService wmService) {
309         validate();
310 
311         // Attach DA group roots to screen hierarchy before adding windows to group hierarchies.
312         mRootHierarchyBuilder.build(mDisplayAreaGroupHierarchyBuilders);
313         List<RootDisplayArea> displayAreaGroupRoots = new ArrayList<>(
314                 mDisplayAreaGroupHierarchyBuilders.size());
315         for (int i = 0; i < mDisplayAreaGroupHierarchyBuilders.size(); i++) {
316             HierarchyBuilder hierarchyBuilder = mDisplayAreaGroupHierarchyBuilders.get(i);
317             hierarchyBuilder.build();
318             displayAreaGroupRoots.add(hierarchyBuilder.mRoot);
319         }
320         // Use the default function if it is not specified otherwise.
321         if (mSelectRootForWindowFunc == null) {
322             mSelectRootForWindowFunc = new DefaultSelectRootForWindowFunction(
323                     mRootHierarchyBuilder.mRoot, displayAreaGroupRoots);
324         }
325         return new Result(wmService, mRootHierarchyBuilder.mRoot, displayAreaGroupRoots,
326                 mSelectRootForWindowFunc);
327     }
328 
329     /**
330      * The default function to be used for finding {@link RootDisplayArea} for window to be attached
331      * to if there is no other function set through {@link #setSelectRootForWindowFunc(BiFunction)}.
332      *
333      * When a window is created with {@link Bundle} options, this function will select the
334      * {@link RootDisplayArea} based on the options. Returns {@link #mDisplayRoot} if there is no
335      * match found.
336      */
337     private static class DefaultSelectRootForWindowFunction implements
338             BiFunction<Integer, Bundle, RootDisplayArea> {
339         final RootDisplayArea mDisplayRoot;
340         final List<RootDisplayArea> mDisplayAreaGroupRoots;
341 
DefaultSelectRootForWindowFunction(RootDisplayArea displayRoot, List<RootDisplayArea> displayAreaGroupRoots)342         DefaultSelectRootForWindowFunction(RootDisplayArea displayRoot,
343                 List<RootDisplayArea> displayAreaGroupRoots) {
344             mDisplayRoot = displayRoot;
345             mDisplayAreaGroupRoots = Collections.unmodifiableList(displayAreaGroupRoots);
346         }
347 
348         @Override
apply(Integer windowType, Bundle options)349         public RootDisplayArea apply(Integer windowType, Bundle options) {
350             if (mDisplayAreaGroupRoots.isEmpty()) {
351                 return mDisplayRoot;
352             }
353 
354             // Select the RootDisplayArea set in options.
355             if (options != null && options.containsKey(KEY_ROOT_DISPLAY_AREA_ID)) {
356                 final int rootId = options.getInt(KEY_ROOT_DISPLAY_AREA_ID);
357                 if (mDisplayRoot.mFeatureId == rootId) {
358                     return mDisplayRoot;
359                 }
360                 for (int i = mDisplayAreaGroupRoots.size() - 1; i >= 0; i--) {
361                     if (mDisplayAreaGroupRoots.get(i).mFeatureId == rootId) {
362                         return mDisplayAreaGroupRoots.get(i);
363                     }
364                 }
365             }
366             return mDisplayRoot;
367         }
368     }
369 
370     /**
371      *  Builder to define {@link Feature} and {@link DisplayArea} hierarchy under a
372      * {@link RootDisplayArea}
373      */
374     static class HierarchyBuilder {
375         private static final int LEAF_TYPE_TASK_CONTAINERS = 1;
376         private static final int LEAF_TYPE_IME_CONTAINERS = 2;
377         private static final int LEAF_TYPE_TOKENS = 0;
378 
379         private final RootDisplayArea mRoot;
380         private final ArrayList<DisplayAreaPolicyBuilder.Feature> mFeatures = new ArrayList<>();
381         private final ArrayList<TaskDisplayArea> mTaskDisplayAreas = new ArrayList<>();
382         @Nullable
383         private DisplayArea.Tokens mImeContainer;
384 
HierarchyBuilder(RootDisplayArea root)385         HierarchyBuilder(RootDisplayArea root) {
386             mRoot = root;
387         }
388 
389         /** Adds {@link Feature} that applies to layers under this container. */
addFeature(DisplayAreaPolicyBuilder.Feature feature)390         HierarchyBuilder addFeature(DisplayAreaPolicyBuilder.Feature feature) {
391             mFeatures.add(feature);
392             return this;
393         }
394 
395         /**
396          * Sets {@link TaskDisplayArea} that are children of this hierarchy root.
397          * {@link DisplayArea} group must have at least one {@link TaskDisplayArea}.
398          */
setTaskDisplayAreas(List<TaskDisplayArea> taskDisplayAreas)399         HierarchyBuilder setTaskDisplayAreas(List<TaskDisplayArea> taskDisplayAreas) {
400             mTaskDisplayAreas.clear();
401             mTaskDisplayAreas.addAll(taskDisplayAreas);
402             return this;
403         }
404 
405         /** Sets IME container as a child of this hierarchy root. */
setImeContainer(DisplayArea.Tokens imeContainer)406         HierarchyBuilder setImeContainer(DisplayArea.Tokens imeContainer) {
407             mImeContainer = imeContainer;
408             return this;
409         }
410 
411         /** Builds the {@link DisplayArea} hierarchy below root. */
build()412         private void build() {
413             build(null /* displayAreaGroupHierarchyBuilders */);
414         }
415 
416         /**
417          * Builds the {@link DisplayArea} hierarchy below root. And adds the roots of those
418          * {@link HierarchyBuilder} as children.
419          */
build(@ullable List<HierarchyBuilder> displayAreaGroupHierarchyBuilders)420         private void build(@Nullable List<HierarchyBuilder> displayAreaGroupHierarchyBuilders) {
421             final WindowManagerPolicy policy = mRoot.mWmService.mPolicy;
422             final int maxWindowLayerCount = policy.getMaxWindowLayer() + 1;
423             final DisplayArea.Tokens[] displayAreaForLayer =
424                     new DisplayArea.Tokens[maxWindowLayerCount];
425             final Map<Feature, List<DisplayArea<WindowContainer>>> featureAreas =
426                     new ArrayMap<>(mFeatures.size());
427             for (int i = 0; i < mFeatures.size(); i++) {
428                 featureAreas.put(mFeatures.get(i), new ArrayList<>());
429             }
430 
431             // This method constructs the layer hierarchy with the following properties:
432             // (1) Every feature maps to a set of DisplayAreas
433             // (2) After adding a window, for every feature the window's type belongs to,
434             //     it is a descendant of one of the corresponding DisplayAreas of the feature.
435             // (3) Z-order is maintained, i.e. if z-range(area) denotes the set of layers of windows
436             //     within a DisplayArea:
437             //      for every pair of DisplayArea siblings (a,b), where a is below b, it holds that
438             //      max(z-range(a)) <= min(z-range(b))
439             //
440             // The algorithm below iteratively creates such a hierarchy:
441             //  - Initially, all windows are attached to the root.
442             //  - For each feature we create a set of DisplayAreas, by looping over the layers
443             //    - if the feature does apply to the current layer, we need to find a DisplayArea
444             //      for it to satisfy (2)
445             //      - we can re-use the previous layer's area if:
446             //         the current feature also applies to the previous layer, (to satisfy (3))
447             //         and the last feature that applied to the previous layer is the same as
448             //           the last feature that applied to the current layer (to satisfy (2))
449             //      - otherwise we create a new DisplayArea below the last feature that applied
450             //        to the current layer
451 
452             PendingArea[] areaForLayer = new PendingArea[maxWindowLayerCount];
453             final PendingArea root = new PendingArea(null, 0, null);
454             Arrays.fill(areaForLayer, root);
455 
456             // Create DisplayAreas to cover all defined features.
457             final int size = mFeatures.size();
458             for (int i = 0; i < size; i++) {
459                 // Traverse the features with the order they are defined, so that the early defined
460                 // feature will be on the top in the hierarchy.
461                 final Feature feature = mFeatures.get(i);
462                 PendingArea featureArea = null;
463                 for (int layer = 0; layer < maxWindowLayerCount; layer++) {
464                     if (feature.mWindowLayers[layer]) {
465                         // This feature will be applied to this window layer.
466                         //
467                         // We need to find a DisplayArea for it:
468                         // We can reuse the existing one if it was created for this feature for the
469                         // previous layer AND the last feature that applied to the previous layer is
470                         // the same as the feature that applied to the current layer (so they are ok
471                         // to share the same parent DisplayArea).
472                         if (featureArea == null || featureArea.mParent != areaForLayer[layer]) {
473                             // No suitable DisplayArea:
474                             // Create a new one under the previous area (as parent) for this layer.
475                             featureArea = new PendingArea(feature, layer, areaForLayer[layer]);
476                             areaForLayer[layer].mChildren.add(featureArea);
477                         }
478                         areaForLayer[layer] = featureArea;
479                     } else {
480                         // This feature won't be applied to this window layer. If it needs to be
481                         // applied to the next layer, we will need to create a new DisplayArea for
482                         // that.
483                         featureArea = null;
484                     }
485                 }
486             }
487 
488             // Create Tokens as leaf for every layer.
489             PendingArea leafArea = null;
490             int leafType = LEAF_TYPE_TOKENS;
491             for (int layer = 0; layer < maxWindowLayerCount; layer++) {
492                 int type = typeOfLayer(policy, layer);
493                 // Check whether we can reuse the same Tokens with the previous layer. This happens
494                 // if the previous layer is the same type as the current layer AND there is no
495                 // feature that applies to only one of them.
496                 if (leafArea == null || leafArea.mParent != areaForLayer[layer]
497                         || type != leafType) {
498                     // Create a new Tokens for this layer.
499                     leafArea = new PendingArea(null /* feature */, layer, areaForLayer[layer]);
500                     areaForLayer[layer].mChildren.add(leafArea);
501                     leafType = type;
502                     if (leafType == LEAF_TYPE_TASK_CONTAINERS) {
503                         // We use the passed in TaskDisplayAreas for task container type of layer.
504                         // Skip creating Tokens even if there is no TDA.
505                         addTaskDisplayAreasToApplicationLayer(areaForLayer[layer]);
506                         addDisplayAreaGroupsToApplicationLayer(areaForLayer[layer],
507                                 displayAreaGroupHierarchyBuilders);
508                         leafArea.mSkipTokens = true;
509                     } else if (leafType == LEAF_TYPE_IME_CONTAINERS) {
510                         // We use the passed in ImeContainer for ime container type of layer.
511                         // Skip creating Tokens even if there is no ime container.
512                         leafArea.mExisting = mImeContainer;
513                         leafArea.mSkipTokens = true;
514                     }
515                 }
516                 leafArea.mMaxLayer = layer;
517             }
518             root.computeMaxLayer();
519 
520             // We built a tree of PendingAreas above with all the necessary info to represent the
521             // hierarchy, now create and attach real DisplayAreas to the root.
522             root.instantiateChildren(mRoot, displayAreaForLayer, 0, featureAreas);
523 
524             // Notify the root that we have finished attaching all the DisplayAreas. Cache all the
525             // feature related collections there for fast access.
526             mRoot.onHierarchyBuilt(mFeatures, displayAreaForLayer, featureAreas);
527         }
528 
529         /** Adds all {@link TaskDisplayArea} to the application layer. */
addTaskDisplayAreasToApplicationLayer(PendingArea parentPendingArea)530         private void addTaskDisplayAreasToApplicationLayer(PendingArea parentPendingArea) {
531             final int count = mTaskDisplayAreas.size();
532             for (int i = 0; i < count; i++) {
533                 PendingArea leafArea =
534                         new PendingArea(null /* feature */, APPLICATION_LAYER, parentPendingArea);
535                 leafArea.mExisting = mTaskDisplayAreas.get(i);
536                 leafArea.mMaxLayer = APPLICATION_LAYER;
537                 parentPendingArea.mChildren.add(leafArea);
538             }
539         }
540 
541         /** Adds roots of the DisplayAreaGroups to the application layer. */
addDisplayAreaGroupsToApplicationLayer( DisplayAreaPolicyBuilder.PendingArea parentPendingArea, @Nullable List<HierarchyBuilder> displayAreaGroupHierarchyBuilders)542         private void addDisplayAreaGroupsToApplicationLayer(
543                 DisplayAreaPolicyBuilder.PendingArea parentPendingArea,
544                 @Nullable List<HierarchyBuilder> displayAreaGroupHierarchyBuilders) {
545             if (displayAreaGroupHierarchyBuilders == null) {
546                 return;
547             }
548             final int count = displayAreaGroupHierarchyBuilders.size();
549             for (int i = 0; i < count; i++) {
550                 DisplayAreaPolicyBuilder.PendingArea
551                         leafArea = new DisplayAreaPolicyBuilder.PendingArea(
552                         null /* feature */, APPLICATION_LAYER, parentPendingArea);
553                 leafArea.mExisting = displayAreaGroupHierarchyBuilders.get(i).mRoot;
554                 leafArea.mMaxLayer = APPLICATION_LAYER;
555                 parentPendingArea.mChildren.add(leafArea);
556             }
557         }
558 
typeOfLayer(WindowManagerPolicy policy, int layer)559         private static int typeOfLayer(WindowManagerPolicy policy, int layer) {
560             if (layer == APPLICATION_LAYER) {
561                 return LEAF_TYPE_TASK_CONTAINERS;
562             } else if (layer == policy.getWindowLayerFromTypeLw(TYPE_INPUT_METHOD)
563                     || layer == policy.getWindowLayerFromTypeLw(TYPE_INPUT_METHOD_DIALOG)) {
564                 return LEAF_TYPE_IME_CONTAINERS;
565             } else {
566                 return LEAF_TYPE_TOKENS;
567             }
568         }
569     }
570 
571     /** Supplier interface to provide a new created {@link DisplayArea}. */
572     interface NewDisplayAreaSupplier {
create(WindowManagerService wms, DisplayArea.Type type, String name, int featureId)573         DisplayArea create(WindowManagerService wms, DisplayArea.Type type, String name,
574                 int featureId);
575     }
576 
577     /**
578      * A feature that requires {@link DisplayArea DisplayArea(s)}.
579      */
580     static class Feature {
581         private final String mName;
582         private final int mId;
583         private final boolean[] mWindowLayers;
584         private final NewDisplayAreaSupplier mNewDisplayAreaSupplier;
585 
Feature(String name, int id, boolean[] windowLayers, NewDisplayAreaSupplier newDisplayAreaSupplier)586         private Feature(String name, int id, boolean[] windowLayers,
587                 NewDisplayAreaSupplier newDisplayAreaSupplier) {
588             mName = name;
589             mId = id;
590             mWindowLayers = windowLayers;
591             mNewDisplayAreaSupplier = newDisplayAreaSupplier;
592         }
593 
594         /**
595          * Returns the id of the feature.
596          *
597          * <p>Must be unique among the features added to a {@link DisplayAreaPolicyBuilder}.
598          *
599          * @see android.window.DisplayAreaOrganizer#FEATURE_SYSTEM_FIRST
600          * @see android.window.DisplayAreaOrganizer#FEATURE_VENDOR_FIRST
601          */
getId()602         public int getId() {
603             return mId;
604         }
605 
606         @Override
toString()607         public String toString() {
608             return "Feature(\"" + mName + "\", " + mId + '}';
609         }
610 
611         static class Builder {
612             private final WindowManagerPolicy mPolicy;
613             private final String mName;
614             private final int mId;
615             private final boolean[] mLayers;
616             private NewDisplayAreaSupplier mNewDisplayAreaSupplier = DisplayArea::new;
617             private boolean mExcludeRoundedCorner = true;
618 
619             /**
620              * Builds a new feature that applies to a set of window types as specified by the
621              * builder methods.
622              *
623              * <p>The set of types is updated iteratively in the order of the method invocations.
624              * For example, {@code all().except(TYPE_STATUS_BAR)} expresses that a feature should
625              * apply to all types except TYPE_STATUS_BAR.
626              *
627              * <p>The builder starts out with the feature not applying to any types.
628              *
629              * @param name the name of the feature.
630              * @param id of the feature. {@see Feature#getId}
631              */
Builder(WindowManagerPolicy policy, String name, int id)632             Builder(WindowManagerPolicy policy, String name, int id) {
633                 mPolicy = policy;
634                 mName = name;
635                 mId = id;
636                 mLayers = new boolean[mPolicy.getMaxWindowLayer() + 1];
637             }
638 
639             /**
640              * Set that the feature applies to all window types.
641              */
all()642             Builder all() {
643                 Arrays.fill(mLayers, true);
644                 return this;
645             }
646 
647             /**
648              * Set that the feature applies to the given window types.
649              */
and(int... types)650             Builder and(int... types) {
651                 for (int i = 0; i < types.length; i++) {
652                     int type = types[i];
653                     set(type, true);
654                 }
655                 return this;
656             }
657 
658             /**
659              * Set that the feature does not apply to the given window types.
660              */
except(int... types)661             Builder except(int... types) {
662                 for (int i = 0; i < types.length; i++) {
663                     int type = types[i];
664                     set(type, false);
665                 }
666                 return this;
667             }
668 
669             /**
670              * Set that the feature applies window types that are layerd at or below the layer of
671              * the given window type.
672              */
upTo(int typeInclusive)673             Builder upTo(int typeInclusive) {
674                 final int max = layerFromType(typeInclusive, false);
675                 for (int i = 0; i < max; i++) {
676                     mLayers[i] = true;
677                 }
678                 set(typeInclusive, true);
679                 return this;
680             }
681 
682             /**
683              * Sets the function to create new {@link DisplayArea} for this feature. By default, it
684              * uses {@link DisplayArea}'s constructor.
685              */
setNewDisplayAreaSupplier(NewDisplayAreaSupplier newDisplayAreaSupplier)686             Builder setNewDisplayAreaSupplier(NewDisplayAreaSupplier newDisplayAreaSupplier) {
687                 mNewDisplayAreaSupplier = newDisplayAreaSupplier;
688                 return this;
689             }
690 
691             // TODO(b/155340867): consider to remove the logic after using pure Surface for rounded
692             // corner overlay.
setExcludeRoundedCornerOverlay(boolean excludeRoundedCorner)693             Builder setExcludeRoundedCornerOverlay(boolean excludeRoundedCorner) {
694                 mExcludeRoundedCorner = excludeRoundedCorner;
695                 return this;
696             }
697 
build()698             Feature build() {
699                 if (mExcludeRoundedCorner) {
700                     // Always put the rounded corner layer to the top most layer.
701                     mLayers[mPolicy.getMaxWindowLayer()] = false;
702                 }
703                 return new Feature(mName, mId, mLayers.clone(), mNewDisplayAreaSupplier);
704             }
705 
set(int type, boolean value)706             private void set(int type, boolean value) {
707                 mLayers[layerFromType(type, true)] = value;
708                 if (type == TYPE_APPLICATION_OVERLAY) {
709                     mLayers[layerFromType(type, true)] = value;
710                     mLayers[layerFromType(TYPE_SYSTEM_ALERT, false)] = value;
711                     mLayers[layerFromType(TYPE_SYSTEM_OVERLAY, false)] = value;
712                     mLayers[layerFromType(TYPE_SYSTEM_ERROR, false)] = value;
713                 }
714             }
715 
layerFromType(int type, boolean internalWindows)716             private int layerFromType(int type, boolean internalWindows) {
717                 return mPolicy.getWindowLayerFromTypeLw(type, internalWindows);
718             }
719         }
720     }
721 
722     static class Result extends DisplayAreaPolicy {
723         final List<RootDisplayArea> mDisplayAreaGroupRoots;
724         final BiFunction<Integer, Bundle, RootDisplayArea> mSelectRootForWindowFunc;
725         private final TaskDisplayArea mDefaultTaskDisplayArea;
726 
Result(WindowManagerService wmService, RootDisplayArea root, List<RootDisplayArea> displayAreaGroupRoots, BiFunction<Integer, Bundle, RootDisplayArea> selectRootForWindowFunc)727         Result(WindowManagerService wmService, RootDisplayArea root,
728                 List<RootDisplayArea> displayAreaGroupRoots,
729                 BiFunction<Integer, Bundle, RootDisplayArea> selectRootForWindowFunc) {
730             super(wmService, root);
731             mDisplayAreaGroupRoots = Collections.unmodifiableList(displayAreaGroupRoots);
732             mSelectRootForWindowFunc = selectRootForWindowFunc;
733 
734             // Cache the default TaskDisplayArea for quick access.
735             mDefaultTaskDisplayArea = mRoot.getItemFromTaskDisplayAreas(taskDisplayArea ->
736                     taskDisplayArea.mFeatureId == FEATURE_DEFAULT_TASK_CONTAINER
737                             ? taskDisplayArea
738                             : null);
739             if (mDefaultTaskDisplayArea == null) {
740                 throw new IllegalStateException(
741                         "No display area with FEATURE_DEFAULT_TASK_CONTAINER");
742             }
743         }
744 
745         @Override
addWindow(WindowToken token)746         public void addWindow(WindowToken token) {
747             DisplayArea.Tokens area = findAreaForToken(token);
748             area.addChild(token);
749         }
750 
751         @VisibleForTesting
findAreaForToken(WindowToken token)752         DisplayArea.Tokens findAreaForToken(WindowToken token) {
753             return mSelectRootForWindowFunc.apply(token.windowType, token.mOptions)
754                     .findAreaForTokenInLayer(token);
755         }
756 
757         @Override
findAreaForWindowType(int type, Bundle options, boolean ownerCanManageAppTokens, boolean roundedCornerOverlay)758         public DisplayArea.Tokens findAreaForWindowType(int type, Bundle options,
759                 boolean ownerCanManageAppTokens, boolean roundedCornerOverlay) {
760             return mSelectRootForWindowFunc.apply(type, options).findAreaForWindowTypeInLayer(type,
761                     ownerCanManageAppTokens, roundedCornerOverlay);
762         }
763 
764         @VisibleForTesting
getFeatures()765         List<Feature> getFeatures() {
766             Set<Feature> features = new ArraySet<>();
767             features.addAll(mRoot.mFeatures);
768             for (int i = 0; i < mDisplayAreaGroupRoots.size(); i++) {
769                 features.addAll(mDisplayAreaGroupRoots.get(i).mFeatures);
770             }
771             return new ArrayList<>(features);
772         }
773 
774         @Override
getDisplayAreas(int featureId)775         public List<DisplayArea<? extends WindowContainer>> getDisplayAreas(int featureId) {
776             List<DisplayArea<? extends WindowContainer>> displayAreas = new ArrayList<>();
777             getDisplayAreas(mRoot, featureId, displayAreas);
778             for (int i = 0; i < mDisplayAreaGroupRoots.size(); i++) {
779                 getDisplayAreas(mDisplayAreaGroupRoots.get(i), featureId, displayAreas);
780             }
781             return displayAreas;
782         }
783 
getDisplayAreas(RootDisplayArea root, int featureId, List<DisplayArea<? extends WindowContainer>> displayAreas)784         private static void getDisplayAreas(RootDisplayArea root, int featureId,
785                 List<DisplayArea<? extends WindowContainer>> displayAreas) {
786             List<Feature> features = root.mFeatures;
787             for (int i = 0; i < features.size(); i++) {
788                 Feature feature = features.get(i);
789                 if (feature.mId == featureId) {
790                     displayAreas.addAll(root.mFeatureToDisplayAreas.get(feature));
791                 }
792             }
793         }
794 
795         @Override
getDefaultTaskDisplayArea()796         public TaskDisplayArea getDefaultTaskDisplayArea() {
797             return mDefaultTaskDisplayArea;
798         }
799     }
800 
801     static class PendingArea {
802         final int mMinLayer;
803         final ArrayList<PendingArea> mChildren = new ArrayList<>();
804         final Feature mFeature;
805         final PendingArea mParent;
806         int mMaxLayer;
807 
808         /** If not {@code null}, use this instead of creating a {@link DisplayArea.Tokens}. */
809         @Nullable DisplayArea mExisting;
810 
811         /**
812          * Whether to skip creating a {@link DisplayArea.Tokens} if {@link #mExisting} is
813          * {@code null}.
814          *
815          * <p>This will be set for {@link HierarchyBuilder#LEAF_TYPE_IME_CONTAINERS} and
816          * {@link HierarchyBuilder#LEAF_TYPE_TASK_CONTAINERS}, because we don't want to create
817          * {@link DisplayArea.Tokens} for them even if they are not set.
818          */
819         boolean mSkipTokens = false;
820 
PendingArea(Feature feature, int minLayer, PendingArea parent)821         PendingArea(Feature feature, int minLayer, PendingArea parent) {
822             mMinLayer = minLayer;
823             mFeature = feature;
824             mParent = parent;
825         }
826 
computeMaxLayer()827         int computeMaxLayer() {
828             for (int i = 0; i < mChildren.size(); i++) {
829                 mMaxLayer = Math.max(mMaxLayer, mChildren.get(i).computeMaxLayer());
830             }
831             return mMaxLayer;
832         }
833 
instantiateChildren(DisplayArea<DisplayArea> parent, DisplayArea.Tokens[] areaForLayer, int level, Map<Feature, List<DisplayArea<WindowContainer>>> areas)834         void instantiateChildren(DisplayArea<DisplayArea> parent, DisplayArea.Tokens[] areaForLayer,
835                 int level, Map<Feature, List<DisplayArea<WindowContainer>>> areas) {
836             mChildren.sort(Comparator.comparingInt(pendingArea -> pendingArea.mMinLayer));
837             for (int i = 0; i < mChildren.size(); i++) {
838                 final PendingArea child = mChildren.get(i);
839                 final DisplayArea area = child.createArea(parent, areaForLayer);
840                 if (area == null) {
841                     // TaskDisplayArea and ImeContainer can be set at different hierarchy, so it can
842                     // be null.
843                     continue;
844                 }
845                 parent.addChild(area, WindowContainer.POSITION_TOP);
846                 if (child.mFeature != null) {
847                     areas.get(child.mFeature).add(area);
848                 }
849                 child.instantiateChildren(area, areaForLayer, level + 1, areas);
850             }
851         }
852 
853         @Nullable
createArea(DisplayArea<DisplayArea> parent, DisplayArea.Tokens[] areaForLayer)854         private DisplayArea createArea(DisplayArea<DisplayArea> parent,
855                 DisplayArea.Tokens[] areaForLayer) {
856             if (mExisting != null) {
857                 if (mExisting.asTokens() != null) {
858                     // Store the WindowToken container for layers
859                     fillAreaForLayers(mExisting.asTokens(), areaForLayer);
860                 }
861                 return mExisting;
862             }
863             if (mSkipTokens) {
864                 return null;
865             }
866             DisplayArea.Type type;
867             if (mMinLayer > APPLICATION_LAYER) {
868                 type = DisplayArea.Type.ABOVE_TASKS;
869             } else if (mMaxLayer < APPLICATION_LAYER) {
870                 type = DisplayArea.Type.BELOW_TASKS;
871             } else {
872                 type = DisplayArea.Type.ANY;
873             }
874             if (mFeature == null) {
875                 final DisplayArea.Tokens leaf = new DisplayArea.Tokens(parent.mWmService, type,
876                         "Leaf:" + mMinLayer + ":" + mMaxLayer);
877                 fillAreaForLayers(leaf, areaForLayer);
878                 return leaf;
879             } else {
880                 return mFeature.mNewDisplayAreaSupplier.create(parent.mWmService, type,
881                         mFeature.mName + ":" + mMinLayer + ":" + mMaxLayer, mFeature.mId);
882             }
883         }
884 
fillAreaForLayers(DisplayArea.Tokens leaf, DisplayArea.Tokens[] areaForLayer)885         private void fillAreaForLayers(DisplayArea.Tokens leaf, DisplayArea.Tokens[] areaForLayer) {
886             for (int i = mMinLayer; i <= mMaxLayer; i++) {
887                 areaForLayer[i] = leaf;
888             }
889         }
890     }
891 }
892