Move clear all to recycler view (1/2)
First part of moving clear all button to recycler view. This CL adds
support in the recycler view adapter for a clear all holder type and
hooks it up to the previous clear all animation.
Adding this breaks several assumptions made externally on the type of
the item and index which will be addressed in the second part.
Bug: 114136250
Test: Builds, testing pending 2nd part
Change-Id: Ib16790028d4e9f520945a987b3dace40d19f2468
(cherry pick from 8573ff04b4
)
This commit is contained in:
parent
56abdd7ade
commit
eda02641a2
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<Button xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/clear_all_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:background="@drawable/clear_all_button"
|
||||
android:gravity="center"
|
||||
android:text="@string/recents_clear_all"
|
||||
android:textAllCaps="false"
|
||||
android:textColor="@color/clear_all_button_text"
|
||||
android:textSize="14sp">
|
||||
</Button>
|
|
@ -19,29 +19,11 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
<LinearLayout
|
||||
android:id="@+id/recent_task_content_view"
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recent_task_recycler_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone">
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recent_task_recycler_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scrollbars="none"/>
|
||||
<Button
|
||||
android:id="@+id/clear_all_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:background="@drawable/clear_all_button"
|
||||
android:gravity="center"
|
||||
android:text="@string/recents_clear_all"
|
||||
android:textAllCaps="false"
|
||||
android:textColor="@color/clear_all_button_text"
|
||||
android:textSize="14sp"/>
|
||||
</LinearLayout>
|
||||
android:scrollbars="none"/>
|
||||
<TextView
|
||||
android:id="@+id/recent_task_empty_view"
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* 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.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
|
||||
|
||||
/**
|
||||
* Holder for clear all button view in task recycler view.
|
||||
*/
|
||||
final class ClearAllHolder extends ViewHolder {
|
||||
public ClearAllHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
}
|
||||
}
|
|
@ -16,12 +16,14 @@
|
|||
package com.android.quickstep;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView.Adapter;
|
||||
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
|
||||
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.quickstep.views.TaskItemView;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
|
@ -34,14 +36,17 @@ import java.util.Optional;
|
|||
* Recycler view adapter that dynamically inflates and binds {@link TaskHolder} instances with the
|
||||
* appropriate {@link Task} from the recents task list.
|
||||
*/
|
||||
public final class TaskAdapter extends Adapter<TaskHolder> {
|
||||
public final class TaskAdapter extends Adapter<ViewHolder> {
|
||||
|
||||
public static final int CHANGE_EVENT_TYPE_EMPTY_TO_CONTENT = 0;
|
||||
public static final int MAX_TASKS_TO_DISPLAY = 6;
|
||||
|
||||
private static final String TAG = "TaskAdapter";
|
||||
private static final int ITEM_TYPE_TASK = 0;
|
||||
private static final int ITEM_TYPE_CLEAR_ALL = 1;
|
||||
private final TaskListLoader mLoader;
|
||||
private TaskActionController mTaskActionController;
|
||||
private OnClickListener mClearAllListener;
|
||||
private boolean mIsShowingLoadingUi;
|
||||
|
||||
public TaskAdapter(@NonNull TaskListLoader loader) {
|
||||
|
@ -52,6 +57,10 @@ public final class TaskAdapter extends Adapter<TaskHolder> {
|
|||
mTaskActionController = taskActionController;
|
||||
}
|
||||
|
||||
public void setOnClearAllClickListener(OnClickListener listener) {
|
||||
mClearAllListener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets all positions in the task adapter to loading views, binding new views if necessary.
|
||||
* This changes the task adapter's view of the data, so the appropriate notify events should be
|
||||
|
@ -65,21 +74,32 @@ public final class TaskAdapter extends Adapter<TaskHolder> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public TaskHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
TaskItemView itemView = (TaskItemView) LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.task_item_view, parent, false);
|
||||
TaskHolder holder = new TaskHolder(itemView);
|
||||
itemView.setOnClickListener(view -> mTaskActionController.launchTask(holder));
|
||||
return holder;
|
||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
switch (viewType) {
|
||||
case ITEM_TYPE_TASK:
|
||||
TaskItemView itemView = (TaskItemView) LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.task_item_view, parent, false);
|
||||
TaskHolder taskHolder = new TaskHolder(itemView);
|
||||
itemView.setOnClickListener(view -> mTaskActionController.launchTask(taskHolder));
|
||||
return taskHolder;
|
||||
case ITEM_TYPE_CLEAR_ALL:
|
||||
Button clearView = (Button) LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.clear_all_button, parent, false);
|
||||
ClearAllHolder clearAllHolder = new ClearAllHolder(clearView);
|
||||
clearView.setOnClickListener(mClearAllListener);
|
||||
return clearAllHolder;
|
||||
default:
|
||||
throw new IllegalArgumentException("No known holder for item type: " + viewType);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(TaskHolder holder, int position) {
|
||||
public void onBindViewHolder(ViewHolder holder, int position) {
|
||||
onBindViewHolderInternal(holder, position, false /* willAnimate */);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull TaskHolder holder, int position,
|
||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position,
|
||||
@NonNull List<Object> payloads) {
|
||||
if (payloads.isEmpty()) {
|
||||
super.onBindViewHolder(holder, position, payloads);
|
||||
|
@ -95,40 +115,60 @@ public final class TaskAdapter extends Adapter<TaskHolder> {
|
|||
}
|
||||
}
|
||||
|
||||
private void onBindViewHolderInternal(@NonNull TaskHolder holder, int position,
|
||||
private void onBindViewHolderInternal(@NonNull ViewHolder holder, int position,
|
||||
boolean willAnimate) {
|
||||
if (mIsShowingLoadingUi) {
|
||||
holder.bindEmptyUi();
|
||||
return;
|
||||
int itemType = getItemViewType(position);
|
||||
switch (itemType) {
|
||||
case ITEM_TYPE_TASK:
|
||||
TaskHolder taskHolder = (TaskHolder) holder;
|
||||
if (mIsShowingLoadingUi) {
|
||||
taskHolder.bindEmptyUi();
|
||||
return;
|
||||
}
|
||||
List<Task> tasks = mLoader.getCurrentTaskList();
|
||||
if (position >= tasks.size()) {
|
||||
// Task list has updated.
|
||||
return;
|
||||
}
|
||||
Task task = tasks.get(position);
|
||||
taskHolder.bindTask(task, willAnimate /* willAnimate */);
|
||||
mLoader.loadTaskIconAndLabel(task, () -> {
|
||||
// Ensure holder still has the same task.
|
||||
if (Objects.equals(Optional.of(task), taskHolder.getTask())) {
|
||||
taskHolder.getTaskItemView().setIcon(task.icon);
|
||||
taskHolder.getTaskItemView().setLabel(task.titleDescription);
|
||||
}
|
||||
});
|
||||
mLoader.loadTaskThumbnail(task, () -> {
|
||||
if (Objects.equals(Optional.of(task), taskHolder.getTask())) {
|
||||
taskHolder.getTaskItemView().setThumbnail(task.thumbnail.thumbnail);
|
||||
}
|
||||
});
|
||||
break;
|
||||
case ITEM_TYPE_CLEAR_ALL:
|
||||
// Nothing to bind.
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("No known holder for item type: " + itemType);
|
||||
}
|
||||
List<Task> tasks = mLoader.getCurrentTaskList();
|
||||
if (position >= tasks.size()) {
|
||||
// Task list has updated.
|
||||
return;
|
||||
}
|
||||
Task task = tasks.get(position);
|
||||
holder.bindTask(task, willAnimate /* willAnimate */);
|
||||
mLoader.loadTaskIconAndLabel(task, () -> {
|
||||
// Ensure holder still has the same task.
|
||||
if (Objects.equals(Optional.of(task), holder.getTask())) {
|
||||
holder.getTaskItemView().setIcon(task.icon);
|
||||
holder.getTaskItemView().setLabel(task.titleDescription);
|
||||
}
|
||||
});
|
||||
mLoader.loadTaskThumbnail(task, () -> {
|
||||
if (Objects.equals(Optional.of(task), holder.getTask())) {
|
||||
holder.getTaskItemView().setThumbnail(task.thumbnail.thumbnail);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
// Bottom is always clear all button.
|
||||
return (position == 0) ? ITEM_TYPE_CLEAR_ALL : ITEM_TYPE_TASK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
// Always at least one for clear all button.
|
||||
int itemCount = 1;
|
||||
if (mIsShowingLoadingUi) {
|
||||
// Show loading version of all items.
|
||||
return MAX_TASKS_TO_DISPLAY;
|
||||
itemCount += MAX_TASKS_TO_DISPLAY;
|
||||
} else {
|
||||
return Math.min(mLoader.getCurrentTaskList().size(), MAX_TASKS_TO_DISPLAY);
|
||||
itemCount += Math.min(mLoader.getCurrentTaskList().size(), MAX_TASKS_TO_DISPLAY);
|
||||
}
|
||||
return itemCount;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,9 +18,6 @@ package com.android.quickstep.views;
|
|||
import static androidx.recyclerview.widget.LinearLayoutManager.VERTICAL;
|
||||
|
||||
import static com.android.quickstep.TaskAdapter.CHANGE_EVENT_TYPE_EMPTY_TO_CONTENT;
|
||||
import static com.android.quickstep.views.TaskLayoutUtils.getClearAllButtonHeight;
|
||||
import static com.android.quickstep.views.TaskLayoutUtils.getClearAllButtonTopBottomMargin;
|
||||
import static com.android.quickstep.views.TaskLayoutUtils.getClearAllButtonWidth;
|
||||
import static com.android.quickstep.views.TaskLayoutUtils.getTaskListHeight;
|
||||
|
||||
import android.animation.Animator;
|
||||
|
@ -114,7 +111,6 @@ public final class IconRecentsView extends FrameLayout {
|
|||
private View mShowingContentView;
|
||||
private View mEmptyView;
|
||||
private View mContentView;
|
||||
private View mClearAllView;
|
||||
private boolean mTransitionedFromApp;
|
||||
private AnimatorSet mLayoutAnimation;
|
||||
private final ArraySet<View> mLayingOutViews = new ArraySet<>();
|
||||
|
@ -141,6 +137,7 @@ public final class IconRecentsView extends FrameLayout {
|
|||
mDeviceProfile = activity.getDeviceProfile();
|
||||
mTaskLoader = new TaskListLoader(mContext);
|
||||
mTaskAdapter = new TaskAdapter(mTaskLoader);
|
||||
mTaskAdapter.setOnClearAllClickListener(view -> animateClearAllTasks());
|
||||
mTaskActionController = new TaskActionController(mTaskLoader, mTaskAdapter);
|
||||
mTaskAdapter.setActionController(mTaskActionController);
|
||||
RecentsModel.INSTANCE.get(context).addThumbnailChangeListener(listener);
|
||||
|
@ -178,7 +175,7 @@ public final class IconRecentsView extends FrameLayout {
|
|||
() -> mTaskRecyclerView.setItemAnimator(new DefaultItemAnimator()));
|
||||
|
||||
mEmptyView = findViewById(R.id.recent_task_empty_view);
|
||||
mContentView = findViewById(R.id.recent_task_content_view);
|
||||
mContentView = mTaskRecyclerView;
|
||||
mTaskAdapter.registerAdapterDataObserver(new AdapterDataObserver() {
|
||||
@Override
|
||||
public void onChanged() {
|
||||
|
@ -190,16 +187,7 @@ public final class IconRecentsView extends FrameLayout {
|
|||
updateContentViewVisibility();
|
||||
}
|
||||
});
|
||||
// TODO: Move clear all button to recycler view so that it can scroll off screen.
|
||||
// TODO: Move layout param logic into onMeasure
|
||||
mClearAllView = findViewById(R.id.clear_all_button);
|
||||
MarginLayoutParams clearAllParams =
|
||||
(MarginLayoutParams) mClearAllView.getLayoutParams();
|
||||
clearAllParams.height = getClearAllButtonHeight(mDeviceProfile);
|
||||
clearAllParams.width = getClearAllButtonWidth(mDeviceProfile);
|
||||
clearAllParams.topMargin = getClearAllButtonTopBottomMargin(mDeviceProfile);
|
||||
clearAllParams.bottomMargin = getClearAllButtonTopBottomMargin(mDeviceProfile);
|
||||
mClearAllView.setOnClickListener(v -> animateClearAllTasks());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -210,7 +198,7 @@ public final class IconRecentsView extends FrameLayout {
|
|||
for (TaskItemView itemView : itemViews) {
|
||||
itemView.setEnabled(enabled);
|
||||
}
|
||||
mClearAllView.setEnabled(enabled);
|
||||
// TODO: Disable clear all button.
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -365,6 +353,7 @@ public final class IconRecentsView extends FrameLayout {
|
|||
* @return array of attached task item views
|
||||
*/
|
||||
private TaskItemView[] getTaskViews() {
|
||||
// TODO: Check that clear all button isn't here..
|
||||
int taskCount = mTaskRecyclerView.getChildCount();
|
||||
TaskItemView[] itemViews = new TaskItemView[taskCount];
|
||||
for (int i = 0; i < taskCount; i ++) {
|
||||
|
|
Loading…
Reference in New Issue