Merge "Show ASAP for Recents Go and load content after" into ub-launcher3-master
This commit is contained in:
commit
7c1d69e515
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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,13 +88,43 @@ 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());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue