Expose method to clear all visible recent tasks

- Atomically remove all the visible tasks so that SysUI doesn't need to
  remove each task individually.

Bug: 80471073
Test: atest FrameworksServicesTests:RecentTasksTest#testRemoveAllVisibleTasks
Change-Id: I23a6e152e94d5462948ab40adc9d7baf593847e1
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index d1585cf..609ad75 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -3230,12 +3230,12 @@
     }
 
     @Override
-    public void onRecentTaskRemoved(TaskRecord task, boolean wasTrimmed) {
+    public void onRecentTaskRemoved(TaskRecord task, boolean wasTrimmed, boolean killProcess) {
         if (wasTrimmed) {
             // Task was trimmed from the recent tasks list -- remove the active task record as well
             // since the user won't really be able to go back to it
-            removeTaskByIdLocked(task.taskId, false /* killProcess */,
-                    false /* removeFromRecents */, !PAUSE_IMMEDIATELY, "recent-task-trimmed");
+            removeTaskByIdLocked(task.taskId, killProcess, false /* removeFromRecents */,
+                    !PAUSE_IMMEDIATELY, "recent-task-trimmed");
         }
         task.removedFromRecents();
     }
diff --git a/services/core/java/com/android/server/am/ActivityTaskManagerService.java b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
index 3b3263c..8ab4a37 100644
--- a/services/core/java/com/android/server/am/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
@@ -1668,6 +1668,19 @@
     }
 
     @Override
+    public void removeAllVisibleRecentTasks() {
+        enforceCallerIsRecentsOrHasPermission(REMOVE_TASKS, "removeAllVisibleRecentTasks()");
+        synchronized (mGlobalLock) {
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                getRecentTasks().removeAllVisibleTasks();
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+    }
+
+    @Override
     public boolean shouldUpRecreateTask(IBinder token, String destAffinity) {
         synchronized (mGlobalLock) {
             final ActivityRecord srec = ActivityRecord.forTokenLocked(token);
diff --git a/services/core/java/com/android/server/am/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java
index fb6b5c1..e11e003 100644
--- a/services/core/java/com/android/server/am/RecentTasks.java
+++ b/services/core/java/com/android/server/am/RecentTasks.java
@@ -106,7 +106,6 @@
     private static final String TAG = TAG_WITH_CLASS_NAME ? "RecentTasks" : TAG_AM;
     private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
     private static final String TAG_TASKS = TAG + POSTFIX_TASKS;
-    private static final boolean TRIMMED = true;
 
     private static final int DEFAULT_INITIAL_CAPACITY = 5;
 
@@ -134,7 +133,7 @@
         /**
          * Called when a task is removed from the recent tasks list.
          */
-        void onRecentTaskRemoved(TaskRecord task, boolean wasTrimmed);
+        void onRecentTaskRemoved(TaskRecord task, boolean wasTrimmed, boolean killProcess);
     }
 
     /**
@@ -322,9 +321,9 @@
         }
     }
 
-    private void notifyTaskRemoved(TaskRecord task, boolean wasTrimmed) {
+    private void notifyTaskRemoved(TaskRecord task, boolean wasTrimmed, boolean killProcess) {
         for (int i = 0; i < mCallbacks.size(); i++) {
-            mCallbacks.get(i).onRecentTaskRemoved(task, wasTrimmed);
+            mCallbacks.get(i).onRecentTaskRemoved(task, wasTrimmed, killProcess);
         }
     }
 
@@ -547,6 +546,16 @@
         }
     }
 
+    void removeAllVisibleTasks() {
+        for (int i = mTasks.size() - 1; i >= 0; --i) {
+            final TaskRecord tr = mTasks.get(i);
+            if (isVisibleRecentTask(tr)) {
+                mTasks.remove(i);
+                notifyTaskRemoved(tr, true /* wasTrimmed */, true /* killProcess */);
+            }
+        }
+    }
+
     void cleanupDisabledPackageTasksLocked(String packageName, Set<String> filterByClasses,
             int userId) {
         for (int i = mTasks.size() - 1; i >= 0; --i) {
@@ -1048,7 +1057,7 @@
      */
     void remove(TaskRecord task) {
         mTasks.remove(task);
-        notifyTaskRemoved(task, !TRIMMED);
+        notifyTaskRemoved(task, false /* wasTrimmed */, false /* killProcess */);
     }
 
     /**
@@ -1060,7 +1069,7 @@
         // Remove from the end of the list until we reach the max number of recents
         while (recentsCount > mGlobalMaxNumTasks) {
             final TaskRecord tr = mTasks.remove(recentsCount - 1);
-            notifyTaskRemoved(tr, TRIMMED);
+            notifyTaskRemoved(tr, true /* wasTrimmed */, false /* killProcess */);
             recentsCount--;
             if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "Trimming over max-recents task=" + tr
                     + " max=" + mGlobalMaxNumTasks);
@@ -1114,7 +1123,7 @@
 
             // Task is no longer active, trim it from the list
             mTasks.remove(task);
-            notifyTaskRemoved(task, TRIMMED);
+            notifyTaskRemoved(task, true /* wasTrimmed */, false /* killProcess */);
             notifyTaskPersisterLocked(task, false /* flush */);
         }
     }
@@ -1268,7 +1277,7 @@
         // callbacks here.
         final TaskRecord removedTask = mTasks.remove(removeIndex);
         if (removedTask != task) {
-            notifyTaskRemoved(removedTask, !TRIMMED);
+            notifyTaskRemoved(removedTask, false /* wasTrimmed */, false /* killProcess */);
             if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "Trimming task=" + removedTask
                     + " for addition of task=" + task);
         }