5/Organize and make running tasks code more efficient

- Move running task code from stack/supervisor into its own class
- Reduce work to calculate running tasks. Instead of creating RunningTaskInfo
  for every single task and then limiting to the requested set, calculate
  the set and then create the infos.
- Consolidate calculation of number of running activities in a task between
  the RecentTaskInfo and the RunningTaskInfo
- Remove unused flag argument, adding another method to instead filter the
  collection of running tasks to exclude certain activity types and windowing
  modes.  This allows us to fetch only the last running task in SystemUI and
  not have additional logic on our side.

Bug: 34270611
Test: runtest --path frameworks/base/services/tests/servicestests/src/com/android/server/am/RunningTasksTest.java
Change-Id: Iaba7487cea0545f69739da7cd3095b500a0df6fc
diff --git a/services/core/java/com/android/server/am/RunningTasks.java b/services/core/java/com/android/server/am/RunningTasks.java
new file mode 100644
index 0000000..400b03a
--- /dev/null
+++ b/services/core/java/com/android/server/am/RunningTasks.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.am;
+
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+
+import android.app.ActivityManager.RunningTaskInfo;
+import android.app.WindowConfiguration.ActivityType;
+import android.app.WindowConfiguration.WindowingMode;
+import android.util.SparseArray;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.TreeSet;
+
+/**
+ * Class for resolving the set of running tasks in the system.
+ */
+class RunningTasks {
+
+    // Comparator to sort by last active time (descending)
+    private static final Comparator<TaskRecord> LAST_ACTIVE_TIME_COMPARATOR =
+            (o1, o2) -> Long.signum(o2.lastActiveTime - o1.lastActiveTime);
+
+    private final TaskRecord.TaskActivitiesReport mTmpReport =
+            new TaskRecord.TaskActivitiesReport();
+    private final TreeSet<TaskRecord> mTmpSortedSet = new TreeSet<>(LAST_ACTIVE_TIME_COMPARATOR);
+    private final ArrayList<TaskRecord> mTmpStackTasks = new ArrayList<>();
+
+    void getTasks(int maxNum, List<RunningTaskInfo> list, @ActivityType int ignoreActivityType,
+            @WindowingMode int ignoreWindowingMode, SparseArray<ActivityDisplay> activityDisplays,
+            int callingUid, boolean allowed) {
+        // For each stack on each display, add the tasks into the sorted set and then pull the first
+        // {@param maxNum} from the set
+
+        // Gather all of the tasks across all of the tasks, and add them to the sorted set
+        mTmpSortedSet.clear();
+        mTmpStackTasks.clear();
+        final int numDisplays = activityDisplays.size();
+        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+            final ActivityDisplay display = activityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
+                stack.getRunningTasks(mTmpStackTasks, ignoreActivityType, ignoreWindowingMode,
+                        callingUid, allowed);
+                for (int i = mTmpStackTasks.size() - 1; i >= 0; i--) {
+                    mTmpSortedSet.addAll(mTmpStackTasks);
+                }
+            }
+        }
+
+        // Take the first {@param maxNum} tasks and create running task infos for them
+        final Iterator<TaskRecord> iter = mTmpSortedSet.iterator();
+        while (iter.hasNext()) {
+            if (maxNum == 0) {
+                break;
+            }
+
+            final TaskRecord task = iter.next();
+            list.add(createRunningTaskInfo(task));
+            maxNum--;
+        }
+    }
+
+    /**
+     * Constructs a {@link RunningTaskInfo} from a given {@param task}.
+     */
+    private RunningTaskInfo createRunningTaskInfo(TaskRecord task) {
+        task.getNumRunningActivities(mTmpReport);
+
+        final RunningTaskInfo ci = new RunningTaskInfo();
+        ci.id = task.taskId;
+        ci.stackId = task.getStackId();
+        ci.baseActivity = mTmpReport.base.intent.getComponent();
+        ci.topActivity = mTmpReport.top.intent.getComponent();
+        ci.lastActiveTime = task.lastActiveTime;
+        ci.description = task.lastDescription;
+        ci.numActivities = mTmpReport.numActivities;
+        ci.numRunning = mTmpReport.numRunning;
+        ci.supportsSplitScreenMultiWindow = task.supportsSplitScreenWindowingMode();
+        ci.resizeMode = task.mResizeMode;
+        ci.configuration.setTo(task.getConfiguration());
+        return ci;
+    }
+}