Home | History | Annotate | Download | only in am
      1 /*
      2  * Copyright (C) 2017 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.am;
     18 
     19 import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
     20 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
     21 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
     22 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
     23 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
     24 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
     25 import static android.app.WindowConfiguration.WINDOWING_MODE_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.view.Display.DEFAULT_DISPLAY;
     31 
     32 import static org.junit.Assert.assertFalse;
     33 import static org.junit.Assert.assertTrue;
     34 import static org.junit.Assert.fail;
     35 import static org.mockito.ArgumentMatchers.anyInt;
     36 import static org.mockito.ArgumentMatchers.anyString;
     37 import static org.mockito.Mockito.doReturn;
     38 import static org.mockito.Mockito.mock;
     39 import static org.mockito.Mockito.spy;
     40 
     41 import static java.lang.Integer.MAX_VALUE;
     42 
     43 import android.annotation.TestApi;
     44 import android.app.ActivityManager;
     45 import android.app.ActivityManager.RecentTaskInfo;
     46 import android.app.ActivityManager.RunningTaskInfo;
     47 import android.app.WindowConfiguration;
     48 import android.content.ComponentName;
     49 import android.content.Context;
     50 import android.content.pm.PackageManager;
     51 import android.content.pm.ParceledListSlice;
     52 import android.content.pm.UserInfo;
     53 import android.content.res.Configuration;
     54 import android.graphics.Rect;
     55 import android.os.Bundle;
     56 import android.os.Debug;
     57 import android.os.Looper;
     58 import android.os.RemoteException;
     59 import android.os.SystemClock;
     60 import android.platform.test.annotations.Presubmit;
     61 import android.support.test.InstrumentationRegistry;
     62 import android.support.test.filters.MediumTest;
     63 import android.support.test.runner.AndroidJUnit4;
     64 import android.util.MutableLong;
     65 import android.util.SparseArray;
     66 import android.util.SparseBooleanArray;
     67 
     68 import com.android.server.am.RecentTasks.Callbacks;
     69 
     70 import org.junit.Before;
     71 import org.junit.Test;
     72 import org.junit.runner.RunWith;
     73 
     74 import java.io.File;
     75 import java.util.ArrayList;
     76 import java.util.Arrays;
     77 import java.util.HashSet;
     78 import java.util.List;
     79 import java.util.Random;
     80 import java.util.Set;
     81 
     82 /**
     83  * atest FrameworksServicesTests:RecentTasksTest
     84  */
     85 @MediumTest
     86 @Presubmit
     87 @RunWith(AndroidJUnit4.class)
     88 public class RecentTasksTest extends ActivityTestsBase {
     89     private static final int TEST_USER_0_ID = 0;
     90     private static final int TEST_USER_1_ID = 10;
     91     private static final int TEST_QUIET_USER_ID = 20;
     92     private static final UserInfo DEFAULT_USER_INFO = new UserInfo();
     93     private static final UserInfo QUIET_USER_INFO = new UserInfo();
     94     private static int LAST_TASK_ID = 1;
     95     private static int LAST_STACK_ID = 1;
     96     private static int INVALID_STACK_ID = 999;
     97 
     98     private Context mContext = InstrumentationRegistry.getContext();
     99     private ActivityManagerService mService;
    100     private ActivityDisplay mDisplay;
    101     private ActivityDisplay mOtherDisplay;
    102     private ActivityStack mStack;
    103     private ActivityStack mHomeStack;
    104     private TestTaskPersister mTaskPersister;
    105     private TestRecentTasks mRecentTasks;
    106     private TestRunningTasks mRunningTasks;
    107 
    108     private ArrayList<TaskRecord> mTasks;
    109     private ArrayList<TaskRecord> mSameDocumentTasks;
    110 
    111     private CallbacksRecorder mCallbacksRecorder;
    112 
    113     class TestUserController extends UserController {
    114         TestUserController(ActivityManagerService service) {
    115             super(service);
    116         }
    117 
    118         @Override
    119         int[] getCurrentProfileIds() {
    120             return new int[] { TEST_USER_0_ID, TEST_QUIET_USER_ID };
    121         }
    122 
    123         @Override
    124         Set<Integer> getProfileIds(int userId) {
    125             Set<Integer> profileIds = new HashSet<>();
    126             profileIds.add(TEST_USER_0_ID);
    127             profileIds.add(TEST_QUIET_USER_ID);
    128             return profileIds;
    129         }
    130 
    131         @Override
    132         UserInfo getUserInfo(int userId) {
    133             switch (userId) {
    134                 case TEST_USER_0_ID:
    135                 case TEST_USER_1_ID:
    136                     return DEFAULT_USER_INFO;
    137                 case TEST_QUIET_USER_ID:
    138                     return QUIET_USER_INFO;
    139             }
    140             return null;
    141         }
    142     }
    143 
    144     @Before
    145     @Override
    146     public void setUp() throws Exception {
    147         super.setUp();
    148 
    149         mTaskPersister = new TestTaskPersister(mContext.getFilesDir());
    150         mService = setupActivityManagerService(new MyTestActivityManagerService(mContext));
    151         mRecentTasks = (TestRecentTasks) mService.getRecentTasks();
    152         mRecentTasks.loadParametersFromResources(mContext.getResources());
    153         mHomeStack = mService.mStackSupervisor.getDefaultDisplay().createStack(
    154                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
    155         mStack = mService.mStackSupervisor.getDefaultDisplay().createStack(
    156                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
    157         ((MyTestActivityStackSupervisor) mService.mStackSupervisor).setHomeStack(mHomeStack);
    158         mCallbacksRecorder = new CallbacksRecorder();
    159         mRecentTasks.registerCallback(mCallbacksRecorder);
    160         QUIET_USER_INFO.flags = UserInfo.FLAG_MANAGED_PROFILE | UserInfo.FLAG_QUIET_MODE;
    161 
    162         mTasks = new ArrayList<>();
    163         mTasks.add(createTaskBuilder(".Task1").build());
    164         mTasks.add(createTaskBuilder(".Task2").build());
    165         mTasks.add(createTaskBuilder(".Task3").build());
    166         mTasks.add(createTaskBuilder(".Task4").build());
    167         mTasks.add(createTaskBuilder(".Task5").build());
    168 
    169         mSameDocumentTasks = new ArrayList<>();
    170         mSameDocumentTasks.add(createDocumentTask(".DocumentTask1"));
    171         mSameDocumentTasks.add(createDocumentTask(".DocumentTask1"));
    172     }
    173 
    174     @Test
    175     public void testCallbacks() throws Exception {
    176         // Add some tasks
    177         mRecentTasks.add(mTasks.get(0));
    178         mRecentTasks.add(mTasks.get(1));
    179         assertTrue(mCallbacksRecorder.added.contains(mTasks.get(0))
    180                 && mCallbacksRecorder.added.contains(mTasks.get(1)));
    181         assertTrue(mCallbacksRecorder.trimmed.isEmpty());
    182         assertTrue(mCallbacksRecorder.removed.isEmpty());
    183         mCallbacksRecorder.clear();
    184 
    185         // Remove some tasks
    186         mRecentTasks.remove(mTasks.get(0));
    187         mRecentTasks.remove(mTasks.get(1));
    188         assertTrue(mCallbacksRecorder.added.isEmpty());
    189         assertTrue(mCallbacksRecorder.trimmed.isEmpty());
    190         assertTrue(mCallbacksRecorder.removed.contains(mTasks.get(0)));
    191         assertTrue(mCallbacksRecorder.removed.contains(mTasks.get(1)));
    192         mCallbacksRecorder.clear();
    193 
    194         // Remove the callback, ensure we don't get any calls
    195         mRecentTasks.unregisterCallback(mCallbacksRecorder);
    196         mRecentTasks.add(mTasks.get(0));
    197         mRecentTasks.remove(mTasks.get(0));
    198         assertTrue(mCallbacksRecorder.added.isEmpty());
    199         assertTrue(mCallbacksRecorder.trimmed.isEmpty());
    200         assertTrue(mCallbacksRecorder.removed.isEmpty());
    201     }
    202 
    203     @Test
    204     public void testAddTasksNoMultiple_expectNoTrim() throws Exception {
    205         // Add same non-multiple-task document tasks will remove the task (to re-add it) but not
    206         // trim it
    207         TaskRecord documentTask1 = createDocumentTask(".DocumentTask1");
    208         TaskRecord documentTask2 = createDocumentTask(".DocumentTask1");
    209         mRecentTasks.add(documentTask1);
    210         mRecentTasks.add(documentTask2);
    211         assertTrue(mCallbacksRecorder.added.contains(documentTask1));
    212         assertTrue(mCallbacksRecorder.added.contains(documentTask2));
    213         assertTrue(mCallbacksRecorder.trimmed.isEmpty());
    214         assertTrue(mCallbacksRecorder.removed.contains(documentTask1));
    215     }
    216 
    217     @Test
    218     public void testAddTasksMaxTaskRecents_expectNoTrim() throws Exception {
    219         // Add a task hitting max-recents for that app will remove the task (to add the next one)
    220         // but not trim it
    221         TaskRecord documentTask1 = createDocumentTask(".DocumentTask1");
    222         TaskRecord documentTask2 = createDocumentTask(".DocumentTask1");
    223         documentTask1.maxRecents = 1;
    224         documentTask2.maxRecents = 1;
    225         mRecentTasks.add(documentTask1);
    226         mRecentTasks.add(documentTask2);
    227         assertTrue(mCallbacksRecorder.added.contains(documentTask1));
    228         assertTrue(mCallbacksRecorder.added.contains(documentTask2));
    229         assertTrue(mCallbacksRecorder.trimmed.isEmpty());
    230         assertTrue(mCallbacksRecorder.removed.contains(documentTask1));
    231     }
    232 
    233     @Test
    234     public void testAddTasksSameTask_expectNoTrim() throws Exception {
    235         // Add a task that is already in the task list does not trigger any callbacks, it just
    236         // moves in the list
    237         TaskRecord documentTask1 = createDocumentTask(".DocumentTask1");
    238         mRecentTasks.add(documentTask1);
    239         mRecentTasks.add(documentTask1);
    240         assertTrue(mCallbacksRecorder.added.size() == 1);
    241         assertTrue(mCallbacksRecorder.added.contains(documentTask1));
    242         assertTrue(mCallbacksRecorder.trimmed.isEmpty());
    243         assertTrue(mCallbacksRecorder.removed.isEmpty());
    244     }
    245 
    246     @Test
    247     public void testAddTasksMultipleDocumentTasks_expectNoTrim() throws Exception {
    248         // Add same multiple-task document tasks does not trim the first tasks
    249         TaskRecord documentTask1 = createDocumentTask(".DocumentTask1",
    250                 FLAG_ACTIVITY_MULTIPLE_TASK);
    251         TaskRecord documentTask2 = createDocumentTask(".DocumentTask1",
    252                 FLAG_ACTIVITY_MULTIPLE_TASK);
    253         mRecentTasks.add(documentTask1);
    254         mRecentTasks.add(documentTask2);
    255         assertTrue(mCallbacksRecorder.added.size() == 2);
    256         assertTrue(mCallbacksRecorder.added.contains(documentTask1));
    257         assertTrue(mCallbacksRecorder.added.contains(documentTask2));
    258         assertTrue(mCallbacksRecorder.trimmed.isEmpty());
    259         assertTrue(mCallbacksRecorder.removed.isEmpty());
    260     }
    261 
    262     @Test
    263     public void testAddTasksMultipleTasks_expectRemovedNoTrim() throws Exception {
    264         // Add multiple same-affinity non-document tasks, ensure that it removes the other task,
    265         // but that it does not trim it
    266         TaskRecord task1 = createTaskBuilder(".Task1")
    267                 .setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK)
    268                 .build();
    269         TaskRecord task2 = createTaskBuilder(".Task1")
    270                 .setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK)
    271                 .build();
    272         mRecentTasks.add(task1);
    273         assertTrue(mCallbacksRecorder.added.size() == 1);
    274         assertTrue(mCallbacksRecorder.added.contains(task1));
    275         assertTrue(mCallbacksRecorder.trimmed.isEmpty());
    276         assertTrue(mCallbacksRecorder.removed.isEmpty());
    277         mCallbacksRecorder.clear();
    278         mRecentTasks.add(task2);
    279         assertTrue(mCallbacksRecorder.added.size() == 1);
    280         assertTrue(mCallbacksRecorder.added.contains(task2));
    281         assertTrue(mCallbacksRecorder.trimmed.isEmpty());
    282         assertTrue(mCallbacksRecorder.removed.size() == 1);
    283         assertTrue(mCallbacksRecorder.removed.contains(task1));
    284     }
    285 
    286     @Test
    287     public void testAddTasksDifferentStacks_expectNoRemove() throws Exception {
    288         // Adding the same task with different activity types should not trigger removal of the
    289         // other task
    290         TaskRecord task1 = createTaskBuilder(".Task1")
    291                 .setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK)
    292                 .setStack(mHomeStack).build();
    293         TaskRecord task2 = createTaskBuilder(".Task1")
    294                 .setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK)
    295                 .setStack(mStack).build();
    296         mRecentTasks.add(task1);
    297         mRecentTasks.add(task2);
    298         assertTrue(mCallbacksRecorder.added.size() == 2);
    299         assertTrue(mCallbacksRecorder.added.contains(task1));
    300         assertTrue(mCallbacksRecorder.added.contains(task2));
    301         assertTrue(mCallbacksRecorder.trimmed.isEmpty());
    302         assertTrue(mCallbacksRecorder.removed.isEmpty());
    303     }
    304 
    305     @Test
    306     public void testAddTaskCompatibleActivityType_expectRemove() throws Exception {
    307         // Test with undefined activity type since the type is not persisted by the task persister
    308         // and we want to ensure that a new task will match a restored task
    309         Configuration config1 = new Configuration();
    310         config1.windowConfiguration.setActivityType(ACTIVITY_TYPE_UNDEFINED);
    311         TaskRecord task1 = createTaskBuilder(".Task1")
    312                 .setFlags(FLAG_ACTIVITY_NEW_TASK)
    313                 .setStack(mStack)
    314                 .build();
    315         task1.onConfigurationChanged(config1);
    316         assertTrue(task1.getActivityType() == ACTIVITY_TYPE_UNDEFINED);
    317         mRecentTasks.add(task1);
    318         mCallbacksRecorder.clear();
    319 
    320         TaskRecord task2 = createTaskBuilder(".Task1")
    321                 .setFlags(FLAG_ACTIVITY_NEW_TASK)
    322                 .setStack(mStack)
    323                 .build();
    324         assertTrue(task2.getActivityType() == ACTIVITY_TYPE_STANDARD);
    325         mRecentTasks.add(task2);
    326         assertTrue(mCallbacksRecorder.added.size() == 1);
    327         assertTrue(mCallbacksRecorder.added.contains(task2));
    328         assertTrue(mCallbacksRecorder.trimmed.isEmpty());
    329         assertTrue(mCallbacksRecorder.removed.size() == 1);
    330         assertTrue(mCallbacksRecorder.removed.contains(task1));
    331     }
    332 
    333     @Test
    334     public void testAddTaskCompatibleActivityTypeDifferentUser_expectNoRemove() throws Exception {
    335         Configuration config1 = new Configuration();
    336         config1.windowConfiguration.setActivityType(ACTIVITY_TYPE_UNDEFINED);
    337         TaskRecord task1 = createTaskBuilder(".Task1")
    338                 .setFlags(FLAG_ACTIVITY_NEW_TASK)
    339                 .setStack(mStack)
    340                 .setUserId(TEST_USER_0_ID)
    341                 .build();
    342         task1.onConfigurationChanged(config1);
    343         assertTrue(task1.getActivityType() == ACTIVITY_TYPE_UNDEFINED);
    344         mRecentTasks.add(task1);
    345         mCallbacksRecorder.clear();
    346 
    347         TaskRecord task2 = createTaskBuilder(".Task1")
    348                 .setFlags(FLAG_ACTIVITY_NEW_TASK)
    349                 .setStack(mStack)
    350                 .setUserId(TEST_USER_1_ID)
    351                 .build();
    352         assertTrue(task2.getActivityType() == ACTIVITY_TYPE_STANDARD);
    353         mRecentTasks.add(task2);
    354         assertTrue(mCallbacksRecorder.added.size() == 1);
    355         assertTrue(mCallbacksRecorder.added.contains(task2));
    356         assertTrue(mCallbacksRecorder.trimmed.isEmpty());
    357         assertTrue(mCallbacksRecorder.removed.isEmpty());
    358     }
    359 
    360     @Test
    361     public void testAddTaskCompatibleWindowingMode_expectRemove() throws Exception {
    362         Configuration config1 = new Configuration();
    363         config1.windowConfiguration.setWindowingMode(WINDOWING_MODE_UNDEFINED);
    364         TaskRecord task1 = createTaskBuilder(".Task1")
    365                 .setFlags(FLAG_ACTIVITY_NEW_TASK)
    366                 .setStack(mStack)
    367                 .build();
    368         task1.onConfigurationChanged(config1);
    369         assertTrue(task1.getWindowingMode() == WINDOWING_MODE_UNDEFINED);
    370         mRecentTasks.add(task1);
    371         mCallbacksRecorder.clear();
    372 
    373         Configuration config2 = new Configuration();
    374         config2.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
    375         TaskRecord task2 = createTaskBuilder(".Task1")
    376                 .setFlags(FLAG_ACTIVITY_NEW_TASK)
    377                 .setStack(mStack)
    378                 .build();
    379         task2.onConfigurationChanged(config2);
    380         assertTrue(task2.getWindowingMode() == WINDOWING_MODE_FULLSCREEN);
    381         mRecentTasks.add(task2);
    382 
    383         assertTrue(mCallbacksRecorder.added.size() == 1);
    384         assertTrue(mCallbacksRecorder.added.contains(task2));
    385         assertTrue(mCallbacksRecorder.trimmed.isEmpty());
    386         assertTrue(mCallbacksRecorder.removed.size() == 1);
    387         assertTrue(mCallbacksRecorder.removed.contains(task1));
    388     }
    389 
    390     @Test
    391     public void testAddTaskIncompatibleWindowingMode_expectNoRemove() throws Exception {
    392         Configuration config1 = new Configuration();
    393         config1.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
    394         TaskRecord task1 = createTaskBuilder(".Task1")
    395                 .setFlags(FLAG_ACTIVITY_NEW_TASK)
    396                 .setStack(mStack)
    397                 .build();
    398         task1.onConfigurationChanged(config1);
    399         assertTrue(task1.getWindowingMode() == WINDOWING_MODE_FULLSCREEN);
    400         mRecentTasks.add(task1);
    401 
    402         Configuration config2 = new Configuration();
    403         config2.windowConfiguration.setWindowingMode(WINDOWING_MODE_PINNED);
    404         TaskRecord task2 = createTaskBuilder(".Task1")
    405                 .setFlags(FLAG_ACTIVITY_NEW_TASK)
    406                 .setStack(mStack)
    407                 .build();
    408         task2.onConfigurationChanged(config2);
    409         assertTrue(task2.getWindowingMode() == WINDOWING_MODE_PINNED);
    410         mRecentTasks.add(task2);
    411 
    412         assertTrue(mCallbacksRecorder.added.size() == 2);
    413         assertTrue(mCallbacksRecorder.added.contains(task1));
    414         assertTrue(mCallbacksRecorder.added.contains(task2));
    415         assertTrue(mCallbacksRecorder.trimmed.isEmpty());
    416         assertTrue(mCallbacksRecorder.removed.isEmpty());
    417     }
    418 
    419     @Test
    420     public void testUsersTasks() throws Exception {
    421         mRecentTasks.setOnlyTestVisibleRange();
    422 
    423         // Setup some tasks for the users
    424         mTaskPersister.userTaskIdsOverride = new SparseBooleanArray();
    425         mTaskPersister.userTaskIdsOverride.put(1, true);
    426         mTaskPersister.userTaskIdsOverride.put(2, true);
    427         mTaskPersister.userTasksOverride = new ArrayList<>();
    428         mTaskPersister.userTasksOverride.add(createTaskBuilder(".UserTask1").build());
    429         mTaskPersister.userTasksOverride.add(createTaskBuilder(".UserTask2").build());
    430 
    431         // Assert no user tasks are initially loaded
    432         assertTrue(mRecentTasks.usersWithRecentsLoadedLocked().length == 0);
    433 
    434         // Load user 0 tasks
    435         mRecentTasks.loadUserRecentsLocked(TEST_USER_0_ID);
    436         assertTrue(arrayContainsUser(mRecentTasks.usersWithRecentsLoadedLocked(), TEST_USER_0_ID));
    437         assertTrue(mRecentTasks.containsTaskId(1, TEST_USER_0_ID));
    438         assertTrue(mRecentTasks.containsTaskId(2, TEST_USER_0_ID));
    439 
    440         // Load user 1 tasks
    441         mRecentTasks.loadUserRecentsLocked(TEST_USER_1_ID);
    442         assertTrue(arrayContainsUser(mRecentTasks.usersWithRecentsLoadedLocked(), TEST_USER_0_ID));
    443         assertTrue(arrayContainsUser(mRecentTasks.usersWithRecentsLoadedLocked(), TEST_USER_1_ID));
    444         assertTrue(mRecentTasks.containsTaskId(1, TEST_USER_0_ID));
    445         assertTrue(mRecentTasks.containsTaskId(2, TEST_USER_0_ID));
    446         assertTrue(mRecentTasks.containsTaskId(1, TEST_USER_1_ID));
    447         assertTrue(mRecentTasks.containsTaskId(2, TEST_USER_1_ID));
    448 
    449         // Unload user 1 tasks
    450         mRecentTasks.unloadUserDataFromMemoryLocked(TEST_USER_1_ID);
    451         assertTrue(arrayContainsUser(mRecentTasks.usersWithRecentsLoadedLocked(), TEST_USER_0_ID));
    452         assertFalse(arrayContainsUser(mRecentTasks.usersWithRecentsLoadedLocked(), TEST_USER_1_ID));
    453         assertTrue(mRecentTasks.containsTaskId(1, TEST_USER_0_ID));
    454         assertTrue(mRecentTasks.containsTaskId(2, TEST_USER_0_ID));
    455 
    456         // Unload user 0 tasks
    457         mRecentTasks.unloadUserDataFromMemoryLocked(TEST_USER_0_ID);
    458         assertFalse(arrayContainsUser(mRecentTasks.usersWithRecentsLoadedLocked(), TEST_USER_0_ID));
    459         assertFalse(arrayContainsUser(mRecentTasks.usersWithRecentsLoadedLocked(), TEST_USER_1_ID));
    460     }
    461 
    462     @Test
    463     public void testOrderedIteration() throws Exception {
    464         mRecentTasks.setOnlyTestVisibleRange();
    465         TaskRecord task1 = createTaskBuilder(".Task1").build();
    466         task1.lastActiveTime = new Random().nextInt();
    467         TaskRecord task2 = createTaskBuilder(".Task1").build();
    468         task2.lastActiveTime = new Random().nextInt();
    469         TaskRecord task3 = createTaskBuilder(".Task1").build();
    470         task3.lastActiveTime = new Random().nextInt();
    471         TaskRecord task4 = createTaskBuilder(".Task1").build();
    472         task4.lastActiveTime = new Random().nextInt();
    473         mRecentTasks.add(task1);
    474         mRecentTasks.add(task2);
    475         mRecentTasks.add(task3);
    476         mRecentTasks.add(task4);
    477 
    478         MutableLong prevLastActiveTime = new MutableLong(0);
    479         final ArrayList<TaskRecord> tasks = mRecentTasks.getRawTasks();
    480         for (int i = 0; i < tasks.size(); i++) {
    481             final TaskRecord task = tasks.get(i);
    482             assertTrue(task.lastActiveTime >= prevLastActiveTime.value);
    483             prevLastActiveTime.value = task.lastActiveTime;
    484         }
    485     }
    486 
    487     @Test
    488     public void testTrimToGlobalMaxNumRecents() throws Exception {
    489         mRecentTasks.setOnlyTestVisibleRange();
    490 
    491         // Limit the global maximum number of recent tasks to a fixed size
    492         mRecentTasks.setGlobalMaxNumTasks(2 /* globalMaxNumTasks */);
    493 
    494         // Add N+1 tasks
    495         mRecentTasks.add(mTasks.get(0));
    496         mRecentTasks.add(mTasks.get(1));
    497         mRecentTasks.add(mTasks.get(2));
    498 
    499         // Ensure that the last task was trimmed as an inactive task
    500         assertTrimmed(mTasks.get(0));
    501     }
    502 
    503     @Test
    504     public void testTrimQuietProfileTasks() throws Exception {
    505         mRecentTasks.setOnlyTestVisibleRange();
    506         TaskRecord qt1 = createTaskBuilder(".QuietTask1").setUserId(TEST_QUIET_USER_ID).build();
    507         TaskRecord qt2 = createTaskBuilder(".QuietTask2").setUserId(TEST_QUIET_USER_ID).build();
    508         mRecentTasks.add(qt1);
    509         mRecentTasks.add(qt2);
    510 
    511         mRecentTasks.add(mTasks.get(0));
    512         mRecentTasks.add(mTasks.get(1));
    513 
    514         // Ensure that the quiet user's tasks was trimmed once the new tasks were added
    515         assertTrimmed(qt1, qt2);
    516     }
    517 
    518     @Test
    519     public void testSessionDuration() throws Exception {
    520         mRecentTasks.setOnlyTestVisibleRange();
    521         mRecentTasks.setParameters(-1 /* min */, -1 /* max */, 50 /* ms */);
    522 
    523         TaskRecord t1 = createTaskBuilder(".Task1").build();
    524         t1.touchActiveTime();
    525         mRecentTasks.add(t1);
    526 
    527         // Force a small sleep just beyond the session duration
    528         SystemClock.sleep(75);
    529 
    530         TaskRecord t2 = createTaskBuilder(".Task2").build();
    531         t2.touchActiveTime();
    532         mRecentTasks.add(t2);
    533 
    534         // Assert that the old task has been removed due to being out of the active session
    535         assertTrimmed(t1);
    536     }
    537 
    538     @Test
    539     public void testVisibleTasks_excludedFromRecents() throws Exception {
    540         mRecentTasks.setOnlyTestVisibleRange();
    541         mRecentTasks.setParameters(-1 /* min */, 4 /* max */, -1 /* ms */);
    542 
    543         TaskRecord excludedTask1 = createTaskBuilder(".ExcludedTask1")
    544                 .setFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
    545                 .build();
    546         TaskRecord excludedTask2 = createTaskBuilder(".ExcludedTask2")
    547                 .setFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
    548                 .build();
    549 
    550         mRecentTasks.add(excludedTask1);
    551         mRecentTasks.add(mTasks.get(0));
    552         mRecentTasks.add(mTasks.get(1));
    553         mRecentTasks.add(mTasks.get(2));
    554         mRecentTasks.add(excludedTask2);
    555 
    556         // The last excluded task should be trimmed, while the first-most excluded task should not
    557         assertTrimmed(excludedTask1);
    558     }
    559 
    560     @Test
    561     public void testVisibleTasks_minNum() throws Exception {
    562         mRecentTasks.setOnlyTestVisibleRange();
    563         mRecentTasks.setParameters(5 /* min */, -1 /* max */, 25 /* ms */);
    564 
    565         for (int i = 0; i < 4; i++) {
    566             final TaskRecord task = mTasks.get(i);
    567             task.touchActiveTime();
    568             mRecentTasks.add(task);
    569         }
    570 
    571         // Force a small sleep just beyond the session duration
    572         SystemClock.sleep(50);
    573 
    574         // Add a new task to trigger tasks to be trimmed
    575         mRecentTasks.add(mTasks.get(4));
    576 
    577         // Ensure that there are a minimum number of tasks regardless of session length
    578         assertNoTasksTrimmed();
    579     }
    580 
    581     @Test
    582     public void testVisibleTasks_maxNum() throws Exception {
    583         mRecentTasks.setOnlyTestVisibleRange();
    584         mRecentTasks.setParameters(-1 /* min */, 3 /* max */, -1 /* ms */);
    585 
    586         for (int i = 0; i < 5; i++) {
    587             final TaskRecord task = mTasks.get(i);
    588             task.touchActiveTime();
    589             mRecentTasks.add(task);
    590         }
    591 
    592         // Ensure that only the last number of max tasks are kept
    593         assertTrimmed(mTasks.get(0), mTasks.get(1));
    594     }
    595 
    596     @Test
    597     public void testBackStackTasks_expectNoTrim() throws Exception {
    598         mRecentTasks.setParameters(-1 /* min */, 1 /* max */, -1 /* ms */);
    599 
    600         final MyTestActivityStackSupervisor supervisor =
    601                 (MyTestActivityStackSupervisor) mService.mStackSupervisor;
    602         final ActivityStack homeStack = new MyTestActivityStack(mDisplay, supervisor);
    603         final ActivityStack aboveHomeStack = new MyTestActivityStack(mDisplay, supervisor);
    604         supervisor.setHomeStack(homeStack);
    605 
    606         // Add a number of tasks (beyond the max) but ensure that nothing is trimmed because all
    607         // the tasks belong in stacks above the home stack
    608         mRecentTasks.add(createTaskBuilder(".HomeTask1").setStack(homeStack).build());
    609         mRecentTasks.add(createTaskBuilder(".Task1").setStack(aboveHomeStack).build());
    610         mRecentTasks.add(createTaskBuilder(".Task2").setStack(aboveHomeStack).build());
    611         mRecentTasks.add(createTaskBuilder(".Task3").setStack(aboveHomeStack).build());
    612 
    613         assertNoTasksTrimmed();
    614     }
    615 
    616     @Test
    617     public void testBehindHomeStackTasks_expectTaskTrimmed() throws Exception {
    618         mRecentTasks.setParameters(-1 /* min */, 1 /* max */, -1 /* ms */);
    619 
    620         final MyTestActivityStackSupervisor supervisor =
    621                 (MyTestActivityStackSupervisor) mService.mStackSupervisor;
    622         final ActivityStack behindHomeStack = new MyTestActivityStack(mDisplay, supervisor);
    623         final ActivityStack homeStack = new MyTestActivityStack(mDisplay, supervisor);
    624         final ActivityStack aboveHomeStack = new MyTestActivityStack(mDisplay, supervisor);
    625         supervisor.setHomeStack(homeStack);
    626 
    627         // Add a number of tasks (beyond the max) but ensure that only the task in the stack behind
    628         // the home stack is trimmed once a new task is added
    629         final TaskRecord behindHomeTask = createTaskBuilder(".Task1")
    630                 .setStack(behindHomeStack)
    631                 .build();
    632         mRecentTasks.add(behindHomeTask);
    633         mRecentTasks.add(createTaskBuilder(".HomeTask1").setStack(homeStack).build());
    634         mRecentTasks.add(createTaskBuilder(".Task2").setStack(aboveHomeStack).build());
    635 
    636         assertTrimmed(behindHomeTask);
    637     }
    638 
    639     @Test
    640     public void testOtherDisplayTasks_expectNoTrim() throws Exception {
    641         mRecentTasks.setParameters(-1 /* min */, 1 /* max */, -1 /* ms */);
    642 
    643         final MyTestActivityStackSupervisor supervisor =
    644                 (MyTestActivityStackSupervisor) mService.mStackSupervisor;
    645         final ActivityStack homeStack = new MyTestActivityStack(mDisplay, supervisor);
    646         final ActivityStack otherDisplayStack = new MyTestActivityStack(mOtherDisplay, supervisor);
    647         supervisor.setHomeStack(homeStack);
    648 
    649         // Add a number of tasks (beyond the max) on each display, ensure that the tasks are not
    650         // removed
    651         mRecentTasks.add(createTaskBuilder(".HomeTask1").setStack(homeStack).build());
    652         mRecentTasks.add(createTaskBuilder(".Task1").setStack(otherDisplayStack).build());
    653         mRecentTasks.add(createTaskBuilder(".Task2").setStack(otherDisplayStack).build());
    654         mRecentTasks.add(createTaskBuilder(".HomeTask2").setStack(homeStack).build());
    655 
    656         assertNoTasksTrimmed();
    657     }
    658 
    659     @Test
    660     public void testRemovePackageByName() throws Exception {
    661         // Add a number of tasks with the same package name
    662         mRecentTasks.add(createTaskBuilder("com.android.pkg1", ".Task1").build());
    663         mRecentTasks.add(createTaskBuilder("com.android.pkg2", ".Task2").build());
    664         mRecentTasks.add(createTaskBuilder("com.android.pkg3", ".Task3").build());
    665         mRecentTasks.add(createTaskBuilder("com.android.pkg1", ".Task4").build());
    666         mRecentTasks.removeTasksByPackageName("com.android.pkg1", TEST_USER_0_ID);
    667 
    668         final ArrayList<TaskRecord> tasks = mRecentTasks.getRawTasks();
    669         for (int i = 0; i < tasks.size(); i++) {
    670             if (tasks.get(i).intent.getComponent().getPackageName().equals("com.android.pkg1")) {
    671                 fail("Expected com.android.pkg1 tasks to be removed");
    672             }
    673         }
    674     }
    675 
    676     @Test
    677     public void testNotRecentsComponent_denyApiAccess() throws Exception {
    678         doReturn(PackageManager.PERMISSION_DENIED).when(mService).checkPermission(anyString(),
    679                 anyInt(), anyInt());
    680 
    681         // Expect the following methods to fail due to recents component not being set
    682         mRecentTasks.setIsCallerRecentsOverride(TestRecentTasks.DENY_THROW_SECURITY_EXCEPTION);
    683         testRecentTasksApis(false /* expectNoSecurityException */);
    684         // Don't throw for the following tests
    685         mRecentTasks.setIsCallerRecentsOverride(TestRecentTasks.DENY);
    686         testGetTasksApis(false /* expectNoSecurityException */);
    687     }
    688 
    689     @Test
    690     public void testRecentsComponent_allowApiAccessWithoutPermissions() throws Exception {
    691         doReturn(PackageManager.PERMISSION_DENIED).when(mService).checkPermission(anyString(),
    692                 anyInt(), anyInt());
    693 
    694         // Set the recents component and ensure that the following calls do not fail
    695         mRecentTasks.setIsCallerRecentsOverride(TestRecentTasks.GRANT);
    696         testRecentTasksApis(true /* expectNoSecurityException */);
    697         testGetTasksApis(true /* expectNoSecurityException */);
    698     }
    699 
    700     private void testRecentTasksApis(boolean expectCallable) {
    701         assertSecurityException(expectCallable, () -> mService.removeStack(INVALID_STACK_ID));
    702         assertSecurityException(expectCallable,
    703                 () -> mService.removeStacksInWindowingModes(new int[] {WINDOWING_MODE_UNDEFINED}));
    704         assertSecurityException(expectCallable,
    705                 () -> mService.removeStacksWithActivityTypes(new int[] {ACTIVITY_TYPE_UNDEFINED}));
    706         assertSecurityException(expectCallable, () -> mService.removeTask(0));
    707         assertSecurityException(expectCallable,
    708                 () -> mService.setTaskWindowingMode(0, WINDOWING_MODE_UNDEFINED, true));
    709         assertSecurityException(expectCallable,
    710                 () -> mService.moveTaskToStack(0, INVALID_STACK_ID, true));
    711         assertSecurityException(expectCallable,
    712                 () -> mService.setTaskWindowingModeSplitScreenPrimary(0,
    713                         SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT, true, true, new Rect(), true));
    714         assertSecurityException(expectCallable, () -> mService.dismissSplitScreenMode(true));
    715         assertSecurityException(expectCallable, () -> mService.dismissPip(true, 0));
    716         assertSecurityException(expectCallable,
    717                 () -> mService.moveTopActivityToPinnedStack(INVALID_STACK_ID, new Rect()));
    718         assertSecurityException(expectCallable,
    719                 () -> mService.resizeStack(INVALID_STACK_ID, new Rect(), true, true, true, 0));
    720         assertSecurityException(expectCallable,
    721                 () -> mService.resizeDockedStack(new Rect(), new Rect(), new Rect(), new Rect(),
    722                         new Rect()));
    723         assertSecurityException(expectCallable,
    724                 () -> mService.resizePinnedStack(new Rect(), new Rect()));
    725         assertSecurityException(expectCallable, () -> mService.getAllStackInfos());
    726         assertSecurityException(expectCallable,
    727                 () -> mService.getStackInfo(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_UNDEFINED));
    728         assertSecurityException(expectCallable, () -> {
    729             try {
    730                 mService.getFocusedStackInfo();
    731             } catch (RemoteException e) {
    732                 // Ignore
    733             }
    734         });
    735         assertSecurityException(expectCallable,
    736                 () -> mService.moveTasksToFullscreenStack(INVALID_STACK_ID, true));
    737         assertSecurityException(expectCallable,
    738                 () -> mService.startActivityFromRecents(0, new Bundle()));
    739         assertSecurityException(expectCallable,
    740                 () -> mService.getTaskSnapshot(0, true));
    741         assertSecurityException(expectCallable, () -> {
    742             try {
    743                 mService.registerTaskStackListener(null);
    744             } catch (RemoteException e) {
    745                 // Ignore
    746             }
    747         });
    748         assertSecurityException(expectCallable, () -> {
    749             try {
    750                 mService.unregisterTaskStackListener(null);
    751             } catch (RemoteException e) {
    752                 // Ignore
    753             }
    754         });
    755         assertSecurityException(expectCallable, () -> mService.getTaskDescription(0));
    756         assertSecurityException(expectCallable, () -> mService.cancelTaskWindowTransition(0));
    757         assertSecurityException(expectCallable, () -> mService.startRecentsActivity(null, null,
    758                 null));
    759         assertSecurityException(expectCallable, () -> mService.cancelRecentsAnimation(true));
    760         assertSecurityException(expectCallable, () -> mService.stopAppSwitches());
    761         assertSecurityException(expectCallable, () -> mService.resumeAppSwitches());
    762     }
    763 
    764     private void testGetTasksApis(boolean expectCallable) {
    765         mService.getRecentTasks(MAX_VALUE, 0, TEST_USER_0_ID);
    766         mService.getTasks(MAX_VALUE);
    767         if (expectCallable) {
    768             assertTrue(mRecentTasks.lastAllowed);
    769             assertTrue(mRunningTasks.lastAllowed);
    770         } else {
    771             assertFalse(mRecentTasks.lastAllowed);
    772             assertFalse(mRunningTasks.lastAllowed);
    773         }
    774     }
    775 
    776     private TaskBuilder createTaskBuilder(String className) {
    777         return createTaskBuilder(mContext.getPackageName(), className);
    778     }
    779 
    780     private TaskBuilder createTaskBuilder(String packageName, String className) {
    781         return new TaskBuilder(mService.mStackSupervisor)
    782                 .setComponent(new ComponentName(packageName, className))
    783                 .setStack(mStack)
    784                 .setTaskId(LAST_TASK_ID++)
    785                 .setUserId(TEST_USER_0_ID);
    786     }
    787 
    788     private TaskRecord createDocumentTask(String className) {
    789         return createDocumentTask(className, 0);
    790     }
    791 
    792     private TaskRecord createDocumentTask(String className, int flags) {
    793         TaskRecord task = createTaskBuilder(className)
    794                 .setFlags(FLAG_ACTIVITY_NEW_DOCUMENT | flags)
    795                 .build();
    796         task.affinity = null;
    797         task.maxRecents = ActivityManager.getMaxAppRecentsLimitStatic();
    798         return task;
    799     }
    800 
    801     private boolean arrayContainsUser(int[] userIds, int targetUserId) {
    802         Arrays.sort(userIds);
    803         return Arrays.binarySearch(userIds, targetUserId) >= 0;
    804     }
    805 
    806     private void assertNoTasksTrimmed() {
    807         assertTrimmed();
    808     }
    809 
    810     private void assertTrimmed(TaskRecord... tasks) {
    811         final ArrayList<TaskRecord> trimmed = mCallbacksRecorder.trimmed;
    812         final ArrayList<TaskRecord> removed = mCallbacksRecorder.removed;
    813         assertTrue("Expected " + tasks.length + " trimmed tasks, got " + trimmed.size(),
    814                 trimmed.size() == tasks.length);
    815         assertTrue("Expected " + tasks.length + " removed tasks, got " + removed.size(),
    816                 removed.size() == tasks.length);
    817         for (TaskRecord task : tasks) {
    818             assertTrue("Expected trimmed task: " + task, trimmed.contains(task));
    819             assertTrue("Expected removed task: " + task, removed.contains(task));
    820         }
    821     }
    822 
    823     private void assertSecurityException(boolean expectCallable, Runnable runnable) {
    824         boolean noSecurityException = true;
    825         try {
    826             runnable.run();
    827         } catch (SecurityException se) {
    828             noSecurityException = false;
    829         } catch (Exception e) {
    830             // We only care about SecurityExceptions, fall through here
    831             e.printStackTrace();
    832         }
    833         if (noSecurityException != expectCallable) {
    834             fail("Expected callable: " + expectCallable + " but got no security exception: "
    835                     + noSecurityException);
    836         }
    837     }
    838 
    839     private class MyTestActivityManagerService extends TestActivityManagerService {
    840         MyTestActivityManagerService(Context context) {
    841             super(context);
    842         }
    843 
    844         @Override
    845         protected ActivityStackSupervisor createTestSupervisor() {
    846             return new MyTestActivityStackSupervisor(this, mHandlerThread.getLooper());
    847         }
    848 
    849         @Override
    850         protected RecentTasks createRecentTasks() {
    851             return new TestRecentTasks(this, mTaskPersister, new TestUserController(this));
    852         }
    853 
    854         @Override
    855         public boolean isUserRunning(int userId, int flags) {
    856             return true;
    857         }
    858     }
    859 
    860     private class MyTestActivityStackSupervisor extends TestActivityStackSupervisor {
    861         public MyTestActivityStackSupervisor(ActivityManagerService service, Looper looper) {
    862             super(service, looper);
    863         }
    864 
    865         @Override
    866         public void initialize() {
    867             super.initialize();
    868             mDisplay = new TestActivityDisplay(this, DEFAULT_DISPLAY);
    869             mOtherDisplay = new TestActivityDisplay(this, DEFAULT_DISPLAY);
    870             attachDisplay(mOtherDisplay);
    871             attachDisplay(mDisplay);
    872         }
    873 
    874         @Override
    875         RunningTasks createRunningTasks() {
    876             mRunningTasks = new TestRunningTasks();
    877             return mRunningTasks;
    878         }
    879 
    880         void setHomeStack(ActivityStack stack) {
    881             mHomeStack = stack;
    882         }
    883     }
    884 
    885     private class MyTestActivityStack extends TestActivityStack {
    886         private ActivityDisplay mDisplay = null;
    887 
    888         MyTestActivityStack(ActivityDisplay display, ActivityStackSupervisor supervisor) {
    889             super(display, LAST_STACK_ID++, supervisor, WINDOWING_MODE_FULLSCREEN,
    890                     ACTIVITY_TYPE_STANDARD, true);
    891             mDisplay = display;
    892         }
    893 
    894         @Override
    895         ActivityDisplay getDisplay() {
    896             if (mDisplay != null) {
    897                 return mDisplay;
    898             }
    899             return super.getDisplay();
    900         }
    901     }
    902 
    903     private static class CallbacksRecorder implements Callbacks {
    904         ArrayList<TaskRecord> added = new ArrayList<>();
    905         ArrayList<TaskRecord> trimmed = new ArrayList<>();
    906         ArrayList<TaskRecord> removed = new ArrayList<>();
    907 
    908         void clear() {
    909             added.clear();
    910             trimmed.clear();
    911             removed.clear();
    912         }
    913 
    914         @Override
    915         public void onRecentTaskAdded(TaskRecord task) {
    916             added.add(task);
    917         }
    918 
    919         @Override
    920         public void onRecentTaskRemoved(TaskRecord task, boolean wasTrimmed) {
    921             if (wasTrimmed) {
    922                 trimmed.add(task);
    923             }
    924             removed.add(task);
    925         }
    926     }
    927 
    928     private static class TestTaskPersister extends TaskPersister {
    929         SparseBooleanArray userTaskIdsOverride;
    930         ArrayList<TaskRecord> userTasksOverride;
    931 
    932         TestTaskPersister(File workingDir) {
    933             super(workingDir);
    934         }
    935 
    936         @Override
    937         SparseBooleanArray loadPersistedTaskIdsForUser(int userId) {
    938             if (userTaskIdsOverride != null) {
    939                 return userTaskIdsOverride;
    940             }
    941             return super.loadPersistedTaskIdsForUser(userId);
    942         }
    943 
    944         @Override
    945         List<TaskRecord> restoreTasksForUserLocked(int userId, SparseBooleanArray preaddedTasks) {
    946             if (userTasksOverride != null) {
    947                 return userTasksOverride;
    948             }
    949             return super.restoreTasksForUserLocked(userId, preaddedTasks);
    950         }
    951     }
    952 
    953     private static class TestRecentTasks extends RecentTasks {
    954         static final int GRANT = 0;
    955         static final int DENY = 1;
    956         static final int DENY_THROW_SECURITY_EXCEPTION = 2;
    957 
    958         private boolean mOverrideIsCallerRecents;
    959         private boolean mIsTrimmableOverride;
    960         private int mIsCallerRecentsPolicy;
    961 
    962         boolean lastAllowed;
    963 
    964         TestRecentTasks(ActivityManagerService service, TaskPersister taskPersister,
    965                 UserController userController) {
    966             super(service, taskPersister, userController);
    967         }
    968 
    969         @Override
    970         boolean isCallerRecents(int callingUid) {
    971             if (mOverrideIsCallerRecents) {
    972                 switch (mIsCallerRecentsPolicy) {
    973                     case GRANT:
    974                         return true;
    975                     case DENY:
    976                         return false;
    977                     case DENY_THROW_SECURITY_EXCEPTION:
    978                         throw new SecurityException();
    979                 }
    980             }
    981             return super.isCallerRecents(callingUid);
    982         }
    983 
    984         void setIsCallerRecentsOverride(int policy) {
    985             mOverrideIsCallerRecents = true;
    986             mIsCallerRecentsPolicy = policy;
    987         }
    988 
    989         /**
    990          * To simplify the setup for some tests, the caller can request that we only rely on the
    991          * visible range test to determine what is trimmable. In this case, we don't try to
    992          * use the stack order to determine additionally if the task is trimmable when it is not
    993          * in the visible range.
    994          */
    995         void setOnlyTestVisibleRange() {
    996             mIsTrimmableOverride = true;
    997         }
    998 
    999         @Override
   1000         ParceledListSlice<RecentTaskInfo> getRecentTasks(int maxNum, int flags,
   1001                 boolean getTasksAllowed,
   1002                 boolean getDetailedTasks, int userId, int callingUid) {
   1003             lastAllowed = getTasksAllowed;
   1004             return super.getRecentTasks(maxNum, flags, getTasksAllowed, getDetailedTasks, userId,
   1005                     callingUid);
   1006         }
   1007 
   1008         @Override
   1009         protected boolean isTrimmable(TaskRecord task) {
   1010             return mIsTrimmableOverride || super.isTrimmable(task);
   1011         }
   1012     }
   1013 
   1014     private static class TestRunningTasks extends RunningTasks {
   1015         boolean lastAllowed;
   1016 
   1017         @Override
   1018         void getTasks(int maxNum, List<RunningTaskInfo> list, int ignoreActivityType,
   1019                 int ignoreWindowingMode, SparseArray<ActivityDisplay> activityDisplays,
   1020                 int callingUid, boolean allowed) {
   1021             lastAllowed = allowed;
   1022             super.getTasks(maxNum, list, ignoreActivityType, ignoreWindowingMode, activityDisplays,
   1023                     callingUid, allowed);
   1024         }
   1025     }
   1026 }
   1027