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