summaryrefslogtreecommitdiffstats
path: root/go
diff options
context:
space:
mode:
authorKevin <kevhan@google.com>2019-03-19 16:59:32 -0700
committerKevin <kevhan@google.com>2019-03-28 18:10:52 -0700
commitb589241fd683cda2da005093c891a89b39fc08a3 (patch)
tree27513c40fd1c16f04e7eb3e91b27923c03282aad /go
parentbd9bd70dcb92206fd40c573a4db7d0fd46abea8a (diff)
downloadandroid_packages_apps_Trebuchet-b589241fd683cda2da005093c891a89b39fc08a3.tar.gz
android_packages_apps_Trebuchet-b589241fd683cda2da005093c891a89b39fc08a3.tar.bz2
android_packages_apps_Trebuchet-b589241fd683cda2da005093c891a89b39fc08a3.zip
Show ASAP for Recents Go and load content after
Recent UX discussion led to decision to show as soon as we have the list and order and then load the content in after as soon as it comes. This introduces API in TaskListLoader to facilitate this and default values for the view when the content is not yet loaded. Bug: 114136250 Test: Go to recents, see content load in Change-Id: I6766cf014e3de78894353614157dbc8798031c2f
Diffstat (limited to 'go')
-rw-r--r--go/quickstep/src/com/android/quickstep/TaskAdapter.java16
-rw-r--r--go/quickstep/src/com/android/quickstep/TaskHolder.java11
-rw-r--r--go/quickstep/src/com/android/quickstep/TaskListLoader.java116
-rw-r--r--go/quickstep/src/com/android/quickstep/views/TaskItemView.java42
4 files changed, 116 insertions, 69 deletions
diff --git a/go/quickstep/src/com/android/quickstep/TaskAdapter.java b/go/quickstep/src/com/android/quickstep/TaskAdapter.java
index e56cc5125..c98eca622 100644
--- a/go/quickstep/src/com/android/quickstep/TaskAdapter.java
+++ b/go/quickstep/src/com/android/quickstep/TaskAdapter.java
@@ -75,8 +75,20 @@ public final class TaskAdapter extends Adapter<TaskHolder> {
// Task list has updated.
return;
}
- holder.bindTask(tasks.get(position));
-
+ Task task = tasks.get(position);
+ holder.bindTask(task);
+ mLoader.loadTaskIconAndLabel(task, () -> {
+ // Ensure holder still has the same task.
+ if (task.equals(holder.getTask())) {
+ holder.getTaskItemView().setIcon(task.icon);
+ holder.getTaskItemView().setLabel(task.titleDescription);
+ }
+ });
+ mLoader.loadTaskThumbnail(task, () -> {
+ if (task.equals(holder.getTask())) {
+ holder.getTaskItemView().setThumbnail(task.thumbnail.thumbnail);
+ }
+ });
}
@Override
diff --git a/go/quickstep/src/com/android/quickstep/TaskHolder.java b/go/quickstep/src/com/android/quickstep/TaskHolder.java
index a89229f2f..744afd766 100644
--- a/go/quickstep/src/com/android/quickstep/TaskHolder.java
+++ b/go/quickstep/src/com/android/quickstep/TaskHolder.java
@@ -35,17 +35,18 @@ public final class TaskHolder extends ViewHolder {
mTaskItemView = itemView;
}
+ public TaskItemView getTaskItemView() {
+ return mTaskItemView;
+ }
+
/**
- * Bind task content to the view. This includes the task icon and title as well as binding
- * input handlers such as which task to launch/remove.
+ * Bind a task to the holder, resetting the view and preparing it for content to load in.
*
* @param task the task to bind to the view
*/
public void bindTask(Task task) {
mTask = task;
- mTaskItemView.setLabel(task.titleDescription);
- mTaskItemView.setIcon(task.icon);
- mTaskItemView.setThumbnail(task.thumbnail.thumbnail);
+ mTaskItemView.resetTaskItemView();
}
/**
diff --git a/go/quickstep/src/com/android/quickstep/TaskListLoader.java b/go/quickstep/src/com/android/quickstep/TaskListLoader.java
index c86c24e8f..1234989d2 100644
--- a/go/quickstep/src/com/android/quickstep/TaskListLoader.java
+++ b/go/quickstep/src/com/android/quickstep/TaskListLoader.java
@@ -25,7 +25,6 @@ import com.android.systemui.shared.recents.model.Task;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
/**
@@ -39,35 +38,48 @@ public final class TaskListLoader {
private ArrayList<Task> mTaskList = new ArrayList<>();
private int mTaskListChangeId;
+ private RecentsModel.TaskThumbnailChangeListener listener = (taskId, thumbnailData) -> {
+ Task foundTask = null;
+ for (Task task : mTaskList) {
+ if (task.key.id == taskId) {
+ foundTask = task;
+ break;
+ }
+ }
+ if (foundTask != null) {
+ foundTask.thumbnail = thumbnailData;
+ }
+ return foundTask;
+ };
public TaskListLoader(Context context) {
mRecentsModel = RecentsModel.INSTANCE.get(context);
+ mRecentsModel.addThumbnailChangeListener(listener);
}
/**
- * Returns the current task list as of the last completed load (see
- * {@link #loadTaskList}) as a read-only list. This list of tasks is guaranteed to always have
- * all its task content loaded.
+ * Returns the current task list as of the last completed load (see {@link #loadTaskList}) as a
+ * read-only list. This list of tasks is not guaranteed to have all content loaded.
*
- * @return the current list of tasks w/ all content loaded
+ * @return the current list of tasks
*/
public List<Task> getCurrentTaskList() {
return Collections.unmodifiableList(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.
+ * Fetches the most recent tasks and updates the task list asynchronously. This call does not
+ * provide guarantees the task content (icon, thumbnail, label) are loaded but will fill in
+ * what it has. May run the callback immediately if there have been no changes in the task
+ * list.
*
- * @param onTasksLoadedCallback callback for when the tasks are fully loaded. Done on the UI
- * thread
+ * @param onLoadedCallback callback to run when task list is loaded
*/
- public void loadTaskList(@Nullable Consumer<ArrayList<Task>> onTasksLoadedCallback) {
+ public void loadTaskList(@Nullable Consumer<ArrayList<Task>> onLoadedCallback) {
if (mRecentsModel.isTaskListValid(mTaskListChangeId)) {
// Current task list is already up to date. No need to update.
- if (onTasksLoadedCallback != null) {
- onTasksLoadedCallback.accept(mTaskList);
+ if (onLoadedCallback != null) {
+ onLoadedCallback.accept(mTaskList);
}
return;
}
@@ -76,16 +88,46 @@ public final class TaskListLoader {
// 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);
+ for (Task task : tasks) {
+ int loadedPos = mTaskList.indexOf(task);
+ if (loadedPos == -1) {
+ continue;
}
- });
+ Task loadedTask = mTaskList.get(loadedPos);
+ task.icon = loadedTask.icon;
+ task.titleDescription = loadedTask.titleDescription;
+ task.thumbnail = loadedTask.thumbnail;
+ }
+ mTaskList = tasks;
+ onLoadedCallback.accept(tasks);
});
}
/**
+ * Load task icon and label asynchronously if it is not already loaded in the task. If the task
+ * already has an icon, this calls the callback immediately.
+ *
+ * @param task task to update with icon + label
+ * @param onLoadedCallback callback to run when task has icon and label
+ */
+ public void loadTaskIconAndLabel(Task task, @Nullable Runnable onLoadedCallback) {
+ mRecentsModel.getIconCache().updateIconInBackground(task,
+ loadedTask -> onLoadedCallback.run());
+ }
+
+ /**
+ * Load thumbnail asynchronously if not already loaded in the task. If the task already has a
+ * thumbnail or if the thumbnail is cached, this calls the callback immediately.
+ *
+ * @param task task to update with the thumbnail
+ * @param onLoadedCallback callback to run when task has thumbnail
+ */
+ public void loadTaskThumbnail(Task task, @Nullable Runnable onLoadedCallback) {
+ mRecentsModel.getThumbnailCache().updateThumbnailInBackground(task,
+ thumbnail -> onLoadedCallback.run());
+ }
+
+ /**
* Removes the task from the current task list.
*/
void removeTask(Task task) {
@@ -98,42 +140,4 @@ public final class TaskListLoader {
void clearAllTasks() {
mTaskList.clear();
}
-
- /**
- * Loads task content for a list of tasks, including the label, icon, and thumbnail. For content
- * that isn't cached, load the content asynchronously in the background.
- *
- * @param tasksToLoad list of tasks that need to load their content
- * @param onFullyLoadedCallback runnable to run after all tasks have loaded their content
- */
- private void loadTaskContents(ArrayList<Task> tasksToLoad,
- @Nullable Runnable onFullyLoadedCallback) {
- // Make two load requests per task, one for the icon/title and one for the thumbnail.
- AtomicInteger loadRequestsCount = new AtomicInteger(tasksToLoad.size() * 2);
- Runnable itemLoadedRunnable = () -> {
- if (loadRequestsCount.decrementAndGet() == 0 && onFullyLoadedCallback != null) {
- onFullyLoadedCallback.run();
- }
- };
- for (Task task : tasksToLoad) {
- // Load icon and title.
- 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;
- itemLoadedRunnable.run();
- } else {
- // Otherwise, load the content in the background.
- mRecentsModel.getIconCache().updateIconInBackground(task,
- loadedTask -> itemLoadedRunnable.run());
- }
-
- // Load the thumbnail. May return immediately and synchronously if the thumbnail is
- // cached.
- mRecentsModel.getThumbnailCache().updateThumbnailInBackground(task,
- thumbnail -> itemLoadedRunnable.run());
- }
- }
}
diff --git a/go/quickstep/src/com/android/quickstep/views/TaskItemView.java b/go/quickstep/src/com/android/quickstep/views/TaskItemView.java
index 373f10791..d831b206a 100644
--- a/go/quickstep/src/com/android/quickstep/views/TaskItemView.java
+++ b/go/quickstep/src/com/android/quickstep/views/TaskItemView.java
@@ -17,6 +17,7 @@ package com.android.quickstep.views;
import android.content.Context;
import android.graphics.Bitmap;
+import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
@@ -24,6 +25,8 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.R;
/**
@@ -31,12 +34,16 @@ import com.android.launcher3.R;
*/
public final class TaskItemView extends LinearLayout {
+ private static final String DEFAULT_LABEL = "...";
+ private final Drawable mDefaultIcon;
private TextView mLabelView;
private ImageView mIconView;
private ImageView mThumbnailView;
public TaskItemView(Context context, AttributeSet attrs) {
super(context, attrs);
+ mDefaultIcon = context.getResources().getDrawable(
+ android.R.drawable.sym_def_app_icon, context.getTheme());
}
@Override
@@ -48,33 +55,56 @@ public final class TaskItemView extends LinearLayout {
}
/**
- * Set the label for the task item.
+ * Resets task item view to default values.
+ */
+ public void resetTaskItemView() {
+ setLabel(DEFAULT_LABEL);
+ setIcon(null);
+ setThumbnail(null);
+ }
+
+ /**
+ * Set the label for the task item. Sets to a default label if null.
*
* @param label task label
*/
- public void setLabel(String label) {
+ public void setLabel(@Nullable String label) {
+ if (label == null) {
+ mLabelView.setText(DEFAULT_LABEL);
+ return;
+ }
mLabelView.setText(label);
}
/**
- * Set the icon for the task item.
+ * Set the icon for the task item. Sets to a default icon if null.
*
* @param icon task icon
*/
- public void setIcon(Drawable icon) {
+ public void setIcon(@Nullable Drawable icon) {
// TODO: Scale the icon up based off the padding on the side
// The icon proper is actually smaller than the drawable and has "padding" on the side for
// the purpose of drawing the shadow, allowing the icon to pop up, so we need to scale the
// view if we want the icon to be flush with the bottom of the thumbnail.
+ if (icon == null) {
+ mIconView.setImageDrawable(mDefaultIcon);
+ return;
+ }
mIconView.setImageDrawable(icon);
}
/**
- * Set the task thumbnail for the task.
+ * Set the task thumbnail for the task. Sets to a default thumbnail if null.
*
* @param thumbnail task thumbnail for the task
*/
- public void setThumbnail(Bitmap thumbnail) {
+ public void setThumbnail(@Nullable Bitmap thumbnail) {
+ if (thumbnail == null) {
+ mThumbnailView.setImageBitmap(null);
+ mThumbnailView.setBackgroundColor(Color.GRAY);
+ return;
+ }
+ mThumbnailView.setBackgroundColor(Color.TRANSPARENT);
mThumbnailView.setImageBitmap(thumbnail);
}