Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b3968640 authored by Sunny Goyal's avatar Sunny Goyal
Browse files

Fixing loadTasksInBackground called twice on swipe up

Bug: 157644889
Change-Id: Ia4413ea878f8ba731fbb7a8f61b7c0c0050f3811
parent c577bb84
Loading
Loading
Loading
Loading
+55 −28
Original line number Diff line number Diff line
@@ -40,21 +40,20 @@ import java.util.function.Consumer;
/**
 * Manages the recent task list from the system, caching it as necessary.
 */
@TargetApi(Build.VERSION_CODES.P)
@TargetApi(Build.VERSION_CODES.R)
public class RecentTasksList extends TaskStackChangeListener {

    private static final TaskLoadResult INVALID_RESULT = new TaskLoadResult(-1, false, 0);

    private final KeyguardManagerCompat mKeyguardManager;
    private final LooperExecutor mMainThreadExecutor;
    private final ActivityManagerWrapper mActivityManagerWrapper;

    // The list change id, increments as the task list changes in the system
    private int mChangeId;
    // The last change id when the list was last loaded completely, must be <= the list change id
    private int mLastLoadedId;
    // The last change id was loaded with keysOnly  = true
    private boolean mLastLoadHadKeysOnly;

    ArrayList<Task> mTasks = new ArrayList<>();
    private TaskLoadResult mResultsBg = INVALID_RESULT;
    private TaskLoadResult mResultsUi = INVALID_RESULT;

