blob: b1cd93168c17d21942b1fa068a56724a5a9d43dc [file] [log] [blame]
Winson Chung1dbc8112017-09-28 18:05:31 -07001/*
Wale Ogunwale59507092018-10-29 09:00:30 -07002 * Copyright (C) 2018 The Android Open Source Project
Winson Chung1dbc8112017-09-28 18:05:31 -07003 *
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
Wale Ogunwale59507092018-10-29 09:00:30 -070014 * limitations under the License
Winson Chung1dbc8112017-09-28 18:05:31 -070015 */
16
Wale Ogunwale59507092018-10-29 09:00:30 -070017package com.android.server.wm;
Winson Chung1dbc8112017-09-28 18:05:31 -070018
Winson Chungd2730072019-02-22 14:10:27 -080019import static android.app.ActivityManager.RECENT_WITH_EXCLUDED;
Wale Ogunwale65ebd952018-04-25 15:41:44 -070020import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
Winson Chung6c9dcad2018-03-13 16:57:55 -070021import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
Winson Chung1dbc8112017-09-28 18:05:31 -070022import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
Winson Chung3f0e59a2017-10-25 10:19:05 -070023import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
Winson Chung1dbc8112017-09-28 18:05:31 -070024import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
Winson Chung27f81882018-04-19 14:45:03 -070025import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
Winson Chung3f0e59a2017-10-25 10:19:05 -070026import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
Winson Chungd6aa3db2017-10-05 17:18:43 -070027import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
Winson Chung079221f2017-12-13 17:43:34 -080028import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
Winson Chung1dbc8112017-09-28 18:05:31 -070029import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
Winson Chung6c9dcad2018-03-13 16:57:55 -070030import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
Winson Chung0ec2a352017-10-26 11:38:30 -070031import static android.view.Display.DEFAULT_DISPLAY;
Winson Chung1dbc8112017-09-28 18:05:31 -070032
Winson Chungd2730072019-02-22 14:10:27 -080033import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
Tadashi G. Takaokaa7a66952018-11-16 15:04:21 +090034import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
Wale Ogunwale8a1860a2019-06-05 08:57:19 -070035import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
Tadashi G. Takaokaa7a66952018-11-16 15:04:21 +090036
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +090037import static com.google.common.truth.Truth.assertThat;
38import static com.google.common.truth.Truth.assertWithMessage;
39
Riddle Hsu090ac6f2018-10-31 12:55:29 +080040import static org.junit.Assert.assertEquals;
Winson Chung1dbc8112017-09-28 18:05:31 -070041import static org.junit.Assert.assertFalse;
42import static org.junit.Assert.assertTrue;
Winson Chung3f0e59a2017-10-25 10:19:05 -070043import static org.junit.Assert.fail;
44import static org.mockito.ArgumentMatchers.anyInt;
45import static org.mockito.ArgumentMatchers.anyString;
Vinit Nayak3e737492019-07-24 13:03:15 -070046import static org.mockito.Mockito.times;
47import static org.mockito.Mockito.verify;
Winson Chung1dbc8112017-09-28 18:05:31 -070048
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +090049import static java.lang.Integer.MAX_VALUE;
50
Winson Chung3f0e59a2017-10-25 10:19:05 -070051import android.app.ActivityManager.RecentTaskInfo;
52import android.app.ActivityManager.RunningTaskInfo;
Wale Ogunwale65ebd952018-04-25 15:41:44 -070053import android.app.ActivityTaskManager;
Winson Chunge6439102018-07-30 15:48:01 -070054import android.app.WindowConfiguration;
Winson Chung1dbc8112017-09-28 18:05:31 -070055import android.content.ComponentName;
Winson Chung3f0e59a2017-10-25 10:19:05 -070056import android.content.pm.PackageManager;
57import android.content.pm.ParceledListSlice;
Winson Chungd6aa3db2017-10-05 17:18:43 -070058import android.content.pm.UserInfo;
Winson Chungc790b6c2018-03-19 11:23:25 -070059import android.content.res.Configuration;
Winson Chung3f0e59a2017-10-25 10:19:05 -070060import android.graphics.Rect;
61import android.os.Bundle;
Winson Chung3f0e59a2017-10-25 10:19:05 -070062import android.os.RemoteException;
Winson Chungd6aa3db2017-10-05 17:18:43 -070063import android.os.SystemClock;
Riddle Hsub81f9312019-11-18 17:04:51 +080064import android.os.UserManager;
Winson Chung1dbc8112017-09-28 18:05:31 -070065import android.platform.test.annotations.Presubmit;
Nicholas Sauer3f9249f2019-09-10 20:23:41 -070066import android.util.ArraySet;
Winson Chung1dbc8112017-09-28 18:05:31 -070067import android.util.SparseBooleanArray;
68
Brett Chabota26eda92018-07-23 13:08:30 -070069import androidx.test.filters.MediumTest;
Brett Chabota26eda92018-07-23 13:08:30 -070070
Wale Ogunwale59507092018-10-29 09:00:30 -070071import com.android.server.wm.RecentTasks.Callbacks;
Winson Chung1dbc8112017-09-28 18:05:31 -070072
Winson Chung1dbc8112017-09-28 18:05:31 -070073import org.junit.Before;
74import org.junit.Test;
Riddle Hsuc8ed2ae2019-10-03 00:08:03 +080075import org.junit.runner.RunWith;
John Reck3d294e72018-09-21 20:26:48 +000076
Winson Chung1dbc8112017-09-28 18:05:31 -070077import java.io.File;
78import java.util.ArrayList;
Winson Chung3f0e59a2017-10-25 10:19:05 -070079import java.util.HashSet;
Winson Chung1dbc8112017-09-28 18:05:31 -070080import java.util.List;
Winson Chung0ec2a352017-10-26 11:38:30 -070081import java.util.Random;
Winson Chung3f0e59a2017-10-25 10:19:05 -070082import java.util.Set;
Winson Chung1dbc8112017-09-28 18:05:31 -070083
84/**
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +090085 * Build/Install/Run:
86 * atest WmTests:RecentTasksTest
Winson Chung1dbc8112017-09-28 18:05:31 -070087 */
88@MediumTest
89@Presubmit
Riddle Hsuc8ed2ae2019-10-03 00:08:03 +080090@RunWith(WindowTestRunner.class)
Winson Chung1dbc8112017-09-28 18:05:31 -070091public class RecentTasksTest extends ActivityTestsBase {
92 private static final int TEST_USER_0_ID = 0;
93 private static final int TEST_USER_1_ID = 10;
Winson Chungd6aa3db2017-10-05 17:18:43 -070094 private static final int TEST_QUIET_USER_ID = 20;
95 private static final UserInfo DEFAULT_USER_INFO = new UserInfo();
Riddle Hsub81f9312019-11-18 17:04:51 +080096 private static final UserInfo QUIET_PROFILE_USER_INFO = new UserInfo(TEST_QUIET_USER_ID,
97 "quiet_profile", null /* iconPath */, UserInfo.FLAG_QUIET_MODE,
98 UserManager.USER_TYPE_PROFILE_MANAGED);
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +090099 private static final int INVALID_STACK_ID = 999;
Winson Chung1dbc8112017-09-28 18:05:31 -0700100
Winson Chung0ec2a352017-10-26 11:38:30 -0700101 private ActivityDisplay mDisplay;
Winson Chung1dbc8112017-09-28 18:05:31 -0700102 private ActivityStack mStack;
103 private TestTaskPersister mTaskPersister;
Winson Chung0ec2a352017-10-26 11:38:30 -0700104 private TestRecentTasks mRecentTasks;
105 private TestRunningTasks mRunningTasks;
Winson Chung1dbc8112017-09-28 18:05:31 -0700106
Louis Changcdec0802019-11-11 11:45:07 +0800107 private ArrayList<Task> mTasks;
108 private ArrayList<Task> mSameDocumentTasks;
Winson Chung1dbc8112017-09-28 18:05:31 -0700109
110 private CallbacksRecorder mCallbacksRecorder;
111
112 @Before
Winson Chung1dbc8112017-09-28 18:05:31 -0700113 public void setUp() throws Exception {
Winson Chung3f0e59a2017-10-25 10:19:05 -0700114 mTaskPersister = new TestTaskPersister(mContext.getFilesDir());
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700115 mDisplay = mRootActivityContainer.getActivityDisplay(DEFAULT_DISPLAY);
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700116
117 // Set the recent tasks we should use for testing in this class.
118 mRecentTasks = new TestRecentTasks(mService, mTaskPersister);
119 spyOn(mRecentTasks);
120 mService.setRecentTasks(mRecentTasks);
Winson Chung3f0e59a2017-10-25 10:19:05 -0700121 mRecentTasks.loadParametersFromResources(mContext.getResources());
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700122
123 // Set the running tasks we should use for testing in this class.
124 mRunningTasks = new TestRunningTasks();
125 mService.mStackSupervisor.setRunningTasks(mRunningTasks);
126
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700127 mStack = mDisplay.createStack(
Winson Chung1dbc8112017-09-28 18:05:31 -0700128 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
Winson Chung1dbc8112017-09-28 18:05:31 -0700129 mCallbacksRecorder = new CallbacksRecorder();
130 mRecentTasks.registerCallback(mCallbacksRecorder);
131
Winson Chungc790b6c2018-03-19 11:23:25 -0700132 mTasks = new ArrayList<>();
Winson Chung0ec2a352017-10-26 11:38:30 -0700133 mTasks.add(createTaskBuilder(".Task1").build());
134 mTasks.add(createTaskBuilder(".Task2").build());
135 mTasks.add(createTaskBuilder(".Task3").build());
136 mTasks.add(createTaskBuilder(".Task4").build());
137 mTasks.add(createTaskBuilder(".Task5").build());
Winson Chung1dbc8112017-09-28 18:05:31 -0700138
Winson Chungc790b6c2018-03-19 11:23:25 -0700139 mSameDocumentTasks = new ArrayList<>();
Winson Chung0ec2a352017-10-26 11:38:30 -0700140 mSameDocumentTasks.add(createDocumentTask(".DocumentTask1"));
141 mSameDocumentTasks.add(createDocumentTask(".DocumentTask1"));
Winson Chung1dbc8112017-09-28 18:05:31 -0700142 }
143
144 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900145 public void testCallbacks() {
Winson Chung1dbc8112017-09-28 18:05:31 -0700146 // Add some tasks
147 mRecentTasks.add(mTasks.get(0));
148 mRecentTasks.add(mTasks.get(1));
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900149 assertThat(mCallbacksRecorder.mAdded).contains(mTasks.get(0));
150 assertThat(mCallbacksRecorder.mAdded).contains(mTasks.get(1));
151 assertThat(mCallbacksRecorder.mTrimmed).isEmpty();
152 assertThat(mCallbacksRecorder.mRemoved).isEmpty();
Winson Chung1dbc8112017-09-28 18:05:31 -0700153 mCallbacksRecorder.clear();
154
155 // Remove some tasks
156 mRecentTasks.remove(mTasks.get(0));
157 mRecentTasks.remove(mTasks.get(1));
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900158 assertThat(mCallbacksRecorder.mAdded).isEmpty();
159 assertThat(mCallbacksRecorder.mTrimmed).isEmpty();
160 assertThat(mCallbacksRecorder.mRemoved).contains(mTasks.get(0));
161 assertThat(mCallbacksRecorder.mRemoved).contains(mTasks.get(1));
Winson Chung1dbc8112017-09-28 18:05:31 -0700162 mCallbacksRecorder.clear();
163
Winson Chung1dbc8112017-09-28 18:05:31 -0700164 // Remove the callback, ensure we don't get any calls
165 mRecentTasks.unregisterCallback(mCallbacksRecorder);
166 mRecentTasks.add(mTasks.get(0));
167 mRecentTasks.remove(mTasks.get(0));
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900168 assertThat(mCallbacksRecorder.mAdded).isEmpty();
169 assertThat(mCallbacksRecorder.mTrimmed).isEmpty();
170 assertThat(mCallbacksRecorder.mRemoved).isEmpty();
Winson Chung1dbc8112017-09-28 18:05:31 -0700171 }
172
173 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900174 public void testAddTasksNoMultiple_expectNoTrim() {
Winson Chung079221f2017-12-13 17:43:34 -0800175 // Add same non-multiple-task document tasks will remove the task (to re-add it) but not
176 // trim it
Louis Changcdec0802019-11-11 11:45:07 +0800177 Task documentTask1 = createDocumentTask(".DocumentTask1");
178 Task documentTask2 = createDocumentTask(".DocumentTask1");
Winson Chung079221f2017-12-13 17:43:34 -0800179 mRecentTasks.add(documentTask1);
180 mRecentTasks.add(documentTask2);
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900181 assertThat(mCallbacksRecorder.mAdded).contains(documentTask1);
182 assertThat(mCallbacksRecorder.mAdded).contains(documentTask2);
183 assertThat(mCallbacksRecorder.mTrimmed).isEmpty();
184 assertThat(mCallbacksRecorder.mRemoved).contains(documentTask1);
Winson Chung079221f2017-12-13 17:43:34 -0800185 }
186
187 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900188 public void testAddTasksMaxTaskRecents_expectNoTrim() {
Winson Chung079221f2017-12-13 17:43:34 -0800189 // Add a task hitting max-recents for that app will remove the task (to add the next one)
190 // but not trim it
Louis Changcdec0802019-11-11 11:45:07 +0800191 Task documentTask1 = createDocumentTask(".DocumentTask1");
192 Task documentTask2 = createDocumentTask(".DocumentTask1");
Winson Chung079221f2017-12-13 17:43:34 -0800193 documentTask1.maxRecents = 1;
194 documentTask2.maxRecents = 1;
195 mRecentTasks.add(documentTask1);
196 mRecentTasks.add(documentTask2);
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900197 assertThat(mCallbacksRecorder.mAdded).contains(documentTask1);
198 assertThat(mCallbacksRecorder.mAdded).contains(documentTask2);
199 assertThat(mCallbacksRecorder.mTrimmed).isEmpty();
200 assertThat(mCallbacksRecorder.mRemoved).contains(documentTask1);
Winson Chung079221f2017-12-13 17:43:34 -0800201 }
202
203 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900204 public void testAddTasksSameTask_expectNoTrim() {
Winson Chung079221f2017-12-13 17:43:34 -0800205 // Add a task that is already in the task list does not trigger any callbacks, it just
206 // moves in the list
Louis Changcdec0802019-11-11 11:45:07 +0800207 Task documentTask1 = createDocumentTask(".DocumentTask1");
Winson Chung079221f2017-12-13 17:43:34 -0800208 mRecentTasks.add(documentTask1);
209 mRecentTasks.add(documentTask1);
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900210 assertThat(mCallbacksRecorder.mAdded).hasSize(1);
211 assertThat(mCallbacksRecorder.mAdded).contains(documentTask1);
212 assertThat(mCallbacksRecorder.mTrimmed).isEmpty();
213 assertThat(mCallbacksRecorder.mRemoved).isEmpty();
Winson Chung079221f2017-12-13 17:43:34 -0800214 }
215
216 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900217 public void testAddTasksMultipleDocumentTasks_expectNoTrim() {
Winson Chung079221f2017-12-13 17:43:34 -0800218 // Add same multiple-task document tasks does not trim the first tasks
Louis Changcdec0802019-11-11 11:45:07 +0800219 Task documentTask1 = createDocumentTask(".DocumentTask1",
Winson Chung079221f2017-12-13 17:43:34 -0800220 FLAG_ACTIVITY_MULTIPLE_TASK);
Louis Changcdec0802019-11-11 11:45:07 +0800221 Task documentTask2 = createDocumentTask(".DocumentTask1",
Winson Chung079221f2017-12-13 17:43:34 -0800222 FLAG_ACTIVITY_MULTIPLE_TASK);
223 mRecentTasks.add(documentTask1);
224 mRecentTasks.add(documentTask2);
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900225 assertThat(mCallbacksRecorder.mAdded).hasSize(2);
226 assertThat(mCallbacksRecorder.mAdded).contains(documentTask1);
227 assertThat(mCallbacksRecorder.mAdded).contains(documentTask2);
228 assertThat(mCallbacksRecorder.mTrimmed).isEmpty();
229 assertThat(mCallbacksRecorder.mRemoved).isEmpty();
Winson Chung079221f2017-12-13 17:43:34 -0800230 }
231
232 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900233 public void testAddTasksMultipleTasks_expectRemovedNoTrim() {
Winson Chung6c9dcad2018-03-13 16:57:55 -0700234 // Add multiple same-affinity non-document tasks, ensure that it removes the other task,
235 // but that it does not trim it
Louis Changcdec0802019-11-11 11:45:07 +0800236 Task task1 = createTaskBuilder(".Task1")
Winson Chung6c9dcad2018-03-13 16:57:55 -0700237 .setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK)
238 .build();
Louis Changcdec0802019-11-11 11:45:07 +0800239 Task task2 = createTaskBuilder(".Task1")
Winson Chung6c9dcad2018-03-13 16:57:55 -0700240 .setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK)
241 .build();
242 mRecentTasks.add(task1);
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900243 assertThat(mCallbacksRecorder.mAdded).hasSize(1);
244 assertThat(mCallbacksRecorder.mAdded).contains(task1);
245 assertThat(mCallbacksRecorder.mTrimmed).isEmpty();
246 assertThat(mCallbacksRecorder.mRemoved).isEmpty();
Winson Chung6c9dcad2018-03-13 16:57:55 -0700247 mCallbacksRecorder.clear();
248 mRecentTasks.add(task2);
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900249 assertThat(mCallbacksRecorder.mAdded).hasSize(1);
250 assertThat(mCallbacksRecorder.mAdded).contains(task2);
251 assertThat(mCallbacksRecorder.mTrimmed).isEmpty();
252 assertThat(mCallbacksRecorder.mRemoved).hasSize(1);
253 assertThat(mCallbacksRecorder.mRemoved).contains(task1);
Winson Chung6c9dcad2018-03-13 16:57:55 -0700254 }
255
256 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900257 public void testAddTasksDifferentStacks_expectNoRemove() {
Winson Chung6c9dcad2018-03-13 16:57:55 -0700258 // Adding the same task with different activity types should not trigger removal of the
259 // other task
Louis Changcdec0802019-11-11 11:45:07 +0800260 Task task1 = createTaskBuilder(".Task1")
Winson Chung6c9dcad2018-03-13 16:57:55 -0700261 .setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK)
Riddle Hsuc8ed2ae2019-10-03 00:08:03 +0800262 .setStack(mDisplay.getHomeStack()).build();
Louis Changcdec0802019-11-11 11:45:07 +0800263 Task task2 = createTaskBuilder(".Task1")
Winson Chung6c9dcad2018-03-13 16:57:55 -0700264 .setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK)
265 .setStack(mStack).build();
266 mRecentTasks.add(task1);
267 mRecentTasks.add(task2);
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900268 assertThat(mCallbacksRecorder.mAdded).hasSize(2);
269 assertThat(mCallbacksRecorder.mAdded).contains(task1);
270 assertThat(mCallbacksRecorder.mAdded).contains(task2);
271 assertThat(mCallbacksRecorder.mTrimmed).isEmpty();
272 assertThat(mCallbacksRecorder.mRemoved).isEmpty();
Winson Chungc790b6c2018-03-19 11:23:25 -0700273 }
Winson Chung6c9dcad2018-03-13 16:57:55 -0700274
Winson Chungc790b6c2018-03-19 11:23:25 -0700275 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900276 public void testAddTaskCompatibleActivityType_expectRemove() {
Winson Chung27f81882018-04-19 14:45:03 -0700277 // Test with undefined activity type since the type is not persisted by the task persister
278 // and we want to ensure that a new task will match a restored task
Louis Changcdec0802019-11-11 11:45:07 +0800279 Task task1 = createTaskBuilder(".Task1")
Winson Chungc790b6c2018-03-19 11:23:25 -0700280 .setFlags(FLAG_ACTIVITY_NEW_TASK)
281 .setStack(mStack)
282 .build();
Winson Chunge6439102018-07-30 15:48:01 -0700283 setTaskActivityType(task1, ACTIVITY_TYPE_UNDEFINED);
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900284 assertThat(task1.getActivityType()).isEqualTo(ACTIVITY_TYPE_UNDEFINED);
Winson Chungc790b6c2018-03-19 11:23:25 -0700285 mRecentTasks.add(task1);
286 mCallbacksRecorder.clear();
287
Louis Changcdec0802019-11-11 11:45:07 +0800288 Task task2 = createTaskBuilder(".Task1")
Winson Chungc790b6c2018-03-19 11:23:25 -0700289 .setFlags(FLAG_ACTIVITY_NEW_TASK)
290 .setStack(mStack)
291 .build();
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900292 assertEquals(ACTIVITY_TYPE_STANDARD, task2.getActivityType());
Winson Chungc790b6c2018-03-19 11:23:25 -0700293 mRecentTasks.add(task2);
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900294 assertThat(mCallbacksRecorder.mAdded).hasSize(1);
295 assertThat(mCallbacksRecorder.mAdded).contains(task2);
296 assertThat(mCallbacksRecorder.mTrimmed).isEmpty();
297 assertThat(mCallbacksRecorder.mRemoved).hasSize(1);
298 assertThat(mCallbacksRecorder.mRemoved).contains(task1);
Winson Chung6c9dcad2018-03-13 16:57:55 -0700299 }
300
301 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900302 public void testAddTaskCompatibleActivityTypeDifferentUser_expectNoRemove() {
Louis Changcdec0802019-11-11 11:45:07 +0800303 Task task1 = createTaskBuilder(".Task1")
Winson Chungb7667272018-04-06 10:18:39 -0700304 .setFlags(FLAG_ACTIVITY_NEW_TASK)
305 .setStack(mStack)
306 .setUserId(TEST_USER_0_ID)
307 .build();
Winson Chunge6439102018-07-30 15:48:01 -0700308 setTaskActivityType(task1, ACTIVITY_TYPE_UNDEFINED);
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900309 assertEquals(ACTIVITY_TYPE_UNDEFINED, task1.getActivityType());
Winson Chungb7667272018-04-06 10:18:39 -0700310 mRecentTasks.add(task1);
311 mCallbacksRecorder.clear();
312
Louis Changcdec0802019-11-11 11:45:07 +0800313 Task task2 = createTaskBuilder(".Task1")
Winson Chungb7667272018-04-06 10:18:39 -0700314 .setFlags(FLAG_ACTIVITY_NEW_TASK)
315 .setStack(mStack)
316 .setUserId(TEST_USER_1_ID)
317 .build();
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900318 assertEquals(ACTIVITY_TYPE_STANDARD, task2.getActivityType());
Winson Chungb7667272018-04-06 10:18:39 -0700319 mRecentTasks.add(task2);
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900320 assertThat(mCallbacksRecorder.mAdded).hasSize(1);
321 assertThat(mCallbacksRecorder.mAdded).contains(task2);
322 assertThat(mCallbacksRecorder.mTrimmed).isEmpty();
323 assertThat(mCallbacksRecorder.mRemoved).isEmpty();
Winson Chungb7667272018-04-06 10:18:39 -0700324 }
325
326 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900327 public void testAddTaskCompatibleWindowingMode_expectRemove() {
Louis Changcdec0802019-11-11 11:45:07 +0800328 Task task1 = createTaskBuilder(".Task1")
Winson Chung27f81882018-04-19 14:45:03 -0700329 .setFlags(FLAG_ACTIVITY_NEW_TASK)
330 .setStack(mStack)
331 .build();
Winson Chunge6439102018-07-30 15:48:01 -0700332 setTaskWindowingMode(task1, WINDOWING_MODE_UNDEFINED);
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900333 assertEquals(WINDOWING_MODE_UNDEFINED, task1.getWindowingMode());
Winson Chung27f81882018-04-19 14:45:03 -0700334 mRecentTasks.add(task1);
335 mCallbacksRecorder.clear();
336
Louis Changcdec0802019-11-11 11:45:07 +0800337 Task task2 = createTaskBuilder(".Task1")
Winson Chung27f81882018-04-19 14:45:03 -0700338 .setFlags(FLAG_ACTIVITY_NEW_TASK)
339 .setStack(mStack)
340 .build();
Winson Chunge6439102018-07-30 15:48:01 -0700341 setTaskWindowingMode(task2, WINDOWING_MODE_FULLSCREEN);
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900342 assertEquals(WINDOWING_MODE_FULLSCREEN, task2.getWindowingMode());
Winson Chung27f81882018-04-19 14:45:03 -0700343 mRecentTasks.add(task2);
344
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900345 assertThat(mCallbacksRecorder.mAdded).hasSize(1);
346 assertThat(mCallbacksRecorder.mAdded).contains(task2);
347 assertThat(mCallbacksRecorder.mTrimmed).isEmpty();
348 assertThat(mCallbacksRecorder.mRemoved).hasSize(1);
349 assertThat(mCallbacksRecorder.mRemoved).contains(task1);
Winson Chung27f81882018-04-19 14:45:03 -0700350 }
351
352 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900353 public void testAddTaskIncompatibleWindowingMode_expectNoRemove() {
Louis Changcdec0802019-11-11 11:45:07 +0800354 Task task1 = createTaskBuilder(".Task1")
Winson Chung27f81882018-04-19 14:45:03 -0700355 .setFlags(FLAG_ACTIVITY_NEW_TASK)
356 .setStack(mStack)
357 .build();
Winson Chunge6439102018-07-30 15:48:01 -0700358 setTaskWindowingMode(task1, WINDOWING_MODE_FULLSCREEN);
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900359 assertEquals(WINDOWING_MODE_FULLSCREEN, task1.getWindowingMode());
Winson Chung27f81882018-04-19 14:45:03 -0700360 mRecentTasks.add(task1);
361
Louis Changcdec0802019-11-11 11:45:07 +0800362 Task task2 = createTaskBuilder(".Task1")
Winson Chung27f81882018-04-19 14:45:03 -0700363 .setFlags(FLAG_ACTIVITY_NEW_TASK)
364 .setStack(mStack)
365 .build();
Winson Chunge6439102018-07-30 15:48:01 -0700366 setTaskWindowingMode(task2, WINDOWING_MODE_PINNED);
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900367 assertEquals(WINDOWING_MODE_PINNED, task2.getWindowingMode());
Winson Chung27f81882018-04-19 14:45:03 -0700368 mRecentTasks.add(task2);
369
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900370 assertThat(mCallbacksRecorder.mAdded).hasSize(2);
371 assertThat(mCallbacksRecorder.mAdded).contains(task1);
372 assertThat(mCallbacksRecorder.mAdded).contains(task2);
373 assertThat(mCallbacksRecorder.mTrimmed).isEmpty();
374 assertThat(mCallbacksRecorder.mRemoved).isEmpty();
Winson Chung27f81882018-04-19 14:45:03 -0700375 }
376
377 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900378 public void testUsersTasks() {
Winson Chung0ec2a352017-10-26 11:38:30 -0700379 mRecentTasks.setOnlyTestVisibleRange();
380
Winson Chung1dbc8112017-09-28 18:05:31 -0700381 // Setup some tasks for the users
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900382 mTaskPersister.mUserTaskIdsOverride = new SparseBooleanArray();
383 mTaskPersister.mUserTaskIdsOverride.put(1, true);
384 mTaskPersister.mUserTaskIdsOverride.put(2, true);
385 mTaskPersister.mUserTasksOverride = new ArrayList<>();
386 mTaskPersister.mUserTasksOverride.add(createTaskBuilder(".UserTask1").build());
387 mTaskPersister.mUserTasksOverride.add(createTaskBuilder(".UserTask2").build());
Winson Chung1dbc8112017-09-28 18:05:31 -0700388
389 // Assert no user tasks are initially loaded
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900390 assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).hasLength(0);
Winson Chung1dbc8112017-09-28 18:05:31 -0700391
392 // Load user 0 tasks
393 mRecentTasks.loadUserRecentsLocked(TEST_USER_0_ID);
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900394 assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).asList().contains(TEST_USER_0_ID);
Winson Chung1dbc8112017-09-28 18:05:31 -0700395 assertTrue(mRecentTasks.containsTaskId(1, TEST_USER_0_ID));
396 assertTrue(mRecentTasks.containsTaskId(2, TEST_USER_0_ID));
397
398 // Load user 1 tasks
399 mRecentTasks.loadUserRecentsLocked(TEST_USER_1_ID);
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900400 assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).asList().contains(TEST_USER_0_ID);
401 assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).asList().contains(TEST_USER_1_ID);
Winson Chung1dbc8112017-09-28 18:05:31 -0700402 assertTrue(mRecentTasks.containsTaskId(1, TEST_USER_0_ID));
403 assertTrue(mRecentTasks.containsTaskId(2, TEST_USER_0_ID));
404 assertTrue(mRecentTasks.containsTaskId(1, TEST_USER_1_ID));
405 assertTrue(mRecentTasks.containsTaskId(2, TEST_USER_1_ID));
406
407 // Unload user 1 tasks
408 mRecentTasks.unloadUserDataFromMemoryLocked(TEST_USER_1_ID);
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900409 assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).asList().contains(TEST_USER_0_ID);
410 assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).asList()
411 .doesNotContain(TEST_USER_1_ID);
Winson Chung1dbc8112017-09-28 18:05:31 -0700412 assertTrue(mRecentTasks.containsTaskId(1, TEST_USER_0_ID));
413 assertTrue(mRecentTasks.containsTaskId(2, TEST_USER_0_ID));
414
415 // Unload user 0 tasks
416 mRecentTasks.unloadUserDataFromMemoryLocked(TEST_USER_0_ID);
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900417 assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).asList()
418 .doesNotContain(TEST_USER_0_ID);
419 assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).asList()
420 .doesNotContain(TEST_USER_1_ID);
Winson Chung1dbc8112017-09-28 18:05:31 -0700421 }
422
Winson Chungd6aa3db2017-10-05 17:18:43 -0700423 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900424 public void testOrderedIteration() {
Winson Chung0ec2a352017-10-26 11:38:30 -0700425 mRecentTasks.setOnlyTestVisibleRange();
Louis Changcdec0802019-11-11 11:45:07 +0800426 Task task1 = createTaskBuilder(".Task1").build();
Winson Chung0ec2a352017-10-26 11:38:30 -0700427 task1.lastActiveTime = new Random().nextInt();
Louis Changcdec0802019-11-11 11:45:07 +0800428 Task task2 = createTaskBuilder(".Task1").build();
Winson Chung0ec2a352017-10-26 11:38:30 -0700429 task2.lastActiveTime = new Random().nextInt();
Louis Changcdec0802019-11-11 11:45:07 +0800430 Task task3 = createTaskBuilder(".Task1").build();
Winson Chung0ec2a352017-10-26 11:38:30 -0700431 task3.lastActiveTime = new Random().nextInt();
Louis Changcdec0802019-11-11 11:45:07 +0800432 Task task4 = createTaskBuilder(".Task1").build();
Winson Chung0ec2a352017-10-26 11:38:30 -0700433 task4.lastActiveTime = new Random().nextInt();
434 mRecentTasks.add(task1);
435 mRecentTasks.add(task2);
436 mRecentTasks.add(task3);
437 mRecentTasks.add(task4);
438
Riddle Hsuc8ed2ae2019-10-03 00:08:03 +0800439 long prevLastActiveTime = 0;
Louis Changcdec0802019-11-11 11:45:07 +0800440 final ArrayList<Task> tasks = mRecentTasks.getRawTasks();
Winson Chungd6aa3db2017-10-05 17:18:43 -0700441 for (int i = 0; i < tasks.size(); i++) {
Louis Changcdec0802019-11-11 11:45:07 +0800442 final Task task = tasks.get(i);
Riddle Hsuc8ed2ae2019-10-03 00:08:03 +0800443 assertThat(prevLastActiveTime).isLessThan(task.lastActiveTime);
444 prevLastActiveTime = task.lastActiveTime;
Winson Chungd6aa3db2017-10-05 17:18:43 -0700445 }
446 }
447
448 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900449 public void testTrimToGlobalMaxNumRecents() {
Winson Chung0ec2a352017-10-26 11:38:30 -0700450 mRecentTasks.setOnlyTestVisibleRange();
451
Winson Chungd6aa3db2017-10-05 17:18:43 -0700452 // Limit the global maximum number of recent tasks to a fixed size
453 mRecentTasks.setGlobalMaxNumTasks(2 /* globalMaxNumTasks */);
454
455 // Add N+1 tasks
456 mRecentTasks.add(mTasks.get(0));
457 mRecentTasks.add(mTasks.get(1));
458 mRecentTasks.add(mTasks.get(2));
459
460 // Ensure that the last task was trimmed as an inactive task
461 assertTrimmed(mTasks.get(0));
462 }
463
464 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900465 public void testTrimQuietProfileTasks() {
Winson Chung0ec2a352017-10-26 11:38:30 -0700466 mRecentTasks.setOnlyTestVisibleRange();
Louis Changcdec0802019-11-11 11:45:07 +0800467 Task qt1 = createTaskBuilder(".QuietTask1").setUserId(TEST_QUIET_USER_ID).build();
468 Task qt2 = createTaskBuilder(".QuietTask2").setUserId(TEST_QUIET_USER_ID).build();
Winson Chungd6aa3db2017-10-05 17:18:43 -0700469 mRecentTasks.add(qt1);
470 mRecentTasks.add(qt2);
471
472 mRecentTasks.add(mTasks.get(0));
473 mRecentTasks.add(mTasks.get(1));
474
475 // Ensure that the quiet user's tasks was trimmed once the new tasks were added
476 assertTrimmed(qt1, qt2);
477 }
478
479 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900480 public void testSessionDuration() {
Winson Chung0ec2a352017-10-26 11:38:30 -0700481 mRecentTasks.setOnlyTestVisibleRange();
Winson Chungd6aa3db2017-10-05 17:18:43 -0700482 mRecentTasks.setParameters(-1 /* min */, -1 /* max */, 50 /* ms */);
483
Louis Changcdec0802019-11-11 11:45:07 +0800484 Task t1 = createTaskBuilder(".Task1").build();
Winson Chungd6aa3db2017-10-05 17:18:43 -0700485 t1.touchActiveTime();
486 mRecentTasks.add(t1);
487
488 // Force a small sleep just beyond the session duration
489 SystemClock.sleep(75);
490
Louis Changcdec0802019-11-11 11:45:07 +0800491 Task t2 = createTaskBuilder(".Task2").build();
Winson Chungd6aa3db2017-10-05 17:18:43 -0700492 t2.touchActiveTime();
493 mRecentTasks.add(t2);
494
495 // Assert that the old task has been removed due to being out of the active session
496 assertTrimmed(t1);
497 }
498
499 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900500 public void testVisibleTasks_excludedFromRecents() {
Winson Chung0ec2a352017-10-26 11:38:30 -0700501 mRecentTasks.setOnlyTestVisibleRange();
Winson Chungd6aa3db2017-10-05 17:18:43 -0700502 mRecentTasks.setParameters(-1 /* min */, 4 /* max */, -1 /* ms */);
503
Louis Changcdec0802019-11-11 11:45:07 +0800504 Task excludedTask1 = createTaskBuilder(".ExcludedTask1")
Winson Chung0ec2a352017-10-26 11:38:30 -0700505 .setFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
506 .build();
Louis Changcdec0802019-11-11 11:45:07 +0800507 Task excludedTask2 = createTaskBuilder(".ExcludedTask2")
Winson Chung0ec2a352017-10-26 11:38:30 -0700508 .setFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
509 .build();
Winson Chungd6aa3db2017-10-05 17:18:43 -0700510
511 mRecentTasks.add(excludedTask1);
512 mRecentTasks.add(mTasks.get(0));
513 mRecentTasks.add(mTasks.get(1));
514 mRecentTasks.add(mTasks.get(2));
515 mRecentTasks.add(excludedTask2);
516
517 // The last excluded task should be trimmed, while the first-most excluded task should not
518 assertTrimmed(excludedTask1);
519 }
520
521 @Test
Winson Chungd2730072019-02-22 14:10:27 -0800522 public void testVisibleTasks_excludedFromRecents_firstTaskNotVisible() {
523 // Create some set of tasks, some of which are visible and some are not
Louis Changcdec0802019-11-11 11:45:07 +0800524 Task homeTask = setTaskActivityType(
Winson Chungd2730072019-02-22 14:10:27 -0800525 createTaskBuilder("com.android.pkg1", ".HomeTask").build(),
526 ACTIVITY_TYPE_HOME);
527 homeTask.mUserSetupComplete = true;
528 mRecentTasks.add(homeTask);
Louis Changcdec0802019-11-11 11:45:07 +0800529 Task excludedTask1 = createTaskBuilder(".ExcludedTask1")
Winson Chungd2730072019-02-22 14:10:27 -0800530 .setFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
531 .build();
532 excludedTask1.mUserSetupComplete = true;
533 mRecentTasks.add(excludedTask1);
534
535 // Expect that the first visible excluded-from-recents task is visible
536 assertGetRecentTasksOrder(0 /* flags */, excludedTask1);
537 }
538
539 @Test
540 public void testVisibleTasks_excludedFromRecents_withExcluded() {
541 // Create some set of tasks, some of which are visible and some are not
Louis Changcdec0802019-11-11 11:45:07 +0800542 Task t1 = createTaskBuilder("com.android.pkg1", ".Task1").build();
Winson Chungd2730072019-02-22 14:10:27 -0800543 t1.mUserSetupComplete = true;
544 mRecentTasks.add(t1);
Louis Changcdec0802019-11-11 11:45:07 +0800545 Task homeTask = setTaskActivityType(
Winson Chungd2730072019-02-22 14:10:27 -0800546 createTaskBuilder("com.android.pkg1", ".HomeTask").build(),
547 ACTIVITY_TYPE_HOME);
548 homeTask.mUserSetupComplete = true;
549 mRecentTasks.add(homeTask);
Louis Changcdec0802019-11-11 11:45:07 +0800550 Task excludedTask1 = createTaskBuilder(".ExcludedTask1")
Winson Chungd2730072019-02-22 14:10:27 -0800551 .setFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
552 .build();
553 excludedTask1.mUserSetupComplete = true;
554 mRecentTasks.add(excludedTask1);
Louis Changcdec0802019-11-11 11:45:07 +0800555 Task excludedTask2 = createTaskBuilder(".ExcludedTask2")
Winson Chungd2730072019-02-22 14:10:27 -0800556 .setFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
557 .build();
558 excludedTask2.mUserSetupComplete = true;
559 mRecentTasks.add(excludedTask2);
Louis Changcdec0802019-11-11 11:45:07 +0800560 Task t2 = createTaskBuilder("com.android.pkg2", ".Task1").build();
Winson Chungd2730072019-02-22 14:10:27 -0800561 t2.mUserSetupComplete = true;
562 mRecentTasks.add(t2);
563
564 assertGetRecentTasksOrder(RECENT_WITH_EXCLUDED, t2, excludedTask2, excludedTask1, t1);
565 }
566
567 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900568 public void testVisibleTasks_minNum() {
Winson Chung0ec2a352017-10-26 11:38:30 -0700569 mRecentTasks.setOnlyTestVisibleRange();
Winson Chungd6aa3db2017-10-05 17:18:43 -0700570 mRecentTasks.setParameters(5 /* min */, -1 /* max */, 25 /* ms */);
571
572 for (int i = 0; i < 4; i++) {
Louis Changcdec0802019-11-11 11:45:07 +0800573 final Task task = mTasks.get(i);
Winson Chungd6aa3db2017-10-05 17:18:43 -0700574 task.touchActiveTime();
575 mRecentTasks.add(task);
576 }
577
578 // Force a small sleep just beyond the session duration
579 SystemClock.sleep(50);
580
581 // Add a new task to trigger tasks to be trimmed
582 mRecentTasks.add(mTasks.get(4));
583
584 // Ensure that there are a minimum number of tasks regardless of session length
Winson Chung0ec2a352017-10-26 11:38:30 -0700585 assertNoTasksTrimmed();
Winson Chungd6aa3db2017-10-05 17:18:43 -0700586 }
587
588 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900589 public void testVisibleTasks_maxNum() {
Winson Chung0ec2a352017-10-26 11:38:30 -0700590 mRecentTasks.setOnlyTestVisibleRange();
Winson Chungd6aa3db2017-10-05 17:18:43 -0700591 mRecentTasks.setParameters(-1 /* min */, 3 /* max */, -1 /* ms */);
592
593 for (int i = 0; i < 5; i++) {
Louis Changcdec0802019-11-11 11:45:07 +0800594 final Task task = mTasks.get(i);
Winson Chungd6aa3db2017-10-05 17:18:43 -0700595 task.touchActiveTime();
596 mRecentTasks.add(task);
597 }
598
599 // Ensure that only the last number of max tasks are kept
600 assertTrimmed(mTasks.get(0), mTasks.get(1));
601 }
602
Mark Renouf2aaf4cd2019-02-19 17:24:43 -0500603 /**
604 * Tests that tasks on singleTaskDisplay are not visible and not trimmed/removed.
605 */
606 @Test
607 public void testVisibleTasks_singleTaskDisplay() {
608 mRecentTasks.setOnlyTestVisibleRange();
609 mRecentTasks.setParameters(-1 /* min */, 3 /* max */, -1 /* ms */);
610
Riddle Hsuc8ed2ae2019-10-03 00:08:03 +0800611 final ActivityDisplay singleTaskDisplay =
612 addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP);
613 singleTaskDisplay.setDisplayToSingleTaskInstance();
614 ActivityStack singleTaskStack = singleTaskDisplay.createStack(
Mark Renouf2aaf4cd2019-02-19 17:24:43 -0500615 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
616
Louis Changcdec0802019-11-11 11:45:07 +0800617 Task excludedTask1 = createTaskBuilder(".ExcludedTask1")
Mark Renouf2aaf4cd2019-02-19 17:24:43 -0500618 .setStack(singleTaskStack)
619 .build();
620
621 assertFalse("Tasks on singleTaskDisplay should not be visible recents",
622 mRecentTasks.isVisibleRecentTask(excludedTask1));
623
624 mRecentTasks.add(excludedTask1);
625
626 // Add N+1 visible tasks.
627 mRecentTasks.add(mTasks.get(0));
628 mRecentTasks.add(mTasks.get(1));
629 mRecentTasks.add(mTasks.get(2));
630 mRecentTasks.add(mTasks.get(3));
631
632 // excludedTask is not trimmed.
633 assertTrimmed(mTasks.get(0));
634
Winson Chung42fa21f2019-04-02 16:23:46 -0700635 mRecentTasks.removeAllVisibleTasks(TEST_USER_0_ID);
Mark Renouf2aaf4cd2019-02-19 17:24:43 -0500636
637 // Only visible tasks removed.
638 assertTrimmed(mTasks.get(0), mTasks.get(1), mTasks.get(2), mTasks.get(3));
639 }
640
Winson Chung3f0e59a2017-10-25 10:19:05 -0700641 @Test
Winson Chungc5fe7ff2019-02-19 14:49:25 -0800642 public void testFreezeTaskListOrder_reorderExistingTask() {
643 // Add some tasks
644 mRecentTasks.add(mTasks.get(0));
645 mRecentTasks.add(mTasks.get(1));
646 mRecentTasks.add(mTasks.get(2));
647 mRecentTasks.add(mTasks.get(3));
648 mRecentTasks.add(mTasks.get(4));
649 mCallbacksRecorder.clear();
650
651 // Freeze the list
652 mRecentTasks.setFreezeTaskListReordering();
653 assertTrue(mRecentTasks.isFreezeTaskListReorderingSet());
654
655 // Relaunch a few tasks
656 mRecentTasks.add(mTasks.get(3));
657 mRecentTasks.add(mTasks.get(2));
658
659 // Commit the task ordering with a specific task focused
660 mRecentTasks.resetFreezeTaskListReordering(mTasks.get(2));
661 assertFalse(mRecentTasks.isFreezeTaskListReorderingSet());
662
663 // Ensure that the order of the task list is the same as before, but with the focused task
664 // at the front
665 assertRecentTasksOrder(mTasks.get(2),
666 mTasks.get(4),
667 mTasks.get(3),
668 mTasks.get(1),
669 mTasks.get(0));
670
671 assertThat(mCallbacksRecorder.mAdded).isEmpty();
672 assertThat(mCallbacksRecorder.mTrimmed).isEmpty();
673 assertThat(mCallbacksRecorder.mRemoved).isEmpty();
674 }
675
676 @Test
677 public void testFreezeTaskListOrder_addRemoveTasks() {
678 // Add some tasks
679 mRecentTasks.add(mTasks.get(0));
680 mRecentTasks.add(mTasks.get(1));
681 mRecentTasks.add(mTasks.get(2));
682 mCallbacksRecorder.clear();
683
684 // Freeze the list
685 mRecentTasks.setFreezeTaskListReordering();
686 assertTrue(mRecentTasks.isFreezeTaskListReorderingSet());
687
688 // Add and remove some tasks
689 mRecentTasks.add(mTasks.get(3));
690 mRecentTasks.add(mTasks.get(4));
691 mRecentTasks.remove(mTasks.get(0));
692 mRecentTasks.remove(mTasks.get(1));
693
694 // Unfreeze the list
695 mRecentTasks.resetFreezeTaskListReordering(null);
696 assertFalse(mRecentTasks.isFreezeTaskListReorderingSet());
697
698 // Ensure that the order of the task list accounts for the added and removed tasks (added
699 // at the end)
700 assertRecentTasksOrder(mTasks.get(4),
701 mTasks.get(3),
702 mTasks.get(2));
703
704 assertThat(mCallbacksRecorder.mAdded).hasSize(2);
705 assertThat(mCallbacksRecorder.mAdded).contains(mTasks.get(3));
706 assertThat(mCallbacksRecorder.mAdded).contains(mTasks.get(4));
707 assertThat(mCallbacksRecorder.mRemoved).hasSize(2);
708 assertThat(mCallbacksRecorder.mRemoved).contains(mTasks.get(0));
709 assertThat(mCallbacksRecorder.mRemoved).contains(mTasks.get(1));
710 }
711
712 @Test
713 public void testFreezeTaskListOrder_timeout() {
714 // Add some tasks
715 mRecentTasks.add(mTasks.get(0));
716 mRecentTasks.add(mTasks.get(1));
717 mRecentTasks.add(mTasks.get(2));
718 mRecentTasks.add(mTasks.get(3));
719 mRecentTasks.add(mTasks.get(4));
720
721 // Freeze the list
Winson Chungc5fe7ff2019-02-19 14:49:25 -0800722 mRecentTasks.setFreezeTaskListReordering();
723 assertTrue(mRecentTasks.isFreezeTaskListReorderingSet());
724
725 // Relaunch a few tasks
726 mRecentTasks.add(mTasks.get(2));
727 mRecentTasks.add(mTasks.get(1));
728
Winson Chungc5fe7ff2019-02-19 14:49:25 -0800729 ActivityStack stack = mTasks.get(2).getStack();
730 stack.moveToFront("", mTasks.get(2));
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700731 doReturn(stack).when(mService.mRootActivityContainer).getTopDisplayFocusedStack();
Winson Chung1fe58e92019-04-10 14:18:06 -0700732
733 // Simulate the reset from the timeout
Winson Chungc5fe7ff2019-02-19 14:49:25 -0800734 mRecentTasks.resetFreezeTaskListReorderingOnTimeout();
735 assertFalse(mRecentTasks.isFreezeTaskListReorderingSet());
736
737 // Ensure that the order of the task list is the same as before, but with the focused task
738 // at the front
739 assertRecentTasksOrder(mTasks.get(2),
740 mTasks.get(4),
741 mTasks.get(3),
742 mTasks.get(1),
743 mTasks.get(0));
744 }
745
746 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900747 public void testBackStackTasks_expectNoTrim() {
Winson Chung0ec2a352017-10-26 11:38:30 -0700748 mRecentTasks.setParameters(-1 /* min */, 1 /* max */, -1 /* ms */);
749
Louis Changbd48dca2018-08-29 17:44:34 +0800750 final ActivityStack homeStack = mDisplay.getHomeStack();
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700751 final ActivityStack aboveHomeStack = mDisplay.createStack(
752 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
Winson Chung0ec2a352017-10-26 11:38:30 -0700753
754 // Add a number of tasks (beyond the max) but ensure that nothing is trimmed because all
755 // the tasks belong in stacks above the home stack
756 mRecentTasks.add(createTaskBuilder(".HomeTask1").setStack(homeStack).build());
757 mRecentTasks.add(createTaskBuilder(".Task1").setStack(aboveHomeStack).build());
758 mRecentTasks.add(createTaskBuilder(".Task2").setStack(aboveHomeStack).build());
759 mRecentTasks.add(createTaskBuilder(".Task3").setStack(aboveHomeStack).build());
760
761 assertNoTasksTrimmed();
762 }
763
764 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900765 public void testBehindHomeStackTasks_expectTaskTrimmed() {
Winson Chung0ec2a352017-10-26 11:38:30 -0700766 mRecentTasks.setParameters(-1 /* min */, 1 /* max */, -1 /* ms */);
767
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700768 final ActivityStack behindHomeStack = mDisplay.createStack(
769 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
Louis Changbd48dca2018-08-29 17:44:34 +0800770 final ActivityStack homeStack = mDisplay.getHomeStack();
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700771 final ActivityStack aboveHomeStack = mDisplay.createStack(
772 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
Winson Chung0ec2a352017-10-26 11:38:30 -0700773
774 // Add a number of tasks (beyond the max) but ensure that only the task in the stack behind
775 // the home stack is trimmed once a new task is added
Louis Changcdec0802019-11-11 11:45:07 +0800776 final Task behindHomeTask = createTaskBuilder(".Task1")
Winson Chung0ec2a352017-10-26 11:38:30 -0700777 .setStack(behindHomeStack)
778 .build();
779 mRecentTasks.add(behindHomeTask);
780 mRecentTasks.add(createTaskBuilder(".HomeTask1").setStack(homeStack).build());
781 mRecentTasks.add(createTaskBuilder(".Task2").setStack(aboveHomeStack).build());
782
783 assertTrimmed(behindHomeTask);
784 }
785
786 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900787 public void testOtherDisplayTasks_expectNoTrim() {
Winson Chung0ec2a352017-10-26 11:38:30 -0700788 mRecentTasks.setParameters(-1 /* min */, 1 /* max */, -1 /* ms */);
789
Louis Changbd48dca2018-08-29 17:44:34 +0800790 final ActivityStack homeStack = mDisplay.getHomeStack();
Riddle Hsuc8ed2ae2019-10-03 00:08:03 +0800791 final ActivityDisplay otherDisplay = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP);
792 final ActivityStack otherDisplayStack = otherDisplay.createStack(
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700793 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
Winson Chung0ec2a352017-10-26 11:38:30 -0700794
795 // Add a number of tasks (beyond the max) on each display, ensure that the tasks are not
796 // removed
797 mRecentTasks.add(createTaskBuilder(".HomeTask1").setStack(homeStack).build());
798 mRecentTasks.add(createTaskBuilder(".Task1").setStack(otherDisplayStack).build());
799 mRecentTasks.add(createTaskBuilder(".Task2").setStack(otherDisplayStack).build());
800 mRecentTasks.add(createTaskBuilder(".HomeTask2").setStack(homeStack).build());
801
802 assertNoTasksTrimmed();
803 }
804
805 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900806 public void testRemovePackageByName() {
Winson Chung99720d42018-04-09 11:28:46 -0700807 // Add a number of tasks with the same package name
808 mRecentTasks.add(createTaskBuilder("com.android.pkg1", ".Task1").build());
809 mRecentTasks.add(createTaskBuilder("com.android.pkg2", ".Task2").build());
810 mRecentTasks.add(createTaskBuilder("com.android.pkg3", ".Task3").build());
811 mRecentTasks.add(createTaskBuilder("com.android.pkg1", ".Task4").build());
812 mRecentTasks.removeTasksByPackageName("com.android.pkg1", TEST_USER_0_ID);
813
Louis Changcdec0802019-11-11 11:45:07 +0800814 final ArrayList<Task> tasks = mRecentTasks.getRawTasks();
Winson Chung99720d42018-04-09 11:28:46 -0700815 for (int i = 0; i < tasks.size(); i++) {
816 if (tasks.get(i).intent.getComponent().getPackageName().equals("com.android.pkg1")) {
817 fail("Expected com.android.pkg1 tasks to be removed");
818 }
819 }
820 }
821
822 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900823 public void testRemoveAllVisibleTasks() {
Winson Chunge6439102018-07-30 15:48:01 -0700824 mRecentTasks.setParameters(-1 /* min */, 3 /* max */, 100 /* ms */);
825
826 // Create some set of tasks, some of which are visible and some are not
Louis Changcdec0802019-11-11 11:45:07 +0800827 Task t1 = createTaskBuilder("com.android.pkg1", ".Task1").build();
Winson Chunge6439102018-07-30 15:48:01 -0700828 mRecentTasks.add(t1);
829 mRecentTasks.add(setTaskActivityType(
830 createTaskBuilder("com.android.pkg1", ".HomeTask").build(),
831 ACTIVITY_TYPE_HOME));
Louis Changcdec0802019-11-11 11:45:07 +0800832 Task t2 = createTaskBuilder("com.android.pkg2", ".Task2").build();
Winson Chunge6439102018-07-30 15:48:01 -0700833 mRecentTasks.add(t2);
834 mRecentTasks.add(setTaskWindowingMode(
835 createTaskBuilder("com.android.pkg1", ".PipTask").build(),
836 WINDOWING_MODE_PINNED));
Louis Changcdec0802019-11-11 11:45:07 +0800837 Task t3 = createTaskBuilder("com.android.pkg3", ".Task3").build();
Winson Chunge6439102018-07-30 15:48:01 -0700838 mRecentTasks.add(t3);
839
840 // Create some more tasks that are out of visible range, but are still visible
Louis Changcdec0802019-11-11 11:45:07 +0800841 Task t4 = createTaskBuilder("com.android.pkg3", ".Task4").build();
Winson Chunge6439102018-07-30 15:48:01 -0700842 mRecentTasks.add(t4);
Louis Changcdec0802019-11-11 11:45:07 +0800843 Task t5 = createTaskBuilder("com.android.pkg3", ".Task5").build();
Winson Chunge6439102018-07-30 15:48:01 -0700844 mRecentTasks.add(t5);
845
846 // Create some more tasks that are out of the active session range, but are still visible
Louis Changcdec0802019-11-11 11:45:07 +0800847 Task t6 = createTaskBuilder("com.android.pkg3", ".Task6").build();
Winson Chunge6439102018-07-30 15:48:01 -0700848 t6.lastActiveTime = SystemClock.elapsedRealtime() - 200;
849 mRecentTasks.add(t6);
Louis Changcdec0802019-11-11 11:45:07 +0800850 Task t7 = createTaskBuilder("com.android.pkg3", ".Task7").build();
Winson Chunge6439102018-07-30 15:48:01 -0700851 t7.lastActiveTime = SystemClock.elapsedRealtime() - 200;
852 mRecentTasks.add(t7);
853
854 // Remove all the visible tasks and ensure that they are removed
Winson Chung42fa21f2019-04-02 16:23:46 -0700855 mRecentTasks.removeAllVisibleTasks(TEST_USER_0_ID);
Winson Chunge6439102018-07-30 15:48:01 -0700856 assertTrimmed(t1, t2, t3, t4, t5, t6, t7);
857 }
858
859 @Test
Winson Chung42fa21f2019-04-02 16:23:46 -0700860 public void testRemoveAllVisibleTasksPerUser() {
861 mRecentTasks.setParameters(-1 /* min */, 3 /* max */, 100 /* ms */);
862
863 // Create a visible task per user
Louis Changcdec0802019-11-11 11:45:07 +0800864 Task t1 = createTaskBuilder(".Task1")
Winson Chung42fa21f2019-04-02 16:23:46 -0700865 .setUserId(TEST_USER_0_ID)
866 .build();
867 mRecentTasks.add(t1);
868
Louis Changcdec0802019-11-11 11:45:07 +0800869 Task t2 = createTaskBuilder(".Task2")
Winson Chungcdd4c3f2019-04-17 15:40:11 -0700870 .setUserId(TEST_QUIET_USER_ID)
Winson Chung42fa21f2019-04-02 16:23:46 -0700871 .build();
872 mRecentTasks.add(t2);
873
Louis Changcdec0802019-11-11 11:45:07 +0800874 Task t3 = createTaskBuilder(".Task3")
Winson Chungcdd4c3f2019-04-17 15:40:11 -0700875 .setUserId(TEST_USER_1_ID)
876 .build();
877 mRecentTasks.add(t3);
878
Winson Chung42fa21f2019-04-02 16:23:46 -0700879 // Remove all the visible tasks and ensure that they are removed
880 mRecentTasks.removeAllVisibleTasks(TEST_USER_0_ID);
Winson Chungcdd4c3f2019-04-17 15:40:11 -0700881 assertTrimmed(t1, t2);
Winson Chung42fa21f2019-04-02 16:23:46 -0700882 }
883
884 @Test
Riddle Hsu090ac6f2018-10-31 12:55:29 +0800885 public void testNotRestoreRecentTaskApis() {
Louis Changcdec0802019-11-11 11:45:07 +0800886 final Task task = createTaskBuilder(".Task").build();
Wale Ogunwale4e79a1c2019-10-05 20:52:40 -0700887 final int taskId = task.mTaskId;
Riddle Hsu090ac6f2018-10-31 12:55:29 +0800888 mRecentTasks.add(task);
889 // Only keep the task in RecentTasks.
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200890 task.removeIfPossible();
Wale Ogunwalebebd8cd2019-10-28 15:53:31 -0700891 mStack.removeIfPossible();
Riddle Hsu090ac6f2018-10-31 12:55:29 +0800892
893 // The following APIs should not restore task from recents to the active list.
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700894 assertNotRestoreTask(() -> mService.setFocusedTask(taskId));
895 assertNotRestoreTask(() -> mService.startSystemLockTaskMode(taskId));
896 assertNotRestoreTask(() -> mService.cancelTaskWindowTransition(taskId));
Riddle Hsu090ac6f2018-10-31 12:55:29 +0800897 assertNotRestoreTask(
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700898 () -> mService.resizeTask(taskId, null /* bounds */, 0 /* resizeMode */));
Riddle Hsu090ac6f2018-10-31 12:55:29 +0800899 assertNotRestoreTask(
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700900 () -> mService.setTaskWindowingMode(taskId, WINDOWING_MODE_FULLSCREEN,
Riddle Hsu090ac6f2018-10-31 12:55:29 +0800901 false/* toTop */));
902 assertNotRestoreTask(
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700903 () -> mService.setTaskWindowingModeSplitScreenPrimary(taskId,
Riddle Hsu090ac6f2018-10-31 12:55:29 +0800904 SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT,
905 false /* toTop */, false /* animate */, null /* initialBounds */,
906 true /* showRecents */));
907 }
908
Vinit Nayak3e737492019-07-24 13:03:15 -0700909 @Test
910 public void addTask_callsTaskNotificationController() {
Louis Changcdec0802019-11-11 11:45:07 +0800911 final Task task = createTaskBuilder(".Task").build();
Vinit Nayak3e737492019-07-24 13:03:15 -0700912
913 mRecentTasks.add(task);
914 mRecentTasks.remove(task);
915
916 TaskChangeNotificationController controller =
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700917 mService.getTaskChangeNotificationController();
Vinit Nayak3e737492019-07-24 13:03:15 -0700918 verify(controller, times(2)).notifyTaskListUpdated();
919 }
920
921 @Test
922 public void removeTask_callsTaskNotificationController() {
Louis Changcdec0802019-11-11 11:45:07 +0800923 final Task task = createTaskBuilder(".Task").build();
Vinit Nayak3e737492019-07-24 13:03:15 -0700924
925 mRecentTasks.add(task);
926 mRecentTasks.remove(task);
927
928 // 2 calls - Once for add and once for remove
929 TaskChangeNotificationController controller =
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700930 mService.getTaskChangeNotificationController();
Vinit Nayak3e737492019-07-24 13:03:15 -0700931 verify(controller, times(2)).notifyTaskListUpdated();
932 }
933
934 @Test
935 public void removeALlVisibleTask_callsTaskNotificationController_twice() {
Louis Changcdec0802019-11-11 11:45:07 +0800936 final Task task1 = createTaskBuilder(".Task").build();
937 final Task task2 = createTaskBuilder(".Task2").build();
Vinit Nayak3e737492019-07-24 13:03:15 -0700938
939 mRecentTasks.add(task1);
940 mRecentTasks.add(task2);
941 mRecentTasks.removeAllVisibleTasks(TEST_USER_0_ID);
942
943 // 4 calls - Twice for add and twice for remove
944 TaskChangeNotificationController controller =
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700945 mService.getTaskChangeNotificationController();
Vinit Nayak3e737492019-07-24 13:03:15 -0700946 verify(controller, times(4)).notifyTaskListUpdated();
947 }
948
Winson Chungc5fe7ff2019-02-19 14:49:25 -0800949 /**
Winson Chungd2730072019-02-22 14:10:27 -0800950 * Ensures that the raw recent tasks list is in the provided order. Note that the expected tasks
Winson Chungc5fe7ff2019-02-19 14:49:25 -0800951 * should be ordered from least to most recent.
952 */
Louis Changcdec0802019-11-11 11:45:07 +0800953 private void assertRecentTasksOrder(Task... expectedTasks) {
954 ArrayList<Task> tasks = mRecentTasks.getRawTasks();
Winson Chungc5fe7ff2019-02-19 14:49:25 -0800955 assertTrue(expectedTasks.length == tasks.size());
956 for (int i = 0; i < tasks.size(); i++) {
957 assertTrue(expectedTasks[i] == tasks.get(i));
958 }
959 }
960
Winson Chungd2730072019-02-22 14:10:27 -0800961 /**
962 * Ensures that the recent tasks list is in the provided order. Note that the expected tasks
963 * should be ordered from least to most recent.
964 */
Louis Changcdec0802019-11-11 11:45:07 +0800965 private void assertGetRecentTasksOrder(int getRecentTaskFlags, Task... expectedTasks) {
Winson Chungd2730072019-02-22 14:10:27 -0800966 doNothing().when(mRecentTasks).loadUserRecentsLocked(anyInt());
967 doReturn(true).when(mRecentTasks).isUserRunning(anyInt(), anyInt());
968 List<RecentTaskInfo> infos = mRecentTasks.getRecentTasks(MAX_VALUE, getRecentTaskFlags,
969 true /* getTasksAllowed */, false /* getDetailedTasks */,
970 TEST_USER_0_ID, 0).getList();
971 assertTrue(expectedTasks.length == infos.size());
972 for (int i = 0; i < infos.size(); i++) {
Wale Ogunwale4e79a1c2019-10-05 20:52:40 -0700973 assertTrue(expectedTasks[i].mTaskId == infos.get(i).taskId);
Winson Chungd2730072019-02-22 14:10:27 -0800974 }
975 }
976
Riddle Hsu090ac6f2018-10-31 12:55:29 +0800977 private void assertNotRestoreTask(Runnable action) {
978 // Verify stack count doesn't change because task with fullscreen mode and standard type
979 // would have its own stack.
Louis Chang2453d062019-11-19 22:30:48 +0800980 final int originalStackCount = mDisplay.getStackCount();
Riddle Hsu090ac6f2018-10-31 12:55:29 +0800981 action.run();
Louis Chang2453d062019-11-19 22:30:48 +0800982 assertEquals(originalStackCount, mDisplay.getStackCount());
Riddle Hsu090ac6f2018-10-31 12:55:29 +0800983 }
984
985 @Test
Winson Chung3f0e59a2017-10-25 10:19:05 -0700986 public void testNotRecentsComponent_denyApiAccess() throws Exception {
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700987 doReturn(PackageManager.PERMISSION_DENIED).when(mService)
Wale Ogunwalea6191b42018-05-09 07:41:32 -0700988 .checkGetTasksPermission(anyString(), anyInt(), anyInt());
Winson Chung3f0e59a2017-10-25 10:19:05 -0700989 // Expect the following methods to fail due to recents component not being set
Winson Chung0ec2a352017-10-26 11:38:30 -0700990 mRecentTasks.setIsCallerRecentsOverride(TestRecentTasks.DENY_THROW_SECURITY_EXCEPTION);
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900991 doTestRecentTasksApis(false /* expectNoSecurityException */);
Winson Chung3f0e59a2017-10-25 10:19:05 -0700992 // Don't throw for the following tests
Winson Chung0ec2a352017-10-26 11:38:30 -0700993 mRecentTasks.setIsCallerRecentsOverride(TestRecentTasks.DENY);
Winson Chung3f0e59a2017-10-25 10:19:05 -0700994 testGetTasksApis(false /* expectNoSecurityException */);
995 }
996
997 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900998 public void testRecentsComponent_allowApiAccessWithoutPermissions() {
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700999 doReturn(PackageManager.PERMISSION_DENIED).when(mService)
Wale Ogunwalea6191b42018-05-09 07:41:32 -07001000 .checkGetTasksPermission(anyString(), anyInt(), anyInt());
Winson Chung3f0e59a2017-10-25 10:19:05 -07001001 // Set the recents component and ensure that the following calls do not fail
Winson Chung0ec2a352017-10-26 11:38:30 -07001002 mRecentTasks.setIsCallerRecentsOverride(TestRecentTasks.GRANT);
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +09001003 doTestRecentTasksApis(true /* expectNoSecurityException */);
Winson Chung3f0e59a2017-10-25 10:19:05 -07001004 testGetTasksApis(true /* expectNoSecurityException */);
1005 }
1006
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +09001007 private void doTestRecentTasksApis(boolean expectCallable) {
Wale Ogunwale8a1860a2019-06-05 08:57:19 -07001008 assertSecurityException(expectCallable, () -> mService.removeStack(INVALID_STACK_ID));
Winson Chung3f0e59a2017-10-25 10:19:05 -07001009 assertSecurityException(expectCallable,
Wale Ogunwale8a1860a2019-06-05 08:57:19 -07001010 () -> mService.removeStacksInWindowingModes(
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +09001011 new int[]{WINDOWING_MODE_UNDEFINED}));
Winson Chung3f0e59a2017-10-25 10:19:05 -07001012 assertSecurityException(expectCallable,
Wale Ogunwale8a1860a2019-06-05 08:57:19 -07001013 () -> mService.removeStacksWithActivityTypes(
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +09001014 new int[]{ACTIVITY_TYPE_UNDEFINED}));
Wale Ogunwale8a1860a2019-06-05 08:57:19 -07001015 assertSecurityException(expectCallable, () -> mService.removeTask(0));
Winson Chung3f0e59a2017-10-25 10:19:05 -07001016 assertSecurityException(expectCallable,
Wale Ogunwale8a1860a2019-06-05 08:57:19 -07001017 () -> mService.setTaskWindowingMode(0, WINDOWING_MODE_UNDEFINED, true));
Winson Chung3f0e59a2017-10-25 10:19:05 -07001018 assertSecurityException(expectCallable,
Wale Ogunwale8a1860a2019-06-05 08:57:19 -07001019 () -> mService.moveTaskToStack(0, INVALID_STACK_ID, true));
Winson Chung3f0e59a2017-10-25 10:19:05 -07001020 assertSecurityException(expectCallable,
Wale Ogunwale8a1860a2019-06-05 08:57:19 -07001021 () -> mService.setTaskWindowingModeSplitScreenPrimary(0,
Wale Ogunwalec59b4f62017-11-30 11:05:43 -08001022 SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT, true, true, new Rect(), true));
Wale Ogunwale8a1860a2019-06-05 08:57:19 -07001023 assertSecurityException(expectCallable, () -> mService.dismissSplitScreenMode(true));
1024 assertSecurityException(expectCallable, () -> mService.dismissPip(true, 0));
Winson Chung3f0e59a2017-10-25 10:19:05 -07001025 assertSecurityException(expectCallable,
Wale Ogunwale8a1860a2019-06-05 08:57:19 -07001026 () -> mService.moveTopActivityToPinnedStack(INVALID_STACK_ID, new Rect()));
Winson Chung3f0e59a2017-10-25 10:19:05 -07001027 assertSecurityException(expectCallable,
Evan Roskydbe2ce52019-07-18 11:13:17 -07001028 () -> mService.animateResizePinnedStack(INVALID_STACK_ID, new Rect(), -1));
Winson Chung3f0e59a2017-10-25 10:19:05 -07001029 assertSecurityException(expectCallable,
Wale Ogunwale8a1860a2019-06-05 08:57:19 -07001030 () -> mService.resizeDockedStack(new Rect(), new Rect(), new Rect(), new Rect(),
Winson Chung3f0e59a2017-10-25 10:19:05 -07001031 new Rect()));
1032 assertSecurityException(expectCallable,
Wale Ogunwale8a1860a2019-06-05 08:57:19 -07001033 () -> mService.resizePinnedStack(new Rect(), new Rect()));
1034 assertSecurityException(expectCallable, () -> mService.getAllStackInfos());
Winson Chung3f0e59a2017-10-25 10:19:05 -07001035 assertSecurityException(expectCallable,
Wale Ogunwale8a1860a2019-06-05 08:57:19 -07001036 () -> mService.getStackInfo(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_UNDEFINED));
Winson Chung3f0e59a2017-10-25 10:19:05 -07001037 assertSecurityException(expectCallable, () -> {
1038 try {
Wale Ogunwale8a1860a2019-06-05 08:57:19 -07001039 mService.getFocusedStackInfo();
Winson Chung3f0e59a2017-10-25 10:19:05 -07001040 } catch (RemoteException e) {
1041 // Ignore
1042 }
1043 });
1044 assertSecurityException(expectCallable,
Wale Ogunwale8a1860a2019-06-05 08:57:19 -07001045 () -> mService.moveTasksToFullscreenStack(INVALID_STACK_ID, true));
Winson Chung3f0e59a2017-10-25 10:19:05 -07001046 assertSecurityException(expectCallable,
Wale Ogunwale8a1860a2019-06-05 08:57:19 -07001047 () -> mService.startActivityFromRecents(0, new Bundle()));
1048 assertSecurityException(expectCallable, () -> mService.getTaskSnapshot(0, true));
1049 assertSecurityException(expectCallable, () -> mService.registerTaskStackListener(null));
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +09001050 assertSecurityException(expectCallable,
Wale Ogunwale8a1860a2019-06-05 08:57:19 -07001051 () -> mService.unregisterTaskStackListener(null));
1052 assertSecurityException(expectCallable, () -> mService.getTaskDescription(0));
1053 assertSecurityException(expectCallable, () -> mService.cancelTaskWindowTransition(0));
1054 assertSecurityException(expectCallable, () -> mService.startRecentsActivity(null, null,
Winson Chunge2d72172018-01-25 17:46:20 +00001055 null));
Wale Ogunwale8a1860a2019-06-05 08:57:19 -07001056 assertSecurityException(expectCallable, () -> mService.cancelRecentsAnimation(true));
1057 assertSecurityException(expectCallable, () -> mService.stopAppSwitches());
1058 assertSecurityException(expectCallable, () -> mService.resumeAppSwitches());
Winson Chung3f0e59a2017-10-25 10:19:05 -07001059 }
1060
1061 private void testGetTasksApis(boolean expectCallable) {
Wale Ogunwale8a1860a2019-06-05 08:57:19 -07001062 mService.getRecentTasks(MAX_VALUE, 0, TEST_USER_0_ID);
1063 mService.getTasks(MAX_VALUE);
Winson Chung3f0e59a2017-10-25 10:19:05 -07001064 if (expectCallable) {
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +09001065 assertTrue(mRecentTasks.mLastAllowed);
1066 assertTrue(mRunningTasks.mLastAllowed);
Winson Chung3f0e59a2017-10-25 10:19:05 -07001067 } else {
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +09001068 assertFalse(mRecentTasks.mLastAllowed);
1069 assertFalse(mRunningTasks.mLastAllowed);
Winson Chung3f0e59a2017-10-25 10:19:05 -07001070 }
1071 }
1072
Winson Chung0ec2a352017-10-26 11:38:30 -07001073 private TaskBuilder createTaskBuilder(String className) {
Winson Chung99720d42018-04-09 11:28:46 -07001074 return createTaskBuilder(mContext.getPackageName(), className);
1075 }
1076
1077 private TaskBuilder createTaskBuilder(String packageName, String className) {
Wale Ogunwale8a1860a2019-06-05 08:57:19 -07001078 return new TaskBuilder(mService.mStackSupervisor)
Winson Chung99720d42018-04-09 11:28:46 -07001079 .setComponent(new ComponentName(packageName, className))
Winson Chung0ec2a352017-10-26 11:38:30 -07001080 .setStack(mStack)
Winson Chung0ec2a352017-10-26 11:38:30 -07001081 .setUserId(TEST_USER_0_ID);
Winson Chung1dbc8112017-09-28 18:05:31 -07001082 }
1083
Louis Changcdec0802019-11-11 11:45:07 +08001084 private Task createDocumentTask(String className) {
Winson Chung079221f2017-12-13 17:43:34 -08001085 return createDocumentTask(className, 0);
1086 }
1087
Louis Changcdec0802019-11-11 11:45:07 +08001088 private Task createDocumentTask(String className, int flags) {
1089 Task task = createTaskBuilder(className)
Winson Chung079221f2017-12-13 17:43:34 -08001090 .setFlags(FLAG_ACTIVITY_NEW_DOCUMENT | flags)
Winson Chung0ec2a352017-10-26 11:38:30 -07001091 .build();
1092 task.affinity = null;
Wale Ogunwale65ebd952018-04-25 15:41:44 -07001093 task.maxRecents = ActivityTaskManager.getMaxAppRecentsLimitStatic();
Winson Chung1dbc8112017-09-28 18:05:31 -07001094 return task;
1095 }
1096
Louis Changcdec0802019-11-11 11:45:07 +08001097 private Task setTaskActivityType(Task task,
Winson Chunge6439102018-07-30 15:48:01 -07001098 @WindowConfiguration.ActivityType int activityType) {
1099 Configuration config1 = new Configuration();
1100 config1.windowConfiguration.setActivityType(activityType);
1101 task.onConfigurationChanged(config1);
1102 return task;
1103 }
1104
Louis Changcdec0802019-11-11 11:45:07 +08001105 private Task setTaskWindowingMode(Task task,
Winson Chunge6439102018-07-30 15:48:01 -07001106 @WindowConfiguration.WindowingMode int windowingMode) {
1107 Configuration config1 = new Configuration();
1108 config1.windowConfiguration.setWindowingMode(windowingMode);
1109 task.onConfigurationChanged(config1);
1110 return task;
1111 }
1112
Winson Chung0ec2a352017-10-26 11:38:30 -07001113 private void assertNoTasksTrimmed() {
1114 assertTrimmed();
1115 }
1116
Louis Changcdec0802019-11-11 11:45:07 +08001117 private void assertTrimmed(Task... tasks) {
1118 final ArrayList<Task> trimmed = mCallbacksRecorder.mTrimmed;
1119 final ArrayList<Task> removed = mCallbacksRecorder.mRemoved;
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +09001120 assertWithMessage("Expected " + tasks.length + " trimmed tasks, got " + trimmed.size())
1121 .that(trimmed).hasSize(tasks.length);
1122 assertWithMessage("Expected " + tasks.length + " removed tasks, got " + removed.size())
1123 .that(removed).hasSize(tasks.length);
Louis Changcdec0802019-11-11 11:45:07 +08001124 for (Task task : tasks) {
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +09001125 assertWithMessage("Expected trimmed task: " + task).that(trimmed).contains(task);
1126 assertWithMessage("Expected removed task: " + task).that(removed).contains(task);
Winson Chungd6aa3db2017-10-05 17:18:43 -07001127 }
1128 }
1129
Winson Chung3f0e59a2017-10-25 10:19:05 -07001130 private void assertSecurityException(boolean expectCallable, Runnable runnable) {
1131 boolean noSecurityException = true;
1132 try {
1133 runnable.run();
1134 } catch (SecurityException se) {
1135 noSecurityException = false;
1136 } catch (Exception e) {
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +09001137 // We only care about SecurityExceptions, fall through here.
Winson Chung3f0e59a2017-10-25 10:19:05 -07001138 }
1139 if (noSecurityException != expectCallable) {
1140 fail("Expected callable: " + expectCallable + " but got no security exception: "
1141 + noSecurityException);
1142 }
1143 }
1144
Winson Chung1dbc8112017-09-28 18:05:31 -07001145 private static class CallbacksRecorder implements Callbacks {
Louis Changcdec0802019-11-11 11:45:07 +08001146 public final ArrayList<Task> mAdded = new ArrayList<>();
1147 public final ArrayList<Task> mTrimmed = new ArrayList<>();
1148 public final ArrayList<Task> mRemoved = new ArrayList<>();
Winson Chung1dbc8112017-09-28 18:05:31 -07001149
1150 void clear() {
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +09001151 mAdded.clear();
1152 mTrimmed.clear();
1153 mRemoved.clear();
Winson Chung1dbc8112017-09-28 18:05:31 -07001154 }
1155
1156 @Override
Louis Changcdec0802019-11-11 11:45:07 +08001157 public void onRecentTaskAdded(Task task) {
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +09001158 mAdded.add(task);
Winson Chung1dbc8112017-09-28 18:05:31 -07001159 }
1160
1161 @Override
Louis Changcdec0802019-11-11 11:45:07 +08001162 public void onRecentTaskRemoved(Task task, boolean wasTrimmed, boolean killProcess) {
Winson Chungd6aa3db2017-10-05 17:18:43 -07001163 if (wasTrimmed) {
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +09001164 mTrimmed.add(task);
Winson Chungd6aa3db2017-10-05 17:18:43 -07001165 }
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +09001166 mRemoved.add(task);
Winson Chung1dbc8112017-09-28 18:05:31 -07001167 }
1168 }
1169
1170 private static class TestTaskPersister extends TaskPersister {
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +09001171 public SparseBooleanArray mUserTaskIdsOverride;
Louis Changcdec0802019-11-11 11:45:07 +08001172 public ArrayList<Task> mUserTasksOverride;
Winson Chung1dbc8112017-09-28 18:05:31 -07001173
1174 TestTaskPersister(File workingDir) {
1175 super(workingDir);
1176 }
1177
1178 @Override
1179 SparseBooleanArray loadPersistedTaskIdsForUser(int userId) {
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +09001180 if (mUserTaskIdsOverride != null) {
1181 return mUserTaskIdsOverride;
Winson Chung1dbc8112017-09-28 18:05:31 -07001182 }
1183 return super.loadPersistedTaskIdsForUser(userId);
1184 }
1185
1186 @Override
Louis Changcdec0802019-11-11 11:45:07 +08001187 List<Task> restoreTasksForUserLocked(int userId, SparseBooleanArray preaddedTasks) {
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +09001188 if (mUserTasksOverride != null) {
1189 return mUserTasksOverride;
Winson Chung1dbc8112017-09-28 18:05:31 -07001190 }
1191 return super.restoreTasksForUserLocked(userId, preaddedTasks);
1192 }
1193 }
Winson Chung3f0e59a2017-10-25 10:19:05 -07001194
1195 private static class TestRecentTasks extends RecentTasks {
1196 static final int GRANT = 0;
1197 static final int DENY = 1;
1198 static final int DENY_THROW_SECURITY_EXCEPTION = 2;
1199
1200 private boolean mOverrideIsCallerRecents;
Winson Chung0ec2a352017-10-26 11:38:30 -07001201 private boolean mIsTrimmableOverride;
Winson Chung3f0e59a2017-10-25 10:19:05 -07001202 private int mIsCallerRecentsPolicy;
Winson Chung0ec2a352017-10-26 11:38:30 -07001203
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +09001204 public boolean mLastAllowed;
Winson Chung3f0e59a2017-10-25 10:19:05 -07001205
Wale Ogunwale86b74462018-07-02 08:42:43 -07001206 TestRecentTasks(ActivityTaskManagerService service, TaskPersister taskPersister) {
1207 super(service, taskPersister);
1208 }
1209
1210 @Override
1211 Set<Integer> getProfileIds(int userId) {
1212 Set<Integer> profileIds = new HashSet<>();
1213 profileIds.add(TEST_USER_0_ID);
1214 profileIds.add(TEST_QUIET_USER_ID);
1215 return profileIds;
1216 }
1217
1218 @Override
1219 UserInfo getUserInfo(int userId) {
1220 switch (userId) {
1221 case TEST_USER_0_ID:
1222 case TEST_USER_1_ID:
1223 return DEFAULT_USER_INFO;
1224 case TEST_QUIET_USER_ID:
Riddle Hsub81f9312019-11-18 17:04:51 +08001225 return QUIET_PROFILE_USER_INFO;
Wale Ogunwale86b74462018-07-02 08:42:43 -07001226 }
1227 return null;
1228 }
1229
1230 @Override
1231 int[] getCurrentProfileIds() {
1232 return new int[] { TEST_USER_0_ID, TEST_QUIET_USER_ID };
Winson Chung3f0e59a2017-10-25 10:19:05 -07001233 }
1234
1235 @Override
1236 boolean isCallerRecents(int callingUid) {
1237 if (mOverrideIsCallerRecents) {
1238 switch (mIsCallerRecentsPolicy) {
1239 case GRANT:
1240 return true;
1241 case DENY:
1242 return false;
1243 case DENY_THROW_SECURITY_EXCEPTION:
1244 throw new SecurityException();
1245 }
1246 }
1247 return super.isCallerRecents(callingUid);
1248 }
1249
1250 void setIsCallerRecentsOverride(int policy) {
1251 mOverrideIsCallerRecents = true;
1252 mIsCallerRecentsPolicy = policy;
1253 }
1254
Winson Chung0ec2a352017-10-26 11:38:30 -07001255 /**
1256 * To simplify the setup for some tests, the caller can request that we only rely on the
1257 * visible range test to determine what is trimmable. In this case, we don't try to
1258 * use the stack order to determine additionally if the task is trimmable when it is not
1259 * in the visible range.
1260 */
1261 void setOnlyTestVisibleRange() {
1262 mIsTrimmableOverride = true;
1263 }
1264
Winson Chung3f0e59a2017-10-25 10:19:05 -07001265 @Override
1266 ParceledListSlice<RecentTaskInfo> getRecentTasks(int maxNum, int flags,
1267 boolean getTasksAllowed,
1268 boolean getDetailedTasks, int userId, int callingUid) {
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +09001269 mLastAllowed = getTasksAllowed;
Winson Chung3f0e59a2017-10-25 10:19:05 -07001270 return super.getRecentTasks(maxNum, flags, getTasksAllowed, getDetailedTasks, userId,
1271 callingUid);
1272 }
Winson Chung0ec2a352017-10-26 11:38:30 -07001273
1274 @Override
Louis Changcdec0802019-11-11 11:45:07 +08001275 protected boolean isTrimmable(Task task) {
Winson Chung0ec2a352017-10-26 11:38:30 -07001276 return mIsTrimmableOverride || super.isTrimmable(task);
1277 }
Winson Chung3f0e59a2017-10-25 10:19:05 -07001278 }
1279
1280 private static class TestRunningTasks extends RunningTasks {
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +09001281 public boolean mLastAllowed;
Winson Chung3f0e59a2017-10-25 10:19:05 -07001282
1283 @Override
1284 void getTasks(int maxNum, List<RunningTaskInfo> list, int ignoreActivityType,
Wale Ogunwale85fb19a2019-12-05 10:41:05 +09001285 int ignoreWindowingMode, RootActivityContainer root,
Nicholas Sauer3f9249f2019-09-10 20:23:41 -07001286 int callingUid, boolean allowed, boolean crossUser, ArraySet<Integer> profileIds) {
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +09001287 mLastAllowed = allowed;
Wale Ogunwale85fb19a2019-12-05 10:41:05 +09001288 super.getTasks(maxNum, list, ignoreActivityType, ignoreWindowingMode, root,
Nicholas Sauer3f9249f2019-09-10 20:23:41 -07001289 callingUid, allowed, crossUser, profileIds);
Winson Chung3f0e59a2017-10-25 10:19:05 -07001290 }
1291 }
Wale Ogunwalec59b4f62017-11-30 11:05:43 -08001292}