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