Merge "Add loader for recents Go." into ub-launcher3-master
diff --git a/go/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java b/go/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
index afc8e47..47e0e61 100644
--- a/go/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
+++ b/go/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
@@ -19,14 +19,12 @@
import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS;
import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
-import android.graphics.Rect;
-
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
import com.android.launcher3.userevent.nano.LauncherLogProto;
-import com.android.quickstep.RecentsModel;
+import com.android.quickstep.views.IconRecentsView;
/**
* Definition for overview state
@@ -50,6 +48,12 @@
}
@Override
+ public void onStateEnabled(Launcher launcher) {
+ IconRecentsView recentsView = launcher.getOverviewPanel();
+ recentsView.onBeginTransitionToOverview();
+ }
+
+ @Override
public PageAlphaProvider getWorkspacePageAlphaProvider(Launcher launcher) {
return new PageAlphaProvider(DEACCEL_2) {
@Override
diff --git a/go/quickstep/src/com/android/quickstep/TaskAdapter.java b/go/quickstep/src/com/android/quickstep/TaskAdapter.java
index 77c3f33..57cd60a 100644
--- a/go/quickstep/src/com/android/quickstep/TaskAdapter.java
+++ b/go/quickstep/src/com/android/quickstep/TaskAdapter.java
@@ -33,10 +33,10 @@
private static final int MAX_TASKS_TO_DISPLAY = 6;
private static final String TAG = "TaskAdapter";
- private final ArrayList<Task> mTaskList;
+ private final TaskListLoader mLoader;
- public TaskAdapter(@NonNull ArrayList<Task> taskList) {
- mTaskList = taskList;
+ public TaskAdapter(@NonNull TaskListLoader loader) {
+ mLoader = loader;
}
@Override
@@ -48,11 +48,16 @@
@Override
public void onBindViewHolder(TaskHolder holder, int position) {
- holder.bindTask(mTaskList.get(position));
+ ArrayList<Task> tasks = mLoader.getCurrentTaskList();
+ if (position >= tasks.size()) {
+ // Task list has updated.
+ return;
+ }
+ holder.bindTask(tasks.get(position));
}
@Override
public int getItemCount() {
- return Math.min(mTaskList.size(), MAX_TASKS_TO_DISPLAY);
+ return Math.min(mLoader.getCurrentTaskList().size(), MAX_TASKS_TO_DISPLAY);
}
}
diff --git a/go/quickstep/src/com/android/quickstep/TaskListLoader.java b/go/quickstep/src/com/android/quickstep/TaskListLoader.java
new file mode 100644
index 0000000..9f359b4
--- /dev/null
+++ b/go/quickstep/src/com/android/quickstep/TaskListLoader.java
@@ -0,0 +1,118 @@
+/*
+ * 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.content.Context;
+
+import androidx.annotation.Nullable;
+
+import com.android.systemui.shared.recents.model.Task;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Consumer;
+
+/**
+ * This class is responsible for maintaining the list of tasks and the task content. The list must
+ * be updated explicitly with {@link #loadTaskList} whenever the list needs to be
+ * up-to-date.
+ */
+public final class TaskListLoader {
+
+ private final RecentsModel mRecentsModel;
+
+ private ArrayList<Task> mTaskList = new ArrayList<>();
+ private int mTaskListChangeId;
+
+ public TaskListLoader(Context context) {
+ mRecentsModel = RecentsModel.INSTANCE.get(context);
+ }
+
+ /**
+ * Returns the current task list as of the last completed load (see
+ * {@link #loadTaskList}). This list of tasks is guaranteed to always have all its task
+ * content loaded.
+ *
+ * @return the current list of tasks w/ all content loaded
+ */
+ public ArrayList<Task> getCurrentTaskList() {
+ return mTaskList;
+ }
+
+ /**
+ * Fetches the most recent tasks and updates the task list asynchronously. In addition it
+ * loads the content for each task (icon and label). The callback and task list being updated
+ * only occur when all task content is fully loaded and up-to-date.
+ *
+ * @param onTasksLoadedCallback callback for when the tasks are fully loaded. Done on the UI
+ * thread
+ */
+ public void loadTaskList(@Nullable Consumer<ArrayList<Task>> onTasksLoadedCallback) {
+ if (mRecentsModel.isTaskListValid(mTaskListChangeId)) {
+ // Current task list is already up to date. No need to update.
+ if (onTasksLoadedCallback != null) {
+ onTasksLoadedCallback.accept(mTaskList);
+ }
+ return;
+ }
+ // TODO: Look into error checking / more robust handling for when things go wrong.
+ mTaskListChangeId = mRecentsModel.getTasks(tasks -> {
+ // Reverse tasks to put most recent at the bottom of the view
+ Collections.reverse(tasks);
+ // Load task content
+ loadTaskContents(tasks, () -> {
+ mTaskList = tasks;
+ if (onTasksLoadedCallback != null) {
+ onTasksLoadedCallback.accept(mTaskList);
+ }
+ });
+ });
+ }
+
+ /**
+ * Loads task content for a list of tasks, including the label and the icon. Uses the list of
+ * tasks since the last load as a cache for loaded content.
+ *
+ * @param tasksToLoad list of tasks that need to load their content
+ * @param onLoadedCallback runnable to run after all tasks have loaded their content
+ */
+ private void loadTaskContents(ArrayList<Task> tasksToLoad,
+ @Nullable Runnable onLoadedCallback) {
+ AtomicInteger loadRequestsCount = new AtomicInteger(0);
+ for (Task task : tasksToLoad) {
+ int index = mTaskList.indexOf(task);
+ if (index >= 0) {
+ // If we've already loaded the task and have its content then just copy it over.
+ Task loadedTask = mTaskList.get(index);
+ task.titleDescription = loadedTask.titleDescription;
+ task.icon = loadedTask.icon;
+ } else {
+ // Otherwise, load the content in the background.
+ loadRequestsCount.getAndIncrement();
+ mRecentsModel.getIconCache().updateIconInBackground(task, loadedTask -> {
+ if (loadRequestsCount.decrementAndGet() == 0 && onLoadedCallback != null) {
+ onLoadedCallback.run();
+ }
+ });
+ }
+ }
+ if (loadRequestsCount.get() == 0 && onLoadedCallback != null) {
+ onLoadedCallback.run();
+ }
+ }
+}
diff --git a/go/quickstep/src/com/android/quickstep/views/IconRecentsView.java b/go/quickstep/src/com/android/quickstep/views/IconRecentsView.java
index 15da10c..afb0540 100644
--- a/go/quickstep/src/com/android/quickstep/views/IconRecentsView.java
+++ b/go/quickstep/src/com/android/quickstep/views/IconRecentsView.java
@@ -27,11 +27,8 @@
import androidx.recyclerview.widget.RecyclerView;
import com.android.launcher3.R;
-import com.android.quickstep.RecentsModel;
import com.android.quickstep.TaskAdapter;
-import com.android.systemui.shared.recents.model.Task;
-
-import java.util.ArrayList;
+import com.android.quickstep.TaskListLoader;
/**
* Root view for the icon recents view. Acts as the main interface to the rest of the Launcher code
@@ -77,13 +74,12 @@
*/
@ViewDebug.ExportedProperty(category = "launcher")
- // TODO: Write a recents task list observer that creates/updates tasks and signals task adapter.
- private static final ArrayList<Task> DUMMY_TASK_LIST = new ArrayList<>();
private final Context mContext;
private float mTranslationYFactor;
private TaskAdapter mTaskAdapter;
private RecyclerView mTaskRecyclerView;
+ private TaskListLoader mTaskLoader;
public IconRecentsView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -93,13 +89,30 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mTaskAdapter = new TaskAdapter(DUMMY_TASK_LIST);
+ mTaskLoader = new TaskListLoader(mContext);
+ mTaskAdapter = new TaskAdapter(mTaskLoader);
mTaskRecyclerView = findViewById(R.id.recent_task_recycler_view);
mTaskRecyclerView.setAdapter(mTaskAdapter);
mTaskRecyclerView.setLayoutManager(
new LinearLayoutManager(mContext, VERTICAL, true /* reverseLayout */));
}
+ /**
+ * Logic for when we know we are going to overview/recents and will be putting up the recents
+ * view. This should be used to prepare recents (e.g. load any task data, etc.) before it
+ * becomes visible.
+ *
+ * TODO: Hook this up for fallback recents activity as well
+ */
+ public void onBeginTransitionToOverview() {
+ // Load any task changes
+ mTaskLoader.loadTaskList(tasks -> {
+ // TODO: Put up some loading UI while task content is loading. May have to do something
+ // smarter when animating from app to overview.
+ mTaskAdapter.notifyDataSetChanged();
+ });
+ }
+
public void setTranslationYFactor(float translationFactor) {
mTranslationYFactor = translationFactor;
setTranslationY(computeTranslationYForFactor(mTranslationYFactor));