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