Merge "Spring neighboring tasks into place on task reflow after dismiss." into main
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchControllerDeprecated.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchControllerDeprecated.java
index b1a36c7..f26bd13 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 @@
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 f426bf5..d8662f2 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -136,7 +136,8 @@
if (tv != null) {
PendingAnimation pa = new PendingAnimation(TASK_DISMISS_DURATION);
createTaskDismissAnimation(pa, tv, true, false,
- TASK_DISMISS_DURATION, false /* dismissingForSplitSelection*/);
+ TASK_DISMISS_DURATION, false /* dismissingForSplitSelection*/,
+ false /* isExpressiveDismiss */);
pa.addEndListener(e -> 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 3430b39..4ce18f5 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.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.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 @@
}
.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 @@
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 @@
)
}
+ 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 @@
.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<TaskView>,
+ dismissedTaskView: TaskView,
+ towardsStart: Boolean,
+ ): List<TaskView> {
+ 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<TaskView>,
+ 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 e434252..89726aa 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.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;
@@ -602,7 +601,7 @@
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.
@@ -1507,7 +1506,7 @@
@Nullable
private TaskView getLastGridTaskView() {
- return getLastGridTaskView(getTopRowIdArray(), getBottomRowIdArray());
+ return getLastGridTaskView(mUtils.getTopRowIdArray(), mUtils.getBottomRowIdArray());
}
@Nullable
@@ -1553,7 +1552,7 @@
* @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());
@@ -3552,7 +3551,7 @@
setGridProgress(mGridProgress);
}
- private boolean isSameGridRow(TaskView taskView1, TaskView taskView2) {
+ protected boolean isSameGridRow(TaskView taskView1, TaskView taskView2) {
if (taskView1 == null || taskView2 == null) {
return false;
}
@@ -3756,11 +3755,13 @@
* @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();
}
@@ -3878,7 +3879,7 @@
}
}
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.
@@ -4018,12 +4019,17 @@
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) {
@@ -4108,13 +4114,16 @@
: 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++;
}
@@ -4214,8 +4223,8 @@
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) {
@@ -4230,8 +4239,8 @@
// 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);
@@ -4313,8 +4322,8 @@
}
}
- 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(
@@ -4437,10 +4446,6 @@
animationEndProgress
)
);
-
- if (view instanceof TaskView) {
- mTaskViewsDismissPrimaryTranslations.put((TaskView) view, scrollDiffPerPage);
- }
if (mEnableDrawingLiveTile && view instanceof TaskView
&& ((TaskView) view).isRunningTask()) {
pendingAnimation.addOnFrameCallback(() -> {
@@ -4485,41 +4490,6 @@
}
/**
- * 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.
*
@@ -4529,8 +4499,8 @@
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++) {
@@ -4625,8 +4595,9 @@
}
// 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();
@@ -4685,7 +4656,15 @@
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);
}
@@ -5414,7 +5393,7 @@
}
// 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);
@@ -5422,7 +5401,7 @@
// 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);
}
@@ -6416,7 +6395,8 @@
* 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(
@@ -6715,7 +6695,7 @@
.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 31ae890..1c37986 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsViewUtils.kt
+++ b/quickstep/src/com/android/quickstep/views/RecentsViewUtils.kt
@@ -83,6 +83,25 @@
/** Returns a list of all large TaskView Ids from [TaskView]s */
fun getLargeTaskViewIds(): List<Int> = taskViews.filter { it.isLargeTile }.map { it.taskViewId }
+ /** Returns a list of all large TaskViews [TaskView]s */
+ fun getLargeTaskViews(): List<TaskView> = taskViews.filter { it.isLargeTile }
+
+ /** Returns all the TaskViews in the top row, without the focused task */
+ fun getTopRowTaskViews(): List<TaskView> =
+ 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<TaskView> =
+ 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<Int>.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 @@
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 3819772..ab78592 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskView.kt
@@ -220,7 +220,7 @@
SPLIT_SELECT_TRANSLATION_Y,
)
- protected val primaryDismissTranslationProperty: FloatProperty<TaskView>
+ val primaryDismissTranslationProperty: FloatProperty<TaskView>
get() =
pagedOrientationHandler.getPrimaryValue(DISMISS_TRANSLATION_X, DISMISS_TRANSLATION_Y)
@@ -743,9 +743,10 @@
// 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 @@
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 74e7bb0..d65580c 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -114,6 +114,8 @@
<!-- Expressive Dismiss -->
<item name="expressive_dismiss_task_trans_y_damping_ratio" type="dimen" format="float">0.6</item>
<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>
<!-- Taskbar -->
<!-- This is a float because it is converted to dp later in DeviceProfile -->