Use system recent tasks stabilization

Bug: 111926330
Test: Swipe to last task, ensure it resets task list on timeout or interaction

Change-Id: Id09215a4cfdea63a4be6fb69fced163ad3bc10bd
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
index e8d4c19..15072a2 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -851,16 +851,6 @@
             Interpolator interpolator, GestureEndTarget target, PointF velocityPxPerMs) {
         mGestureEndTarget = target;
 
-        if (mGestureEndTarget.canBeContinued) {
-            // Because we might continue this gesture, e.g. for consecutive quick switch, we need to
-            // stabilize the task list so that tasks don't rearrange in the middle of the gesture.
-            RecentsModel.INSTANCE.get(mContext).startStabilizationSession();
-        } else if (mGestureEndTarget.isLauncher) {
-            // Otherwise, if we're going to home or overview,
-            // we reset the tasks to a consistent start state.
-            RecentsModel.INSTANCE.get(mContext).endStabilizationSession();
-        }
-
         if (mGestureEndTarget == HOME) {
             HomeAnimationFactory homeAnimFactory;
             if (mActivity != null) {
@@ -1003,10 +993,12 @@
         // Launch the task user scrolled to (mRecentsView.getNextPage()).
         if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
             // We finish recents animation inside launchTask() when live tile is enabled.
-            mRecentsView.getTaskViewAt(mRecentsView.getNextPage()).launchTask(false);
+            mRecentsView.getTaskViewAt(mRecentsView.getNextPage()).launchTask(false /* animate */,
+                    true /* freezeTaskList */);
         } else {
             mRecentsAnimationWrapper.finish(true /* toRecents */, () -> {
-                mRecentsView.getTaskViewAt(mRecentsView.getNextPage()).launchTask(false);
+                mRecentsView.getTaskViewAt(mRecentsView.getNextPage()).launchTask(
+                        false /* animate */, true /* freezeTaskList */);
             });
         }
         TOUCH_INTERACTION_LOG.addLog("finishRecentsAnimation", false);
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
index eb17e3e..6ba89c9 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
@@ -250,7 +250,11 @@
     }
 
     public void launchTask(boolean animate) {
-        launchTask(animate, (result) -> {
+        launchTask(animate, false /* freezeTaskList */);
+    }
+
+    public void launchTask(boolean animate, boolean freezeTaskList) {
+        launchTask(animate, freezeTaskList, (result) -> {
             if (!result) {
                 notifyTaskLaunchFailed(TAG);
             }
@@ -259,25 +263,33 @@
 
     public void launchTask(boolean animate, Consumer<Boolean> resultCallback,
             Handler resultCallbackHandler) {
+        launchTask(animate, false /* freezeTaskList */, resultCallback, resultCallbackHandler);
+    }
+
+    public void launchTask(boolean animate, boolean freezeTaskList, Consumer<Boolean> resultCallback,
+            Handler resultCallbackHandler) {
         if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
             if (isRunningTask()) {
                 getRecentsView().finishRecentsAnimation(false /* toRecents */,
                         () -> resultCallbackHandler.post(() -> resultCallback.accept(true)));
             } else {
-                launchTaskInternal(animate, resultCallback, resultCallbackHandler);
+                launchTaskInternal(animate, freezeTaskList, resultCallback, resultCallbackHandler);
             }
         } else {
-            launchTaskInternal(animate, resultCallback, resultCallbackHandler);
+            launchTaskInternal(animate, freezeTaskList, resultCallback, resultCallbackHandler);
         }
     }
 
-    private void launchTaskInternal(boolean animate, Consumer<Boolean> resultCallback,
-            Handler resultCallbackHandler) {
+    private void launchTaskInternal(boolean animate, boolean freezeTaskList,
+            Consumer<Boolean> resultCallback, Handler resultCallbackHandler) {
         if (mTask != null) {
             final ActivityOptions opts;
             if (animate) {
                 opts = ((BaseDraggingActivity) fromContext(getContext()))
                         .getActivityLaunchOptions(this);
+                if (freezeTaskList) {
+                    ActivityOptionsCompat.setFreezeRecentTasksList(opts);
+                }
                 ActivityManagerWrapper.getInstance().startActivityFromRecentsAsync(mTask.key,
                         opts, resultCallback, resultCallbackHandler);
             } else {
@@ -288,6 +300,9 @@
                         resultCallbackHandler.post(() -> resultCallback.accept(true));
                     }
                 }, resultCallbackHandler);
+                if (freezeTaskList) {
+                    ActivityOptionsCompat.setFreezeRecentTasksList(opts);
+                }
                 ActivityManagerWrapper.getInstance().startActivityFromRecentsAsync(mTask.key,
                         opts, (success) -> {
                             if (resultCallback != null && !success) {
diff --git a/quickstep/src/com/android/quickstep/NavBarModeOverlayResourceObserver.java b/quickstep/src/com/android/quickstep/NavBarModeOverlayResourceObserver.java
index 058b46f..3136632 100644
--- a/quickstep/src/com/android/quickstep/NavBarModeOverlayResourceObserver.java
+++ b/quickstep/src/com/android/quickstep/NavBarModeOverlayResourceObserver.java
@@ -70,6 +70,11 @@
                 NAV_BAR_INTERACTION_MODE_RES_NAME));
     }
 
+    public static boolean isLegacyModeEnabled(Context context) {
+        return QuickStepContract.isLegacyMode(getSystemIntegerRes(context,
+                NAV_BAR_INTERACTION_MODE_RES_NAME));
+    }
+
     private static int getSystemIntegerRes(Context context, String resName) {
         Resources res = context.getResources();
         int resId = res.getIdentifier(resName, "integer", "android");
@@ -81,4 +86,4 @@
             return -1;
         }
     }
-}
+}
\ No newline at end of file
diff --git a/quickstep/src/com/android/quickstep/RecentTasksList.java b/quickstep/src/com/android/quickstep/RecentTasksList.java
index e15a3f1..06a36c9 100644
--- a/quickstep/src/com/android/quickstep/RecentTasksList.java
+++ b/quickstep/src/com/android/quickstep/RecentTasksList.java
@@ -44,7 +44,6 @@
     private final KeyguardManagerCompat mKeyguardManager;
     private final MainThreadExecutor mMainThreadExecutor;
     private final BackgroundExecutor mBgThreadExecutor;
-    private final TaskListStabilizer mStabilizer = new TaskListStabilizer();
 
     // The list change id, increments as the task list changes in the system
     private int mChangeId;
@@ -74,14 +73,6 @@
         });
     }
 
