diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchControllerDeprecated.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchControllerDeprecated.java index b1a36c7665..f26bd13586 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchControllerDeprecated.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchControllerDeprecated.java @@ -239,7 +239,7 @@ public class TaskViewTouchControllerDeprecated< pa = new PendingAnimation(maxDuration); mRecentsView.createTaskDismissAnimation(pa, mTaskBeingDragged, true /* animateTaskView */, true /* removeTask */, maxDuration, - false /* dismissingForSplitSelection*/); + false /* dismissingForSplitSelection*/, false /* isExpressiveDismiss */); mEndDisplacement = -secondaryTaskDimension; } else { diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java index f426bf5124..d8662f274d 100644 --- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java +++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java @@ -136,7 +136,8 @@ public class FallbackRecentsView setCurrentTask(-1)); AnimatorPlaybackController controller = pa.createPlaybackController(); controller.dispatchOnStart(); diff --git a/quickstep/src/com/android/quickstep/views/RecentsDismissUtils.kt b/quickstep/src/com/android/quickstep/views/RecentsDismissUtils.kt index 3430b39ac1..4ce18f50a1 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsDismissUtils.kt +++ b/quickstep/src/com/android/quickstep/views/RecentsDismissUtils.kt @@ -21,6 +21,7 @@ import androidx.dynamicanimation.animation.FloatPropertyCompat import androidx.dynamicanimation.animation.FloatValueHolder import androidx.dynamicanimation.animation.SpringAnimation import androidx.dynamicanimation.animation.SpringForce +import com.android.launcher3.Flags.enableGridOnlyOverview import com.android.launcher3.R import com.android.launcher3.Utilities.boundToRange import com.android.launcher3.touch.SingleAxisSwipeDetector @@ -31,6 +32,7 @@ import com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY import com.google.android.msdl.data.model.MSDLToken import com.google.android.msdl.domain.InteractionProperties import kotlin.math.abs +import kotlin.math.roundToInt /** * Helper class for [RecentsView]. This util class contains refactored and extracted functions from @@ -76,11 +78,18 @@ class RecentsDismissUtils(private val recentsView: RecentsView<*, *>) { } .addEndListener { _, _, _, _ -> if (isDismissing) { - recentsView.dismissTaskView( - draggedTaskView, - /* animateTaskView = */ false, - /* removeTask = */ true, - ) + if (!recentsView.showAsGrid() || enableGridOnlyOverview()) { + runTaskGridReflowSpringAnimation( + draggedTaskView, + getDismissedTaskGapForReflow(draggedTaskView), + ) + } else { + recentsView.dismissTaskView( + draggedTaskView, + /* animateTaskView = */ false, + /* removeTask = */ true, + ) + } } else { recentsView.onDismissAnimationEnds() } @@ -160,8 +169,8 @@ class RecentsDismissUtils(private val recentsView: RecentsView<*, *>) { if (recentsView.showAsGrid()) { val taskGridNavHelper = TaskGridNavHelper( - recentsView.topRowIdArray, - recentsView.bottomRowIdArray, + recentsView.mUtils.getTopRowIdArray(), + recentsView.mUtils.getBottomRowIdArray(), recentsView.mUtils.getLargeTaskViewIds(), hasAddDesktopButton = false, ) @@ -237,6 +246,19 @@ class RecentsDismissUtils(private val recentsView: RecentsView<*, *>) { ) } + private fun createExpressiveGridReflowSpringForce( + finalPosition: Float = Float.MAX_VALUE + ): SpringForce { + val resourceProvider = DynamicResource.provider(recentsView.mContainer) + return SpringForce(finalPosition) + .setDampingRatio( + resourceProvider.getFloat(R.dimen.expressive_dismiss_task_trans_x_damping_ratio) + ) + .setStiffness( + resourceProvider.getFloat(R.dimen.expressive_dismiss_task_trans_x_stiffness) + ) + } + /** * Plays a haptic as the dragged task view settles back into its rest state. * @@ -286,6 +308,197 @@ class RecentsDismissUtils(private val recentsView: RecentsView<*, *>) { .apply { animateToFinalPosition(RECENTS_SCALE_SPRING_MULTIPLIER * scale) } } + /** Animates with springs the TaskViews beyond the dismissed task to fill the gap it left. */ + private fun runTaskGridReflowSpringAnimation( + dismissedTaskView: TaskView, + dismissedTaskGap: Float, + ) { + // Empty spring animation exists for conditional start, and to drive neighboring springs. + val springAnimationDriver = + SpringAnimation(FloatValueHolder()) + .setSpring(createExpressiveGridReflowSpringForce(finalPosition = dismissedTaskGap)) + val towardsStart = if (recentsView.isRtl) dismissedTaskGap < 0 else dismissedTaskGap > 0 + + // Build the chains of Spring Animations + when { + !recentsView.showAsGrid() -> { + buildDismissReflowSpringAnimationChain( + getTasksToReflow( + recentsView.mUtils.taskViews.toList(), + dismissedTaskView, + towardsStart, + ), + dismissedTaskGap, + previousSpring = springAnimationDriver, + ) + } + dismissedTaskView.isLargeTile -> { + val lastSpringAnimation = + buildDismissReflowSpringAnimationChain( + getTasksToReflow( + recentsView.mUtils.getLargeTaskViews(), + dismissedTaskView, + towardsStart, + ), + dismissedTaskGap, + previousSpring = springAnimationDriver, + ) + // Add all top and bottom grid tasks when animating towards the end of the grid. + if (!towardsStart) { + buildDismissReflowSpringAnimationChain( + recentsView.mUtils.getTopRowTaskViews(), + dismissedTaskGap, + previousSpring = lastSpringAnimation, + ) + buildDismissReflowSpringAnimationChain( + recentsView.mUtils.getBottomRowTaskViews(), + dismissedTaskGap, + previousSpring = lastSpringAnimation, + ) + } + } + recentsView.isOnGridBottomRow(dismissedTaskView) -> { + buildDismissReflowSpringAnimationChain( + getTasksToReflow( + recentsView.mUtils.getBottomRowTaskViews(), + dismissedTaskView, + towardsStart, + ), + dismissedTaskGap, + previousSpring = springAnimationDriver, + ) + } + else -> { + buildDismissReflowSpringAnimationChain( + getTasksToReflow( + recentsView.mUtils.getTopRowTaskViews(), + dismissedTaskView, + towardsStart, + ), + dismissedTaskGap, + previousSpring = springAnimationDriver, + ) + } + } + + // Start animations and remove the dismissed task at the end, dismiss immediately if no + // neighboring tasks exist. + val runGridEndAnimationAndRelayout = { + recentsView.expressiveDismissTaskView(dismissedTaskView) + } + springAnimationDriver?.apply { + addEndListener { _, _, _, _ -> runGridEndAnimationAndRelayout() } + animateToFinalPosition(dismissedTaskGap) + } ?: runGridEndAnimationAndRelayout() + } + + private fun getDismissedTaskGapForReflow(dismissedTaskView: TaskView): Float { + val screenStart = recentsView.pagedOrientationHandler.getPrimaryScroll(recentsView) + val screenEnd = + screenStart + recentsView.pagedOrientationHandler.getMeasuredSize(recentsView) + val taskStart = + recentsView.pagedOrientationHandler.getChildStart(dismissedTaskView) + + dismissedTaskView.getOffsetAdjustment(recentsView.showAsGrid()) + val taskSize = + recentsView.pagedOrientationHandler.getMeasuredSize(dismissedTaskView) * + dismissedTaskView.getSizeAdjustment(recentsView.showAsFullscreen()) + val taskEnd = taskStart + taskSize + + val isDismissedTaskBeyondEndOfScreen = + if (recentsView.isRtl) taskEnd > screenEnd else taskStart < screenStart + if ( + dismissedTaskView.isLargeTile && + isDismissedTaskBeyondEndOfScreen && + recentsView.mUtils.getLargeTileCount() == 1 + ) { + return with(recentsView) { + pagedOrientationHandler.getPrimaryScroll(this) - + getScrollForPage(indexOfChild(mUtils.getFirstNonDesktopTaskView())) + } + .toFloat() + } + + // If current page is beyond last TaskView's index, use last TaskView to calculate offset. + val lastTaskViewIndex = recentsView.indexOfChild(recentsView.mUtils.getLastTaskView()) + val currentPage = recentsView.currentPage.coerceAtMost(lastTaskViewIndex) + val dismissHorizontalFactor = + when { + dismissedTaskView.isGridTask -> 1f + currentPage == lastTaskViewIndex -> -1f + recentsView.indexOfChild(dismissedTaskView) < currentPage -> -1f + else -> 1f + } * (if (recentsView.isRtl) 1f else -1f) + + return (dismissedTaskView.layoutParams.width + recentsView.pageSpacing) * + dismissHorizontalFactor + } + + private fun getTasksToReflow( + taskViews: List, + dismissedTaskView: TaskView, + towardsStart: Boolean, + ): List { + val dismissedTaskViewIndex = taskViews.indexOf(dismissedTaskView) + if (dismissedTaskViewIndex == -1) { + return emptyList() + } + return if (towardsStart) { + taskViews.take(dismissedTaskViewIndex).reversed() + } else { + taskViews.takeLast(taskViews.size - dismissedTaskViewIndex - 1) + } + } + + private fun willTaskBeVisibleAfterDismiss(taskView: TaskView, taskTranslation: Int): Boolean { + val screenStart = recentsView.pagedOrientationHandler.getPrimaryScroll(recentsView) + val screenEnd = + screenStart + recentsView.pagedOrientationHandler.getMeasuredSize(recentsView) + return recentsView.isTaskViewWithinBounds( + taskView, + screenStart, + screenEnd, + /* taskViewTranslation = */ taskTranslation, + ) + } + + /** Builds a chain of spring animations for task reflow after dismissal */ + private fun buildDismissReflowSpringAnimationChain( + taskViews: Iterable, + dismissedTaskGap: Float, + previousSpring: SpringAnimation, + ): SpringAnimation { + var lastTaskViewSpring = previousSpring + taskViews + .filter { taskView -> + willTaskBeVisibleAfterDismiss(taskView, dismissedTaskGap.roundToInt()) + } + .forEach { taskView -> + val taskViewSpringAnimation = + SpringAnimation( + taskView, + FloatPropertyCompat.createFloatPropertyCompat( + taskView.primaryDismissTranslationProperty + ), + ) + .setSpring(createExpressiveGridReflowSpringForce(dismissedTaskGap)) + // Update live tile on spring animation. + if (taskView.isRunningTask && recentsView.enableDrawingLiveTile) { + taskViewSpringAnimation.addUpdateListener { _, _, _ -> + recentsView.runActionOnRemoteHandles { remoteTargetHandle -> + remoteTargetHandle.taskViewSimulator.taskPrimaryTranslation.value = + taskView.primaryDismissTranslationProperty.get(taskView) + } + recentsView.redrawLiveTile() + } + } + lastTaskViewSpring.addUpdateListener { _, value, _ -> + taskViewSpringAnimation.animateToFinalPosition(value) + } + lastTaskViewSpring = taskViewSpringAnimation + } + return lastTaskViewSpring + } + private companion object { // The additional damping to apply to tasks further from the dismissed task. private const val ADDITIONAL_DISMISS_DAMPING_RATIO = 0.15f diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index 54d5e954e4..4cd6c9ddd4 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -38,7 +38,6 @@ import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAG import static com.android.launcher3.Flags.enableAdditionalHomeAnimations; import static com.android.launcher3.Flags.enableDesktopExplodedView; import static com.android.launcher3.Flags.enableDesktopTaskAlphaAnimation; -import static com.android.launcher3.Flags.enableExpressiveDismissTaskMotion; import static com.android.launcher3.Flags.enableGridOnlyOverview; import static com.android.launcher3.Flags.enableLargeDesktopWindowingTile; import static com.android.launcher3.Flags.enableRefactorTaskThumbnail; @@ -605,7 +604,7 @@ public abstract class RecentsView< private float mTaskThumbnailSplashAlpha = 0; private boolean mBorderEnabled = false; private boolean mShowAsGridLastOnLayout = false; - private final IntSet mTopRowIdSet = new IntSet(); + protected final IntSet mTopRowIdSet = new IntSet(); private int mClearAllShortTotalWidthTranslation = 0; // The GestureEndTarget that is still in progress. @@ -1511,7 +1510,7 @@ public abstract class RecentsView< @Nullable private TaskView getLastGridTaskView() { - return getLastGridTaskView(getTopRowIdArray(), getBottomRowIdArray()); + return getLastGridTaskView(mUtils.getTopRowIdArray(), mUtils.getBottomRowIdArray()); } @Nullable @@ -1557,7 +1556,7 @@ public abstract class RecentsView< * @param taskViewTranslation taskView is considered within bounds if either translated or * original position of taskView is within screen bounds. */ - private boolean isTaskViewWithinBounds(TaskView taskView, int screenStart, int screenEnd, + protected boolean isTaskViewWithinBounds(TaskView taskView, int screenStart, int screenEnd, int taskViewTranslation) { int taskStart = getPagedOrientationHandler().getChildStart(taskView) + (int) taskView.getOffsetAdjustment(showAsGrid()); @@ -3556,7 +3555,7 @@ public abstract class RecentsView< setGridProgress(mGridProgress); } - private boolean isSameGridRow(TaskView taskView1, TaskView taskView2) { + protected boolean isSameGridRow(TaskView taskView1, TaskView taskView2) { if (taskView1 == null || taskView2 == null) { return false; } @@ -3760,11 +3759,13 @@ public abstract class RecentsView< * @param duration duration of the animation * @param dismissingForSplitSelection task dismiss animation is used for entering split * selection state from app icon + * @param isExpressiveDismiss runs expressive animations controlled via + * {@link RecentsDismissUtils} */ public void createTaskDismissAnimation(PendingAnimation anim, @Nullable TaskView dismissedTaskView, boolean animateTaskView, boolean shouldRemoveTask, long duration, - boolean dismissingForSplitSelection) { + boolean dismissingForSplitSelection, boolean isExpressiveDismiss) { if (mPendingAnimation != null) { mPendingAnimation.createPlaybackController().dispatchOnCancel().dispatchOnEnd(); } @@ -3882,7 +3883,7 @@ public abstract class RecentsView< } } if (lastGridTaskView != null && (lastGridTaskView.isVisibleToUser() || ( - enableExpressiveDismissTaskMotion() && lastGridTaskView == dismissedTaskView))) { + isExpressiveDismiss && lastGridTaskView == dismissedTaskView))) { // After dismissal, animate translation of the remaining tasks to fill any gap left // between the end of the grid and the clear all button. Only animate if the clear // all button is visible or would become visible after dismissal. @@ -4022,12 +4023,17 @@ public abstract class RecentsView< lastTaskViewIndex); int scrollDiff = newScroll[i] - oldScroll[i] + offset; if (scrollDiff != 0) { - translateTaskWhenDismissed( - child, - Math.abs(i - dismissedIndex), - scrollDiff, - anim, - splitTimings); + if (!isExpressiveDismiss) { + translateTaskWhenDismissed( + child, + Math.abs(i - dismissedIndex), + scrollDiff, + anim, + splitTimings); + } + if (child instanceof TaskView taskView) { + mTaskViewsDismissPrimaryTranslations.put(taskView, scrollDiffPerPage); + } needsCurveUpdates = true; } } else if (child instanceof TaskView taskView) { @@ -4112,13 +4118,16 @@ public abstract class RecentsView< : finalTranslation + (mIsRtl ? -mLastComputedTaskSize.right : mLastComputedTaskSize.right); } - Animator dismissAnimator = ObjectAnimator.ofFloat(taskView, - taskView.getPrimaryDismissTranslationProperty(), - startTranslation, finalTranslation); - dismissAnimator.setInterpolator( - clampToProgress(dismissInterpolator, animationStartProgress, - animationEndProgress)); - anim.add(dismissAnimator); + // Expressive dismiss will animate the translations of taskViews itself. + if (!isExpressiveDismiss) { + Animator dismissAnimator = ObjectAnimator.ofFloat(taskView, + taskView.getPrimaryDismissTranslationProperty(), + startTranslation, finalTranslation); + dismissAnimator.setInterpolator( + clampToProgress(dismissInterpolator, animationStartProgress, + animationEndProgress)); + anim.add(dismissAnimator); + } mTaskViewsDismissPrimaryTranslations.put(taskView, (int) finalTranslation); distanceFromDismissedTask++; } @@ -4218,8 +4227,8 @@ public abstract class RecentsView< boolean isSnappedTaskInTopRow = mTopRowIdSet.contains( snappedTaskViewId); IntArray taskViewIdArray = - isSnappedTaskInTopRow ? getTopRowIdArray() - : getBottomRowIdArray(); + isSnappedTaskInTopRow ? mUtils.getTopRowIdArray() + : mUtils.getBottomRowIdArray(); int snappedIndex = taskViewIdArray.indexOf(snappedTaskViewId); taskViewIdArray.removeValue(dismissedTaskViewId); if (finalNextFocusedTaskView != null) { @@ -4234,8 +4243,8 @@ public abstract class RecentsView< // dismissed row, // snap to the same column in the other grid row IntArray inverseRowTaskViewIdArray = - isSnappedTaskInTopRow ? getBottomRowIdArray() - : getTopRowIdArray(); + isSnappedTaskInTopRow ? mUtils.getBottomRowIdArray() + : mUtils.getTopRowIdArray(); if (snappedIndex < inverseRowTaskViewIdArray.size()) { taskViewIdToSnapTo = inverseRowTaskViewIdArray.get( snappedIndex); @@ -4317,8 +4326,8 @@ public abstract class RecentsView< } } - IntArray topRowIdArray = getTopRowIdArray(); - IntArray bottomRowIdArray = getBottomRowIdArray(); + IntArray topRowIdArray = mUtils.getTopRowIdArray(); + IntArray bottomRowIdArray = mUtils.getBottomRowIdArray(); if (finalSnapToLastTask) { // If snapping to last task, find the last task after dismissal. pageToSnapTo = indexOfChild( @@ -4441,10 +4450,6 @@ public abstract class RecentsView< animationEndProgress ) ); - - if (view instanceof TaskView) { - mTaskViewsDismissPrimaryTranslations.put((TaskView) view, scrollDiffPerPage); - } if (mEnableDrawingLiveTile && view instanceof TaskView && ((TaskView) view).isRunningTask()) { pendingAnimation.addOnFrameCallback(() -> { @@ -4488,41 +4493,6 @@ public abstract class RecentsView< return true; } - /** - * Returns all the tasks in the top row, without the focused task - */ - IntArray getTopRowIdArray() { - if (mTopRowIdSet.isEmpty()) { - return new IntArray(0); - } - IntArray topArray = new IntArray(mTopRowIdSet.size()); - for (TaskView taskView : getTaskViews()) { - int taskViewId = taskView.getTaskViewId(); - if (mTopRowIdSet.contains(taskViewId)) { - topArray.add(taskViewId); - } - } - return topArray; - } - - /** - * Returns all the tasks in the bottom row, without the focused task - */ - IntArray getBottomRowIdArray() { - int bottomRowIdArraySize = getBottomRowTaskCountForTablet(); - if (bottomRowIdArraySize <= 0) { - return new IntArray(0); - } - IntArray bottomArray = new IntArray(bottomRowIdArraySize); - for (TaskView taskView : getTaskViews()) { - int taskViewId = taskView.getTaskViewId(); - if (!mTopRowIdSet.contains(taskViewId) && !taskView.isLargeTile()) { - bottomArray.add(taskViewId); - } - } - return bottomArray; - } - /** * Iterate the grid by columns instead of by TaskView index, starting after the focused task and * up to the last balanced column. @@ -4533,8 +4503,8 @@ public abstract class RecentsView< if (mTopRowIdSet.isEmpty()) return null; // return earlier TaskView lastVisibleTaskView = null; - IntArray topRowIdArray = getTopRowIdArray(); - IntArray bottomRowIdArray = getBottomRowIdArray(); + IntArray topRowIdArray = mUtils.getTopRowIdArray(); + IntArray bottomRowIdArray = mUtils.getBottomRowIdArray(); int balancedColumns = Math.min(bottomRowIdArray.size(), topRowIdArray.size()); for (int i = 0; i < balancedColumns; i++) { @@ -4629,8 +4599,9 @@ public abstract class RecentsView< } // Init task grid nav helper with top/bottom id arrays. - TaskGridNavHelper taskGridNavHelper = new TaskGridNavHelper(getTopRowIdArray(), - getBottomRowIdArray(), mUtils.getLargeTaskViewIds(), mAddDesktopButton != null); + TaskGridNavHelper taskGridNavHelper = new TaskGridNavHelper(mUtils.getTopRowIdArray(), + mUtils.getBottomRowIdArray(), mUtils.getLargeTaskViewIds(), + mAddDesktopButton != null); // Get current page's task view ID. TaskView currentPageTaskView = getCurrentPageTaskView(); @@ -4689,7 +4660,15 @@ public abstract class RecentsView< public void dismissTaskView(TaskView taskView, boolean animateTaskView, boolean removeTask) { PendingAnimation pa = new PendingAnimation(DISMISS_TASK_DURATION); createTaskDismissAnimation(pa, taskView, animateTaskView, removeTask, DISMISS_TASK_DURATION, - false /* dismissingForSplitSelection*/); + false /* dismissingForSplitSelection*/, false /* isExpressiveDismiss */); + runDismissAnimation(pa); + } + + protected void expressiveDismissTaskView(TaskView taskView) { + PendingAnimation pa = new PendingAnimation(DISMISS_TASK_DURATION); + createTaskDismissAnimation(pa, taskView, false /* animateTaskView */, true /* removeTask */, + DISMISS_TASK_DURATION, false /* dismissingForSplitSelection*/, + true /* isExpressiveDismiss */); runDismissAnimation(pa); } @@ -5418,7 +5397,7 @@ public abstract class RecentsView< } // Splitting from Overview for fullscreen task createTaskDismissAnimation(builder, mSplitHiddenTaskView, true, false, duration, - true /* dismissingForSplitSelection*/); + true /* dismissingForSplitSelection*/, false /* isExpressiveDismiss */); } else { // Splitting from Home TaskView currentPageTaskView = getTaskViewAt(mCurrentPage); @@ -5426,7 +5405,7 @@ public abstract class RecentsView< // display correct animation in split mode if (currentPageTaskView instanceof DesktopTaskView) { createTaskDismissAnimation(builder, null, true, false, duration, - true /* dismissingForSplitSelection*/); + true /* dismissingForSplitSelection*/, false /* isExpressiveDismiss */); } else { createInitialSplitSelectAnimation(builder); } @@ -6420,7 +6399,8 @@ public abstract class RecentsView< * Returns how many pixels the page is offset from its scroll position. */ private int getOffsetFromScrollPosition(int pageIndex) { - return getOffsetFromScrollPosition(pageIndex, getTopRowIdArray(), getBottomRowIdArray()); + return getOffsetFromScrollPosition(pageIndex, mUtils.getTopRowIdArray(), + mUtils.getBottomRowIdArray()); } private int getOffsetFromScrollPosition( @@ -6719,7 +6699,7 @@ public abstract class RecentsView< .displayOverviewTasksAsGrid(mContainer.getDeviceProfile())); } - private boolean showAsFullscreen() { + protected boolean showAsFullscreen() { return mOverviewFullscreenEnabled && mCurrentGestureEndTarget != GestureState.GestureEndTarget.RECENTS; } diff --git a/quickstep/src/com/android/quickstep/views/RecentsViewUtils.kt b/quickstep/src/com/android/quickstep/views/RecentsViewUtils.kt index 31ae890d97..1c37986584 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsViewUtils.kt +++ b/quickstep/src/com/android/quickstep/views/RecentsViewUtils.kt @@ -83,6 +83,25 @@ class RecentsViewUtils(private val recentsView: RecentsView<*, *>) { /** Returns a list of all large TaskView Ids from [TaskView]s */ fun getLargeTaskViewIds(): List = taskViews.filter { it.isLargeTile }.map { it.taskViewId } + /** Returns a list of all large TaskViews [TaskView]s */ + fun getLargeTaskViews(): List = taskViews.filter { it.isLargeTile } + + /** Returns all the TaskViews in the top row, without the focused task */ + fun getTopRowTaskViews(): List = + taskViews.filter { recentsView.mTopRowIdSet.contains(it.taskViewId) } + + /** Returns all the task Ids in the top row, without the focused task */ + fun getTopRowIdArray(): IntArray = getTopRowTaskViews().map { it.taskViewId }.toIntArray() + + /** Returns all the TaskViews in the bottom row, without the focused task */ + fun getBottomRowTaskViews(): List = + taskViews.filter { !recentsView.mTopRowIdSet.contains(it.taskViewId) && !it.isLargeTile } + + /** Returns all the task Ids in the bottom row, without the focused task */ + fun getBottomRowIdArray(): IntArray = getBottomRowTaskViews().map { it.taskViewId }.toIntArray() + + private fun List.toIntArray() = IntArray(size).apply { this@toIntArray.forEach(::add) } + /** Counts [TaskView]s that are large tiles. */ fun getLargeTileCount(): Int = taskViews.count { it.isLargeTile } @@ -266,8 +285,8 @@ class RecentsViewUtils(private val recentsView: RecentsView<*, *>) { return } getRowRect(getFirstLargeTaskView(), getLastLargeTaskView(), outTaskViewRowRect) - getRowRect(recentsView.getTopRowIdArray(), outTopRowRect) - getRowRect(recentsView.getBottomRowIdArray(), outBottomRowRect) + getRowRect(getTopRowIdArray(), outTopRowRect) + getRowRect(getBottomRowIdArray(), outBottomRowRect) // Expand large tile Rect to include space between top/bottom row. val nonEmptyRowRect = diff --git a/quickstep/src/com/android/quickstep/views/TaskView.kt b/quickstep/src/com/android/quickstep/views/TaskView.kt index 3819772243..ab785924dd 100644 --- a/quickstep/src/com/android/quickstep/views/TaskView.kt +++ b/quickstep/src/com/android/quickstep/views/TaskView.kt @@ -220,7 +220,7 @@ constructor( SPLIT_SELECT_TRANSLATION_Y, ) - protected val primaryDismissTranslationProperty: FloatProperty + val primaryDismissTranslationProperty: FloatProperty get() = pagedOrientationHandler.getPrimaryValue(DISMISS_TRANSLATION_X, DISMISS_TRANSLATION_Y) @@ -743,9 +743,10 @@ constructor( // The TaskView lifecycle is starts the ViewModel during onBind, and cleans it in // onRecycle. So it should be initialized at this point. TaskView Lifecycle: // `bind` -> `onBind` -> onAttachedToWindow() -> onDetachFromWindow -> onRecycle - coroutineJobs += coroutineScope.launch(dispatcherProvider.main) { - viewModel!!.state.collectLatest(::updateTaskViewState) - } + coroutineJobs += + coroutineScope.launch(dispatcherProvider.main) { + viewModel!!.state.collectLatest(::updateTaskViewState) + } } } @@ -1653,7 +1654,7 @@ constructor( protected fun getScrollAdjustment(gridEnabled: Boolean) = if (gridEnabled) gridTranslationX else nonGridTranslationX - protected fun getOffsetAdjustment(gridEnabled: Boolean) = getScrollAdjustment(gridEnabled) + fun getOffsetAdjustment(gridEnabled: Boolean) = getScrollAdjustment(gridEnabled) fun getSizeAdjustment(fullscreenEnabled: Boolean) = if (fullscreenEnabled) nonGridScale else 1f diff --git a/res/values/config.xml b/res/values/config.xml index 1a2ac9e928..c11777e120 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -117,6 +117,8 @@ 0.6 900 + 0.8 + 900