Merge "Translate grid end for tasks after dismiss." into main

This commit is contained in:
Treehugger Robot
2025-04-02 06:08:07 -07:00
committed by Android (Google) Code Review
5 changed files with 322 additions and 161 deletions
@@ -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 {
@@ -143,7 +143,7 @@ public class FallbackRecentsView<CONTAINER_TYPE extends Context & RecentsViewCon
PendingAnimation pendingAnimation = new PendingAnimation(TASK_DISMISS_DURATION);
createTaskDismissAnimation(pendingAnimation, homeTaskView, true, false,
TASK_DISMISS_DURATION, false /* dismissingForSplitSelection*/,
false /* isExpressiveDismiss */);
false /* isExpressiveDismiss */, null /* gridEndData */);
pendingAnimation.addEndListener(e -> setCurrentTask(-1));
AnimatorPlaybackController controller = pendingAnimation.createPlaybackController();
controller.dispatchOnStart();
@@ -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
}
}
@@ -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<Unit> 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);
}
+2
View File
@@ -115,6 +115,8 @@
<item name="expressive_dismiss_task_trans_y_stiffness" type="dimen" format="float">900</item>
<item name="expressive_dismiss_task_trans_x_damping_ratio" type="dimen" format="float">0.8</item>
<item name="expressive_dismiss_task_trans_x_stiffness" type="dimen" format="float">900</item>
<item name="expressive_dismiss_effects_damping_ratio" type="dimen" format="float">1</item>
<item name="expressive_dismiss_effects_stiffness" type="dimen" format="float">1600</item>
<!-- Taskbar -->
<!-- This is a float because it is converted to dp later in DeviceProfile -->