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