1 /* 2 * Copyright (C) 2018 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.ActivityManager.RECENT_WITH_EXCLUDED; 20 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; 21 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; 22 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 23 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; 24 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; 25 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; 26 import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; 27 import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK; 28 import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT; 29 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; 30 import static android.content.res.Configuration.ORIENTATION_PORTRAIT; 31 import static android.os.Process.NOBODY_UID; 32 33 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; 34 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; 35 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; 36 import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_TASK_ORG; 37 38 import static com.google.common.truth.Truth.assertThat; 39 import static com.google.common.truth.Truth.assertWithMessage; 40 41 import static org.junit.Assert.assertEquals; 42 import static org.junit.Assert.assertFalse; 43 import static org.junit.Assert.assertNotNull; 44 import static org.junit.Assert.assertNull; 45 import static org.junit.Assert.assertTrue; 46 import static org.junit.Assert.fail; 47 import static org.mockito.ArgumentMatchers.anyBoolean; 48 import static org.mockito.ArgumentMatchers.anyInt; 49 import static org.mockito.ArgumentMatchers.eq; 50 import static org.mockito.Mockito.clearInvocations; 51 import static org.mockito.Mockito.mock; 52 import static org.mockito.Mockito.reset; 53 import static org.mockito.Mockito.times; 54 import static org.mockito.Mockito.verify; 55 import static org.mockito.Mockito.verifyZeroInteractions; 56 57 import static java.lang.Integer.MAX_VALUE; 58 59 import android.app.ActivityManager.RecentTaskInfo; 60 import android.app.ActivityManager.RunningTaskInfo; 61 import android.app.ActivityTaskManager; 62 import android.content.ComponentName; 63 import android.content.pm.ParceledListSlice; 64 import android.content.pm.UserInfo; 65 import android.graphics.ColorSpace; 66 import android.graphics.Point; 67 import android.graphics.Rect; 68 import android.hardware.HardwareBuffer; 69 import android.os.Bundle; 70 import android.os.RemoteException; 71 import android.os.SystemClock; 72 import android.os.UserManager; 73 import android.platform.test.annotations.Presubmit; 74 import android.util.ArraySet; 75 import android.util.SparseBooleanArray; 76 import android.view.Surface; 77 import android.window.TaskSnapshot; 78 79 import androidx.test.filters.MediumTest; 80 81 import com.android.server.wm.RecentTasks.Callbacks; 82 83 import org.junit.Before; 84 import org.junit.Test; 85 import org.junit.runner.RunWith; 86 87 import java.io.File; 88 import java.util.ArrayList; 89 import java.util.HashSet; 90 import java.util.List; 91 import java.util.Random; 92 import java.util.Set; 93 import java.util.function.Function; 94 95 /** 96 * Build/Install/Run: 97 * atest WmTests:RecentTasksTest 98 */ 99 @MediumTest 100 @Presubmit 101 @RunWith(WindowTestRunner.class) 102 public class RecentTasksTest extends WindowTestsBase { 103 private static final int TEST_USER_0_ID = 0; 104 private static final int TEST_USER_1_ID = 10; 105 private static final int TEST_QUIET_USER_ID = 20; 106 private static final UserInfo DEFAULT_USER_INFO = new UserInfo(TEST_USER_0_ID, 107 "default", 0 /* flags */); 108 private static final UserInfo QUIET_PROFILE_USER_INFO = new UserInfo(TEST_QUIET_USER_ID, 109 "quiet_profile", null /* iconPath */, UserInfo.FLAG_QUIET_MODE, 110 UserManager.USER_TYPE_PROFILE_MANAGED); 111 private static final int INVALID_STACK_ID = 999; 112 113 private TaskDisplayArea mTaskContainer; 114 private TestTaskPersister mTaskPersister; 115 private TestRecentTasks mRecentTasks; 116 private TestRunningTasks mRunningTasks; 117 118 private ArrayList<Task> mTasks; 119 private ArrayList<Task> mSameDocumentTasks; 120 121 private CallbacksRecorder mCallbacksRecorder; 122 123 @Before setUp()124 public void setUp() throws Exception { 125 mTaskPersister = new TestTaskPersister(mContext.getFilesDir()); 126 spyOn(mTaskPersister); 127 mTaskContainer = mRootWindowContainer.getDefaultTaskDisplayArea(); 128 129 // Set the recent tasks we should use for testing in this class. 130 mRecentTasks = new TestRecentTasks(mAtm, mTaskPersister); 131 spyOn(mRecentTasks); 132 mAtm.setRecentTasks(mRecentTasks); 133 mRecentTasks.loadParametersFromResources(mContext.getResources()); 134 135 // Set the running tasks we should use for testing in this class. 136 mRunningTasks = new TestRunningTasks(); 137 mAtm.mTaskSupervisor.setRunningTasks(mRunningTasks); 138 139 mCallbacksRecorder = new CallbacksRecorder(); 140 mRecentTasks.registerCallback(mCallbacksRecorder); 141 142 mTasks = new ArrayList<>(); 143 mTasks.add(createTaskBuilder(".Task1").build()); 144 mTasks.add(createTaskBuilder(".Task2").build()); 145 mTasks.add(createTaskBuilder(".Task3").build()); 146 mTasks.add(createTaskBuilder(".Task4").build()); 147 mTasks.add(createTaskBuilder(".Task5").build()); 148 149 mSameDocumentTasks = new ArrayList<>(); 150 mSameDocumentTasks.add(createDocumentTask(".DocumentTask1")); 151 mSameDocumentTasks.add(createDocumentTask(".DocumentTask1")); 152 } 153 154 @Test testCallbacks()155 public void testCallbacks() { 156 // Add some tasks 157 mRecentTasks.add(mTasks.get(0)); 158 mRecentTasks.add(mTasks.get(1)); 159 assertThat(mCallbacksRecorder.mAdded).contains(mTasks.get(0)); 160 assertThat(mCallbacksRecorder.mAdded).contains(mTasks.get(1)); 161 assertThat(mCallbacksRecorder.mTrimmed).isEmpty(); 162 assertThat(mCallbacksRecorder.mRemoved).isEmpty(); 163 mCallbacksRecorder.clear(); 164 165 // Remove some tasks 166 mRecentTasks.remove(mTasks.get(0)); 167 mRecentTasks.remove(mTasks.get(1)); 168 assertThat(mCallbacksRecorder.mAdded).isEmpty(); 169 assertThat(mCallbacksRecorder.mTrimmed).isEmpty(); 170 assertThat(mCallbacksRecorder.mRemoved).contains(mTasks.get(0)); 171 assertThat(mCallbacksRecorder.mRemoved).contains(mTasks.get(1)); 172 mCallbacksRecorder.clear(); 173 174 // Remove the callback, ensure we don't get any calls 175 mRecentTasks.unregisterCallback(mCallbacksRecorder); 176 mRecentTasks.add(mTasks.get(0)); 177 mRecentTasks.remove(mTasks.get(0)); 178 assertThat(mCallbacksRecorder.mAdded).isEmpty(); 179 assertThat(mCallbacksRecorder.mTrimmed).isEmpty(); 180 assertThat(mCallbacksRecorder.mRemoved).isEmpty(); 181 } 182 183 @Test testPersister()184 public void testPersister() { 185 // Add some tasks, ensure the persister is woken 186 mRecentTasks.add(mTasks.get(0)); 187 mRecentTasks.add(mTasks.get(1)); 188 verify(mTaskPersister, times(1)).wakeup(eq(mTasks.get(0)), anyBoolean()); 189 verify(mTaskPersister, times(1)).wakeup(eq(mTasks.get(1)), anyBoolean()); 190 reset(mTaskPersister); 191 192 // Update a task, ensure the persister is woken 193 mRecentTasks.add(mTasks.get(0)); 194 verify(mTaskPersister, times(1)).wakeup(eq(mTasks.get(0)), anyBoolean()); 195 reset(mTaskPersister); 196 197 // Remove some tasks, ensure the persister is woken 198 mRecentTasks.remove(mTasks.get(0)); 199 mRecentTasks.remove(mTasks.get(1)); 200 verify(mTaskPersister, times(1)).wakeup(eq(mTasks.get(0)), anyBoolean()); 201 verify(mTaskPersister, times(1)).wakeup(eq(mTasks.get(1)), anyBoolean()); 202 reset(mTaskPersister); 203 } 204 205 @Test testPersisterTrimmed()206 public void testPersisterTrimmed() { 207 mRecentTasks.setOnlyTestVisibleRange(); 208 209 // Limit the global maximum number of recent tasks to a fixed size 210 mRecentTasks.setGlobalMaxNumTasks(1 /* globalMaxNumTasks */); 211 212 mRecentTasks.add(mTasks.get(0)); 213 verify(mTaskPersister, times(1)).wakeup(eq(mTasks.get(0)), anyBoolean()); 214 reset(mTaskPersister); 215 216 // Add N+1 tasks to ensure the previous task is trimmed 217 mRecentTasks.add(mTasks.get(1)); 218 triggerTrimAndAssertTrimmed(mTasks.get(0)); 219 verify(mTaskPersister, times(1)).wakeup(eq(mTasks.get(0)), anyBoolean()); 220 verify(mTaskPersister, times(1)).wakeup(eq(mTasks.get(1)), anyBoolean()); 221 } 222 223 @Test testAddDocumentTasksNoMultiple_expectNoTrim()224 public void testAddDocumentTasksNoMultiple_expectNoTrim() { 225 // Add same non-multiple-task document tasks will remove the task (to re-add it) but not 226 // trim it 227 Task documentTask1 = createDocumentTask(".DocumentTask1"); 228 Task documentTask2 = createDocumentTask(".DocumentTask1"); 229 mRecentTasks.add(documentTask1); 230 mRecentTasks.add(documentTask2); 231 assertThat(mCallbacksRecorder.mAdded).contains(documentTask1); 232 assertThat(mCallbacksRecorder.mAdded).contains(documentTask2); 233 assertThat(mCallbacksRecorder.mTrimmed).isEmpty(); 234 assertThat(mCallbacksRecorder.mRemoved).contains(documentTask1); 235 } 236 237 @Test testAddTasksMaxTaskRecents_expectNoTrim()238 public void testAddTasksMaxTaskRecents_expectNoTrim() { 239 // Add a task hitting max-recents for that app will remove the task (to add the next one) 240 // but not trim it 241 Task documentTask1 = createDocumentTask(".DocumentTask1"); 242 Task documentTask2 = createDocumentTask(".DocumentTask1"); 243 documentTask1.maxRecents = 1; 244 documentTask2.maxRecents = 1; 245 mRecentTasks.add(documentTask1); 246 mRecentTasks.add(documentTask2); 247 assertThat(mCallbacksRecorder.mAdded).contains(documentTask1); 248 assertThat(mCallbacksRecorder.mAdded).contains(documentTask2); 249 assertThat(mCallbacksRecorder.mTrimmed).isEmpty(); 250 assertThat(mCallbacksRecorder.mRemoved).contains(documentTask1); 251 } 252 253 @Test testAddTasksSameTask_expectNoTrim()254 public void testAddTasksSameTask_expectNoTrim() { 255 // Add a task that is already in the task list does not trigger any callbacks, it just 256 // moves in the list 257 Task documentTask1 = createDocumentTask(".DocumentTask1"); 258 mRecentTasks.add(documentTask1); 259 mRecentTasks.add(documentTask1); 260 assertThat(mCallbacksRecorder.mAdded).hasSize(1); 261 assertThat(mCallbacksRecorder.mAdded).contains(documentTask1); 262 assertThat(mCallbacksRecorder.mTrimmed).isEmpty(); 263 assertThat(mCallbacksRecorder.mRemoved).isEmpty(); 264 } 265 266 @Test testAddMultipleDocumentTasks_expectNoTrim()267 public void testAddMultipleDocumentTasks_expectNoTrim() { 268 // Add same multiple-task document tasks does not trim the first tasks 269 Task documentTask1 = createDocumentTask(".DocumentTask1", 270 FLAG_ACTIVITY_MULTIPLE_TASK); 271 Task documentTask2 = createDocumentTask(".DocumentTask1", 272 FLAG_ACTIVITY_MULTIPLE_TASK); 273 mRecentTasks.add(documentTask1); 274 mRecentTasks.add(documentTask2); 275 assertThat(mCallbacksRecorder.mAdded).hasSize(2); 276 assertThat(mCallbacksRecorder.mAdded).contains(documentTask1); 277 assertThat(mCallbacksRecorder.mAdded).contains(documentTask2); 278 assertThat(mCallbacksRecorder.mTrimmed).isEmpty(); 279 assertThat(mCallbacksRecorder.mRemoved).isEmpty(); 280 } 281 282 @Test testAddTasks_expectRemovedNoTrim()283 public void testAddTasks_expectRemovedNoTrim() { 284 // Add multiple same-affinity non-document tasks, ensure that it removes, but does not trim 285 // the other task 286 Task task1 = createTaskBuilder(".Task1") 287 .setFlags(FLAG_ACTIVITY_NEW_TASK) 288 .build(); 289 Task task2 = createTaskBuilder(".Task1") 290 .setFlags(FLAG_ACTIVITY_NEW_TASK) 291 .build(); 292 mRecentTasks.add(task1); 293 assertThat(mCallbacksRecorder.mAdded).hasSize(1); 294 assertThat(mCallbacksRecorder.mAdded).contains(task1); 295 assertThat(mCallbacksRecorder.mTrimmed).isEmpty(); 296 assertThat(mCallbacksRecorder.mRemoved).isEmpty(); 297 mCallbacksRecorder.clear(); 298 mRecentTasks.add(task2); 299 assertThat(mCallbacksRecorder.mAdded).hasSize(1); 300 assertThat(mCallbacksRecorder.mAdded).contains(task2); 301 assertThat(mCallbacksRecorder.mTrimmed).isEmpty(); 302 assertThat(mCallbacksRecorder.mRemoved).hasSize(1); 303 assertThat(mCallbacksRecorder.mRemoved).contains(task1); 304 } 305 306 @Test testAddMultipleTasks_expectNotRemoved()307 public void testAddMultipleTasks_expectNotRemoved() { 308 // Add multiple same-affinity non-document tasks with MULTIPLE_TASK, ensure that it does not 309 // remove the other task 310 Task task1 = createTaskBuilder(".Task1") 311 .setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK) 312 .build(); 313 Task task2 = createTaskBuilder(".Task1") 314 .setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK) 315 .build(); 316 mRecentTasks.add(task1); 317 assertThat(mCallbacksRecorder.mAdded).hasSize(1); 318 assertThat(mCallbacksRecorder.mAdded).contains(task1); 319 assertThat(mCallbacksRecorder.mTrimmed).isEmpty(); 320 assertThat(mCallbacksRecorder.mRemoved).isEmpty(); 321 mCallbacksRecorder.clear(); 322 mRecentTasks.add(task2); 323 assertThat(mCallbacksRecorder.mAdded).hasSize(1); 324 assertThat(mCallbacksRecorder.mAdded).contains(task2); 325 assertThat(mCallbacksRecorder.mTrimmed).isEmpty(); 326 assertThat(mCallbacksRecorder.mRemoved).isEmpty(); 327 } 328 329 @Test testAddTasksDifferentStacks_expectNoRemove()330 public void testAddTasksDifferentStacks_expectNoRemove() { 331 // Adding the same task with different activity types should not trigger removal of the 332 // other task 333 Task task1 = createTaskBuilder(".Task1") 334 .setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK) 335 .setParentTask(mTaskContainer.getRootHomeTask()).build(); 336 Task task2 = createTaskBuilder(".Task1") 337 .setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK) 338 .build(); 339 mRecentTasks.add(task1); 340 mRecentTasks.add(task2); 341 assertThat(mCallbacksRecorder.mAdded).hasSize(2); 342 assertThat(mCallbacksRecorder.mAdded).contains(task1); 343 assertThat(mCallbacksRecorder.mAdded).contains(task2); 344 assertThat(mCallbacksRecorder.mTrimmed).isEmpty(); 345 assertThat(mCallbacksRecorder.mRemoved).isEmpty(); 346 } 347 348 @Test testAddTaskCompatibleActivityType_expectRemove()349 public void testAddTaskCompatibleActivityType_expectRemove() { 350 // Test with undefined activity type since the type is not persisted by the task persister 351 // and we want to ensure that a new task will match a restored task 352 Task task1 = createTaskBuilder(".Task1") 353 .setActivityType(ACTIVITY_TYPE_UNDEFINED) 354 .setFlags(FLAG_ACTIVITY_NEW_TASK) 355 .build(); 356 // Set the activity type again or the activity type of a root task would be remapped 357 // to ACTIVITY_TYPE_STANDARD, {@link TaskDisplayArea#createRootTask()} 358 task1.getWindowConfiguration().setActivityType(ACTIVITY_TYPE_UNDEFINED); 359 mRecentTasks.add(task1); 360 mCallbacksRecorder.clear(); 361 362 Task task2 = createTaskBuilder(".Task1") 363 .setFlags(FLAG_ACTIVITY_NEW_TASK) 364 .build(); 365 assertEquals(ACTIVITY_TYPE_STANDARD, task2.getActivityType()); 366 mRecentTasks.add(task2); 367 assertThat(mCallbacksRecorder.mAdded).hasSize(1); 368 assertThat(mCallbacksRecorder.mAdded).contains(task2); 369 assertThat(mCallbacksRecorder.mTrimmed).isEmpty(); 370 assertThat(mCallbacksRecorder.mRemoved).hasSize(1); 371 assertThat(mCallbacksRecorder.mRemoved).contains(task1); 372 } 373 374 @Test testAddTaskCompatibleActivityTypeDifferentUser_expectNoRemove()375 public void testAddTaskCompatibleActivityTypeDifferentUser_expectNoRemove() { 376 Task task1 = createTaskBuilder(".Task1") 377 .setActivityType(ACTIVITY_TYPE_UNDEFINED) 378 .setFlags(FLAG_ACTIVITY_NEW_TASK) 379 .setUserId(TEST_USER_0_ID) 380 .build(); 381 // Set the activity type again or the activity type of a root task would be remapped 382 // to ACTIVITY_TYPE_STANDARD, {@link TaskDisplayArea#createRootTask()} 383 task1.getWindowConfiguration().setActivityType(ACTIVITY_TYPE_UNDEFINED); 384 mRecentTasks.add(task1); 385 mCallbacksRecorder.clear(); 386 387 Task task2 = createTaskBuilder(".Task1") 388 .setFlags(FLAG_ACTIVITY_NEW_TASK) 389 .setUserId(TEST_USER_1_ID) 390 .build(); 391 assertEquals(ACTIVITY_TYPE_STANDARD, task2.getActivityType()); 392 mRecentTasks.add(task2); 393 assertThat(mCallbacksRecorder.mAdded).hasSize(1); 394 assertThat(mCallbacksRecorder.mAdded).contains(task2); 395 assertThat(mCallbacksRecorder.mTrimmed).isEmpty(); 396 assertThat(mCallbacksRecorder.mRemoved).isEmpty(); 397 } 398 399 @Test testAddTaskCompatibleWindowingMode_expectRemove()400 public void testAddTaskCompatibleWindowingMode_expectRemove() { 401 Task task1 = createTaskBuilder(".Task1") 402 .setFlags(FLAG_ACTIVITY_NEW_TASK) 403 .build(); 404 doReturn(WINDOWING_MODE_UNDEFINED).when(task1).getWindowingMode(); 405 mRecentTasks.add(task1); 406 mCallbacksRecorder.clear(); 407 408 Task task2 = createTaskBuilder(".Task1") 409 .setWindowingMode(WINDOWING_MODE_FULLSCREEN) 410 .setFlags(FLAG_ACTIVITY_NEW_TASK) 411 .build(); 412 assertEquals(WINDOWING_MODE_FULLSCREEN, task2.getWindowingMode()); 413 mRecentTasks.add(task2); 414 415 assertThat(mCallbacksRecorder.mAdded).hasSize(1); 416 assertThat(mCallbacksRecorder.mAdded).contains(task2); 417 assertThat(mCallbacksRecorder.mTrimmed).isEmpty(); 418 assertThat(mCallbacksRecorder.mRemoved).hasSize(1); 419 assertThat(mCallbacksRecorder.mRemoved).contains(task1); 420 } 421 422 @Test testAddTaskIncompatibleWindowingMode_expectNoRemove()423 public void testAddTaskIncompatibleWindowingMode_expectNoRemove() { 424 Task task1 = createTaskBuilder(".Task1") 425 .setWindowingMode(WINDOWING_MODE_FULLSCREEN) 426 .setFlags(FLAG_ACTIVITY_NEW_TASK) 427 .build(); 428 assertEquals(WINDOWING_MODE_FULLSCREEN, task1.getWindowingMode()); 429 mRecentTasks.add(task1); 430 431 Task task2 = createTaskBuilder(".Task1") 432 .setWindowingMode(WINDOWING_MODE_PINNED) 433 .setFlags(FLAG_ACTIVITY_NEW_TASK) 434 .build(); 435 assertEquals(WINDOWING_MODE_PINNED, task2.getWindowingMode()); 436 mRecentTasks.add(task2); 437 438 assertThat(mCallbacksRecorder.mAdded).hasSize(2); 439 assertThat(mCallbacksRecorder.mAdded).contains(task1); 440 assertThat(mCallbacksRecorder.mAdded).contains(task2); 441 assertThat(mCallbacksRecorder.mTrimmed).isEmpty(); 442 assertThat(mCallbacksRecorder.mRemoved).isEmpty(); 443 } 444 445 @Test testRemoveAffinityTask()446 public void testRemoveAffinityTask() { 447 // Add task to recents 448 final String taskAffinity = "affinity"; 449 final int uid = 10123; 450 final Task task1 = createTaskBuilder(".Task1").build(); 451 final ComponentName componentName = getUniqueComponentName(); 452 task1.affinity = ActivityRecord.computeTaskAffinity(taskAffinity, uid); 453 mRecentTasks.add(task1); 454 455 // Add another task to recents, and make sure the previous task was removed. 456 final Task task2 = createTaskBuilder(".Task2").build(); 457 task2.affinity = ActivityRecord.computeTaskAffinity(taskAffinity, uid); 458 mRecentTasks.add(task2); 459 assertEquals(1, mRecentTasks.getRecentTasks(MAX_VALUE, 0 /* flags */, 460 true /* getTasksAllowed */, TEST_USER_0_ID, 0).getList().size()); 461 } 462 463 @Test testAppendOrganizedChildTaskInfo()464 public void testAppendOrganizedChildTaskInfo() { 465 final Task root = createTaskBuilder(".CreatedByOrganizerRoot").build(); 466 root.mCreatedByOrganizer = true; 467 // Add organized and non-organized child. 468 final Task child1 = createTaskBuilder(".Task1").setParentTask(root).build(); 469 final Task child2 = createTaskBuilder(".Task2").setParentTask(root).build(); 470 doReturn(true).when(child1).isOrganized(); 471 doReturn(false).when(child2).isOrganized(); 472 mRecentTasks.add(root); 473 474 // Make sure only organized child will be appended. 475 final List<RecentTaskInfo> infos = getRecentTasks(0 /* flags */); 476 final List<RecentTaskInfo> childrenTaskInfos = infos.get(0).childrenTaskInfos; 477 assertEquals(childrenTaskInfos.size(), 1); 478 assertEquals(childrenTaskInfos.get(0).taskId, child1.mTaskId); 479 } 480 481 @Test testAddTasksHomeClearUntrackedTasks_expectFinish()482 public void testAddTasksHomeClearUntrackedTasks_expectFinish() { 483 // There may be multiple tasks with the same base intent by flags (FLAG_ACTIVITY_NEW_TASK | 484 // FLAG_ACTIVITY_MULTIPLE_TASK). If the previous task is still active, it should be removed 485 // because user may not be able to return to the task. 486 final String className = ".PermissionsReview"; 487 final Function<Boolean, Task> taskBuilder = visible -> { 488 final Task task = createTaskBuilder(className).build(); 489 // Make the task non-empty. 490 final ActivityRecord r = new ActivityBuilder(mAtm).setTask(task).build(); 491 r.setVisibility(visible); 492 return task; 493 }; 494 495 final Task task1 = taskBuilder.apply(false /* visible */); 496 mRecentTasks.add(task1); 497 final Task task2 = taskBuilder.apply(true /* visible */); 498 mRecentTasks.add(task2); 499 final Task task3 = createTaskBuilder(className).build(); 500 mRecentTasks.add(task3); 501 // Only the last added task is kept in recents and the previous 2 tasks will become hidden 502 // tasks because their intents are identical. 503 mRecentTasks.add(task1); 504 // Go home to trigger the removal of untracked tasks. 505 mRecentTasks.add(createTaskBuilder(".Home") 506 .setParentTask(mTaskContainer.getRootHomeTask()) 507 .build()); 508 triggerIdleToTrim(); 509 510 // The task was added into recents again so it is not hidden and shouldn't be removed. 511 assertNotNull(task1.getTopNonFinishingActivity()); 512 // All activities in the invisible task should be finishing or removed. 513 assertNull(task3.getTopNonFinishingActivity()); 514 // The visible task should not be affected. 515 assertNotNull(task2.getTopNonFinishingActivity()); 516 } 517 518 @Test testUsersTasks()519 public void testUsersTasks() { 520 mRecentTasks.setOnlyTestVisibleRange(); 521 mRecentTasks.unloadUserDataFromMemoryLocked(TEST_USER_0_ID); 522 523 // Setup some tasks for the users 524 mTaskPersister.mUserTaskIdsOverride = new SparseBooleanArray(); 525 mTaskPersister.mUserTaskIdsOverride.put(1, true); 526 mTaskPersister.mUserTaskIdsOverride.put(2, true); 527 mTaskPersister.mUserTasksOverride = new ArrayList<>(); 528 mTaskPersister.mUserTasksOverride.add(createTaskBuilder(".UserTask1").build()); 529 mTaskPersister.mUserTasksOverride.add(createTaskBuilder(".UserTask2").build()); 530 531 // Assert no user tasks are initially loaded 532 assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).hasLength(0); 533 534 // Load user 0 tasks 535 mRecentTasks.loadUserRecentsLocked(TEST_USER_0_ID); 536 assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).asList().contains(TEST_USER_0_ID); 537 assertTrue(mRecentTasks.containsTaskId(1, TEST_USER_0_ID)); 538 assertTrue(mRecentTasks.containsTaskId(2, TEST_USER_0_ID)); 539 540 // Load user 1 tasks 541 mRecentTasks.loadUserRecentsLocked(TEST_USER_1_ID); 542 assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).asList().contains(TEST_USER_0_ID); 543 assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).asList().contains(TEST_USER_1_ID); 544 assertTrue(mRecentTasks.containsTaskId(1, TEST_USER_0_ID)); 545 assertTrue(mRecentTasks.containsTaskId(2, TEST_USER_0_ID)); 546 assertTrue(mRecentTasks.containsTaskId(1, TEST_USER_1_ID)); 547 assertTrue(mRecentTasks.containsTaskId(2, TEST_USER_1_ID)); 548 549 // Unload user 1 tasks 550 mRecentTasks.unloadUserDataFromMemoryLocked(TEST_USER_1_ID); 551 assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).asList().contains(TEST_USER_0_ID); 552 assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).asList() 553 .doesNotContain(TEST_USER_1_ID); 554 assertTrue(mRecentTasks.containsTaskId(1, TEST_USER_0_ID)); 555 assertTrue(mRecentTasks.containsTaskId(2, TEST_USER_0_ID)); 556 557 // Unload user 0 tasks 558 mRecentTasks.unloadUserDataFromMemoryLocked(TEST_USER_0_ID); 559 assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).asList() 560 .doesNotContain(TEST_USER_0_ID); 561 assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).asList() 562 .doesNotContain(TEST_USER_1_ID); 563 } 564 565 @Test testOrderedIteration()566 public void testOrderedIteration() { 567 mRecentTasks.setOnlyTestVisibleRange(); 568 Task task1 = createTaskBuilder(".Task1").build(); 569 task1.lastActiveTime = new Random().nextInt(); 570 Task task2 = createTaskBuilder(".Task1").build(); 571 task2.lastActiveTime = new Random().nextInt(); 572 Task task3 = createTaskBuilder(".Task1").build(); 573 task3.lastActiveTime = new Random().nextInt(); 574 Task task4 = createTaskBuilder(".Task1").build(); 575 task4.lastActiveTime = new Random().nextInt(); 576 mRecentTasks.add(task1); 577 mRecentTasks.add(task2); 578 mRecentTasks.add(task3); 579 mRecentTasks.add(task4); 580 581 long prevLastActiveTime = 0; 582 final ArrayList<Task> tasks = mRecentTasks.getRawTasks(); 583 for (int i = 0; i < tasks.size(); i++) { 584 final Task task = tasks.get(i); 585 assertThat(prevLastActiveTime).isLessThan(task.lastActiveTime); 586 prevLastActiveTime = task.lastActiveTime; 587 } 588 } 589 590 @Test testTrimToGlobalMaxNumRecents()591 public void testTrimToGlobalMaxNumRecents() { 592 mRecentTasks.setOnlyTestVisibleRange(); 593 594 // Limit the global maximum number of recent tasks to a fixed size 595 mRecentTasks.setGlobalMaxNumTasks(2 /* globalMaxNumTasks */); 596 597 // Add N+1 tasks 598 mRecentTasks.add(mTasks.get(0)); 599 mRecentTasks.add(mTasks.get(1)); 600 mRecentTasks.add(mTasks.get(2)); 601 602 // Ensure that the last task was trimmed as an inactive task 603 triggerTrimAndAssertTrimmed(mTasks.get(0)); 604 } 605 606 @Test testTrimQuietProfileTasks()607 public void testTrimQuietProfileTasks() { 608 mRecentTasks.setOnlyTestVisibleRange(); 609 Task qt1 = createTaskBuilder(".QuietTask1").setUserId(TEST_QUIET_USER_ID).build(); 610 Task qt2 = createTaskBuilder(".QuietTask2").setUserId(TEST_QUIET_USER_ID).build(); 611 mRecentTasks.add(qt1); 612 mRecentTasks.add(qt2); 613 614 mRecentTasks.add(mTasks.get(0)); 615 mRecentTasks.add(mTasks.get(1)); 616 617 // Ensure that the quiet user's tasks was trimmed once the new tasks were added 618 triggerTrimAndAssertTrimmed(qt1, qt2); 619 } 620 621 @Test testSessionDuration()622 public void testSessionDuration() { 623 mRecentTasks.setOnlyTestVisibleRange(); 624 mRecentTasks.setParameters(-1 /* min */, -1 /* max */, 50 /* ms */); 625 626 Task t1 = createTaskBuilder(".Task1").build(); 627 t1.touchActiveTime(); 628 mRecentTasks.add(t1); 629 630 // Force a small sleep just beyond the session duration 631 SystemClock.sleep(75); 632 633 // Assert that the old task has been removed due to being out of the active session 634 triggerTrimAndAssertTrimmed(t1); 635 } 636 637 @Test testVisibleTasks_excludedFromRecents()638 public void testVisibleTasks_excludedFromRecents() { 639 mRecentTasks.setParameters(-1 /* min */, 4 /* max */, -1 /* ms */); 640 641 Task excludedTask1 = createTaskBuilder(".ExcludedTask1") 642 .setFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) 643 .build(); 644 Task excludedTask2 = createTaskBuilder(".ExcludedTask2") 645 .setFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) 646 .build(); 647 Task detachedExcludedTask = createTaskBuilder(".DetachedExcludedTask") 648 .setFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) 649 .build(); 650 651 // Move home to front so other task can satisfy the condition in RecentTasks#isTrimmable. 652 mRootWindowContainer.getDefaultTaskDisplayArea().getRootHomeTask().moveToFront("test"); 653 // Avoid Task#autoRemoveFromRecents when removing from parent. 654 detachedExcludedTask.setHasBeenVisible(true); 655 detachedExcludedTask.removeImmediately(); 656 assertFalse(detachedExcludedTask.isAttached()); 657 658 mRecentTasks.add(detachedExcludedTask); 659 mRecentTasks.add(excludedTask1); 660 mRecentTasks.add(mTasks.get(0)); 661 mRecentTasks.add(mTasks.get(1)); 662 mRecentTasks.add(mTasks.get(2)); 663 mRecentTasks.add(excludedTask2); 664 665 // Except the first-most excluded task, other excluded tasks should be trimmed. 666 triggerTrimAndAssertTrimmed(excludedTask1, detachedExcludedTask); 667 } 668 669 @Test testVisibleTasks_excludedFromRecents_firstTaskNotVisible()670 public void testVisibleTasks_excludedFromRecents_firstTaskNotVisible() { 671 // Create some set of tasks, some of which are visible and some are not 672 Task homeTask = createTaskBuilder("com.android.pkg1", ".HomeTask") 673 .setParentTask(mTaskContainer.getRootHomeTask()) 674 .build(); 675 homeTask.mUserSetupComplete = true; 676 mRecentTasks.add(homeTask); 677 Task excludedTask1 = createTaskBuilder(".ExcludedTask1") 678 .setFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) 679 .build(); 680 excludedTask1.mUserSetupComplete = true; 681 mRecentTasks.add(excludedTask1); 682 683 // Expect that the first visible excluded-from-recents task is visible 684 assertGetRecentTasksOrder(0 /* flags */, excludedTask1); 685 } 686 687 @Test testVisibleTasks_excludedFromRecents_nonDefaultDisplayTaskNotVisible()688 public void testVisibleTasks_excludedFromRecents_nonDefaultDisplayTaskNotVisible() { 689 Task excludedTaskOnVirtualDisplay = createTaskBuilder(".excludedTaskOnVirtualDisplay") 690 .setFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) 691 .build(); 692 excludedTaskOnVirtualDisplay.mUserSetupComplete = true; 693 doReturn(false).when(excludedTaskOnVirtualDisplay).isOnHomeDisplay(); 694 mRecentTasks.add(mTasks.get(0)); 695 mRecentTasks.add(excludedTaskOnVirtualDisplay); 696 697 // Expect that the first visible excluded-from-recents task is visible 698 assertGetRecentTasksOrder(0 /* flags */, mTasks.get(0)); 699 } 700 701 @Test testVisibleTasks_excludedFromRecents_withExcluded()702 public void testVisibleTasks_excludedFromRecents_withExcluded() { 703 // Create some set of tasks, some of which are visible and some are not 704 Task t1 = createTaskBuilder("com.android.pkg1", ".Task1").build(); 705 t1.mUserSetupComplete = true; 706 mRecentTasks.add(t1); 707 Task homeTask = createTaskBuilder("com.android.pkg1", ".HomeTask") 708 .setParentTask(mTaskContainer.getRootHomeTask()) 709 .build(); 710 homeTask.mUserSetupComplete = true; 711 mRecentTasks.add(homeTask); 712 Task excludedTask1 = createTaskBuilder(".ExcludedTask1") 713 .setFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) 714 .build(); 715 excludedTask1.mUserSetupComplete = true; 716 mRecentTasks.add(excludedTask1); 717 Task excludedTask2 = createTaskBuilder(".ExcludedTask2") 718 .setFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) 719 .build(); 720 excludedTask2.mUserSetupComplete = true; 721 mRecentTasks.add(excludedTask2); 722 Task t2 = createTaskBuilder("com.android.pkg2", ".Task1").build(); 723 t2.mUserSetupComplete = true; 724 mRecentTasks.add(t2); 725 726 assertGetRecentTasksOrder(RECENT_WITH_EXCLUDED, t2, excludedTask2, excludedTask1, t1); 727 } 728 729 @Test testVisibleTasks_minNum()730 public void testVisibleTasks_minNum() { 731 mRecentTasks.setOnlyTestVisibleRange(); 732 mRecentTasks.setParameters(5 /* min */, -1 /* max */, 25 /* ms */); 733 734 for (int i = 0; i < 4; i++) { 735 final Task task = mTasks.get(i); 736 task.touchActiveTime(); 737 mRecentTasks.add(task); 738 } 739 740 // Force a small sleep just beyond the session duration 741 SystemClock.sleep(50); 742 743 // Add a new task to trigger tasks to be trimmed 744 mRecentTasks.add(mTasks.get(4)); 745 746 // Ensure that there are a minimum number of tasks regardless of session length 747 triggerTrimAndAssertNoTasksTrimmed(); 748 } 749 750 @Test testVisibleTasks_maxNum()751 public void testVisibleTasks_maxNum() { 752 mRecentTasks.setOnlyTestVisibleRange(); 753 mRecentTasks.setParameters(-1 /* min */, 3 /* max */, -1 /* ms */); 754 755 for (int i = 0; i < 5; i++) { 756 final Task task = mTasks.get(i); 757 task.touchActiveTime(); 758 mRecentTasks.add(task); 759 } 760 761 // Ensure that only the last number of max tasks are kept 762 triggerTrimAndAssertTrimmed(mTasks.get(0), mTasks.get(1)); 763 } 764 765 /** 766 * Tests that tasks on always on top multi-window tasks are not visible and not trimmed/removed. 767 */ 768 @Test testVisibleTasks_alwaysOnTop()769 public void testVisibleTasks_alwaysOnTop() { 770 mRecentTasks.setOnlyTestVisibleRange(); 771 mRecentTasks.setParameters(-1 /* min */, 3 /* max */, -1 /* ms */); 772 773 final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); 774 final Task alwaysOnTopTask = taskDisplayArea.createRootTask(WINDOWING_MODE_MULTI_WINDOW, 775 ACTIVITY_TYPE_STANDARD, true /* onTop */); 776 alwaysOnTopTask.setAlwaysOnTop(true); 777 alwaysOnTopTask.setForceHidden(FLAG_FORCE_HIDDEN_FOR_TASK_ORG, true); 778 779 assertFalse("Always on top tasks should not be visible recents", 780 mRecentTasks.isVisibleRecentTask(alwaysOnTopTask)); 781 782 mRecentTasks.add(alwaysOnTopTask); 783 784 // Add N+1 visible tasks. 785 mRecentTasks.add(mTasks.get(0)); 786 mRecentTasks.add(mTasks.get(1)); 787 mRecentTasks.add(mTasks.get(2)); 788 mRecentTasks.add(mTasks.get(3)); 789 790 // excludedTask is not trimmed. 791 triggerTrimAndAssertTrimmed(mTasks.get(0)); 792 793 mRecentTasks.removeAllVisibleTasks(TEST_USER_0_ID); 794 795 // Only visible tasks removed. 796 triggerTrimAndAssertTrimmed(mTasks.get(0), mTasks.get(1), mTasks.get(2), mTasks.get(3)); 797 } 798 799 @Test testVisibleTask_displayCanNotShowTaskFromRecents_expectNotVisible()800 public void testVisibleTask_displayCanNotShowTaskFromRecents_expectNotVisible() { 801 final DisplayContent displayContent = addNewDisplayContentAt(DisplayContent.POSITION_TOP); 802 doReturn(false).when(displayContent).canShowTasksInHostDeviceRecents(); 803 final Task task = displayContent.getDefaultTaskDisplayArea().createRootTask( 804 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); 805 mRecentTasks.add(task); 806 807 assertFalse(mRecentTasks.isVisibleRecentTask(task)); 808 } 809 810 @Test testFreezeTaskListOrder_reorderExistingTask()811 public void testFreezeTaskListOrder_reorderExistingTask() { 812 // Add some tasks 813 mRecentTasks.add(mTasks.get(0)); 814 mRecentTasks.add(mTasks.get(1)); 815 mRecentTasks.add(mTasks.get(2)); 816 mRecentTasks.add(mTasks.get(3)); 817 mRecentTasks.add(mTasks.get(4)); 818 mCallbacksRecorder.clear(); 819 820 // Freeze the list 821 mRecentTasks.setFreezeTaskListReordering(); 822 assertTrue(mRecentTasks.isFreezeTaskListReorderingSet()); 823 824 // Relaunch a few tasks 825 mRecentTasks.add(mTasks.get(3)); 826 mRecentTasks.add(mTasks.get(2)); 827 828 // Commit the task ordering with a specific task focused 829 mRecentTasks.resetFreezeTaskListReordering(mTasks.get(2)); 830 assertFalse(mRecentTasks.isFreezeTaskListReorderingSet()); 831 832 // Ensure that the order of the task list is the same as before, but with the focused task 833 // at the front 834 assertRecentTasksOrder(mTasks.get(2), 835 mTasks.get(4), 836 mTasks.get(3), 837 mTasks.get(1), 838 mTasks.get(0)); 839 840 assertThat(mCallbacksRecorder.mAdded).isEmpty(); 841 assertThat(mCallbacksRecorder.mTrimmed).isEmpty(); 842 assertThat(mCallbacksRecorder.mRemoved).isEmpty(); 843 } 844 845 @Test testFreezeTaskListOrder_addRemoveTasks()846 public void testFreezeTaskListOrder_addRemoveTasks() { 847 // Add some tasks 848 mRecentTasks.add(mTasks.get(0)); 849 mRecentTasks.add(mTasks.get(1)); 850 mRecentTasks.add(mTasks.get(2)); 851 mCallbacksRecorder.clear(); 852 853 // Freeze the list 854 mRecentTasks.setFreezeTaskListReordering(); 855 assertTrue(mRecentTasks.isFreezeTaskListReorderingSet()); 856 857 // Add and remove some tasks 858 mRecentTasks.add(mTasks.get(3)); 859 mRecentTasks.add(mTasks.get(4)); 860 mRecentTasks.remove(mTasks.get(0)); 861 mRecentTasks.remove(mTasks.get(1)); 862 863 // Unfreeze the list 864 mRecentTasks.resetFreezeTaskListReordering(null); 865 assertFalse(mRecentTasks.isFreezeTaskListReorderingSet()); 866 867 // Ensure that the order of the task list accounts for the added and removed tasks (added 868 // at the end) 869 assertRecentTasksOrder(mTasks.get(4), 870 mTasks.get(3), 871 mTasks.get(2)); 872 873 assertThat(mCallbacksRecorder.mAdded).hasSize(2); 874 assertThat(mCallbacksRecorder.mAdded).contains(mTasks.get(3)); 875 assertThat(mCallbacksRecorder.mAdded).contains(mTasks.get(4)); 876 assertThat(mCallbacksRecorder.mRemoved).hasSize(2); 877 assertThat(mCallbacksRecorder.mRemoved).contains(mTasks.get(0)); 878 assertThat(mCallbacksRecorder.mRemoved).contains(mTasks.get(1)); 879 } 880 881 @Test testFreezeTaskListOrder_replaceTask()882 public void testFreezeTaskListOrder_replaceTask() { 883 // Create two tasks with the same affinity 884 Task affinityTask1 = createTaskBuilder(".AffinityTask1") 885 .setFlags(FLAG_ACTIVITY_NEW_TASK) 886 .build(); 887 Task affinityTask2 = createTaskBuilder(".AffinityTask2") 888 .setFlags(FLAG_ACTIVITY_NEW_TASK) 889 .build(); 890 affinityTask2.affinity = affinityTask1.affinity = "affinity"; 891 892 // Add some tasks 893 mRecentTasks.add(mTasks.get(0)); 894 mRecentTasks.add(affinityTask1); 895 mRecentTasks.add(mTasks.get(1)); 896 mCallbacksRecorder.clear(); 897 898 // Freeze the list 899 mRecentTasks.setFreezeTaskListReordering(); 900 assertTrue(mRecentTasks.isFreezeTaskListReorderingSet()); 901 902 // Add the affinity task 903 mRecentTasks.add(affinityTask2); 904 905 assertRecentTasksOrder(mTasks.get(1), 906 affinityTask2, 907 mTasks.get(0)); 908 909 assertThat(mCallbacksRecorder.mAdded).hasSize(1); 910 assertThat(mCallbacksRecorder.mAdded).contains(affinityTask2); 911 assertThat(mCallbacksRecorder.mRemoved).hasSize(1); 912 assertThat(mCallbacksRecorder.mRemoved).contains(affinityTask1); 913 } 914 915 @Test testFreezeTaskListOrder_timeout()916 public void testFreezeTaskListOrder_timeout() { 917 for (Task t : mTasks) { 918 // Make all the tasks non-empty 919 new ActivityBuilder(mAtm).setTask(t).build(); 920 } 921 922 // Add some tasks 923 mRecentTasks.add(mTasks.get(0)); 924 mRecentTasks.add(mTasks.get(1)); 925 mRecentTasks.add(mTasks.get(2)); 926 mRecentTasks.add(mTasks.get(3)); 927 mRecentTasks.add(mTasks.get(4)); 928 929 // Freeze the list 930 mRecentTasks.setFreezeTaskListReordering(); 931 assertTrue(mRecentTasks.isFreezeTaskListReorderingSet()); 932 933 // Relaunch a few tasks 934 mRecentTasks.add(mTasks.get(2)); 935 mRecentTasks.add(mTasks.get(1)); 936 937 Task stack = mTasks.get(2).getRootTask(); 938 stack.moveToFront("", mTasks.get(2)); 939 doReturn(stack).when(mAtm.mRootWindowContainer).getTopDisplayFocusedRootTask(); 940 941 // Simulate the reset from the timeout 942 mRecentTasks.resetFreezeTaskListReorderingOnTimeout(); 943 assertFalse(mRecentTasks.isFreezeTaskListReorderingSet()); 944 945 // Ensure that the order of the task list is the same as before, but with the focused task 946 // at the front 947 assertRecentTasksOrder(mTasks.get(2), 948 mTasks.get(4), 949 mTasks.get(3), 950 mTasks.get(1), 951 mTasks.get(0)); 952 } 953 954 @Test testBackStackTasks_expectNoTrim()955 public void testBackStackTasks_expectNoTrim() { 956 mRecentTasks.setParameters(-1 /* min */, 1 /* max */, -1 /* ms */); 957 958 final Task homeStack = mTaskContainer.getRootHomeTask(); 959 final Task aboveHomeStack = mTaskContainer.createRootTask( 960 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); 961 962 // Add a number of tasks (beyond the max) but ensure that nothing is trimmed because all 963 // the tasks belong in stacks above the home stack 964 mRecentTasks.add(createTaskBuilder(".HomeTask1").setParentTask(homeStack).build()); 965 mRecentTasks.add(createTaskBuilder(".Task1").setParentTask(aboveHomeStack).build()); 966 mRecentTasks.add(createTaskBuilder(".Task2").setParentTask(aboveHomeStack).build()); 967 mRecentTasks.add(createTaskBuilder(".Task3").setParentTask(aboveHomeStack).build()); 968 969 triggerTrimAndAssertNoTasksTrimmed(); 970 } 971 972 @Test testBehindHomeStackTasks_expectTaskTrimmed()973 public void testBehindHomeStackTasks_expectTaskTrimmed() { 974 mRecentTasks.setParameters(-1 /* min */, 1 /* max */, -1 /* ms */); 975 976 final Task behindHomeStack = mTaskContainer.createRootTask( 977 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); 978 final Task homeStack = mTaskContainer.getRootHomeTask(); 979 final Task aboveHomeStack = mTaskContainer.createRootTask( 980 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); 981 982 // Add a number of tasks (beyond the max) but ensure that only the task in the stack behind 983 // the home stack is trimmed once a new task is added 984 final Task behindHomeTask = createTaskBuilder(".Task1") 985 .setParentTask(behindHomeStack) 986 .build(); 987 mRecentTasks.add(behindHomeTask); 988 mRecentTasks.add(createTaskBuilder(".HomeTask1").setParentTask(homeStack).build()); 989 mRecentTasks.add(createTaskBuilder(".Task2").setParentTask(aboveHomeStack).build()); 990 991 triggerTrimAndAssertTrimmed(behindHomeTask); 992 } 993 994 @Test testOtherDisplayTasks_expectNoTrim()995 public void testOtherDisplayTasks_expectNoTrim() { 996 mRecentTasks.setParameters(-1 /* min */, 1 /* max */, -1 /* ms */); 997 998 final Task homeTask = mTaskContainer.getRootHomeTask(); 999 final DisplayContent otherDisplay = addNewDisplayContentAt(DisplayContent.POSITION_TOP); 1000 final Task otherDisplayRootTask = otherDisplay.getDefaultTaskDisplayArea().createRootTask( 1001 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); 1002 1003 // Add a number of tasks (beyond the max) on each display, ensure that the tasks are not 1004 // removed 1005 mRecentTasks.add(createTaskBuilder(".HomeTask1").setParentTask(homeTask).build()); 1006 mRecentTasks.add(createTaskBuilder(".Task1").setParentTask(otherDisplayRootTask) 1007 .build()); 1008 mRecentTasks.add(createTaskBuilder(".Task2").setParentTask(otherDisplayRootTask) 1009 .build()); 1010 mRecentTasks.add(createTaskBuilder(".HomeTask2").setParentTask(homeTask).build()); 1011 1012 triggerTrimAndAssertNoTasksTrimmed(); 1013 } 1014 1015 @Test testRemovePackageByName()1016 public void testRemovePackageByName() { 1017 // Add a number of tasks with the same package name 1018 mRecentTasks.add(createTaskBuilder("com.android.pkg1", ".Task1").build()); 1019 mRecentTasks.add(createTaskBuilder("com.android.pkg2", ".Task2").build()); 1020 mRecentTasks.add(createTaskBuilder("com.android.pkg3", ".Task3").build()); 1021 mRecentTasks.add(createTaskBuilder("com.android.pkg1", ".Task4").build()); 1022 mRecentTasks.removeTasksByPackageName("com.android.pkg1", TEST_USER_0_ID); 1023 1024 final ArrayList<Task> tasks = mRecentTasks.getRawTasks(); 1025 for (int i = 0; i < tasks.size(); i++) { 1026 if (tasks.get(i).intent.getComponent().getPackageName().equals("com.android.pkg1")) { 1027 fail("Expected com.android.pkg1 tasks to be removed"); 1028 } 1029 } 1030 1031 // If the task has a non-stopped activity, the removal will wait for its onDestroy. 1032 final Task task = tasks.get(0); 1033 final ActivityRecord top = new ActivityBuilder(mAtm).setTask(task).build(); 1034 top.lastVisibleTime = 123; 1035 top.setState(ActivityRecord.State.RESUMED, "test"); 1036 mRecentTasks.removeTasksByPackageName(task.getBasePackageName(), TEST_USER_0_ID); 1037 assertTrue(task.mKillProcessesOnDestroyed); 1038 top.setState(ActivityRecord.State.DESTROYING, "test"); 1039 top.destroyed("test"); 1040 assertFalse(task.mKillProcessesOnDestroyed); 1041 } 1042 1043 @Test testRemoveAllVisibleTasks()1044 public void testRemoveAllVisibleTasks() { 1045 mRecentTasks.setParameters(-1 /* min */, 3 /* max */, 100 /* ms */); 1046 1047 // Create some set of tasks, some of which are visible and some are not 1048 Task t1 = createTaskBuilder("com.android.pkg1", ".Task1").build(); 1049 mRecentTasks.add(t1); 1050 mRecentTasks.add(createTaskBuilder("com.android.pkg1", ".HomeTask") 1051 .setParentTask(mTaskContainer.getRootHomeTask()).build()); 1052 Task t2 = createTaskBuilder("com.android.pkg2", ".Task2").build(); 1053 mRecentTasks.add(t2); 1054 mRecentTasks.add(createTaskBuilder("com.android.pkg1", ".PipTask") 1055 .setWindowingMode(WINDOWING_MODE_PINNED).build()); 1056 Task t3 = createTaskBuilder("com.android.pkg3", ".Task3").build(); 1057 mRecentTasks.add(t3); 1058 1059 // Create some more tasks that are out of visible range, but are still visible 1060 Task t4 = createTaskBuilder("com.android.pkg3", ".Task4").build(); 1061 mRecentTasks.add(t4); 1062 Task t5 = createTaskBuilder("com.android.pkg3", ".Task5").build(); 1063 mRecentTasks.add(t5); 1064 1065 // Create some more tasks that are out of the active session range, but are still visible 1066 Task t6 = createTaskBuilder("com.android.pkg3", ".Task6").build(); 1067 t6.lastActiveTime = SystemClock.elapsedRealtime() - 200; 1068 mRecentTasks.add(t6); 1069 Task t7 = createTaskBuilder("com.android.pkg3", ".Task7").build(); 1070 t7.lastActiveTime = SystemClock.elapsedRealtime() - 200; 1071 mRecentTasks.add(t7); 1072 1073 // Remove all the visible tasks and ensure that they are removed 1074 mRecentTasks.removeAllVisibleTasks(TEST_USER_0_ID); 1075 triggerTrimAndAssertTrimmed(t1, t2, t3, t4, t5, t6, t7); 1076 } 1077 1078 @Test testRemoveAllVisibleTasksPerUser()1079 public void testRemoveAllVisibleTasksPerUser() { 1080 mRecentTasks.setParameters(-1 /* min */, 3 /* max */, 100 /* ms */); 1081 1082 // Create a visible task per user 1083 Task t1 = createTaskBuilder(".Task1") 1084 .setUserId(TEST_USER_0_ID) 1085 .build(); 1086 mRecentTasks.add(t1); 1087 1088 Task t2 = createTaskBuilder(".Task2") 1089 .setUserId(TEST_QUIET_USER_ID) 1090 .build(); 1091 mRecentTasks.add(t2); 1092 1093 Task t3 = createTaskBuilder(".Task3") 1094 .setUserId(TEST_USER_1_ID) 1095 .build(); 1096 mRecentTasks.add(t3); 1097 1098 // Remove all the visible tasks and ensure that they are removed 1099 mRecentTasks.removeAllVisibleTasks(TEST_USER_0_ID); 1100 triggerTrimAndAssertTrimmed(t1, t2); 1101 } 1102 1103 @Test testNotRestoreRecentTaskApis()1104 public void testNotRestoreRecentTaskApis() { 1105 final Task task = createTaskBuilder(".Task").build(); 1106 final int taskId = task.mTaskId; 1107 mRecentTasks.add(task); 1108 // Only keep the task in RecentTasks. 1109 task.removeIfPossible(); 1110 1111 // The following APIs should not restore task from recents to the active list. 1112 assertNotRestoreTask(() -> mAtm.setFocusedTask(taskId)); 1113 assertNotRestoreTask(() -> mAtm.startSystemLockTaskMode(taskId)); 1114 assertNotRestoreTask(() -> mAtm.cancelTaskWindowTransition(taskId)); 1115 assertNotRestoreTask( 1116 () -> mAtm.resizeTask(taskId, null /* bounds */, 0 /* resizeMode */)); 1117 } 1118 1119 @Test addTask_callsTaskNotificationController()1120 public void addTask_callsTaskNotificationController() { 1121 final Task task = createTaskBuilder(".Task").build(); 1122 1123 mRecentTasks.add(task); 1124 mRecentTasks.remove(task); 1125 1126 TaskChangeNotificationController controller = 1127 mAtm.getTaskChangeNotificationController(); 1128 verify(controller, times(2)).notifyTaskListUpdated(); 1129 } 1130 1131 @Test addTask_taskAlreadyInRecentsMovedToTop_callsTaskNotificationController()1132 public void addTask_taskAlreadyInRecentsMovedToTop_callsTaskNotificationController() { 1133 final Task firstTask = createTaskBuilder(".Task").build(); 1134 final Task secondTask = createTaskBuilder(".Task2").build(); 1135 1136 mRecentTasks.add(firstTask); 1137 mRecentTasks.add(secondTask); 1138 1139 TaskChangeNotificationController controller = 1140 mAtm.getTaskChangeNotificationController(); 1141 clearInvocations(controller); 1142 1143 // Add firstTask back to top 1144 mRecentTasks.add(firstTask); 1145 verify(controller).notifyTaskListUpdated(); 1146 } 1147 1148 @Test addTask_taskAlreadyInRecentsOnTop_doesNotNotify()1149 public void addTask_taskAlreadyInRecentsOnTop_doesNotNotify() { 1150 final Task firstTask = createTaskBuilder(".Task").build(); 1151 final Task secondTask = createTaskBuilder(".Task2").build(); 1152 1153 mRecentTasks.add(firstTask); 1154 mRecentTasks.add(secondTask); 1155 1156 TaskChangeNotificationController controller = 1157 mAtm.getTaskChangeNotificationController(); 1158 clearInvocations(controller); 1159 1160 // Add secondTask to top again 1161 mRecentTasks.add(secondTask); 1162 verifyZeroInteractions(controller); 1163 } 1164 1165 @Test removeTask_callsTaskNotificationController()1166 public void removeTask_callsTaskNotificationController() { 1167 final Task task = createTaskBuilder(".Task").build(); 1168 1169 mRecentTasks.add(task); 1170 mRecentTasks.remove(task); 1171 1172 // 2 calls - Once for add and once for remove 1173 TaskChangeNotificationController controller = 1174 mAtm.getTaskChangeNotificationController(); 1175 verify(controller, times(2)).notifyTaskListUpdated(); 1176 } 1177 1178 @Test removeALlVisibleTask_callsTaskNotificationController_twice()1179 public void removeALlVisibleTask_callsTaskNotificationController_twice() { 1180 final Task task1 = createTaskBuilder(".Task").build(); 1181 final Task task2 = createTaskBuilder(".Task2").build(); 1182 1183 mRecentTasks.add(task1); 1184 mRecentTasks.add(task2); 1185 mRecentTasks.removeAllVisibleTasks(TEST_USER_0_ID); 1186 1187 // 4 calls - Twice for add and twice for remove 1188 TaskChangeNotificationController controller = 1189 mAtm.getTaskChangeNotificationController(); 1190 verify(controller, times(4)).notifyTaskListUpdated(); 1191 } 1192 1193 @Test testTaskInfo_expectNoExtras()1194 public void testTaskInfo_expectNoExtras() { 1195 final Bundle data = new Bundle(); 1196 data.putInt("key", 100); 1197 final Task task1 = createTaskBuilder(".Task").build(); 1198 final ActivityRecord r1 = new ActivityBuilder(mAtm) 1199 .setTask(task1) 1200 .setIntentExtras(data) 1201 .build(); 1202 mRecentTasks.add(r1.getTask()); 1203 1204 final List<RecentTaskInfo> infos = getRecentTasks(0 /* flags */); 1205 assertTrue(infos.size() == 1); 1206 for (int i = 0; i < infos.size(); i++) { 1207 final Bundle extras = infos.get(i).baseIntent.getExtras(); 1208 assertTrue(extras == null || extras.isEmpty()); 1209 } 1210 } 1211 1212 @Test testLastSnapshotData_snapshotSaved()1213 public void testLastSnapshotData_snapshotSaved() { 1214 final TaskSnapshot snapshot = createSnapshot(new Point(100, 100), new Point(80, 80)); 1215 final Task task1 = createTaskBuilder(".Task").build(); 1216 task1.onSnapshotChanged(snapshot); 1217 1218 mRecentTasks.add(task1); 1219 final List<RecentTaskInfo> infos = getRecentTasks(0 /* flags */); 1220 final RecentTaskInfo.PersistedTaskSnapshotData lastSnapshotData = 1221 infos.get(0).lastSnapshotData; 1222 assertTrue(lastSnapshotData.taskSize.equals(100, 100)); 1223 assertTrue(lastSnapshotData.bufferSize.equals(80, 80)); 1224 } 1225 1226 @Test testLastSnapshotData_noBuffer()1227 public void testLastSnapshotData_noBuffer() { 1228 final Task task1 = createTaskBuilder(".Task").build(); 1229 final TaskSnapshot snapshot = createSnapshot(new Point(100, 100), null); 1230 task1.onSnapshotChanged(snapshot); 1231 1232 mRecentTasks.add(task1); 1233 final List<RecentTaskInfo> infos = getRecentTasks(0 /* flags */); 1234 final RecentTaskInfo.PersistedTaskSnapshotData lastSnapshotData = 1235 infos.get(0).lastSnapshotData; 1236 assertTrue(lastSnapshotData.taskSize.equals(100, 100)); 1237 assertNull(lastSnapshotData.bufferSize); 1238 } 1239 1240 @Test testLastSnapshotData_notSet()1241 public void testLastSnapshotData_notSet() { 1242 final Task task1 = createTaskBuilder(".Task").build(); 1243 1244 mRecentTasks.add(task1); 1245 final List<RecentTaskInfo> infos = getRecentTasks(0 /* flags */); 1246 final RecentTaskInfo.PersistedTaskSnapshotData lastSnapshotData = 1247 infos.get(0).lastSnapshotData; 1248 assertNull(lastSnapshotData.taskSize); 1249 assertNull(lastSnapshotData.bufferSize); 1250 } 1251 1252 @Test testCreateRecentTaskInfo_detachedTask()1253 public void testCreateRecentTaskInfo_detachedTask() { 1254 final Task task = createTaskBuilder(".Task").build(); 1255 final ComponentName componentName = getUniqueComponentName(); 1256 new ActivityBuilder(mSupervisor.mService) 1257 .setTask(task) 1258 .setUid(NOBODY_UID) 1259 .setComponent(componentName) 1260 .build(); 1261 final TaskDisplayArea tda = task.getDisplayArea(); 1262 1263 assertTrue(task.isAttached()); 1264 assertTrue(task.supportsMultiWindow()); 1265 1266 RecentTaskInfo info = mRecentTasks.createRecentTaskInfo(task, true /* stripExtras */, 1267 true /* getTasksAllowed */); 1268 1269 assertTrue(info.supportsMultiWindow); 1270 1271 info = mRecentTasks.createRecentTaskInfo(task, true /* stripExtras */, 1272 false /* getTasksAllowed */); 1273 1274 assertFalse(info.topActivity.equals(componentName)); 1275 assertFalse(info.topActivityInfo.packageName.equals(componentName.getPackageName())); 1276 assertFalse(info.baseActivity.equals(componentName)); 1277 1278 // The task can be put in split screen even if it is not attached now. 1279 task.removeImmediately(); 1280 1281 info = mRecentTasks.createRecentTaskInfo(task, true /* stripExtras */, 1282 true /* getTasksAllowed */); 1283 1284 assertTrue(info.supportsMultiWindow); 1285 1286 // Test non-resizable. 1287 // The non-resizable task cannot be put in split screen because of the config. 1288 doReturn(false).when(tda).supportsNonResizableMultiWindow(); 1289 doReturn(false).when(task).isResizeable(); 1290 1291 info = mRecentTasks.createRecentTaskInfo(task, true /* stripExtras */, 1292 true /* getTasksAllowed */); 1293 1294 assertFalse(info.supportsMultiWindow); 1295 1296 // Even if it is not attached, the non-resizable task can be put in split screen as long as 1297 // the device supports it. 1298 doReturn(true).when(tda).supportsNonResizableMultiWindow(); 1299 1300 info = mRecentTasks.createRecentTaskInfo(task, true /* stripExtras */, 1301 true /* getTasksAllowed */); 1302 1303 assertTrue(info.supportsMultiWindow); 1304 } 1305 1306 @Test testRemoveCompatibleRecentTask()1307 public void testRemoveCompatibleRecentTask() { 1308 final Task task1 = createTaskBuilder(".Task").setWindowingMode( 1309 WINDOWING_MODE_FULLSCREEN).build(); 1310 mRecentTasks.add(task1); 1311 final Task task2 = createTaskBuilder(".Task").setWindowingMode( 1312 WINDOWING_MODE_MULTI_WINDOW).build(); 1313 mRecentTasks.add(task2); 1314 assertEquals(2, mRecentTasks.getRecentTasks(MAX_VALUE, 0 /* flags */, 1315 true /* getTasksAllowed */, TEST_USER_0_ID, 0).getList().size()); 1316 1317 // Set windowing mode and ensure the same fullscreen task that created earlier is removed. 1318 task2.setWindowingMode(WINDOWING_MODE_FULLSCREEN); 1319 mRecentTasks.removeCompatibleRecentTask(task2); 1320 assertEquals(1, mRecentTasks.getRecentTasks(MAX_VALUE, 0 /* flags */, 1321 true /* getTasksAllowed */, TEST_USER_0_ID, 0).getList().size()); 1322 assertEquals(task2.mTaskId, mRecentTasks.getRecentTasks(MAX_VALUE, 0 /* flags */, 1323 true /* getTasksAllowed */, TEST_USER_0_ID, 0).getList().get(0).taskId); 1324 } 1325 createSnapshot(Point taskSize, Point bufferSize)1326 private TaskSnapshot createSnapshot(Point taskSize, Point bufferSize) { 1327 HardwareBuffer buffer = null; 1328 if (bufferSize != null) { 1329 buffer = mock(HardwareBuffer.class); 1330 doReturn(bufferSize.x).when(buffer).getWidth(); 1331 doReturn(bufferSize.y).when(buffer).getHeight(); 1332 } 1333 return new TaskSnapshot(1, 0 /* captureTime */, new ComponentName("", ""), buffer, 1334 ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT, 1335 Surface.ROTATION_0, taskSize, new Rect() /* contentInsets */, 1336 new Rect() /* letterboxInsets*/, false /* isLowResolution */, 1337 true /* isRealSnapshot */, WINDOWING_MODE_FULLSCREEN, 0 /* mSystemUiVisibility */, 1338 false /* isTranslucent */, false /* hasImeSurface */); 1339 } 1340 1341 /** 1342 * Ensures that the raw recent tasks list is in the provided order. Note that the expected tasks 1343 * should be ordered from least to most recent. 1344 */ assertRecentTasksOrder(Task... expectedTasks)1345 private void assertRecentTasksOrder(Task... expectedTasks) { 1346 ArrayList<Task> tasks = mRecentTasks.getRawTasks(); 1347 assertTrue(expectedTasks.length == tasks.size()); 1348 for (int i = 0; i < tasks.size(); i++) { 1349 assertTrue(expectedTasks[i] == tasks.get(i)); 1350 } 1351 } 1352 getRecentTasks(int flags)1353 private List<RecentTaskInfo> getRecentTasks(int flags) { 1354 doNothing().when(mRecentTasks).loadUserRecentsLocked(anyInt()); 1355 doReturn(true).when(mRecentTasks).isUserRunning(anyInt(), anyInt()); 1356 return mRecentTasks.getRecentTasks(MAX_VALUE, flags, true /* getTasksAllowed */, 1357 TEST_USER_0_ID, 0 /* callingUid */).getList(); 1358 } 1359 1360 /** 1361 * Ensures that the recent tasks list is in the provided order. Note that the expected tasks 1362 * should be ordered from least to most recent. 1363 */ assertGetRecentTasksOrder(int getRecentTaskFlags, Task... expectedTasks)1364 private void assertGetRecentTasksOrder(int getRecentTaskFlags, Task... expectedTasks) { 1365 List<RecentTaskInfo> infos = getRecentTasks(getRecentTaskFlags); 1366 assertTrue(expectedTasks.length == infos.size()); 1367 for (int i = 0; i < infos.size(); i++) { 1368 assertTrue(expectedTasks[i].mTaskId == infos.get(i).taskId); 1369 } 1370 } 1371 assertNotRestoreTask(Runnable action)1372 private void assertNotRestoreTask(Runnable action) { 1373 // Verify stack count doesn't change because task with fullscreen mode and standard type 1374 // would have its own stack. 1375 final int originalStackCount = mTaskContainer.getRootTaskCount(); 1376 action.run(); 1377 assertEquals(originalStackCount, mTaskContainer.getRootTaskCount()); 1378 } 1379 doTestRecentTasksApis(boolean expectCallable)1380 private void doTestRecentTasksApis(boolean expectCallable) { 1381 assertSecurityException(expectCallable, () -> mAtm.removeTask(INVALID_STACK_ID)); 1382 assertSecurityException(expectCallable, 1383 () -> mAtm.removeRootTasksInWindowingModes( 1384 new int[]{WINDOWING_MODE_UNDEFINED})); 1385 assertSecurityException(expectCallable, 1386 () -> mAtm.removeRootTasksWithActivityTypes( 1387 new int[]{ACTIVITY_TYPE_UNDEFINED})); 1388 assertSecurityException(expectCallable, () -> mAtm.removeTask(0)); 1389 assertSecurityException(expectCallable, 1390 () -> mAtm.moveTaskToRootTask(0, INVALID_STACK_ID, true)); 1391 assertSecurityException(expectCallable, () -> mAtm.getAllRootTaskInfos()); 1392 assertSecurityException(expectCallable, 1393 () -> mAtm.getRootTaskInfo(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_UNDEFINED)); 1394 assertSecurityException(expectCallable, () -> { 1395 try { 1396 mAtm.getFocusedRootTaskInfo(); 1397 } catch (RemoteException e) { 1398 // Ignore 1399 } 1400 }); 1401 assertSecurityException(expectCallable, 1402 () -> mAtm.startActivityFromRecents(0, new Bundle())); 1403 assertSecurityException(expectCallable, () -> mAtm.getTaskSnapshot(0, true, false)); 1404 assertSecurityException(expectCallable, () -> mAtm.registerTaskStackListener(null)); 1405 assertSecurityException(expectCallable, 1406 () -> mAtm.unregisterTaskStackListener(null)); 1407 assertSecurityException(expectCallable, () -> mAtm.getTaskDescription(0)); 1408 assertSecurityException(expectCallable, () -> mAtm.cancelTaskWindowTransition(0)); 1409 assertSecurityException(expectCallable, () -> mAtm.startRecentsActivity(null, 0, 1410 null)); 1411 assertSecurityException(expectCallable, () -> mAtm.cancelRecentsAnimation(true)); 1412 assertSecurityException(expectCallable, () -> mAtm.stopAppSwitches()); 1413 assertSecurityException(expectCallable, () -> mAtm.resumeAppSwitches()); 1414 } 1415 testGetTasksApis(boolean expectCallable)1416 private void testGetTasksApis(boolean expectCallable) { 1417 mAtm.getRecentTasks(MAX_VALUE, 0, TEST_USER_0_ID); 1418 mAtm.getTasks(MAX_VALUE); 1419 if (expectCallable) { 1420 assertTrue(mRecentTasks.mLastAllowed); 1421 assertTrue(mRunningTasks.mLastAllowed); 1422 } else { 1423 assertFalse(mRecentTasks.mLastAllowed); 1424 assertFalse(mRunningTasks.mLastAllowed); 1425 } 1426 } 1427 createTaskBuilder(String className)1428 private TaskBuilder createTaskBuilder(String className) { 1429 return createTaskBuilder(mContext.getPackageName(), className); 1430 } 1431 createTaskBuilder(String packageName, String className)1432 private TaskBuilder createTaskBuilder(String packageName, String className) { 1433 return new TaskBuilder(mAtm.mTaskSupervisor) 1434 .setComponent(new ComponentName(packageName, className)) 1435 .setUserId(TEST_USER_0_ID); 1436 } 1437 createDocumentTask(String className)1438 private Task createDocumentTask(String className) { 1439 return createDocumentTask(className, 0); 1440 } 1441 createDocumentTask(String className, int flags)1442 private Task createDocumentTask(String className, int flags) { 1443 Task task = createTaskBuilder(className) 1444 .setFlags(FLAG_ACTIVITY_NEW_DOCUMENT | flags) 1445 .build(); 1446 task.affinity = null; 1447 task.maxRecents = ActivityTaskManager.getMaxAppRecentsLimitStatic(); 1448 return task; 1449 } 1450 triggerIdleToTrim()1451 private void triggerIdleToTrim() { 1452 doNothing().when(mAtm).scheduleAppGcsLocked(); 1453 final ActivityRecord r = mRootWindowContainer.topRunningActivity(); 1454 mSupervisor.activityIdleInternal(r != null ? r : mock(ActivityRecord.class), 1455 false /* fromTimeout */, false /* processPausingActivities */, null /* config */); 1456 } 1457 triggerTrimAndAssertNoTasksTrimmed()1458 private void triggerTrimAndAssertNoTasksTrimmed() { 1459 triggerTrimAndAssertTrimmed(); 1460 } 1461 triggerTrimAndAssertTrimmed(Task... tasks)1462 private void triggerTrimAndAssertTrimmed(Task... tasks) { 1463 triggerIdleToTrim(); 1464 final ArrayList<Task> trimmed = mCallbacksRecorder.mTrimmed; 1465 final ArrayList<Task> removed = mCallbacksRecorder.mRemoved; 1466 assertWithMessage("Expected " + tasks.length + " trimmed tasks, got " + trimmed.size()) 1467 .that(trimmed).hasSize(tasks.length); 1468 assertWithMessage("Expected " + tasks.length + " removed tasks, got " + removed.size()) 1469 .that(removed).hasSize(tasks.length); 1470 for (Task task : tasks) { 1471 assertWithMessage("Expected trimmed task: " + task).that(trimmed).contains(task); 1472 assertWithMessage("Expected removed task: " + task).that(removed).contains(task); 1473 } 1474 } 1475 assertSecurityException(boolean expectCallable, Runnable runnable)1476 private void assertSecurityException(boolean expectCallable, Runnable runnable) { 1477 boolean noSecurityException = true; 1478 try { 1479 runnable.run(); 1480 } catch (SecurityException se) { 1481 noSecurityException = false; 1482 } catch (Exception e) { 1483 // We only care about SecurityExceptions, fall through here. 1484 } 1485 if (noSecurityException != expectCallable) { 1486 fail("Expected callable: " + expectCallable + " but got no security exception: " 1487 + noSecurityException); 1488 } 1489 } 1490 1491 private static class CallbacksRecorder implements Callbacks { 1492 public final ArrayList<Task> mAdded = new ArrayList<>(); 1493 public final ArrayList<Task> mTrimmed = new ArrayList<>(); 1494 public final ArrayList<Task> mRemoved = new ArrayList<>(); 1495 clear()1496 void clear() { 1497 mAdded.clear(); 1498 mTrimmed.clear(); 1499 mRemoved.clear(); 1500 } 1501 1502 @Override onRecentTaskAdded(Task task)1503 public void onRecentTaskAdded(Task task) { 1504 mAdded.add(task); 1505 } 1506 1507 @Override onRecentTaskRemoved(Task task, boolean wasTrimmed, boolean killProcess)1508 public void onRecentTaskRemoved(Task task, boolean wasTrimmed, boolean killProcess) { 1509 if (wasTrimmed) { 1510 mTrimmed.add(task); 1511 } 1512 mRemoved.add(task); 1513 } 1514 } 1515 1516 private static class TestTaskPersister extends TaskPersister { 1517 public SparseBooleanArray mUserTaskIdsOverride; 1518 public ArrayList<Task> mUserTasksOverride; 1519 TestTaskPersister(File workingDir)1520 TestTaskPersister(File workingDir) { 1521 super(workingDir); 1522 } 1523 1524 @Override loadPersistedTaskIdsForUser(int userId)1525 SparseBooleanArray loadPersistedTaskIdsForUser(int userId) { 1526 if (mUserTaskIdsOverride != null) { 1527 return mUserTaskIdsOverride; 1528 } 1529 return super.loadPersistedTaskIdsForUser(userId); 1530 } 1531 1532 @Override restoreTasksForUserLocked(int userId, SparseBooleanArray preaddedTasks)1533 List<Task> restoreTasksForUserLocked(int userId, SparseBooleanArray preaddedTasks) { 1534 if (mUserTasksOverride != null) { 1535 return mUserTasksOverride; 1536 } 1537 return super.restoreTasksForUserLocked(userId, preaddedTasks); 1538 } 1539 } 1540 1541 private static class TestRecentTasks extends RecentTasks { 1542 private boolean mIsTrimmableOverride; 1543 1544 public boolean mLastAllowed; 1545 TestRecentTasks(ActivityTaskManagerService service, TaskPersister taskPersister)1546 TestRecentTasks(ActivityTaskManagerService service, TaskPersister taskPersister) { 1547 super(service, taskPersister); 1548 } 1549 1550 @Override getProfileIds(int userId)1551 Set<Integer> getProfileIds(int userId) { 1552 Set<Integer> profileIds = new HashSet<>(); 1553 profileIds.add(TEST_USER_0_ID); 1554 profileIds.add(TEST_QUIET_USER_ID); 1555 return profileIds; 1556 } 1557 1558 @Override getUserInfo(int userId)1559 UserInfo getUserInfo(int userId) { 1560 switch (userId) { 1561 case TEST_USER_0_ID: 1562 case TEST_USER_1_ID: 1563 return DEFAULT_USER_INFO; 1564 case TEST_QUIET_USER_ID: 1565 return QUIET_PROFILE_USER_INFO; 1566 } 1567 return null; 1568 } 1569 1570 @Override getCurrentProfileIds()1571 int[] getCurrentProfileIds() { 1572 return new int[] { TEST_USER_0_ID, TEST_QUIET_USER_ID }; 1573 } 1574 1575 /** 1576 * To simplify the setup for some tests, the caller can request that we only rely on the 1577 * visible range test to determine what is trimmable. In this case, we don't try to 1578 * use the stack order to determine additionally if the task is trimmable when it is not 1579 * in the visible range. 1580 */ setOnlyTestVisibleRange()1581 void setOnlyTestVisibleRange() { 1582 mIsTrimmableOverride = true; 1583 } 1584 1585 @Override getRecentTasks(int maxNum, int flags, boolean getTasksAllowed, int userId, int callingUid)1586 ParceledListSlice<RecentTaskInfo> getRecentTasks(int maxNum, int flags, 1587 boolean getTasksAllowed, int userId, int callingUid) { 1588 mLastAllowed = getTasksAllowed; 1589 return super.getRecentTasks(maxNum, flags, getTasksAllowed, userId, callingUid); 1590 } 1591 1592 @Override isTrimmable(Task task)1593 protected boolean isTrimmable(Task task) { 1594 return mIsTrimmableOverride || super.isTrimmable(task); 1595 } 1596 } 1597 1598 private static class TestRunningTasks extends RunningTasks { 1599 public boolean mLastAllowed; 1600 1601 @Override getTasks(int maxNum, List<RunningTaskInfo> list, int flags, RecentTasks recentTasks, WindowContainer<?> root, int callingUid, ArraySet<Integer> profileIds)1602 void getTasks(int maxNum, List<RunningTaskInfo> list, int flags, RecentTasks recentTasks, 1603 WindowContainer<?> root, int callingUid, ArraySet<Integer> profileIds) { 1604 mLastAllowed = (flags & FLAG_ALLOWED) == FLAG_ALLOWED; 1605 super.getTasks(maxNum, list, flags, recentTasks, root, callingUid, profileIds); 1606 } 1607 } 1608 } 1609