    public RecentTasksList(LooperExecutor mainThreadExecutor,
            KeyguardManagerCompat keyguardManager, ActivityManagerWrapper activityManagerWrapper) {
@@ -71,7 +70,7 @@ public class RecentTasksList extends TaskStackChangeListener {
    public void getTaskKeys(int numTasks, Consumer<ArrayList<Task>> callback) {
        // Kick off task loading in the background
        UI_HELPER_EXECUTOR.execute(() -> {
            ArrayList<Task> tasks = loadTasksInBackground(numTasks, true /* loadKeysOnly */);
            ArrayList<Task> tasks = loadTasksInBackground(numTasks, -1, true /* loadKeysOnly */);
            mMainThreadExecutor.execute(() -> callback.accept(tasks));
        });
    }
@@ -85,26 +84,30 @@ public class RecentTasksList extends TaskStackChangeListener {
     */
    public synchronized int getTasks(boolean loadKeysOnly, Consumer<ArrayList<Task>> callback) {
        final int requestLoadId = mChangeId;
        Runnable resultCallback = callback == null
                ? () -> { }
                : () -> callback.accept(copyOf(mTasks));

        if (mLastLoadedId == mChangeId && (!mLastLoadHadKeysOnly || loadKeysOnly)) {
        if (mResultsUi.isValidForRequest(requestLoadId, loadKeysOnly)) {
            // The list is up to date, send the callback on the next frame,
            // so that requestID can be returned first.
            mMainThreadExecutor.post(resultCallback);
            if (callback != null) {
                // Copy synchronously as the changeId might change by next frame
                ArrayList<Task> result = copyOf(mResultsUi);
                mMainThreadExecutor.post(() -> callback.accept(result));
            }

            return requestLoadId;
        }

        // Kick off task loading in the background
        UI_HELPER_EXECUTOR.execute(() -> {
            ArrayList<Task> tasks = loadTasksInBackground(Integer.MAX_VALUE, loadKeysOnly);

            if (!mResultsBg.isValidForRequest(requestLoadId, loadKeysOnly)) {
                mResultsBg = loadTasksInBackground(Integer.MAX_VALUE, requestLoadId, loadKeysOnly);
            }
            TaskLoadResult loadResult = mResultsBg;
            mMainThreadExecutor.execute(() -> {
                mTasks = tasks;
                mLastLoadedId = requestLoadId;
                mLastLoadHadKeysOnly = loadKeysOnly;
                resultCallback.run();
                mResultsUi = loadResult;
                if (callback != null) {
                    ArrayList<Task> result = copyOf(mResultsUi);
                    callback.accept(result);
                }
            });
        });

@@ -119,8 +122,8 @@ public class RecentTasksList extends TaskStackChangeListener {
    }

    @Override
    public synchronized void onTaskStackChanged() {
        mChangeId++;
    public void onTaskStackChanged() {
        invalidateLoadedTasks();
    }

    @Override
@@ -131,22 +134,28 @@ public class RecentTasksList extends TaskStackChangeListener {
        // callback (those are for changes to the active tasks), but the task list is still updated,
        // so we should also invalidate the change id to ensure we load a new list instead of 
        // reusing a stale list.
        mChangeId++;
        invalidateLoadedTasks();
    }

    @Override
    public void onTaskRemoved(int taskId) {
        mTasks = loadTasksInBackground(Integer.MAX_VALUE, false);
        invalidateLoadedTasks();
    }


    @Override
    public synchronized void onActivityPinned(String packageName, int userId, int taskId,
            int stackId) {
        mChangeId++;
    public void onActivityPinned(String packageName, int userId, int taskId, int stackId) {
        invalidateLoadedTasks();
    }

    @Override
    public synchronized void onActivityUnpinned() {
        invalidateLoadedTasks();
    }

    private synchronized void invalidateLoadedTasks() {
        UI_HELPER_EXECUTOR.execute(() -> mResultsBg = INVALID_RESULT);
        mResultsUi = INVALID_RESULT;
        mChangeId++;
    }

@@ -154,9 +163,8 @@ public class RecentTasksList extends TaskStackChangeListener {
     * Loads and creates a list of all the recent tasks.
     */
    @VisibleForTesting
    ArrayList<Task> loadTasksInBackground(int numTasks, boolean loadKeysOnly) {
    TaskLoadResult loadTasksInBackground(int numTasks, int requestId, boolean loadKeysOnly) {
        int currentUserId = Process.myUserHandle().getIdentifier();
        ArrayList<Task> allTasks = new ArrayList<>();
        List<ActivityManager.RecentTaskInfo> rawTasks =
                mActivityManagerWrapper.getRecentTasks(numTasks, currentUserId);
        // The raw tasks are given in most-recent to least-recent order, we need to reverse it
@@ -173,6 +181,7 @@ public class RecentTasksList extends TaskStackChangeListener {
            }
        };

        TaskLoadResult allTasks = new TaskLoadResult(requestId, loadKeysOnly, rawTasks.size());
        for (ActivityManager.RecentTaskInfo rawTask : rawTasks) {
            Task.TaskKey taskKey = new Task.TaskKey(rawTask);
            Task task;
@@ -197,4 +206,22 @@ public class RecentTasksList extends TaskStackChangeListener {
        }
        return newTasks;
    }

    private static class TaskLoadResult extends ArrayList<Task> {

        final int mId;

        // If the result was loaded with keysOnly  = true
        final boolean mKeysOnly;

        TaskLoadResult(int id, boolean keysOnly, int size) {
            super(size);
            mId = id;
            mKeysOnly = keysOnly;
        }

        boolean isValidForRequest(int requestId, boolean loadKeysOnly) {
            return mId == requestId && (!mKeysOnly || loadKeysOnly);
        }
    }
}
 No newline at end of file
+4 −4
Original line number Diff line number Diff line
@@ -58,9 +58,9 @@ public class RecentTasksListTest {
    }

    @Test
    public void onTaskRemoved_reloadsAllTasks() {
    public void onTaskRemoved_doesNotFetchTasks() {
        mRecentTasksList.onTaskRemoved(0);
        verify(mockActivityManagerWrapper, times(1))
        verify(mockActivityManagerWrapper, times(0))
                .getRecentTasks(anyInt(), anyInt());
    }

@@ -77,7 +77,7 @@ public class RecentTasksListTest {
        when(mockActivityManagerWrapper.getRecentTasks(anyInt(), anyInt()))
                .thenReturn(Collections.singletonList(recentTaskInfo));

        List<Task> taskList = mRecentTasksList.loadTasksInBackground(Integer.MAX_VALUE, true);
        List<Task> taskList = mRecentTasksList.loadTasksInBackground(Integer.MAX_VALUE, -1, true);

        assertEquals(1, taskList.size());
        assertNull(taskList.get(0).taskDescription.getLabel());
@@ -91,7 +91,7 @@ public class RecentTasksListTest {
        when(mockActivityManagerWrapper.getRecentTasks(anyInt(), anyInt()))
                .thenReturn(Collections.singletonList(recentTaskInfo));

        List<Task> taskList = mRecentTasksList.loadTasksInBackground(Integer.MAX_VALUE, false);
        List<Task> taskList = mRecentTasksList.loadTasksInBackground(Integer.MAX_VALUE, -1, false);

        assertEquals(1, taskList.size());
        assertEquals(taskDescription, taskList.get(0).taskDescription.getLabel());