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