1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.wm; 18 19 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; 20 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; 21 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LOCKED; 22 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR; 23 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; 24 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; 25 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; 26 import static android.view.WindowManager.LayoutParams.TYPE_PRESENTATION; 27 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; 28 import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER; 29 import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST; 30 31 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; 32 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; 33 import static com.android.dx.mockito.inline.extended.ExtendedMockito.never; 34 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; 35 import static com.android.server.wm.ActivityTaskSupervisor.ON_TOP; 36 import static com.android.server.wm.DisplayArea.Type.ABOVE_TASKS; 37 import static com.android.server.wm.DisplayArea.Type.ANY; 38 import static com.android.server.wm.DisplayArea.Type.BELOW_TASKS; 39 import static com.android.server.wm.DisplayArea.Type.checkChild; 40 import static com.android.server.wm.DisplayArea.Type.checkSiblings; 41 import static com.android.server.wm.DisplayArea.Type.typeOf; 42 import static com.android.server.wm.WindowContainer.POSITION_BOTTOM; 43 import static com.android.server.wm.WindowContainer.POSITION_TOP; 44 import static com.android.server.wm.testing.Assert.assertThrows; 45 46 import static com.google.common.truth.Truth.assertThat; 47 48 import static org.junit.Assert.assertEquals; 49 import static org.junit.Assert.assertNull; 50 import static org.mockito.ArgumentMatchers.any; 51 import static org.mockito.ArgumentMatchers.argThat; 52 import static org.mockito.ArgumentMatchers.eq; 53 import static org.mockito.Mockito.mock; 54 import static org.mockito.Mockito.times; 55 import static org.mockito.Mockito.verify; 56 import static org.mockito.Mockito.verifyZeroInteractions; 57 import static org.mockito.Mockito.when; 58 59 import android.content.pm.ActivityInfo; 60 import android.content.res.Configuration; 61 import android.graphics.Rect; 62 import android.os.Binder; 63 import android.os.IBinder; 64 import android.platform.test.annotations.Presubmit; 65 import android.view.SurfaceControl; 66 import android.view.View; 67 import android.view.WindowManager; 68 import android.window.DisplayAreaInfo; 69 import android.window.IDisplayAreaOrganizer; 70 71 import com.google.android.collect.Lists; 72 73 import org.junit.Test; 74 import org.junit.runner.RunWith; 75 76 import java.util.ArrayList; 77 import java.util.List; 78 import java.util.function.BiFunction; 79 import java.util.function.Consumer; 80 import java.util.function.Function; 81 import java.util.function.Predicate; 82 83 /** 84 * Tests for the {@link DisplayArea} container. 85 * 86 * Build/Install/Run: 87 * atest WmTests:DisplayAreaTest 88 */ 89 @Presubmit 90 @RunWith(WindowTestRunner.class) 91 public class DisplayAreaTest extends WindowTestsBase { 92 93 @Test testDisplayArea_positionChanged_throwsIfIncompatibleChild()94 public void testDisplayArea_positionChanged_throwsIfIncompatibleChild() { 95 DisplayArea<WindowContainer> parent = new DisplayArea<>(mWm, BELOW_TASKS, "Parent"); 96 DisplayArea<WindowContainer> child = new DisplayArea<>(mWm, ANY, "Child"); 97 98 assertThrows(IllegalStateException.class, () -> parent.addChild(child, 0)); 99 } 100 101 @Test testType_typeOf()102 public void testType_typeOf() { 103 assertEquals(ABOVE_TASKS, typeOf(new DisplayArea<>(mWm, ABOVE_TASKS, "test"))); 104 assertEquals(ANY, typeOf(new DisplayArea<>(mWm, ANY, "test"))); 105 assertEquals(BELOW_TASKS, typeOf(new DisplayArea<>(mWm, BELOW_TASKS, "test"))); 106 107 assertEquals(ABOVE_TASKS, typeOf(createWindowToken(TYPE_APPLICATION_OVERLAY))); 108 assertEquals(ABOVE_TASKS, typeOf(createWindowToken(TYPE_PRESENTATION))); 109 assertEquals(BELOW_TASKS, typeOf(createWindowToken(TYPE_WALLPAPER))); 110 111 assertThrows(IllegalArgumentException.class, () -> typeOf(mock(ActivityRecord.class))); 112 assertThrows(IllegalArgumentException.class, () -> typeOf(mock(WindowContainer.class))); 113 } 114 115 @Test testType_checkSiblings()116 public void testType_checkSiblings() { 117 checkSiblings(BELOW_TASKS, BELOW_TASKS); 118 checkSiblings(BELOW_TASKS, ANY); 119 checkSiblings(BELOW_TASKS, ABOVE_TASKS); 120 checkSiblings(ANY, ABOVE_TASKS); 121 checkSiblings(ABOVE_TASKS, ABOVE_TASKS); 122 checkSiblings(ANY, ANY); 123 124 assertThrows(IllegalStateException.class, () -> checkSiblings(ABOVE_TASKS, BELOW_TASKS)); 125 assertThrows(IllegalStateException.class, () -> checkSiblings(ABOVE_TASKS, ANY)); 126 assertThrows(IllegalStateException.class, () -> checkSiblings(ANY, BELOW_TASKS)); 127 } 128 129 @Test testType_checkChild()130 public void testType_checkChild() { 131 checkChild(ANY, ANY); 132 checkChild(ANY, ABOVE_TASKS); 133 checkChild(ANY, BELOW_TASKS); 134 checkChild(ABOVE_TASKS, ABOVE_TASKS); 135 checkChild(BELOW_TASKS, BELOW_TASKS); 136 137 assertThrows(IllegalStateException.class, () -> checkChild(ABOVE_TASKS, BELOW_TASKS)); 138 assertThrows(IllegalStateException.class, () -> checkChild(ABOVE_TASKS, ANY)); 139 assertThrows(IllegalStateException.class, () -> checkChild(BELOW_TASKS, ABOVE_TASKS)); 140 assertThrows(IllegalStateException.class, () -> checkChild(BELOW_TASKS, ANY)); 141 } 142 143 @Test testAsDisplayArea()144 public void testAsDisplayArea() { 145 final WindowContainer windowContainer = new WindowContainer(mWm); 146 final DisplayArea<WindowContainer> displayArea = new DisplayArea<>(mWm, ANY, "DA"); 147 final TaskDisplayArea taskDisplayArea = new TaskDisplayArea(null /* displayContent */, 148 mWm, "TDA", FEATURE_DEFAULT_TASK_CONTAINER); 149 150 assertThat(windowContainer.asDisplayArea()).isNull(); 151 assertThat(displayArea.asDisplayArea()).isEqualTo(displayArea); 152 assertThat(taskDisplayArea.asDisplayArea()).isEqualTo(taskDisplayArea); 153 } 154 155 @Test testForAllTaskDisplayAreas_onlyTraversesDisplayAreaOfTypeAny()156 public void testForAllTaskDisplayAreas_onlyTraversesDisplayAreaOfTypeAny() { 157 final RootDisplayArea root = 158 new DisplayAreaPolicyBuilderTest.SurfacelessDisplayAreaRoot(mWm); 159 final Predicate<TaskDisplayArea> callback0 = tda -> false; 160 final Consumer<TaskDisplayArea> callback1 = tda -> { }; 161 final BiFunction<TaskDisplayArea, Integer, Integer> callback2 = (tda, result) -> result; 162 final Function<TaskDisplayArea, TaskDisplayArea> callback3 = tda -> null; 163 164 // Don't traverse the child if the current DA has type BELOW_TASKS 165 final DisplayArea<WindowContainer> da1 = new DisplayArea<>(mWm, BELOW_TASKS, "DA1"); 166 final DisplayArea<WindowContainer> da2 = new DisplayArea<>(mWm, BELOW_TASKS, "DA2"); 167 root.addChild(da1, POSITION_BOTTOM); 168 da1.addChild(da2, POSITION_TOP); 169 spyOn(da2); 170 171 da1.forAllTaskDisplayAreas(callback0); 172 da1.forAllTaskDisplayAreas(callback1); 173 da1.reduceOnAllTaskDisplayAreas(callback2, 0); 174 da1.getItemFromTaskDisplayAreas(callback3); 175 176 verifyZeroInteractions(da2); 177 178 // Traverse the child if the current DA has type ANY 179 final DisplayArea<WindowContainer> da3 = new DisplayArea<>(mWm, ANY, "DA3"); 180 final DisplayArea<WindowContainer> da4 = new DisplayArea<>(mWm, ANY, "DA4"); 181 root.addChild(da3, POSITION_TOP); 182 da3.addChild(da4, POSITION_TOP); 183 spyOn(da4); 184 185 da3.forAllTaskDisplayAreas(callback0); 186 da3.forAllTaskDisplayAreas(callback1); 187 da3.reduceOnAllTaskDisplayAreas(callback2, 0); 188 da3.getItemFromTaskDisplayAreas(callback3); 189 190 verify(da4).forAllTaskDisplayAreas(callback0, true /* traverseTopToBottom */); 191 verify(da4).forAllTaskDisplayAreas(callback1, true /* traverseTopToBottom */); 192 verify(da4).reduceOnAllTaskDisplayAreas(callback2, 0 /* initValue */, 193 true /* traverseTopToBottom */); 194 verify(da4).getItemFromTaskDisplayAreas( 195 callback3, true /* traverseTopToBottom */); 196 197 // Don't traverse the child if the current DA has type ABOVE_TASKS 198 final DisplayArea<WindowContainer> da5 = new DisplayArea<>(mWm, ABOVE_TASKS, "DA5"); 199 final DisplayArea<WindowContainer> da6 = new DisplayArea<>(mWm, ABOVE_TASKS, "DA6"); 200 root.addChild(da5, POSITION_TOP); 201 da5.addChild(da6, POSITION_TOP); 202 spyOn(da6); 203 204 da5.forAllTaskDisplayAreas(callback0); 205 da5.forAllTaskDisplayAreas(callback1); 206 da5.reduceOnAllTaskDisplayAreas(callback2, 0); 207 da5.getItemFromTaskDisplayAreas(callback3); 208 209 verifyZeroInteractions(da6); 210 } 211 212 @Test testForAllTaskDisplayAreas_appliesOnTaskDisplayAreaInOrder()213 public void testForAllTaskDisplayAreas_appliesOnTaskDisplayAreaInOrder() { 214 final RootDisplayArea root = 215 new DisplayAreaPolicyBuilderTest.SurfacelessDisplayAreaRoot(mWm); 216 final DisplayArea<DisplayArea> da1 = 217 new DisplayArea<>(mWm, ANY, "DA1"); 218 final DisplayArea<DisplayArea> da2 = 219 new DisplayArea<>(mWm, ANY, "DA2"); 220 final TaskDisplayArea tda1 = new TaskDisplayArea(null /* displayContent */, 221 mWm, "TDA1", FEATURE_DEFAULT_TASK_CONTAINER); 222 final TaskDisplayArea tda2 = new TaskDisplayArea(null /* displayContent */, 223 mWm, "TDA2", FEATURE_VENDOR_FIRST); 224 final TaskDisplayArea tda3 = new TaskDisplayArea(null /* displayContent */, 225 mWm, "TDA3", FEATURE_VENDOR_FIRST + 1); 226 root.addChild(da1, POSITION_TOP); 227 root.addChild(da2, POSITION_TOP); 228 da1.addChild(tda1, POSITION_TOP); 229 da2.addChild(tda2, POSITION_TOP); 230 da2.addChild(tda3, POSITION_TOP); 231 232 /* The hierarchy looks like this 233 Root 234 - DA1 235 - TDA1 ------ bottom 236 - DA2 237 - TDA2 238 - TDA3 ------ top 239 */ 240 241 // Test forAllTaskDisplayAreas(Consumer<TaskDisplayArea>) 242 List<TaskDisplayArea> actualOrder = new ArrayList<>(); 243 root.forAllTaskDisplayAreas(tda -> { 244 actualOrder.add(tda); 245 }); 246 247 assertThat(actualOrder).isEqualTo(Lists.newArrayList(tda3, tda2, tda1)); 248 249 // Test forAllTaskDisplayAreas(Consumer<TaskDisplayArea>, boolean) 250 actualOrder.clear(); 251 root.forAllTaskDisplayAreas(tda -> { 252 actualOrder.add(tda); 253 }, false /* traverseTopToBottom */); 254 255 assertThat(actualOrder).isEqualTo(Lists.newArrayList(tda1, tda2, tda3)); 256 257 // Test forAllTaskDisplayAreas(Function<TaskDisplayArea, Boolean>) 258 actualOrder.clear(); 259 root.forAllTaskDisplayAreas(tda -> { 260 actualOrder.add(tda); 261 return false; 262 }); 263 264 assertThat(actualOrder).isEqualTo(Lists.newArrayList(tda3, tda2, tda1)); 265 266 // Test forAllTaskDisplayAreas(Function<TaskDisplayArea, Boolean>, boolean) 267 actualOrder.clear(); 268 root.forAllTaskDisplayAreas(tda -> { 269 actualOrder.add(tda); 270 return false; 271 }, false /* traverseTopToBottom */); 272 273 assertThat(actualOrder).isEqualTo(Lists.newArrayList(tda1, tda2, tda3)); 274 275 // Test forAllTaskDisplayAreas(BiFunction<TaskDisplayArea, R, R>, R) 276 actualOrder.clear(); 277 root.reduceOnAllTaskDisplayAreas((tda, result) -> { 278 actualOrder.add(tda); 279 return result; 280 }, 0 /* initValue */); 281 282 assertThat(actualOrder).isEqualTo(Lists.newArrayList(tda3, tda2, tda1)); 283 284 // Test forAllTaskDisplayAreas(BiFunction<TaskDisplayArea, R, R>, R, boolean) 285 actualOrder.clear(); 286 root.reduceOnAllTaskDisplayAreas((tda, result) -> { 287 actualOrder.add(tda); 288 return result; 289 }, 0 /* initValue */, false /* traverseTopToBottom */); 290 291 assertThat(actualOrder).isEqualTo(Lists.newArrayList(tda1, tda2, tda3)); 292 293 // Test <R> R getItemFromTaskDisplayAreas(Function<TaskDisplayArea, R> callback) 294 actualOrder.clear(); 295 root.getItemFromTaskDisplayAreas(tda -> { 296 actualOrder.add(tda); 297 return null; 298 }); 299 300 assertThat(actualOrder).isEqualTo(Lists.newArrayList(tda3, tda2, tda1)); 301 302 // Test <R> R getItemFromTaskDisplayAreas(Function<TaskDisplayArea, R> callback, boolean) 303 actualOrder.clear(); 304 root.getItemFromTaskDisplayAreas(tda -> { 305 actualOrder.add(tda); 306 return null; 307 }, false /* traverseTopToBottom */); 308 309 assertThat(actualOrder).isEqualTo(Lists.newArrayList(tda1, tda2, tda3)); 310 } 311 312 @Test testForAllTaskDisplayAreas_returnsWhenCallbackReturnTrue()313 public void testForAllTaskDisplayAreas_returnsWhenCallbackReturnTrue() { 314 final RootDisplayArea root = 315 new DisplayAreaPolicyBuilderTest.SurfacelessDisplayAreaRoot(mWm); 316 final TaskDisplayArea tda1 = new TaskDisplayArea(null /* displayContent */, 317 mWm, "TDA1", FEATURE_DEFAULT_TASK_CONTAINER); 318 final TaskDisplayArea tda2 = new TaskDisplayArea(null /* displayContent */, 319 mWm, "TDA2", FEATURE_VENDOR_FIRST); 320 root.addChild(tda1, POSITION_TOP); 321 root.addChild(tda2, POSITION_TOP); 322 323 /* The hierarchy looks like this 324 Root 325 - TDA1 ------ bottom 326 - TDA2 ------ top 327 */ 328 329 root.forAllTaskDisplayAreas(tda -> { 330 assertThat(tda).isEqualTo(tda2); 331 return true; 332 }); 333 334 root.forAllTaskDisplayAreas(tda -> { 335 assertThat(tda).isEqualTo(tda1); 336 return true; 337 }, false /* traverseTopToBottom */); 338 } 339 340 @Test testReduceOnAllTaskDisplayAreas_returnsTheAccumulativeResult()341 public void testReduceOnAllTaskDisplayAreas_returnsTheAccumulativeResult() { 342 final RootDisplayArea root = 343 new DisplayAreaPolicyBuilderTest.SurfacelessDisplayAreaRoot(mWm); 344 final TaskDisplayArea tda1 = new TaskDisplayArea(null /* displayContent */, 345 mWm, "TDA1", FEATURE_DEFAULT_TASK_CONTAINER); 346 final TaskDisplayArea tda2 = new TaskDisplayArea(null /* displayContent */, 347 mWm, "TDA2", FEATURE_VENDOR_FIRST); 348 root.addChild(tda1, POSITION_TOP); 349 root.addChild(tda2, POSITION_TOP); 350 351 /* The hierarchy looks like this 352 Root 353 - TDA1 ------ bottom 354 - TDA2 ------ top 355 */ 356 357 String accumulativeName = root.reduceOnAllTaskDisplayAreas((tda, result) -> 358 result + tda.getName(), "" /* initValue */); 359 assertThat(accumulativeName).isEqualTo("TDA2TDA1"); 360 361 accumulativeName = root.reduceOnAllTaskDisplayAreas((tda, result) -> 362 result + tda.getName(), "" /* initValue */, false /* traverseTopToBottom */); 363 assertThat(accumulativeName).isEqualTo("TDA1TDA2"); 364 } 365 366 @Test testGetItemFromTaskDisplayAreas_returnsWhenCallbackReturnNotNull()367 public void testGetItemFromTaskDisplayAreas_returnsWhenCallbackReturnNotNull() { 368 final RootDisplayArea root = 369 new DisplayAreaPolicyBuilderTest.SurfacelessDisplayAreaRoot(mWm); 370 final TaskDisplayArea tda1 = new TaskDisplayArea(null /* displayContent */, 371 mWm, "TDA1", FEATURE_DEFAULT_TASK_CONTAINER); 372 final TaskDisplayArea tda2 = new TaskDisplayArea(null /* displayContent */, 373 mWm, "TDA2", FEATURE_VENDOR_FIRST); 374 root.addChild(tda1, POSITION_TOP); 375 root.addChild(tda2, POSITION_TOP); 376 377 /* The hierarchy looks like this 378 Root 379 - TDA1 ------ bottom 380 - TDA2 ------ top 381 */ 382 383 TaskDisplayArea result = root.getItemFromTaskDisplayAreas(tda -> { 384 assertThat(tda).isEqualTo(tda2); 385 return tda; 386 }); 387 388 assertThat(result).isEqualTo(tda2); 389 390 result = root.getItemFromTaskDisplayAreas(tda -> { 391 assertThat(tda).isEqualTo(tda1); 392 return tda; 393 }, false /* traverseTopToBottom */); 394 395 assertThat(result).isEqualTo(tda1); 396 } 397 398 @Test testSetMaxBounds()399 public void testSetMaxBounds() { 400 final Rect parentBounds = new Rect(0, 0, 100, 100); 401 final Rect childBounds1 = new Rect(parentBounds.left, parentBounds.top, 402 parentBounds.right / 2, parentBounds.bottom); 403 final Rect childBounds2 = new Rect(parentBounds.right / 2, parentBounds.top, 404 parentBounds.right, parentBounds.bottom); 405 TestDisplayArea parentDa = new TestDisplayArea(mWm, parentBounds, "Parent"); 406 TestDisplayArea childDa1 = new TestDisplayArea(mWm, childBounds1, "Child1"); 407 TestDisplayArea childDa2 = new TestDisplayArea(mWm, childBounds2, "Child2"); 408 parentDa.addChild(childDa1, 0); 409 parentDa.addChild(childDa2, 1); 410 411 assertEquals(parentBounds, parentDa.getMaxBounds()); 412 assertEquals(childBounds1, childDa1.getMaxBounds()); 413 assertEquals(childBounds2, childDa2.getMaxBounds()); 414 415 final WindowToken windowToken = createWindowToken(TYPE_APPLICATION); 416 childDa1.addChild(windowToken, 0); 417 418 assertEquals("DisplayArea's children must have the same max bounds as itself", 419 childBounds1, windowToken.getMaxBounds()); 420 } 421 422 @Test testRestrictAppBoundsToOverrideBounds()423 public void testRestrictAppBoundsToOverrideBounds() { 424 final RootDisplayArea root = 425 new DisplayAreaPolicyBuilderTest.SurfacelessDisplayAreaRoot(mWm); 426 final DisplayArea<DisplayArea> da = new DisplayArea<>(mWm, ANY, "Test_DA"); 427 root.addChild(da, POSITION_TOP); 428 final Rect displayBounds = new Rect(0, 0, 1800, 2800); 429 final Rect displayAppBounds = new Rect(0, 100, 1800, 2800); 430 final Rect daBounds = new Rect(0, 1400, 1800, 2800); 431 root.setBounds(displayBounds); 432 433 // DA inherit parent app bounds. 434 final Configuration displayConfig = new Configuration(); 435 displayConfig.windowConfiguration.setAppBounds(displayAppBounds); 436 root.onRequestedOverrideConfigurationChanged(displayConfig); 437 438 assertEquals(displayAppBounds, da.getConfiguration().windowConfiguration.getAppBounds()); 439 440 // Restrict DA appBounds to override Bounds 441 da.setBounds(daBounds); 442 443 final Rect expectedDaAppBounds = new Rect(daBounds); 444 expectedDaAppBounds.intersect(displayAppBounds); 445 assertEquals(expectedDaAppBounds, da.getConfiguration().windowConfiguration.getAppBounds()); 446 } 447 448 @Test testGetOrientation()449 public void testGetOrientation() { 450 final DisplayArea.Tokens area = new DisplayArea.Tokens(mWm, ABOVE_TASKS, "test"); 451 final WindowToken token = createWindowToken(TYPE_APPLICATION_OVERLAY); 452 spyOn(token); 453 doReturn(mock(DisplayContent.class)).when(token).getDisplayContent(); 454 doNothing().when(token).setParent(any()); 455 final WindowState win = createWindowState(token); 456 spyOn(win); 457 doNothing().when(win).setParent(any()); 458 win.mAttrs.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; 459 token.addChild(win, 0); 460 area.addChild(token); 461 462 doReturn(true).when(win).isVisible(); 463 464 assertEquals("Visible window can request orientation", 465 ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE, 466 area.getOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR)); 467 468 doReturn(false).when(win).isVisible(); 469 470 assertEquals("Invisible window cannot request orientation", 471 ActivityInfo.SCREEN_ORIENTATION_NOSENSOR, 472 area.getOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR)); 473 } 474 475 @Test testSetIgnoreOrientationRequest_notCallSuperOnDescendantOrientationChanged()476 public void testSetIgnoreOrientationRequest_notCallSuperOnDescendantOrientationChanged() { 477 final TaskDisplayArea tda = mDisplayContent.getDefaultTaskDisplayArea(); 478 final Task stack = 479 new TaskBuilder(mSupervisor).setOnTop(!ON_TOP).setCreateActivity(true).build(); 480 final ActivityRecord activity = stack.getTopNonFinishingActivity(); 481 482 tda.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 483 484 activity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE); 485 486 verify(tda).onDescendantOrientationChanged(any()); 487 verify(mDisplayContent, never()).onDescendantOrientationChanged(any()); 488 489 tda.setIgnoreOrientationRequest(false /* ignoreOrientationRequest */); 490 activity.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT); 491 492 verify(tda, times(2)).onDescendantOrientationChanged(any()); 493 verify(mDisplayContent).onDescendantOrientationChanged(any()); 494 } 495 496 @Test testSetIgnoreOrientationRequest_callSuperOnDescendantOrientationChangedNoSensor()497 public void testSetIgnoreOrientationRequest_callSuperOnDescendantOrientationChangedNoSensor() { 498 final TaskDisplayArea tda = mDisplayContent.getDefaultTaskDisplayArea(); 499 final Task stack = 500 new TaskBuilder(mSupervisor).setOnTop(!ON_TOP).setCreateActivity(true).build(); 501 final ActivityRecord activity = stack.getTopNonFinishingActivity(); 502 503 tda.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 504 505 activity.setRequestedOrientation(SCREEN_ORIENTATION_NOSENSOR); 506 507 verify(tda).onDescendantOrientationChanged(any()); 508 verify(mDisplayContent).onDescendantOrientationChanged(any()); 509 510 tda.setIgnoreOrientationRequest(false /* ignoreOrientationRequest */); 511 activity.setRequestedOrientation(SCREEN_ORIENTATION_NOSENSOR); 512 513 verify(tda).onDescendantOrientationChanged(any()); 514 verify(mDisplayContent).onDescendantOrientationChanged(any()); 515 } 516 517 @Test testSetIgnoreOrientationRequest_callSuperOnDescendantOrientationChangedLocked()518 public void testSetIgnoreOrientationRequest_callSuperOnDescendantOrientationChangedLocked() { 519 final TaskDisplayArea tda = mDisplayContent.getDefaultTaskDisplayArea(); 520 final Task stack = 521 new TaskBuilder(mSupervisor).setOnTop(!ON_TOP).setCreateActivity(true).build(); 522 final ActivityRecord activity = stack.getTopNonFinishingActivity(); 523 524 tda.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 525 526 activity.setRequestedOrientation(SCREEN_ORIENTATION_LOCKED); 527 528 verify(tda).onDescendantOrientationChanged(any()); 529 verify(mDisplayContent).onDescendantOrientationChanged(any()); 530 531 tda.setIgnoreOrientationRequest(false /* ignoreOrientationRequest */); 532 activity.setRequestedOrientation(SCREEN_ORIENTATION_LOCKED); 533 534 verify(tda).onDescendantOrientationChanged(any()); 535 verify(mDisplayContent).onDescendantOrientationChanged(any()); 536 } 537 538 @Test testGetOrientationRequestingTaskDisplayArea_updateOrientationTaskDisplayArea()539 public void testGetOrientationRequestingTaskDisplayArea_updateOrientationTaskDisplayArea() { 540 final TaskDisplayArea tda = mDisplayContent.getDefaultTaskDisplayArea(); 541 final Task stack = 542 new TaskBuilder(mSupervisor).setOnTop(!ON_TOP).setCreateActivity(true).build(); 543 final ActivityRecord activity = stack.getTopNonFinishingActivity(); 544 545 mDisplayContent.setFocusedApp(activity); 546 assertThat(mDisplayContent.getOrientationRequestingTaskDisplayArea()).isEqualTo(tda); 547 548 // TDA is no longer handling orientation request, clear the last focused TDA. 549 tda.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 550 551 assertThat(mDisplayContent.getOrientationRequestingTaskDisplayArea()).isEqualTo(tda); 552 553 // TDA now handles orientation request, update last focused TDA based on the focused app. 554 tda.setIgnoreOrientationRequest(false /* ignoreOrientationRequest */); 555 556 assertThat(mDisplayContent.getOrientationRequestingTaskDisplayArea()).isEqualTo(tda); 557 } 558 559 @Test testDisplayContentUpdateDisplayAreaOrganizers_onDisplayAreaAppeared()560 public void testDisplayContentUpdateDisplayAreaOrganizers_onDisplayAreaAppeared() { 561 final DisplayArea<WindowContainer> displayArea = new DisplayArea<>( 562 mWm, BELOW_TASKS, "NewArea", FEATURE_VENDOR_FIRST); 563 final IDisplayAreaOrganizer mockDisplayAreaOrganizer = mock(IDisplayAreaOrganizer.class); 564 spyOn(mWm.mAtmService.mWindowOrganizerController.mDisplayAreaOrganizerController); 565 when(mWm.mAtmService.mWindowOrganizerController.mDisplayAreaOrganizerController 566 .getOrganizerByFeature(FEATURE_VENDOR_FIRST)) 567 .thenReturn(mockDisplayAreaOrganizer); 568 569 mDisplayContent.addChild(displayArea, 0); 570 mDisplayContent.updateDisplayAreaOrganizers(); 571 572 assertEquals(mockDisplayAreaOrganizer, displayArea.mOrganizer); 573 verify(mWm.mAtmService.mWindowOrganizerController.mDisplayAreaOrganizerController) 574 .onDisplayAreaAppeared( 575 eq(mockDisplayAreaOrganizer), 576 argThat(it -> it == displayArea && it.getSurfaceControl() != null)); 577 } 578 579 @Test testRemoveImmediately_onDisplayAreaVanished()580 public void testRemoveImmediately_onDisplayAreaVanished() { 581 final DisplayArea<WindowContainer> displayArea = new DisplayArea<>( 582 mWm, BELOW_TASKS, "NewArea", FEATURE_VENDOR_FIRST); 583 final IDisplayAreaOrganizer mockDisplayAreaOrganizer = mock(IDisplayAreaOrganizer.class); 584 doReturn(mock(IBinder.class)).when(mockDisplayAreaOrganizer).asBinder(); 585 displayArea.mOrganizer = mockDisplayAreaOrganizer; 586 spyOn(mWm.mAtmService.mWindowOrganizerController.mDisplayAreaOrganizerController); 587 mDisplayContent.addChild(displayArea, 0); 588 589 displayArea.removeImmediately(); 590 591 assertNull(displayArea.mOrganizer); 592 verify(mWm.mAtmService.mWindowOrganizerController.mDisplayAreaOrganizerController) 593 .onDisplayAreaVanished(mockDisplayAreaOrganizer, displayArea); 594 } 595 596 @Test testGetDisplayAreaInfo()597 public void testGetDisplayAreaInfo() { 598 final DisplayArea<WindowContainer> displayArea = new DisplayArea<>( 599 mWm, BELOW_TASKS, "NewArea", FEATURE_VENDOR_FIRST); 600 mDisplayContent.addChild(displayArea, 0); 601 final DisplayAreaInfo info = displayArea.getDisplayAreaInfo(); 602 603 assertThat(info.token).isEqualTo(displayArea.mRemoteToken.toWindowContainerToken()); 604 assertThat(info.configuration).isEqualTo(displayArea.getConfiguration()); 605 assertThat(info.displayId).isEqualTo(mDisplayContent.getDisplayId()); 606 assertThat(info.featureId).isEqualTo(displayArea.mFeatureId); 607 assertThat(info.rootDisplayAreaId).isEqualTo(mDisplayContent.mFeatureId); 608 609 final TaskDisplayArea tda = mDisplayContent.getDefaultTaskDisplayArea(); 610 final int tdaIndex = tda.getParent().mChildren.indexOf(tda); 611 final RootDisplayArea root = 612 new DisplayAreaGroup(mWm, "TestRoot", FEATURE_VENDOR_FIRST + 1); 613 mDisplayContent.addChild(root, tdaIndex + 1); 614 displayArea.reparent(root, 0); 615 616 final DisplayAreaInfo info2 = displayArea.getDisplayAreaInfo(); 617 618 assertThat(info2.rootDisplayAreaId).isEqualTo(root.mFeatureId); 619 } 620 621 @Test testRegisterUnregisterOrganizer()622 public void testRegisterUnregisterOrganizer() { 623 final IDisplayAreaOrganizer mockDisplayAreaOrganizer = mock(IDisplayAreaOrganizer.class); 624 doReturn(mock(IBinder.class)).when(mockDisplayAreaOrganizer).asBinder(); 625 final DisplayAreaOrganizerController controller = 626 mWm.mAtmService.mWindowOrganizerController.mDisplayAreaOrganizerController; 627 controller.registerOrganizer(mockDisplayAreaOrganizer, FEATURE_VENDOR_FIRST); 628 controller.unregisterOrganizer(mockDisplayAreaOrganizer); 629 controller.registerOrganizer(mockDisplayAreaOrganizer, FEATURE_VENDOR_FIRST); 630 } 631 632 @Test testSetAlwaysOnTop_movesDisplayAreaToTop()633 public void testSetAlwaysOnTop_movesDisplayAreaToTop() { 634 final Rect bounds = new Rect(0, 0, 100, 100); 635 DisplayArea<WindowContainer> parent = new TestDisplayArea(mWm, bounds, "Parent"); 636 parent.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); 637 DisplayArea<WindowContainer> child1 = new TestDisplayArea(mWm, bounds, "Child1"); 638 child1.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); 639 DisplayArea<WindowContainer> child2 = new TestDisplayArea(mWm, bounds, "Child2"); 640 child2.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); 641 parent.addChild(child2, 0); 642 parent.addChild(child1, 1); 643 644 child2.setAlwaysOnTop(true); 645 646 assertEquals(parent.getChildAt(1), child2); 647 assertThat(child2.isAlwaysOnTop()).isTrue(); 648 } 649 650 @Test testDisplayAreaRequestsTopPosition_alwaysOnTopSiblingExists_doesNotMoveToTop()651 public void testDisplayAreaRequestsTopPosition_alwaysOnTopSiblingExists_doesNotMoveToTop() { 652 final Rect bounds = new Rect(0, 0, 100, 100); 653 DisplayArea<WindowContainer> parent = new TestDisplayArea(mWm, bounds, "Parent"); 654 parent.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); 655 DisplayArea<WindowContainer> alwaysOnTopChild = new TestDisplayArea(mWm, bounds, 656 "AlwaysOnTopChild"); 657 alwaysOnTopChild.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); 658 DisplayArea<WindowContainer> child = new TestDisplayArea(mWm, bounds, "Child"); 659 child.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); 660 parent.addChild(alwaysOnTopChild, 0); 661 parent.addChild(child, 1); 662 alwaysOnTopChild.setAlwaysOnTop(true); 663 664 parent.positionChildAt(POSITION_TOP, child, false /* includingParents */); 665 666 assertEquals(parent.getChildAt(1), alwaysOnTopChild); 667 assertEquals(parent.getChildAt(0), child); 668 } 669 670 @Test testAlwaysOnTopDisplayArea_requestsNonTopLocation_doesNotMove()671 public void testAlwaysOnTopDisplayArea_requestsNonTopLocation_doesNotMove() { 672 final Rect bounds = new Rect(0, 0, 100, 100); 673 DisplayArea<WindowContainer> parent = new TestDisplayArea(mWm, bounds, "Parent"); 674 parent.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); 675 DisplayArea<WindowContainer> alwaysOnTopChild = new TestDisplayArea(mWm, bounds, 676 "AlwaysOnTopChild"); 677 alwaysOnTopChild.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); 678 DisplayArea<WindowContainer> child = new TestDisplayArea(mWm, bounds, "Child"); 679 child.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); 680 parent.addChild(alwaysOnTopChild, 0); 681 parent.addChild(child, 1); 682 alwaysOnTopChild.setAlwaysOnTop(true); 683 684 parent.positionChildAt(POSITION_BOTTOM, alwaysOnTopChild, false /* includingParents */); 685 686 assertEquals(parent.getChildAt(1), alwaysOnTopChild); 687 assertEquals(parent.getChildAt(0), child); 688 } 689 690 private static class TestDisplayArea<T extends WindowContainer> extends DisplayArea<T> { TestDisplayArea(WindowManagerService wms, Rect bounds, String name)691 private TestDisplayArea(WindowManagerService wms, Rect bounds, String name) { 692 super(wms, ANY, name); 693 setBounds(bounds); 694 } 695 696 @Override makeChildSurface(WindowContainer child)697 SurfaceControl.Builder makeChildSurface(WindowContainer child) { 698 return new MockSurfaceControlBuilder(); 699 } 700 } 701 createWindowState(WindowToken token)702 private WindowState createWindowState(WindowToken token) { 703 return new WindowState(mWm, mock(Session.class), new TestIWindow(), token, 704 null /* parentWindow */, 0 /* appOp */, new WindowManager.LayoutParams(), 705 View.VISIBLE, 0 /* ownerId */, 0 /* showUserId */, 706 false /* ownerCanAddInternalSystemWindow */); 707 } 708 createWindowToken(int type)709 private WindowToken createWindowToken(int type) { 710 return new WindowToken.Builder(mWm, new Binder(), type).build(); 711 } 712 } 713