summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Bowen Li <libowen1@xiaomi.corp-partner.google.com> 2022-10-20 13:06:19 +0800
committer Chris Li <lihongyu@google.com> 2022-11-03 11:21:02 +0000
commita1df4706c18b6d0b871091ab5f518a803de1afde (patch)
tree2f66dd0906d789a06f8ce7128048c9b7f875fa07
parent72ca88f7356356bbc985bc5f6bb6fa0f144ffc0e (diff)
Sort running task by focus and visibility
Currently the order of visible tasks we get is opposite to that in the system. This CL is to ensure that the visible focused task is on top, visible tasks below, then invisible tasks. And keep the order within the acquired focus, visible and invisible tasks groups consistent with the system instead of sort by lastActiveTime. If there are multiple DisplayContents, getTasks method will return: [{VisibleFocusTask for DisplayTop, VisibleFocusTask for DisplayBottom}, {VisbleTask0...n1 for DisplayTop, VisbleTask0...n2 for DisplayBottom}, {InvisbleTask0...n3 for DisplayTop, InvisbleTask0...n4 for DisplayBottom}] in the same result List. Bug: 255255158 Signed-off-by: Bowen Li <libowen1@xiaomi.corp-partner.google.com> Merged-In: I7f7d5e72fbf73988b58c23f8a11dff05dbc1b3f1 Change-Id: I7f7d5e72fbf73988b58c23f8a11dff05dbc1b3f1
-rw-r--r--services/core/java/com/android/server/wm/RunningTasks.java111
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java103
2 files changed, 108 insertions, 106 deletions
diff --git a/services/core/java/com/android/server/wm/RunningTasks.java b/services/core/java/com/android/server/wm/RunningTasks.java
index 120fec0fe0e6..33f019e0c9fb 100644
--- a/services/core/java/com/android/server/wm/RunningTasks.java
+++ b/services/core/java/com/android/server/wm/RunningTasks.java
@@ -20,16 +20,15 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import android.app.ActivityManager.RunningTaskInfo;
+import android.os.SystemClock;
import android.os.UserHandle;
import android.util.ArraySet;
import com.android.internal.util.function.pooled.PooledConsumer;
import com.android.internal.util.function.pooled.PooledLambda;
-import java.util.Comparator;
-import java.util.Iterator;
+import java.util.ArrayList;
import java.util.List;
-import java.util.TreeSet;
/**
* Class for resolving the set of running tasks in the system.
@@ -41,15 +40,13 @@ class RunningTasks {
static final int FLAG_CROSS_USERS = 1 << 2;
static final int FLAG_KEEP_INTENT_EXTRA = 1 << 3;
- // Comparator to sort by last active time (descending)
- private static final Comparator<Task> LAST_ACTIVE_TIME_COMPARATOR =
- (o1, o2) -> {
- return o1.lastActiveTime == o2.lastActiveTime
- ? Integer.signum(o2.mTaskId - o1.mTaskId) :
- Long.signum(o2.lastActiveTime - o1.lastActiveTime);
- };
-
- private final TreeSet<Task> mTmpSortedSet = new TreeSet<>(LAST_ACTIVE_TIME_COMPARATOR);
+ // Tasks are sorted in order {focusedVisibleTasks, visibleTasks, invisibleTasks}.
+ private final ArrayList<Task> mTmpSortedTasks = new ArrayList<>();
+ // mTmpVisibleTasks, mTmpInvisibleTasks and mTmpFocusedTasks are sorted from top
+ // to bottom.
+ private final ArrayList<Task> mTmpVisibleTasks = new ArrayList<>();
+ private final ArrayList<Task> mTmpInvisibleTasks = new ArrayList<>();
+ private final ArrayList<Task> mTmpFocusedTasks = new ArrayList<>();
private int mCallingUid;
private int mUserId;
@@ -67,8 +64,6 @@ class RunningTasks {
return;
}
- // Gather all of the tasks across all of the tasks, and add them to the sorted set
- mTmpSortedSet.clear();
mCallingUid = callingUid;
mUserId = UserHandle.getUserId(callingUid);
mCrossUser = (flags & FLAG_CROSS_USERS) == FLAG_CROSS_USERS;
@@ -79,22 +74,67 @@ class RunningTasks {
mRecentTasks = recentTasks;
mKeepIntentExtra = (flags & FLAG_KEEP_INTENT_EXTRA) == FLAG_KEEP_INTENT_EXTRA;
- final PooledConsumer c = PooledLambda.obtainConsumer(RunningTasks::processTask, this,
- PooledLambda.__(Task.class));
- root.forAllLeafTasks(c, false);
- c.recycle();
+ if (root instanceof RootWindowContainer) {
+ ((RootWindowContainer) root).forAllDisplays(dc -> {
+ final Task focusedTask = dc.mFocusedApp != null ? dc.mFocusedApp.getTask() : null;
+ if (focusedTask != null) {
+ mTmpFocusedTasks.add(focusedTask);
+ }
+ processTaskInWindowContainer(dc);
+ });
+ } else {
+ final DisplayContent dc = root.getDisplayContent();
+ final Task focusedTask = dc != null
+ ? (dc.mFocusedApp != null ? dc.mFocusedApp.getTask() : null)
+ : null;
+ // May not be include focusedTask if root is DisplayArea.
+ final boolean rootContainsFocusedTask = focusedTask != null
+ && focusedTask.isDescendantOf(root);
+ if (rootContainsFocusedTask) {
+ mTmpFocusedTasks.add(focusedTask);
+ }
+ processTaskInWindowContainer(root);
+ }
- // Take the first {@param maxNum} tasks and create running task infos for them
- final Iterator<Task> iter = mTmpSortedSet.iterator();
- while (iter.hasNext()) {
- if (maxNum == 0) {
- break;
+ final int visibleTaskCount = mTmpVisibleTasks.size();
+ for (int i = 0; i < mTmpFocusedTasks.size(); i++) {
+ final Task focusedTask = mTmpFocusedTasks.get(i);
+ final boolean containsFocusedTask = mTmpVisibleTasks.remove(focusedTask);
+ if (containsFocusedTask) {
+ // Put the visible focused task at the first position.
+ mTmpSortedTasks.add(focusedTask);
}
+ }
+ if (!mTmpVisibleTasks.isEmpty()) {
+ mTmpSortedTasks.addAll(mTmpVisibleTasks);
+ }
+ if (!mTmpInvisibleTasks.isEmpty()) {
+ mTmpSortedTasks.addAll(mTmpInvisibleTasks);
+ }
- final Task task = iter.next();
- list.add(createRunningTaskInfo(task));
- maxNum--;
+ // Take the first {@param maxNum} tasks and create running task infos for them
+ final int size = Math.min(maxNum, mTmpSortedTasks.size());
+ final long now = SystemClock.elapsedRealtime();
+ for (int i = 0; i < size; i++) {
+ final Task task = mTmpSortedTasks.get(i);
+ // Override the last active to current time for the visible tasks because the visible
+ // tasks can be considered to be currently active, the values are descending as
+ // the item order.
+ final long visibleActiveTime = i < visibleTaskCount ? now + size - i : -1;
+ list.add(createRunningTaskInfo(task, visibleActiveTime));
}
+
+ mTmpFocusedTasks.clear();
+ mTmpVisibleTasks.clear();
+ mTmpInvisibleTasks.clear();
+ mTmpSortedTasks.clear();
+ }
+
+ private void processTaskInWindowContainer(WindowContainer wc) {
+ final PooledConsumer c = PooledLambda.obtainConsumer(RunningTasks::processTask, this,
+ PooledLambda.__(Task.class));
+ wc.forAllLeafTasks(c, true);
+ c.recycle();
}
private void processTask(Task task) {
@@ -121,25 +161,20 @@ class RunningTasks {
// home & recent tasks
return;
}
-
if (task.isVisible()) {
- // For the visible task, update the last active time so that it can be used to determine
- // the order of the tasks (it may not be set for newly created tasks)
- task.touchActiveTime();
- if (!task.isFocused()) {
- // TreeSet doesn't allow the same value and make sure this task is lower than the
- // focused one.
- task.lastActiveTime -= mTmpSortedSet.size();
- }
+ mTmpVisibleTasks.add(task);
+ } else {
+ mTmpInvisibleTasks.add(task);
}
-
- mTmpSortedSet.add(task);
}
/** Constructs a {@link RunningTaskInfo} from a given {@param task}. */
- private RunningTaskInfo createRunningTaskInfo(Task task) {
+ private RunningTaskInfo createRunningTaskInfo(Task task, long visibleActiveTime) {
final RunningTaskInfo rti = new RunningTaskInfo();
task.fillTaskInfo(rti, !mKeepIntentExtra);
+ if (visibleActiveTime > 0) {
+ rti.lastActiveTime = visibleActiveTime;
+ }
// Fill in some deprecated values
rti.id = rti.taskId;
return rti;
diff --git a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
index b1acae20afb0..eab2e156e9aa 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
@@ -42,7 +42,6 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.ArrayList;
-import java.util.List;
/**
* Build/Install/Run:
@@ -66,55 +65,6 @@ public class RunningTasksTest extends WindowTestsBase {
}
@Test
- public void testCollectTasksByLastActiveTime() {
- // Create a number of stacks with tasks (of incrementing active time)
- final ArrayList<DisplayContent> displays = new ArrayList<>();
- final DisplayContent display = new TestDisplayContent.Builder(mAtm, 1000, 2500).build();
- displays.add(display);
-
- final int numStacks = 2;
- for (int stackIndex = 0; stackIndex < numStacks; stackIndex++) {
- final Task stack = new TaskBuilder(mSupervisor)
- .setDisplay(display)
- .setOnTop(false)
- .build();
- }
-
- final int numTasks = 10;
- int activeTime = 0;
- final List<Task> rootTasks = new ArrayList<>();
- display.getDefaultTaskDisplayArea().forAllRootTasks(task -> {
- rootTasks.add(task);
- }, false /* traverseTopToBottom */);
- for (int i = 0; i < numTasks; i++) {
- final Task task =
- createTask(rootTasks.get(i % numStacks), ".Task" + i, i, activeTime++, null);
- doReturn(false).when(task).isVisible();
- }
-
- // Ensure that the latest tasks were returned in order of decreasing last active time,
- // collected from all tasks across all the stacks
- final int numFetchTasks = 5;
- ArrayList<RunningTaskInfo> tasks = new ArrayList<>();
- mRunningTasks.getTasks(5, tasks, FLAG_ALLOWED | FLAG_CROSS_USERS,
- mAtm.getRecentTasks(), mRootWindowContainer, -1 /* callingUid */, PROFILE_IDS);
- assertThat(tasks).hasSize(numFetchTasks);
- for (int i = 0; i < numFetchTasks; i++) {
- assertEquals(numTasks - i - 1, tasks.get(i).id);
- }
-
- // Ensure that requesting more than the total number of tasks only returns the subset
- // and does not crash
- tasks.clear();
- mRunningTasks.getTasks(100, tasks, FLAG_ALLOWED | FLAG_CROSS_USERS,
- mAtm.getRecentTasks(), mRootWindowContainer, -1 /* callingUid */, PROFILE_IDS);
- assertThat(tasks).hasSize(numTasks);
- for (int i = 0; i < numTasks; i++) {
- assertEquals(numTasks - i - 1, tasks.get(i).id);
- }
- }
-
- @Test
public void testTaskInfo_expectNoExtrasByDefault() {
final DisplayContent display = new TestDisplayContent.Builder(mAtm, 1000, 2500).build();
final int numTasks = 10;
@@ -125,7 +75,7 @@ public class RunningTasksTest extends WindowTestsBase {
.build();
final Bundle data = new Bundle();
data.putInt("key", 100);
- createTask(stack, ".Task" + i, i, i, data);
+ createTask(stack, ".Task" + i, i, data);
}
final int numFetchTasks = 5;
@@ -150,7 +100,7 @@ public class RunningTasksTest extends WindowTestsBase {
.build();
final Bundle data = new Bundle();
data.putInt("key", 100);
- createTask(stack, ".Task" + i, i, i, data);
+ createTask(stack, ".Task" + i, i, data);
}
final int numFetchTasks = 5;
@@ -167,46 +117,63 @@ public class RunningTasksTest extends WindowTestsBase {
}
@Test
- public void testUpdateLastActiveTimeOfVisibleTasks() {
+ public void testGetTasksSortByFocusAndVisibility() {
final DisplayContent display = new TestDisplayContent.Builder(mAtm, 1000, 2500).build();
+ final Task stack = new TaskBuilder(mSupervisor)
+ .setDisplay(display)
+ .setOnTop(true)
+ .build();
+
final int numTasks = 10;
final ArrayList<Task> tasks = new ArrayList<>();
for (int i = 0; i < numTasks; i++) {
- final Task task = createTask(null, ".Task" + i, i, i, null);
+ final Task task = createTask(stack, ".Task" + i, i, null);
doReturn(false).when(task).isVisible();
tasks.add(task);
}
- final Task visibleTask = tasks.get(0);
- doReturn(true).when(visibleTask).isVisible();
-
- final Task focusedTask = tasks.get(1);
+ final Task focusedTask = tasks.get(numTasks - 1);
doReturn(true).when(focusedTask).isVisible();
- doReturn(true).when(focusedTask).isFocused();
+ display.mFocusedApp = focusedTask.getTopNonFinishingActivity();
+
+ final Task visibleTaskTop = tasks.get(numTasks - 2);
+ doReturn(true).when(visibleTaskTop).isVisible();
- // Ensure that the last active time of visible tasks were updated while the focused one had
- // the largest last active time.
+ final Task visibleTaskBottom = tasks.get(numTasks - 3);
+ doReturn(true).when(visibleTaskBottom).isVisible();
+
+ // Ensure that the focused Task is on top, visible tasks below, then invisible tasks.
final int numFetchTasks = 5;
final ArrayList<RunningTaskInfo> fetchTasks = new ArrayList<>();
mRunningTasks.getTasks(numFetchTasks, fetchTasks,
FLAG_ALLOWED | FLAG_CROSS_USERS | FLAG_KEEP_INTENT_EXTRA,
mAtm.getRecentTasks(), mRootWindowContainer, -1 /* callingUid */, PROFILE_IDS);
assertThat(fetchTasks).hasSize(numFetchTasks);
- assertEquals(fetchTasks.get(0).id, focusedTask.mTaskId);
- assertEquals(fetchTasks.get(1).id, visibleTask.mTaskId);
+ for (int i = 0; i < numFetchTasks; i++) {
+ assertEquals(numTasks - i - 1, fetchTasks.get(i).id);
+ }
+
+ // Ensure that requesting more than the total number of tasks only returns the subset
+ // and does not crash
+ fetchTasks.clear();
+ mRunningTasks.getTasks(100, fetchTasks,
+ FLAG_ALLOWED | FLAG_CROSS_USERS | FLAG_KEEP_INTENT_EXTRA,
+ mAtm.getRecentTasks(), mRootWindowContainer, -1 /* callingUid */, PROFILE_IDS);
+ assertThat(fetchTasks).hasSize(numTasks);
+ for (int i = 0; i < numTasks; i++) {
+ assertEquals(numTasks - i - 1, fetchTasks.get(i).id);
+ }
}
/**
- * Create a task with a single activity in it, with the given last active time.
+ * Create a task with a single activity in it.
*/
- private Task createTask(Task stack, String className, int taskId,
- int lastActiveTime, Bundle extras) {
+ private Task createTask(Task stack, String className, int taskId, Bundle extras) {
final Task task = new TaskBuilder(mAtm.mTaskSupervisor)
.setComponent(new ComponentName(mContext.getPackageName(), className))
.setTaskId(taskId)
.setParentTaskFragment(stack)
.build();
- task.lastActiveTime = lastActiveTime;
final ActivityRecord activity = new ActivityBuilder(mAtm)
.setTask(task)
.setComponent(new ComponentName(mContext.getPackageName(), ".TaskActivity"))
@@ -227,7 +194,7 @@ public class RunningTasksTest extends WindowTestsBase {
.setDisplay(i % 2 == 0 ? display0 : display1)
.setOnTop(true)
.build();
- final Task task = createTask(stack, ".Task" + i, i, i, null);
+ final Task task = createTask(stack, ".Task" + i, i, null);
tasks.add(task);
}