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.Display.DEFAULT_DISPLAY; 20 import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY; 21 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; 22 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; 23 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; 24 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; 25 import static android.view.WindowManager.LayoutParams.TYPE_POINTER; 26 import static android.view.WindowManager.LayoutParams.TYPE_PRESENTATION; 27 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; 28 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; 29 import static android.view.WindowManagerPolicyConstants.APPLICATION_LAYER; 30 import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER; 31 import static android.window.DisplayAreaOrganizer.FEATURE_FULLSCREEN_MAGNIFICATION; 32 import static android.window.DisplayAreaOrganizer.FEATURE_IME_PLACEHOLDER; 33 import static android.window.DisplayAreaOrganizer.FEATURE_ONE_HANDED; 34 import static android.window.DisplayAreaOrganizer.FEATURE_ROOT; 35 import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST; 36 import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_LAST; 37 import static android.window.DisplayAreaOrganizer.FEATURE_WINDOWED_MAGNIFICATION; 38 import static android.window.DisplayAreaOrganizer.KEY_ROOT_DISPLAY_AREA_ID; 39 40 import static com.android.server.wm.DisplayArea.Type.ABOVE_TASKS; 41 import static com.android.server.wm.DisplayAreaPolicyBuilder.Feature; 42 43 import static com.google.common.truth.Truth.assertThat; 44 45 import static org.mockito.Mockito.doReturn; 46 import static org.mockito.Mockito.mock; 47 import static org.mockito.Mockito.when; 48 import static org.testng.Assert.assertThrows; 49 50 import static java.util.stream.Collectors.toList; 51 52 import android.app.ActivityOptions; 53 import android.content.res.Resources; 54 import android.os.Binder; 55 import android.os.Bundle; 56 import android.os.IBinder; 57 import android.platform.test.annotations.Presubmit; 58 import android.view.SurfaceControl; 59 import android.window.WindowContainerToken; 60 61 import com.google.android.collect.Lists; 62 63 import org.hamcrest.CustomTypeSafeMatcher; 64 import org.hamcrest.Description; 65 import org.hamcrest.Matcher; 66 import org.junit.Before; 67 import org.junit.Rule; 68 import org.junit.Test; 69 70 import java.util.ArrayList; 71 import java.util.HashMap; 72 import java.util.HashSet; 73 import java.util.List; 74 import java.util.Map; 75 import java.util.Set; 76 import java.util.function.Consumer; 77 import java.util.function.Function; 78 import java.util.stream.Collectors; 79 80 /** 81 * Build/Install/Run: 82 * atest WmTests:DisplayAreaPolicyBuilderTest 83 */ 84 @Presubmit 85 public class DisplayAreaPolicyBuilderTest { 86 private static final String KEY_LAUNCH_TASK_DISPLAY_AREA_FEATURE_ID = 87 "android.test.launchTaskDisplayAreaFeatureId"; 88 89 @Rule 90 public final SystemServicesTestRule mSystemServices = new SystemServicesTestRule(); 91 92 private TestWindowManagerPolicy mPolicy = new TestWindowManagerPolicy(); 93 private WindowManagerService mWms; 94 private RootDisplayArea mRoot; 95 private DisplayArea.Tokens mImeContainer; 96 private DisplayContent mDisplayContent; 97 private TaskDisplayArea mDefaultTaskDisplayArea; 98 private List<TaskDisplayArea> mTaskDisplayAreaList; 99 private RootDisplayArea mGroupRoot1; 100 private RootDisplayArea mGroupRoot2; 101 private TaskDisplayArea mTda1; 102 private TaskDisplayArea mTda2; 103 104 @Before setup()105 public void setup() { 106 mWms = mSystemServices.getWindowManagerService(); 107 mRoot = new SurfacelessDisplayAreaRoot(mWms); 108 mImeContainer = new DisplayArea.Tokens(mWms, ABOVE_TASKS, "ImeContainer"); 109 mDisplayContent = mock(DisplayContent.class); 110 doReturn(true).when(mDisplayContent).isTrusted(); 111 doReturn(DEFAULT_DISPLAY).when(mDisplayContent).getDisplayId(); 112 mDisplayContent.isDefaultDisplay = true; 113 mDefaultTaskDisplayArea = new TaskDisplayArea(mDisplayContent, mWms, "Tasks", 114 FEATURE_DEFAULT_TASK_CONTAINER); 115 mTaskDisplayAreaList = new ArrayList<>(); 116 mTaskDisplayAreaList.add(mDefaultTaskDisplayArea); 117 mGroupRoot1 = new SurfacelessDisplayAreaRoot(mWms, "group1", FEATURE_VENDOR_FIRST + 1); 118 mGroupRoot2 = new SurfacelessDisplayAreaRoot(mWms, "group2", FEATURE_VENDOR_FIRST + 2); 119 mTda1 = new TaskDisplayArea(mDisplayContent, mWms, "tda1", FEATURE_VENDOR_FIRST + 3); 120 mTda2 = new TaskDisplayArea(mDisplayContent, mWms, "tda2", FEATURE_VENDOR_FIRST + 4); 121 } 122 123 @Test testBuilder()124 public void testBuilder() { 125 final Feature foo; 126 final Feature bar; 127 DisplayAreaPolicyBuilder.HierarchyBuilder rootHierarchy = 128 new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot) 129 .addFeature(foo = new Feature.Builder(mPolicy, "Foo", 130 FEATURE_VENDOR_FIRST) 131 .upTo(TYPE_STATUS_BAR) 132 .and(TYPE_NAVIGATION_BAR) 133 .build()) 134 .addFeature(bar = new Feature.Builder(mPolicy, "Bar", 135 FEATURE_VENDOR_FIRST + 1) 136 .all() 137 .except(TYPE_STATUS_BAR) 138 .build()) 139 .setImeContainer(mImeContainer) 140 .setTaskDisplayAreas(mTaskDisplayAreaList); 141 DisplayAreaPolicyBuilder.Result policy = new DisplayAreaPolicyBuilder() 142 .setRootHierarchy(rootHierarchy) 143 .build(mWms); 144 145 assertThat(policy.getDisplayAreas(foo.getId())).isNotEmpty(); 146 assertThat(policy.getDisplayAreas(bar.getId())).isNotEmpty(); 147 148 Matcher<WindowContainer> fooDescendantMatcher = descendantOfOneOf( 149 policy.getDisplayAreas(foo.getId())); 150 Matcher<WindowContainer> barDescendantMatcher = descendantOfOneOf( 151 policy.getDisplayAreas(bar.getId())); 152 153 // There is a DA of TYPE_STATUS_BAR below foo, but not below bar 154 assertThat(fooDescendantMatcher.matches( 155 policy.findAreaForToken(tokenOfType(TYPE_STATUS_BAR)))).isTrue(); 156 assertThat(barDescendantMatcher.matches( 157 policy.findAreaForToken(tokenOfType(TYPE_STATUS_BAR)))).isFalse(); 158 159 // The TDA is below both foo and bar. 160 assertThat(fooDescendantMatcher.matches(mDefaultTaskDisplayArea)).isTrue(); 161 assertThat(barDescendantMatcher.matches(mDefaultTaskDisplayArea)).isTrue(); 162 163 // The IME is below both foo and bar. 164 assertThat(fooDescendantMatcher.matches(mImeContainer)).isTrue(); 165 assertThat(barDescendantMatcher.matches(mImeContainer)).isTrue(); 166 assertThat(policy.findAreaForToken(tokenOfType(TYPE_INPUT_METHOD))) 167 .isEqualTo(mImeContainer); 168 assertThat(policy.findAreaForToken(tokenOfType(TYPE_INPUT_METHOD_DIALOG))) 169 .isEqualTo(mImeContainer); 170 171 List<DisplayArea<?>> actualOrder = collectLeafAreas(mRoot); 172 Map<DisplayArea<?>, Set<Integer>> zSets = calculateZSets(policy, mImeContainer, 173 mDefaultTaskDisplayArea); 174 actualOrder = actualOrder.stream().filter(zSets::containsKey).collect(toList()); 175 176 Map<DisplayArea<?>, Integer> expectedByMinLayer = mapValues(zSets, 177 v -> v.stream().min(Integer::compareTo).get()); 178 Map<DisplayArea<?>, Integer> expectedByMaxLayer = mapValues(zSets, 179 v -> v.stream().max(Integer::compareTo).get()); 180 181 // Make sure the DAs' order is the same as their layer order. 182 assertMatchLayerOrder(actualOrder, expectedByMinLayer); 183 assertMatchLayerOrder(actualOrder, expectedByMaxLayer); 184 } 185 186 @Test testBuilder_defaultPolicy_hasOneHandedFeature()187 public void testBuilder_defaultPolicy_hasOneHandedFeature() { 188 final DisplayAreaPolicy.Provider defaultProvider = DisplayAreaPolicy.Provider.fromResources( 189 resourcesWithProvider("")); 190 final DisplayAreaPolicyBuilder.Result defaultPolicy = 191 (DisplayAreaPolicyBuilder.Result) defaultProvider.instantiate(mWms, mDisplayContent, 192 mRoot, mImeContainer); 193 if (mDisplayContent.isDefaultDisplay) { 194 final List<Feature> features = defaultPolicy.getFeatures(); 195 boolean hasOneHandedFeature = false; 196 for (Feature feature : features) { 197 hasOneHandedFeature |= feature.getId() == FEATURE_ONE_HANDED; 198 } 199 200 assertThat(hasOneHandedFeature).isTrue(); 201 } 202 } 203 204 @Test testBuilder_defaultPolicy_hasWindowedMagnificationFeature()205 public void testBuilder_defaultPolicy_hasWindowedMagnificationFeature() { 206 final DisplayAreaPolicy.Provider defaultProvider = DisplayAreaPolicy.Provider.fromResources( 207 resourcesWithProvider("")); 208 final DisplayAreaPolicyBuilder.Result defaultPolicy = 209 (DisplayAreaPolicyBuilder.Result) defaultProvider.instantiate(mWms, mDisplayContent, 210 mRoot, mImeContainer); 211 final List<Feature> features = defaultPolicy.getFeatures(); 212 boolean hasWindowedMagnificationFeature = false; 213 for (Feature feature : features) { 214 hasWindowedMagnificationFeature |= feature.getId() == FEATURE_WINDOWED_MAGNIFICATION; 215 } 216 217 assertThat(hasWindowedMagnificationFeature).isTrue(); 218 } 219 220 @Test testBuilder_defaultPolicy_hasFullscreenMagnificationFeature()221 public void testBuilder_defaultPolicy_hasFullscreenMagnificationFeature() { 222 final DisplayAreaPolicy.Provider defaultProvider = DisplayAreaPolicy.Provider.fromResources( 223 resourcesWithProvider("")); 224 final DisplayAreaPolicyBuilder.Result defaultPolicy = 225 (DisplayAreaPolicyBuilder.Result) defaultProvider.instantiate(mWms, mDisplayContent, 226 mRoot, mImeContainer); 227 final List<Feature> features = defaultPolicy.getFeatures(); 228 boolean hasFullscreenMagnificationFeature = false; 229 for (Feature feature : features) { 230 hasFullscreenMagnificationFeature |= 231 feature.getId() == FEATURE_FULLSCREEN_MAGNIFICATION; 232 } 233 234 assertThat(hasFullscreenMagnificationFeature).isTrue(); 235 } 236 237 @Test testBuilder_defaultPolicy_hasImePlaceholderFeature()238 public void testBuilder_defaultPolicy_hasImePlaceholderFeature() { 239 final DisplayAreaPolicy.Provider defaultProvider = DisplayAreaPolicy.Provider.fromResources( 240 resourcesWithProvider("")); 241 final DisplayAreaPolicyBuilder.Result defaultPolicy = 242 (DisplayAreaPolicyBuilder.Result) defaultProvider.instantiate(mWms, mDisplayContent, 243 mRoot, mImeContainer); 244 final List<Feature> features = defaultPolicy.getFeatures(); 245 boolean hasImePlaceholderFeature = false; 246 for (Feature feature : features) { 247 hasImePlaceholderFeature |= feature.getId() == FEATURE_IME_PLACEHOLDER; 248 } 249 250 assertThat(hasImePlaceholderFeature).isTrue(); 251 } 252 253 @Test testBuilder_createCustomizedDisplayAreaForFeature()254 public void testBuilder_createCustomizedDisplayAreaForFeature() { 255 final Feature dimmable; 256 final Feature other; 257 DisplayAreaPolicyBuilder.HierarchyBuilder rootHierarchy = 258 new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot) 259 .addFeature(dimmable = new Feature.Builder(mPolicy, "Dimmable", 260 FEATURE_VENDOR_FIRST) 261 .upTo(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY) 262 .except(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY) 263 .setNewDisplayAreaSupplier(DisplayArea.Dimmable::new) 264 .build()) 265 .addFeature(other = new Feature.Builder(mPolicy, "Other", 266 FEATURE_VENDOR_FIRST + 1) 267 .all() 268 .build()) 269 .setImeContainer(mImeContainer) 270 .setTaskDisplayAreas(mTaskDisplayAreaList); 271 DisplayAreaPolicyBuilder.Result policy = new DisplayAreaPolicyBuilder() 272 .setRootHierarchy(rootHierarchy) 273 .build(mWms); 274 275 List<DisplayArea<? extends WindowContainer>> dimmableDAs = 276 policy.getDisplayAreas(dimmable.getId()); 277 List<DisplayArea<? extends WindowContainer>> otherDAs = 278 policy.getDisplayAreas(other.getId()); 279 assertThat(dimmableDAs).hasSize(1); 280 assertThat(dimmableDAs.get(0)).isInstanceOf(DisplayArea.Dimmable.class); 281 for (DisplayArea otherDA : otherDAs) { 282 assertThat(otherDA).isNotInstanceOf(DisplayArea.Dimmable.class); 283 } 284 } 285 286 @Test testBuilder_singleRoot_validateSettings()287 public void testBuilder_singleRoot_validateSettings() { 288 final DisplayAreaPolicyBuilder builder = new DisplayAreaPolicyBuilder(); 289 290 // Root must be set. 291 assertThrows(IllegalStateException.class, () -> builder.build(mWms)); 292 293 // IME must be set. 294 builder.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot) 295 .setTaskDisplayAreas(mTaskDisplayAreaList)); 296 297 assertThrows(IllegalStateException.class, () -> builder.build(mWms)); 298 299 // Default TaskDisplayArea must be set. 300 builder.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot) 301 .setImeContainer(mImeContainer) 302 .setTaskDisplayAreas(Lists.newArrayList( 303 new TaskDisplayArea(mDisplayContent, mWms, "testTda", 304 FEATURE_VENDOR_FIRST + 1)))); 305 306 assertThrows(IllegalStateException.class, () -> builder.build(mWms)); 307 308 // No exception 309 builder.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot) 310 .setImeContainer(mImeContainer) 311 .setTaskDisplayAreas(mTaskDisplayAreaList)); 312 313 builder.build(mWms); 314 } 315 316 @Test testBuilder_displayAreaGroup_validateSettings()317 public void testBuilder_displayAreaGroup_validateSettings() { 318 final DisplayAreaPolicyBuilder builder1 = new DisplayAreaPolicyBuilder(); 319 320 // IME must be set to one of the roots. 321 builder1.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)); 322 builder1.addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder( 323 mGroupRoot1) 324 .setTaskDisplayAreas(mTaskDisplayAreaList)); 325 326 assertThrows(IllegalStateException.class, () -> builder1.build(mWms)); 327 328 // Default TaskDisplayArea must be set. 329 final DisplayAreaPolicyBuilder builder2 = new DisplayAreaPolicyBuilder(); 330 builder2.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)); 331 builder2.addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder( 332 mGroupRoot1) 333 .setImeContainer(mImeContainer) 334 .setTaskDisplayAreas(Lists.newArrayList(mTda1))); 335 336 assertThrows(IllegalStateException.class, () -> builder2.build(mWms)); 337 338 // Each DisplayAreaGroup must have at least one TaskDisplayArea. 339 final DisplayAreaPolicyBuilder builder3 = new DisplayAreaPolicyBuilder(); 340 builder3.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)); 341 builder3.addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder( 342 mGroupRoot1) 343 .setImeContainer(mImeContainer) 344 .setTaskDisplayAreas(mTaskDisplayAreaList)); 345 builder3.addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder( 346 mGroupRoot2)); 347 348 assertThrows(IllegalStateException.class, () -> builder3.build(mWms)); 349 350 // No exception 351 final DisplayAreaPolicyBuilder builder4 = new DisplayAreaPolicyBuilder(); 352 builder4.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)); 353 builder4.addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder( 354 mGroupRoot1) 355 .setImeContainer(mImeContainer) 356 .setTaskDisplayAreas(mTaskDisplayAreaList)); 357 builder4.addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder( 358 mGroupRoot2) 359 .setTaskDisplayAreas(Lists.newArrayList(mTda1))); 360 361 builder4.build(mWms); 362 } 363 364 @Test testBuilder_rootHasUniqueId()365 public void testBuilder_rootHasUniqueId() { 366 // Root must have different id from all roots. 367 final DisplayAreaPolicyBuilder builder1 = new DisplayAreaPolicyBuilder(); 368 builder1.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot) 369 .setImeContainer(mImeContainer) 370 .setTaskDisplayAreas(mTaskDisplayAreaList)); 371 final RootDisplayArea groupRoot1 = new SurfacelessDisplayAreaRoot(mWms, "group1", 372 mRoot.mFeatureId); 373 builder1.addDisplayAreaGroupHierarchy( 374 new DisplayAreaPolicyBuilder.HierarchyBuilder(groupRoot1) 375 .setTaskDisplayAreas(Lists.newArrayList(mTda1))); 376 377 assertThrows(IllegalStateException.class, () -> builder1.build(mWms)); 378 379 // Root must have different id from all TDAs. 380 final DisplayAreaPolicyBuilder builder2 = new DisplayAreaPolicyBuilder(); 381 builder2.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot) 382 .setImeContainer(mImeContainer) 383 .setTaskDisplayAreas(Lists.newArrayList( 384 mDefaultTaskDisplayArea, 385 new TaskDisplayArea(mDisplayContent, mWms, "testTda", 386 mRoot.mFeatureId)))); 387 388 assertThrows(IllegalStateException.class, () -> builder2.build(mWms)); 389 390 // Root must have different id from all features. 391 final DisplayAreaPolicyBuilder builder3 = new DisplayAreaPolicyBuilder(); 392 builder3.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot) 393 .setImeContainer(mImeContainer) 394 .setTaskDisplayAreas(mTaskDisplayAreaList) 395 .addFeature(new Feature.Builder(mPolicy, "testFeature", mRoot.mFeatureId) 396 .all() 397 .build())); 398 399 assertThrows(IllegalStateException.class, () -> builder3.build(mWms)); 400 } 401 402 @Test testBuilder_taskDisplayAreaHasUniqueId()403 public void testBuilder_taskDisplayAreaHasUniqueId() { 404 // TDA must have different id from all TDAs. 405 final DisplayAreaPolicyBuilder builder = new DisplayAreaPolicyBuilder(); 406 final List<TaskDisplayArea> tdaList = Lists.newArrayList( 407 mDefaultTaskDisplayArea, 408 mTda1, 409 new TaskDisplayArea(mDisplayContent, mWms, "tda2", mTda1.mFeatureId)); 410 builder.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot) 411 .setImeContainer(mImeContainer) 412 .setTaskDisplayAreas(tdaList)); 413 414 assertThrows(IllegalStateException.class, () -> builder.build(mWms)); 415 416 // TDA must have different id from all features. 417 final DisplayAreaPolicyBuilder builder2 = new DisplayAreaPolicyBuilder(); 418 builder2.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot) 419 .setImeContainer(mImeContainer) 420 .setTaskDisplayAreas(Lists.newArrayList( 421 mDefaultTaskDisplayArea, 422 mTda1)) 423 .addFeature(new Feature.Builder(mPolicy, "testFeature", mTda1.mFeatureId) 424 .all() 425 .build())); 426 427 assertThrows(IllegalStateException.class, () -> builder2.build(mWms)); 428 } 429 430 @Test testBuilder_featureHasUniqueId()431 public void testBuilder_featureHasUniqueId() { 432 // Feature must have different id from features below the same root. 433 final DisplayAreaPolicyBuilder builder = new DisplayAreaPolicyBuilder(); 434 builder.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot) 435 .setImeContainer(mImeContainer) 436 .setTaskDisplayAreas(mTaskDisplayAreaList) 437 .addFeature(new Feature.Builder(mPolicy, "feature1", FEATURE_VENDOR_FIRST + 10) 438 .all() 439 .build()) 440 .addFeature(new Feature.Builder(mPolicy, "feature2", FEATURE_VENDOR_FIRST + 10) 441 .upTo(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY) 442 .build())); 443 444 assertThrows(IllegalStateException.class, () -> builder.build(mWms)); 445 446 // Features below different root can have the same id. 447 final DisplayAreaPolicyBuilder builder2 = new DisplayAreaPolicyBuilder(); 448 builder2.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot) 449 .setImeContainer(mImeContainer) 450 .setTaskDisplayAreas(mTaskDisplayAreaList) 451 .addFeature(new Feature.Builder(mPolicy, "feature1", FEATURE_VENDOR_FIRST + 10) 452 .all() 453 .build())); 454 builder2.addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder( 455 mGroupRoot1) 456 .setTaskDisplayAreas(Lists.newArrayList(mTda1)) 457 .addFeature(new Feature.Builder(mPolicy, "feature2", FEATURE_VENDOR_FIRST + 10) 458 .all() 459 .build())); 460 461 builder2.build(mWms); 462 } 463 464 @Test testBuilder_idsNotGreaterThanFeatureVendorLast()465 public void testBuilder_idsNotGreaterThanFeatureVendorLast() { 466 // Root id should not be greater than FEATURE_VENDOR_LAST. 467 final DisplayAreaPolicyBuilder builder1 = new DisplayAreaPolicyBuilder(); 468 final RootDisplayArea root = new SurfacelessDisplayAreaRoot(mWms, "testRoot", 469 FEATURE_VENDOR_LAST + 1); 470 builder1.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(root) 471 .setImeContainer(mImeContainer) 472 .setTaskDisplayAreas(mTaskDisplayAreaList)); 473 474 assertThrows(IllegalStateException.class, () -> builder1.build(mWms)); 475 476 // TDA id should not be greater than FEATURE_VENDOR_LAST. 477 final DisplayAreaPolicyBuilder builder2 = new DisplayAreaPolicyBuilder(); 478 builder2.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(root) 479 .setImeContainer(mImeContainer) 480 .setTaskDisplayAreas(Lists.newArrayList( 481 mDefaultTaskDisplayArea, 482 new TaskDisplayArea(mDisplayContent, mWms, "testTda", 483 FEATURE_VENDOR_LAST + 1)))); 484 485 assertThrows(IllegalStateException.class, () -> builder2.build(mWms)); 486 487 // Feature id should not be greater than FEATURE_VENDOR_LAST. 488 final DisplayAreaPolicyBuilder builder3 = new DisplayAreaPolicyBuilder(); 489 builder3.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot) 490 .setImeContainer(mImeContainer) 491 .setTaskDisplayAreas(mTaskDisplayAreaList) 492 .addFeature(new Feature.Builder(mPolicy, "testFeature", FEATURE_VENDOR_LAST + 1) 493 .all() 494 .build())); 495 496 assertThrows(IllegalStateException.class, () -> builder3.build(mWms)); 497 } 498 499 @Test testBuilder_displayAreaGroup_attachDisplayAreas()500 public void testBuilder_displayAreaGroup_attachDisplayAreas() { 501 final DisplayAreaPolicyBuilder.Result policy = new DisplayAreaPolicyBuilder() 502 .setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot) 503 .setTaskDisplayAreas(mTaskDisplayAreaList)) 504 .addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder( 505 mGroupRoot1) 506 .setImeContainer(mImeContainer) 507 .setTaskDisplayAreas(Lists.newArrayList(mTda1))) 508 .addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder( 509 mGroupRoot2) 510 .setTaskDisplayAreas(Lists.newArrayList(mTda2))) 511 .build(mWms); 512 513 assertThat(mDefaultTaskDisplayArea.isDescendantOf(mRoot)).isTrue(); 514 assertThat(mGroupRoot1.isDescendantOf(mRoot)).isTrue(); 515 assertThat(mGroupRoot2.isDescendantOf(mRoot)).isTrue(); 516 assertThat(mImeContainer.isDescendantOf(mGroupRoot1)).isTrue(); 517 assertThat(mTda1.isDescendantOf(mGroupRoot1)).isTrue(); 518 assertThat(mTda2.isDescendantOf(mGroupRoot2)).isTrue(); 519 assertThat(isSibling(mDefaultTaskDisplayArea, mGroupRoot1)).isTrue(); 520 assertThat(isSibling(mDefaultTaskDisplayArea, mGroupRoot2)).isTrue(); 521 } 522 523 @Test testBuilder_displayAreaGroup_createFeatureOnGroup()524 public void testBuilder_displayAreaGroup_createFeatureOnGroup() { 525 final Feature feature1 = new Feature.Builder(mWms.mPolicy, "feature1", 526 FEATURE_VENDOR_FIRST + 5) 527 .all() 528 .except(TYPE_STATUS_BAR) 529 .build(); 530 final Feature feature2 = new Feature.Builder(mWms.mPolicy, "feature2", 531 FEATURE_VENDOR_FIRST + 6) 532 .upTo(TYPE_STATUS_BAR) 533 .and(TYPE_NAVIGATION_BAR) 534 .build(); 535 final DisplayAreaPolicyBuilder.Result policy = new DisplayAreaPolicyBuilder() 536 .setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot) 537 .setTaskDisplayAreas(mTaskDisplayAreaList)) 538 .addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder( 539 mGroupRoot1) 540 .setImeContainer(mImeContainer) 541 .setTaskDisplayAreas(Lists.newArrayList(mTda1)) 542 .addFeature(feature1)) 543 .addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder( 544 mGroupRoot2) 545 .setTaskDisplayAreas(Lists.newArrayList(mTda2)) 546 .addFeature(feature2)) 547 .build(mWms); 548 549 List<DisplayArea<? extends WindowContainer>> feature1DAs = 550 policy.getDisplayAreas(feature1.getId()); 551 List<DisplayArea<? extends WindowContainer>> feature2DAs = 552 policy.getDisplayAreas(feature2.getId()); 553 for (DisplayArea<? extends WindowContainer> da : feature1DAs) { 554 assertThat(da.isDescendantOf(mGroupRoot1)).isTrue(); 555 } 556 for (DisplayArea<? extends WindowContainer> da : feature2DAs) { 557 assertThat(da.isDescendantOf(mGroupRoot2)).isTrue(); 558 } 559 } 560 561 @Test testBuilder_addWindow_selectContainerForWindowFunc_defaultFunc()562 public void testBuilder_addWindow_selectContainerForWindowFunc_defaultFunc() { 563 final DisplayAreaPolicyBuilder.Result policy = new DisplayAreaPolicyBuilder() 564 .setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot) 565 .setTaskDisplayAreas(mTaskDisplayAreaList)) 566 .addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder( 567 mGroupRoot1) 568 .setImeContainer(mImeContainer) 569 .setTaskDisplayAreas(Lists.newArrayList(mTda1))) 570 .addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder( 571 mGroupRoot2) 572 .setTaskDisplayAreas(Lists.newArrayList(mTda2))) 573 .build(mWms); 574 575 final WindowToken token = new WindowToken.Builder(mWms, mock(IBinder.class), 576 TYPE_STATUS_BAR) 577 .setDisplayContent(mDisplayContent) 578 .setPersistOnEmpty(true) 579 .setOwnerCanManageAppTokens(true) 580 .build(); 581 582 policy.addWindow(token); 583 584 // By default, window are always added to the root. 585 assertThat(token.isDescendantOf(mRoot)).isTrue(); 586 assertThat(token.isDescendantOf(mGroupRoot1)).isFalse(); 587 assertThat(token.isDescendantOf(mGroupRoot2)).isFalse(); 588 589 // When the window has options for target root id, attach it to the target root. 590 final Bundle options = new Bundle(); 591 options.putInt(KEY_ROOT_DISPLAY_AREA_ID, mGroupRoot2.mFeatureId); 592 final WindowToken token2 = new WindowToken.Builder(mWms, mock(IBinder.class), 593 TYPE_STATUS_BAR) 594 .setDisplayContent(mDisplayContent) 595 .setPersistOnEmpty(true) 596 .setOwnerCanManageAppTokens(true) 597 .setOptions(options) 598 .build(); 599 policy.addWindow(token2); 600 601 assertThat(token2.isDescendantOf(mGroupRoot2)).isTrue(); 602 } 603 604 @Test testBuilder_addWindow_selectContainerForWindowFunc_selectBasedOnType()605 public void testBuilder_addWindow_selectContainerForWindowFunc_selectBasedOnType() { 606 final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy1 = 607 new DisplayAreaPolicyBuilder.HierarchyBuilder(mGroupRoot1) 608 .setImeContainer(mImeContainer) 609 .setTaskDisplayAreas(Lists.newArrayList(mTda1)); 610 final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy2 = 611 new DisplayAreaPolicyBuilder.HierarchyBuilder(mGroupRoot2) 612 .setTaskDisplayAreas(Lists.newArrayList(mTda2)); 613 final DisplayAreaPolicyBuilder.Result policy = new DisplayAreaPolicyBuilder() 614 .setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot) 615 .setTaskDisplayAreas(mTaskDisplayAreaList)) 616 .addDisplayAreaGroupHierarchy(hierarchy1) 617 .addDisplayAreaGroupHierarchy(hierarchy2) 618 .setSelectRootForWindowFunc((type, options) -> { 619 if (type == TYPE_STATUS_BAR) { 620 return mGroupRoot1; 621 } 622 return mGroupRoot2; 623 }) 624 .build(mWms); 625 626 final WindowToken token1 = new WindowToken.Builder(mWms, mock(IBinder.class), 627 TYPE_STATUS_BAR) 628 .setDisplayContent(mDisplayContent) 629 .setPersistOnEmpty(true) 630 .setOwnerCanManageAppTokens(true) 631 .build(); 632 final WindowToken token2 = new WindowToken.Builder(mWms, mock(IBinder.class), 633 TYPE_WALLPAPER) 634 .setDisplayContent(mDisplayContent) 635 .setPersistOnEmpty(true) 636 .setOwnerCanManageAppTokens(true) 637 .build(); 638 policy.addWindow(token1); 639 policy.addWindow(token2); 640 641 assertThat(token1.isDescendantOf(mGroupRoot1)).isTrue(); 642 assertThat(token2.isDescendantOf(mGroupRoot2)).isTrue(); 643 } 644 645 @Test testBuilder_addWindow_selectContainerForWindowFunc_selectBasedOnOptions()646 public void testBuilder_addWindow_selectContainerForWindowFunc_selectBasedOnOptions() { 647 final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy0 = 648 new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot) 649 .setTaskDisplayAreas(mTaskDisplayAreaList); 650 final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy1 = 651 new DisplayAreaPolicyBuilder.HierarchyBuilder( 652 mGroupRoot1) 653 .setImeContainer(mImeContainer) 654 .setTaskDisplayAreas(Lists.newArrayList(mTda1)); 655 final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy2 = 656 new DisplayAreaPolicyBuilder.HierarchyBuilder( 657 mGroupRoot2) 658 .setTaskDisplayAreas(Lists.newArrayList(mTda2)); 659 final DisplayAreaPolicyBuilder.Result policy = new DisplayAreaPolicyBuilder() 660 .setRootHierarchy(hierarchy0) 661 .addDisplayAreaGroupHierarchy(hierarchy1) 662 .addDisplayAreaGroupHierarchy(hierarchy2) 663 .setSelectRootForWindowFunc((token, options) -> { 664 if (options == null) { 665 return mRoot; 666 } 667 if (options.getInt("HIERARCHY_ROOT_ID") == mGroupRoot1.mFeatureId) { 668 return mGroupRoot1; 669 } 670 if (options.getInt("HIERARCHY_ROOT_ID") == mGroupRoot2.mFeatureId) { 671 return mGroupRoot2; 672 } 673 return mRoot; 674 }) 675 .build(mWms); 676 677 final Bundle options1 = new Bundle(); 678 options1.putInt("HIERARCHY_ROOT_ID", mGroupRoot1.mFeatureId); 679 final Bundle options2 = new Bundle(); 680 options2.putInt("HIERARCHY_ROOT_ID", mGroupRoot2.mFeatureId); 681 final WindowToken token0 = new WindowToken.Builder(mWms, mock(IBinder.class), 682 TYPE_STATUS_BAR) 683 .setDisplayContent(mDisplayContent) 684 .setPersistOnEmpty(true) 685 .setOwnerCanManageAppTokens(true) 686 .build(); 687 final WindowToken token1 = new WindowToken.Builder(mWms, mock(IBinder.class), 688 TYPE_STATUS_BAR) 689 .setDisplayContent(mDisplayContent) 690 .setPersistOnEmpty(true) 691 .setOwnerCanManageAppTokens(true) 692 .setOptions(options1) 693 .build(); 694 final WindowToken token2 = new WindowToken.Builder(mWms, mock(IBinder.class), 695 TYPE_STATUS_BAR) 696 .setDisplayContent(mDisplayContent) 697 .setPersistOnEmpty(true) 698 .setOwnerCanManageAppTokens(true) 699 .setOptions(options2) 700 .build(); 701 702 policy.addWindow(token0); 703 policy.addWindow(token1); 704 policy.addWindow(token2); 705 706 assertThat(token0.isDescendantOf(mRoot)).isTrue(); 707 assertThat(token1.isDescendantOf(mGroupRoot1)).isTrue(); 708 assertThat(token2.isDescendantOf(mGroupRoot2)).isTrue(); 709 } 710 711 @Test testFeatureNotThrowArrayIndexOutOfBoundsException()712 public void testFeatureNotThrowArrayIndexOutOfBoundsException() { 713 final Feature feature1 = new Feature.Builder(mWms.mPolicy, "feature1", 714 FEATURE_VENDOR_FIRST + 5) 715 .all() 716 .except(TYPE_POINTER) 717 .build(); 718 } 719 720 @Test testGetTaskDisplayArea_DefaultFunction_NullOptions_ReturnsDefaultTda()721 public void testGetTaskDisplayArea_DefaultFunction_NullOptions_ReturnsDefaultTda() { 722 final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy0 = 723 new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot) 724 .setTaskDisplayAreas(mTaskDisplayAreaList); 725 final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy1 = 726 new DisplayAreaPolicyBuilder.HierarchyBuilder(mGroupRoot1) 727 .setImeContainer(mImeContainer) 728 .setTaskDisplayAreas(Lists.newArrayList(mTda1)); 729 final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy2 = 730 new DisplayAreaPolicyBuilder.HierarchyBuilder(mGroupRoot2) 731 .setTaskDisplayAreas(Lists.newArrayList(mTda2)); 732 final DisplayAreaPolicyBuilder.Result policy = new DisplayAreaPolicyBuilder() 733 .setRootHierarchy(hierarchy0) 734 .addDisplayAreaGroupHierarchy(hierarchy1) 735 .addDisplayAreaGroupHierarchy(hierarchy2) 736 .build(mWms); 737 738 final TaskDisplayArea tda = policy.getTaskDisplayArea(null /* options */); 739 740 assertThat(tda).isEqualTo(mDefaultTaskDisplayArea); 741 assertThat(tda).isEqualTo(policy.getDefaultTaskDisplayArea()); 742 } 743 744 @Test testGetTaskDisplayArea_DefaultFunction_NotContainsLunchedTda_ReturnsDefaultTda()745 public void testGetTaskDisplayArea_DefaultFunction_NotContainsLunchedTda_ReturnsDefaultTda() { 746 final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy0 = 747 new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot) 748 .setTaskDisplayAreas(mTaskDisplayAreaList); 749 final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy1 = 750 new DisplayAreaPolicyBuilder.HierarchyBuilder(mGroupRoot1) 751 .setImeContainer(mImeContainer) 752 .setTaskDisplayAreas(Lists.newArrayList(mTda1)); 753 final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy2 = 754 new DisplayAreaPolicyBuilder.HierarchyBuilder(mGroupRoot2) 755 .setTaskDisplayAreas(Lists.newArrayList(mTda2)); 756 final DisplayAreaPolicyBuilder.Result policy = new DisplayAreaPolicyBuilder() 757 .setRootHierarchy(hierarchy0) 758 .addDisplayAreaGroupHierarchy(hierarchy1) 759 .addDisplayAreaGroupHierarchy(hierarchy2) 760 .build(mWms); 761 762 final TaskDisplayArea tda = policy.getTaskDisplayArea(new Bundle()); 763 764 assertThat(tda).isEqualTo(mDefaultTaskDisplayArea); 765 assertThat(tda).isEqualTo(policy.getDefaultTaskDisplayArea()); 766 } 767 768 @Test testGetTaskDisplayArea_DefaultFunction_InvalidTdaToken_ReturnsDefaultTda()769 public void testGetTaskDisplayArea_DefaultFunction_InvalidTdaToken_ReturnsDefaultTda() { 770 final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy0 = 771 new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot) 772 .setTaskDisplayAreas(mTaskDisplayAreaList); 773 final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy1 = 774 new DisplayAreaPolicyBuilder.HierarchyBuilder(mGroupRoot1) 775 .setImeContainer(mImeContainer) 776 .setTaskDisplayAreas(Lists.newArrayList(mTda1)); 777 final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy2 = 778 new DisplayAreaPolicyBuilder.HierarchyBuilder(mGroupRoot2) 779 .setTaskDisplayAreas(Lists.newArrayList(mTda2)); 780 final DisplayAreaPolicyBuilder.Result policy = new DisplayAreaPolicyBuilder() 781 .setRootHierarchy(hierarchy0) 782 .addDisplayAreaGroupHierarchy(hierarchy1) 783 .addDisplayAreaGroupHierarchy(hierarchy2) 784 .build(mWms); 785 final ActivityOptions options = ActivityOptions.makeBasic(); 786 final WindowContainerToken fakeToken = mRoot.mRemoteToken.toWindowContainerToken(); 787 options.setLaunchTaskDisplayArea(fakeToken); 788 789 final TaskDisplayArea tda = policy.getTaskDisplayArea(options.toBundle()); 790 791 assertThat(tda).isEqualTo(mDefaultTaskDisplayArea); 792 assertThat(tda).isEqualTo(policy.getDefaultTaskDisplayArea()); 793 } 794 795 @Test(expected = IllegalArgumentException.class) testGetTaskDisplayArea_DefaultFunction_TdaOnDifferentDisplay_ThrowException()796 public void testGetTaskDisplayArea_DefaultFunction_TdaOnDifferentDisplay_ThrowException() { 797 final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy0 = 798 new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot) 799 .setTaskDisplayAreas(mTaskDisplayAreaList); 800 final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy1 = 801 new DisplayAreaPolicyBuilder.HierarchyBuilder(mGroupRoot1) 802 .setImeContainer(mImeContainer) 803 .setTaskDisplayAreas(Lists.newArrayList(mTda1)); 804 final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy2 = 805 new DisplayAreaPolicyBuilder.HierarchyBuilder(mGroupRoot2) 806 .setTaskDisplayAreas(Lists.newArrayList(mTda2)); 807 final DisplayAreaPolicyBuilder.Result policy = new DisplayAreaPolicyBuilder() 808 .setRootHierarchy(hierarchy0) 809 .addDisplayAreaGroupHierarchy(hierarchy1) 810 .addDisplayAreaGroupHierarchy(hierarchy2) 811 .build(mWms); 812 final TaskDisplayArea tdaOnSecondaryDisplay = mock(TaskDisplayArea.class); 813 doReturn(DEFAULT_DISPLAY + 1).when(tdaOnSecondaryDisplay).getDisplayId(); 814 doReturn(tdaOnSecondaryDisplay).when(tdaOnSecondaryDisplay).asTaskDisplayArea(); 815 tdaOnSecondaryDisplay.mRemoteToken = new WindowContainer.RemoteToken(tdaOnSecondaryDisplay); 816 817 final WindowContainerToken tdaToken = tdaOnSecondaryDisplay.mRemoteToken 818 .toWindowContainerToken(); 819 final ActivityOptions options = ActivityOptions.makeBasic(); 820 options.setLaunchTaskDisplayArea(tdaToken); 821 final TaskDisplayArea tda = policy.getTaskDisplayArea(options.toBundle()); 822 823 assertThat(tda).isEqualTo(mDefaultTaskDisplayArea); 824 assertThat(tda).isEqualTo(policy.getDefaultTaskDisplayArea()); 825 } 826 827 @Test testGetTaskDisplayArea_DefaultFunction_ContainsTdaToken_ReturnsTda()828 public void testGetTaskDisplayArea_DefaultFunction_ContainsTdaToken_ReturnsTda() { 829 final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy0 = 830 new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot) 831 .setTaskDisplayAreas(mTaskDisplayAreaList); 832 final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy1 = 833 new DisplayAreaPolicyBuilder.HierarchyBuilder(mGroupRoot1) 834 .setImeContainer(mImeContainer) 835 .setTaskDisplayAreas(Lists.newArrayList(mTda1)); 836 final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy2 = 837 new DisplayAreaPolicyBuilder.HierarchyBuilder(mGroupRoot2) 838 .setTaskDisplayAreas(Lists.newArrayList(mTda2)); 839 final DisplayAreaPolicyBuilder.Result policy = new DisplayAreaPolicyBuilder() 840 .setRootHierarchy(hierarchy0) 841 .addDisplayAreaGroupHierarchy(hierarchy1) 842 .addDisplayAreaGroupHierarchy(hierarchy2) 843 .build(mWms); 844 final ActivityOptions options = ActivityOptions.makeBasic(); 845 846 final WindowContainerToken defaultTdaToken = mDefaultTaskDisplayArea.mRemoteToken 847 .toWindowContainerToken(); 848 options.setLaunchTaskDisplayArea(defaultTdaToken); 849 TaskDisplayArea tda = policy.getTaskDisplayArea(options.toBundle()); 850 851 assertThat(tda).isEqualTo(mDefaultTaskDisplayArea); 852 assertThat(tda).isEqualTo(policy.getDefaultTaskDisplayArea()); 853 854 final WindowContainerToken tda1Token = mTda1.mRemoteToken.toWindowContainerToken(); 855 options.setLaunchTaskDisplayArea(tda1Token); 856 tda = policy.getTaskDisplayArea(options.toBundle()); 857 858 assertThat(tda).isEqualTo(mTda1); 859 860 final WindowContainerToken tda2Token = mTda2.mRemoteToken.toWindowContainerToken(); 861 options.setLaunchTaskDisplayArea(tda2Token); 862 tda = policy.getTaskDisplayArea(options.toBundle()); 863 864 assertThat(tda).isEqualTo(mTda2); 865 } 866 867 @Test testBuilder_getTaskDisplayArea_setSelectTaskDisplayAreaFunc()868 public void testBuilder_getTaskDisplayArea_setSelectTaskDisplayAreaFunc() { 869 final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy0 = 870 new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot) 871 .setTaskDisplayAreas(mTaskDisplayAreaList); 872 final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy1 = 873 new DisplayAreaPolicyBuilder.HierarchyBuilder(mGroupRoot1) 874 .setImeContainer(mImeContainer) 875 .setTaskDisplayAreas(Lists.newArrayList(mTda1)); 876 final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy2 = 877 new DisplayAreaPolicyBuilder.HierarchyBuilder(mGroupRoot2) 878 .setTaskDisplayAreas(Lists.newArrayList(mTda2)); 879 final DisplayAreaPolicyBuilder.Result policy = new DisplayAreaPolicyBuilder() 880 .setRootHierarchy(hierarchy0) 881 .setSelectTaskDisplayAreaFunc((options) -> { 882 if (options == null) { 883 return mDefaultTaskDisplayArea; 884 } 885 final int tdaFeatureId = 886 options.getInt(KEY_LAUNCH_TASK_DISPLAY_AREA_FEATURE_ID); 887 if (tdaFeatureId == mTda1.mFeatureId) { 888 return mTda1; 889 } 890 if (tdaFeatureId == mTda2.mFeatureId) { 891 return mTda2; 892 } 893 return mDefaultTaskDisplayArea; 894 }) 895 .addDisplayAreaGroupHierarchy(hierarchy1) 896 .addDisplayAreaGroupHierarchy(hierarchy2) 897 .build(mWms); 898 899 TaskDisplayArea tda = policy.getTaskDisplayArea(null /* options */); 900 901 assertThat(tda).isEqualTo(mDefaultTaskDisplayArea); 902 assertThat(tda).isEqualTo(policy.getDefaultTaskDisplayArea()); 903 904 final Bundle options = new Bundle(); 905 options.putInt(KEY_LAUNCH_TASK_DISPLAY_AREA_FEATURE_ID, -1); 906 tda = policy.getTaskDisplayArea(options); 907 assertThat(tda).isEqualTo(mDefaultTaskDisplayArea); 908 909 options.putInt(KEY_LAUNCH_TASK_DISPLAY_AREA_FEATURE_ID, mDefaultTaskDisplayArea.mFeatureId); 910 tda = policy.getTaskDisplayArea(options); 911 assertThat(tda).isEqualTo(mDefaultTaskDisplayArea); 912 913 options.putInt(KEY_LAUNCH_TASK_DISPLAY_AREA_FEATURE_ID, mTda1.mFeatureId); 914 tda = policy.getTaskDisplayArea(options); 915 assertThat(tda).isEqualTo(mTda1); 916 917 options.putInt(KEY_LAUNCH_TASK_DISPLAY_AREA_FEATURE_ID, mTda2.mFeatureId); 918 tda = policy.getTaskDisplayArea(options); 919 assertThat(tda).isEqualTo(mTda2); 920 } 921 resourcesWithProvider(String provider)922 private static Resources resourcesWithProvider(String provider) { 923 Resources mock = mock(Resources.class); 924 when(mock.getString( 925 com.android.internal.R.string.config_deviceSpecificDisplayAreaPolicyProvider)) 926 .thenReturn(provider); 927 return mock; 928 } 929 mapValues(Map<K, V> zSets, Function<V, R> f)930 private <K, V, R> Map<K, R> mapValues(Map<K, V> zSets, Function<V, R> f) { 931 return zSets.entrySet().stream().collect(Collectors.toMap( 932 Map.Entry::getKey, 933 e -> f.apply(e.getValue()))); 934 } 935 collectLeafAreas(DisplayArea<?> root)936 private List<DisplayArea<?>> collectLeafAreas(DisplayArea<?> root) { 937 ArrayList<DisplayArea<?>> leafs = new ArrayList<>(); 938 traverseLeafAreas(root, leafs::add); 939 return leafs; 940 } 941 calculateZSets( DisplayAreaPolicyBuilder.Result policy, DisplayArea.Tokens ime, TaskDisplayArea taskDisplayArea)942 private Map<DisplayArea<?>, Set<Integer>> calculateZSets( 943 DisplayAreaPolicyBuilder.Result policy, 944 DisplayArea.Tokens ime, 945 TaskDisplayArea taskDisplayArea) { 946 Map<DisplayArea<?>, Set<Integer>> zSets = new HashMap<>(); 947 int[] types = {TYPE_STATUS_BAR, TYPE_NAVIGATION_BAR, TYPE_PRESENTATION, 948 TYPE_APPLICATION_OVERLAY}; 949 for (int type : types) { 950 WindowToken token = tokenOfType(type); 951 recordLayer(policy.findAreaForToken(token), token.getWindowLayerFromType(), zSets); 952 } 953 recordLayer(taskDisplayArea, APPLICATION_LAYER, zSets); 954 recordLayer(ime, mPolicy.getWindowLayerFromTypeLw(TYPE_INPUT_METHOD), zSets); 955 return zSets; 956 } 957 recordLayer(DisplayArea<?> area, int layer, Map<DisplayArea<?>, Set<Integer>> zSets)958 private void recordLayer(DisplayArea<?> area, int layer, 959 Map<DisplayArea<?>, Set<Integer>> zSets) { 960 zSets.computeIfAbsent(area, k -> new HashSet<>()).add(layer); 961 } 962 descendantOfOneOf(List<? extends WindowContainer> expected)963 private Matcher<WindowContainer> descendantOfOneOf(List<? extends WindowContainer> expected) { 964 return new CustomTypeSafeMatcher<WindowContainer>("descendant of one of " + expected) { 965 @Override 966 protected boolean matchesSafely(WindowContainer actual) { 967 for (WindowContainer expected : expected) { 968 WindowContainer candidate = actual; 969 while (candidate != null && candidate.getParent() != candidate) { 970 if (candidate.getParent() == expected) { 971 return true; 972 } 973 candidate = candidate.getParent(); 974 } 975 } 976 return false; 977 } 978 979 @Override 980 protected void describeMismatchSafely(WindowContainer item, 981 Description description) { 982 description.appendText("was ").appendValue(item); 983 while (item != null && item.getParent() != item) { 984 item = item.getParent(); 985 description.appendText(", child of ").appendValue(item); 986 } 987 } 988 }; 989 } 990 991 private boolean isSibling(WindowContainer da1, WindowContainer da2) { 992 return da1.getParent() != null && da1.getParent() == da2.getParent(); 993 } 994 995 private WindowToken tokenOfType(int type) { 996 return new WindowToken.Builder(mWms, new Binder(), type) 997 .setDisplayContent(mDisplayContent).build(); 998 } 999 1000 private static void assertMatchLayerOrder(List<DisplayArea<?>> actualOrder, 1001 Map<DisplayArea<?>, Integer> areaToLayerMap) { 1002 for (int i = 0; i < actualOrder.size() - 1; i++) { 1003 DisplayArea<?> curr = actualOrder.get(i); 1004 DisplayArea<?> next = actualOrder.get(i + 1); 1005 assertThat(areaToLayerMap.get(curr)).isLessThan(areaToLayerMap.get(next)); 1006 } 1007 } 1008 1009 private static void traverseLeafAreas(DisplayArea<?> root, Consumer<DisplayArea<?>> consumer) { 1010 boolean leaf = true; 1011 for (int i = 0; i < root.getChildCount(); i++) { 1012 WindowContainer child = root.getChildAt(i); 1013 if (child instanceof DisplayArea<?>) { 1014 traverseLeafAreas((DisplayArea<?>) child, consumer); 1015 leaf = false; 1016 } 1017 } 1018 if (leaf) { 1019 consumer.accept(root); 1020 } 1021 } 1022 1023 static class SurfacelessDisplayAreaRoot extends RootDisplayArea { 1024 1025 SurfacelessDisplayAreaRoot(WindowManagerService wms) { 1026 this(wms, "SurfacelessDisplayAreaRoot", FEATURE_ROOT); 1027 } 1028 1029 SurfacelessDisplayAreaRoot(WindowManagerService wms, String name, int featureId) { 1030 super(wms, name, featureId); 1031 } 1032 1033 @Override 1034 SurfaceControl.Builder makeChildSurface(WindowContainer child) { 1035 return new MockSurfaceControlBuilder(); 1036 } 1037 } 1038 1039 } 1040