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