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