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