Add loader for recents Go.

This CL introduces a loader specific to recents Go that utilizes the
underlying recents model already built in. The class is responsible for
maintaining the data source for the recycler view and also loading the
task list and content. We also provide a hook into the recents view
class to call a load when the transition to recents starts.

Bug: 114136250
Test: Build Launcher3GoIconRecents
Change-Id: I22ce6f767852b0f37961e2fd06dfcb6475c91235
This commit is contained in:
Kevin 2019-02-28 11:08:54 -08:00
parent ba39c84664
commit 45f81fd732
4 changed files with 155 additions and 15 deletions

View File

@ -19,14 +19,12 @@ package com.android.launcher3.uioverrides;
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
@ -49,6 +47,12 @@ public class OverviewState extends LauncherState {
return new float[] {1f, 0f};
}
@Override
public void onStateEnabled(Launcher launcher) {
IconRecentsView recentsView = launcher.getOverviewPanel();
recentsView.onBeginTransitionToOverview();
}
@Override
public PageAlphaProvider getWorkspacePageAlphaProvider(Launcher launcher) {
return new PageAlphaProvider(DEACCEL_2) {

View File

@ -33,10 +33,10 @@ public final class TaskAdapter extends Adapter<TaskHolder> {
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 @@ public final class TaskAdapter extends Adapter<TaskHolder> {
@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);
}
}

View File

@ -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();
}
}
}

View File

@ -27,11 +27,8 @@ import androidx.recyclerview.widget.LinearLayoutManager;
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 @@ public final class IconRecentsView extends FrameLayout {
*/
@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 @@ public final class IconRecentsView extends FrameLayout {
@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));