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