diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchControllerDeprecated.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchControllerDeprecated.java index 57ffd9538d..3905557c8d 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchControllerDeprecated.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchControllerDeprecated.java @@ -246,7 +246,8 @@ public class TaskViewTouchControllerDeprecated< pa = new PendingAnimation(maxDuration); mRecentsView.createTaskDismissAnimation(pa, mTaskBeingDragged, true /* animateTaskView */, true /* removeTask */, maxDuration, - false /* dismissingForSplitSelection*/, false /* isExpressiveDismiss */); + false /* dismissingForSplitSelection*/, false /* isExpressiveDismiss */, + null /* gridEndData */); mEndDisplacement = -secondaryTaskDimension; } else { diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java index fbcf2522b1..b6e41a9efa 100644 --- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java +++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java @@ -143,7 +143,7 @@ public class FallbackRecentsView setCurrentTask(-1)); AnimatorPlaybackController controller = pendingAnimation.createPlaybackController(); controller.dispatchOnStart(); diff --git a/quickstep/src/com/android/quickstep/views/RecentsDismissUtils.kt b/quickstep/src/com/android/quickstep/views/RecentsDismissUtils.kt index e830966180..32ce047db6 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsDismissUtils.kt +++ b/quickstep/src/com/android/quickstep/views/RecentsDismissUtils.kt @@ -29,9 +29,11 @@ import com.android.launcher3.util.MSDLPlayerWrapper import com.android.launcher3.views.ActivityContext import com.android.quickstep.util.TaskGridNavHelper import com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY +import com.android.quickstep.views.TaskView.Companion.GRID_END_TRANSLATION_X import com.google.android.msdl.data.model.MSDLToken import com.google.android.msdl.domain.InteractionProperties import kotlin.math.abs +import kotlin.math.max import kotlin.math.roundToInt import kotlin.math.sign @@ -343,6 +345,15 @@ class RecentsDismissUtils(private val recentsView: RecentsView<*, *>) { ) } + private fun createExpressiveDismissAlphaSpringForce(): SpringForce { + val resourceProvider = DynamicResource.provider(recentsView.mContainer) + return SpringForce() + .setDampingRatio( + resourceProvider.getFloat(R.dimen.expressive_dismiss_effects_damping_ratio) + ) + .setStiffness(resourceProvider.getFloat(R.dimen.expressive_dismiss_effects_stiffness)) + } + /** * Plays a haptic as the dragged task view settles back into its rest state. * @@ -477,16 +488,11 @@ class RecentsDismissUtils(private val recentsView: RecentsView<*, *>) { } } - // Start animations and remove the dismissed task at the end, dismiss immediately if no - // neighboring tasks exist. - val runGridEndAnimationAndRelayout = { dismissDuration: Int -> - recentsView.expressiveDismissTaskView(dismissedTaskView, onEndRunnable, dismissDuration) - } val runImmediately = tasksToReflow.isEmpty() if (runImmediately) { // Play the same haptic as when neighbors spring into place. MSDLPlayerWrapper.INSTANCE.get(recentsView.context)?.playToken(MSDLToken.CANCEL) - runGridEndAnimationAndRelayout(DISMISS_IMMEDIATE_DURATION) + runGridEndTranslation(dismissedTaskView, onEndRunnable, DISMISS_IMMEDIATE_DURATION) } else { addNeighborSettlingSpringAnimations( dismissedTaskView, @@ -498,7 +504,11 @@ class RecentsDismissUtils(private val recentsView: RecentsView<*, *>) { ) springAnimationDriver.apply { addEndListener { _, _, _, _ -> - runGridEndAnimationAndRelayout(DISMISS_DEFAULT_DURATION) + runGridEndTranslation( + dismissedTaskView, + onEndRunnable, + DISMISS_DEFAULT_DURATION, + ) } animateToFinalPosition(dismissedTaskGap) } @@ -587,11 +597,237 @@ class RecentsDismissUtils(private val recentsView: RecentsView<*, *>) { return lastTaskViewSpring } + /** Animates the grid to compensate the clear all gap after dismissal. */ + private fun runGridEndTranslation( + dismissedTaskView: TaskView, + onEndRunnable: () -> Unit, + dismissDuration: Int, + ) { + val runGridEndAnimationAndRelayout = { gridEndData: GridEndData -> + recentsView.expressiveDismissTaskView( + dismissedTaskView, + onEndRunnable, + dismissDuration, + gridEndData, + ) + } + val gridEndData = getGridEndData(dismissedTaskView) + val gridEndOffset = gridEndData.gridEndOffset + if (gridEndOffset == 0f) { + runGridEndAnimationAndRelayout(gridEndData) + return + } + + // Create spring animation to drive all task grid translation simultaneously. + val gridEndSpring = + SpringAnimation(FloatValueHolder()) + .setSpring(createExpressiveGridReflowSpringForce(gridEndOffset)) + recentsView.mUtils.taskViews.forEach { taskView -> + val taskViewGridEndSpringAnimation = + SpringAnimation( + taskView, + FloatPropertyCompat.createFloatPropertyCompat(GRID_END_TRANSLATION_X), + ) + .setSpring(createExpressiveGridReflowSpringForce(gridEndOffset)) + // Update live tile on spring animation. + if (taskView.isRunningTask && recentsView.enableDrawingLiveTile) { + taskViewGridEndSpringAnimation.addUpdateListener { _, _, _ -> + recentsView.runActionOnRemoteHandles { remoteTargetHandle -> + remoteTargetHandle.taskViewSimulator.taskPrimaryTranslation.value = + GRID_END_TRANSLATION_X.get(taskView) + } + recentsView.redrawLiveTile() + } + } + gridEndSpring.addUpdateListener { _, value, _ -> + taskViewGridEndSpringAnimation.animateToFinalPosition(value) + } + } + // Animate alpha of clear all if translating grid to hide it. + if (recentsView.isClearAllHidden) { + SpringAnimation( + recentsView.clearAllButton, + FloatPropertyCompat.createFloatPropertyCompat(ClearAllButton.DISMISS_ALPHA), + ) + .setSpring(createExpressiveDismissAlphaSpringForce()) + .addEndListener { _, _, _, _ -> recentsView.clearAllButton.dismissAlpha = 1f } + .animateToFinalPosition(0f) + } + gridEndSpring.addEndListener { _, _, _, _ -> runGridEndAnimationAndRelayout(gridEndData) } + gridEndSpring.animateToFinalPosition(gridEndOffset) + } + + /** Returns the distance between the end of the grid and clear all button after dismissal. */ + fun getGridEndData( + dismissedTaskView: TaskView?, + isExpressiveDismiss: Boolean = true, + isFocusedTaskDismissed: Boolean = false, + nextFocusedTaskView: TaskView? = null, + isStagingFocusedTask: Boolean = false, + nextFocusedTaskFromTop: Boolean = false, + nextFocusedTaskWidth: Float = 0f, + ): GridEndData { + var gridEndOffset = 0f + var snapToLastTask = false + var newClearAllShortTotalWidthTranslation: Float + var currentPageSnapsToEndOfGrid: Boolean + with(recentsView) { + val lastGridTaskView = if (showAsGrid()) lastGridTaskView else null + val currentPageScroll = getScrollForPage(currentPage) + val lastGridTaskScroll = getScrollForPage(indexOfChild(lastGridTaskView)) + currentPageSnapsToEndOfGrid = currentPageScroll == lastGridTaskScroll + var topGridRowCount = mTopRowIdSet.size() + var bottomGridRowCount = + taskViewCount - mTopRowIdSet.size() - mUtils.getLargeTileCount() + val topRowLonger = topGridRowCount > bottomGridRowCount + val bottomRowLonger = bottomGridRowCount > topGridRowCount + val dismissedFromTop = + dismissedTaskView != null && mTopRowIdSet.contains(dismissedTaskView.taskViewId) + val dismissedFromBottom = + dismissedTaskView != null && !dismissedFromTop && !dismissedTaskView.isLargeTile + if (dismissedFromTop || (isFocusedTaskDismissed && nextFocusedTaskFromTop)) { + topGridRowCount-- + } + if (dismissedFromBottom || (isFocusedTaskDismissed && !nextFocusedTaskFromTop)) { + bottomGridRowCount-- + } + newClearAllShortTotalWidthTranslation = + getNewClearAllShortTotalWidthTranslation( + topGridRowCount, + bottomGridRowCount, + isStagingFocusedTask, + ) + val isLastGridTaskViewVisibleForDismiss = + when { + lastGridTaskView == null -> false + isExpressiveDismiss -> + isTaskViewVisible(lastGridTaskView) || lastGridTaskView == dismissedTaskView + else -> lastGridTaskView.isVisibleToUser + } + if (!isLastGridTaskViewVisibleForDismiss) { + return GridEndData( + gridEndOffset, + snapToLastTask, + newClearAllShortTotalWidthTranslation, + currentPageSnapsToEndOfGrid, + ) + } + val dismissedTaskWidth = + if (dismissedTaskView == null) 0f + else (dismissedTaskView.layoutParams.width + pageSpacing).toFloat() + val gapWidth = + when { + (topRowLonger && dismissedFromTop) || + (bottomRowLonger && dismissedFromBottom) -> dismissedTaskWidth + nextFocusedTaskView != null && + ((topRowLonger && nextFocusedTaskFromTop) || + (bottomRowLonger && !nextFocusedTaskFromTop)) -> nextFocusedTaskWidth + else -> 0f + } + if (gapWidth > 0) { + if (clearAllShortTotalWidthTranslation == 0) { + val gapCompensation = gapWidth - newClearAllShortTotalWidthTranslation + gridEndOffset += if (isRtl) -gapCompensation else gapCompensation + } + if (isClearAllHidden) { + // If ClearAllButton isn't fully shown, snap to the last task. + snapToLastTask = true + } + } + val isLeftRightSplit = + (mContainer as ActivityContext).getDeviceProfile().isLeftRightSplit && + isSplitSelectionActive + if (isLeftRightSplit && !isStagingFocusedTask) { + // LastTask's scroll is the minimum scroll in split select, if current scroll is + // beyond that, we'll need to snap to last task instead. + getLastGridTaskView()?.let { lastTask -> + val primaryScroll = pagedOrientationHandler.getPrimaryScroll(this) + val lastTaskScroll = getScrollForPage(indexOfChild(lastTask)) + if ( + (isRtl && primaryScroll < lastTaskScroll) || + (!isRtl && primaryScroll > lastTaskScroll) + ) { + snapToLastTask = true + } + } + } + if (snapToLastTask) { + gridEndOffset += snapToLastTaskScrollDiff.toFloat() + } else if (isLeftRightSplit && currentPageSnapsToEndOfGrid) { + // Use last task as reference point for scroll diff and snapping calculation as it's + // the only invariant point in landscape split screen. + snapToLastTask = true + } + + // Handle large tile scroll when dismissing the last small task. + if (mUtils.getGridTaskCount() == 1 && dismissedTaskView?.isGridTask == true) { + mUtils.getLastLargeTaskView()?.let { lastLargeTile -> + val primaryScroll = pagedOrientationHandler.getPrimaryScroll(this) + val lastLargeTileScroll = getScrollForPage(indexOfChild(lastLargeTile)) + gridEndOffset = (primaryScroll - lastLargeTileScroll).toFloat() + + if (!isClearAllHidden) { + // If ClearAllButton is visible, reduce the distance by scroll difference + // between ClearAllButton and the last task. + gridEndOffset += + getLastTaskScroll( + /*clearAllScroll=*/ 0, + pagedOrientationHandler.getPrimarySize(clearAllButton), + ) + .toFloat() + } + } + } + } + return GridEndData( + gridEndOffset, + snapToLastTask, + newClearAllShortTotalWidthTranslation, + currentPageSnapsToEndOfGrid, + ) + } + + private fun getNewClearAllShortTotalWidthTranslation( + topGridRowCount: Int, + bottomGridRowCount: Int, + isStagingFocusedTask: Boolean, + ): Float { + with(recentsView) { + if (clearAllShortTotalWidthTranslation != 0) { + return 0f + } + // If first task is not in the expected position (mLastComputedTaskSize) and too + // close to ClearAllButton, then apply extra translation to ClearAllButton. + var longRowWidth = + max(topGridRowCount, bottomGridRowCount) * + (mLastComputedGridTaskSize.width() + pageSpacing) + if (!enableGridOnlyOverview() && !isStagingFocusedTask) { + longRowWidth += mLastComputedTaskSize.width() + pageSpacing + } + val firstTaskStart = mLastComputedGridSize.left + longRowWidth + val expectedFirstTaskStart = mLastComputedTaskSize.right + // Compensate the removed gap if we don't already have shortTotalCompensation, + // and adjust accordingly to the new shortTotalCompensation after dismiss. + return if (firstTaskStart < expectedFirstTaskStart) { + (expectedFirstTaskStart - firstTaskStart).toFloat() + } else { + 0f + } + } + } + + data class GridEndData( + val gridEndOffset: Float, + val snapToLastTask: Boolean, + val newClearAllShortTotalWidthTranslation: Float, + val currentPageSnapsToEndOfGrid: Boolean, + ) + private companion object { // The additional damping to apply to tasks further from the dismissed task. private const val ADDITIONAL_DISMISS_DAMPING_RATIO = 0.15f private const val RECENTS_SCALE_SPRING_MULTIPLIER = 1000f private const val DISMISS_DEFAULT_DURATION = 300 - private const val DISMISS_IMMEDIATE_DURATION = 10 + private const val DISMISS_IMMEDIATE_DURATION = 100 } } diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index 003b3d7c9f..45822b1a39 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -1518,7 +1518,7 @@ public abstract class RecentsView< } @Nullable - private TaskView getLastGridTaskView() { + protected TaskView getLastGridTaskView() { return getLastGridTaskView(mUtils.getTopRowIdArray(), mUtils.getBottomRowIdArray()); } @@ -1532,7 +1532,7 @@ public abstract class RecentsView< return getTaskViewFromTaskViewId(lastTaskViewId); } - private int getSnapToLastTaskScrollDiff() { + protected int getSnapToLastTaskScrollDiff() { // Snap to a position where ClearAll is just invisible. int screenStart = getPagedOrientationHandler().getPrimaryScroll(this); int clearAllScroll = getScrollForPage(indexOfChild(mClearAllButton)); @@ -1541,7 +1541,7 @@ public abstract class RecentsView< return screenStart - lastTaskScroll; } - private int getLastTaskScroll(int clearAllScroll, int clearAllWidth) { + protected int getLastTaskScroll(int clearAllScroll, int clearAllWidth) { int distance = clearAllWidth + getClearAllExtraPageSpacing(); return clearAllScroll + (mIsRtl ? distance : -distance); } @@ -2871,6 +2871,10 @@ public abstract class RecentsView< return tv == null ? -1 : indexOfChild(tv); } + protected int getClearAllShortTotalWidthTranslation() { + return mClearAllShortTotalWidthTranslation; + } + /** * Reloads the view if anything in recents changed. */ @@ -3716,11 +3720,14 @@ public abstract class RecentsView< * selection state from app icon * @param isExpressiveDismiss runs expressive animations controlled via * {@link RecentsDismissUtils} + * @param gridEndData used to compute any gap left between the end of the + * grid and the clear all button. */ public void createTaskDismissAnimation(PendingAnimation anim, @Nullable TaskView dismissedTaskView, boolean animateTaskView, boolean shouldRemoveTask, long duration, - boolean dismissingForSplitSelection, boolean isExpressiveDismiss) { + boolean dismissingForSplitSelection, boolean isExpressiveDismiss, + @Nullable RecentsDismissUtils.GridEndData gridEndData) { if (mPendingAnimation != null) { mPendingAnimation.createPlaybackController().dispatchOnCancel().dispatchOnEnd(); } @@ -3739,7 +3746,7 @@ public abstract class RecentsView< // Grid specific properties. boolean isFocusedTaskDismissed = false; boolean isStagingFocusedTask = false; - boolean isSlidingTasks = false; + boolean isSlidingTasks; TaskView nextFocusedTaskView = null; boolean nextFocusedTaskFromTop = false; float dismissedTaskWidth = 0; @@ -3799,156 +3806,69 @@ public abstract class RecentsView< float dismissTranslationInterpolationEnd = 1; boolean closeGapBetweenClearAll = false; boolean isClearAllHidden = isClearAllHidden(); - boolean snapToLastTask = false; - boolean isLeftRightSplit = - mContainer.getDeviceProfile().isLeftRightSplit && isSplitSelectionActive(); - TaskView lastGridTaskView = showAsGrid ? getLastGridTaskView() : null; - int currentPageScroll = getScrollForPage(mCurrentPage); - int lastGridTaskScroll = getScrollForPage(indexOfChild(lastGridTaskView)); - boolean currentPageSnapsToEndOfGrid = currentPageScroll == lastGridTaskScroll; - int topGridRowSize = mTopRowIdSet.size(); - int numLargeTiles = mUtils.getLargeTileCount(); - int bottomGridRowSize = taskCount - mTopRowIdSet.size() - numLargeTiles; - boolean topRowLonger = topGridRowSize > bottomGridRowSize; - boolean bottomRowLonger = bottomGridRowSize > topGridRowSize; - boolean dismissedTaskFromTop = mTopRowIdSet.contains(dismissedTaskViewId); - boolean dismissedTaskFromBottom = !dismissedTaskFromTop && !isFocusedTaskDismissed; - if (dismissedTaskFromTop || (isFocusedTaskDismissed && nextFocusedTaskFromTop)) { - topGridRowSize--; + if (gridEndData == null) { + gridEndData = mDismissUtils.getGridEndData(dismissedTaskView, isExpressiveDismiss, + isFocusedTaskDismissed, nextFocusedTaskView, isStagingFocusedTask, + nextFocusedTaskFromTop, nextFocusedTaskWidth); } - if (dismissedTaskFromBottom || (isFocusedTaskDismissed && !nextFocusedTaskFromTop)) { - bottomGridRowSize--; + float longGridRowWidthDiff = gridEndData.getGridEndOffset(); + boolean snapToLastTask = gridEndData.getSnapToLastTask(); + float newClearAllShortTotalWidthTranslation = + gridEndData.getNewClearAllShortTotalWidthTranslation(); + boolean currentPageSnapsToEndOfGrid = gridEndData.getCurrentPageSnapsToEndOfGrid(); + if (longGridRowWidthDiff != 0f) { + closeGapBetweenClearAll = true; } - int longRowWidth = Math.max(topGridRowSize, bottomGridRowSize) - * (mLastComputedGridTaskSize.width() + mPageSpacing); - if (!enableGridOnlyOverview() && !isStagingFocusedTask) { - longRowWidth += mLastComputedTaskSize.width() + mPageSpacing; - } - // Compensate the removed gap if we don't already have shortTotalCompensation, - // and adjust accordingly to the new shortTotalCompensation after dismiss. - int newClearAllShortTotalWidthTranslation = 0; - if (mClearAllShortTotalWidthTranslation == 0) { - // If first task is not in the expected position (mLastComputedTaskSize) and being too - // close to ClearAllButton, then apply extra translation to ClearAllButton. - int firstTaskStart = mLastComputedGridSize.left + longRowWidth; - int expectedFirstTaskStart = mLastComputedTaskSize.right; - if (firstTaskStart < expectedFirstTaskStart) { - newClearAllShortTotalWidthTranslation = expectedFirstTaskStart - firstTaskStart; - } - } - if (lastGridTaskView != null && ( - (!isExpressiveDismiss && lastGridTaskView.isVisibleToUser()) || (isExpressiveDismiss - && (isTaskViewVisible(lastGridTaskView) - || 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. - float longGridRowWidthDiff = 0; - float gapWidth = 0; - if ((topRowLonger && dismissedTaskFromTop) - || (bottomRowLonger && dismissedTaskFromBottom)) { - gapWidth = dismissedTaskWidth; - } else if (nextFocusedTaskView != null - && ((topRowLonger && nextFocusedTaskFromTop) - || (bottomRowLonger && !nextFocusedTaskFromTop))) { - gapWidth = nextFocusedTaskWidth; - } - if (gapWidth > 0) { - if (mClearAllShortTotalWidthTranslation == 0) { - float gapCompensation = gapWidth - newClearAllShortTotalWidthTranslation; - longGridRowWidthDiff += mIsRtl ? -gapCompensation : gapCompensation; - } - if (isClearAllHidden) { - // If ClearAllButton isn't fully shown, snap to the last task. - snapToLastTask = true; - } - } - if (isLeftRightSplit && !isStagingFocusedTask) { - // LastTask's scroll is the minimum scroll in split select, if current scroll is - // beyond that, we'll need to snap to last task instead. - TaskView lastTask = getLastGridTaskView(); - if (lastTask != null) { - int primaryScroll = getPagedOrientationHandler().getPrimaryScroll(this); - int lastTaskScroll = getScrollForPage(indexOfChild(lastTask)); - if ((mIsRtl && primaryScroll < lastTaskScroll) - || (!mIsRtl && primaryScroll > lastTaskScroll)) { - snapToLastTask = true; - } - } - } - if (snapToLastTask) { - longGridRowWidthDiff += getSnapToLastTaskScrollDiff(); - } else if (isLeftRightSplit && currentPageSnapsToEndOfGrid) { - // Use last task as reference point for scroll diff and snapping calculation as it's - // the only invariant point in landscape split screen. - snapToLastTask = true; - } - if (mUtils.getGridTaskCount() == 1 && dismissedTaskView.isGridTask()) { - TaskView lastLargeTile = mUtils.getLastLargeTaskView(); - if (lastLargeTile != null) { - // Calculate the distance to put last large tile back to middle of the screen. - int primaryScroll = getPagedOrientationHandler().getPrimaryScroll(this); - int lastLargeTileScroll = getScrollForPage(indexOfChild(lastLargeTile)); - longGridRowWidthDiff = primaryScroll - lastLargeTileScroll; - - if (!isClearAllHidden) { - // If ClearAllButton is visible, reduce the distance by scroll difference - // between ClearAllButton and the last task. - longGridRowWidthDiff += getLastTaskScroll(/*clearAllScroll=*/0, - getPagedOrientationHandler().getPrimarySize(mClearAllButton)); - } - } - } - - // If we need to animate the grid to compensate the clear all gap, we split the second - // half of the dismiss pending animation (in which the non-dismissed tasks slide into - // place) in half again, making the first quarter the existing non-dismissal sliding - // and the second quarter this new animation of gap filling. This is due to the fact - // that PendingAnimation is a single animation, not a sequence of animations, so we - // fake it using interpolation. - if (longGridRowWidthDiff != 0) { - closeGapBetweenClearAll = true; - // Stagger the offsets of each additional task for a delayed animation. We use - // half here as this animation is half of half of an animation (1/4th). - float halfAdditionalDismissTranslationOffset = - (0.5f * ADDITIONAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET); + // 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. + if (!isExpressiveDismiss && longGridRowWidthDiff != 0) { + // If we need to animate the grid to compensate the clear all gap, we split the + // second half of the dismiss pending animation (in which the non-dismissed tasks + // slide into place) in half again, making the first quarter the existing + // non-dismissal sliding and the second quarter this new animation of gap filling. + // This is due to the fact that PendingAnimation is a single animation, not a + // sequence of animations, so we fake it using interpolation. Stagger the offsets of + // each additional task for a delayed animation. We use half here as this animation is + // half of half of an animation (1/4th). + float halfAdditionalDismissTranslationOffset = + (0.5f * ADDITIONAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET); + dismissTranslationInterpolationEnd = Utilities.boundToRange( + END_DISMISS_TRANSLATION_INTERPOLATION_OFFSET + + (taskCount - 1) * halfAdditionalDismissTranslationOffset, + END_DISMISS_TRANSLATION_INTERPOLATION_OFFSET, 1); + for (TaskView taskView : getTaskViews()) { + anim.setFloat(taskView, TaskView.GRID_END_TRANSLATION_X, + longGridRowWidthDiff, + clampToProgress(LINEAR, dismissTranslationInterpolationEnd, 1)); dismissTranslationInterpolationEnd = Utilities.boundToRange( - END_DISMISS_TRANSLATION_INTERPOLATION_OFFSET - + (taskCount - 1) * halfAdditionalDismissTranslationOffset, + dismissTranslationInterpolationEnd + - halfAdditionalDismissTranslationOffset, END_DISMISS_TRANSLATION_INTERPOLATION_OFFSET, 1); - for (TaskView taskView : getTaskViews()) { - anim.setFloat(taskView, TaskView.GRID_END_TRANSLATION_X, longGridRowWidthDiff, - clampToProgress(LINEAR, dismissTranslationInterpolationEnd, 1)); - dismissTranslationInterpolationEnd = Utilities.boundToRange( - dismissTranslationInterpolationEnd - - halfAdditionalDismissTranslationOffset, - END_DISMISS_TRANSLATION_INTERPOLATION_OFFSET, 1); - if (mEnableDrawingLiveTile && taskView.isRunningTask()) { - anim.addOnFrameCallback(() -> { - runActionOnRemoteHandles( - remoteTargetHandle -> - remoteTargetHandle.getTaskViewSimulator() - .taskPrimaryTranslation.value = - TaskView.GRID_END_TRANSLATION_X.get(taskView)); - redrawLiveTile(); - }); - } - } - - // Change alpha of clear all if translating grid to hide it - if (isClearAllHidden) { - anim.setFloat(mClearAllButton, DISMISS_ALPHA, 0, LINEAR); - anim.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - super.onAnimationEnd(animation); - mClearAllButton.setDismissAlpha(1); - } + if (mEnableDrawingLiveTile && taskView.isRunningTask()) { + anim.addOnFrameCallback(() -> { + runActionOnRemoteHandles(remoteTargetHandle -> + remoteTargetHandle.getTaskViewSimulator() + .taskPrimaryTranslation.value = + TaskView.GRID_END_TRANSLATION_X.get(taskView)); + redrawLiveTile(); }); } } + + // Change alpha of clear all if translating grid to hide it + if (isClearAllHidden) { + anim.setFloat(mClearAllButton, DISMISS_ALPHA, 0, LINEAR); + anim.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + mClearAllButton.setDismissAlpha(1); + } + }); + } } SplitAnimationTimings splitTimings = @@ -4636,17 +4556,17 @@ public abstract class RecentsView< PendingAnimation pa = new PendingAnimation(DISMISS_TASK_DURATION); createTaskDismissAnimation(pa, taskView, animateTaskView, removeTask, DISMISS_TASK_DURATION, false /* dismissingForSplitSelection*/, - false /* isExpressiveDismiss */); + false /* isExpressiveDismiss */, null /* gridEndData */); runDismissAnimation(pa); } } protected void expressiveDismissTaskView(TaskView taskView, Function0 onEndRunnable, - int dismissDuration) { + int dismissDuration, @Nullable RecentsDismissUtils.GridEndData gridEndData) { PendingAnimation pa = new PendingAnimation(dismissDuration); createTaskDismissAnimation(pa, taskView, false /* animateTaskView */, true /* removeTask */, dismissDuration, false /* dismissingForSplitSelection*/, - true /* isExpressiveDismiss */); + true /* isExpressiveDismiss */, gridEndData); pa.addEndListener((success) -> onEndRunnable.invoke()); runDismissAnimation(pa); } @@ -5381,7 +5301,8 @@ public abstract class RecentsView< } // Splitting from Overview for fullscreen task createTaskDismissAnimation(builder, mSplitHiddenTaskView, true, false, duration, - true /* dismissingForSplitSelection*/, false /* isExpressiveDismiss */); + true /* dismissingForSplitSelection*/, false /* isExpressiveDismiss */, + null /* gridEndData */); } else { // Splitting from Home TaskView currentPageTaskView = getTaskViewAt(mCurrentPage); @@ -5389,7 +5310,8 @@ public abstract class RecentsView< // display correct animation in split mode if (currentPageTaskView instanceof DesktopTaskView) { createTaskDismissAnimation(builder, null, true, false, duration, - true /* dismissingForSplitSelection*/, false /* isExpressiveDismiss */); + true /* dismissingForSplitSelection*/, false /* isExpressiveDismiss */, + null /* gridEndData */); } else { createInitialSplitSelectAnimation(builder); } diff --git a/res/values/config.xml b/res/values/config.xml index fc636a5055..9c6199680e 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -115,6 +115,8 @@ 900 0.8 900 + 1 + 1600