1 /* 2 * Copyright (C) 2019 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.KeyguardManager.ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER; 20 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; 21 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; 22 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; 23 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; 24 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 25 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; 26 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; 27 import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE; 28 import static android.view.Display.DEFAULT_DISPLAY; 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.spyOn; 34 import static com.android.server.wm.ActivityRecord.State.FINISHING; 35 import static com.android.server.wm.ActivityRecord.State.PAUSED; 36 import static com.android.server.wm.ActivityRecord.State.PAUSING; 37 import static com.android.server.wm.ActivityRecord.State.RESUMED; 38 import static com.android.server.wm.ActivityRecord.State.STOPPED; 39 import static com.android.server.wm.ActivityRecord.State.STOPPING; 40 import static com.android.server.wm.ActivityTaskSupervisor.ON_TOP; 41 import static com.android.server.wm.RootWindowContainer.MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE; 42 import static com.android.server.wm.WindowContainer.POSITION_BOTTOM; 43 44 import static com.google.common.truth.Truth.assertThat; 45 46 import static org.junit.Assert.assertEquals; 47 import static org.junit.Assert.assertFalse; 48 import static org.junit.Assert.assertNotEquals; 49 import static org.junit.Assert.assertNotNull; 50 import static org.junit.Assert.assertNull; 51 import static org.junit.Assert.assertTrue; 52 import static org.mockito.ArgumentMatchers.any; 53 import static org.mockito.ArgumentMatchers.anyBoolean; 54 import static org.mockito.ArgumentMatchers.anyInt; 55 import static org.mockito.ArgumentMatchers.contains; 56 import static org.mockito.ArgumentMatchers.eq; 57 import static org.mockito.ArgumentMatchers.refEq; 58 import static org.mockito.Mockito.clearInvocations; 59 import static org.mockito.Mockito.mock; 60 import static org.mockito.Mockito.never; 61 import static org.mockito.Mockito.reset; 62 import static org.mockito.Mockito.spy; 63 import static org.mockito.Mockito.times; 64 import static org.mockito.Mockito.verify; 65 66 import android.app.ActivityOptions; 67 import android.app.WindowConfiguration; 68 import android.content.ComponentName; 69 import android.content.Intent; 70 import android.content.pm.ActivityInfo; 71 import android.content.pm.ApplicationInfo; 72 import android.content.pm.ResolveInfo; 73 import android.content.res.Configuration; 74 import android.content.res.Resources; 75 import android.graphics.Rect; 76 import android.os.UserHandle; 77 import android.platform.test.annotations.Presubmit; 78 import android.util.MergedConfiguration; 79 import android.util.Pair; 80 81 import androidx.test.filters.MediumTest; 82 83 import com.android.internal.app.ResolverActivity; 84 85 import org.junit.Before; 86 import org.junit.Test; 87 import org.junit.runner.RunWith; 88 89 import java.util.ArrayList; 90 import java.util.Arrays; 91 import java.util.List; 92 import java.util.function.Consumer; 93 94 /** 95 * Tests for {@link RootWindowContainer}. 96 * 97 * Build/Install/Run: 98 * atest WmTests:RootWindowContainerTests 99 */ 100 @MediumTest 101 @Presubmit 102 @RunWith(WindowTestRunner.class) 103 public class RootWindowContainerTests extends WindowTestsBase { 104 105 @Before setUp()106 public void setUp() throws Exception { 107 doNothing().when(mAtm).updateSleepIfNeededLocked(); 108 } 109 110 @Test testUpdateDefaultTaskDisplayAreaWindowingModeOnSettingsRetrieved()111 public void testUpdateDefaultTaskDisplayAreaWindowingModeOnSettingsRetrieved() { 112 assertEquals(WindowConfiguration.WINDOWING_MODE_FULLSCREEN, 113 mWm.getDefaultDisplayContentLocked().getDefaultTaskDisplayArea() 114 .getWindowingMode()); 115 116 mWm.mIsPc = true; 117 mWm.mAtmService.mSupportsFreeformWindowManagement = true; 118 119 mWm.mRoot.onSettingsRetrieved(); 120 121 assertEquals(WindowConfiguration.WINDOWING_MODE_FREEFORM, 122 mWm.getDefaultDisplayContentLocked().getDefaultTaskDisplayArea() 123 .getWindowingMode()); 124 } 125 126 /** 127 * This test ensures that an existing single instance activity with alias name can be found by 128 * the same activity info. So {@link ActivityStarter#getReusableTask} won't miss it that leads 129 * to create an unexpected new instance. 130 */ 131 @Test testFindActivityByTargetComponent()132 public void testFindActivityByTargetComponent() { 133 final ComponentName aliasComponent = ComponentName.createRelative( 134 DEFAULT_COMPONENT_PACKAGE_NAME, ".AliasActivity"); 135 final ComponentName targetComponent = ComponentName.createRelative( 136 aliasComponent.getPackageName(), ".TargetActivity"); 137 final ActivityRecord activity = new ActivityBuilder(mWm.mAtmService) 138 .setComponent(aliasComponent) 139 .setTargetActivity(targetComponent.getClassName()) 140 .setLaunchMode(ActivityInfo.LAUNCH_SINGLE_INSTANCE) 141 .setCreateTask(true) 142 .build(); 143 144 assertEquals(activity, mWm.mRoot.findActivity(activity.intent, activity.info, 145 false /* compareIntentFilters */)); 146 } 147 148 @Test testAllPausedActivitiesComplete()149 public void testAllPausedActivitiesComplete() { 150 DisplayContent displayContent = mWm.mRoot.getDisplayContent(DEFAULT_DISPLAY); 151 ActivityRecord activity = createActivityRecord(displayContent); 152 Task task = activity.getTask(); 153 task.setPausingActivity(activity); 154 155 activity.setState(PAUSING, "test PAUSING"); 156 assertThat(mWm.mRoot.allPausedActivitiesComplete()).isFalse(); 157 158 activity.setState(PAUSED, "test PAUSED"); 159 assertThat(mWm.mRoot.allPausedActivitiesComplete()).isTrue(); 160 161 activity.setState(STOPPED, "test STOPPED"); 162 assertThat(mWm.mRoot.allPausedActivitiesComplete()).isTrue(); 163 164 activity.setState(STOPPING, "test STOPPING"); 165 assertThat(mWm.mRoot.allPausedActivitiesComplete()).isTrue(); 166 167 activity.setState(FINISHING, "test FINISHING"); 168 assertThat(mWm.mRoot.allPausedActivitiesComplete()).isTrue(); 169 } 170 171 @Test testTaskLayerRank()172 public void testTaskLayerRank() { 173 final Task rootTask = new TaskBuilder(mSupervisor).build(); 174 final Task task1 = new TaskBuilder(mSupervisor).setParentTaskFragment(rootTask).build(); 175 new ActivityBuilder(mAtm).setTask(task1).build().setVisibleRequested(true); 176 mWm.mRoot.rankTaskLayers(); 177 178 assertEquals(1, task1.mLayerRank); 179 // Only tasks that directly contain activities have a ranking. 180 assertEquals(Task.LAYER_RANK_INVISIBLE, rootTask.mLayerRank); 181 182 final Task task2 = new TaskBuilder(mSupervisor).build(); 183 new ActivityBuilder(mAtm).setTask(task2).build().setVisibleRequested(true); 184 mWm.mRoot.rankTaskLayers(); 185 186 // Note that ensureActivitiesVisible is disabled in SystemServicesTestRule, so both the 187 // activities have the visible rank. 188 assertEquals(2, task1.mLayerRank); 189 // The task2 is the top task, so it has a lower rank as a higher priority oom score. 190 assertEquals(1, task2.mLayerRank); 191 192 task2.moveToBack("test", null /* task */); 193 // RootWindowContainer#invalidateTaskLayers should post to update. 194 waitHandlerIdle(mWm.mH); 195 196 assertEquals(1, task1.mLayerRank); 197 assertEquals(2, task2.mLayerRank); 198 } 199 200 @Test testForceStopPackage()201 public void testForceStopPackage() { 202 final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).build(); 203 final ActivityRecord activity = task.getTopMostActivity(); 204 final WindowProcessController wpc = activity.app; 205 final ActivityRecord[] activities = { 206 activity, 207 new ActivityBuilder(mWm.mAtmService).setTask(task).setUseProcess(wpc).build(), 208 new ActivityBuilder(mWm.mAtmService).setTask(task).setUseProcess(wpc).build() 209 }; 210 activities[0].detachFromProcess(); 211 activities[1].finishing = true; 212 activities[1].destroyImmediately("test"); 213 spyOn(wpc); 214 doReturn(true).when(wpc).isRemoved(); 215 216 mWm.mAtmService.mInternal.onForceStopPackage(wpc.mInfo.packageName, true /* doit */, 217 false /* evenPersistent */, wpc.mUserId); 218 // The activity without process should be removed. 219 assertEquals(2, task.getChildCount()); 220 221 wpc.handleAppDied(); 222 // The activities with process should be removed because WindowProcessController#isRemoved. 223 assertFalse(task.hasChild()); 224 assertFalse(wpc.hasActivities()); 225 } 226 227 /** 228 * This test ensures that we do not try to restore a task based off an invalid task id. We 229 * should expect {@code null} to be returned in this case. 230 */ 231 @Test testRestoringInvalidTask()232 public void testRestoringInvalidTask() { 233 mRootWindowContainer.getDefaultDisplay().removeAllTasks(); 234 Task task = mRootWindowContainer.anyTaskForId(0 /*taskId*/, 235 MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE, null, false /* onTop */); 236 assertNull(task); 237 } 238 239 /** 240 * This test ensures that an existing task in the pinned root task is moved to the fullscreen 241 * activity root task when a new task is added. 242 */ 243 @Test testReplacingTaskInPinnedRootTask()244 public void testReplacingTaskInPinnedRootTask() { 245 Task fullscreenTask = mRootWindowContainer.getDefaultTaskDisplayArea().createRootTask( 246 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); 247 final ActivityRecord firstActivity = new ActivityBuilder(mAtm) 248 .setTask(fullscreenTask).build(); 249 final ActivityRecord secondActivity = new ActivityBuilder(mAtm) 250 .setTask(fullscreenTask).build(); 251 252 fullscreenTask.moveToFront("testReplacingTaskInPinnedRootTask"); 253 254 // Ensure full screen root task has both tasks. 255 ensureTaskPlacement(fullscreenTask, firstActivity, secondActivity); 256 257 // Move first activity to pinned root task. 258 mRootWindowContainer.moveActivityToPinnedRootTask(firstActivity, 259 null /* launchIntoPipHostActivity */, "initialMove"); 260 261 final TaskDisplayArea taskDisplayArea = fullscreenTask.getDisplayArea(); 262 Task pinnedRootTask = taskDisplayArea.getRootPinnedTask(); 263 // Ensure a task has moved over. 264 ensureTaskPlacement(pinnedRootTask, firstActivity); 265 ensureTaskPlacement(fullscreenTask, secondActivity); 266 267 // Move second activity to pinned root task. 268 mRootWindowContainer.moveActivityToPinnedRootTask(secondActivity, 269 null /* launchIntoPipHostActivity */, "secondMove"); 270 271 // Need to get root tasks again as a new instance might have been created. 272 pinnedRootTask = taskDisplayArea.getRootPinnedTask(); 273 fullscreenTask = taskDisplayArea.getRootTask(WINDOWING_MODE_FULLSCREEN, 274 ACTIVITY_TYPE_STANDARD); 275 // Ensure root tasks have swapped tasks. 276 ensureTaskPlacement(pinnedRootTask, secondActivity); 277 ensureTaskPlacement(fullscreenTask, firstActivity); 278 } 279 280 @Test testMovingBottomMostRootTaskActivityToPinnedRootTask()281 public void testMovingBottomMostRootTaskActivityToPinnedRootTask() { 282 final Task fullscreenTask = mRootWindowContainer.getDefaultTaskDisplayArea().createRootTask( 283 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); 284 final ActivityRecord firstActivity = new ActivityBuilder(mAtm) 285 .setTask(fullscreenTask).build(); 286 final Task task = firstActivity.getTask(); 287 288 final ActivityRecord secondActivity = new ActivityBuilder(mAtm) 289 .setTask(fullscreenTask).build(); 290 291 fullscreenTask.moveTaskToBack(task); 292 293 // Ensure full screen task has both tasks. 294 ensureTaskPlacement(fullscreenTask, firstActivity, secondActivity); 295 assertEquals(task.getTopMostActivity(), secondActivity); 296 firstActivity.setState(STOPPED, "testMovingBottomMostRootTaskActivityToPinnedRootTask"); 297 298 299 // Move first activity to pinned root task. 300 mRootWindowContainer.moveActivityToPinnedRootTask(secondActivity, 301 null /* launchIntoPipHostActivity */, "initialMove"); 302 303 assertTrue(firstActivity.mRequestForceTransition); 304 } 305 306 /** 307 * When there is only one activity in the Task, and the activity is requesting to enter PIP, the 308 * whole Task should enter PIP. 309 */ 310 @Test testSingleActivityTaskEnterPip()311 public void testSingleActivityTaskEnterPip() { 312 final Task fullscreenTask = mRootWindowContainer.getDefaultTaskDisplayArea().createRootTask( 313 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); 314 final ActivityRecord activity = new ActivityBuilder(mAtm) 315 .setTask(fullscreenTask) 316 .build(); 317 final Task task = activity.getTask(); 318 319 // Move activity to pinned root task. 320 mRootWindowContainer.moveActivityToPinnedRootTask(activity, 321 null /* launchIntoPipHostActivity */, "test"); 322 323 // Ensure a task has moved over. 324 ensureTaskPlacement(task, activity); 325 assertTrue(task.inPinnedWindowingMode()); 326 } 327 328 /** 329 * When there is only one activity in the Task, and the activity is requesting to enter PIP, the 330 * whole Task should enter PIP even if the activity is in a TaskFragment. 331 */ 332 @Test testSingleActivityInTaskFragmentEnterPip()333 public void testSingleActivityInTaskFragmentEnterPip() { 334 final Task fullscreenTask = mRootWindowContainer.getDefaultTaskDisplayArea().createRootTask( 335 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); 336 final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm) 337 .setParentTask(fullscreenTask) 338 .createActivityCount(1) 339 .build(); 340 final ActivityRecord activity = taskFragment.getTopMostActivity(); 341 final Task task = activity.getTask(); 342 343 // Move activity to pinned root task. 344 mRootWindowContainer.moveActivityToPinnedRootTask(activity, 345 null /* launchIntoPipHostActivity */, "test"); 346 347 // Ensure a task has moved over. 348 ensureTaskPlacement(task, activity); 349 assertTrue(task.inPinnedWindowingMode()); 350 } 351 352 /** 353 * When there is one TaskFragment with two activities in the Task, the activity requests to 354 * enter PIP, that activity will be move to PIP root task. 355 */ 356 @Test testMultipleActivitiesInTaskFragmentEnterPip()357 public void testMultipleActivitiesInTaskFragmentEnterPip() { 358 final Task fullscreenTask = mRootWindowContainer.getDefaultTaskDisplayArea().createRootTask( 359 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); 360 final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm) 361 .setParentTask(fullscreenTask) 362 .createActivityCount(2) 363 .build(); 364 final ActivityRecord firstActivity = taskFragment.getTopMostActivity(); 365 final ActivityRecord secondActivity = taskFragment.getBottomMostActivity(); 366 367 // Move first activity to pinned root task. 368 mRootWindowContainer.moveActivityToPinnedRootTask(firstActivity, 369 null /* launchIntoPipHostActivity */, "test"); 370 371 final TaskDisplayArea taskDisplayArea = fullscreenTask.getDisplayArea(); 372 final Task pinnedRootTask = taskDisplayArea.getRootPinnedTask(); 373 374 // Ensure a task has moved over. 375 ensureTaskPlacement(pinnedRootTask, firstActivity); 376 ensureTaskPlacement(fullscreenTask, secondActivity); 377 assertTrue(pinnedRootTask.inPinnedWindowingMode()); 378 assertEquals(WINDOWING_MODE_FULLSCREEN, fullscreenTask.getWindowingMode()); 379 } 380 381 @Test testMovingEmbeddedActivityToPip()382 public void testMovingEmbeddedActivityToPip() { 383 final Rect taskBounds = new Rect(0, 0, 800, 1000); 384 final Rect taskFragmentBounds = new Rect(0, 0, 400, 1000); 385 final Task task = mRootWindowContainer.getDefaultTaskDisplayArea().createRootTask( 386 WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD, true /* onTop */); 387 task.setBounds(taskBounds); 388 assertEquals(taskBounds, task.getBounds()); 389 final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm) 390 .setParentTask(task) 391 .createActivityCount(2) 392 .setBounds(taskFragmentBounds) 393 .build(); 394 assertEquals(taskFragmentBounds, taskFragment.getBounds()); 395 final ActivityRecord topActivity = taskFragment.getTopMostActivity(); 396 397 // Move the top activity to pinned root task. 398 mRootWindowContainer.moveActivityToPinnedRootTask(topActivity, 399 null /* launchIntoPipHostActivity */, "test"); 400 401 final Task pinnedRootTask = task.getDisplayArea().getRootPinnedTask(); 402 403 // Ensure the initial bounds of the PiP Task is the same as the TaskFragment. 404 ensureTaskPlacement(pinnedRootTask, topActivity); 405 assertEquals(taskFragmentBounds, pinnedRootTask.getBounds()); 406 } 407 ensureTaskPlacement(Task task, ActivityRecord... activities)408 private static void ensureTaskPlacement(Task task, ActivityRecord... activities) { 409 final ArrayList<ActivityRecord> taskActivities = new ArrayList<>(); 410 411 task.forAllActivities((Consumer<ActivityRecord>) taskActivities::add, false); 412 413 assertEquals("Expecting " + Arrays.deepToString(activities) + " got " + taskActivities, 414 taskActivities.size(), activities != null ? activities.length : 0); 415 416 if (activities == null) { 417 return; 418 } 419 420 for (ActivityRecord activity : activities) { 421 assertTrue(taskActivities.contains(activity)); 422 } 423 } 424 425 @Test testApplySleepTokens()426 public void testApplySleepTokens() { 427 final DisplayContent display = mRootWindowContainer.getDefaultDisplay(); 428 final KeyguardController keyguard = mSupervisor.getKeyguardController(); 429 final Task task = new TaskBuilder(mSupervisor) 430 .setDisplay(display) 431 .setOnTop(false) 432 .build(); 433 434 // Make sure we wake and resume in the case the display is turning on and the keyguard is 435 // not showing. 436 verifySleepTokenBehavior(display, keyguard, task, true /*displaySleeping*/, 437 false /* displayShouldSleep */, true /* isFocusedTask */, 438 false /* keyguardShowing */, true /* expectWakeFromSleep */, 439 true /* expectResumeTopActivity */); 440 441 // Make sure we wake and don't resume when the display is turning on and the keyguard is 442 // showing. 443 verifySleepTokenBehavior(display, keyguard, task, true /*displaySleeping*/, 444 false /* displayShouldSleep */, true /* isFocusedTask */, 445 true /* keyguardShowing */, true /* expectWakeFromSleep */, 446 false /* expectResumeTopActivity */); 447 448 // Make sure we wake and don't resume when the display is turning on and the keyguard is 449 // not showing as unfocused. 450 verifySleepTokenBehavior(display, keyguard, task, true /*displaySleeping*/, 451 false /* displayShouldSleep */, false /* isFocusedTask */, 452 false /* keyguardShowing */, true /* expectWakeFromSleep */, 453 false /* expectResumeTopActivity */); 454 455 // Should not do anything if the display state hasn't changed. 456 verifySleepTokenBehavior(display, keyguard, task, false /*displaySleeping*/, 457 false /* displayShouldSleep */, true /* isFocusedTask */, 458 false /* keyguardShowing */, false /* expectWakeFromSleep */, 459 false /* expectResumeTopActivity */); 460 } 461 verifySleepTokenBehavior(DisplayContent display, KeyguardController keyguard, Task task, boolean displaySleeping, boolean displayShouldSleep, boolean isFocusedTask, boolean keyguardShowing, boolean expectWakeFromSleep, boolean expectResumeTopActivity)462 private void verifySleepTokenBehavior(DisplayContent display, KeyguardController keyguard, 463 Task task, boolean displaySleeping, boolean displayShouldSleep, 464 boolean isFocusedTask, boolean keyguardShowing, boolean expectWakeFromSleep, 465 boolean expectResumeTopActivity) { 466 reset(task); 467 468 doReturn(displayShouldSleep).when(display).shouldSleep(); 469 doReturn(displaySleeping).when(display).isSleeping(); 470 doReturn(keyguardShowing).when(keyguard).isKeyguardOrAodShowing(anyInt()); 471 472 doReturn(isFocusedTask).when(task).isFocusedRootTaskOnDisplay(); 473 doReturn(isFocusedTask ? task : null).when(display).getFocusedRootTask(); 474 TaskDisplayArea defaultTaskDisplayArea = display.getDefaultTaskDisplayArea(); 475 doReturn(isFocusedTask ? task : null).when(defaultTaskDisplayArea).getFocusedRootTask(); 476 mRootWindowContainer.applySleepTokens(true); 477 verify(task, times(expectWakeFromSleep ? 1 : 0)).awakeFromSleeping(); 478 verify(task, times(expectResumeTopActivity ? 1 : 0)).resumeTopActivityUncheckedLocked( 479 null /* target */, null /* targetOptions */); 480 } 481 482 @Test testAwakeFromSleepingWithAppConfiguration()483 public void testAwakeFromSleepingWithAppConfiguration() { 484 final DisplayContent display = mRootWindowContainer.getDefaultDisplay(); 485 final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build(); 486 activity.moveFocusableActivityToTop("test"); 487 assertTrue(activity.getRootTask().isFocusedRootTaskOnDisplay()); 488 ActivityRecordTests.setRotatedScreenOrientationSilently(activity); 489 490 final Configuration rotatedConfig = new Configuration(); 491 display.computeScreenConfiguration(rotatedConfig, display.getDisplayRotation() 492 .rotationForOrientation(activity.getOrientation(), display.getRotation())); 493 assertNotEquals(activity.getConfiguration().orientation, rotatedConfig.orientation); 494 // Assume the activity was shown in different orientation. For example, the top activity is 495 // landscape and the portrait lockscreen is shown. 496 activity.setLastReportedConfiguration( 497 new MergedConfiguration(mAtm.getGlobalConfiguration(), rotatedConfig)); 498 activity.setState(STOPPED, "sleep"); 499 500 display.setIsSleeping(true); 501 doReturn(false).when(display).shouldSleep(); 502 // Allow to resume when awaking. 503 setBooted(mAtm); 504 mRootWindowContainer.applySleepTokens(true); 505 506 // The display orientation should be changed by the activity so there is no relaunch. 507 verify(activity, never()).relaunchActivityLocked(anyBoolean()); 508 assertEquals(rotatedConfig.orientation, display.getConfiguration().orientation); 509 } 510 511 /** 512 * Verifies that removal of activity with task and root task is done correctly. 513 */ 514 @Test testRemovingRootTaskOnAppCrash()515 public void testRemovingRootTaskOnAppCrash() { 516 final TaskDisplayArea defaultTaskDisplayArea = mRootWindowContainer 517 .getDefaultTaskDisplayArea(); 518 final int originalRootTaskCount = defaultTaskDisplayArea.getRootTaskCount(); 519 final Task rootTask = defaultTaskDisplayArea.createRootTask( 520 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); 521 final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setTask(rootTask).build(); 522 523 assertEquals(originalRootTaskCount + 1, defaultTaskDisplayArea.getRootTaskCount()); 524 525 // Let's pretend that the app has crashed. 526 firstActivity.app.setThread(null); 527 mRootWindowContainer.finishTopCrashedActivities(firstActivity.app, "test"); 528 529 // Verify that the root task was removed. 530 assertEquals(originalRootTaskCount, defaultTaskDisplayArea.getRootTaskCount()); 531 } 532 533 /** 534 * Verifies that removal of activities with task and root task is done correctly when there are 535 * several task display areas. 536 */ 537 @Test testRemovingRootTaskOnAppCrash_multipleDisplayAreas()538 public void testRemovingRootTaskOnAppCrash_multipleDisplayAreas() { 539 final TaskDisplayArea defaultTaskDisplayArea = mRootWindowContainer 540 .getDefaultTaskDisplayArea(); 541 final int originalRootTaskCount = defaultTaskDisplayArea.getRootTaskCount(); 542 final Task rootTask = defaultTaskDisplayArea.createRootTask( 543 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); 544 final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setTask(rootTask).build(); 545 assertEquals(originalRootTaskCount + 1, defaultTaskDisplayArea.getRootTaskCount()); 546 547 final DisplayContent dc = defaultTaskDisplayArea.getDisplayContent(); 548 final TaskDisplayArea secondTaskDisplayArea = createTaskDisplayArea( 549 dc, mRootWindowContainer.mWmService, "TestTaskDisplayArea", FEATURE_VENDOR_FIRST); 550 final Task secondRootTask = secondTaskDisplayArea.createRootTask( 551 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); 552 new ActivityBuilder(mAtm).setTask(secondRootTask).setUseProcess(firstActivity.app).build(); 553 assertEquals(1, secondTaskDisplayArea.getRootTaskCount()); 554 555 // Let's pretend that the app has crashed. 556 firstActivity.app.setThread(null); 557 mRootWindowContainer.finishTopCrashedActivities(firstActivity.app, "test"); 558 559 // Verify that the root tasks were removed. 560 assertEquals(originalRootTaskCount, defaultTaskDisplayArea.getRootTaskCount()); 561 assertEquals(0, secondTaskDisplayArea.getRootTaskCount()); 562 } 563 564 @Test testFocusability()565 public void testFocusability() { 566 final TaskDisplayArea defaultTaskDisplayArea = mRootWindowContainer 567 .getDefaultTaskDisplayArea(); 568 final Task task = defaultTaskDisplayArea.createRootTask( 569 WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD, true /* onTop */); 570 final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task).build(); 571 572 // Created tasks are focusable by default. 573 assertTrue(task.isTopActivityFocusable()); 574 assertTrue(activity.isFocusable()); 575 576 // If the task is made unfocusable, its activities should inherit that. 577 task.setFocusable(false); 578 assertFalse(task.isTopActivityFocusable()); 579 assertFalse(activity.isFocusable()); 580 581 final Task pinnedTask = defaultTaskDisplayArea.createRootTask( 582 WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */); 583 final ActivityRecord pinnedActivity = new ActivityBuilder(mAtm) 584 .setTask(pinnedTask).build(); 585 586 // We should not be focusable when in pinned mode 587 assertFalse(pinnedTask.isTopActivityFocusable()); 588 assertFalse(pinnedActivity.isFocusable()); 589 590 // Add flag forcing focusability. 591 pinnedActivity.info.flags |= FLAG_ALWAYS_FOCUSABLE; 592 593 // Task with FLAG_ALWAYS_FOCUSABLE should be focusable. 594 assertTrue(pinnedTask.isTopActivityFocusable()); 595 assertTrue(pinnedActivity.isFocusable()); 596 } 597 598 /** 599 * Verify that home root task would be moved to front when the top activity is Recents. 600 */ 601 @Test testFindTaskToMoveToFrontWhenRecentsOnTop()602 public void testFindTaskToMoveToFrontWhenRecentsOnTop() { 603 // Create root task/task on default display. 604 final Task targetRootTask = new TaskBuilder(mSupervisor) 605 .setCreateActivity(true) 606 .setOnTop(false) 607 .build(); 608 final Task targetTask = targetRootTask.getBottomMostTask(); 609 610 // Create Recents on top of the display. 611 final Task rootTask = new TaskBuilder(mSupervisor) 612 .setCreateActivity(true) 613 .setActivityType(ACTIVITY_TYPE_RECENTS) 614 .build(); 615 616 final String reason = "findTaskToMoveToFront"; 617 mSupervisor.findTaskToMoveToFront(targetTask, 0, ActivityOptions.makeBasic(), reason, 618 false); 619 620 final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); 621 verify(taskDisplayArea).moveHomeRootTaskToFront(contains(reason)); 622 } 623 624 /** 625 * Verify that home root task won't be moved to front if the top activity on other display is 626 * Recents. 627 */ 628 @Test testFindTaskToMoveToFrontWhenRecentsOnOtherDisplay()629 public void testFindTaskToMoveToFrontWhenRecentsOnOtherDisplay() { 630 // Create tasks on default display. 631 final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); 632 final Task targetRootTask = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN, 633 ACTIVITY_TYPE_STANDARD, false /* onTop */); 634 final Task targetTask = new TaskBuilder(mSupervisor).setParentTaskFragment(targetRootTask) 635 .build(); 636 637 // Create Recents on secondary display. 638 final TestDisplayContent secondDisplay = addNewDisplayContentAt( 639 DisplayContent.POSITION_TOP); 640 final Task rootTask = secondDisplay.getDefaultTaskDisplayArea() 641 .createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_RECENTS, true /* onTop */); 642 new ActivityBuilder(mAtm).setTask(rootTask).build(); 643 644 final String reason = "findTaskToMoveToFront"; 645 mSupervisor.findTaskToMoveToFront(targetTask, 0, ActivityOptions.makeBasic(), reason, 646 false); 647 648 verify(taskDisplayArea, never()).moveHomeRootTaskToFront(contains(reason)); 649 } 650 651 /** 652 * Verify if a root task is not at the topmost position, it should be able to resume its 653 * activity if the root task is the top focused. 654 */ 655 @Test testResumeActivityWhenNonTopmostRootTaskIsTopFocused()656 public void testResumeActivityWhenNonTopmostRootTaskIsTopFocused() { 657 // Create a root task at bottom. 658 final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); 659 final Task rootTask = spy(taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN, 660 ACTIVITY_TYPE_STANDARD, false /* onTop */)); 661 final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(rootTask).build(); 662 taskDisplayArea.positionChildAt(POSITION_BOTTOM, rootTask, false /*includingParents*/); 663 664 // Assume the task is not at the topmost position (e.g. behind always-on-top root tasks) 665 // but it is the current top focused task. 666 assertFalse(rootTask.isTopRootTaskInDisplayArea()); 667 doReturn(rootTask).when(mRootWindowContainer).getTopDisplayFocusedRootTask(); 668 669 // Use the task as target to resume. 670 mRootWindowContainer.resumeFocusedTasksTopActivities(rootTask, activity, 671 null /* targetOptions */); 672 673 // Verify the target task should resume its activity. 674 verify(rootTask, times(1)).resumeTopActivityUncheckedLocked( 675 eq(activity), eq(null /* targetOptions */), eq(false)); 676 } 677 678 /** 679 * Verify that home activity will be started on a display even if another display has a 680 * focusable activity. 681 */ 682 @Test testResumeFocusedRootTasksStartsHomeActivity_NoActivities()683 public void testResumeFocusedRootTasksStartsHomeActivity_NoActivities() { 684 final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); 685 taskDisplayArea.getRootHomeTask().removeIfPossible(); 686 taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP); 687 688 doReturn(true).when(mRootWindowContainer).resumeHomeActivity(any(), any(), any()); 689 690 setBooted(mAtm); 691 692 // Trigger resume on all displays 693 mRootWindowContainer.resumeFocusedTasksTopActivities(); 694 695 // Verify that home activity was started on the default display 696 verify(mRootWindowContainer).resumeHomeActivity(any(), any(), eq(taskDisplayArea)); 697 } 698 699 /** 700 * Verify that home activity will be started on a display even if another display has a 701 * focusable activity. 702 */ 703 @Test testResumeFocusedRootTasksStartsHomeActivity_ActivityOnSecondaryScreen()704 public void testResumeFocusedRootTasksStartsHomeActivity_ActivityOnSecondaryScreen() { 705 final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); 706 taskDisplayArea.getRootHomeTask().removeIfPossible(); 707 taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP); 708 709 // Create an activity on secondary display. 710 final TestDisplayContent secondDisplay = addNewDisplayContentAt( 711 DisplayContent.POSITION_TOP); 712 final Task rootTask = secondDisplay.getDefaultTaskDisplayArea().createRootTask( 713 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); 714 new ActivityBuilder(mAtm).setTask(rootTask).build(); 715 716 doReturn(true).when(mRootWindowContainer).resumeHomeActivity(any(), any(), any()); 717 718 setBooted(mAtm); 719 720 // Trigger resume on all displays 721 mRootWindowContainer.resumeFocusedTasksTopActivities(); 722 723 // Verify that home activity was started on the default display 724 verify(mRootWindowContainer).resumeHomeActivity(any(), any(), eq(taskDisplayArea)); 725 } 726 727 /** 728 * Verify that a lingering transition is being executed in case the activity to be resumed is 729 * already resumed 730 */ 731 @Test testResumeActivityLingeringTransition()732 public void testResumeActivityLingeringTransition() { 733 // Create a root task at top. 734 final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); 735 final Task rootTask = spy(taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN, 736 ACTIVITY_TYPE_STANDARD, false /* onTop */)); 737 final ActivityRecord activity = new ActivityBuilder(mAtm) 738 .setTask(rootTask).setOnTop(true).build(); 739 activity.setState(RESUMED, "test"); 740 741 // Assume the task is at the topmost position 742 assertTrue(rootTask.isTopRootTaskInDisplayArea()); 743 744 // Use the task as target to resume. 745 mRootWindowContainer.resumeFocusedTasksTopActivities(); 746 747 // Verify the lingering app transition is being executed because it's already resumed 748 verify(rootTask, times(1)).executeAppTransition(any()); 749 } 750 751 @Test testResumeActivityLingeringTransition_notExecuted()752 public void testResumeActivityLingeringTransition_notExecuted() { 753 // Create a root task at bottom. 754 final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); 755 final Task rootTask = spy(taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN, 756 ACTIVITY_TYPE_STANDARD, false /* onTop */)); 757 final ActivityRecord activity = new ActivityBuilder(mAtm) 758 .setTask(rootTask).setOnTop(true).build(); 759 activity.setState(RESUMED, "test"); 760 taskDisplayArea.positionChildAt(POSITION_BOTTOM, rootTask, false /*includingParents*/); 761 762 // Assume the task is at the topmost position 763 assertFalse(rootTask.isTopRootTaskInDisplayArea()); 764 doReturn(taskDisplayArea.getHomeActivity()).when(taskDisplayArea).topRunningActivity(); 765 766 // Use the task as target to resume. 767 mRootWindowContainer.resumeFocusedTasksTopActivities(); 768 769 // Verify the lingering app transition is being executed because it's already resumed 770 verify(rootTask, never()).executeAppTransition(any()); 771 } 772 773 /** 774 * Tests that home activities can be started on the displays that supports system decorations. 775 */ 776 @Test testStartHomeOnAllDisplays()777 public void testStartHomeOnAllDisplays() { 778 mockResolveHomeActivity(true /* primaryHome */, false /* forceSystemProvided */); 779 mockResolveSecondaryHomeActivity(); 780 781 // Create secondary displays. 782 final TestDisplayContent secondDisplay = 783 new TestDisplayContent.Builder(mAtm, 1000, 1500) 784 .setSystemDecorations(true).build(); 785 786 doReturn(true).when(mRootWindowContainer) 787 .ensureVisibilityAndConfig(any(), anyInt(), anyBoolean(), anyBoolean()); 788 doReturn(true).when(mRootWindowContainer).canStartHomeOnDisplayArea(any(), any(), 789 anyBoolean()); 790 791 mRootWindowContainer.startHomeOnAllDisplays(0, "testStartHome"); 792 793 assertTrue(mRootWindowContainer.getDefaultDisplay().getTopRootTask().isActivityTypeHome()); 794 assertNotNull(secondDisplay.getTopRootTask()); 795 assertTrue(secondDisplay.getTopRootTask().isActivityTypeHome()); 796 } 797 798 /** 799 * Tests that home activities won't be started before booting when display added. 800 */ 801 @Test testNotStartHomeBeforeBoot()802 public void testNotStartHomeBeforeBoot() { 803 final int displayId = 1; 804 doReturn(false).when(mAtm).isBooting(); 805 doReturn(false).when(mAtm).isBooted(); 806 mRootWindowContainer.onDisplayAdded(displayId); 807 verify(mRootWindowContainer, never()).startHomeOnDisplay(anyInt(), any(), anyInt()); 808 } 809 810 /** 811 * Tests whether home can be started if being instrumented. 812 */ 813 @Test testCanStartHomeWhenInstrumented()814 public void testCanStartHomeWhenInstrumented() { 815 final ActivityInfo info = new ActivityInfo(); 816 info.applicationInfo = new ApplicationInfo(); 817 final WindowProcessController app = mock(WindowProcessController.class); 818 doReturn(app).when(mAtm).getProcessController(any(), anyInt()); 819 820 // Can not start home if we don't want to start home while home is being instrumented. 821 doReturn(true).when(app).isInstrumenting(); 822 final TaskDisplayArea defaultTaskDisplayArea = mRootWindowContainer 823 .getDefaultTaskDisplayArea(); 824 assertFalse(mRootWindowContainer.canStartHomeOnDisplayArea(info, defaultTaskDisplayArea, 825 false /* allowInstrumenting*/)); 826 827 // Can start home for other cases. 828 assertTrue(mRootWindowContainer.canStartHomeOnDisplayArea(info, defaultTaskDisplayArea, 829 true /* allowInstrumenting*/)); 830 831 doReturn(false).when(app).isInstrumenting(); 832 assertTrue(mRootWindowContainer.canStartHomeOnDisplayArea(info, defaultTaskDisplayArea, 833 false /* allowInstrumenting*/)); 834 assertTrue(mRootWindowContainer.canStartHomeOnDisplayArea(info, defaultTaskDisplayArea, 835 true /* allowInstrumenting*/)); 836 } 837 838 /** 839 * Tests that secondary home activity should not be resolved if device is still locked. 840 */ 841 @Test testStartSecondaryHomeOnDisplayWithUserKeyLocked()842 public void testStartSecondaryHomeOnDisplayWithUserKeyLocked() { 843 // Create secondary displays. 844 final TestDisplayContent secondDisplay = 845 new TestDisplayContent.Builder(mAtm, 1000, 1500) 846 .setSystemDecorations(true).build(); 847 848 // Use invalid user id to let StorageManager.isUserKeyUnlocked() return false. 849 final int currentUser = mRootWindowContainer.mCurrentUser; 850 mRootWindowContainer.mCurrentUser = -1; 851 852 mRootWindowContainer.startHomeOnDisplay(0 /* userId */, "testStartSecondaryHome", 853 secondDisplay.mDisplayId, true /* allowInstrumenting */, true /* fromHomeKey */); 854 855 try { 856 verify(mRootWindowContainer, never()).resolveSecondaryHomeActivity(anyInt(), any()); 857 } finally { 858 mRootWindowContainer.mCurrentUser = currentUser; 859 } 860 } 861 862 /** 863 * Tests that secondary home activity should not be resolved if display does not support system 864 * decorations. 865 */ 866 @Test testStartSecondaryHomeOnDisplayWithoutSysDecorations()867 public void testStartSecondaryHomeOnDisplayWithoutSysDecorations() { 868 // Create secondary displays. 869 final TestDisplayContent secondDisplay = 870 new TestDisplayContent.Builder(mAtm, 1000, 1500) 871 .setSystemDecorations(false).build(); 872 873 mRootWindowContainer.startHomeOnDisplay(0 /* userId */, "testStartSecondaryHome", 874 secondDisplay.mDisplayId, true /* allowInstrumenting */, true /* fromHomeKey */); 875 876 verify(mRootWindowContainer, never()).resolveSecondaryHomeActivity(anyInt(), any()); 877 } 878 879 /** 880 * Tests that when starting {@link ResolverActivity} for home, it should use the standard 881 * activity type (in a new root task) so the order of back stack won't be broken. 882 */ 883 @Test testStartResolverActivityForHome()884 public void testStartResolverActivityForHome() { 885 final ActivityInfo info = new ActivityInfo(); 886 info.applicationInfo = new ApplicationInfo(); 887 info.applicationInfo.packageName = "android"; 888 info.name = ResolverActivity.class.getName(); 889 doReturn(info).when(mRootWindowContainer).resolveHomeActivity(anyInt(), any()); 890 891 mRootWindowContainer.startHomeOnDisplay(0 /* userId */, "test", DEFAULT_DISPLAY); 892 final ActivityRecord resolverActivity = mRootWindowContainer.topRunningActivity(); 893 894 assertEquals(info, resolverActivity.info); 895 assertEquals(ACTIVITY_TYPE_STANDARD, resolverActivity.getRootTask().getActivityType()); 896 } 897 898 /** 899 * Tests that secondary home should be selected if primary home not set. 900 */ 901 @Test testResolveSecondaryHomeActivityWhenPrimaryHomeNotSet()902 public void testResolveSecondaryHomeActivityWhenPrimaryHomeNotSet() { 903 // Setup: primary home not set. 904 final Intent primaryHomeIntent = mAtm.getHomeIntent(); 905 final ActivityInfo aInfoPrimary = new ActivityInfo(); 906 aInfoPrimary.name = ResolverActivity.class.getName(); 907 doReturn(aInfoPrimary).when(mRootWindowContainer).resolveHomeActivity(anyInt(), 908 refEq(primaryHomeIntent)); 909 // Setup: set secondary home. 910 mockResolveHomeActivity(false /* primaryHome */, false /* forceSystemProvided */); 911 912 // Run the test. 913 final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer 914 .resolveSecondaryHomeActivity(0 /* userId */, mock(TaskDisplayArea.class)); 915 final ActivityInfo aInfoSecondary = getFakeHomeActivityInfo(false /* primaryHome*/); 916 assertEquals(aInfoSecondary.name, resolvedInfo.first.name); 917 assertEquals(aInfoSecondary.applicationInfo.packageName, 918 resolvedInfo.first.applicationInfo.packageName); 919 } 920 921 /** 922 * Tests that the default secondary home activity is always picked when it is in forced by 923 * config_useSystemProvidedLauncherForSecondary. 924 */ 925 @Test testResolveSecondaryHomeActivityForced()926 public void testResolveSecondaryHomeActivityForced() { 927 // SetUp: set primary home. 928 mockResolveHomeActivity(true /* primaryHome */, false /* forceSystemProvided */); 929 // SetUp: set secondary home and force it. 930 mockResolveHomeActivity(false /* primaryHome */, true /* forceSystemProvided */); 931 final Intent secondaryHomeIntent = 932 mAtm.getSecondaryHomeIntent(null /* preferredPackage */); 933 final List<ResolveInfo> resolutions = new ArrayList<>(); 934 final ResolveInfo resolveInfo = new ResolveInfo(); 935 final ActivityInfo aInfoSecondary = getFakeHomeActivityInfo(false /* primaryHome*/); 936 resolveInfo.activityInfo = aInfoSecondary; 937 resolutions.add(resolveInfo); 938 doReturn(resolutions).when(mRootWindowContainer).resolveActivities(anyInt(), 939 refEq(secondaryHomeIntent)); 940 doReturn(true).when(mRootWindowContainer).canStartHomeOnDisplayArea(any(), any(), 941 anyBoolean()); 942 943 // Run the test. 944 final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer 945 .resolveSecondaryHomeActivity(0 /* userId */, mock(TaskDisplayArea.class)); 946 assertEquals(aInfoSecondary.name, resolvedInfo.first.name); 947 assertEquals(aInfoSecondary.applicationInfo.packageName, 948 resolvedInfo.first.applicationInfo.packageName); 949 } 950 951 /** 952 * Tests that secondary home should be selected if primary home not support secondary displays 953 * or there is no matched activity in the same package as selected primary home. 954 */ 955 @Test testResolveSecondaryHomeActivityWhenPrimaryHomeNotSupportMultiDisplay()956 public void testResolveSecondaryHomeActivityWhenPrimaryHomeNotSupportMultiDisplay() { 957 // Setup: there is no matched activity in the same package as selected primary home. 958 mockResolveHomeActivity(true /* primaryHome */, false /* forceSystemProvided */); 959 final List<ResolveInfo> resolutions = new ArrayList<>(); 960 doReturn(resolutions).when(mRootWindowContainer).resolveActivities(anyInt(), any()); 961 // Setup: set secondary home. 962 mockResolveHomeActivity(false /* primaryHome */, false /* forceSystemProvided */); 963 964 // Run the test. 965 final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer 966 .resolveSecondaryHomeActivity(0 /* userId */, mock(TaskDisplayArea.class)); 967 final ActivityInfo aInfoSecondary = getFakeHomeActivityInfo(false /* primaryHome*/); 968 assertEquals(aInfoSecondary.name, resolvedInfo.first.name); 969 assertEquals(aInfoSecondary.applicationInfo.packageName, 970 resolvedInfo.first.applicationInfo.packageName); 971 } 972 /** 973 * Tests that primary home activity should be selected if it already support secondary displays. 974 */ 975 @Test testResolveSecondaryHomeActivityWhenPrimaryHomeSupportMultiDisplay()976 public void testResolveSecondaryHomeActivityWhenPrimaryHomeSupportMultiDisplay() { 977 // SetUp: set primary home. 978 mockResolveHomeActivity(true /* primaryHome */, false /* forceSystemProvided */); 979 // SetUp: put primary home info on 2nd item 980 final List<ResolveInfo> resolutions = new ArrayList<>(); 981 final ResolveInfo infoFake1 = new ResolveInfo(); 982 infoFake1.activityInfo = new ActivityInfo(); 983 infoFake1.activityInfo.name = "fakeActivity1"; 984 infoFake1.activityInfo.applicationInfo = new ApplicationInfo(); 985 infoFake1.activityInfo.applicationInfo.packageName = "fakePackage1"; 986 final ResolveInfo infoFake2 = new ResolveInfo(); 987 final ActivityInfo aInfoPrimary = getFakeHomeActivityInfo(true /* primaryHome */); 988 infoFake2.activityInfo = aInfoPrimary; 989 resolutions.add(infoFake1); 990 resolutions.add(infoFake2); 991 doReturn(resolutions).when(mRootWindowContainer).resolveActivities(anyInt(), any()); 992 993 doReturn(true).when(mRootWindowContainer).canStartHomeOnDisplayArea(any(), any(), 994 anyBoolean()); 995 996 // Run the test. 997 final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer 998 .resolveSecondaryHomeActivity(0 /* userId */, mock(TaskDisplayArea.class)); 999 assertEquals(aInfoPrimary.name, resolvedInfo.first.name); 1000 assertEquals(aInfoPrimary.applicationInfo.packageName, 1001 resolvedInfo.first.applicationInfo.packageName); 1002 } 1003 1004 /** 1005 * Tests that the first one that matches should be selected if there are multiple activities. 1006 */ 1007 @Test testResolveSecondaryHomeActivityWhenOtherActivitySupportMultiDisplay()1008 public void testResolveSecondaryHomeActivityWhenOtherActivitySupportMultiDisplay() { 1009 // SetUp: set primary home. 1010 mockResolveHomeActivity(true /* primaryHome */, false /* forceSystemProvided */); 1011 // Setup: prepare two eligible activity info. 1012 final List<ResolveInfo> resolutions = new ArrayList<>(); 1013 final ResolveInfo infoFake1 = new ResolveInfo(); 1014 infoFake1.activityInfo = new ActivityInfo(); 1015 infoFake1.activityInfo.name = "fakeActivity1"; 1016 infoFake1.activityInfo.applicationInfo = new ApplicationInfo(); 1017 infoFake1.activityInfo.applicationInfo.packageName = "fakePackage1"; 1018 final ResolveInfo infoFake2 = new ResolveInfo(); 1019 infoFake2.activityInfo = new ActivityInfo(); 1020 infoFake2.activityInfo.name = "fakeActivity2"; 1021 infoFake2.activityInfo.applicationInfo = new ApplicationInfo(); 1022 infoFake2.activityInfo.applicationInfo.packageName = "fakePackage2"; 1023 resolutions.add(infoFake1); 1024 resolutions.add(infoFake2); 1025 doReturn(resolutions).when(mRootWindowContainer).resolveActivities(anyInt(), any()); 1026 1027 doReturn(true).when(mRootWindowContainer).canStartHomeOnDisplayArea(any(), any(), 1028 anyBoolean()); 1029 1030 // Use the first one of matched activities in the same package as selected primary home. 1031 final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer 1032 .resolveSecondaryHomeActivity(0 /* userId */, mock(TaskDisplayArea.class)); 1033 1034 assertEquals(infoFake1.activityInfo.applicationInfo.packageName, 1035 resolvedInfo.first.applicationInfo.packageName); 1036 assertEquals(infoFake1.activityInfo.name, resolvedInfo.first.name); 1037 } 1038 1039 @Test testGetLaunchRootTaskOnSecondaryTaskDisplayArea()1040 public void testGetLaunchRootTaskOnSecondaryTaskDisplayArea() { 1041 // Adding another TaskDisplayArea to the default display. 1042 final DisplayContent display = mRootWindowContainer.getDefaultDisplay(); 1043 final TaskDisplayArea taskDisplayArea = new TaskDisplayArea(display, 1044 mWm, "TDA", FEATURE_VENDOR_FIRST); 1045 display.addChild(taskDisplayArea, POSITION_BOTTOM); 1046 1047 // Making sure getting the root task from the preferred TDA and the preferred windowing mode 1048 LaunchParamsController.LaunchParams launchParams = 1049 new LaunchParamsController.LaunchParams(); 1050 launchParams.mPreferredTaskDisplayArea = taskDisplayArea; 1051 launchParams.mWindowingMode = WINDOWING_MODE_FREEFORM; 1052 Task root = mRootWindowContainer.getOrCreateRootTask(null /* r */, null /* options */, 1053 null /* candidateTask */, null /* sourceTask */, true /* onTop */, launchParams, 1054 0 /* launchParams */); 1055 assertEquals(taskDisplayArea, root.getTaskDisplayArea()); 1056 assertEquals(WINDOWING_MODE_FREEFORM, root.getWindowingMode()); 1057 1058 // Making sure still getting the root task from the preferred TDA when passing in a 1059 // launching activity. 1060 ActivityRecord r = new ActivityBuilder(mAtm).build(); 1061 root = mRootWindowContainer.getOrCreateRootTask(r, null /* options */, 1062 null /* candidateTask */, null /* sourceTask */, true /* onTop */, launchParams, 1063 0 /* launchParams */); 1064 assertEquals(taskDisplayArea, root.getTaskDisplayArea()); 1065 assertEquals(WINDOWING_MODE_FREEFORM, root.getWindowingMode()); 1066 } 1067 1068 @Test testGetOrCreateRootTaskOnDisplayWithCandidateRootTask()1069 public void testGetOrCreateRootTaskOnDisplayWithCandidateRootTask() { 1070 // Create a root task with an activity on secondary display. 1071 final TestDisplayContent secondaryDisplay = new TestDisplayContent.Builder(mAtm, 300, 1072 600).build(); 1073 final Task task = new TaskBuilder(mSupervisor) 1074 .setDisplay(secondaryDisplay).build(); 1075 final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task).build(); 1076 1077 // Make sure the root task is valid and can be reused on default display. 1078 final Task rootTask = mRootWindowContainer.getDefaultTaskDisplayArea().getOrCreateRootTask( 1079 activity, null /* options */, task, null /* sourceTask */, null /* launchParams */, 1080 0 /* launchFlags */, ACTIVITY_TYPE_STANDARD, true /* onTop */); 1081 assertEquals(task, rootTask); 1082 } 1083 1084 @Test testSwitchUser_missingHomeRootTask()1085 public void testSwitchUser_missingHomeRootTask() { 1086 final Task fullscreenTask = mRootWindowContainer.getDefaultTaskDisplayArea().createRootTask( 1087 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); 1088 doReturn(fullscreenTask).when(mRootWindowContainer).getTopDisplayFocusedRootTask(); 1089 1090 final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); 1091 Task rootHomeTask = taskDisplayArea.getRootHomeTask(); 1092 if (rootHomeTask != null) { 1093 rootHomeTask.removeImmediately(); 1094 } 1095 assertNull(taskDisplayArea.getRootHomeTask()); 1096 1097 int currentUser = mRootWindowContainer.mCurrentUser; 1098 int otherUser = currentUser + 1; 1099 1100 mRootWindowContainer.switchUser(otherUser, null); 1101 1102 assertNotNull(taskDisplayArea.getRootHomeTask()); 1103 assertEquals(taskDisplayArea.getTopRootTask(), taskDisplayArea.getRootHomeTask()); 1104 } 1105 1106 @Test testLockAllProfileTasks()1107 public void testLockAllProfileTasks() { 1108 final int profileUid = UserHandle.PER_USER_RANGE + UserHandle.MIN_SECONDARY_USER_ID; 1109 final int profileUserId = UserHandle.getUserId(profileUid); 1110 // Create an activity belonging to the profile user. 1111 final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true) 1112 .setUid(profileUid).build(); 1113 final Task task = activity.getTask(); 1114 1115 // Create another activity belonging to current user on top. 1116 final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(task).build(); 1117 topActivity.intent.setAction(Intent.ACTION_MAIN); 1118 1119 // Make sure the listeners will be notified for putting the task to locked state 1120 TaskChangeNotificationController controller = mAtm.getTaskChangeNotificationController(); 1121 spyOn(controller); 1122 mWm.mRoot.lockAllProfileTasks(profileUserId); 1123 verify(controller).notifyTaskProfileLocked(any()); 1124 1125 // Create the work lock activity on top of the task 1126 final ActivityRecord workLockActivity = new ActivityBuilder(mAtm).setTask(task).build(); 1127 workLockActivity.intent.setAction(ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER); 1128 doReturn(workLockActivity.mActivityComponent).when(mAtm).getSysUiServiceComponentLocked(); 1129 1130 // Make sure the listener won't be notified again. 1131 clearInvocations(controller); 1132 mWm.mRoot.lockAllProfileTasks(profileUserId); 1133 verify(controller, never()).notifyTaskProfileLocked(any()); 1134 } 1135 1136 /** 1137 * Mock {@link RootWindowContainer#resolveHomeActivity} for returning consistent activity 1138 * info for test cases. 1139 * 1140 * @param primaryHome Indicate to use primary home intent as parameter, otherwise, use 1141 * secondary home intent. 1142 * @param forceSystemProvided Indicate to force using system provided home activity. 1143 */ mockResolveHomeActivity(boolean primaryHome, boolean forceSystemProvided)1144 private void mockResolveHomeActivity(boolean primaryHome, boolean forceSystemProvided) { 1145 ActivityInfo targetActivityInfo = getFakeHomeActivityInfo(primaryHome); 1146 Intent targetIntent; 1147 if (primaryHome) { 1148 targetIntent = mAtm.getHomeIntent(); 1149 } else { 1150 Resources resources = mContext.getResources(); 1151 spyOn(resources); 1152 doReturn(targetActivityInfo.applicationInfo.packageName).when(resources).getString( 1153 com.android.internal.R.string.config_secondaryHomePackage); 1154 doReturn(forceSystemProvided).when(resources).getBoolean( 1155 com.android.internal.R.bool.config_useSystemProvidedLauncherForSecondary); 1156 targetIntent = mAtm.getSecondaryHomeIntent(null /* preferredPackage */); 1157 } 1158 doReturn(targetActivityInfo).when(mRootWindowContainer).resolveHomeActivity(anyInt(), 1159 refEq(targetIntent)); 1160 } 1161 1162 /** 1163 * Mock {@link RootWindowContainer#resolveSecondaryHomeActivity} for returning consistent 1164 * activity info for test cases. 1165 */ mockResolveSecondaryHomeActivity()1166 private void mockResolveSecondaryHomeActivity() { 1167 final Intent secondaryHomeIntent = mAtm 1168 .getSecondaryHomeIntent(null /* preferredPackage */); 1169 final ActivityInfo aInfoSecondary = getFakeHomeActivityInfo(false); 1170 doReturn(Pair.create(aInfoSecondary, secondaryHomeIntent)).when(mRootWindowContainer) 1171 .resolveSecondaryHomeActivity(anyInt(), any()); 1172 } 1173 getFakeHomeActivityInfo(boolean primaryHome)1174 private ActivityInfo getFakeHomeActivityInfo(boolean primaryHome) { 1175 final ActivityInfo aInfo = new ActivityInfo(); 1176 aInfo.name = primaryHome ? "fakeHomeActivity" : "fakeSecondaryHomeActivity"; 1177 aInfo.applicationInfo = new ApplicationInfo(); 1178 aInfo.applicationInfo.packageName = 1179 primaryHome ? "fakeHomePackage" : "fakeSecondaryHomePackage"; 1180 return aInfo; 1181 } 1182 } 1183 1184