From b06ff838089f227289c90342b0cd0d4940602e12 Mon Sep 17 00:00:00 2001 From: Jordan Silva Date: Wed, 21 Aug 2024 10:19:41 +0000 Subject: [PATCH] Move DesktopTask to front of RecentsView (1/2) This CL updates the DesktopTasks in the RecentsView to be displayed after the focused task, separated from the other tasks in the grid. The DesktopTasks will be larger, following the same size used for focused tasks. It was necessary to do the following changes to support DesktopTask at the front of the list. 1. Sort the GroupTasks in applyLoadPlan to move DesktopTasks after all other tasks. 2. Update the target page to take into account the DesktopTasks after the running task. 3. updateGridProperties had to support DesktopTask and Focused Task to be positioned at the front of the list. This function updates view translations to support the grid with two rows and rebalacing the position after a task is dimissed. 4. Update the max and min page scroll. Updated getFirstViewIndex to check for a DesktopTaskView, and if it doesn't exist, it uses the focused task as reference. 5. TaskView.updateTaskSize was updated to prevent DesktopTaskView being resized. This change makes DesktopTaskView to have the same size of our current focused task. 6. Update several places using focused task to use isLargeTile. Bug: 353947137 Fix: 353947516 Fix: 353947467 Fix: 353947334 Flag: com.android.launcher3.enable_large_desktop_windowing_tile Test: OverviewDesktopTaskImageTest Change-Id: Ic7c0d8340ca259e8644de180aa6859a3c968d66e --- aconfig/launcher_overview.aconfig | 8 + .../TaskViewTouchController.java | 4 +- .../quickstep/TaskShortcutFactory.java | 8 +- .../quickstep/util/RecentsViewUtils.kt | 71 ++++++++ .../views/DigitalWellBeingToast.java | 2 +- .../android/quickstep/views/RecentsView.java | 164 +++++++++++------- ...iewHelper.kt => RecentsViewModelHelper.kt} | 8 +- .../quickstep/views/TaskMenuViewWithArrow.kt | 2 +- .../com/android/quickstep/views/TaskView.kt | 28 +-- 9 files changed, 211 insertions(+), 84 deletions(-) create mode 100644 quickstep/src/com/android/quickstep/util/RecentsViewUtils.kt rename quickstep/src/com/android/quickstep/views/{RecentsViewHelper.kt => RecentsViewModelHelper.kt} (92%) diff --git a/aconfig/launcher_overview.aconfig b/aconfig/launcher_overview.aconfig index 11740ee97c..e11b00c675 100644 --- a/aconfig/launcher_overview.aconfig +++ b/aconfig/launcher_overview.aconfig @@ -31,3 +31,11 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "enable_large_desktop_windowing_tile" + namespace: "launcher_overview" + description: "Makes the desktop tiles larger and moves them to the front of the list in Overview." + bug: "353947137" +} + diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java index eafc5b6fe7..202276e1e9 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java @@ -181,7 +181,7 @@ public abstract class TaskViewTouchController): List { + val (desktopTasks, otherTasks) = tasks.partition { it.taskViewType == TaskViewType.DESKTOP } + return otherTasks + desktopTasks + } + + fun getFocusedTaskIndex(taskGroups: List): Int { + // The focused task index is placed after the desktop tasks views. + return if (enableLargeDesktopWindowingTile()) { + taskGroups.count { it.taskViewType == TaskViewType.DESKTOP } + } else { + 0 + } + } + + /** + * Counts [numChildren] that are [DesktopTaskView] instances. + * + * @param numChildren Quantity of children to transverse + * @param getTaskViewAt Function that provides a TaskView given an index + */ + fun getDesktopTaskViewCount(numChildren: Int, getTaskViewAt: (Int) -> TaskView?): Int = + (0 until numChildren).count { getTaskViewAt(it) is DesktopTaskView } + + /** + * Returns the first TaskView that should be displayed as a large tile. + * + * @param numChildren Quantity of children to transverse + * @param getTaskViewAt Function that provides a TaskView given an index + */ + fun getFirstLargeTaskView(numChildren: Int, getTaskViewAt: (Int) -> TaskView?): TaskView? { + return (0 until numChildren).firstNotNullOfOrNull { index -> + val taskView = getTaskViewAt(index) + if (taskView?.isLargeTile == true) taskView else null + } + } +} diff --git a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java index 9f268a0420..8b87718163 100644 --- a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java +++ b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java @@ -191,7 +191,7 @@ public final class DigitalWellBeingToast { private @SplitBannerConfig int getSplitBannerConfig() { if (mSplitBounds == null || !mContainer.getDeviceProfile().isTablet - || mTaskView.isFocusedTask()) { + || mTaskView.isLargeTile()) { return SPLIT_BANNER_FULLSCREEN; } diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index bb2a12f87e..e05349756a 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -37,6 +37,7 @@ import static com.android.launcher3.AbstractFloatingView.getTopOpenViewWithType; import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS; import static com.android.launcher3.Flags.enableAdditionalHomeAnimations; import static com.android.launcher3.Flags.enableGridOnlyOverview; +import static com.android.launcher3.Flags.enableLargeDesktopWindowingTile; import static com.android.launcher3.Flags.enableRefactorTaskThumbnail; import static com.android.launcher3.LauncherAnimUtils.SUCCESS_TRANSITION_PROGRESS; import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA; @@ -211,6 +212,7 @@ import com.android.quickstep.util.GroupTask; import com.android.quickstep.util.LayoutUtils; import com.android.quickstep.util.RecentsAtomicAnimationFactory; import com.android.quickstep.util.RecentsOrientedState; +import com.android.quickstep.util.RecentsViewUtils; import com.android.quickstep.util.SplitAnimationController.Companion.SplitAnimInitProps; import com.android.quickstep.util.SplitAnimationTimings; import com.android.quickstep.util.SplitSelectStateController; @@ -254,8 +256,8 @@ import java.util.stream.Collectors; * @param : the container that should host recents view * @param : the type of base state that will be used */ - -public abstract class RecentsView> extends PagedView implements Insettable, TaskThumbnailCache.HighResLoadingState.HighResLoadingStateChangedCallback, TaskVisualsChangeListener { @@ -656,7 +658,7 @@ public abstract class RecentsView new RecentsRotationStateRepositoryImpl(mOrientationState)); @@ -1685,10 +1689,10 @@ public abstract class RecentsView taskGroups) { if (mPendingAnimation != null) { - mPendingAnimation.addEndListener(success -> applyLoadPlan(taskGroups)); + final List finalTaskGroups = taskGroups; + mPendingAnimation.addEndListener(success -> applyLoadPlan(finalTaskGroups)); return; } @@ -1824,7 +1832,7 @@ public abstract class RecentsView= 0; i--) { @@ -1900,11 +1913,14 @@ public abstract class RecentsView 0) { - newFocusedTaskView = getTaskViewAt(0); + int newFocusedTaskViewIndex = mRecentsViewUtils.getFocusedTaskIndex(taskGroups); + if (newFocusedTaskView == null && getTaskViewCount() > newFocusedTaskViewIndex) { + newFocusedTaskView = getTaskViewAt(newFocusedTaskViewIndex); } - mFocusedTaskViewId = newFocusedTaskView != null && !enableGridOnlyOverview() - ? newFocusedTaskView.getTaskViewId() : INVALID_TASK_ID; + + setFocusedTaskViewId(newFocusedTaskView != null && !enableGridOnlyOverview() + ? newFocusedTaskView.getTaskViewId() : INVALID_TASK_ID); + updateTaskSize(); updateChildTaskOrientations(); @@ -1944,8 +1960,8 @@ public abstract class RecentsView 0) { - targetPage = indexOfChild(requireTaskViewAt(0)); + } else if (getTaskViewCount() > newFocusedTaskViewIndex) { + targetPage = indexOfChild(requireTaskViewAt(newFocusedTaskViewIndex)); } } if (targetPage != -1 && mCurrentPage != targetPage) { @@ -1970,6 +1986,7 @@ public abstract class RecentsView 1; boolean needDesktopTask = hasDesktopTask(runningTasks); @@ -2926,7 +2947,11 @@ public abstract class RecentsView setCurrentPage(getRunningTaskIndex())); setRunningTaskViewShowScreenshot(false); setRunningTaskHidden(runningTaskTileHidden); @@ -2978,6 +3003,10 @@ public abstract class RecentsView largeTasksIndices = new HashSet<>(); int focusedTaskShift = 0; - int focusedTaskWidthAndSpacing = 0; + int largeTaskWidthAndSpacing = 0; int snappedTaskRowWidth = 0; int snappedPage = isKeyboardTaskFocusPending() ? mKeyboardTaskFocusIndex : getNextPage(); TaskView snappedTaskView = getTaskViewAt(snappedPage); @@ -3095,12 +3125,11 @@ public abstract class RecentsView focusedTaskIndex) { // For tasks after the focused task, shift by focused task's width and spacing. gridTranslations[i] += - mIsRtl ? focusedTaskWidthAndSpacing : -focusedTaskWidthAndSpacing; + mIsRtl ? largeTaskWidthAndSpacing : -largeTaskWidthAndSpacing; } else { // For task before the focused task, accumulate the width and spacing to // calculate the distance focused task need to shift. @@ -3152,7 +3187,7 @@ public abstract class RecentsView= 0; j--) { - if (j == focusedTaskIndex) { + if (largeTasksIndices.contains(j)) { continue; } widthOffset += requireTaskViewAt(j).getLayoutParams().width + mPageSpacing; @@ -3171,7 +3206,7 @@ public abstract class RecentsView= 0; j--) { - if (j == focusedTaskIndex) { + if (largeTasksIndices.contains(j)) { continue; } widthOffset += requireTaskViewAt(j).getLayoutParams().width + mPageSpacing; @@ -3221,6 +3256,16 @@ public abstract class RecentsView 0 && mTopRowIdSet.size() >= (taskCount - 1) / 2f; + !mTopRowIdSet.isEmpty() && mTopRowIdSet.size() >= (taskCount - 1) / 2f; // Pick the next focused task from the preferred row. for (int i = 0; i < taskCount; i++) { TaskView taskView = requireTaskViewAt(i); - if (taskView == dismissedTaskView) { + if (taskView == dismissedTaskView || taskView.isLargeTile()) { continue; } boolean isTopRow = mTopRowIdSet.contains(taskView.getTaskViewId()); @@ -4017,9 +4061,9 @@ public abstract class RecentsView 0; - if (isModalGridWithoutFocusedTask) { + boolean shouldCalculateOffsetForAllTasks = showAsGrid + && (enableGridOnlyOverview() || enableLargeDesktopWindowingTile()) + && mTaskModalness > 0; + if (shouldCalculateOffsetForAllTasks) { modalMidpoint = indexOfChild(mSelectedTask); } @@ -4638,7 +4685,7 @@ public abstract class RecentsView getEventDispatcher(float navbarRotation) { diff --git a/quickstep/src/com/android/quickstep/views/RecentsViewHelper.kt b/quickstep/src/com/android/quickstep/views/RecentsViewModelHelper.kt similarity index 92% rename from quickstep/src/com/android/quickstep/views/RecentsViewHelper.kt rename to quickstep/src/com/android/quickstep/views/RecentsViewModelHelper.kt index e8c971857c..5b71da10b0 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsViewHelper.kt +++ b/quickstep/src/com/android/quickstep/views/RecentsViewModelHelper.kt @@ -27,8 +27,8 @@ import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.cancel import kotlinx.coroutines.launch -/** Helper for [RecentsView] to interact with coroutine. */ -class RecentsViewHelper(private val recentsViewModel: RecentsViewModel) { +/** Helper for [RecentsView] to interact with the [RecentsViewModel]. */ +class RecentsViewModelHelper(private val recentsViewModel: RecentsViewModel) { private lateinit var viewAttachedScope: CoroutineScope fun onAttachedToWindow() { @@ -43,7 +43,7 @@ class RecentsViewHelper(private val recentsViewModel: RecentsViewModel) { fun switchToScreenshot( taskView: TaskView, recentsAnimationController: RecentsAnimationController, - onFinishRunnable: Runnable + onFinishRunnable: Runnable, ) { val updatedThumbnails = taskView.taskContainers.associate { @@ -55,7 +55,7 @@ class RecentsViewHelper(private val recentsViewModel: RecentsViewModel) { fun switchToScreenshot( taskView: TaskView, updatedThumbnails: Map?, - onFinishRunnable: Runnable + onFinishRunnable: Runnable, ) { // Update recentsViewModel and apply the thumbnailOverride ASAP, before waiting inside // viewAttachedScope. diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt index 158ae331a8..19d706fbb7 100644 --- a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt +++ b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt @@ -99,7 +99,7 @@ class TaskMenuViewWithArrow : ArrowPopup where T : RecentsViewContainer, T private var optionMeasuredHeight = 0 private val arrowHorizontalPadding: Int get() = - if (taskView.isFocusedTask) + if (taskView.isLargeTile) resources.getDimensionPixelSize(R.dimen.task_menu_horizontal_padding) else 0 diff --git a/quickstep/src/com/android/quickstep/views/TaskView.kt b/quickstep/src/com/android/quickstep/views/TaskView.kt index 176a538d48..50a1356681 100644 --- a/quickstep/src/com/android/quickstep/views/TaskView.kt +++ b/quickstep/src/com/android/quickstep/views/TaskView.kt @@ -49,6 +49,7 @@ import com.android.launcher3.Flags.enableCursorHoverStates import com.android.launcher3.Flags.enableFocusOutline import com.android.launcher3.Flags.enableGridOnlyOverview import com.android.launcher3.Flags.enableHoverOfChildElementsInTaskview +import com.android.launcher3.Flags.enableLargeDesktopWindowingTile import com.android.launcher3.Flags.enableOverviewIconMenu import com.android.launcher3.Flags.enableRefactorTaskThumbnail import com.android.launcher3.R @@ -108,7 +109,7 @@ constructor( defStyleRes: Int = 0, focusBorderAnimator: BorderAnimator? = null, hoverBorderAnimator: BorderAnimator? = null, - type: TaskViewType = TaskViewType.SINGLE + private val type: TaskViewType = TaskViewType.SINGLE, ) : FrameLayout(context, attrs), ViewPool.Reusable { /** * Used in conjunction with [onTaskListVisibilityChanged], providing more granularity on which @@ -133,13 +134,15 @@ constructor( val isGridTask: Boolean /** Returns whether the task is part of overview grid and not being focused. */ - get() = container.deviceProfile.isTablet && !isFocusedTask + get() = container.deviceProfile.isTablet && !isLargeTile val isRunningTask: Boolean get() = this === recentsView?.runningTaskView - val isFocusedTask: Boolean - get() = this === recentsView?.focusedTaskView + val isLargeTile: Boolean + get() = + this == recentsView?.focusedTaskView || + (enableLargeDesktopWindowingTile() && type == TaskViewType.DESKTOP) val taskCornerRadius: Float get() = currentFullscreenParams.cornerRadius @@ -521,7 +524,7 @@ constructor( public override fun onFocusChanged( gainFocus: Boolean, direction: Int, - previouslyFocusedRect: Rect? + previouslyFocusedRect: Rect?, ) { super.onFocusChanged(gainFocus, direction, previouslyFocusedRect) if (borderEnabled) { @@ -682,7 +685,7 @@ constructor( open fun bind( task: Task, orientedState: RecentsOrientedState, - taskOverlayFactory: TaskOverlayFactory + taskOverlayFactory: TaskOverlayFactory, ) { cancelPendingLoadTasks() @@ -707,7 +710,7 @@ constructor( @IdRes iconViewId: Int, @IdRes showWindowViewId: Int, @StagePosition stagePosition: Int, - taskOverlayFactory: TaskOverlayFactory + taskOverlayFactory: TaskOverlayFactory, ): TaskContainer { val thumbnailViewDeprecated: TaskThumbnailViewDeprecated = findViewById(thumbnailViewId)!! val snapshotView = @@ -777,7 +780,7 @@ constructor( fun updateTaskSize( lastComputedTaskSize: Rect, lastComputedGridTaskSize: Rect, - lastComputedCarouselTaskSize: Rect + lastComputedCarouselTaskSize: Rect, ) { val thumbnailPadding = container.deviceProfile.overviewTaskThumbnailTopMarginPx val taskWidth = lastComputedTaskSize.width() @@ -789,9 +792,10 @@ constructor( if (container.deviceProfile.isTablet) { val boxWidth: Int val boxHeight: Int - if (isFocusedTask) { - // Task will be focused and should use focused task size. Use focusTaskRatio - // that is associated with the original orientation of the focused task. + + // Focused task and Desktop tasks should use focusTaskRatio that is associated + // with the original orientation of the focused task. + if (isLargeTile) { boxWidth = taskWidth boxHeight = taskHeight } else { @@ -1334,7 +1338,7 @@ constructor( private fun computeAndSetIconTouchDelegate( view: TaskViewIcon, tempCenterCoordinates: FloatArray, - transformingTouchDelegate: TransformingTouchDelegate + transformingTouchDelegate: TransformingTouchDelegate, ) { val viewHalfWidth = view.width / 2f val viewHalfHeight = view.height / 2f