diff --git a/quickstep/src/com/android/quickstep/util/RecentsViewUtils.kt b/quickstep/src/com/android/quickstep/util/RecentsViewUtils.kt index 595aa0077b..be1af64f02 100644 --- a/quickstep/src/com/android/quickstep/util/RecentsViewUtils.kt +++ b/quickstep/src/com/android/quickstep/util/RecentsViewUtils.kt @@ -28,9 +28,17 @@ import com.android.systemui.shared.recents.model.ThumbnailData * and extracted functions from RecentsView to facilitate the implementation of unit tests. */ class RecentsViewUtils { + /** Takes a screenshot of all [taskView] and return map of taskId to the screenshot */ + fun screenshotTasks( + taskView: TaskView, + recentsAnimationController: RecentsAnimationController, + ): Map = + taskView.taskContainers.associate { + it.task.key.id to recentsAnimationController.screenshotTask(it.task.key.id) + } /** - * Sort task groups to move desktop tasks to the end of the list. + * Sorts task groups to move desktop tasks to the end of the list. * * @param tasks List of group tasks to be sorted. * @return Sorted list of GroupTasks to be used in the RecentsView. @@ -40,6 +48,7 @@ class RecentsViewUtils { return otherTasks + desktopTasks } + /** Returns the expected index of the focus task. */ fun getFocusedTaskIndex(taskGroups: List): Int { // The focused task index is placed after the desktop tasks views. return if (enableLargeDesktopWindowingTile()) { @@ -49,12 +58,8 @@ class RecentsViewUtils { } } - /** - * Counts [TaskView]s that are [DesktopTaskView] instances. - * - * @param taskViews List of [TaskView]s - */ - fun getDesktopTaskViewCount(taskViews: List): Int = + /** Counts [TaskView]s that are [DesktopTaskView] instances. */ + fun getDesktopTaskViewCount(taskViews: Iterable): Int = taskViews.count { it is DesktopTaskView } /** Returns a list of all large TaskView Ids from [TaskView]s */ @@ -66,18 +71,64 @@ class RecentsViewUtils { * * @param taskViews List of [TaskView]s */ - fun getFirstLargeTaskView(taskViews: List): TaskView? = + fun getFirstLargeTaskView(taskViews: Iterable): TaskView? = taskViews.firstOrNull { it.isLargeTile } - fun screenshotTasks( - taskView: TaskView, - recentsAnimationController: RecentsAnimationController, - ): Map = - taskView.taskContainers.associate { - it.task.key.id to recentsAnimationController.screenshotTask(it.task.key.id) + /** Returns the last TaskView that should be displayed as a large tile. */ + fun getLastLargeTaskView(taskViews: Iterable): TaskView? = + taskViews.lastOrNull { it.isLargeTile } + + /** Returns the first [TaskView], with some tasks possibly hidden in the carousel. */ + fun getFirstTaskViewInCarousel( + nonRunningTaskCategoryHidden: Boolean, + taskViews: Iterable, + runningTaskView: TaskView?, + ): TaskView? = + taskViews.firstOrNull { + it.isVisibleInCarousel(runningTaskView, nonRunningTaskCategoryHidden) + } + + /** Returns the last [TaskView], with some tasks possibly hidden in the carousel. */ + fun getLastTaskViewInCarousel( + nonRunningTaskCategoryHidden: Boolean, + taskViews: Iterable, + runningTaskView: TaskView?, + ): TaskView? = + taskViews.lastOrNull { + it.isVisibleInCarousel(runningTaskView, nonRunningTaskCategoryHidden) } /** Returns the current list of [TaskView] children. */ - fun getTaskViews(taskViewCount: Int, requireTaskViewAt: (Int) -> TaskView): List = + fun getTaskViews(taskViewCount: Int, requireTaskViewAt: (Int) -> TaskView): Iterable = (0 until taskViewCount).map(requireTaskViewAt) + + /** Apply attachAlpha to all [TaskView] accordingly to different conditions. */ + fun applyAttachAlpha( + taskViews: Iterable, + runningTaskView: TaskView?, + runningTaskTileHidden: Boolean, + nonRunningTaskCategoryHidden: Boolean, + ) { + taskViews.forEach { taskView -> + val isVisible = + if (taskView == runningTaskView) !runningTaskTileHidden + else taskView.isVisibleInCarousel(runningTaskView, nonRunningTaskCategoryHidden) + taskView.attachAlpha = if (isVisible) 1f else 0f + } + } + + private fun TaskView.isVisibleInCarousel( + runningTaskView: TaskView?, + nonRunningTaskCategoryHidden: Boolean, + ): Boolean = + if (!nonRunningTaskCategoryHidden) true + else if (runningTaskView == null) true else getCategory() == runningTaskView.getCategory() + + private fun TaskView.getCategory(): TaskViewCategory = + if (this is DesktopTaskView) TaskViewCategory.DESKTOP else TaskViewCategory.FULL_SCREEN + + private enum class TaskViewCategory { + FULL_SCREEN, + DESKTOP, + } } diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index e37e036857..bb46a2c3ed 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -681,6 +681,7 @@ public abstract class RecentsView< protected int mRunningTaskViewId = -1; private int mTaskViewIdCount; protected boolean mRunningTaskTileHidden; + private boolean mNonRunningTaskCategoryHidden; @Nullable private Task[] mTmpRunningTasks; protected int mFocusedTaskViewId = INVALID_TASK_ID; @@ -2094,14 +2095,10 @@ public abstract class RecentsView< simulator.fullScreenProgress.value = 0; simulator.recentsViewScale.value = 1; }); - // Similar to setRunningTaskHidden below, reapply the state before runningTaskView is - // null. - if (!mRunningTaskShowScreenshot) { - setRunningTaskViewShowScreenshot(mRunningTaskShowScreenshot); - } - if (mRunningTaskTileHidden) { - setRunningTaskHidden(mRunningTaskTileHidden); - } + // Reapply runningTask related attributes as they might have been reset by + // resetViewTransforms(). + setRunningTaskViewShowScreenshot(mRunningTaskShowScreenshot); + applyAttachAlpha(); updateCurveProperties(); // Update the set of visible task's data @@ -2650,10 +2647,6 @@ public abstract class RecentsView< return getTaskViewFromTaskViewId(mFocusedTaskViewId); } - private @Nullable TaskView getFirstLargeTaskView() { - return mUtils.getFirstLargeTaskView(getTaskViews()); - } - @Nullable private TaskView getTaskViewFromTaskViewId(int taskViewId) { if (taskViewId == -1) { @@ -2749,7 +2742,10 @@ public abstract class RecentsView< showCurrentTask(mActiveGestureRunningTasks); setEnableFreeScroll(false); setEnableDrawingLiveTile(false); - setRunningTaskHidden(!shouldUpdateRunningTaskAlpha()); + setRunningTaskHidden(true); + if (enableLargeDesktopWindowingTile()) { + setNonRunningTaskCategoryHidden(true); + } setTaskIconScaledDown(true); } @@ -2888,6 +2884,9 @@ public abstract class RecentsView< setEnableDrawingLiveTile(mCurrentGestureEndTarget == GestureState.GestureEndTarget.RECENTS); Log.d(TAG, "onGestureAnimationEnd - mEnableDrawingLiveTile: " + mEnableDrawingLiveTile); setRunningTaskHidden(false); + if (enableLargeDesktopWindowingTile()) { + setNonRunningTaskCategoryHidden(false); + } animateUpTaskIconScale(); animateActionsViewIn(); @@ -3043,13 +3042,27 @@ public abstract class RecentsView< if (runningTask == null) { return; } - runningTask.setStableAlpha(isHidden ? 0 : mContentAlpha); + applyAttachAlpha(); if (!isHidden) { AccessibilityManagerCompat.sendCustomAccessibilityEvent( runningTask, AccessibilityEvent.TYPE_VIEW_FOCUSED, null); } } + /** + * Hides the tasks that has a different category (Fullscreen/Desktop) from the running task. + */ + public void setNonRunningTaskCategoryHidden(boolean isHidden) { + mNonRunningTaskCategoryHidden = isHidden; + updateMinAndMaxScrollX(); + applyAttachAlpha(); + } + + private void applyAttachAlpha() { + mUtils.applyAttachAlpha(getTaskViews(), getRunningTaskView(), mRunningTaskTileHidden, + mNonRunningTaskCategoryHidden); + } + private void setRunningTaskViewShowScreenshot(boolean showScreenshot) { setRunningTaskViewShowScreenshot(showScreenshot, /*updatedThumbnails=*/null); } @@ -4447,11 +4460,7 @@ public abstract class RecentsView< alpha = Utilities.boundToRange(alpha, 0, 1); mContentAlpha = alpha; - TaskView runningTaskView = getRunningTaskView(); for (TaskView taskView : getTaskViews()) { - if (runningTaskView != null && mRunningTaskTileHidden && taskView == runningTaskView) { - continue; - } taskView.setStableAlpha(alpha); } mClearAllButton.setContentAlpha(mContentAlpha); @@ -4564,7 +4573,7 @@ public abstract class RecentsView< /** * Returns the current list of [TaskView] children. */ - private List getTaskViews() { + private Iterable getTaskViews() { return mUtils.getTaskViews(getTaskViewCount(), this::requireTaskViewAt); } @@ -5794,26 +5803,42 @@ public abstract class RecentsView< } private int getFirstViewIndex() { - TaskView firstTaskView = mShowAsGridLastOnLayout ? getFirstLargeTaskView() : null; - return firstTaskView != null ? indexOfChild(firstTaskView) : 0; + final TaskView firstView; + if (mShowAsGridLastOnLayout) { + // For grid Overivew, it always start if a large tile (focused task or desktop task) if + // they exist, otherwise it start with the first task. + TaskView firstLargeTaskView = mUtils.getFirstLargeTaskView(getTaskViews()); + if (firstLargeTaskView != null) { + firstView = firstLargeTaskView; + } else { + firstView = getTaskViewAt(0); + } + } else { + firstView = mUtils.getFirstTaskViewInCarousel(mNonRunningTaskCategoryHidden, + getTaskViews(), getRunningTaskView()); + } + return indexOfChild(firstView); } private int getLastViewIndex() { + final View lastView; if (!mDisallowScrollToClearAll) { - return indexOfChild(mClearAllButton); + // When ClearAllButton is present, it always end with ClearAllButton. + lastView = mClearAllButton; + } else if (mShowAsGridLastOnLayout) { + // When ClearAllButton is absent, for the grid Overview, it always end with a grid task + // if they exist, otherwise it ends with a large tile (focused task or desktop task). + TaskView lastGridTaskView = getLastGridTaskView(); + if (lastGridTaskView != null) { + lastView = lastGridTaskView; + } else { + lastView = mUtils.getLastLargeTaskView(getTaskViews()); + } + } else { + lastView = mUtils.getLastTaskViewInCarousel(mNonRunningTaskCategoryHidden, + getTaskViews(), getRunningTaskView()); } - - if (!mShowAsGridLastOnLayout) { - return getTaskViewCount() - 1; - } - - TaskView lastGridTaskView = getLastGridTaskView(); - if (lastGridTaskView != null) { - return indexOfChild(lastGridTaskView); - } - - // Returns focus task if there are no grid tasks. - return indexOfChild(getFirstLargeTaskView()); + return indexOfChild(lastView); } /** diff --git a/quickstep/src/com/android/quickstep/views/TaskView.kt b/quickstep/src/com/android/quickstep/views/TaskView.kt index 291ccef258..2ed6ae66c8 100644 --- a/quickstep/src/com/android/quickstep/views/TaskView.kt +++ b/quickstep/src/com/android/quickstep/views/TaskView.kt @@ -82,7 +82,6 @@ import com.android.quickstep.TaskViewUtils import com.android.quickstep.orientation.RecentsPagedOrientationHandler import com.android.quickstep.recents.di.RecentsDependencies import com.android.quickstep.recents.di.get -import com.android.quickstep.task.thumbnail.TaskThumbnailView import com.android.quickstep.task.viewmodel.TaskViewModel import com.android.quickstep.util.ActiveGestureErrorDetector import com.android.quickstep.util.ActiveGestureLog @@ -397,7 +396,7 @@ constructor( } get() = taskViewAlpha.get(ALPHA_INDEX_STABLE).value - protected var attachAlpha + var attachAlpha set(value) { taskViewAlpha.get(ALPHA_INDEX_ATTACH).value = value } @@ -606,6 +605,7 @@ constructor( override fun onRecycle() { resetPersistentViewTransforms() + attachAlpha = 1f // Clear any references to the thumbnail (it will be re-read either from the cache or the // system on next bind) if (!enableRefactorTaskThumbnail()) { @@ -1587,10 +1587,7 @@ constructor( resetViewTransforms() } - fun getTaskContainerForTaskThumbnailView(taskThumbnailView: TaskThumbnailView): TaskContainer? = - taskContainers.firstOrNull { it.thumbnailView == taskThumbnailView } - - open fun resetViewTransforms() { + fun resetViewTransforms() { // fullscreenTranslation and accumulatedTranslation should not be reset, as // resetViewTransforms is called during QuickSwitch scrolling. dismissTranslationX = 0f @@ -1606,7 +1603,6 @@ constructor( } dismissScale = 1f translationZ = 0f - attachAlpha = 1f setIconScaleAndDim(1f) setColorTint(0f, 0) }