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

Commit 7c1d69e5 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Show ASAP for Recents Go and load content after" into ub-launcher3-master

parents 09b91447 b589241f
Loading
Loading
Loading
Loading
+14 −2
Original line number Diff line number Diff line
@@ -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
+6 −5
Original line number Diff line number Diff line
@@ -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();
    }

    /**
+60 −56
Original line number Diff line number Diff line
@@ -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,64 +88,56 @@ 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);
        });
    }

    /**
     * Removes the task from the current task list.
     * 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
     */
    void removeTask(Task task) {
        mTaskList.remove(task);
    public void loadTaskIconAndLabel(Task task, @Nullable Runnable onLoadedCallback) {
        mRecentsModel.getIconCache().updateIconInBackground(task,
                loadedTask -> onLoadedCallback.run());
    }

    /**
     * Clears the current task list.
     * 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
     */
    void clearAllTasks() {
        mTaskList.clear();
    public void loadTaskThumbnail(Task task, @Nullable Runnable onLoadedCallback) {
        mRecentsModel.getThumbnailCache().updateThumbnailInBackground(task,
                thumbnail -> onLoadedCallback.run());
    }

    /**
     * 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
     * Removes the task from the current task list.
     */
    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());
    void removeTask(Task task) {
        mTaskList.remove(task);
    }

            // Load the thumbnail. May return immediately and synchronously if the thumbnail is
            // cached.
            mRecentsModel.getThumbnailCache().updateThumbnailInBackground(task,
                    thumbnail -> itemLoadedRunnable.run());
        }
    /**
     * Clears the current task list.
     */
    void clearAllTasks() {
        mTaskList.clear();
    }
}
+36 −6
Original line number Diff line number Diff line
@@ -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);
    }