1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License
15  */
16 
17 package com.android.server.wm;
18 
19 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
20 import static com.android.server.wm.RunningTasks.FLAG_ALLOWED;
21 import static com.android.server.wm.RunningTasks.FLAG_CROSS_USERS;
22 import static com.android.server.wm.RunningTasks.FLAG_KEEP_INTENT_EXTRA;
23 
24 import static com.google.common.truth.Truth.assertThat;
25 
26 import static org.junit.Assert.assertEquals;
27 import static org.junit.Assert.assertNotNull;
28 import static org.junit.Assert.assertTrue;
29 
30 import android.app.ActivityManager.RunningTaskInfo;
31 import android.content.ComponentName;
32 import android.os.Bundle;
33 import android.platform.test.annotations.Presubmit;
34 import android.util.ArraySet;
35 
36 import androidx.test.filters.MediumTest;
37 
38 import com.google.common.truth.Correspondence;
39 
40 import org.junit.Before;
41 import org.junit.Test;
42 import org.junit.runner.RunWith;
43 
44 import java.util.ArrayList;
45 
46 /**
47  * Build/Install/Run:
48  *  atest WmTests:RunningTasksTest
49  */
50 @MediumTest
51 @Presubmit
52 @RunWith(WindowTestRunner.class)
53 public class RunningTasksTest extends WindowTestsBase {
54 
55     private static final ArraySet<Integer> PROFILE_IDS = new ArraySet<>();
56     private static final Correspondence<RunningTaskInfo, Integer> TASKINFO_HAS_ID =
57             Correspondence.transforming((RunningTaskInfo t) -> t.taskId, "has id");
58 
59 
60     private RunningTasks mRunningTasks;
61 
62     @Before
setUp()63     public void setUp() throws Exception {
64         mRunningTasks = new RunningTasks();
65     }
66 
67     @Test
testTaskInfo_expectNoExtrasByDefault()68     public void testTaskInfo_expectNoExtrasByDefault() {
69         final DisplayContent display = new TestDisplayContent.Builder(mAtm, 1000, 2500).build();
70         final int numTasks = 10;
71         for (int i = 0; i < numTasks; i++) {
72             final Task stack = new TaskBuilder(mSupervisor)
73                     .setDisplay(display)
74                     .setOnTop(true)
75                     .build();
76             final Bundle data = new Bundle();
77             data.putInt("key", 100);
78             createTask(stack, ".Task" + i, i, data);
79         }
80 
81         final int numFetchTasks = 5;
82         final ArrayList<RunningTaskInfo> tasks = new ArrayList<>();
83         mRunningTasks.getTasks(numFetchTasks, tasks, FLAG_ALLOWED | FLAG_CROSS_USERS,
84                 mAtm.getRecentTasks(), mRootWindowContainer, -1 /* callingUid */, PROFILE_IDS);
85         assertThat(tasks).hasSize(numFetchTasks);
86         for (int i = 0; i < tasks.size(); i++) {
87             final Bundle extras = tasks.get(i).baseIntent.getExtras();
88             assertTrue(extras == null || extras.isEmpty());
89         }
90     }
91 
92     @Test
testTaskInfo_expectExtrasWithKeepExtraFlag()93     public void testTaskInfo_expectExtrasWithKeepExtraFlag() {
94         final DisplayContent display = new TestDisplayContent.Builder(mAtm, 1000, 2500).build();
95         final int numTasks = 10;
96         for (int i = 0; i < numTasks; i++) {
97             final Task stack = new TaskBuilder(mSupervisor)
98                     .setDisplay(display)
99                     .setOnTop(true)
100                     .build();
101             final Bundle data = new Bundle();
102             data.putInt("key", 100);
103             createTask(stack, ".Task" + i, i, data);
104         }
105 
106         final int numFetchTasks = 5;
107         final ArrayList<RunningTaskInfo> tasks = new ArrayList<>();
108         mRunningTasks.getTasks(numFetchTasks, tasks,
109                 FLAG_ALLOWED | FLAG_CROSS_USERS | FLAG_KEEP_INTENT_EXTRA,
110                 mAtm.getRecentTasks(), mRootWindowContainer, -1 /* callingUid */, PROFILE_IDS);
111         assertThat(tasks).hasSize(numFetchTasks);
112         for (int i = 0; i < tasks.size(); i++) {
113             final Bundle extras = tasks.get(i).baseIntent.getExtras();
114             assertNotNull(extras);
115             assertEquals(100, extras.getInt("key"));
116         }
117     }
118 
119     @Test
testGetTasksSortByFocusAndVisibility()120     public void testGetTasksSortByFocusAndVisibility() {
121         final DisplayContent display = new TestDisplayContent.Builder(mAtm, 1000, 2500).build();
122         final Task stack = new TaskBuilder(mSupervisor)
123                 .setDisplay(display)
124                 .setOnTop(true)
125                 .build();
126 
127         final int numTasks = 10;
128         final ArrayList<Task> tasks = new ArrayList<>();
129         for (int i = 0; i < numTasks; i++) {
130             final Task task = createTask(stack, ".Task" + i, i, null);
131             doReturn(false).when(task).isVisible();
132             tasks.add(task);
133         }
134 
135         final Task focusedTask = tasks.get(numTasks - 1);
136         doReturn(true).when(focusedTask).isVisible();
137         display.mFocusedApp = focusedTask.getTopNonFinishingActivity();
138 
139         final Task visibleTaskTop = tasks.get(numTasks - 2);
140         doReturn(true).when(visibleTaskTop).isVisible();
141 
142         final Task visibleTaskBottom = tasks.get(numTasks - 3);
143         doReturn(true).when(visibleTaskBottom).isVisible();
144 
145         // Ensure that the focused Task is on top, visible tasks below, then invisible tasks.
146         final int numFetchTasks = 5;
147         final ArrayList<RunningTaskInfo> fetchTasks = new ArrayList<>();
148         mRunningTasks.getTasks(numFetchTasks, fetchTasks,
149                 FLAG_ALLOWED | FLAG_CROSS_USERS | FLAG_KEEP_INTENT_EXTRA,
150                 mAtm.getRecentTasks(), mRootWindowContainer, -1 /* callingUid */, PROFILE_IDS);
151         assertThat(fetchTasks).hasSize(numFetchTasks);
152         for (int i = 0; i < numFetchTasks; i++) {
153             assertEquals(numTasks - i - 1, fetchTasks.get(i).id);
154         }
155 
156         // Ensure that requesting more than the total number of tasks only returns the subset
157         // and does not crash
158         fetchTasks.clear();
159         mRunningTasks.getTasks(100, fetchTasks,
160                 FLAG_ALLOWED | FLAG_CROSS_USERS | FLAG_KEEP_INTENT_EXTRA,
161                 mAtm.getRecentTasks(), mRootWindowContainer, -1 /* callingUid */, PROFILE_IDS);
162         assertThat(fetchTasks).hasSize(numTasks);
163         for (int i = 0; i < numTasks; i++) {
164             assertEquals(numTasks - i - 1, fetchTasks.get(i).id);
165         }
166     }
167 
168     /**
169      * Create a task with a single activity in it.
170      */
createTask(Task stack, String className, int taskId, Bundle extras)171     private Task createTask(Task stack, String className, int taskId, Bundle extras) {
172         final Task task = new TaskBuilder(mAtm.mTaskSupervisor)
173                 .setComponent(new ComponentName(mContext.getPackageName(), className))
174                 .setTaskId(taskId)
175                 .setParentTask(stack)
176                 .build();
177         final ActivityRecord activity = new ActivityBuilder(mAtm)
178                 .setTask(task)
179                 .setComponent(new ComponentName(mContext.getPackageName(), ".TaskActivity"))
180                 .setIntentExtras(extras)
181                 .build();
182         task.intent = activity.intent;
183         return task;
184     }
185 
186     @Test
testMultipleDisplays()187     public void testMultipleDisplays() {
188         final DisplayContent display0 = new TestDisplayContent.Builder(mAtm, 1000, 2500).build();
189         final DisplayContent display1 = new TestDisplayContent.Builder(mAtm, 1000, 2500).build();
190         final int numTasks = 10;
191         final ArrayList<Task> tasks = new ArrayList<>();
192         for (int i = 0; i < numTasks; i++) {
193             final Task stack = new TaskBuilder(mSupervisor)
194                     .setDisplay(i % 2 == 0 ? display0 : display1)
195                     .setOnTop(true)
196                     .build();
197             final Task task = createTask(stack, ".Task" + i, i, null);
198             tasks.add(task);
199         }
200 
201         final int numFetchTasks = numTasks;
202         final ArrayList<RunningTaskInfo> fetchTasks = new ArrayList<>();
203 
204         mRunningTasks.getTasks(numFetchTasks, fetchTasks,
205                 FLAG_ALLOWED | FLAG_CROSS_USERS,
206                 mAtm.getRecentTasks(), display0, -1 /* callingUid */, PROFILE_IDS);
207         assertThat(fetchTasks).hasSize(numTasks / 2);
208         assertThat(fetchTasks).comparingElementsUsing(TASKINFO_HAS_ID)
209                 .containsExactly(0, 2, 4, 6, 8);
210 
211         fetchTasks.clear();
212         mRunningTasks.getTasks(numFetchTasks, fetchTasks,
213                 FLAG_ALLOWED | FLAG_CROSS_USERS,
214                 mAtm.getRecentTasks(), display1, -1 /* callingUid */, PROFILE_IDS);
215         assertThat(fetchTasks).hasSize(numTasks / 2);
216         assertThat(fetchTasks).comparingElementsUsing(TASKINFO_HAS_ID)
217                 .containsExactly(1, 3, 5, 7, 9);
218 
219         fetchTasks.clear();
220         mRunningTasks.getTasks(numFetchTasks, fetchTasks,
221                 FLAG_ALLOWED | FLAG_CROSS_USERS,
222                 mAtm.getRecentTasks(), mRootWindowContainer, -1 /* callingUid */, PROFILE_IDS);
223         assertThat(fetchTasks).hasSize(numTasks);
224         assertThat(fetchTasks).comparingElementsUsing(TASKINFO_HAS_ID)
225                 .containsExactly(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
226     }
227 }
228