1 /* 2 * Copyright (C) 2016 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 org.junit.Test; 20 import org.junit.runner.RunWith; 21 22 import android.content.res.Configuration; 23 import android.platform.test.annotations.Presubmit; 24 import android.support.test.filters.SmallTest; 25 import android.support.test.runner.AndroidJUnit4; 26 27 import java.util.Comparator; 28 29 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND; 30 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; 31 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; 32 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE; 33 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT; 34 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; 35 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; 36 37 import static com.android.server.wm.WindowContainer.POSITION_BOTTOM; 38 import static com.android.server.wm.WindowContainer.POSITION_TOP; 39 40 import static org.junit.Assert.assertEquals; 41 import static org.junit.Assert.assertFalse; 42 import static org.junit.Assert.assertNotNull; 43 import static org.junit.Assert.assertNull; 44 import static org.junit.Assert.assertTrue; 45 46 /** 47 * Test class for {@link WindowContainer}. 48 * 49 * Build/Install/Run: 50 * bit FrameworksServicesTests:com.android.server.wm.WindowContainerTests 51 */ 52 @SmallTest 53 @Presubmit 54 @RunWith(AndroidJUnit4.class) 55 public class WindowContainerTests extends WindowTestsBase { 56 57 @Test 58 public void testCreation() throws Exception { 59 final TestWindowContainer w = new TestWindowContainerBuilder().setLayer(0).build(); 60 assertNull("window must have no parent", w.getParentWindow()); 61 assertEquals("window must have no children", 0, w.getChildrenCount()); 62 } 63 64 @Test 65 public void testAdd() throws Exception { 66 final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(); 67 final TestWindowContainer root = builder.setLayer(0).build(); 68 69 final TestWindowContainer layer1 = root.addChildWindow(builder.setLayer(1)); 70 final TestWindowContainer secondLayer1 = root.addChildWindow(builder.setLayer(1)); 71 final TestWindowContainer layer2 = root.addChildWindow(builder.setLayer(2)); 72 final TestWindowContainer layerNeg1 = root.addChildWindow(builder.setLayer(-1)); 73 final TestWindowContainer layerNeg2 = root.addChildWindow(builder.setLayer(-2)); 74 final TestWindowContainer secondLayerNeg1 = root.addChildWindow(builder.setLayer(-1)); 75 final TestWindowContainer layer0 = root.addChildWindow(builder.setLayer(0)); 76 77 assertEquals(7, root.getChildrenCount()); 78 79 assertEquals(root, layer1.getParentWindow()); 80 assertEquals(root, secondLayer1.getParentWindow()); 81 assertEquals(root, layer2.getParentWindow()); 82 assertEquals(root, layerNeg1.getParentWindow()); 83 assertEquals(root, layerNeg2.getParentWindow()); 84 assertEquals(root, secondLayerNeg1.getParentWindow()); 85 assertEquals(root, layer0.getParentWindow()); 86 87 assertEquals(layerNeg2, root.getChildAt(0)); 88 assertEquals(secondLayerNeg1, root.getChildAt(1)); 89 assertEquals(layerNeg1, root.getChildAt(2)); 90 assertEquals(layer0, root.getChildAt(3)); 91 assertEquals(layer1, root.getChildAt(4)); 92 assertEquals(secondLayer1, root.getChildAt(5)); 93 assertEquals(layer2, root.getChildAt(6)); 94 95 assertTrue(layer1.mOnParentSetCalled); 96 assertTrue(secondLayer1.mOnParentSetCalled); 97 assertTrue(layer2.mOnParentSetCalled); 98 assertTrue(layerNeg1.mOnParentSetCalled); 99 assertTrue(layerNeg2.mOnParentSetCalled); 100 assertTrue(secondLayerNeg1.mOnParentSetCalled); 101 assertTrue(layer0.mOnParentSetCalled); 102 } 103 104 @Test 105 public void testAdd_AlreadyHasParent() throws Exception { 106 final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(); 107 final TestWindowContainer root = builder.setLayer(0).build(); 108 109 final TestWindowContainer child1 = root.addChildWindow(); 110 final TestWindowContainer child2 = root.addChildWindow(); 111 112 boolean gotException = false; 113 try { 114 child1.addChildWindow(child2); 115 } catch (IllegalArgumentException e) { 116 gotException = true; 117 } 118 assertTrue(gotException); 119 120 gotException = false; 121 try { 122 root.addChildWindow(child2); 123 } catch (IllegalArgumentException e) { 124 gotException = true; 125 } 126 assertTrue(gotException); 127 } 128 129 @Test 130 public void testHasChild() throws Exception { 131 final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(); 132 final TestWindowContainer root = builder.setLayer(0).build(); 133 134 final TestWindowContainer child1 = root.addChildWindow(); 135 final TestWindowContainer child2 = root.addChildWindow(); 136 final TestWindowContainer child11 = child1.addChildWindow(); 137 final TestWindowContainer child12 = child1.addChildWindow(); 138 final TestWindowContainer child21 = child2.addChildWindow(); 139 140 assertEquals(2, root.getChildrenCount()); 141 assertEquals(2, child1.getChildrenCount()); 142 assertEquals(1, child2.getChildrenCount()); 143 144 assertTrue(root.hasChild(child1)); 145 assertTrue(root.hasChild(child2)); 146 assertTrue(root.hasChild(child11)); 147 assertTrue(root.hasChild(child12)); 148 assertTrue(root.hasChild(child21)); 149 150 assertTrue(child1.hasChild(child11)); 151 assertTrue(child1.hasChild(child12)); 152 assertFalse(child1.hasChild(child21)); 153 154 assertTrue(child2.hasChild(child21)); 155 assertFalse(child2.hasChild(child11)); 156 assertFalse(child2.hasChild(child12)); 157 } 158 159 @Test 160 public void testRemoveImmediately() throws Exception { 161 final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(); 162 final TestWindowContainer root = builder.setLayer(0).build(); 163 164 final TestWindowContainer child1 = root.addChildWindow(); 165 final TestWindowContainer child2 = root.addChildWindow(); 166 final TestWindowContainer child11 = child1.addChildWindow(); 167 final TestWindowContainer child12 = child1.addChildWindow(); 168 final TestWindowContainer child21 = child2.addChildWindow(); 169 170 assertNotNull(child12.getParentWindow()); 171 child12.removeImmediately(); 172 assertNull(child12.getParentWindow()); 173 assertEquals(1, child1.getChildrenCount()); 174 assertFalse(child1.hasChild(child12)); 175 assertFalse(root.hasChild(child12)); 176 177 assertTrue(root.hasChild(child2)); 178 assertNotNull(child2.getParentWindow()); 179 child2.removeImmediately(); 180 assertNull(child2.getParentWindow()); 181 assertNull(child21.getParentWindow()); 182 assertEquals(0, child2.getChildrenCount()); 183 assertEquals(1, root.getChildrenCount()); 184 assertFalse(root.hasChild(child2)); 185 assertFalse(root.hasChild(child21)); 186 187 assertTrue(root.hasChild(child1)); 188 assertTrue(root.hasChild(child11)); 189 190 root.removeImmediately(); 191 assertEquals(0, root.getChildrenCount()); 192 } 193 194 @Test 195 public void testRemoveImmediately_WithController() throws Exception { 196 final WindowContainer container = new WindowContainer(); 197 final WindowContainerController controller = new WindowContainerController(null, sWm); 198 199 container.setController(controller); 200 assertEquals(controller, container.getController()); 201 assertEquals(container, controller.mContainer); 202 203 container.removeImmediately(); 204 assertNull(container.getController()); 205 assertNull(controller.mContainer); 206 } 207 208 @Test 209 public void testSetController() throws Exception { 210 final WindowContainerController controller = new WindowContainerController(null, sWm); 211 final WindowContainer container = new WindowContainer(); 212 213 container.setController(controller); 214 assertEquals(controller, container.getController()); 215 assertEquals(container, controller.mContainer); 216 217 // Assert we can't change the controller to another one once set 218 boolean gotException = false; 219 try { 220 container.setController(new WindowContainerController(null, sWm)); 221 } catch (IllegalArgumentException e) { 222 gotException = true; 223 } 224 assertTrue(gotException); 225 226 // Assert that we can set the controller to null. 227 container.setController(null); 228 assertNull(container.getController()); 229 assertNull(controller.mContainer); 230 } 231 232 @Test 233 public void testPositionChildAt() throws Exception { 234 final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(); 235 final TestWindowContainer root = builder.setLayer(0).build(); 236 237 final TestWindowContainer child1 = root.addChildWindow(); 238 final TestWindowContainer child2 = root.addChildWindow(); 239 final TestWindowContainer child3 = root.addChildWindow(); 240 241 // Test position at top. 242 root.positionChildAt(POSITION_TOP, child1, false /* includingParents */); 243 assertEquals(child1, root.getChildAt(root.getChildrenCount() - 1)); 244 245 // Test position at bottom. 246 root.positionChildAt(POSITION_BOTTOM, child1, false /* includingParents */); 247 assertEquals(child1, root.getChildAt(0)); 248 249 // Test position in the middle. 250 root.positionChildAt(1, child3, false /* includingParents */); 251 assertEquals(child1, root.getChildAt(0)); 252 assertEquals(child3, root.getChildAt(1)); 253 assertEquals(child2, root.getChildAt(2)); 254 } 255 256 @Test 257 public void testPositionChildAtIncludeParents() throws Exception { 258 final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(); 259 final TestWindowContainer root = builder.setLayer(0).build(); 260 261 final TestWindowContainer child1 = root.addChildWindow(); 262 final TestWindowContainer child2 = root.addChildWindow(); 263 final TestWindowContainer child11 = child1.addChildWindow(); 264 final TestWindowContainer child12 = child1.addChildWindow(); 265 final TestWindowContainer child13 = child1.addChildWindow(); 266 final TestWindowContainer child21 = child2.addChildWindow(); 267 final TestWindowContainer child22 = child2.addChildWindow(); 268 final TestWindowContainer child23 = child2.addChildWindow(); 269 270 // Test moving to top. 271 child1.positionChildAt(POSITION_TOP, child11, true /* includingParents */); 272 assertEquals(child12, child1.getChildAt(0)); 273 assertEquals(child13, child1.getChildAt(1)); 274 assertEquals(child11, child1.getChildAt(2)); 275 assertEquals(child2, root.getChildAt(0)); 276 assertEquals(child1, root.getChildAt(1)); 277 278 // Test moving to bottom. 279 child1.positionChildAt(POSITION_BOTTOM, child11, true /* includingParents */); 280 assertEquals(child11, child1.getChildAt(0)); 281 assertEquals(child12, child1.getChildAt(1)); 282 assertEquals(child13, child1.getChildAt(2)); 283 assertEquals(child1, root.getChildAt(0)); 284 assertEquals(child2, root.getChildAt(1)); 285 286 // Test moving to middle, includeParents shouldn't do anything. 287 child2.positionChildAt(1, child21, true /* includingParents */); 288 assertEquals(child11, child1.getChildAt(0)); 289 assertEquals(child12, child1.getChildAt(1)); 290 assertEquals(child13, child1.getChildAt(2)); 291 assertEquals(child22, child2.getChildAt(0)); 292 assertEquals(child21, child2.getChildAt(1)); 293 assertEquals(child23, child2.getChildAt(2)); 294 assertEquals(child1, root.getChildAt(0)); 295 assertEquals(child2, root.getChildAt(1)); 296 } 297 298 @Test 299 public void testPositionChildAtInvalid() throws Exception { 300 final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(); 301 final TestWindowContainer root = builder.setLayer(0).build(); 302 303 final TestWindowContainer child1 = root.addChildWindow(); 304 final TestWindowContainer child2 = root.addChildWindow(); 305 306 boolean gotException = false; 307 try { 308 // Check response to negative position. 309 root.positionChildAt(-1, child1, false /* includingParents */); 310 } catch (IllegalArgumentException e) { 311 gotException = true; 312 } 313 assertTrue(gotException); 314 315 gotException = false; 316 try { 317 // Check response to position that's bigger than child number. 318 root.positionChildAt(3, child1, false /* includingParents */); 319 } catch (IllegalArgumentException e) { 320 gotException = true; 321 } 322 assertTrue(gotException); 323 } 324 325 @Test 326 public void testIsAnimating() throws Exception { 327 final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(); 328 final TestWindowContainer root = builder.setLayer(0).build(); 329 330 final TestWindowContainer child1 = root.addChildWindow(builder.setIsAnimating(true)); 331 final TestWindowContainer child2 = root.addChildWindow(); 332 final TestWindowContainer child11 = child1.addChildWindow(); 333 final TestWindowContainer child12 = child1.addChildWindow(builder.setIsAnimating(true)); 334 final TestWindowContainer child21 = child2.addChildWindow(); 335 336 assertTrue(root.isAnimating()); 337 assertTrue(child1.isAnimating()); 338 assertFalse(child11.isAnimating()); 339 assertTrue(child12.isAnimating()); 340 assertFalse(child2.isAnimating()); 341 assertFalse(child21.isAnimating()); 342 } 343 344 @Test 345 public void testIsVisible() throws Exception { 346 final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(); 347 final TestWindowContainer root = builder.setLayer(0).build(); 348 349 final TestWindowContainer child1 = root.addChildWindow(builder.setIsVisible(true)); 350 final TestWindowContainer child2 = root.addChildWindow(); 351 final TestWindowContainer child11 = child1.addChildWindow(); 352 final TestWindowContainer child12 = child1.addChildWindow(builder.setIsVisible(true)); 353 final TestWindowContainer child21 = child2.addChildWindow(); 354 355 assertFalse(root.isVisible()); 356 assertTrue(child1.isVisible()); 357 assertFalse(child11.isVisible()); 358 assertTrue(child12.isVisible()); 359 assertFalse(child2.isVisible()); 360 assertFalse(child21.isVisible()); 361 } 362 363 @Test 364 public void testOverrideConfigurationAncestorNotification() { 365 final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(); 366 final TestWindowContainer grandparent = builder.setLayer(0).build(); 367 368 final TestWindowContainer parent = grandparent.addChildWindow(); 369 final TestWindowContainer child = parent.addChildWindow(); 370 child.onOverrideConfigurationChanged(new Configuration()); 371 372 assertTrue(grandparent.mOnDescendantOverrideCalled); 373 } 374 375 @Test 376 public void testRemoveChild() throws Exception { 377 final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(); 378 final TestWindowContainer root = builder.setLayer(0).build(); 379 final TestWindowContainer child1 = root.addChildWindow(); 380 final TestWindowContainer child2 = root.addChildWindow(); 381 final TestWindowContainer child11 = child1.addChildWindow(); 382 final TestWindowContainer child21 = child2.addChildWindow(); 383 384 assertTrue(root.hasChild(child2)); 385 assertTrue(root.hasChild(child21)); 386 root.removeChild(child2); 387 assertFalse(root.hasChild(child2)); 388 assertFalse(root.hasChild(child21)); 389 assertNull(child2.getParentWindow()); 390 391 boolean gotException = false; 392 assertTrue(root.hasChild(child11)); 393 try { 394 // Can only detach our direct children. 395 root.removeChild(child11); 396 } catch (IllegalArgumentException e) { 397 gotException = true; 398 } 399 assertTrue(gotException); 400 } 401 402 @Test 403 public void testGetOrientation_childSpecified() throws Exception { 404 testGetOrientation_childSpecifiedConfig(false, SCREEN_ORIENTATION_LANDSCAPE, 405 SCREEN_ORIENTATION_LANDSCAPE); 406 testGetOrientation_childSpecifiedConfig(false, SCREEN_ORIENTATION_UNSET, 407 SCREEN_ORIENTATION_UNSPECIFIED); 408 } 409 410 private void testGetOrientation_childSpecifiedConfig(boolean childVisible, int childOrientation, 411 int expectedOrientation) { 412 final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(); 413 final TestWindowContainer root = builder.setLayer(0).build(); 414 root.setFillsParent(true); 415 416 builder.setIsVisible(childVisible); 417 418 if (childOrientation != SCREEN_ORIENTATION_UNSET) { 419 builder.setOrientation(childOrientation); 420 } 421 422 final TestWindowContainer child1 = root.addChildWindow(builder); 423 child1.setFillsParent(true); 424 425 assertEquals(expectedOrientation, root.getOrientation()); 426 } 427 428 @Test 429 public void testGetOrientation_Unset() throws Exception { 430 final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(); 431 final TestWindowContainer root = builder.setLayer(0).setIsVisible(true).build(); 432 // Unspecified well because we didn't specify anything... 433 assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, root.getOrientation()); 434 } 435 436 @Test 437 public void testGetOrientation_InvisibleParentUnsetVisibleChildren() throws Exception { 438 final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(); 439 final TestWindowContainer root = builder.setLayer(0).setIsVisible(true).build(); 440 441 builder.setIsVisible(false).setLayer(-1); 442 final TestWindowContainer invisible = root.addChildWindow(builder); 443 builder.setIsVisible(true).setLayer(-2); 444 final TestWindowContainer invisibleChild1VisibleAndSet = invisible.addChildWindow(builder); 445 invisibleChild1VisibleAndSet.setOrientation(SCREEN_ORIENTATION_LANDSCAPE); 446 // Landscape well because the container is visible and that is what we set on it above. 447 assertEquals(SCREEN_ORIENTATION_LANDSCAPE, invisibleChild1VisibleAndSet.getOrientation()); 448 // Landscape because even though the container isn't visible it has a child that is 449 // specifying it can influence the orientation by being visible. 450 assertEquals(SCREEN_ORIENTATION_LANDSCAPE, invisible.getOrientation()); 451 // Landscape because the grandchild is visible and therefore can participate. 452 assertEquals(SCREEN_ORIENTATION_LANDSCAPE, root.getOrientation()); 453 454 builder.setIsVisible(true).setLayer(-3); 455 final TestWindowContainer visibleUnset = root.addChildWindow(builder); 456 visibleUnset.setOrientation(SCREEN_ORIENTATION_UNSET); 457 assertEquals(SCREEN_ORIENTATION_UNSET, visibleUnset.getOrientation()); 458 assertEquals(SCREEN_ORIENTATION_LANDSCAPE, root.getOrientation()); 459 460 } 461 462 @Test 463 public void testGetOrientation_setBehind() throws Exception { 464 final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(); 465 final TestWindowContainer root = builder.setLayer(0).setIsVisible(true).build(); 466 467 builder.setIsVisible(true).setLayer(-1); 468 final TestWindowContainer visibleUnset = root.addChildWindow(builder); 469 visibleUnset.setOrientation(SCREEN_ORIENTATION_UNSET); 470 471 builder.setIsVisible(true).setLayer(-2); 472 final TestWindowContainer visibleUnsetChild1VisibleSetBehind = 473 visibleUnset.addChildWindow(builder); 474 visibleUnsetChild1VisibleSetBehind.setOrientation(SCREEN_ORIENTATION_BEHIND); 475 // Setting to visible behind will be used by the parents if there isn't another other 476 // container behind this one that has an orientation set. 477 assertEquals(SCREEN_ORIENTATION_BEHIND, 478 visibleUnsetChild1VisibleSetBehind.getOrientation()); 479 assertEquals(SCREEN_ORIENTATION_BEHIND, visibleUnset.getOrientation()); 480 assertEquals(SCREEN_ORIENTATION_BEHIND, root.getOrientation()); 481 } 482 483 @Test 484 public void testGetOrientation_fillsParent() throws Exception { 485 final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(); 486 final TestWindowContainer root = builder.setLayer(0).setIsVisible(true).build(); 487 488 builder.setIsVisible(true).setLayer(-1); 489 final TestWindowContainer visibleUnset = root.addChildWindow(builder); 490 visibleUnset.setOrientation(SCREEN_ORIENTATION_BEHIND); 491 492 builder.setLayer(1).setIsVisible(true); 493 final TestWindowContainer visibleUnspecifiedRootChild = root.addChildWindow(builder); 494 visibleUnspecifiedRootChild.setFillsParent(false); 495 visibleUnspecifiedRootChild.setOrientation(SCREEN_ORIENTATION_UNSPECIFIED); 496 // Unset because the child doesn't fill the parent. May as well be invisible... 497 assertEquals(SCREEN_ORIENTATION_UNSET, visibleUnspecifiedRootChild.getOrientation()); 498 // The parent uses whatever orientation is set behind this container since it doesn't fill 499 // the parent. 500 assertEquals(SCREEN_ORIENTATION_BEHIND, root.getOrientation()); 501 502 // Test case of child filling its parent, but its parent isn't filling its own parent. 503 builder.setLayer(2).setIsVisible(true); 504 final TestWindowContainer visibleUnspecifiedRootChildChildFillsParent = 505 visibleUnspecifiedRootChild.addChildWindow(builder); 506 visibleUnspecifiedRootChildChildFillsParent.setOrientation( 507 SCREEN_ORIENTATION_PORTRAIT); 508 assertEquals(SCREEN_ORIENTATION_PORTRAIT, 509 visibleUnspecifiedRootChildChildFillsParent.getOrientation()); 510 assertEquals(SCREEN_ORIENTATION_UNSET, visibleUnspecifiedRootChild.getOrientation()); 511 assertEquals(SCREEN_ORIENTATION_BEHIND, root.getOrientation()); 512 513 514 visibleUnspecifiedRootChild.setFillsParent(true); 515 assertEquals(SCREEN_ORIENTATION_PORTRAIT, visibleUnspecifiedRootChild.getOrientation()); 516 assertEquals(SCREEN_ORIENTATION_PORTRAIT, root.getOrientation()); 517 } 518 519 @Test 520 public void testCompareTo() throws Exception { 521 final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(); 522 final TestWindowContainer root = builder.setLayer(0).build(); 523 524 final TestWindowContainer child1 = root.addChildWindow(); 525 final TestWindowContainer child11 = child1.addChildWindow(); 526 final TestWindowContainer child12 = child1.addChildWindow(); 527 528 final TestWindowContainer child2 = root.addChildWindow(); 529 final TestWindowContainer child21 = child2.addChildWindow(); 530 final TestWindowContainer child22 = child2.addChildWindow(); 531 final TestWindowContainer child23 = child2.addChildWindow(); 532 final TestWindowContainer child221 = child22.addChildWindow(); 533 final TestWindowContainer child222 = child22.addChildWindow(); 534 final TestWindowContainer child223 = child22.addChildWindow(); 535 final TestWindowContainer child2221 = child222.addChildWindow(); 536 final TestWindowContainer child2222 = child222.addChildWindow(); 537 final TestWindowContainer child2223 = child222.addChildWindow(); 538 539 final TestWindowContainer root2 = builder.setLayer(0).build(); 540 541 assertEquals(0, root.compareTo(root)); 542 assertEquals(-1, child1.compareTo(child2)); 543 assertEquals(1, child2.compareTo(child1)); 544 545 boolean inTheSameTree = true; 546 try { 547 root.compareTo(root2); 548 } catch (IllegalArgumentException e) { 549 inTheSameTree = false; 550 } 551 assertFalse(inTheSameTree); 552 553 assertEquals(-1, child1.compareTo(child11)); 554 assertEquals(1, child21.compareTo(root)); 555 assertEquals(1, child21.compareTo(child12)); 556 assertEquals(-1, child11.compareTo(child2)); 557 assertEquals(1, child2221.compareTo(child11)); 558 assertEquals(-1, child2222.compareTo(child223)); 559 assertEquals(1, child2223.compareTo(child21)); 560 } 561 562 @Test 563 public void testConfigurationInit() throws Exception { 564 final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(); 565 566 // Check root container initial config. 567 final TestWindowContainer root = builder.setLayer(0).build(); 568 assertEquals(Configuration.EMPTY, root.getOverrideConfiguration()); 569 assertEquals(Configuration.EMPTY, root.getMergedOverrideConfiguration()); 570 assertEquals(Configuration.EMPTY, root.getConfiguration()); 571 572 // Check child initial config. 573 final TestWindowContainer child1 = root.addChildWindow(); 574 assertEquals(Configuration.EMPTY, child1.getOverrideConfiguration()); 575 assertEquals(Configuration.EMPTY, child1.getMergedOverrideConfiguration()); 576 assertEquals(Configuration.EMPTY, child1.getConfiguration()); 577 578 // Check child initial config if root has overrides. 579 final Configuration rootOverrideConfig = new Configuration(); 580 rootOverrideConfig.fontScale = 1.3f; 581 root.onOverrideConfigurationChanged(rootOverrideConfig); 582 final TestWindowContainer child2 = root.addChildWindow(); 583 assertEquals(Configuration.EMPTY, child2.getOverrideConfiguration()); 584 assertEquals(rootOverrideConfig, child2.getMergedOverrideConfiguration()); 585 assertEquals(rootOverrideConfig, child2.getConfiguration()); 586 587 // Check child initial config if root has parent config set. 588 final Configuration rootParentConfig = new Configuration(); 589 rootParentConfig.fontScale = 0.8f; 590 rootParentConfig.orientation = SCREEN_ORIENTATION_LANDSCAPE; 591 root.onConfigurationChanged(rootParentConfig); 592 final Configuration rootFullConfig = new Configuration(rootParentConfig); 593 rootFullConfig.updateFrom(rootOverrideConfig); 594 595 final TestWindowContainer child3 = root.addChildWindow(); 596 assertEquals(Configuration.EMPTY, child3.getOverrideConfiguration()); 597 assertEquals(rootOverrideConfig, child3.getMergedOverrideConfiguration()); 598 assertEquals(rootFullConfig, child3.getConfiguration()); 599 } 600 601 @Test 602 public void testConfigurationChangeOnAddRemove() throws Exception { 603 final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(); 604 605 // Init root's config. 606 final TestWindowContainer root = builder.setLayer(0).build(); 607 final Configuration rootOverrideConfig = new Configuration(); 608 rootOverrideConfig.fontScale = 1.3f; 609 root.onOverrideConfigurationChanged(rootOverrideConfig); 610 611 // Init child's config. 612 final TestWindowContainer child = root.addChildWindow(); 613 final Configuration childOverrideConfig = new Configuration(); 614 childOverrideConfig.densityDpi = 320; 615 child.onOverrideConfigurationChanged(childOverrideConfig); 616 final Configuration mergedOverrideConfig = new Configuration(root.getConfiguration()); 617 mergedOverrideConfig.updateFrom(childOverrideConfig); 618 619 // Check configuration update when child is removed from parent - it should remain same. 620 root.removeChild(child); 621 assertEquals(childOverrideConfig, child.getOverrideConfiguration()); 622 assertEquals(mergedOverrideConfig, child.getMergedOverrideConfiguration()); 623 assertEquals(mergedOverrideConfig, child.getConfiguration()); 624 625 // It may be paranoia... but let's check if parent's config didn't change after removal. 626 assertEquals(rootOverrideConfig, root.getOverrideConfiguration()); 627 assertEquals(rootOverrideConfig, root.getMergedOverrideConfiguration()); 628 assertEquals(rootOverrideConfig, root.getConfiguration()); 629 630 // Init different root 631 final TestWindowContainer root2 = builder.setLayer(0).build(); 632 final Configuration rootOverrideConfig2 = new Configuration(); 633 rootOverrideConfig2.fontScale = 1.1f; 634 root2.onOverrideConfigurationChanged(rootOverrideConfig2); 635 636 // Check configuration update when child is added to different parent. 637 mergedOverrideConfig.setTo(rootOverrideConfig2); 638 mergedOverrideConfig.updateFrom(childOverrideConfig); 639 root2.addChildWindow(child); 640 assertEquals(childOverrideConfig, child.getOverrideConfiguration()); 641 assertEquals(mergedOverrideConfig, child.getMergedOverrideConfiguration()); 642 assertEquals(mergedOverrideConfig, child.getConfiguration()); 643 } 644 645 @Test 646 public void testConfigurationChangePropagation() throws Exception { 647 final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(); 648 649 // Builds 3-level vertical hierarchy with one window container on each level. 650 // In addition to different overrides on each level, everyone in hierarchy will have one 651 // common overridden value - orientation; 652 653 // Init root's config. 654 final TestWindowContainer root = builder.setLayer(0).build(); 655 final Configuration rootOverrideConfig = new Configuration(); 656 rootOverrideConfig.fontScale = 1.3f; 657 rootOverrideConfig.orientation = SCREEN_ORIENTATION_REVERSE_LANDSCAPE; 658 root.onOverrideConfigurationChanged(rootOverrideConfig); 659 660 // Init children. 661 final TestWindowContainer child1 = root.addChildWindow(); 662 final Configuration childOverrideConfig1 = new Configuration(); 663 childOverrideConfig1.densityDpi = 320; 664 childOverrideConfig1.orientation = SCREEN_ORIENTATION_LANDSCAPE; 665 child1.onOverrideConfigurationChanged(childOverrideConfig1); 666 667 final TestWindowContainer child2 = child1.addChildWindow(); 668 final Configuration childOverrideConfig2 = new Configuration(); 669 childOverrideConfig2.screenWidthDp = 150; 670 childOverrideConfig2.orientation = SCREEN_ORIENTATION_PORTRAIT; 671 child2.onOverrideConfigurationChanged(childOverrideConfig2); 672 673 // Check configuration on all levels when root override is updated. 674 rootOverrideConfig.smallestScreenWidthDp = 200; 675 root.onOverrideConfigurationChanged(rootOverrideConfig); 676 677 final Configuration mergedOverrideConfig1 = new Configuration(rootOverrideConfig); 678 mergedOverrideConfig1.updateFrom(childOverrideConfig1); 679 final Configuration mergedConfig1 = new Configuration(mergedOverrideConfig1); 680 681 final Configuration mergedOverrideConfig2 = new Configuration(mergedOverrideConfig1); 682 mergedOverrideConfig2.updateFrom(childOverrideConfig2); 683 final Configuration mergedConfig2 = new Configuration(mergedOverrideConfig2); 684 685 assertEquals(rootOverrideConfig, root.getOverrideConfiguration()); 686 assertEquals(rootOverrideConfig, root.getMergedOverrideConfiguration()); 687 assertEquals(rootOverrideConfig, root.getConfiguration()); 688 689 assertEquals(childOverrideConfig1, child1.getOverrideConfiguration()); 690 assertEquals(mergedOverrideConfig1, child1.getMergedOverrideConfiguration()); 691 assertEquals(mergedConfig1, child1.getConfiguration()); 692 693 assertEquals(childOverrideConfig2, child2.getOverrideConfiguration()); 694 assertEquals(mergedOverrideConfig2, child2.getMergedOverrideConfiguration()); 695 assertEquals(mergedConfig2, child2.getConfiguration()); 696 697 // Check configuration on all levels when root parent config is updated. 698 final Configuration rootParentConfig = new Configuration(); 699 rootParentConfig.screenHeightDp = 100; 700 rootParentConfig.orientation = SCREEN_ORIENTATION_REVERSE_PORTRAIT; 701 root.onConfigurationChanged(rootParentConfig); 702 final Configuration mergedRootConfig = new Configuration(rootParentConfig); 703 mergedRootConfig.updateFrom(rootOverrideConfig); 704 705 mergedConfig1.setTo(mergedRootConfig); 706 mergedConfig1.updateFrom(mergedOverrideConfig1); 707 708 mergedConfig2.setTo(mergedConfig1); 709 mergedConfig2.updateFrom(mergedOverrideConfig2); 710 711 assertEquals(rootOverrideConfig, root.getOverrideConfiguration()); 712 assertEquals(rootOverrideConfig, root.getMergedOverrideConfiguration()); 713 assertEquals(mergedRootConfig, root.getConfiguration()); 714 715 assertEquals(childOverrideConfig1, child1.getOverrideConfiguration()); 716 assertEquals(mergedOverrideConfig1, child1.getMergedOverrideConfiguration()); 717 assertEquals(mergedConfig1, child1.getConfiguration()); 718 719 assertEquals(childOverrideConfig2, child2.getOverrideConfiguration()); 720 assertEquals(mergedOverrideConfig2, child2.getMergedOverrideConfiguration()); 721 assertEquals(mergedConfig2, child2.getConfiguration()); 722 } 723 724 /* Used so we can gain access to some protected members of the {@link WindowContainer} class */ 725 private class TestWindowContainer extends WindowContainer<TestWindowContainer> { 726 private final int mLayer; 727 private boolean mIsAnimating; 728 private boolean mIsVisible; 729 private boolean mFillsParent; 730 private Integer mOrientation; 731 732 private boolean mOnParentSetCalled; 733 private boolean mOnDescendantOverrideCalled; 734 735 /** 736 * Compares 2 window layers and returns -1 if the first is lesser than the second in terms 737 * of z-order and 1 otherwise. 738 */ 739 private final Comparator<TestWindowContainer> mWindowSubLayerComparator = (w1, w2) -> { 740 final int layer1 = w1.mLayer; 741 final int layer2 = w2.mLayer; 742 if (layer1 < layer2 || (layer1 == layer2 && layer2 < 0 )) { 743 // We insert the child window into the list ordered by the mLayer. For same layers, 744 // the negative one should go below others; the positive one should go above others. 745 return -1; 746 } 747 return 1; 748 }; 749 750 TestWindowContainer(int layer, boolean isAnimating, boolean isVisible, 751 Integer orientation) { 752 mLayer = layer; 753 mIsAnimating = isAnimating; 754 mIsVisible = isVisible; 755 mFillsParent = true; 756 mOrientation = orientation; 757 } 758 759 TestWindowContainer getParentWindow() { 760 return (TestWindowContainer) getParent(); 761 } 762 763 int getChildrenCount() { 764 return mChildren.size(); 765 } 766 767 TestWindowContainer addChildWindow(TestWindowContainer child) { 768 addChild(child, mWindowSubLayerComparator); 769 return child; 770 } 771 772 TestWindowContainer addChildWindow(TestWindowContainerBuilder childBuilder) { 773 TestWindowContainer child = childBuilder.build(); 774 addChild(child, mWindowSubLayerComparator); 775 return child; 776 } 777 778 TestWindowContainer addChildWindow() { 779 return addChildWindow(new TestWindowContainerBuilder().setLayer(1)); 780 } 781 782 TestWindowContainer getChildAt(int index) { 783 return mChildren.get(index); 784 } 785 786 @Override 787 void onParentSet() { 788 mOnParentSetCalled = true; 789 } 790 791 @Override 792 void onDescendantOverrideConfigurationChanged() { 793 mOnDescendantOverrideCalled = true; 794 super.onDescendantOverrideConfigurationChanged(); 795 } 796 797 @Override 798 boolean isAnimating() { 799 return mIsAnimating || super.isAnimating(); 800 } 801 802 @Override 803 boolean isVisible() { 804 return mIsVisible; 805 } 806 807 @Override 808 int getOrientation(int candidate) { 809 return mOrientation != null ? mOrientation : super.getOrientation(candidate); 810 } 811 812 @Override 813 int getOrientation() { 814 return getOrientation(super.mOrientation); 815 } 816 817 @Override 818 boolean fillsParent() { 819 return mFillsParent; 820 } 821 822 void setFillsParent(boolean fillsParent) { 823 mFillsParent = fillsParent; 824 } 825 } 826 827 private class TestWindowContainerBuilder { 828 private int mLayer; 829 private boolean mIsAnimating; 830 private boolean mIsVisible; 831 private Integer mOrientation; 832 833 public TestWindowContainerBuilder() { 834 reset(); 835 } 836 837 TestWindowContainerBuilder setLayer(int layer) { 838 mLayer = layer; 839 return this; 840 } 841 842 TestWindowContainerBuilder setIsAnimating(boolean isAnimating) { 843 mIsAnimating = isAnimating; 844 return this; 845 } 846 847 TestWindowContainerBuilder setIsVisible(boolean isVisible) { 848 mIsVisible = isVisible; 849 return this; 850 } 851 852 TestWindowContainerBuilder setOrientation(int orientation) { 853 mOrientation = orientation; 854 return this; 855 } 856 857 TestWindowContainerBuilder reset() { 858 mLayer = 0; 859 mIsAnimating = false; 860 mIsVisible = false; 861 mOrientation = null; 862 return this; 863 } 864 865 TestWindowContainer build() { 866 return new TestWindowContainer(mLayer, mIsAnimating, mIsVisible, mOrientation); 867 } 868 } 869 } 870