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