-    public void startStabilizationSession() {
-        mStabilizer.startStabilizationSession();
-    }
-
-    public void endStabilizationSession() {
-        mStabilizer.endStabilizationSession();
-    }
-
     /**
      * Asynchronously fetches the list of recent tasks, reusing cached list if available.
      *
@@ -93,7 +84,7 @@
         final int requestLoadId = mChangeId;
         Runnable resultCallback = callback == null
                 ? () -> { }
-                : () -> callback.accept(mStabilizer.reorder(mTasks));
+                : () -> callback.accept(mTasks);
 
         if (mLastLoadedId == mChangeId && (!mLastLoadHadKeysOnly || loadKeysOnly)) {
             // The list is up to date, callback with the same list
diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java
index 56bc8570..a65bc33 100644
--- a/quickstep/src/com/android/quickstep/RecentsModel.java
+++ b/quickstep/src/com/android/quickstep/RecentsModel.java
@@ -90,14 +90,6 @@
         return mThumbnailCache;
     }
 
-    public void startStabilizationSession() {
-        mTaskList.startStabilizationSession();
-    }
-
-    public void endStabilizationSession() {
-        mTaskList.endStabilizationSession();
-    }
-
     /**
      * Fetches the list of recent tasks.
      *
diff --git a/quickstep/src/com/android/quickstep/TaskListStabilizer.java b/quickstep/src/com/android/quickstep/TaskListStabilizer.java
deleted file mode 100644
index 4c63f81..0000000
--- a/quickstep/src/com/android/quickstep/TaskListStabilizer.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright (C) 2019 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.quickstep;
-
-import android.app.ActivityManager.RecentTaskInfo;
-import android.content.ComponentName;
-import android.os.Process;
-import android.os.SystemClock;
-
-import com.android.launcher3.util.IntArray;
-import com.android.systemui.shared.recents.model.Task;
-import com.android.systemui.shared.recents.model.Task.TaskKey;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.shared.system.TaskStackChangeListener;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Keeps the task list stable during quick switch gestures. So if you swipe right to switch from app
- * A to B, you can then swipe right again to get to app C or left to get back to A.
- */
-public class TaskListStabilizer {
-
-    private static final long TASK_CACHE_TIMEOUT_MS = 5000;
-
-    private final TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() {
-
-        @Override
-        public void onTaskCreated(int taskId, ComponentName componentName) {
-            endStabilizationSession();
-        }
-
-        @Override
-        public void onTaskRemoved(int taskId) {
-            endStabilizationSession();
-        }
-    };
-
-    // Task ids ordered based on recency, 0th index is the least recent task
-    private final IntArray mSystemOrder;
-    private final IntArray mStabilizedOrder;
-
-    // Wrapper objects used for sorting tasks
-    private final ArrayList<TaskWrapper> mTaskWrappers = new ArrayList<>();
-
-    private boolean mInStabilizationSession;
-    private long mSessionStartTime;
-
-    public TaskListStabilizer() {
-        // Initialize the task ids map
-        List<RecentTaskInfo> rawTasks = ActivityManagerWrapper.getInstance().getRecentTasks(
-                Integer.MAX_VALUE, Process.myUserHandle().getIdentifier());
-        mSystemOrder = new IntArray(rawTasks.size());
-        for (RecentTaskInfo info : rawTasks) {
-            mSystemOrder.add(new TaskKey(info).id);
-        }
-        // We will lazily copy the task id's from mSystemOrder when a stabilization session starts.
-        mStabilizedOrder = new IntArray(rawTasks.size());
-
-        ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
-    }
-
-    public synchronized void startStabilizationSession() {
-        if (!mInStabilizationSession) {
-            mStabilizedOrder.clear();
-            mStabilizedOrder.addAll(mSystemOrder);
-        }
-        mInStabilizationSession = true;
-        mSessionStartTime = SystemClock.uptimeMillis();
-    }
-
-    public synchronized void endStabilizationSession() {
-        mInStabilizationSession = false;
-    }
-
-    public synchronized ArrayList<Task> reorder(ArrayList<Task> tasks) {
-        mSystemOrder.clear();
-        for (Task task : tasks) {
-            mSystemOrder.add(task.key.id);
-        }
-
-        if ((SystemClock.uptimeMillis() - mSessionStartTime) > TASK_CACHE_TIMEOUT_MS) {
-            endStabilizationSession();
-        }
-
-        if (!mInStabilizationSession) {
-            return tasks;
-        }
-
-        // Ensure that we have enough wrappers
-        int taskCount = tasks.size();
-        for (int i = taskCount - mTaskWrappers.size(); i > 0; i--) {
-            mTaskWrappers.add(new TaskWrapper());
-        }
-
-        List<TaskWrapper> listToSort = mTaskWrappers.size() == taskCount
-                ? mTaskWrappers : mTaskWrappers.subList(0, taskCount);
-        int missingTaskIndex = -taskCount;
-
-        for (int i = 0; i < taskCount; i++){
-            TaskWrapper wrapper = listToSort.get(i);
-            wrapper.task = tasks.get(i);
-            wrapper.index = mStabilizedOrder.indexOf(wrapper.task.key.id);
-
-            // Ensure that missing tasks are put in the front, in the order they appear in the
-            // original list
-            if (wrapper.index < 0) {
-                wrapper.index = missingTaskIndex;
-                missingTaskIndex++;
-            }
-        }
-        Collections.sort(listToSort);
-
-        ArrayList<Task> result = new ArrayList<>(taskCount);
-        for (int i = 0; i < taskCount; i++) {
-            result.add(listToSort.get(i).task);
-        }
-        return result;
-    }
-
-    private static class TaskWrapper implements Comparable<TaskWrapper> {
-        Task task;
-        int index;
-
-        @Override
-        public int compareTo(TaskWrapper other) {
-            return Integer.compare(index, other.index);
-        }
-    }
-}