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