diff options
author | 2022-10-20 13:06:19 +0800 | |
---|---|---|
committer | 2022-11-03 11:21:02 +0000 | |
commit | a1df4706c18b6d0b871091ab5f518a803de1afde (patch) | |
tree | 2f66dd0906d789a06f8ce7128048c9b7f875fa07 | |
parent | 72ca88f7356356bbc985bc5f6bb6fa0f144ffc0e (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.java | 111 | ||||
-rw-r--r-- | services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java | 103 |
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); } |