Initial implementation of the AddDesktopButton
Add the AddDesktopButton to the view hierarchy behind the flags.
Flag: com.android.window.flags.enable_multiple_desktops_frontend
com.android.window.flags.enable_multiple_desktops_backend
Bug: 382057498
Test: Manual
Change-Id: I5748d8c18d8f5204fa1fb0717c4a8098bfde1537
diff --git a/quickstep/res/layout/overview_add_desktop_button.xml b/quickstep/res/layout/overview_add_desktop_button.xml
index 2333dd1..e36cf72 100644
--- a/quickstep/res/layout/overview_add_desktop_button.xml
+++ b/quickstep/res/layout/overview_add_desktop_button.xml
@@ -18,7 +18,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:launcher="http://schemas.android.com/apgk/res-auto"
android:id="@+id/add_desktop_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_width="@dimen/add_desktop_button_size"
+ android:layout_height="@dimen/add_desktop_button_size"
android:src="@drawable/ic_desktop_add"
android:padding="10dp" />
\ No newline at end of file
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 493a5b8..b253343 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -106,6 +106,9 @@
<dimen name="recents_clear_all_outline_radius">24dp</dimen>
<dimen name="recents_clear_all_outline_padding">2dp</dimen>
+ <!-- Recents add desktop button -->
+ <dimen name="add_desktop_button_size">56dp</dimen>
+
<!-- The speed in dp/s at which the user needs to be scrolling in recents such that we start
loading full resolution screenshots. -->
<dimen name="recents_fast_fling_velocity">600dp</dimen>
diff --git a/quickstep/src/com/android/quickstep/views/AddDesktopButton.kt b/quickstep/src/com/android/quickstep/views/AddDesktopButton.kt
index f973dd0..1dab18a 100644
--- a/quickstep/src/com/android/quickstep/views/AddDesktopButton.kt
+++ b/quickstep/src/com/android/quickstep/views/AddDesktopButton.kt
@@ -17,8 +17,11 @@
package com.android.quickstep.views
import android.content.Context
+import android.graphics.drawable.ShapeDrawable
+import android.graphics.drawable.shapes.RoundRectShape
import android.util.AttributeSet
import android.widget.ImageButton
+import com.android.launcher3.R
/**
* Button for supporting multiple desktop sessions. The button will be next to the first TaskView
@@ -26,5 +29,21 @@
*/
class AddDesktopButton @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
ImageButton(context, attrs) {
- // TODO(b/382057498): add this button the overview.
+
+ override fun onFinishInflate() {
+ super.onFinishInflate()
+
+ background =
+ ShapeDrawable().apply {
+ shape =
+ RoundRectShape(
+ FloatArray(8) { R.dimen.add_desktop_button_size.toFloat() },
+ null,
+ null,
+ )
+ setTint(
+ resources.getColor(android.R.color.system_surface_bright_light, context.theme)
+ )
+ }
+ }
}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index b6c976d..f8a8c48 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -547,6 +547,8 @@
private final int mSplitPlaceholderSize;
private final int mSplitPlaceholderInset;
private final ClearAllButton mClearAllButton;
+ @Nullable
+ private AddDesktopButton mAddDesktopButton = null;
private final Rect mClearAllButtonDeadZoneRect = new Rect();
private final Rect mTaskViewDeadZoneRect = new Rect();
private final Rect mTopRowDeadZoneRect = new Rect();
@@ -902,6 +904,12 @@
mClearAllButton = (ClearAllButton) LayoutInflater.from(context)
.inflate(R.layout.overview_clear_all_button, this, false);
mClearAllButton.setOnClickListener(this::dismissAllTasks);
+
+ if (DesktopModeStatus.enableMultipleDesktops(mContext)) {
+ mAddDesktopButton = (AddDesktopButton) LayoutInflater.from(context).inflate(
+ R.layout.overview_add_desktop_button, this, false);
+ }
+
mTaskViewPool = new ViewPool<>(context, this, R.layout.task, 20 /* max size */,
10 /* initial size */);
mGroupedTaskViewPool = new ViewPool<>(context, this,
@@ -1880,7 +1888,7 @@
}
mLoadPlanEverApplied = true;
if (taskGroups == null || taskGroups.isEmpty()) {
- removeTasksViewsAndClearAllButton();
+ removeAllTaskViews();
onTaskStackUpdated();
// With all tasks removed, touch handling in PagedView is disabled and we need to reset
// touch state or otherwise values will be obsolete.
@@ -1943,6 +1951,11 @@
taskGroups = mUtils.sortDesktopTasksToFront(taskGroups);
}
+ if (mAddDesktopButton != null) {
+ // Add `mAddDesktopButton` as the first child.
+ addView(mAddDesktopButton);
+ }
+
// Add views as children based on whether it's grouped or single task. Looping through
// taskGroups backwards populates the thumbnail grid from least recent to most recent.
for (int i = taskGroups.size() - 1; i >= 0; i--) {
@@ -2088,13 +2101,14 @@
return mModel.isLoadingTasksInBackground();
}
- private void removeTasksViewsAndClearAllButton() {
+ private void removeAllTaskViews() {
// This handles an edge case where applyLoadPlan happens during a gesture when the only
// Task is one with excludeFromRecents, in which case we should not remove it.
CollectionsKt
.filter(getTaskViews(), taskView -> !isGestureActive() || !taskView.isRunningTask())
.forEach(this::removeView);
if (!hasTaskViews()) {
+ removeView(mAddDesktopButton);
removeView(mClearAllButton);
}
}
@@ -2324,6 +2338,9 @@
float taskAlignmentTranslationY = getTaskAlignmentTranslationY();
mClearAllButton.setTaskAlignmentTranslationY(taskAlignmentTranslationY);
+ if (mAddDesktopButton != null) {
+ mAddDesktopButton.setTranslationY(taskAlignmentTranslationY);
+ }
updateGridProperties();
}
@@ -3006,6 +3023,9 @@
taskView = getTaskViewFromPool(TaskViewType.SINGLE);
taskView.bind(runningTasks[0], mOrientationState, mTaskOverlayFactory);
}
+ if (mAddDesktopButton != null && wasEmpty) {
+ addView(mAddDesktopButton);
+ }
addView(taskView, getRunningTaskExpectedIndex(taskView));
runningTaskViewId = taskView.getTaskViewId();
if (wasEmpty) {
@@ -3426,6 +3446,12 @@
+ snappedTaskNonGridScrollAdjustment);
}
+ if (mAddDesktopButton != null) {
+ mAddDesktopButton.setTranslationX(
+ gridTranslations.get(getFirstTaskView()) - snappedTaskGridTranslationX
+ + snappedTaskNonGridScrollAdjustment);
+ }
+
final TaskView runningTask = getRunningTaskView();
if (showAsGrid() && enableGridOnlyOverview() && runningTask != null) {
runActionOnRemoteHandles(
@@ -4133,6 +4159,7 @@
if (taskCount == 1) {
removeViewInLayout(mClearAllButton);
+ removeViewInLayout(mAddDesktopButton);
if (isHomeTaskDismissed) {
updateEmptyMessage();
} else if (!mSplitSelectStateController.isSplitSelectActive()) {
@@ -4464,7 +4491,7 @@
finishRecentsAnimation(true /* toRecents */, false /* shouldPip */, () -> {
UI_HELPER_EXECUTOR.getHandler().post(
ActivityManagerWrapper.getInstance()::removeAllRecentTasks);
- removeTasksViewsAndClearAllButton();
+ removeAllTaskViews();
startHome();
});
}
@@ -4624,6 +4651,11 @@
taskView.setStableAlpha(alpha);
}
mClearAllButton.setContentAlpha(mContentAlpha);
+
+ // TODO(b/389209338): Handle the visibility of the `mAddDesktopButton`.
+ if (mAddDesktopButton != null) {
+ mAddDesktopButton.setAlpha(mContentAlpha);
+ }
int alphaInt = Math.round(alpha * 255);
mEmptyMessagePaint.setAlpha(alphaInt);
mEmptyIcon.setAlpha(alphaInt);
@@ -4920,9 +4952,11 @@
+ carouselHiddenOffsetSize;
if (child instanceof TaskView taskView) {
taskView.getPrimaryTaskOffsetTranslationProperty().set(taskView, totalTranslationX);
- } else {
+ } else if (child instanceof ClearAllButton) {
getPagedOrientationHandler().getPrimaryViewTranslate().set(child,
totalTranslationX);
+ } else {
+ // TODO(b/389209581): Handle the page offsets update of the 'mAddDesktopButton'.
}
if (mEnableDrawingLiveTile && i == getRunningTaskIndex()) {
runActionOnRemoteHandles(
@@ -6100,6 +6134,13 @@
outPageScrolls[clearAllIndex] = clearAllScroll;
}
+ int addDesktopButtonIndex = indexOfChild(mAddDesktopButton);
+ if (addDesktopButtonIndex != -1 && addDesktopButtonIndex < outPageScrolls.length) {
+ outPageScrolls[addDesktopButtonIndex] =
+ newPageScrolls[addDesktopButtonIndex] + Math.round(
+ mAddDesktopButton.getTranslationX());
+ }
+
int lastTaskScroll = getLastTaskScroll(clearAllScroll, clearAllWidth);
getTaskViews().forEachWithIndexInParent((index, taskView) -> {
float scrollDiff = taskView.getScrollAdjustment(showAsGrid);
diff --git a/res/drawable/ic_desktop_add.xml b/res/drawable/ic_desktop_add.xml
index fa5e0de..d31b04b 100644
--- a/res/drawable/ic_desktop_add.xml
+++ b/res/drawable/ic_desktop_add.xml
@@ -14,8 +14,8 @@
~ limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
+ android:width="24dp"
+ android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path