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.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 20 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND; 21 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; 22 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; 23 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; 24 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; 25 import static android.view.WindowInsets.Type.systemOverlays; 26 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; 27 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; 28 import static android.view.WindowManager.TRANSIT_CLOSE; 29 import static android.view.WindowManager.TRANSIT_OLD_TASK_CLOSE; 30 import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CHANGE; 31 import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN; 32 import static android.view.WindowManager.TRANSIT_OPEN; 33 import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER; 34 35 import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; 36 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyFloat; 37 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt; 38 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; 39 import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq; 40 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; 41 import static com.android.dx.mockito.inline.extended.ExtendedMockito.never; 42 import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset; 43 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; 44 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; 45 import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; 46 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; 47 import static com.android.server.wm.DisplayArea.Type.ANY; 48 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_ALL; 49 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; 50 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_SCREEN_ROTATION; 51 import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN; 52 import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; 53 import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; 54 import static com.android.server.wm.WindowContainer.POSITION_BOTTOM; 55 import static com.android.server.wm.WindowContainer.POSITION_TOP; 56 57 import static com.google.common.truth.Truth.assertThat; 58 59 import static org.junit.Assert.assertEquals; 60 import static org.junit.Assert.assertFalse; 61 import static org.junit.Assert.assertNotEquals; 62 import static org.junit.Assert.assertNotNull; 63 import static org.junit.Assert.assertNull; 64 import static org.junit.Assert.assertTrue; 65 import static org.mockito.Mockito.clearInvocations; 66 67 import android.annotation.NonNull; 68 import android.annotation.Nullable; 69 import android.content.pm.ActivityInfo; 70 import android.content.res.Configuration; 71 import android.graphics.Rect; 72 import android.os.Binder; 73 import android.os.DeadObjectException; 74 import android.os.IBinder; 75 import android.os.IInterface; 76 import android.os.Parcel; 77 import android.os.RemoteException; 78 import android.os.ResultReceiver; 79 import android.os.ShellCallback; 80 import android.platform.test.annotations.Presubmit; 81 import android.view.IRemoteAnimationFinishedCallback; 82 import android.view.IRemoteAnimationRunner; 83 import android.view.InsetsFrameProvider; 84 import android.view.InsetsSource; 85 import android.view.RemoteAnimationAdapter; 86 import android.view.RemoteAnimationTarget; 87 import android.view.SurfaceControl; 88 import android.view.SurfaceSession; 89 import android.view.WindowInsets; 90 import android.view.WindowManager; 91 92 import androidx.test.filters.SmallTest; 93 94 import org.junit.Test; 95 import org.junit.runner.RunWith; 96 import org.mockito.ArgumentCaptor; 97 import org.mockito.Mockito; 98 99 import java.io.FileDescriptor; 100 import java.util.ArrayList; 101 import java.util.Comparator; 102 import java.util.NoSuchElementException; 103 104 105 /** 106 * Test class for {@link WindowContainer}. 107 * 108 * Build/Install/Run: 109 * atest WmTests:WindowContainerTests 110 */ 111 @SmallTest 112 @Presubmit 113 @RunWith(WindowTestRunner.class) 114 public class WindowContainerTests extends WindowTestsBase { 115 116 @Test testCreation()117 public void testCreation() { 118 final TestWindowContainer w = new TestWindowContainerBuilder(mWm).setLayer(0).build(); 119 assertNull("window must have no parent", w.getParentWindow()); 120 assertEquals("window must have no children", 0, w.getChildrenCount()); 121 } 122 123 @Test testAdd()124 public void testAdd() { 125 final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); 126 final TestWindowContainer root = builder.setLayer(0).build(); 127 128 final TestWindowContainer layer1 = root.addChildWindow(builder.setLayer(1)); 129 final TestWindowContainer secondLayer1 = root.addChildWindow(builder.setLayer(1)); 130 final TestWindowContainer layer2 = root.addChildWindow(builder.setLayer(2)); 131 final TestWindowContainer layerNeg1 = root.addChildWindow(builder.setLayer(-1)); 132 final TestWindowContainer layerNeg2 = root.addChildWindow(builder.setLayer(-2)); 133 final TestWindowContainer secondLayerNeg1 = root.addChildWindow(builder.setLayer(-1)); 134 final TestWindowContainer layer0 = root.addChildWindow(builder.setLayer(0)); 135 136 assertEquals(7, root.getChildrenCount()); 137 138 assertEquals(root, layer1.getParentWindow()); 139 assertEquals(root, secondLayer1.getParentWindow()); 140 assertEquals(root, layer2.getParentWindow()); 141 assertEquals(root, layerNeg1.getParentWindow()); 142 assertEquals(root, layerNeg2.getParentWindow()); 143 assertEquals(root, secondLayerNeg1.getParentWindow()); 144 assertEquals(root, layer0.getParentWindow()); 145 146 assertEquals(layerNeg2, root.getChildAt(0)); 147 assertEquals(secondLayerNeg1, root.getChildAt(1)); 148 assertEquals(layerNeg1, root.getChildAt(2)); 149 assertEquals(layer0, root.getChildAt(3)); 150 assertEquals(layer1, root.getChildAt(4)); 151 assertEquals(secondLayer1, root.getChildAt(5)); 152 assertEquals(layer2, root.getChildAt(6)); 153 154 assertTrue(layer1.mOnParentChangedCalled); 155 assertTrue(secondLayer1.mOnParentChangedCalled); 156 assertTrue(layer2.mOnParentChangedCalled); 157 assertTrue(layerNeg1.mOnParentChangedCalled); 158 assertTrue(layerNeg2.mOnParentChangedCalled); 159 assertTrue(secondLayerNeg1.mOnParentChangedCalled); 160 assertTrue(layer0.mOnParentChangedCalled); 161 } 162 163 @Test testAddChildSetsSurfacePosition()164 public void testAddChildSetsSurfacePosition() { 165 reset(mTransaction); 166 try (MockSurfaceBuildingContainer top = new MockSurfaceBuildingContainer(mWm)) { 167 WindowContainer child = new WindowContainer(mWm); 168 child.setBounds(1, 1, 10, 10); 169 170 verify(mTransaction, never()).setPosition(any(), anyFloat(), anyFloat()); 171 top.addChild(child, 0); 172 verify(mTransaction, times(1)).setPosition(any(), eq(1.f), eq(1.f)); 173 } 174 } 175 176 @Test testAdd_AlreadyHasParent()177 public void testAdd_AlreadyHasParent() { 178 final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); 179 final TestWindowContainer root = builder.setLayer(0).build(); 180 181 final TestWindowContainer child1 = root.addChildWindow(); 182 final TestWindowContainer child2 = root.addChildWindow(); 183 184 boolean gotException = false; 185 try { 186 child1.addChildWindow(child2); 187 } catch (IllegalArgumentException e) { 188 gotException = true; 189 } 190 assertTrue(gotException); 191 192 gotException = false; 193 try { 194 root.addChildWindow(child2); 195 } catch (IllegalArgumentException e) { 196 gotException = true; 197 } 198 assertTrue(gotException); 199 } 200 201 @Test testHasChild()202 public void testHasChild() { 203 final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); 204 final TestWindowContainer root = builder.setLayer(0).build(); 205 206 final TestWindowContainer child1 = root.addChildWindow(); 207 final TestWindowContainer child2 = root.addChildWindow(); 208 final TestWindowContainer child11 = child1.addChildWindow(); 209 final TestWindowContainer child12 = child1.addChildWindow(); 210 final TestWindowContainer child21 = child2.addChildWindow(); 211 212 assertEquals(2, root.getChildrenCount()); 213 assertEquals(2, child1.getChildrenCount()); 214 assertEquals(1, child2.getChildrenCount()); 215 216 assertTrue(root.hasChild(child1)); 217 assertTrue(root.hasChild(child2)); 218 assertTrue(root.hasChild(child11)); 219 assertTrue(root.hasChild(child12)); 220 assertTrue(root.hasChild(child21)); 221 222 assertTrue(child1.hasChild(child11)); 223 assertTrue(child1.hasChild(child12)); 224 assertFalse(child1.hasChild(child21)); 225 226 assertTrue(child2.hasChild(child21)); 227 assertFalse(child2.hasChild(child11)); 228 assertFalse(child2.hasChild(child12)); 229 } 230 231 @Test testRemoveImmediately()232 public void testRemoveImmediately() { 233 final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); 234 final TestWindowContainer root = builder.setLayer(0).build(); 235 236 final TestWindowContainer child1 = root.addChildWindow(); 237 final TestWindowContainer child2 = root.addChildWindow(); 238 final TestWindowContainer child11 = child1.addChildWindow(); 239 final TestWindowContainer child12 = child1.addChildWindow(); 240 final TestWindowContainer child21 = child2.addChildWindow(); 241 242 assertNotNull(child12.getParentWindow()); 243 child12.removeImmediately(); 244 assertNull(child12.getParentWindow()); 245 assertEquals(1, child1.getChildrenCount()); 246 assertFalse(child1.hasChild(child12)); 247 assertFalse(root.hasChild(child12)); 248 249 assertTrue(root.hasChild(child2)); 250 assertNotNull(child2.getParentWindow()); 251 child2.removeImmediately(); 252 assertNull(child2.getParentWindow()); 253 assertNull(child21.getParentWindow()); 254 assertEquals(0, child2.getChildrenCount()); 255 assertEquals(1, root.getChildrenCount()); 256 assertFalse(root.hasChild(child2)); 257 assertFalse(root.hasChild(child21)); 258 259 assertTrue(root.hasChild(child1)); 260 assertTrue(root.hasChild(child11)); 261 262 root.removeImmediately(); 263 assertEquals(0, root.getChildrenCount()); 264 } 265 266 @Test testRemoveImmediatelyClearsLastSurfacePosition()267 public void testRemoveImmediatelyClearsLastSurfacePosition() { 268 reset(mTransaction); 269 try (MockSurfaceBuildingContainer top = new MockSurfaceBuildingContainer(mWm)) { 270 final WindowContainer<WindowContainer> child1 = new WindowContainer(mWm); 271 child1.setBounds(1, 1, 10, 10); 272 273 top.addChild(child1, 0); 274 assertEquals(1, child1.getLastSurfacePosition().x); 275 assertEquals(1, child1.getLastSurfacePosition().y); 276 277 WindowContainer child11 = new WindowContainer(mWm); 278 child1.addChild(child11, 0); 279 280 child1.setBounds(2, 2, 20, 20); 281 assertEquals(2, child1.getLastSurfacePosition().x); 282 assertEquals(2, child1.getLastSurfacePosition().y); 283 284 child1.removeImmediately(); 285 assertEquals(0, child1.getLastSurfacePosition().x); 286 assertEquals(0, child1.getLastSurfacePosition().y); 287 assertEquals(0, child11.getLastSurfacePosition().x); 288 assertEquals(0, child11.getLastSurfacePosition().y); 289 } 290 } 291 292 @Test testRemoveImmediatelyClearsLeash()293 public void testRemoveImmediatelyClearsLeash() { 294 final AnimationAdapter animAdapter = mock(AnimationAdapter.class); 295 final WindowToken token = createTestWindowToken(TYPE_APPLICATION_OVERLAY, mDisplayContent); 296 final SurfaceControl.Transaction t = token.getPendingTransaction(); 297 token.startAnimation(t, animAdapter, false /* hidden */, 298 SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION); 299 final ArgumentCaptor<SurfaceControl> leashCaptor = 300 ArgumentCaptor.forClass(SurfaceControl.class); 301 verify(animAdapter).startAnimation(leashCaptor.capture(), eq(t), anyInt(), any()); 302 assertTrue(token.mSurfaceAnimator.hasLeash()); 303 token.removeImmediately(); 304 assertFalse(token.mSurfaceAnimator.hasLeash()); 305 verify(t).remove(eq(leashCaptor.getValue())); 306 } 307 308 @Test testAddChildByIndex()309 public void testAddChildByIndex() { 310 final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); 311 final TestWindowContainer root = builder.setLayer(0).build(); 312 313 final TestWindowContainer child = root.addChildWindow(); 314 315 final TestWindowContainer child2 = builder.setLayer(1).build(); 316 final TestWindowContainer child3 = builder.setLayer(2).build(); 317 final TestWindowContainer child4 = builder.setLayer(3).build(); 318 319 // Test adding at top. 320 root.addChild(child2, POSITION_TOP); 321 assertEquals(child2, root.getChildAt(root.getChildrenCount() - 1)); 322 323 // Test adding at bottom. 324 root.addChild(child3, POSITION_BOTTOM); 325 assertEquals(child3, root.getChildAt(0)); 326 327 // Test adding in the middle. 328 root.addChild(child4, 1); 329 assertEquals(child3, root.getChildAt(0)); 330 assertEquals(child4, root.getChildAt(1)); 331 assertEquals(child, root.getChildAt(2)); 332 assertEquals(child2, root.getChildAt(3)); 333 } 334 335 @Test testPositionChildAt()336 public void testPositionChildAt() { 337 final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); 338 final TestWindowContainer root = builder.setLayer(0).build(); 339 340 final TestWindowContainer child1 = root.addChildWindow(); 341 final TestWindowContainer child2 = root.addChildWindow(); 342 final TestWindowContainer child3 = root.addChildWindow(); 343 344 // Test position at top. 345 root.positionChildAt(POSITION_TOP, child1, false /* includingParents */); 346 assertEquals(child1, root.getChildAt(root.getChildrenCount() - 1)); 347 348 // Test position at bottom. 349 root.positionChildAt(POSITION_BOTTOM, child1, false /* includingParents */); 350 assertEquals(child1, root.getChildAt(0)); 351 352 // Test position in the middle. 353 root.positionChildAt(1, child3, false /* includingParents */); 354 assertEquals(child1, root.getChildAt(0)); 355 assertEquals(child3, root.getChildAt(1)); 356 assertEquals(child2, root.getChildAt(2)); 357 } 358 359 @Test testPositionChildAtIncludeParents()360 public void testPositionChildAtIncludeParents() { 361 final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); 362 final TestWindowContainer root = builder.setLayer(0).build(); 363 364 final TestWindowContainer child1 = root.addChildWindow(); 365 final TestWindowContainer child2 = root.addChildWindow(); 366 final TestWindowContainer child11 = child1.addChildWindow(); 367 final TestWindowContainer child12 = child1.addChildWindow(); 368 final TestWindowContainer child13 = child1.addChildWindow(); 369 final TestWindowContainer child21 = child2.addChildWindow(); 370 final TestWindowContainer child22 = child2.addChildWindow(); 371 final TestWindowContainer child23 = child2.addChildWindow(); 372 373 // Test moving to top. 374 child1.positionChildAt(POSITION_TOP, child11, true /* includingParents */); 375 assertEquals(child12, child1.getChildAt(0)); 376 assertEquals(child13, child1.getChildAt(1)); 377 assertEquals(child11, child1.getChildAt(2)); 378 assertEquals(child2, root.getChildAt(0)); 379 assertEquals(child1, root.getChildAt(1)); 380 381 // Test moving to bottom. 382 child1.positionChildAt(POSITION_BOTTOM, child11, true /* includingParents */); 383 assertEquals(child11, child1.getChildAt(0)); 384 assertEquals(child12, child1.getChildAt(1)); 385 assertEquals(child13, child1.getChildAt(2)); 386 assertEquals(child1, root.getChildAt(0)); 387 assertEquals(child2, root.getChildAt(1)); 388 389 // Test moving to middle, includeParents shouldn't do anything. 390 child2.positionChildAt(1, child21, true /* includingParents */); 391 assertEquals(child11, child1.getChildAt(0)); 392 assertEquals(child12, child1.getChildAt(1)); 393 assertEquals(child13, child1.getChildAt(2)); 394 assertEquals(child22, child2.getChildAt(0)); 395 assertEquals(child21, child2.getChildAt(1)); 396 assertEquals(child23, child2.getChildAt(2)); 397 assertEquals(child1, root.getChildAt(0)); 398 assertEquals(child2, root.getChildAt(1)); 399 } 400 401 @Test testIsAnimating_TransitionFlag()402 public void testIsAnimating_TransitionFlag() { 403 final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); 404 final TestWindowContainer root = builder.setLayer(0).build(); 405 final TestWindowContainer child1 = root.addChildWindow( 406 builder.setWaitForTransitionStart(true)); 407 408 assertFalse(root.isAnimating(TRANSITION)); 409 assertTrue(child1.isAnimating(TRANSITION)); 410 } 411 412 @Test testIsAnimating_ParentsFlag()413 public void testIsAnimating_ParentsFlag() { 414 final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); 415 final TestWindowContainer root = builder.setLayer(0).build(); 416 final TestWindowContainer child1 = root.addChildWindow(builder); 417 final TestWindowContainer child2 = root.addChildWindow(builder.setIsAnimating(true)); 418 final TestWindowContainer child21 = child2.addChildWindow(builder.setIsAnimating(false)); 419 420 assertFalse(root.isAnimating()); 421 assertFalse(child1.isAnimating()); 422 assertFalse(child1.isAnimating(PARENTS)); 423 assertTrue(child2.isAnimating()); 424 assertTrue(child2.isAnimating(PARENTS)); 425 assertFalse(child21.isAnimating()); 426 assertTrue(child21.isAnimating(PARENTS)); 427 } 428 429 @Test testIsAnimating_ChildrenFlag()430 public void testIsAnimating_ChildrenFlag() { 431 final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); 432 final TestWindowContainer root = builder.setLayer(0).build(); 433 final TestWindowContainer child1 = root.addChildWindow(builder); 434 final TestWindowContainer child2 = root.addChildWindow(builder.setIsAnimating(true)); 435 final TestWindowContainer child11 = child1.addChildWindow(builder.setIsAnimating(true)); 436 437 assertFalse(root.isAnimating()); 438 assertTrue(root.isAnimating(CHILDREN)); 439 assertFalse(child1.isAnimating()); 440 assertTrue(child1.isAnimating(CHILDREN)); 441 assertTrue(child2.isAnimating()); 442 assertTrue(child2.isAnimating(CHILDREN)); 443 assertTrue(child11.isAnimating()); 444 assertTrue(child11.isAnimating(CHILDREN)); 445 } 446 447 @Test testIsAnimating_combineFlags()448 public void testIsAnimating_combineFlags() { 449 final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); 450 final TestWindowContainer root = builder.setLayer(0).build(); 451 452 final TestWindowContainer child1 = root.addChildWindow(builder.setIsAnimating(true)); 453 final TestWindowContainer child2 = root.addChildWindow(); 454 final TestWindowContainer child11 = child1.addChildWindow(); 455 final TestWindowContainer child12 = child1.addChildWindow(builder.setIsAnimating(true)); 456 final TestWindowContainer child21 = child2.addChildWindow(); 457 458 assertFalse(root.isAnimating(TRANSITION | PARENTS)); 459 assertTrue(child1.isAnimating(TRANSITION | PARENTS)); 460 assertTrue(child11.isAnimating(TRANSITION | PARENTS)); 461 assertTrue(child12.isAnimating(TRANSITION | PARENTS)); 462 assertFalse(child2.isAnimating(TRANSITION | PARENTS)); 463 assertFalse(child21.isAnimating(TRANSITION | PARENTS)); 464 465 assertTrue(root.isAnimating(TRANSITION | CHILDREN)); 466 assertTrue(child1.isAnimating(TRANSITION | CHILDREN)); 467 assertFalse(child11.isAnimating(TRANSITION | CHILDREN)); 468 assertTrue(child12.isAnimating(TRANSITION | CHILDREN)); 469 assertFalse(child2.isAnimating(TRANSITION | CHILDREN)); 470 assertFalse(child21.isAnimating(TRANSITION | CHILDREN)); 471 } 472 473 @Test testIsAnimating_typesToCheck()474 public void testIsAnimating_typesToCheck() { 475 final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); 476 final TestWindowContainer window = builder.setIsAnimating(true).setLayer(0).build(); 477 478 assertTrue(window.isAnimating()); 479 assertFalse(window.isAnimating(0, ANIMATION_TYPE_SCREEN_ROTATION)); 480 assertTrue(window.isAnimating(0, ANIMATION_TYPE_APP_TRANSITION)); 481 assertFalse(window.isAnimating(0, ANIMATION_TYPE_ALL & ~ANIMATION_TYPE_APP_TRANSITION)); 482 483 final TestWindowContainer child = window.addChildWindow(); 484 assertFalse(child.isAnimating()); 485 assertTrue(child.isAnimating(PARENTS)); 486 assertTrue(child.isAnimating(PARENTS, ANIMATION_TYPE_APP_TRANSITION)); 487 assertFalse(child.isAnimating(PARENTS, ANIMATION_TYPE_SCREEN_ROTATION)); 488 489 final WindowState windowState = createWindow(null /* parent */, TYPE_BASE_APPLICATION, 490 mDisplayContent, "TestWindowState"); 491 WindowContainer parent = windowState.getParent(); 492 spyOn(windowState.mSurfaceAnimator); 493 doReturn(true).when(windowState.mSurfaceAnimator).isAnimating(); 494 doReturn(ANIMATION_TYPE_APP_TRANSITION).when( 495 windowState.mSurfaceAnimator).getAnimationType(); 496 assertTrue(parent.isAnimating(CHILDREN)); 497 498 windowState.setControllableInsetProvider(mock(InsetsSourceProvider.class)); 499 assertFalse(parent.isAnimating(CHILDREN)); 500 } 501 502 @Test testIsVisible()503 public void testIsVisible() { 504 final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); 505 final TestWindowContainer root = builder.setLayer(0).build(); 506 507 final TestWindowContainer child1 = root.addChildWindow(builder.setIsVisible(true)); 508 final TestWindowContainer child2 = root.addChildWindow(); 509 final TestWindowContainer child11 = child1.addChildWindow(); 510 final TestWindowContainer child12 = child1.addChildWindow(builder.setIsVisible(true)); 511 final TestWindowContainer child21 = child2.addChildWindow(); 512 513 assertFalse(root.isVisible()); 514 assertTrue(child1.isVisible()); 515 assertFalse(child11.isVisible()); 516 assertTrue(child12.isVisible()); 517 assertFalse(child2.isVisible()); 518 assertFalse(child21.isVisible()); 519 } 520 521 @Test testOverrideConfigurationAncestorNotification()522 public void testOverrideConfigurationAncestorNotification() { 523 final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); 524 final TestWindowContainer grandparent = builder.setLayer(0).build(); 525 526 final TestWindowContainer parent = grandparent.addChildWindow(); 527 final TestWindowContainer child = parent.addChildWindow(); 528 child.onRequestedOverrideConfigurationChanged(new Configuration()); 529 530 assertTrue(grandparent.mOnDescendantOverrideCalled); 531 } 532 533 @Test testRemoveChild()534 public void testRemoveChild() { 535 final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); 536 final TestWindowContainer root = builder.setLayer(0).build(); 537 final TestWindowContainer child1 = root.addChildWindow(); 538 final TestWindowContainer child2 = root.addChildWindow(); 539 final TestWindowContainer child11 = child1.addChildWindow(); 540 final TestWindowContainer child21 = child2.addChildWindow(); 541 542 assertTrue(root.hasChild(child2)); 543 assertTrue(root.hasChild(child21)); 544 root.removeChild(child2); 545 assertFalse(root.hasChild(child2)); 546 assertFalse(root.hasChild(child21)); 547 assertNull(child2.getParentWindow()); 548 549 boolean gotException = false; 550 assertTrue(root.hasChild(child11)); 551 try { 552 // Can only detach our direct children. 553 root.removeChild(child11); 554 } catch (IllegalArgumentException e) { 555 gotException = true; 556 } 557 assertTrue(gotException); 558 } 559 560 @Test testGetOrientation_childSpecified()561 public void testGetOrientation_childSpecified() { 562 testGetOrientation_childSpecifiedConfig(false, SCREEN_ORIENTATION_LANDSCAPE, 563 SCREEN_ORIENTATION_LANDSCAPE); 564 testGetOrientation_childSpecifiedConfig(false, SCREEN_ORIENTATION_UNSET, 565 SCREEN_ORIENTATION_UNSPECIFIED); 566 } 567 testGetOrientation_childSpecifiedConfig(boolean childVisible, int childOrientation, int expectedOrientation)568 private void testGetOrientation_childSpecifiedConfig(boolean childVisible, int childOrientation, 569 int expectedOrientation) { 570 final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); 571 final TestWindowContainer root = builder.setLayer(0).build(); 572 root.setFillsParent(true); 573 574 builder.setIsVisible(childVisible); 575 576 if (childOrientation != SCREEN_ORIENTATION_UNSET) { 577 builder.setOrientation(childOrientation); 578 } 579 580 final TestWindowContainer child1 = root.addChildWindow(builder); 581 child1.setFillsParent(true); 582 583 assertEquals(expectedOrientation, root.getOrientation()); 584 } 585 586 @Test testGetOrientation_Unset()587 public void testGetOrientation_Unset() { 588 final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); 589 final TestWindowContainer root = builder.setLayer(0).setIsVisible(true).build(); 590 // Unspecified well because we didn't specify anything... 591 assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, root.getOrientation()); 592 } 593 594 @Test testGetOrientation_InvisibleParentUnsetVisibleChildren()595 public void testGetOrientation_InvisibleParentUnsetVisibleChildren() { 596 final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); 597 final TestWindowContainer root = builder.setLayer(0).setIsVisible(true).build(); 598 599 builder.setIsVisible(false).setLayer(-1); 600 final TestWindowContainer invisible = root.addChildWindow(builder); 601 builder.setIsVisible(true).setLayer(-2); 602 final TestWindowContainer invisibleChild1VisibleAndSet = invisible.addChildWindow(builder); 603 invisibleChild1VisibleAndSet.setOrientation(SCREEN_ORIENTATION_LANDSCAPE); 604 // Landscape well because the container is visible and that is what we set on it above. 605 assertEquals(SCREEN_ORIENTATION_LANDSCAPE, invisibleChild1VisibleAndSet.getOrientation()); 606 // Landscape because even though the container isn't visible it has a child that is 607 // specifying it can influence the orientation by being visible. 608 assertEquals(SCREEN_ORIENTATION_LANDSCAPE, invisible.getOrientation()); 609 // Landscape because the grandchild is visible and therefore can participate. 610 assertEquals(SCREEN_ORIENTATION_LANDSCAPE, root.getOrientation()); 611 612 builder.setIsVisible(true).setLayer(-3); 613 final TestWindowContainer visibleUnset = root.addChildWindow(builder); 614 visibleUnset.setOrientation(SCREEN_ORIENTATION_UNSET); 615 assertEquals(SCREEN_ORIENTATION_UNSET, visibleUnset.getOrientation()); 616 assertEquals(SCREEN_ORIENTATION_LANDSCAPE, root.getOrientation()); 617 } 618 619 @Test testGetOrientation_setBehind()620 public void testGetOrientation_setBehind() { 621 final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); 622 final TestWindowContainer root = builder.setLayer(0).setIsVisible(true).build(); 623 624 builder.setIsVisible(true).setLayer(-1); 625 final TestWindowContainer visibleUnset = root.addChildWindow(builder); 626 visibleUnset.setOrientation(SCREEN_ORIENTATION_UNSET); 627 628 builder.setIsVisible(true).setLayer(-2); 629 final TestWindowContainer visibleUnsetChild1VisibleSetBehind = 630 visibleUnset.addChildWindow(builder); 631 visibleUnsetChild1VisibleSetBehind.setOrientation(SCREEN_ORIENTATION_BEHIND); 632 // Setting to visible behind will be used by the parents if there isn't another other 633 // container behind this one that has an orientation set. 634 assertEquals(SCREEN_ORIENTATION_BEHIND, 635 visibleUnsetChild1VisibleSetBehind.getOrientation()); 636 assertEquals(SCREEN_ORIENTATION_BEHIND, visibleUnset.getOrientation()); 637 assertEquals(SCREEN_ORIENTATION_BEHIND, root.getOrientation()); 638 } 639 640 @Test testGetOrientation_fillsParent()641 public void testGetOrientation_fillsParent() { 642 final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); 643 final TestWindowContainer root = builder.setLayer(0).setIsVisible(true).build(); 644 645 builder.setIsVisible(true).setLayer(-1); 646 final TestWindowContainer visibleUnset = root.addChildWindow(builder); 647 visibleUnset.setOrientation(SCREEN_ORIENTATION_BEHIND); 648 649 builder.setLayer(1).setIsVisible(true); 650 final TestWindowContainer visibleUnspecifiedRootChild = root.addChildWindow(builder); 651 visibleUnspecifiedRootChild.setFillsParent(false); 652 visibleUnspecifiedRootChild.setOrientation(SCREEN_ORIENTATION_UNSPECIFIED); 653 // Unset because the child doesn't fill the parent. May as well be invisible... 654 assertEquals(SCREEN_ORIENTATION_UNSET, visibleUnspecifiedRootChild.getOrientation()); 655 // The parent uses whatever orientation is set behind this container since it doesn't fill 656 // the parent. 657 assertEquals(SCREEN_ORIENTATION_BEHIND, root.getOrientation()); 658 659 // Test case of child filling its parent, but its parent isn't filling its own parent. 660 builder.setLayer(2).setIsVisible(true); 661 final TestWindowContainer visibleUnspecifiedRootChildChildFillsParent = 662 visibleUnspecifiedRootChild.addChildWindow(builder); 663 visibleUnspecifiedRootChildChildFillsParent.setOrientation(SCREEN_ORIENTATION_PORTRAIT); 664 assertEquals(SCREEN_ORIENTATION_PORTRAIT, 665 visibleUnspecifiedRootChildChildFillsParent.getOrientation()); 666 assertEquals(SCREEN_ORIENTATION_UNSET, visibleUnspecifiedRootChild.getOrientation()); 667 assertEquals(SCREEN_ORIENTATION_BEHIND, root.getOrientation()); 668 669 670 visibleUnspecifiedRootChild.setFillsParent(true); 671 assertEquals(SCREEN_ORIENTATION_PORTRAIT, visibleUnspecifiedRootChild.getOrientation()); 672 assertEquals(SCREEN_ORIENTATION_PORTRAIT, root.getOrientation()); 673 } 674 675 @Test testSetVisibleRequested()676 public void testSetVisibleRequested() { 677 final TestWindowContainer root = spy(new TestWindowContainerBuilder(mWm).setLayer( 678 0).build()); 679 assertThat(root.isVisibleRequested()).isFalse(); 680 final TestWindowContainerListener listener = new TestWindowContainerListener(); 681 root.registerWindowContainerListener(listener); 682 683 assertThat(root.setVisibleRequested(/* isVisible= */ false)).isFalse(); 684 assertThat(root.isVisibleRequested()).isFalse(); 685 686 assertThat(root.setVisibleRequested(/* isVisible= */ true)).isTrue(); 687 assertThat(root.isVisibleRequested()).isTrue(); 688 assertThat(listener.mIsVisibleRequested).isTrue(); 689 } 690 691 @Test testSetVisibleRequested_childRequestsVisible()692 public void testSetVisibleRequested_childRequestsVisible() { 693 final TestWindowContainer root = spy(new TestWindowContainerBuilder(mWm).setLayer( 694 0).build()); 695 final TestWindowContainer child1 = root.addChildWindow(); 696 assertThat(child1.isVisibleRequested()).isFalse(); 697 final TestWindowContainerListener listener = new TestWindowContainerListener(); 698 root.registerWindowContainerListener(listener); 699 700 // Hidden root and child request hidden. 701 assertThat(root.setVisibleRequested(/* isVisible= */ false)).isFalse(); 702 assertThat(listener.mIsVisibleRequested).isFalse(); 703 assertThat(child1.isVisibleRequested()).isFalse(); 704 705 // Child requests to be visible, so child and root request visible. 706 assertThat(child1.setVisibleRequested(/* isVisible= */ true)).isTrue(); 707 assertThat(root.isVisibleRequested()).isTrue(); 708 assertThat(listener.mIsVisibleRequested).isTrue(); 709 assertThat(child1.isVisibleRequested()).isTrue(); 710 // Visible request didn't change. 711 assertThat(child1.setVisibleRequested(/* isVisible= */ true)).isFalse(); 712 verify(root, times(2)).onChildVisibleRequestedChanged(child1); 713 } 714 715 @Test testSetVisibleRequested_childRequestsHidden()716 public void testSetVisibleRequested_childRequestsHidden() { 717 final TestWindowContainer root = spy(new TestWindowContainerBuilder(mWm).setLayer( 718 0).build()); 719 final TestWindowContainer child1 = root.addChildWindow(); 720 assertThat(child1.isVisibleRequested()).isFalse(); 721 final TestWindowContainerListener listener = new TestWindowContainerListener(); 722 root.registerWindowContainerListener(listener); 723 724 // Root and child requests visible. 725 assertThat(root.setVisibleRequested(/* isVisible= */ true)).isTrue(); 726 assertThat(listener.mIsVisibleRequested).isTrue(); 727 assertThat(child1.setVisibleRequested(/* isVisible= */ true)).isTrue(); 728 assertThat(child1.isVisibleRequested()).isTrue(); 729 730 // Child requests hidden, so child and root request hidden. 731 assertThat(child1.setVisibleRequested(/* isVisible= */ false)).isTrue(); 732 assertThat(root.isVisibleRequested()).isFalse(); 733 assertThat(listener.mIsVisibleRequested).isFalse(); 734 assertThat(child1.isVisibleRequested()).isFalse(); 735 // Visible request didn't change. 736 assertThat(child1.setVisibleRequested(/* isVisible= */ false)).isFalse(); 737 verify(root, times(3)).onChildVisibleRequestedChanged(child1); 738 } 739 740 @Test testOnChildVisibleRequestedChanged_bothVisible()741 public void testOnChildVisibleRequestedChanged_bothVisible() { 742 final TestWindowContainer root = spy(new TestWindowContainerBuilder(mWm).setLayer( 743 0).build()); 744 final TestWindowContainer child1 = root.addChildWindow(); 745 746 // Child and root request visible. 747 assertThat(root.setVisibleRequested(/* isVisible= */ true)).isTrue(); 748 assertThat(child1.setVisibleRequested(/* isVisible= */ true)).isTrue(); 749 750 // Visible request already updated on root when child requested. 751 assertThat(root.onChildVisibleRequestedChanged(child1)).isFalse(); 752 } 753 754 @Test testOnChildVisibleRequestedChanged_childVisible()755 public void testOnChildVisibleRequestedChanged_childVisible() { 756 final TestWindowContainer root = spy(new TestWindowContainerBuilder(mWm).setLayer( 757 0).build()); 758 final TestWindowContainer child1 = root.addChildWindow(); 759 760 assertThat(root.setVisibleRequested(/* isVisible= */ false)).isFalse(); 761 assertThat(child1.setVisibleRequested(/* isVisible= */ true)).isTrue(); 762 763 // Visible request already updated on root when child requested. 764 assertThat(root.onChildVisibleRequestedChanged(child1)).isFalse(); 765 } 766 767 @Test testOnChildVisibleRequestedChanged_childHidden()768 public void testOnChildVisibleRequestedChanged_childHidden() { 769 final TestWindowContainer root = spy(new TestWindowContainerBuilder(mWm).setLayer( 770 0).build()); 771 final TestWindowContainer child1 = root.addChildWindow(); 772 773 assertThat(root.setVisibleRequested(/* isVisible= */ false)).isFalse(); 774 assertThat(child1.setVisibleRequested(/* isVisible= */ false)).isFalse(); 775 776 // Visible request did not change. 777 assertThat(root.onChildVisibleRequestedChanged(child1)).isFalse(); 778 } 779 780 @Test testSetOrientation()781 public void testSetOrientation() { 782 final TestWindowContainer root = spy(new TestWindowContainerBuilder(mWm).build()); 783 final TestWindowContainer child = spy(root.addChildWindow()); 784 doReturn(true).when(root).handlesOrientationChangeFromDescendant(anyInt()); 785 child.getWindowConfiguration().setWindowingMode(WINDOWING_MODE_FULLSCREEN); 786 child.setOrientation(SCREEN_ORIENTATION_PORTRAIT); 787 // The ancestor should decide whether to dispatch the configuration change. 788 verify(child, never()).onConfigurationChanged(any()); 789 790 doReturn(false).when(root).handlesOrientationChangeFromDescendant(anyInt()); 791 child.setOrientation(SCREEN_ORIENTATION_LANDSCAPE); 792 // The ancestor doesn't handle the request so the descendant applies the change directly. 793 verify(child).onConfigurationChanged(any()); 794 } 795 796 @Test testCompareTo()797 public void testCompareTo() { 798 final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); 799 final TestWindowContainer root = builder.setLayer(0).build(); 800 801 final TestWindowContainer child1 = root.addChildWindow(); 802 final TestWindowContainer child11 = child1.addChildWindow(); 803 final TestWindowContainer child12 = child1.addChildWindow(); 804 805 final TestWindowContainer child2 = root.addChildWindow(); 806 final TestWindowContainer child21 = child2.addChildWindow(); 807 final TestWindowContainer child22 = child2.addChildWindow(); 808 final TestWindowContainer child222 = child22.addChildWindow(); 809 final TestWindowContainer child223 = child22.addChildWindow(); 810 final TestWindowContainer child2221 = child222.addChildWindow(); 811 final TestWindowContainer child2222 = child222.addChildWindow(); 812 final TestWindowContainer child2223 = child222.addChildWindow(); 813 814 final TestWindowContainer root2 = builder.setLayer(0).build(); 815 816 assertEquals(0, root.compareTo(root)); 817 assertEquals(-1, child1.compareTo(child2)); 818 assertEquals(1, child2.compareTo(child1)); 819 820 boolean inTheSameTree = true; 821 try { 822 root.compareTo(root2); 823 } catch (IllegalArgumentException e) { 824 inTheSameTree = false; 825 } 826 assertFalse(inTheSameTree); 827 828 assertEquals(-1, child1.compareTo(child11)); 829 assertEquals(1, child21.compareTo(root)); 830 assertEquals(1, child21.compareTo(child12)); 831 assertEquals(-1, child11.compareTo(child2)); 832 assertEquals(1, child2221.compareTo(child11)); 833 assertEquals(-1, child2222.compareTo(child223)); 834 assertEquals(1, child2223.compareTo(child21)); 835 } 836 837 @Test testPrefixOrderIndex()838 public void testPrefixOrderIndex() { 839 final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); 840 final TestWindowContainer root = builder.build(); 841 842 final TestWindowContainer child1 = root.addChildWindow(); 843 844 final TestWindowContainer child11 = child1.addChildWindow(); 845 final TestWindowContainer child12 = child1.addChildWindow(); 846 847 final TestWindowContainer child2 = root.addChildWindow(); 848 849 final TestWindowContainer child21 = child2.addChildWindow(); 850 final TestWindowContainer child22 = child2.addChildWindow(); 851 852 final TestWindowContainer child221 = child22.addChildWindow(); 853 final TestWindowContainer child222 = child22.addChildWindow(); 854 final TestWindowContainer child223 = child22.addChildWindow(); 855 856 final TestWindowContainer child23 = child2.addChildWindow(); 857 858 assertEquals(0, root.getPrefixOrderIndex()); 859 assertEquals(1, child1.getPrefixOrderIndex()); 860 assertEquals(2, child11.getPrefixOrderIndex()); 861 assertEquals(3, child12.getPrefixOrderIndex()); 862 assertEquals(4, child2.getPrefixOrderIndex()); 863 assertEquals(5, child21.getPrefixOrderIndex()); 864 assertEquals(6, child22.getPrefixOrderIndex()); 865 assertEquals(7, child221.getPrefixOrderIndex()); 866 assertEquals(8, child222.getPrefixOrderIndex()); 867 assertEquals(9, child223.getPrefixOrderIndex()); 868 assertEquals(10, child23.getPrefixOrderIndex()); 869 } 870 871 @Test testPrefixOrder_addEntireSubtree()872 public void testPrefixOrder_addEntireSubtree() { 873 final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); 874 final TestWindowContainer root = builder.build(); 875 final TestWindowContainer subtree = builder.build(); 876 final TestWindowContainer subtree2 = builder.build(); 877 878 final TestWindowContainer child1 = subtree.addChildWindow(); 879 final TestWindowContainer child11 = child1.addChildWindow(); 880 final TestWindowContainer child2 = subtree2.addChildWindow(); 881 final TestWindowContainer child3 = subtree2.addChildWindow(); 882 subtree.addChild(subtree2, 1); 883 root.addChild(subtree, 0); 884 885 assertEquals(0, root.getPrefixOrderIndex()); 886 assertEquals(1, subtree.getPrefixOrderIndex()); 887 assertEquals(2, child1.getPrefixOrderIndex()); 888 assertEquals(3, child11.getPrefixOrderIndex()); 889 assertEquals(4, subtree2.getPrefixOrderIndex()); 890 assertEquals(5, child2.getPrefixOrderIndex()); 891 assertEquals(6, child3.getPrefixOrderIndex()); 892 } 893 894 @Test testPrefixOrder_remove()895 public void testPrefixOrder_remove() { 896 final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); 897 final TestWindowContainer root = builder.build(); 898 899 final TestWindowContainer child1 = root.addChildWindow(); 900 901 final TestWindowContainer child11 = child1.addChildWindow(); 902 final TestWindowContainer child12 = child1.addChildWindow(); 903 904 final TestWindowContainer child2 = root.addChildWindow(); 905 906 assertEquals(0, root.getPrefixOrderIndex()); 907 assertEquals(1, child1.getPrefixOrderIndex()); 908 assertEquals(2, child11.getPrefixOrderIndex()); 909 assertEquals(3, child12.getPrefixOrderIndex()); 910 assertEquals(4, child2.getPrefixOrderIndex()); 911 912 root.removeChild(child1); 913 914 assertEquals(1, child2.getPrefixOrderIndex()); 915 } 916 917 /** 918 * Ensure children of a {@link WindowContainer} do not have 919 * {@link WindowContainer#onParentResize()} called when {@link WindowContainer#onParentResize()} 920 * is invoked with overridden bounds. 921 */ 922 @Test testOnParentResizePropagation()923 public void testOnParentResizePropagation() { 924 final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); 925 final TestWindowContainer root = builder.build(); 926 927 final TestWindowContainer child = root.addChildWindow(); 928 child.setBounds(new Rect(1, 1, 2, 2)); 929 930 final TestWindowContainer grandChild = mock(TestWindowContainer.class); 931 932 child.addChildWindow(grandChild); 933 root.onResize(); 934 935 // Make sure the child does not propagate resize through onParentResize when bounds are set. 936 verify(grandChild, never()).onParentResize(); 937 938 child.removeChild(grandChild); 939 940 child.setBounds(null); 941 child.addChildWindow(grandChild); 942 root.onResize(); 943 944 // Make sure the child propagates resize through onParentResize when no bounds set. 945 verify(grandChild, times(1)).onParentResize(); 946 } 947 948 @Test testOnDescendantOrientationRequestChangedPropagation()949 public void testOnDescendantOrientationRequestChangedPropagation() { 950 final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); 951 final TestWindowContainer root = spy(builder.build()); 952 953 final ActivityRecord activityRecord = mock(ActivityRecord.class); 954 final TestWindowContainer child = root.addChildWindow(); 955 956 child.setOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED, activityRecord); 957 verify(root).onDescendantOrientationChanged(activityRecord); 958 } 959 960 @Test testHandlesOrientationChangeFromDescendantProgation()961 public void testHandlesOrientationChangeFromDescendantProgation() { 962 final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); 963 final TestWindowContainer root = spy(builder.build()); 964 965 // We use an orientation that is not an exception for the ignoreOrientationRequest flag 966 final int orientation = SCREEN_ORIENTATION_PORTRAIT; 967 968 final TestWindowContainer child = root.addChildWindow(); 969 assertFalse(child.handlesOrientationChangeFromDescendant(orientation)); 970 971 Mockito.doReturn(true).when(root).handlesOrientationChangeFromDescendant(anyInt()); 972 assertTrue(child.handlesOrientationChangeFromDescendant(orientation)); 973 } 974 975 @Test testOnDisplayChanged()976 public void testOnDisplayChanged() { 977 final Task rootTask = createTask(mDisplayContent); 978 final Task task = createTaskInRootTask(rootTask, 0 /* userId */); 979 final ActivityRecord activity = createActivityRecord(mDisplayContent, task); 980 981 final DisplayContent newDc = createNewDisplay(); 982 rootTask.getDisplayArea().removeRootTask(rootTask); 983 newDc.getDefaultTaskDisplayArea().addChild(rootTask, POSITION_TOP); 984 985 verify(rootTask).onDisplayChanged(newDc); 986 verify(task).onDisplayChanged(newDc); 987 verify(activity).onDisplayChanged(newDc); 988 assertEquals(newDc, rootTask.mDisplayContent); 989 assertEquals(newDc, task.mDisplayContent); 990 assertEquals(newDc, activity.mDisplayContent); 991 } 992 993 @Test testOnDisplayChanged_cleanupChanging()994 public void testOnDisplayChanged_cleanupChanging() { 995 final Task task = createTask(mDisplayContent); 996 spyOn(task.mSurfaceFreezer); 997 mDisplayContent.mChangingContainers.add(task); 998 999 // Don't remove the changing transition of this window when it is still the old display. 1000 // This happens on display info changed. 1001 task.onDisplayChanged(mDisplayContent); 1002 1003 assertTrue(mDisplayContent.mChangingContainers.contains(task)); 1004 verify(task.mSurfaceFreezer, never()).unfreeze(any()); 1005 1006 // Remove the changing transition of this window when it is moved or reparented from the old 1007 // display. 1008 final DisplayContent newDc = createNewDisplay(); 1009 task.onDisplayChanged(newDc); 1010 1011 assertFalse(mDisplayContent.mChangingContainers.contains(task)); 1012 verify(task.mSurfaceFreezer).unfreeze(any()); 1013 } 1014 1015 @Test testHandleCompleteDeferredRemoval()1016 public void testHandleCompleteDeferredRemoval() { 1017 final DisplayContent displayContent = createNewDisplay(); 1018 // Do not reparent activity to default display when removing the display. 1019 doReturn(true).when(displayContent).shouldDestroyContentOnRemove(); 1020 1021 // An animating window with mRemoveOnExit can be removed by handleCompleteDeferredRemoval 1022 // once it no longer animates. 1023 final WindowState exitingWindow = createWindow(null, TYPE_APPLICATION_OVERLAY, 1024 displayContent, "exiting window"); 1025 exitingWindow.startAnimation(exitingWindow.getPendingTransaction(), 1026 mock(AnimationAdapter.class), false /* hidden */, 1027 SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION); 1028 exitingWindow.mRemoveOnExit = true; 1029 exitingWindow.handleCompleteDeferredRemoval(); 1030 // The animation has not finished so the window is not removed. 1031 assertTrue(exitingWindow.isAnimating()); 1032 assertTrue(exitingWindow.isAttached()); 1033 exitingWindow.cancelAnimation(); 1034 // The window is removed because the animation is gone. 1035 exitingWindow.handleCompleteDeferredRemoval(); 1036 assertFalse(exitingWindow.isAttached()); 1037 1038 final ActivityRecord r = new TaskBuilder(mSupervisor).setCreateActivity(true) 1039 .setDisplay(displayContent).build().getTopMostActivity(); 1040 // Add a window and make the activity animating so the removal of activity is deferred. 1041 createWindow(null, TYPE_BASE_APPLICATION, r, "win"); 1042 doReturn(true).when(r).isAnimating(anyInt(), anyInt()); 1043 1044 displayContent.remove(); 1045 // Ensure that ActivityRecord#onRemovedFromDisplay is called. 1046 r.destroyed("test"); 1047 // The removal is deferred, so the activity is still in the display. 1048 assertEquals(r, displayContent.getTopMostActivity()); 1049 1050 // Assume the animation is done so the deferred removal can continue. 1051 doReturn(false).when(r).isAnimating(anyInt(), anyInt()); 1052 1053 assertFalse(displayContent.handleCompleteDeferredRemoval()); 1054 assertFalse(displayContent.hasChild()); 1055 assertFalse(r.hasChild()); 1056 } 1057 1058 @Test testTaskCanApplyAnimation()1059 public void testTaskCanApplyAnimation() { 1060 final Task rootTask = createTask(mDisplayContent); 1061 final Task task = createTaskInRootTask(rootTask, 0 /* userId */); 1062 final ActivityRecord activity2 = createActivityRecord(mDisplayContent, task); 1063 final ActivityRecord activity1 = createActivityRecord(mDisplayContent, task); 1064 verifyWindowContainerApplyAnimation(task, activity1, activity2); 1065 } 1066 1067 @Test testRootTaskCanApplyAnimation()1068 public void testRootTaskCanApplyAnimation() { 1069 final Task rootTask = createTask(mDisplayContent); 1070 final ActivityRecord activity2 = createActivityRecord(mDisplayContent, 1071 createTaskInRootTask(rootTask, 0 /* userId */)); 1072 final ActivityRecord activity1 = createActivityRecord(mDisplayContent, 1073 createTaskInRootTask(rootTask, 0 /* userId */)); 1074 verifyWindowContainerApplyAnimation(rootTask, activity1, activity2); 1075 } 1076 1077 @Test testGetDisplayArea()1078 public void testGetDisplayArea() { 1079 // WindowContainer 1080 final WindowContainer windowContainer = new WindowContainer(mWm); 1081 1082 assertNull(windowContainer.getDisplayArea()); 1083 1084 // Task > WindowContainer 1085 final Task task = createTask(mDisplayContent); 1086 task.addChild(windowContainer, 0); 1087 task.setParent(null); 1088 1089 assertNull(windowContainer.getDisplayArea()); 1090 assertNull(task.getDisplayArea()); 1091 1092 // TaskDisplayArea > Task > WindowContainer 1093 final TaskDisplayArea taskDisplayArea = new TaskDisplayArea( 1094 mDisplayContent, mWm, "TaskDisplayArea", FEATURE_DEFAULT_TASK_CONTAINER); 1095 taskDisplayArea.addChild(task, 0); 1096 1097 assertEquals(taskDisplayArea, windowContainer.getDisplayArea()); 1098 assertEquals(taskDisplayArea, task.getDisplayArea()); 1099 assertEquals(taskDisplayArea, taskDisplayArea.getDisplayArea()); 1100 1101 // DisplayArea 1102 final DisplayArea displayArea = new DisplayArea(mWm, ANY, "DisplayArea"); 1103 1104 assertEquals(displayArea, displayArea.getDisplayArea()); 1105 } 1106 verifyWindowContainerApplyAnimation(WindowContainer wc, ActivityRecord act, ActivityRecord act2)1107 private void verifyWindowContainerApplyAnimation(WindowContainer wc, ActivityRecord act, 1108 ActivityRecord act2) { 1109 // Initial remote animation for app transition. 1110 final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter( 1111 new IRemoteAnimationRunner.Stub() { 1112 @Override 1113 public void onAnimationStart(@WindowManager.TransitionOldType int transit, 1114 RemoteAnimationTarget[] apps, 1115 RemoteAnimationTarget[] wallpapers, 1116 RemoteAnimationTarget[] nonApps, 1117 IRemoteAnimationFinishedCallback finishedCallback) { 1118 try { 1119 finishedCallback.onAnimationFinished(); 1120 } catch (RemoteException e) { 1121 e.printStackTrace(); 1122 } 1123 } 1124 1125 @Override 1126 public void onAnimationCancelled() { 1127 } 1128 }, 0, 0, false); 1129 adapter.setCallingPidUid(123, 456); 1130 wc.getDisplayContent().prepareAppTransition(TRANSIT_OPEN); 1131 wc.getDisplayContent().mAppTransition.overridePendingAppTransitionRemote(adapter); 1132 spyOn(wc); 1133 doReturn(true).when(wc).okToAnimate(); 1134 1135 // Make sure animating state is as expected after applied animation. 1136 1137 // Animation target is promoted from act to wc. act2 is a descendant of wc, but not a source 1138 // of the animation. 1139 ArrayList<WindowContainer<WindowState>> sources = new ArrayList<>(); 1140 sources.add(act); 1141 assertTrue(wc.applyAnimation(null, TRANSIT_OLD_TASK_OPEN, true, false, sources)); 1142 1143 assertEquals(act, wc.getTopMostActivity()); 1144 assertTrue(wc.isAnimating()); 1145 assertTrue(wc.isAnimating(0, ANIMATION_TYPE_APP_TRANSITION)); 1146 assertTrue(wc.getAnimationSources().contains(act)); 1147 assertFalse(wc.getAnimationSources().contains(act2)); 1148 assertTrue(act.isAnimating(PARENTS)); 1149 assertTrue(act.isAnimating(PARENTS, ANIMATION_TYPE_APP_TRANSITION)); 1150 assertEquals(wc, act.getAnimatingContainer(PARENTS, ANIMATION_TYPE_APP_TRANSITION)); 1151 1152 // Make sure animation finish callback will be received and reset animating state after 1153 // animation finish. 1154 wc.getDisplayContent().mAppTransition.goodToGo(TRANSIT_OLD_TASK_OPEN, act); 1155 verify(wc).onAnimationFinished(eq(ANIMATION_TYPE_APP_TRANSITION), any()); 1156 assertFalse(wc.isAnimating()); 1157 assertFalse(act.isAnimating(PARENTS)); 1158 } 1159 1160 @Test testRegisterWindowContainerListener()1161 public void testRegisterWindowContainerListener() { 1162 final WindowContainer container = new WindowContainer(mWm); 1163 container.mDisplayContent = mDisplayContent; 1164 final TestWindowContainerListener listener = new TestWindowContainerListener(); 1165 Configuration config = container.getConfiguration(); 1166 Rect bounds = new Rect(0, 0, 10, 10); 1167 config.windowConfiguration.setBounds(bounds); 1168 config.densityDpi = 100; 1169 container.onRequestedOverrideConfigurationChanged(config); 1170 container.registerWindowContainerListener(listener); 1171 1172 assertEquals(mDisplayContent, listener.mDisplayContent); 1173 assertEquals(bounds, listener.mConfiguration.windowConfiguration.getBounds()); 1174 assertEquals(100, listener.mConfiguration.densityDpi); 1175 1176 container.onDisplayChanged(mDefaultDisplay); 1177 assertEquals(listener.mDisplayContent, mDefaultDisplay); 1178 1179 config = new Configuration(); 1180 bounds = new Rect(0, 0, 20, 20); 1181 config.windowConfiguration.setBounds(bounds); 1182 config.densityDpi = 200; 1183 1184 container.onRequestedOverrideConfigurationChanged(config); 1185 1186 assertEquals(bounds, listener.mConfiguration.windowConfiguration.getBounds()); 1187 assertEquals(200, listener.mConfiguration.densityDpi); 1188 } 1189 1190 @Test testFreezeInsets()1191 public void testFreezeInsets() { 1192 final Task task = createTask(mDisplayContent); 1193 final ActivityRecord activity = createActivityRecord(mDisplayContent, task); 1194 final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, activity, "win"); 1195 1196 // Set visibility to false, verify the main window of the task will be set the frozen 1197 // insets state immediately. 1198 activity.setVisibility(false); 1199 assertNotNull(win.getFrozenInsetsState()); 1200 1201 // Now make it visible again, verify that the insets are immediately unfrozen. 1202 activity.setVisibility(true); 1203 assertNull(win.getFrozenInsetsState()); 1204 } 1205 1206 @Test testFreezeInsetsStateWhenAppTransition()1207 public void testFreezeInsetsStateWhenAppTransition() { 1208 final Task rootTask = createTask(mDisplayContent); 1209 final Task task = createTaskInRootTask(rootTask, 0 /* userId */); 1210 final ActivityRecord activity = createActivityRecord(mDisplayContent, task); 1211 final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, activity, "win"); 1212 task.getDisplayContent().prepareAppTransition(TRANSIT_CLOSE); 1213 spyOn(win); 1214 doReturn(true).when(task).okToAnimate(); 1215 ArrayList<WindowContainer> sources = new ArrayList<>(); 1216 sources.add(activity); 1217 1218 // Simulate the task applying the exit transition, verify the main window of the task 1219 // will be set the frozen insets state before the animation starts 1220 activity.setVisibility(false); 1221 task.applyAnimation(null, TRANSIT_OLD_TASK_CLOSE, false /* enter */, 1222 false /* isVoiceInteraction */, sources); 1223 verify(win).freezeInsetsState(); 1224 1225 // Simulate the task transition finished. 1226 activity.commitVisibility(false, false); 1227 task.onAnimationFinished(ANIMATION_TYPE_APP_TRANSITION, 1228 task.mSurfaceAnimator.getAnimation()); 1229 1230 // Now make it visible again, verify that the insets are immediately unfrozen even before 1231 // transition starts. 1232 activity.setVisibility(true); 1233 verify(win).clearFrozenInsetsState(); 1234 } 1235 1236 @Test testAssignRelativeLayer()1237 public void testAssignRelativeLayer() { 1238 final WindowContainer container = new WindowContainer(mWm); 1239 container.mSurfaceControl = mock(SurfaceControl.class); 1240 final SurfaceAnimator surfaceAnimator = container.mSurfaceAnimator; 1241 final SurfaceControl relativeParent = mock(SurfaceControl.class); 1242 final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class); 1243 spyOn(container); 1244 spyOn(surfaceAnimator); 1245 1246 // Trigger for first relative layer call. 1247 container.assignRelativeLayer(t, relativeParent, 1 /* layer */); 1248 verify(surfaceAnimator).setRelativeLayer(t, relativeParent, 1 /* layer */); 1249 1250 // Not trigger for the same relative layer call. 1251 clearInvocations(surfaceAnimator); 1252 container.assignRelativeLayer(t, relativeParent, 1 /* layer */); 1253 verify(surfaceAnimator, never()).setRelativeLayer(t, relativeParent, 1 /* layer */); 1254 1255 // Trigger for the same relative layer call if forceUpdate=true 1256 container.assignRelativeLayer(t, relativeParent, 1 /* layer */, true /* forceUpdate */); 1257 verify(surfaceAnimator).setRelativeLayer(t, relativeParent, 1 /* layer */); 1258 } 1259 1260 @Test testAssignAnimationLayer()1261 public void testAssignAnimationLayer() { 1262 final WindowContainer container = new WindowContainer(mWm); 1263 container.mSurfaceControl = mock(SurfaceControl.class); 1264 final SurfaceAnimator surfaceAnimator = container.mSurfaceAnimator; 1265 final SurfaceFreezer surfaceFreezer = container.mSurfaceFreezer; 1266 final SurfaceControl relativeParent = mock(SurfaceControl.class); 1267 final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class); 1268 spyOn(container); 1269 spyOn(surfaceAnimator); 1270 spyOn(surfaceFreezer); 1271 1272 container.setLayer(t, 1); 1273 container.setRelativeLayer(t, relativeParent, 2); 1274 1275 // Set through surfaceAnimator if surfaceFreezer doesn't have leash. 1276 verify(surfaceAnimator).setLayer(t, 1); 1277 verify(surfaceAnimator).setRelativeLayer(t, relativeParent, 2); 1278 verify(surfaceFreezer, never()).setLayer(any(), anyInt()); 1279 verify(surfaceFreezer, never()).setRelativeLayer(any(), any(), anyInt()); 1280 1281 clearInvocations(surfaceAnimator); 1282 clearInvocations(surfaceFreezer); 1283 doReturn(true).when(surfaceFreezer).hasLeash(); 1284 1285 container.setLayer(t, 1); 1286 container.setRelativeLayer(t, relativeParent, 2); 1287 1288 // Set through surfaceFreezer if surfaceFreezer has leash. 1289 verify(surfaceFreezer).setLayer(t, 1); 1290 verify(surfaceFreezer).setRelativeLayer(t, relativeParent, 2); 1291 verify(surfaceAnimator, never()).setLayer(any(), anyInt()); 1292 verify(surfaceAnimator, never()).setRelativeLayer(any(), any(), anyInt()); 1293 } 1294 1295 @Test testStartChangeTransitionWhenPreviousIsNotFinished()1296 public void testStartChangeTransitionWhenPreviousIsNotFinished() { 1297 final WindowContainer container = createTaskFragmentWithActivity( 1298 createTask(mDisplayContent)); 1299 container.mSurfaceControl = mock(SurfaceControl.class); 1300 final SurfaceAnimator surfaceAnimator = container.mSurfaceAnimator; 1301 final SurfaceFreezer surfaceFreezer = container.mSurfaceFreezer; 1302 final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class); 1303 spyOn(container); 1304 spyOn(surfaceAnimator); 1305 mockSurfaceFreezerSnapshot(surfaceFreezer); 1306 doReturn(t).when(container).getPendingTransaction(); 1307 doReturn(t).when(container).getSyncTransaction(); 1308 1309 // Leash and snapshot created for change transition. 1310 container.initializeChangeTransition(new Rect(0, 0, 1000, 2000)); 1311 1312 assertNotNull(surfaceFreezer.mLeash); 1313 assertNotNull(surfaceFreezer.mSnapshot); 1314 assertEquals(surfaceFreezer.mLeash, container.getAnimationLeash()); 1315 1316 // Start animation: surfaceAnimator take over the leash and snapshot from surfaceFreezer. 1317 container.applyAnimationUnchecked(null /* lp */, true /* enter */, 1318 TRANSIT_OLD_TASK_FRAGMENT_CHANGE, false /* isVoiceInteraction */, 1319 null /* sources */); 1320 1321 assertNull(surfaceFreezer.mLeash); 1322 assertNull(surfaceFreezer.mSnapshot); 1323 assertNotNull(surfaceAnimator.mLeash); 1324 assertNotNull(surfaceAnimator.mSnapshot); 1325 final SurfaceControl prevLeash = surfaceAnimator.mLeash; 1326 final SurfaceFreezer.Snapshot prevSnapshot = surfaceAnimator.mSnapshot; 1327 1328 // Prepare another change transition. 1329 container.initializeChangeTransition(new Rect(0, 0, 1000, 2000)); 1330 1331 assertNotNull(surfaceFreezer.mLeash); 1332 assertNotNull(surfaceFreezer.mSnapshot); 1333 assertEquals(surfaceFreezer.mLeash, container.getAnimationLeash()); 1334 assertNotEquals(prevLeash, container.getAnimationLeash()); 1335 1336 // Start another animation before the previous one is finished, it should reset the previous 1337 // one, but not change the current one. 1338 container.applyAnimationUnchecked(null /* lp */, true /* enter */, 1339 TRANSIT_OLD_TASK_FRAGMENT_CHANGE, false /* isVoiceInteraction */, 1340 null /* sources */); 1341 1342 verify(container, never()).onAnimationLeashLost(any()); 1343 verify(surfaceFreezer, never()).unfreeze(any()); 1344 assertNotNull(surfaceAnimator.mLeash); 1345 assertNotNull(surfaceAnimator.mSnapshot); 1346 assertEquals(surfaceAnimator.mLeash, container.getAnimationLeash()); 1347 assertNotEquals(prevLeash, surfaceAnimator.mLeash); 1348 assertNotEquals(prevSnapshot, surfaceAnimator.mSnapshot); 1349 1350 // Clean up after animation finished. 1351 surfaceAnimator.mInnerAnimationFinishedCallback.onAnimationFinished( 1352 ANIMATION_TYPE_APP_TRANSITION, surfaceAnimator.getAnimation()); 1353 1354 verify(container).onAnimationLeashLost(any()); 1355 assertNull(surfaceAnimator.mLeash); 1356 assertNull(surfaceAnimator.mSnapshot); 1357 } 1358 1359 @Test testUnfreezeWindow_removeWindowFromChanging()1360 public void testUnfreezeWindow_removeWindowFromChanging() { 1361 final WindowContainer container = createTaskFragmentWithActivity( 1362 createTask(mDisplayContent)); 1363 mockSurfaceFreezerSnapshot(container.mSurfaceFreezer); 1364 final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class); 1365 1366 container.initializeChangeTransition(new Rect(0, 0, 1000, 2000)); 1367 1368 assertTrue(mDisplayContent.mChangingContainers.contains(container)); 1369 1370 container.mSurfaceFreezer.unfreeze(t); 1371 1372 assertFalse(mDisplayContent.mChangingContainers.contains(container)); 1373 } 1374 1375 @Test testFailToTaskSnapshot_unfreezeWindow()1376 public void testFailToTaskSnapshot_unfreezeWindow() { 1377 final WindowContainer container = createTaskFragmentWithActivity( 1378 createTask(mDisplayContent)); 1379 final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class); 1380 spyOn(container.mSurfaceFreezer); 1381 1382 container.initializeChangeTransition(new Rect(0, 0, 1000, 2000)); 1383 1384 verify(container.mSurfaceFreezer).freeze(any(), any(), any(), any()); 1385 verify(container.mSurfaceFreezer).unfreeze(any()); 1386 assertTrue(mDisplayContent.mChangingContainers.isEmpty()); 1387 } 1388 1389 @Test testRemoveUnstartedFreezeSurfaceWhenFreezeAgain()1390 public void testRemoveUnstartedFreezeSurfaceWhenFreezeAgain() { 1391 final WindowContainer container = createTaskFragmentWithActivity( 1392 createTask(mDisplayContent)); 1393 container.mSurfaceControl = mock(SurfaceControl.class); 1394 final SurfaceFreezer surfaceFreezer = container.mSurfaceFreezer; 1395 mockSurfaceFreezerSnapshot(surfaceFreezer); 1396 final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class); 1397 spyOn(container); 1398 doReturn(t).when(container).getPendingTransaction(); 1399 doReturn(t).when(container).getSyncTransaction(); 1400 1401 // Leash and snapshot created for change transition. 1402 container.initializeChangeTransition(new Rect(0, 0, 1000, 2000)); 1403 1404 assertNotNull(surfaceFreezer.mLeash); 1405 assertNotNull(surfaceFreezer.mSnapshot); 1406 1407 final SurfaceControl prevLeash = surfaceFreezer.mLeash; 1408 final SurfaceFreezer.Snapshot prevSnapshot = surfaceFreezer.mSnapshot; 1409 spyOn(prevSnapshot); 1410 1411 container.initializeChangeTransition(new Rect(0, 0, 1500, 2500)); 1412 1413 verify(t).remove(prevLeash); 1414 verify(prevSnapshot).destroy(t); 1415 } 1416 1417 @Test testAddLocalInsetsFrameProvider()1418 public void testAddLocalInsetsFrameProvider() { 1419 /* 1420 ___ rootTask _______________________________________________ 1421 | | | | 1422 activity0 container navigationBarInsetsProvider1 navigationBarInsetsProvider2 1423 / \ 1424 activity1 activity2 1425 */ 1426 final Task rootTask = createTask(mDisplayContent); 1427 1428 final ActivityRecord activity0 = createActivityRecord(mDisplayContent, 1429 createTaskInRootTask(rootTask, 0 /* userId */)); 1430 final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams( 1431 TYPE_BASE_APPLICATION); 1432 attrs.setTitle("AppWindow0"); 1433 activity0.addWindow(createWindowState(attrs, activity0)); 1434 1435 final Task container = createTaskInRootTask(rootTask, 0); 1436 final ActivityRecord activity1 = createActivityRecord(mDisplayContent, 1437 createTaskInRootTask(container, 0 /* userId */)); 1438 final WindowManager.LayoutParams attrs1 = new WindowManager.LayoutParams( 1439 TYPE_BASE_APPLICATION); 1440 attrs1.setTitle("AppWindow1"); 1441 activity1.addWindow(createWindowState(attrs1, activity1)); 1442 1443 final ActivityRecord activity2 = createActivityRecord(mDisplayContent, 1444 createTaskInRootTask(container, 0 /* userId */)); 1445 final WindowManager.LayoutParams attrs2 = new WindowManager.LayoutParams( 1446 TYPE_BASE_APPLICATION); 1447 attrs2.setTitle("AppWindow2"); 1448 activity2.addWindow(createWindowState(attrs2, activity2)); 1449 final Binder owner = new Binder(); 1450 Rect genericOverlayInsetsRect1 = new Rect(0, 200, 1080, 700); 1451 Rect genericOverlayInsetsRect2 = new Rect(0, 0, 1080, 200); 1452 final InsetsFrameProvider provider1 = 1453 new InsetsFrameProvider(owner, 1, WindowInsets.Type.systemOverlays()) 1454 .setArbitraryRectangle(genericOverlayInsetsRect1); 1455 final InsetsFrameProvider provider2 = 1456 new InsetsFrameProvider(owner, 2, WindowInsets.Type.systemOverlays()) 1457 .setArbitraryRectangle(genericOverlayInsetsRect2); 1458 final int sourceId1 = provider1.getId(); 1459 final int sourceId2 = provider2.getId(); 1460 1461 rootTask.addLocalInsetsFrameProvider(provider1, owner); 1462 container.addLocalInsetsFrameProvider(provider2, owner); 1463 1464 InsetsSource genericOverlayInsetsProvider1Source = new InsetsSource( 1465 sourceId1, systemOverlays()); 1466 genericOverlayInsetsProvider1Source.setFrame(genericOverlayInsetsRect1); 1467 genericOverlayInsetsProvider1Source.setVisible(true); 1468 InsetsSource genericOverlayInsetsProvider2Source = new InsetsSource( 1469 sourceId2, systemOverlays()); 1470 genericOverlayInsetsProvider2Source.setFrame(genericOverlayInsetsRect2); 1471 genericOverlayInsetsProvider2Source.setVisible(true); 1472 1473 activity0.forAllWindows(window -> { 1474 assertEquals(genericOverlayInsetsRect1, 1475 window.getInsetsState().peekSource(sourceId1).getFrame()); 1476 assertEquals(null, 1477 window.getInsetsState().peekSource(sourceId2)); 1478 }, true); 1479 activity1.forAllWindows(window -> { 1480 assertEquals(genericOverlayInsetsRect1, 1481 window.getInsetsState().peekSource(sourceId1).getFrame()); 1482 assertEquals(genericOverlayInsetsRect2, 1483 window.getInsetsState().peekSource(sourceId2).getFrame()); 1484 }, true); 1485 activity2.forAllWindows(window -> { 1486 assertEquals(genericOverlayInsetsRect1, 1487 window.getInsetsState().peekSource(sourceId1).getFrame()); 1488 assertEquals(genericOverlayInsetsRect2, 1489 window.getInsetsState().peekSource(sourceId2).getFrame()); 1490 }, true); 1491 } 1492 1493 @Test testAddLocalInsetsFrameProvider_sameType_replacesInsets()1494 public void testAddLocalInsetsFrameProvider_sameType_replacesInsets() { 1495 /* 1496 ___ rootTask ________________________________________ 1497 | | | 1498 activity0 genericOverlayInsetsProvider1 genericOverlayInsetsProvider2 1499 */ 1500 final Task rootTask = createTask(mDisplayContent); 1501 1502 final ActivityRecord activity0 = createActivityRecord(mDisplayContent, 1503 createTaskInRootTask(rootTask, 0 /* userId */)); 1504 final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams( 1505 TYPE_BASE_APPLICATION); 1506 attrs.setTitle("AppWindow0"); 1507 activity0.addWindow(createWindowState(attrs, activity0)); 1508 1509 final Binder owner = new Binder(); 1510 final Rect genericOverlayInsetsRect1 = new Rect(0, 200, 1080, 700); 1511 final Rect genericOverlayInsetsRect2 = new Rect(0, 0, 1080, 200); 1512 final InsetsFrameProvider provider1 = 1513 new InsetsFrameProvider(owner, 1, WindowInsets.Type.systemOverlays()) 1514 .setArbitraryRectangle(genericOverlayInsetsRect1); 1515 final InsetsFrameProvider provider2 = 1516 new InsetsFrameProvider(owner, 1, WindowInsets.Type.systemOverlays()) 1517 .setArbitraryRectangle(genericOverlayInsetsRect2); 1518 final int sourceId1 = provider1.getId(); 1519 final int sourceId2 = provider2.getId(); 1520 1521 rootTask.addLocalInsetsFrameProvider(provider1, owner); 1522 activity0.forAllWindows(window -> { 1523 assertEquals(genericOverlayInsetsRect1, 1524 window.getInsetsState().peekSource(sourceId1).getFrame()); 1525 }, true); 1526 1527 rootTask.addLocalInsetsFrameProvider(provider2, owner); 1528 1529 activity0.forAllWindows(window -> { 1530 assertEquals(genericOverlayInsetsRect2, 1531 window.getInsetsState().peekSource(sourceId2).getFrame()); 1532 }, true); 1533 } 1534 1535 @Test testRemoveLocalInsetsFrameProvider()1536 public void testRemoveLocalInsetsFrameProvider() { 1537 /* 1538 ___ rootTask _______________________________________________ 1539 | | | | 1540 activity0 container navigationBarInsetsProvider1 navigationBarInsetsProvider2 1541 / \ 1542 activity1 activity2 1543 */ 1544 final Task rootTask = createTask(mDisplayContent); 1545 1546 final ActivityRecord activity0 = createActivityRecord(mDisplayContent, 1547 createTaskInRootTask(rootTask, 0 /* userId */)); 1548 final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams( 1549 TYPE_BASE_APPLICATION); 1550 attrs.setTitle("AppWindow0"); 1551 activity0.addWindow(createWindowState(attrs, activity0)); 1552 1553 final Task container = createTaskInRootTask(rootTask, 0); 1554 final ActivityRecord activity1 = createActivityRecord(mDisplayContent, 1555 createTaskInRootTask(container, 0 /* userId */)); 1556 final WindowManager.LayoutParams attrs1 = new WindowManager.LayoutParams( 1557 TYPE_BASE_APPLICATION); 1558 attrs1.setTitle("AppWindow1"); 1559 activity1.addWindow(createWindowState(attrs1, activity1)); 1560 1561 final ActivityRecord activity2 = createActivityRecord(mDisplayContent, 1562 createTaskInRootTask(container, 0 /* userId */)); 1563 final WindowManager.LayoutParams attrs2 = new WindowManager.LayoutParams( 1564 TYPE_BASE_APPLICATION); 1565 attrs2.setTitle("AppWindow2"); 1566 activity2.addWindow(createWindowState(attrs2, activity2)); 1567 1568 activity2.addWindow(createWindowState(attrs2, activity2)); 1569 1570 final Binder owner = new Binder(); 1571 final Rect navigationBarInsetsRect1 = new Rect(0, 200, 1080, 700); 1572 final Rect navigationBarInsetsRect2 = new Rect(0, 0, 1080, 200); 1573 final InsetsFrameProvider provider1 = 1574 new InsetsFrameProvider(owner, 1, WindowInsets.Type.systemOverlays()) 1575 .setArbitraryRectangle(navigationBarInsetsRect1); 1576 final InsetsFrameProvider provider2 = 1577 new InsetsFrameProvider(owner, 2, WindowInsets.Type.systemOverlays()) 1578 .setArbitraryRectangle(navigationBarInsetsRect2); 1579 final int sourceId1 = provider1.getId(); 1580 final int sourceId2 = provider2.getId(); 1581 1582 rootTask.addLocalInsetsFrameProvider(provider1, owner); 1583 container.addLocalInsetsFrameProvider(provider2, owner); 1584 mDisplayContent.getInsetsStateController().onPostLayout(); 1585 rootTask.removeLocalInsetsFrameProvider(provider1, owner); 1586 mDisplayContent.getInsetsStateController().onPostLayout(); 1587 1588 activity0.forAllWindows(window -> { 1589 assertEquals(null, 1590 window.getInsetsState().peekSource(sourceId1)); 1591 assertEquals(null, 1592 window.getInsetsState().peekSource(sourceId2)); 1593 }, true); 1594 activity1.forAllWindows(window -> { 1595 assertEquals(null, 1596 window.getInsetsState().peekSource(sourceId1)); 1597 assertEquals(navigationBarInsetsRect2, 1598 window.getInsetsState().peekSource(sourceId2) 1599 .getFrame()); 1600 }, true); 1601 activity2.forAllWindows(window -> { 1602 assertEquals(null, 1603 window.getInsetsState().peekSource(sourceId1)); 1604 assertEquals(navigationBarInsetsRect2, 1605 window.getInsetsState().peekSource(sourceId2) 1606 .getFrame()); 1607 }, true); 1608 } 1609 1610 @Test testAddLocalInsetsFrameProvider_ownerDiesAfterAdding()1611 public void testAddLocalInsetsFrameProvider_ownerDiesAfterAdding() { 1612 final Task task = createTask(mDisplayContent); 1613 final TestBinder owner = new TestBinder(); 1614 final InsetsFrameProvider provider = 1615 new InsetsFrameProvider(owner, 0, WindowInsets.Type.systemOverlays()) 1616 .setArbitraryRectangle(new Rect()); 1617 task.addLocalInsetsFrameProvider(provider, owner); 1618 1619 assertTrue("The death recipient must exist.", owner.hasDeathRecipient()); 1620 assertTrue("The source must be added.", hasLocalSource(task, provider.getId())); 1621 1622 // The owner dies after adding the source. 1623 owner.die(); 1624 1625 assertFalse("The death recipient must be removed.", owner.hasDeathRecipient()); 1626 assertFalse("The source must be removed.", hasLocalSource(task, provider.getId())); 1627 } 1628 1629 @Test testAddLocalInsetsFrameProvider_ownerDiesBeforeAdding()1630 public void testAddLocalInsetsFrameProvider_ownerDiesBeforeAdding() { 1631 final Task task = createTask(mDisplayContent); 1632 final TestBinder owner = new TestBinder(); 1633 1634 // The owner dies before adding the source. 1635 owner.die(); 1636 1637 final InsetsFrameProvider provider = 1638 new InsetsFrameProvider(owner, 0, WindowInsets.Type.systemOverlays()) 1639 .setArbitraryRectangle(new Rect()); 1640 task.addLocalInsetsFrameProvider(provider, owner); 1641 1642 assertFalse("The death recipient must not exist.", owner.hasDeathRecipient()); 1643 assertFalse("The source must not be added.", hasLocalSource(task, provider.getId())); 1644 } 1645 1646 @Test testRemoveLocalInsetsFrameProvider_removeDeathRecipient()1647 public void testRemoveLocalInsetsFrameProvider_removeDeathRecipient() { 1648 final Task task = createTask(mDisplayContent); 1649 final TestBinder owner = new TestBinder(); 1650 final InsetsFrameProvider provider = 1651 new InsetsFrameProvider(owner, 0, WindowInsets.Type.systemOverlays()) 1652 .setArbitraryRectangle(new Rect()); 1653 task.addLocalInsetsFrameProvider(provider, owner); 1654 1655 assertTrue("The death recipient must exist.", owner.hasDeathRecipient()); 1656 assertTrue("The source must be added.", hasLocalSource(task, provider.getId())); 1657 1658 task.removeLocalInsetsFrameProvider(provider, owner); 1659 1660 assertFalse("The death recipient must be removed.", owner.hasDeathRecipient()); 1661 assertFalse("The source must be removed.", hasLocalSource(task, provider.getId())); 1662 } 1663 hasLocalSource(WindowContainer container, int sourceId)1664 private static boolean hasLocalSource(WindowContainer container, int sourceId) { 1665 if (container.mLocalInsetsSources == null) { 1666 return false; 1667 } 1668 return container.mLocalInsetsSources.contains(sourceId); 1669 } 1670 1671 /* Used so we can gain access to some protected members of the {@link WindowContainer} class */ 1672 private static class TestWindowContainer extends WindowContainer<TestWindowContainer> { 1673 private final int mLayer; 1674 private boolean mIsAnimating; 1675 private boolean mIsVisible; 1676 private boolean mFillsParent; 1677 private boolean mWaitForTransitStart; 1678 private Integer mOrientation; 1679 1680 private boolean mOnParentChangedCalled; 1681 private boolean mOnDescendantOverrideCalled; 1682 1683 /** 1684 * Compares 2 window layers and returns -1 if the first is lesser than the second in terms 1685 * of z-order and 1 otherwise. 1686 */ 1687 private static final Comparator<TestWindowContainer> SUBLAYER_COMPARATOR = (w1, w2) -> { 1688 final int layer1 = w1.mLayer; 1689 final int layer2 = w2.mLayer; 1690 if (layer1 < layer2 || (layer1 == layer2 && layer2 < 0)) { 1691 // We insert the child window into the list ordered by the mLayer. For same layers, 1692 // the negative one should go below others; the positive one should go above others. 1693 return -1; 1694 } 1695 if (layer1 == layer2) return 0; 1696 return 1; 1697 }; 1698 TestWindowContainer(WindowManagerService wm, int layer, boolean isAnimating, boolean isVisible, boolean waitTransitStart, Integer orientation)1699 TestWindowContainer(WindowManagerService wm, int layer, boolean isAnimating, 1700 boolean isVisible, boolean waitTransitStart, Integer orientation) { 1701 super(wm); 1702 1703 mLayer = layer; 1704 mIsAnimating = isAnimating; 1705 mIsVisible = isVisible; 1706 mFillsParent = true; 1707 mOrientation = orientation; 1708 mWaitForTransitStart = waitTransitStart; 1709 spyOn(mSurfaceAnimator); 1710 doReturn(mIsAnimating).when(mSurfaceAnimator).isAnimating(); 1711 doReturn(ANIMATION_TYPE_APP_TRANSITION).when(mSurfaceAnimator).getAnimationType(); 1712 } 1713 getParentWindow()1714 TestWindowContainer getParentWindow() { 1715 return (TestWindowContainer) getParent(); 1716 } 1717 getChildrenCount()1718 int getChildrenCount() { 1719 return mChildren.size(); 1720 } 1721 addChildWindow(TestWindowContainer child)1722 TestWindowContainer addChildWindow(TestWindowContainer child) { 1723 addChild(child, SUBLAYER_COMPARATOR); 1724 return child; 1725 } 1726 addChildWindow(TestWindowContainerBuilder childBuilder)1727 TestWindowContainer addChildWindow(TestWindowContainerBuilder childBuilder) { 1728 TestWindowContainer child = childBuilder.build(); 1729 addChild(child, SUBLAYER_COMPARATOR); 1730 return child; 1731 } 1732 addChildWindow()1733 TestWindowContainer addChildWindow() { 1734 return addChildWindow(new TestWindowContainerBuilder(mWmService).setLayer(1)); 1735 } 1736 1737 @Override onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent)1738 void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) { 1739 mOnParentChangedCalled = true; 1740 } 1741 1742 @Override onDescendantOverrideConfigurationChanged()1743 void onDescendantOverrideConfigurationChanged() { 1744 mOnDescendantOverrideCalled = true; 1745 super.onDescendantOverrideConfigurationChanged(); 1746 } 1747 1748 @Override isVisible()1749 boolean isVisible() { 1750 return mIsVisible; 1751 } 1752 1753 @Override getOrientation(int candidate)1754 int getOrientation(int candidate) { 1755 return mOrientation != null ? mOrientation : super.getOrientation(candidate); 1756 } 1757 1758 @Override getOrientation()1759 int getOrientation() { 1760 return getOrientation(super.getOverrideOrientation()); 1761 } 1762 1763 @Override fillsParent()1764 boolean fillsParent() { 1765 return mFillsParent; 1766 } 1767 setFillsParent(boolean fillsParent)1768 void setFillsParent(boolean fillsParent) { 1769 mFillsParent = fillsParent; 1770 } 1771 1772 @Override isWaitingForTransitionStart()1773 boolean isWaitingForTransitionStart() { 1774 return mWaitForTransitStart; 1775 } 1776 } 1777 1778 private static class TestWindowContainerBuilder { 1779 private final WindowManagerService mWm; 1780 private int mLayer; 1781 private boolean mIsAnimating; 1782 private boolean mIsVisible; 1783 private boolean mIsWaitTransitStart; 1784 private Integer mOrientation; 1785 TestWindowContainerBuilder(WindowManagerService wm)1786 TestWindowContainerBuilder(WindowManagerService wm) { 1787 mWm = wm; 1788 mLayer = 0; 1789 mIsAnimating = false; 1790 mIsVisible = false; 1791 mOrientation = null; 1792 } 1793 setLayer(int layer)1794 TestWindowContainerBuilder setLayer(int layer) { 1795 mLayer = layer; 1796 return this; 1797 } 1798 setIsAnimating(boolean isAnimating)1799 TestWindowContainerBuilder setIsAnimating(boolean isAnimating) { 1800 mIsAnimating = isAnimating; 1801 return this; 1802 } 1803 setIsVisible(boolean isVisible)1804 TestWindowContainerBuilder setIsVisible(boolean isVisible) { 1805 mIsVisible = isVisible; 1806 return this; 1807 } 1808 setOrientation(int orientation)1809 TestWindowContainerBuilder setOrientation(int orientation) { 1810 mOrientation = orientation; 1811 return this; 1812 } 1813 setWaitForTransitionStart(boolean waitTransitStart)1814 TestWindowContainerBuilder setWaitForTransitionStart(boolean waitTransitStart) { 1815 mIsWaitTransitStart = waitTransitStart; 1816 return this; 1817 } 1818 build()1819 TestWindowContainer build() { 1820 return new TestWindowContainer(mWm, mLayer, mIsAnimating, mIsVisible, 1821 mIsWaitTransitStart, mOrientation); 1822 } 1823 } 1824 1825 private static class MockSurfaceBuildingContainer extends WindowContainer<WindowContainer> 1826 implements AutoCloseable { 1827 private final SurfaceSession mSession = new SurfaceSession(); 1828 MockSurfaceBuildingContainer(WindowManagerService wm)1829 MockSurfaceBuildingContainer(WindowManagerService wm) { 1830 super(wm); 1831 } 1832 1833 static class MockSurfaceBuilder extends SurfaceControl.Builder { MockSurfaceBuilder(SurfaceSession ss)1834 MockSurfaceBuilder(SurfaceSession ss) { 1835 super(ss); 1836 } 1837 1838 @Override build()1839 public SurfaceControl build() { 1840 return mock(SurfaceControl.class); 1841 } 1842 } 1843 1844 @Override makeChildSurface(WindowContainer child)1845 SurfaceControl.Builder makeChildSurface(WindowContainer child) { 1846 return new MockSurfaceBuilder(mSession); 1847 } 1848 1849 @Override close()1850 public void close() { 1851 mSession.kill(); 1852 } 1853 } 1854 1855 private static class TestWindowContainerListener implements WindowContainerListener { 1856 private Configuration mConfiguration = new Configuration(); 1857 private DisplayContent mDisplayContent; 1858 private boolean mIsVisibleRequested; 1859 1860 @Override onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration)1861 public void onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration) { 1862 mConfiguration.setTo(overrideConfiguration); 1863 } 1864 1865 @Override onDisplayChanged(DisplayContent dc)1866 public void onDisplayChanged(DisplayContent dc) { 1867 mDisplayContent = dc; 1868 } 1869 1870 @Override onVisibleRequestedChanged(boolean isVisibleRequested)1871 public void onVisibleRequestedChanged(boolean isVisibleRequested) { 1872 mIsVisibleRequested = isVisibleRequested; 1873 } 1874 } 1875 1876 private static class TestBinder implements IBinder { 1877 1878 private boolean mDead; 1879 private final ArrayList<IBinder.DeathRecipient> mDeathRecipients = new ArrayList<>(); 1880 die()1881 public void die() { 1882 mDead = true; 1883 for (int i = mDeathRecipients.size() - 1; i >= 0; i--) { 1884 final DeathRecipient recipient = mDeathRecipients.get(i); 1885 recipient.binderDied(this); 1886 } 1887 } 1888 hasDeathRecipient()1889 public boolean hasDeathRecipient() { 1890 return !mDeathRecipients.isEmpty(); 1891 } 1892 1893 @Override linkToDeath(@onNull DeathRecipient recipient, int flags)1894 public void linkToDeath(@NonNull DeathRecipient recipient, int flags) 1895 throws RemoteException { 1896 if (mDead) { 1897 throw new DeadObjectException(); 1898 } 1899 mDeathRecipients.add(recipient); 1900 } 1901 1902 @Override unlinkToDeath(@onNull DeathRecipient recipient, int flags)1903 public boolean unlinkToDeath(@NonNull DeathRecipient recipient, int flags) { 1904 final boolean successes = mDeathRecipients.remove(recipient); 1905 if (successes || mDead) { 1906 return successes; 1907 } 1908 throw new NoSuchElementException("Given recipient has not been registered."); 1909 } 1910 1911 @Override isBinderAlive()1912 public boolean isBinderAlive() { 1913 return !mDead; 1914 } 1915 1916 @Override pingBinder()1917 public boolean pingBinder() { 1918 return !mDead; 1919 } 1920 1921 @Nullable 1922 @Override getInterfaceDescriptor()1923 public String getInterfaceDescriptor() throws RemoteException { 1924 return null; 1925 } 1926 1927 @Nullable 1928 @Override queryLocalInterface(@onNull String descriptor)1929 public IInterface queryLocalInterface(@NonNull String descriptor) { 1930 return null; 1931 } 1932 1933 @Override dump(@onNull FileDescriptor fd, @Nullable String[] args)1934 public void dump(@NonNull FileDescriptor fd, @Nullable String[] args) 1935 throws RemoteException { } 1936 1937 @Override dumpAsync(@onNull FileDescriptor fd, @Nullable String[] args)1938 public void dumpAsync(@NonNull FileDescriptor fd, @Nullable String[] args) 1939 throws RemoteException { } 1940 1941 @Override shellCommand(@ullable FileDescriptor in, @Nullable FileDescriptor out, @Nullable FileDescriptor err, @NonNull String[] args, @Nullable ShellCallback shellCallback, @NonNull ResultReceiver resultReceiver)1942 public void shellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out, 1943 @Nullable FileDescriptor err, @NonNull String[] args, 1944 @Nullable ShellCallback shellCallback, 1945 @NonNull ResultReceiver resultReceiver) throws RemoteException { } 1946 1947 @Override transact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags)1948 public boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) 1949 throws RemoteException { 1950 return false; 1951 } 1952 } 1953 } 1954