use of com.android.quickstep.views.ClearAllButton.DISMISS_ALPHA in project android_packages_apps_Launcher3 by AOSPA.
the class RecentsView method createTaskDismissAnimation.
/**
* Creates a {@link PendingAnimation} for dismissing the specified {@link TaskView}.
* @param dismissedTaskView the {@link TaskView} to be dismissed
* @param animateTaskView whether the {@link TaskView} to be dismissed should be animated
* @param shouldRemoveTask whether the associated {@link Task} should be removed from
* ActivityManager after dismissal
* @param duration duration of the animation
* @param dismissingForSplitSelection task dismiss animation is used for entering split
* selection state from app icon
*/
public PendingAnimation createTaskDismissAnimation(TaskView dismissedTaskView, boolean animateTaskView, boolean shouldRemoveTask, long duration, boolean dismissingForSplitSelection) {
if (mPendingAnimation != null) {
mPendingAnimation.createPlaybackController().dispatchOnCancel().dispatchOnEnd();
}
PendingAnimation anim = new PendingAnimation(duration);
int count = getPageCount();
if (count == 0) {
return anim;
}
boolean showAsGrid = showAsGrid();
int taskCount = getTaskViewCount();
int dismissedIndex = indexOfChild(dismissedTaskView);
int dismissedTaskViewId = dismissedTaskView.getTaskViewId();
// Grid specific properties.
boolean isFocusedTaskDismissed = false;
TaskView nextFocusedTaskView = null;
boolean nextFocusedTaskFromTop = false;
float dismissedTaskWidth = 0;
float nextFocusedTaskWidth = 0;
// Non-grid specific properties.
int[] oldScroll = new int[count];
int[] newScroll = new int[count];
int scrollDiffPerPage = 0;
boolean needsCurveUpdates = false;
if (showAsGrid) {
dismissedTaskWidth = dismissedTaskView.getLayoutParams().width + mPageSpacing;
isFocusedTaskDismissed = dismissedTaskViewId == mFocusedTaskViewId;
if (isFocusedTaskDismissed && !isSplitSelectionActive()) {
nextFocusedTaskFromTop = mTopRowIdSet.size() > 0 && mTopRowIdSet.size() >= (taskCount - 1) / 2f;
// Pick the next focused task from the preferred row.
for (int i = 0; i < taskCount; i++) {
TaskView taskView = requireTaskViewAt(i);
if (taskView == dismissedTaskView) {
continue;
}
boolean isTopRow = mTopRowIdSet.contains(taskView.getTaskViewId());
if ((nextFocusedTaskFromTop && isTopRow || (!nextFocusedTaskFromTop && !isTopRow))) {
nextFocusedTaskView = taskView;
break;
}
}
if (nextFocusedTaskView != null) {
nextFocusedTaskWidth = nextFocusedTaskView.getLayoutParams().width + mPageSpacing;
}
}
} else {
getPageScrolls(oldScroll, false, SIMPLE_SCROLL_LOGIC);
getPageScrolls(newScroll, false, v -> v.getVisibility() != GONE && v != dismissedTaskView);
if (count > 1) {
scrollDiffPerPage = Math.abs(oldScroll[1] - oldScroll[0]);
}
}
announceForAccessibility(getResources().getString(R.string.task_view_closed));
float dismissTranslationInterpolationEnd = 1;
boolean closeGapBetweenClearAll = false;
boolean isClearAllHidden = isClearAllHidden();
boolean snapToLastTask = false;
boolean isLandscapeSplit = mActivity.getDeviceProfile().isLandscape && isSplitSelectionActive();
boolean isSplitPlaceholderFirstInGrid = isSplitPlaceholderFirstInGrid();
boolean isSplitPlaceholderLastInGrid = isSplitPlaceholderLastInGrid();
TaskView lastGridTaskView = showAsGrid ? getLastGridTaskView() : null;
int currentPageScroll = getScrollForPage(mCurrentPage);
int lastGridTaskScroll = getScrollForPage(indexOfChild(lastGridTaskView));
boolean currentPageSnapsToEndOfGrid = currentPageScroll == lastGridTaskScroll;
if (lastGridTaskView != null && lastGridTaskView.isVisibleToUser()) {
// 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;
int topGridRowSize = mTopRowIdSet.size();
int bottomGridRowSize = taskCount - mTopRowIdSet.size() - 1;
boolean topRowLonger = topGridRowSize > bottomGridRowSize;
boolean bottomRowLonger = bottomGridRowSize > topGridRowSize;
boolean dismissedTaskFromTop = mTopRowIdSet.contains(dismissedTaskViewId);
boolean dismissedTaskFromBottom = !dismissedTaskFromTop && !isFocusedTaskDismissed;
float gapWidth = 0;
if ((topRowLonger && dismissedTaskFromTop) || (bottomRowLonger && dismissedTaskFromBottom)) {
gapWidth = dismissedTaskWidth;
} else if ((topRowLonger && nextFocusedTaskFromTop) || (bottomRowLonger && !nextFocusedTaskFromTop)) {
gapWidth = nextFocusedTaskWidth;
}
if (gapWidth > 0) {
if (taskCount > 2) {
// Compensate the removed gap.
longGridRowWidthDiff += mIsRtl ? -gapWidth : gapWidth;
if (isClearAllHidden) {
// If ClearAllButton isn't fully shown, snap to the last task.
snapToLastTask = true;
}
} else {
// If only focused task will be left, snap to focused task instead.
longGridRowWidthDiff += getSnapToFocusedTaskScrollDiff(isClearAllHidden);
}
}
if (mClearAllButton.getAlpha() != 0f && isLandscapeSplit) {
// ClearAllButton will not be available in split select, snap to last task instead.
snapToLastTask = true;
}
if (snapToLastTask) {
longGridRowWidthDiff += getSnapToLastTaskScrollDiff();
if (isSplitPlaceholderLastInGrid) {
// Shift all the tasks to make space for split placeholder.
longGridRowWidthDiff += mIsRtl ? mSplitPlaceholderSize : -mSplitPlaceholderSize;
}
} else if (isLandscapeSplit && 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;
}
// 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);
dismissTranslationInterpolationEnd = Utilities.boundToRange(END_DISMISS_TRANSLATION_INTERPOLATION_OFFSET + (taskCount - 1) * halfAdditionalDismissTranslationOffset, END_DISMISS_TRANSLATION_INTERPOLATION_OFFSET, 1);
for (int i = 0; i < taskCount; i++) {
TaskView taskView = requireTaskViewAt(i);
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 (ENABLE_QUICKSTEP_LIVE_TILE.get() && 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);
}
});
}
}
}
int distanceFromDismissedTask = 0;
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
if (child == dismissedTaskView) {
if (animateTaskView) {
if (dismissingForSplitSelection) {
createInitialSplitSelectAnimation(anim);
} else {
addDismissedTaskAnimations(dismissedTaskView, duration, anim);
}
}
} else if (!showAsGrid) {
// Compute scroll offsets from task dismissal for animation.
// If we just take newScroll - oldScroll, everything to the right of dragged task
// translates to the left. We need to offset this in some cases:
// - In RTL, add page offset to all pages, since we want pages to move to the right
// Additionally, add a page offset if:
// - Current page is rightmost page (leftmost for RTL)
// - Dragging an adjacent page on the left side (right side for RTL)
int offset = mIsRtl ? scrollDiffPerPage : 0;
if (mCurrentPage == dismissedIndex) {
int lastPage = taskCount - 1;
if (mCurrentPage == lastPage) {
offset += mIsRtl ? -scrollDiffPerPage : scrollDiffPerPage;
}
} else {
// Dismissing an adjacent page.
// (Right in RTL, left in LTR)
int negativeAdjacent = mCurrentPage - 1;
if (dismissedIndex == negativeAdjacent) {
offset += mIsRtl ? -scrollDiffPerPage : scrollDiffPerPage;
}
}
int scrollDiff = newScroll[i] - oldScroll[i] + offset;
if (scrollDiff != 0) {
FloatProperty translationProperty = child instanceof TaskView ? ((TaskView) child).getPrimaryDismissTranslationProperty() : mOrientationHandler.getPrimaryViewTranslate();
float additionalDismissDuration = ADDITIONAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET * Math.abs(i - dismissedIndex);
anim.setFloat(child, translationProperty, scrollDiff, clampToProgress(LINEAR, Utilities.boundToRange(INITIAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET + additionalDismissDuration, 0f, 1f), 1));
if (ENABLE_QUICKSTEP_LIVE_TILE.get() && mEnableDrawingLiveTile && child instanceof TaskView && ((TaskView) child).isRunningTask()) {
anim.addOnFrameCallback(() -> {
runActionOnRemoteHandles(remoteTargetHandle -> remoteTargetHandle.getTaskViewSimulator().taskPrimaryTranslation.value = mOrientationHandler.getPrimaryValue(child.getTranslationX(), child.getTranslationY()));
redrawLiveTile();
});
}
needsCurveUpdates = true;
}
} else if (child instanceof TaskView) {
TaskView taskView = (TaskView) child;
if (isFocusedTaskDismissed) {
if (nextFocusedTaskView != null && !isSameGridRow(taskView, nextFocusedTaskView)) {
continue;
}
} else {
if (i < dismissedIndex || !isSameGridRow(taskView, dismissedTaskView)) {
continue;
}
}
// Animate task with index >= dismissed index and in the same row as the
// dismissed index or next focused index. Offset successive task dismissal
// durations for a staggered effect.
float animationStartProgress = Utilities.boundToRange(INITIAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET + ADDITIONAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET * ++distanceFromDismissedTask, 0f, dismissTranslationInterpolationEnd);
if (taskView == nextFocusedTaskView) {
// Enlarge the task to be focused next, and translate into focus position.
float scale = mTaskWidth / (float) mLastComputedGridTaskSize.width();
anim.setFloat(taskView, TaskView.SNAPSHOT_SCALE, scale, clampToProgress(LINEAR, animationStartProgress, dismissTranslationInterpolationEnd));
anim.setFloat(taskView, taskView.getPrimaryDismissTranslationProperty(), mIsRtl ? dismissedTaskWidth : -dismissedTaskWidth, clampToProgress(LINEAR, animationStartProgress, dismissTranslationInterpolationEnd));
float secondaryTranslation = -mTaskGridVerticalDiff;
if (!nextFocusedTaskFromTop) {
secondaryTranslation -= mTopBottomRowHeightDiff;
}
anim.setFloat(taskView, taskView.getSecondaryDissmissTranslationProperty(), secondaryTranslation, clampToProgress(LINEAR, animationStartProgress, dismissTranslationInterpolationEnd));
anim.setFloat(taskView, TaskView.FOCUS_TRANSITION, 0f, clampToProgress(LINEAR, 0f, ANIMATION_DISMISS_PROGRESS_MIDPOINT));
} else {
float primaryTranslation = nextFocusedTaskView != null ? nextFocusedTaskWidth : dismissedTaskWidth;
if (isFocusedTaskDismissed && nextFocusedTaskView == null) {
// Moves less if focused task is not in scroll position.
int focusedTaskScroll = getScrollForPage(dismissedIndex);
int primaryScroll = mOrientationHandler.getPrimaryScroll(this);
int focusedTaskScrollDiff = primaryScroll - focusedTaskScroll;
primaryTranslation += mIsRtl ? focusedTaskScrollDiff : -focusedTaskScrollDiff;
if (isSplitPlaceholderFirstInGrid) {
// Moves less if split placeholder is at the start.
primaryTranslation += mIsRtl ? -mSplitPlaceholderSize : mSplitPlaceholderSize;
}
}
anim.setFloat(taskView, taskView.getPrimaryDismissTranslationProperty(), mIsRtl ? primaryTranslation : -primaryTranslation, clampToProgress(LINEAR, animationStartProgress, dismissTranslationInterpolationEnd));
}
}
}
if (needsCurveUpdates) {
anim.addOnFrameCallback(this::updateCurveProperties);
}
// Add a tiny bit of translation Z, so that it draws on top of other views
if (animateTaskView) {
dismissedTaskView.setTranslationZ(0.1f);
}
mPendingAnimation = anim;
final TaskView finalNextFocusedTaskView = nextFocusedTaskView;
final boolean finalCloseGapBetweenClearAll = closeGapBetweenClearAll;
final boolean finalSnapToLastTask = snapToLastTask;
final boolean finalIsFocusedTaskDismissed = isFocusedTaskDismissed;
mPendingAnimation.addEndListener(new Consumer<Boolean>() {
@Override
public void accept(Boolean success) {
if (ENABLE_QUICKSTEP_LIVE_TILE.get() && mEnableDrawingLiveTile && dismissedTaskView.isRunningTask() && success) {
finishRecentsAnimation(true, /* toRecents */
false, /* shouldPip */
() -> onEnd(success));
} else {
onEnd(success);
}
}
@SuppressWarnings("WrongCall")
private void onEnd(boolean success) {
// Reset task translations as they may have updated via animations in
// createTaskDismissAnimation
resetTaskVisuals();
if (success) {
if (shouldRemoveTask) {
if (dismissedTaskView.getTask() != null) {
if (ENABLE_QUICKSTEP_LIVE_TILE.get() && dismissedTaskView.isRunningTask()) {
finishRecentsAnimation(true, /* toRecents */
false, /* shouldPip */
() -> removeTaskInternal(dismissedTaskViewId));
} else {
removeTaskInternal(dismissedTaskViewId);
}
mActivity.getStatsLogManager().logger().withItemInfo(dismissedTaskView.getItemInfo()).log(LAUNCHER_TASK_DISMISS_SWIPE_UP);
}
}
int pageToSnapTo = mCurrentPage;
mCurrentPageScrollDiff = 0;
int taskViewIdToSnapTo = -1;
if (showAsGrid) {
if (finalCloseGapBetweenClearAll) {
if (finalSnapToLastTask) {
// Last task will be determined after removing dismissed task.
pageToSnapTo = -1;
} else if (taskCount > 2) {
pageToSnapTo = indexOfChild(mClearAllButton);
} else if (isClearAllHidden) {
// Snap to focused task if clear all is hidden.
pageToSnapTo = 0;
}
} else {
// Get the id of the task view we will snap to based on the current
// page's relative position as the order of indices change over time due
// to dismissals.
TaskView snappedTaskView = getTaskViewAt(mCurrentPage);
boolean calculateScrollDiff = true;
if (snappedTaskView != null && !finalSnapToLastTask) {
if (snappedTaskView.getTaskViewId() == mFocusedTaskViewId) {
if (finalNextFocusedTaskView != null) {
taskViewIdToSnapTo = finalNextFocusedTaskView.getTaskViewId();
} else if (dismissedTaskViewId != mFocusedTaskViewId) {
taskViewIdToSnapTo = mFocusedTaskViewId;
} else {
// Won't focus next task in split select, so snap to the
// first task.
pageToSnapTo = 0;
calculateScrollDiff = false;
}
} else {
int snappedTaskViewId = snappedTaskView.getTaskViewId();
boolean isSnappedTaskInTopRow = mTopRowIdSet.contains(snappedTaskViewId);
IntArray taskViewIdArray = isSnappedTaskInTopRow ? getTopRowIdArray() : getBottomRowIdArray();
int snappedIndex = taskViewIdArray.indexOf(snappedTaskViewId);
taskViewIdArray.removeValue(dismissedTaskViewId);
if (finalNextFocusedTaskView != null) {
taskViewIdArray.removeValue(finalNextFocusedTaskView.getTaskViewId());
}
if (snappedIndex < taskViewIdArray.size()) {
taskViewIdToSnapTo = taskViewIdArray.get(snappedIndex);
} else if (snappedIndex == taskViewIdArray.size()) {
// If the snapped task is the last item from the
// dismissed row,
// snap to the same column in the other grid row
IntArray inverseRowTaskViewIdArray = isSnappedTaskInTopRow ? getBottomRowIdArray() : getTopRowIdArray();
if (snappedIndex < inverseRowTaskViewIdArray.size()) {
taskViewIdToSnapTo = inverseRowTaskViewIdArray.get(snappedIndex);
}
}
}
}
if (calculateScrollDiff) {
int primaryScroll = mOrientationHandler.getPrimaryScroll(RecentsView.this);
int currentPageScroll = getScrollForPage(mCurrentPage);
mCurrentPageScrollDiff = primaryScroll - currentPageScroll;
// Compensate for coordinate shift by split placeholder.
if (isSplitPlaceholderFirstInGrid && !finalSnapToLastTask) {
mCurrentPageScrollDiff += mIsRtl ? -mSplitPlaceholderSize : mSplitPlaceholderSize;
} else if (isSplitPlaceholderLastInGrid && finalSnapToLastTask) {
mCurrentPageScrollDiff += mIsRtl ? mSplitPlaceholderSize : -mSplitPlaceholderSize;
}
}
}
} else if (dismissedIndex < pageToSnapTo || pageToSnapTo == taskCount - 1) {
pageToSnapTo--;
}
boolean isHomeTaskDismissed = dismissedTaskView == getHomeTaskView();
removeViewInLayout(dismissedTaskView);
mTopRowIdSet.remove(dismissedTaskViewId);
if (taskCount == 1) {
removeViewInLayout(mClearAllButton);
if (isHomeTaskDismissed) {
updateEmptyMessage();
} else {
startHome();
}
} else {
// Update focus task and its size.
if (finalIsFocusedTaskDismissed && finalNextFocusedTaskView != null) {
mFocusedTaskViewId = finalNextFocusedTaskView.getTaskViewId();
mTopRowIdSet.remove(mFocusedTaskViewId);
finalNextFocusedTaskView.animateIconScaleAndDimIntoView();
}
updateTaskSize(/*isTaskDismissal=*/
true);
updateChildTaskOrientations();
// Update scroll and snap to page.
updateScrollSynchronously();
if (showAsGrid) {
// Rebalance tasks in the grid
int highestVisibleTaskIndex = getHighestVisibleTaskIndex();
if (highestVisibleTaskIndex < Integer.MAX_VALUE) {
TaskView taskView = requireTaskViewAt(highestVisibleTaskIndex);
boolean shouldRebalance;
int screenStart = mOrientationHandler.getPrimaryScroll(RecentsView.this);
int taskStart = mOrientationHandler.getChildStart(taskView) + (int) taskView.getOffsetAdjustment(/*fullscreenEnabled=*/
false, /*gridEnabled=*/
true);
// visible screen.
if (mIsRtl) {
shouldRebalance = taskStart <= screenStart + mPageSpacing;
} else {
int screenEnd = screenStart + mOrientationHandler.getMeasuredSize(RecentsView.this);
int taskSize = (int) (mOrientationHandler.getMeasuredSize(taskView) * taskView.getSizeAdjustment(/*fullscreenEnabled=*/
false));
int taskEnd = taskStart + taskSize;
shouldRebalance = taskEnd >= screenEnd - mPageSpacing;
}
if (shouldRebalance) {
updateGridProperties(/*isTaskDismissal=*/
true, highestVisibleTaskIndex);
updateScrollSynchronously();
}
}
IntArray topRowIdArray = getTopRowIdArray();
IntArray bottomRowIdArray = getBottomRowIdArray();
if (finalSnapToLastTask) {
// If snapping to last task, find the last task after dismissal.
pageToSnapTo = indexOfChild(getLastGridTaskView(topRowIdArray, bottomRowIdArray));
} else if (taskViewIdToSnapTo != -1) {
// If snapping to another page due to indices rearranging, find
// the new index after dismissal & rearrange using the task view id.
pageToSnapTo = indexOfChild(getTaskViewFromTaskViewId(taskViewIdToSnapTo));
if (!currentPageSnapsToEndOfGrid) {
// If it wasn't snapped to one of the last pages, but is now
// snapped to last pages, we'll need to compensate for the
// offset from the page's scroll to its visual position.
mCurrentPageScrollDiff += getOffsetFromScrollPosition(pageToSnapTo, topRowIdArray, bottomRowIdArray);
}
}
}
pageBeginTransition();
setCurrentPage(pageToSnapTo);
// Update various scroll-dependent UI.
dispatchScrollChanged();
updateActionsViewFocusedScroll();
if (isClearAllHidden()) {
mActionsView.updateDisabledFlags(OverviewActionsView.DISABLED_SCROLLING, false);
}
}
}
updateCurrentTaskActionsVisibility();
onDismissAnimationEnds();
mPendingAnimation = null;
}
});
return anim;
}
use of com.android.quickstep.views.ClearAllButton.DISMISS_ALPHA in project android_packages_apps_Launcher3 by ArrowOS.
the class RecentsView method createTaskDismissAnimation.
/**
* Creates a {@link PendingAnimation} for dismissing the specified {@link TaskView}.
* @param dismissedTaskView the {@link TaskView} to be dismissed
* @param animateTaskView whether the {@link TaskView} to be dismissed should be animated
* @param shouldRemoveTask whether the associated {@link Task} should be removed from
* ActivityManager after dismissal
* @param duration duration of the animation
* @param dismissingForSplitSelection task dismiss animation is used for entering split
* selection state from app icon
*/
public PendingAnimation createTaskDismissAnimation(TaskView dismissedTaskView, boolean animateTaskView, boolean shouldRemoveTask, long duration, boolean dismissingForSplitSelection) {
if (mPendingAnimation != null) {
mPendingAnimation.createPlaybackController().dispatchOnCancel().dispatchOnEnd();
}
PendingAnimation anim = new PendingAnimation(duration);
int count = getPageCount();
if (count == 0) {
return anim;
}
boolean showAsGrid = showAsGrid();
int taskCount = getTaskViewCount();
int dismissedIndex = indexOfChild(dismissedTaskView);
int dismissedTaskViewId = dismissedTaskView.getTaskViewId();
// Grid specific properties.
boolean isFocusedTaskDismissed = false;
TaskView nextFocusedTaskView = null;
boolean nextFocusedTaskFromTop = false;
float dismissedTaskWidth = 0;
float nextFocusedTaskWidth = 0;
// Non-grid specific properties.
int[] oldScroll = new int[count];
int[] newScroll = new int[count];
int scrollDiffPerPage = 0;
boolean needsCurveUpdates = false;
if (showAsGrid) {
dismissedTaskWidth = dismissedTaskView.getLayoutParams().width + mPageSpacing;
isFocusedTaskDismissed = dismissedTaskViewId == mFocusedTaskViewId;
if (isFocusedTaskDismissed && !isSplitSelectionActive()) {
nextFocusedTaskFromTop = mTopRowIdSet.size() > 0 && mTopRowIdSet.size() >= (taskCount - 1) / 2f;
// Pick the next focused task from the preferred row.
for (int i = 0; i < taskCount; i++) {
TaskView taskView = requireTaskViewAt(i);
if (taskView == dismissedTaskView) {
continue;
}
boolean isTopRow = mTopRowIdSet.contains(taskView.getTaskViewId());
if ((nextFocusedTaskFromTop && isTopRow || (!nextFocusedTaskFromTop && !isTopRow))) {
nextFocusedTaskView = taskView;
break;
}
}
if (nextFocusedTaskView != null) {
nextFocusedTaskWidth = nextFocusedTaskView.getLayoutParams().width + mPageSpacing;
}
}
} else {
getPageScrolls(oldScroll, false, SIMPLE_SCROLL_LOGIC);
getPageScrolls(newScroll, false, v -> v.getVisibility() != GONE && v != dismissedTaskView);
if (count > 1) {
scrollDiffPerPage = Math.abs(oldScroll[1] - oldScroll[0]);
}
}
announceForAccessibility(getResources().getString(R.string.task_view_closed));
float dismissTranslationInterpolationEnd = 1;
boolean closeGapBetweenClearAll = false;
boolean isClearAllHidden = isClearAllHidden();
boolean snapToLastTask = false;
boolean isLandscapeSplit = mActivity.getDeviceProfile().isLandscape && isSplitSelectionActive();
boolean isSplitPlaceholderFirstInGrid = isSplitPlaceholderFirstInGrid();
boolean isSplitPlaceholderLastInGrid = isSplitPlaceholderLastInGrid();
TaskView lastGridTaskView = showAsGrid ? getLastGridTaskView() : null;
int currentPageScroll = getScrollForPage(mCurrentPage);
int lastGridTaskScroll = getScrollForPage(indexOfChild(lastGridTaskView));
boolean currentPageSnapsToEndOfGrid = currentPageScroll == lastGridTaskScroll;
if (lastGridTaskView != null && lastGridTaskView.isVisibleToUser()) {
// 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;
int topGridRowSize = mTopRowIdSet.size();
int bottomGridRowSize = taskCount - mTopRowIdSet.size() - 1;
boolean topRowLonger = topGridRowSize > bottomGridRowSize;
boolean bottomRowLonger = bottomGridRowSize > topGridRowSize;
boolean dismissedTaskFromTop = mTopRowIdSet.contains(dismissedTaskViewId);
boolean dismissedTaskFromBottom = !dismissedTaskFromTop && !isFocusedTaskDismissed;
float gapWidth = 0;
if ((topRowLonger && dismissedTaskFromTop) || (bottomRowLonger && dismissedTaskFromBottom)) {
gapWidth = dismissedTaskWidth;
} else if ((topRowLonger && nextFocusedTaskFromTop) || (bottomRowLonger && !nextFocusedTaskFromTop)) {
gapWidth = nextFocusedTaskWidth;
}
if (gapWidth > 0) {
if (taskCount > 2) {
// Compensate the removed gap.
longGridRowWidthDiff += mIsRtl ? -gapWidth : gapWidth;
if (isClearAllHidden) {
// If ClearAllButton isn't fully shown, snap to the last task.
snapToLastTask = true;
}
} else {
// If only focused task will be left, snap to focused task instead.
longGridRowWidthDiff += getSnapToFocusedTaskScrollDiff(isClearAllHidden);
}
}
if (mClearAllButton.getAlpha() != 0f && isLandscapeSplit) {
// ClearAllButton will not be available in split select, snap to last task instead.
snapToLastTask = true;
}
if (snapToLastTask) {
longGridRowWidthDiff += getSnapToLastTaskScrollDiff();
if (isSplitPlaceholderLastInGrid) {
// Shift all the tasks to make space for split placeholder.
longGridRowWidthDiff += mIsRtl ? mSplitPlaceholderSize : -mSplitPlaceholderSize;
}
} else if (isLandscapeSplit && 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;
}
// 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);
dismissTranslationInterpolationEnd = Utilities.boundToRange(END_DISMISS_TRANSLATION_INTERPOLATION_OFFSET + (taskCount - 1) * halfAdditionalDismissTranslationOffset, END_DISMISS_TRANSLATION_INTERPOLATION_OFFSET, 1);
for (int i = 0; i < taskCount; i++) {
TaskView taskView = requireTaskViewAt(i);
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 (ENABLE_QUICKSTEP_LIVE_TILE.get() && 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);
}
});
}
}
}
int distanceFromDismissedTask = 0;
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
if (child == dismissedTaskView) {
if (animateTaskView) {
if (dismissingForSplitSelection) {
createInitialSplitSelectAnimation(anim);
} else {
addDismissedTaskAnimations(dismissedTaskView, duration, anim);
}
}
} else if (!showAsGrid) {
// Compute scroll offsets from task dismissal for animation.
// If we just take newScroll - oldScroll, everything to the right of dragged task
// translates to the left. We need to offset this in some cases:
// - In RTL, add page offset to all pages, since we want pages to move to the right
// Additionally, add a page offset if:
// - Current page is rightmost page (leftmost for RTL)
// - Dragging an adjacent page on the left side (right side for RTL)
int offset = mIsRtl ? scrollDiffPerPage : 0;
if (mCurrentPage == dismissedIndex) {
int lastPage = taskCount - 1;
if (mCurrentPage == lastPage) {
offset += mIsRtl ? -scrollDiffPerPage : scrollDiffPerPage;
}
} else {
// Dismissing an adjacent page.
// (Right in RTL, left in LTR)
int negativeAdjacent = mCurrentPage - 1;
if (dismissedIndex == negativeAdjacent) {
offset += mIsRtl ? -scrollDiffPerPage : scrollDiffPerPage;
}
}
int scrollDiff = newScroll[i] - oldScroll[i] + offset;
if (scrollDiff != 0) {
FloatProperty translationProperty = child instanceof TaskView ? ((TaskView) child).getPrimaryDismissTranslationProperty() : mOrientationHandler.getPrimaryViewTranslate();
float additionalDismissDuration = ADDITIONAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET * Math.abs(i - dismissedIndex);
anim.setFloat(child, translationProperty, scrollDiff, clampToProgress(LINEAR, Utilities.boundToRange(INITIAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET + additionalDismissDuration, 0f, 1f), 1));
if (ENABLE_QUICKSTEP_LIVE_TILE.get() && mEnableDrawingLiveTile && child instanceof TaskView && ((TaskView) child).isRunningTask()) {
anim.addOnFrameCallback(() -> {
runActionOnRemoteHandles(remoteTargetHandle -> remoteTargetHandle.getTaskViewSimulator().taskPrimaryTranslation.value = mOrientationHandler.getPrimaryValue(child.getTranslationX(), child.getTranslationY()));
redrawLiveTile();
});
}
needsCurveUpdates = true;
}
} else if (child instanceof TaskView) {
TaskView taskView = (TaskView) child;
if (isFocusedTaskDismissed) {
if (nextFocusedTaskView != null && !isSameGridRow(taskView, nextFocusedTaskView)) {
continue;
}
} else {
if (i < dismissedIndex || !isSameGridRow(taskView, dismissedTaskView)) {
continue;
}
}
// Animate task with index >= dismissed index and in the same row as the
// dismissed index or next focused index. Offset successive task dismissal
// durations for a staggered effect.
float animationStartProgress = Utilities.boundToRange(INITIAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET + ADDITIONAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET * ++distanceFromDismissedTask, 0f, dismissTranslationInterpolationEnd);
if (taskView == nextFocusedTaskView) {
// Enlarge the task to be focused next, and translate into focus position.
float scale = mTaskWidth / (float) mLastComputedGridTaskSize.width();
anim.setFloat(taskView, TaskView.SNAPSHOT_SCALE, scale, clampToProgress(LINEAR, animationStartProgress, dismissTranslationInterpolationEnd));
anim.setFloat(taskView, taskView.getPrimaryDismissTranslationProperty(), mIsRtl ? dismissedTaskWidth : -dismissedTaskWidth, clampToProgress(LINEAR, animationStartProgress, dismissTranslationInterpolationEnd));
float secondaryTranslation = -mTaskGridVerticalDiff;
if (!nextFocusedTaskFromTop) {
secondaryTranslation -= mTopBottomRowHeightDiff;
}
anim.setFloat(taskView, taskView.getSecondaryDissmissTranslationProperty(), secondaryTranslation, clampToProgress(LINEAR, animationStartProgress, dismissTranslationInterpolationEnd));
anim.setFloat(taskView, TaskView.FOCUS_TRANSITION, 0f, clampToProgress(LINEAR, 0f, ANIMATION_DISMISS_PROGRESS_MIDPOINT));
} else {
float primaryTranslation = nextFocusedTaskView != null ? nextFocusedTaskWidth : dismissedTaskWidth;
if (isFocusedTaskDismissed && nextFocusedTaskView == null) {
// Moves less if focused task is not in scroll position.
int focusedTaskScroll = getScrollForPage(dismissedIndex);
int primaryScroll = mOrientationHandler.getPrimaryScroll(this);
int focusedTaskScrollDiff = primaryScroll - focusedTaskScroll;
primaryTranslation += mIsRtl ? focusedTaskScrollDiff : -focusedTaskScrollDiff;
if (isSplitPlaceholderFirstInGrid) {
// Moves less if split placeholder is at the start.
primaryTranslation += mIsRtl ? -mSplitPlaceholderSize : mSplitPlaceholderSize;
}
}
anim.setFloat(taskView, taskView.getPrimaryDismissTranslationProperty(), mIsRtl ? primaryTranslation : -primaryTranslation, clampToProgress(LINEAR, animationStartProgress, dismissTranslationInterpolationEnd));
}
}
}
if (needsCurveUpdates) {
anim.addOnFrameCallback(this::updateCurveProperties);
}
// Add a tiny bit of translation Z, so that it draws on top of other views
if (animateTaskView) {
dismissedTaskView.setTranslationZ(0.1f);
}
mPendingAnimation = anim;
final TaskView finalNextFocusedTaskView = nextFocusedTaskView;
final boolean finalCloseGapBetweenClearAll = closeGapBetweenClearAll;
final boolean finalSnapToLastTask = snapToLastTask;
final boolean finalIsFocusedTaskDismissed = isFocusedTaskDismissed;
mPendingAnimation.addEndListener(new Consumer<Boolean>() {
@Override
public void accept(Boolean success) {
if (ENABLE_QUICKSTEP_LIVE_TILE.get() && mEnableDrawingLiveTile && dismissedTaskView.isRunningTask() && success) {
finishRecentsAnimation(true, /* toRecents */
false, /* shouldPip */
() -> onEnd(success));
} else {
onEnd(success);
}
}
@SuppressWarnings("WrongCall")
private void onEnd(boolean success) {
// Reset task translations as they may have updated via animations in
// createTaskDismissAnimation
resetTaskVisuals();
if (success) {
if (shouldRemoveTask) {
if (dismissedTaskView.getTask() != null) {
if (ENABLE_QUICKSTEP_LIVE_TILE.get() && dismissedTaskView.isRunningTask()) {
finishRecentsAnimation(true, /* toRecents */
false, /* shouldPip */
() -> removeTaskInternal(dismissedTaskViewId));
} else {
removeTaskInternal(dismissedTaskViewId);
}
mActivity.getStatsLogManager().logger().withItemInfo(dismissedTaskView.getItemInfo()).log(LAUNCHER_TASK_DISMISS_SWIPE_UP);
}
}
int pageToSnapTo = mCurrentPage;
mCurrentPageScrollDiff = 0;
int taskViewIdToSnapTo = -1;
if (showAsGrid) {
if (finalCloseGapBetweenClearAll) {
if (finalSnapToLastTask) {
// Last task will be determined after removing dismissed task.
pageToSnapTo = -1;
} else if (taskCount > 2) {
pageToSnapTo = indexOfChild(mClearAllButton);
} else if (isClearAllHidden) {
// Snap to focused task if clear all is hidden.
pageToSnapTo = 0;
}
} else {
// Get the id of the task view we will snap to based on the current
// page's relative position as the order of indices change over time due
// to dismissals.
TaskView snappedTaskView = getTaskViewAt(mCurrentPage);
boolean calculateScrollDiff = true;
if (snappedTaskView != null && !finalSnapToLastTask) {
if (snappedTaskView.getTaskViewId() == mFocusedTaskViewId) {
if (finalNextFocusedTaskView != null) {
taskViewIdToSnapTo = finalNextFocusedTaskView.getTaskViewId();
} else if (dismissedTaskViewId != mFocusedTaskViewId) {
taskViewIdToSnapTo = mFocusedTaskViewId;
} else {
// Won't focus next task in split select, so snap to the
// first task.
pageToSnapTo = 0;
calculateScrollDiff = false;
}
} else {
int snappedTaskViewId = snappedTaskView.getTaskViewId();
boolean isSnappedTaskInTopRow = mTopRowIdSet.contains(snappedTaskViewId);
IntArray taskViewIdArray = isSnappedTaskInTopRow ? getTopRowIdArray() : getBottomRowIdArray();
int snappedIndex = taskViewIdArray.indexOf(snappedTaskViewId);
taskViewIdArray.removeValue(dismissedTaskViewId);
if (finalNextFocusedTaskView != null) {
taskViewIdArray.removeValue(finalNextFocusedTaskView.getTaskViewId());
}
if (snappedIndex < taskViewIdArray.size()) {
taskViewIdToSnapTo = taskViewIdArray.get(snappedIndex);
} else if (snappedIndex == taskViewIdArray.size()) {
// If the snapped task is the last item from the
// dismissed row,
// snap to the same column in the other grid row
IntArray inverseRowTaskViewIdArray = isSnappedTaskInTopRow ? getBottomRowIdArray() : getTopRowIdArray();
if (snappedIndex < inverseRowTaskViewIdArray.size()) {
taskViewIdToSnapTo = inverseRowTaskViewIdArray.get(snappedIndex);
}
}
}
}
if (calculateScrollDiff) {
int primaryScroll = mOrientationHandler.getPrimaryScroll(RecentsView.this);
int currentPageScroll = getScrollForPage(mCurrentPage);
mCurrentPageScrollDiff = primaryScroll - currentPageScroll;
// Compensate for coordinate shift by split placeholder.
if (isSplitPlaceholderFirstInGrid && !finalSnapToLastTask) {
mCurrentPageScrollDiff += mIsRtl ? -mSplitPlaceholderSize : mSplitPlaceholderSize;
} else if (isSplitPlaceholderLastInGrid && finalSnapToLastTask) {
mCurrentPageScrollDiff += mIsRtl ? mSplitPlaceholderSize : -mSplitPlaceholderSize;
}
}
}
} else if (dismissedIndex < pageToSnapTo || pageToSnapTo == taskCount - 1) {
pageToSnapTo--;
}
boolean isHomeTaskDismissed = dismissedTaskView == getHomeTaskView();
removeViewInLayout(dismissedTaskView);
mTopRowIdSet.remove(dismissedTaskViewId);
if (taskCount == 1) {
removeViewInLayout(mClearAllButton);
if (isHomeTaskDismissed) {
updateEmptyMessage();
} else {
startHome();
}
} else {
// Update focus task and its size.
if (finalIsFocusedTaskDismissed && finalNextFocusedTaskView != null) {
mFocusedTaskViewId = finalNextFocusedTaskView.getTaskViewId();
mTopRowIdSet.remove(mFocusedTaskViewId);
finalNextFocusedTaskView.animateIconScaleAndDimIntoView();
}
updateTaskSize(/*isTaskDismissal=*/
true);
updateChildTaskOrientations();
// Update scroll and snap to page.
updateScrollSynchronously();
if (showAsGrid) {
// Rebalance tasks in the grid
int highestVisibleTaskIndex = getHighestVisibleTaskIndex();
if (highestVisibleTaskIndex < Integer.MAX_VALUE) {
TaskView taskView = requireTaskViewAt(highestVisibleTaskIndex);
boolean shouldRebalance;
int screenStart = mOrientationHandler.getPrimaryScroll(RecentsView.this);
int taskStart = mOrientationHandler.getChildStart(taskView) + (int) taskView.getOffsetAdjustment(/*fullscreenEnabled=*/
false, /*gridEnabled=*/
true);
// visible screen.
if (mIsRtl) {
shouldRebalance = taskStart <= screenStart + mPageSpacing;
} else {
int screenEnd = screenStart + mOrientationHandler.getMeasuredSize(RecentsView.this);
int taskSize = (int) (mOrientationHandler.getMeasuredSize(taskView) * taskView.getSizeAdjustment(/*fullscreenEnabled=*/
false));
int taskEnd = taskStart + taskSize;
shouldRebalance = taskEnd >= screenEnd - mPageSpacing;
}
if (shouldRebalance) {
updateGridProperties(/*isTaskDismissal=*/
true, highestVisibleTaskIndex);
updateScrollSynchronously();
}
}
IntArray topRowIdArray = getTopRowIdArray();
IntArray bottomRowIdArray = getBottomRowIdArray();
if (finalSnapToLastTask) {
// If snapping to last task, find the last task after dismissal.
pageToSnapTo = indexOfChild(getLastGridTaskView(topRowIdArray, bottomRowIdArray));
} else if (taskViewIdToSnapTo != -1) {
// If snapping to another page due to indices rearranging, find
// the new index after dismissal & rearrange using the task view id.
pageToSnapTo = indexOfChild(getTaskViewFromTaskViewId(taskViewIdToSnapTo));
if (!currentPageSnapsToEndOfGrid) {
// If it wasn't snapped to one of the last pages, but is now
// snapped to last pages, we'll need to compensate for the
// offset from the page's scroll to its visual position.
mCurrentPageScrollDiff += getOffsetFromScrollPosition(pageToSnapTo, topRowIdArray, bottomRowIdArray);
}
}
}
pageBeginTransition();
setCurrentPage(pageToSnapTo);
// Update various scroll-dependent UI.
dispatchScrollChanged();
updateActionsViewFocusedScroll();
if (isClearAllHidden()) {
mActionsView.updateDisabledFlags(OverviewActionsView.DISABLED_SCROLLING, false);
}
}
}
updateCurrentTaskActionsVisibility();
onDismissAnimationEnds();
mPendingAnimation = null;
}
});
return anim;
}
use of com.android.quickstep.views.ClearAllButton.DISMISS_ALPHA in project android_packages_apps_Launcher3 by ProtonAOSP.
the class RecentsView method createTaskDismissAnimation.
/**
* Creates a {@link PendingAnimation} for dismissing the specified {@link TaskView}.
* @param dismissedTaskView the {@link TaskView} to be dismissed
* @param animateTaskView whether the {@link TaskView} to be dismissed should be animated
* @param shouldRemoveTask whether the associated {@link Task} should be removed from
* ActivityManager after dismissal
* @param duration duration of the animation
* @param dismissingForSplitSelection task dismiss animation is used for entering split
* selection state from app icon
*/
public PendingAnimation createTaskDismissAnimation(TaskView dismissedTaskView, boolean animateTaskView, boolean shouldRemoveTask, long duration, boolean dismissingForSplitSelection) {
if (mPendingAnimation != null) {
mPendingAnimation.createPlaybackController().dispatchOnCancel().dispatchOnEnd();
}
PendingAnimation anim = new PendingAnimation(duration);
int count = getPageCount();
if (count == 0) {
return anim;
}
boolean showAsGrid = showAsGrid();
int taskCount = getTaskViewCount();
int dismissedIndex = indexOfChild(dismissedTaskView);
int dismissedTaskViewId = dismissedTaskView.getTaskViewId();
// Grid specific properties.
boolean isFocusedTaskDismissed = false;
TaskView nextFocusedTaskView = null;
boolean nextFocusedTaskFromTop = false;
float dismissedTaskWidth = 0;
float nextFocusedTaskWidth = 0;
// Non-grid specific properties.
int[] oldScroll = new int[count];
int[] newScroll = new int[count];
int scrollDiffPerPage = 0;
boolean needsCurveUpdates = false;
if (showAsGrid) {
dismissedTaskWidth = dismissedTaskView.getLayoutParams().width + mPageSpacing;
isFocusedTaskDismissed = dismissedTaskViewId == mFocusedTaskViewId;
if (isFocusedTaskDismissed && !isSplitSelectionActive()) {
nextFocusedTaskFromTop = mTopRowIdSet.size() > 0 && mTopRowIdSet.size() >= (taskCount - 1) / 2f;
// Pick the next focused task from the preferred row.
for (int i = 0; i < taskCount; i++) {
TaskView taskView = requireTaskViewAt(i);
if (taskView == dismissedTaskView) {
continue;
}
boolean isTopRow = mTopRowIdSet.contains(taskView.getTaskViewId());
if ((nextFocusedTaskFromTop && isTopRow || (!nextFocusedTaskFromTop && !isTopRow))) {
nextFocusedTaskView = taskView;
break;
}
}
if (nextFocusedTaskView != null) {
nextFocusedTaskWidth = nextFocusedTaskView.getLayoutParams().width + mPageSpacing;
}
}
} else {
getPageScrolls(oldScroll, false, SIMPLE_SCROLL_LOGIC);
getPageScrolls(newScroll, false, v -> v.getVisibility() != GONE && v != dismissedTaskView);
if (count > 1) {
scrollDiffPerPage = Math.abs(oldScroll[1] - oldScroll[0]);
}
}
announceForAccessibility(getResources().getString(R.string.task_view_closed));
float dismissTranslationInterpolationEnd = 1;
boolean closeGapBetweenClearAll = false;
boolean isClearAllHidden = isClearAllHidden();
boolean snapToLastTask = false;
boolean isLandscapeSplit = mActivity.getDeviceProfile().isLandscape && isSplitSelectionActive();
boolean isSplitPlaceholderFirstInGrid = isSplitPlaceholderFirstInGrid();
boolean isSplitPlaceholderLastInGrid = isSplitPlaceholderLastInGrid();
TaskView lastGridTaskView = showAsGrid ? getLastGridTaskView() : null;
int currentPageScroll = getScrollForPage(mCurrentPage);
int lastGridTaskScroll = getScrollForPage(indexOfChild(lastGridTaskView));
boolean currentPageSnapsToEndOfGrid = currentPageScroll == lastGridTaskScroll;
if (lastGridTaskView != null && lastGridTaskView.isVisibleToUser()) {
// 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;
int topGridRowSize = mTopRowIdSet.size();
int bottomGridRowSize = taskCount - mTopRowIdSet.size() - 1;
boolean topRowLonger = topGridRowSize > bottomGridRowSize;
boolean bottomRowLonger = bottomGridRowSize > topGridRowSize;
boolean dismissedTaskFromTop = mTopRowIdSet.contains(dismissedTaskViewId);
boolean dismissedTaskFromBottom = !dismissedTaskFromTop && !isFocusedTaskDismissed;
float gapWidth = 0;
if ((topRowLonger && dismissedTaskFromTop) || (bottomRowLonger && dismissedTaskFromBottom)) {
gapWidth = dismissedTaskWidth;
} else if ((topRowLonger && nextFocusedTaskFromTop) || (bottomRowLonger && !nextFocusedTaskFromTop)) {
gapWidth = nextFocusedTaskWidth;
}
if (gapWidth > 0) {
if (taskCount > 2) {
// Compensate the removed gap.
longGridRowWidthDiff += mIsRtl ? -gapWidth : gapWidth;
if (isClearAllHidden) {
// If ClearAllButton isn't fully shown, snap to the last task.
snapToLastTask = true;
}
} else {
// If only focused task will be left, snap to focused task instead.
longGridRowWidthDiff += getSnapToFocusedTaskScrollDiff(isClearAllHidden);
}
}
if (mClearAllButton.getAlpha() != 0f && isLandscapeSplit) {
// ClearAllButton will not be available in split select, snap to last task instead.
snapToLastTask = true;
}
if (snapToLastTask) {
longGridRowWidthDiff += getSnapToLastTaskScrollDiff();
if (isSplitPlaceholderLastInGrid) {
// Shift all the tasks to make space for split placeholder.
longGridRowWidthDiff += mIsRtl ? mSplitPlaceholderSize : -mSplitPlaceholderSize;
}
} else if (isLandscapeSplit && 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;
}
// 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);
dismissTranslationInterpolationEnd = Utilities.boundToRange(END_DISMISS_TRANSLATION_INTERPOLATION_OFFSET + (taskCount - 1) * halfAdditionalDismissTranslationOffset, END_DISMISS_TRANSLATION_INTERPOLATION_OFFSET, 1);
for (int i = 0; i < taskCount; i++) {
TaskView taskView = requireTaskViewAt(i);
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 (ENABLE_QUICKSTEP_LIVE_TILE.get() && 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);
}
});
}
}
}
int distanceFromDismissedTask = 0;
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
if (child == dismissedTaskView) {
if (animateTaskView) {
if (dismissingForSplitSelection) {
createInitialSplitSelectAnimation(anim);
} else {
addDismissedTaskAnimations(dismissedTaskView, duration, anim);
}
}
} else if (!showAsGrid) {
// Compute scroll offsets from task dismissal for animation.
// If we just take newScroll - oldScroll, everything to the right of dragged task
// translates to the left. We need to offset this in some cases:
// - In RTL, add page offset to all pages, since we want pages to move to the right
// Additionally, add a page offset if:
// - Current page is rightmost page (leftmost for RTL)
// - Dragging an adjacent page on the left side (right side for RTL)
int offset = mIsRtl ? scrollDiffPerPage : 0;
if (mCurrentPage == dismissedIndex) {
int lastPage = taskCount - 1;
if (mCurrentPage == lastPage) {
offset += mIsRtl ? -scrollDiffPerPage : scrollDiffPerPage;
}
} else {
// Dismissing an adjacent page.
// (Right in RTL, left in LTR)
int negativeAdjacent = mCurrentPage - 1;
if (dismissedIndex == negativeAdjacent) {
offset += mIsRtl ? -scrollDiffPerPage : scrollDiffPerPage;
}
}
int scrollDiff = newScroll[i] - oldScroll[i] + offset;
if (scrollDiff != 0) {
FloatProperty translationProperty = child instanceof TaskView ? ((TaskView) child).getPrimaryDismissTranslationProperty() : mOrientationHandler.getPrimaryViewTranslate();
float additionalDismissDuration = ADDITIONAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET * Math.abs(i - dismissedIndex);
anim.setFloat(child, translationProperty, scrollDiff, clampToProgress(LINEAR, Utilities.boundToRange(INITIAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET + additionalDismissDuration, 0f, 1f), 1));
if (ENABLE_QUICKSTEP_LIVE_TILE.get() && mEnableDrawingLiveTile && child instanceof TaskView && ((TaskView) child).isRunningTask()) {
anim.addOnFrameCallback(() -> {
runActionOnRemoteHandles(remoteTargetHandle -> remoteTargetHandle.getTaskViewSimulator().taskPrimaryTranslation.value = mOrientationHandler.getPrimaryValue(child.getTranslationX(), child.getTranslationY()));
redrawLiveTile();
});
}
needsCurveUpdates = true;
}
} else if (child instanceof TaskView) {
TaskView taskView = (TaskView) child;
if (isFocusedTaskDismissed) {
if (nextFocusedTaskView != null && !isSameGridRow(taskView, nextFocusedTaskView)) {
continue;
}
} else {
if (i < dismissedIndex || !isSameGridRow(taskView, dismissedTaskView)) {
continue;
}
}
// Animate task with index >= dismissed index and in the same row as the
// dismissed index or next focused index. Offset successive task dismissal
// durations for a staggered effect.
float animationStartProgress = Utilities.boundToRange(INITIAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET + ADDITIONAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET * ++distanceFromDismissedTask, 0f, dismissTranslationInterpolationEnd);
if (taskView == nextFocusedTaskView) {
// Enlarge the task to be focused next, and translate into focus position.
float scale = mTaskWidth / (float) mLastComputedGridTaskSize.width();
anim.setFloat(taskView, TaskView.SNAPSHOT_SCALE, scale, clampToProgress(LINEAR, animationStartProgress, dismissTranslationInterpolationEnd));
anim.setFloat(taskView, taskView.getPrimaryDismissTranslationProperty(), mIsRtl ? dismissedTaskWidth : -dismissedTaskWidth, clampToProgress(LINEAR, animationStartProgress, dismissTranslationInterpolationEnd));
float secondaryTranslation = -mTaskGridVerticalDiff;
if (!nextFocusedTaskFromTop) {
secondaryTranslation -= mTopBottomRowHeightDiff;
}
anim.setFloat(taskView, taskView.getSecondaryDissmissTranslationProperty(), secondaryTranslation, clampToProgress(LINEAR, animationStartProgress, dismissTranslationInterpolationEnd));
anim.setFloat(taskView, TaskView.FOCUS_TRANSITION, 0f, clampToProgress(LINEAR, 0f, ANIMATION_DISMISS_PROGRESS_MIDPOINT));
} else {
float primaryTranslation = nextFocusedTaskView != null ? nextFocusedTaskWidth : dismissedTaskWidth;
if (isFocusedTaskDismissed && nextFocusedTaskView == null) {
// Moves less if focused task is not in scroll position.
int focusedTaskScroll = getScrollForPage(dismissedIndex);
int primaryScroll = mOrientationHandler.getPrimaryScroll(this);
int focusedTaskScrollDiff = primaryScroll - focusedTaskScroll;
primaryTranslation += mIsRtl ? focusedTaskScrollDiff : -focusedTaskScrollDiff;
if (isSplitPlaceholderFirstInGrid) {
// Moves less if split placeholder is at the start.
primaryTranslation += mIsRtl ? -mSplitPlaceholderSize : mSplitPlaceholderSize;
}
}
anim.setFloat(taskView, taskView.getPrimaryDismissTranslationProperty(), mIsRtl ? primaryTranslation : -primaryTranslation, clampToProgress(LINEAR, animationStartProgress, dismissTranslationInterpolationEnd));
}
}
}
if (needsCurveUpdates) {
anim.addOnFrameCallback(this::updateCurveProperties);
}
// Add a tiny bit of translation Z, so that it draws on top of other views
if (animateTaskView) {
dismissedTaskView.setTranslationZ(0.1f);
}
mPendingAnimation = anim;
final TaskView finalNextFocusedTaskView = nextFocusedTaskView;
final boolean finalCloseGapBetweenClearAll = closeGapBetweenClearAll;
final boolean finalSnapToLastTask = snapToLastTask;
final boolean finalIsFocusedTaskDismissed = isFocusedTaskDismissed;
mPendingAnimation.addEndListener(new Consumer<Boolean>() {
@Override
public void accept(Boolean success) {
if (ENABLE_QUICKSTEP_LIVE_TILE.get() && mEnableDrawingLiveTile && dismissedTaskView.isRunningTask() && success) {
finishRecentsAnimation(true, /* toRecents */
false, /* shouldPip */
() -> onEnd(success));
} else {
onEnd(success);
}
}
@SuppressWarnings("WrongCall")
private void onEnd(boolean success) {
// Reset task translations as they may have updated via animations in
// createTaskDismissAnimation
resetTaskVisuals();
if (success) {
if (shouldRemoveTask) {
if (dismissedTaskView.getTask() != null) {
if (ENABLE_QUICKSTEP_LIVE_TILE.get() && dismissedTaskView.isRunningTask()) {
finishRecentsAnimation(true, /* toRecents */
false, /* shouldPip */
() -> removeTaskInternal(dismissedTaskViewId));
} else {
removeTaskInternal(dismissedTaskViewId);
}
mActivity.getStatsLogManager().logger().withItemInfo(dismissedTaskView.getItemInfo()).log(LAUNCHER_TASK_DISMISS_SWIPE_UP);
}
}
int pageToSnapTo = mCurrentPage;
mCurrentPageScrollDiff = 0;
int taskViewIdToSnapTo = -1;
if (showAsGrid) {
if (finalCloseGapBetweenClearAll) {
if (finalSnapToLastTask) {
// Last task will be determined after removing dismissed task.
pageToSnapTo = -1;
} else if (taskCount > 2) {
pageToSnapTo = indexOfChild(mClearAllButton);
} else if (isClearAllHidden) {
// Snap to focused task if clear all is hidden.
pageToSnapTo = 0;
}
} else {
// Get the id of the task view we will snap to based on the current
// page's relative position as the order of indices change over time due
// to dismissals.
TaskView snappedTaskView = getTaskViewAt(mCurrentPage);
boolean calculateScrollDiff = true;
if (snappedTaskView != null && !finalSnapToLastTask) {
if (snappedTaskView.getTaskViewId() == mFocusedTaskViewId) {
if (finalNextFocusedTaskView != null) {
taskViewIdToSnapTo = finalNextFocusedTaskView.getTaskViewId();
} else if (dismissedTaskViewId != mFocusedTaskViewId) {
taskViewIdToSnapTo = mFocusedTaskViewId;
} else {
// Won't focus next task in split select, so snap to the
// first task.
pageToSnapTo = 0;
calculateScrollDiff = false;
}
} else {
int snappedTaskViewId = snappedTaskView.getTaskViewId();
boolean isSnappedTaskInTopRow = mTopRowIdSet.contains(snappedTaskViewId);
IntArray taskViewIdArray = isSnappedTaskInTopRow ? getTopRowIdArray() : getBottomRowIdArray();
int snappedIndex = taskViewIdArray.indexOf(snappedTaskViewId);
taskViewIdArray.removeValue(dismissedTaskViewId);
if (finalNextFocusedTaskView != null) {
taskViewIdArray.removeValue(finalNextFocusedTaskView.getTaskViewId());
}
if (snappedIndex < taskViewIdArray.size()) {
taskViewIdToSnapTo = taskViewIdArray.get(snappedIndex);
} else if (snappedIndex == taskViewIdArray.size()) {
// If the snapped task is the last item from the
// dismissed row,
// snap to the same column in the other grid row
IntArray inverseRowTaskViewIdArray = isSnappedTaskInTopRow ? getBottomRowIdArray() : getTopRowIdArray();
if (snappedIndex < inverseRowTaskViewIdArray.size()) {
taskViewIdToSnapTo = inverseRowTaskViewIdArray.get(snappedIndex);
}
}
}
}
if (calculateScrollDiff) {
int primaryScroll = mOrientationHandler.getPrimaryScroll(RecentsView.this);
int currentPageScroll = getScrollForPage(mCurrentPage);
mCurrentPageScrollDiff = primaryScroll - currentPageScroll;
// Compensate for coordinate shift by split placeholder.
if (isSplitPlaceholderFirstInGrid && !finalSnapToLastTask) {
mCurrentPageScrollDiff += mIsRtl ? -mSplitPlaceholderSize : mSplitPlaceholderSize;
} else if (isSplitPlaceholderLastInGrid && finalSnapToLastTask) {
mCurrentPageScrollDiff += mIsRtl ? mSplitPlaceholderSize : -mSplitPlaceholderSize;
}
}
}
} else if (dismissedIndex < pageToSnapTo || pageToSnapTo == taskCount - 1) {
pageToSnapTo--;
}
boolean isHomeTaskDismissed = dismissedTaskView == getHomeTaskView();
removeViewInLayout(dismissedTaskView);
mTopRowIdSet.remove(dismissedTaskViewId);
if (taskCount == 1) {
removeViewInLayout(mClearAllButton);
if (isHomeTaskDismissed) {
updateEmptyMessage();
} else {
startHome();
}
} else {
// Update focus task and its size.
if (finalIsFocusedTaskDismissed && finalNextFocusedTaskView != null) {
mFocusedTaskViewId = finalNextFocusedTaskView.getTaskViewId();
mTopRowIdSet.remove(mFocusedTaskViewId);
finalNextFocusedTaskView.animateIconScaleAndDimIntoView();
}
updateTaskSize(/*isTaskDismissal=*/
true);
updateChildTaskOrientations();
// Update scroll and snap to page.
updateScrollSynchronously();
if (showAsGrid) {
// Rebalance tasks in the grid
int highestVisibleTaskIndex = getHighestVisibleTaskIndex();
if (highestVisibleTaskIndex < Integer.MAX_VALUE) {
TaskView taskView = requireTaskViewAt(highestVisibleTaskIndex);
boolean shouldRebalance;
int screenStart = mOrientationHandler.getPrimaryScroll(RecentsView.this);
int taskStart = mOrientationHandler.getChildStart(taskView) + (int) taskView.getOffsetAdjustment(/*fullscreenEnabled=*/
false, /*gridEnabled=*/
true);
// visible screen.
if (mIsRtl) {
shouldRebalance = taskStart <= screenStart + mPageSpacing;
} else {
int screenEnd = screenStart + mOrientationHandler.getMeasuredSize(RecentsView.this);
int taskSize = (int) (mOrientationHandler.getMeasuredSize(taskView) * taskView.getSizeAdjustment(/*fullscreenEnabled=*/
false));
int taskEnd = taskStart + taskSize;
shouldRebalance = taskEnd >= screenEnd - mPageSpacing;
}
if (shouldRebalance) {
updateGridProperties(/*isTaskDismissal=*/
true, highestVisibleTaskIndex);
updateScrollSynchronously();
}
}
IntArray topRowIdArray = getTopRowIdArray();
IntArray bottomRowIdArray = getBottomRowIdArray();
if (finalSnapToLastTask) {
// If snapping to last task, find the last task after dismissal.
pageToSnapTo = indexOfChild(getLastGridTaskView(topRowIdArray, bottomRowIdArray));
} else if (taskViewIdToSnapTo != -1) {
// If snapping to another page due to indices rearranging, find
// the new index after dismissal & rearrange using the task view id.
pageToSnapTo = indexOfChild(getTaskViewFromTaskViewId(taskViewIdToSnapTo));
if (!currentPageSnapsToEndOfGrid) {
// If it wasn't snapped to one of the last pages, but is now
// snapped to last pages, we'll need to compensate for the
// offset from the page's scroll to its visual position.
mCurrentPageScrollDiff += getOffsetFromScrollPosition(pageToSnapTo, topRowIdArray, bottomRowIdArray);
}
}
}
pageBeginTransition();
setCurrentPage(pageToSnapTo);
// Update various scroll-dependent UI.
dispatchScrollChanged();
updateActionsViewFocusedScroll();
if (isClearAllHidden()) {
mActionsView.updateDisabledFlags(OverviewActionsView.DISABLED_SCROLLING, false);
}
}
}
updateCurrentTaskActionsVisibility();
onDismissAnimationEnds();
mPendingAnimation = null;
}
});
return anim;
}
use of com.android.quickstep.views.ClearAllButton.DISMISS_ALPHA in project android_packages_apps_404Launcher by P-404.
the class RecentsView method createTaskDismissAnimation.
/**
* Creates a {@link PendingAnimation} for dismissing the specified {@link TaskView}.
* @param dismissedTaskView the {@link TaskView} to be dismissed
* @param animateTaskView whether the {@link TaskView} to be dismissed should be animated
* @param shouldRemoveTask whether the associated {@link Task} should be removed from
* ActivityManager after dismissal
* @param duration duration of the animation
* @param dismissingForSplitSelection task dismiss animation is used for entering split
* selection state from app icon
*/
public PendingAnimation createTaskDismissAnimation(TaskView dismissedTaskView, boolean animateTaskView, boolean shouldRemoveTask, long duration, boolean dismissingForSplitSelection) {
if (mPendingAnimation != null) {
mPendingAnimation.createPlaybackController().dispatchOnCancel().dispatchOnEnd();
}
PendingAnimation anim = new PendingAnimation(duration);
int count = getPageCount();
if (count == 0) {
return anim;
}
boolean showAsGrid = showAsGrid();
int taskCount = getTaskViewCount();
int dismissedIndex = indexOfChild(dismissedTaskView);
int dismissedTaskViewId = dismissedTaskView.getTaskViewId();
// Grid specific properties.
boolean isFocusedTaskDismissed = false;
TaskView nextFocusedTaskView = null;
boolean nextFocusedTaskFromTop = false;
float dismissedTaskWidth = 0;
float nextFocusedTaskWidth = 0;
// Non-grid specific properties.
int[] oldScroll = new int[count];
int[] newScroll = new int[count];
int scrollDiffPerPage = 0;
boolean needsCurveUpdates = false;
if (showAsGrid) {
dismissedTaskWidth = dismissedTaskView.getLayoutParams().width + mPageSpacing;
isFocusedTaskDismissed = dismissedTaskViewId == mFocusedTaskViewId;
if (isFocusedTaskDismissed && !isSplitSelectionActive()) {
nextFocusedTaskFromTop = mTopRowIdSet.size() > 0 && mTopRowIdSet.size() >= (taskCount - 1) / 2f;
// Pick the next focused task from the preferred row.
for (int i = 0; i < taskCount; i++) {
TaskView taskView = requireTaskViewAt(i);
if (taskView == dismissedTaskView) {
continue;
}
boolean isTopRow = mTopRowIdSet.contains(taskView.getTaskViewId());
if ((nextFocusedTaskFromTop && isTopRow || (!nextFocusedTaskFromTop && !isTopRow))) {
nextFocusedTaskView = taskView;
break;
}
}
if (nextFocusedTaskView != null) {
nextFocusedTaskWidth = nextFocusedTaskView.getLayoutParams().width + mPageSpacing;
}
}
} else {
getPageScrolls(oldScroll, false, SIMPLE_SCROLL_LOGIC);
getPageScrolls(newScroll, false, v -> v.getVisibility() != GONE && v != dismissedTaskView);
if (count > 1) {
scrollDiffPerPage = Math.abs(oldScroll[1] - oldScroll[0]);
}
}
announceForAccessibility(getResources().getString(R.string.task_view_closed));
float dismissTranslationInterpolationEnd = 1;
boolean closeGapBetweenClearAll = false;
boolean isClearAllHidden = isClearAllHidden();
boolean snapToLastTask = false;
boolean isLandscapeSplit = mActivity.getDeviceProfile().isLandscape && isSplitSelectionActive();
boolean isSplitPlaceholderFirstInGrid = isSplitPlaceholderFirstInGrid();
boolean isSplitPlaceholderLastInGrid = isSplitPlaceholderLastInGrid();
TaskView lastGridTaskView = showAsGrid ? getLastGridTaskView() : null;
int currentPageScroll = getScrollForPage(mCurrentPage);
int lastGridTaskScroll = getScrollForPage(indexOfChild(lastGridTaskView));
boolean currentPageSnapsToEndOfGrid = currentPageScroll == lastGridTaskScroll;
if (lastGridTaskView != null && lastGridTaskView.isVisibleToUser()) {
// 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;
int topGridRowSize = mTopRowIdSet.size();
int bottomGridRowSize = taskCount - mTopRowIdSet.size() - 1;
boolean topRowLonger = topGridRowSize > bottomGridRowSize;
boolean bottomRowLonger = bottomGridRowSize > topGridRowSize;
boolean dismissedTaskFromTop = mTopRowIdSet.contains(dismissedTaskViewId);
boolean dismissedTaskFromBottom = !dismissedTaskFromTop && !isFocusedTaskDismissed;
float gapWidth = 0;
if ((topRowLonger && dismissedTaskFromTop) || (bottomRowLonger && dismissedTaskFromBottom)) {
gapWidth = dismissedTaskWidth;
} else if ((topRowLonger && nextFocusedTaskFromTop) || (bottomRowLonger && !nextFocusedTaskFromTop)) {
gapWidth = nextFocusedTaskWidth;
}
if (gapWidth > 0) {
if (taskCount > 2) {
// Compensate the removed gap.
longGridRowWidthDiff += mIsRtl ? -gapWidth : gapWidth;
if (isClearAllHidden) {
// If ClearAllButton isn't fully shown, snap to the last task.
snapToLastTask = true;
}
} else {
// If only focused task will be left, snap to focused task instead.
longGridRowWidthDiff += getSnapToFocusedTaskScrollDiff(isClearAllHidden);
}
}
if (mClearAllButton.getAlpha() != 0f && isLandscapeSplit) {
// ClearAllButton will not be available in split select, snap to last task instead.
snapToLastTask = true;
}
if (snapToLastTask) {
longGridRowWidthDiff += getSnapToLastTaskScrollDiff();
if (isSplitPlaceholderLastInGrid) {
// Shift all the tasks to make space for split placeholder.
longGridRowWidthDiff += mIsRtl ? mSplitPlaceholderSize : -mSplitPlaceholderSize;
}
} else if (isLandscapeSplit && 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;
}
// 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);
dismissTranslationInterpolationEnd = Utilities.boundToRange(END_DISMISS_TRANSLATION_INTERPOLATION_OFFSET + (taskCount - 1) * halfAdditionalDismissTranslationOffset, END_DISMISS_TRANSLATION_INTERPOLATION_OFFSET, 1);
for (int i = 0; i < taskCount; i++) {
TaskView taskView = requireTaskViewAt(i);
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 (ENABLE_QUICKSTEP_LIVE_TILE.get() && 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);
}
});
}
}
}
int distanceFromDismissedTask = 0;
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
if (child == dismissedTaskView) {
if (animateTaskView) {
if (dismissingForSplitSelection) {
createInitialSplitSelectAnimation(anim);
} else {
addDismissedTaskAnimations(dismissedTaskView, duration, anim);
}
}
} else if (!showAsGrid) {
// Compute scroll offsets from task dismissal for animation.
// If we just take newScroll - oldScroll, everything to the right of dragged task
// translates to the left. We need to offset this in some cases:
// - In RTL, add page offset to all pages, since we want pages to move to the right
// Additionally, add a page offset if:
// - Current page is rightmost page (leftmost for RTL)
// - Dragging an adjacent page on the left side (right side for RTL)
int offset = mIsRtl ? scrollDiffPerPage : 0;
if (mCurrentPage == dismissedIndex) {
int lastPage = taskCount - 1;
if (mCurrentPage == lastPage) {
offset += mIsRtl ? -scrollDiffPerPage : scrollDiffPerPage;
}
} else {
// Dismissing an adjacent page.
// (Right in RTL, left in LTR)
int negativeAdjacent = mCurrentPage - 1;
if (dismissedIndex == negativeAdjacent) {
offset += mIsRtl ? -scrollDiffPerPage : scrollDiffPerPage;
}
}
int scrollDiff = newScroll[i] - oldScroll[i] + offset;
if (scrollDiff != 0) {
FloatProperty translationProperty = child instanceof TaskView ? ((TaskView) child).getPrimaryDismissTranslationProperty() : mOrientationHandler.getPrimaryViewTranslate();
float additionalDismissDuration = ADDITIONAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET * Math.abs(i - dismissedIndex);
anim.setFloat(child, translationProperty, scrollDiff, clampToProgress(LINEAR, Utilities.boundToRange(INITIAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET + additionalDismissDuration, 0f, 1f), 1));
if (ENABLE_QUICKSTEP_LIVE_TILE.get() && mEnableDrawingLiveTile && child instanceof TaskView && ((TaskView) child).isRunningTask()) {
anim.addOnFrameCallback(() -> {
runActionOnRemoteHandles(remoteTargetHandle -> remoteTargetHandle.getTaskViewSimulator().taskPrimaryTranslation.value = mOrientationHandler.getPrimaryValue(child.getTranslationX(), child.getTranslationY()));
redrawLiveTile();
});
}
needsCurveUpdates = true;
}
} else if (child instanceof TaskView) {
TaskView taskView = (TaskView) child;
if (isFocusedTaskDismissed) {
if (nextFocusedTaskView != null && !isSameGridRow(taskView, nextFocusedTaskView)) {
continue;
}
} else {
if (i < dismissedIndex || !isSameGridRow(taskView, dismissedTaskView)) {
continue;
}
}
// Animate task with index >= dismissed index and in the same row as the
// dismissed index or next focused index. Offset successive task dismissal
// durations for a staggered effect.
float animationStartProgress = Utilities.boundToRange(INITIAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET + ADDITIONAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET * ++distanceFromDismissedTask, 0f, dismissTranslationInterpolationEnd);
if (taskView == nextFocusedTaskView) {
// Enlarge the task to be focused next, and translate into focus position.
float scale = mTaskWidth / (float) mLastComputedGridTaskSize.width();
anim.setFloat(taskView, TaskView.SNAPSHOT_SCALE, scale, clampToProgress(LINEAR, animationStartProgress, dismissTranslationInterpolationEnd));
anim.setFloat(taskView, taskView.getPrimaryDismissTranslationProperty(), mIsRtl ? dismissedTaskWidth : -dismissedTaskWidth, clampToProgress(LINEAR, animationStartProgress, dismissTranslationInterpolationEnd));
float secondaryTranslation = -mTaskGridVerticalDiff;
if (!nextFocusedTaskFromTop) {
secondaryTranslation -= mTopBottomRowHeightDiff;
}
anim.setFloat(taskView, taskView.getSecondaryDissmissTranslationProperty(), secondaryTranslation, clampToProgress(LINEAR, animationStartProgress, dismissTranslationInterpolationEnd));
anim.setFloat(taskView, TaskView.FOCUS_TRANSITION, 0f, clampToProgress(LINEAR, 0f, ANIMATION_DISMISS_PROGRESS_MIDPOINT));
} else {
float primaryTranslation = nextFocusedTaskView != null ? nextFocusedTaskWidth : dismissedTaskWidth;
if (isFocusedTaskDismissed && nextFocusedTaskView == null) {
// Moves less if focused task is not in scroll position.
int focusedTaskScroll = getScrollForPage(dismissedIndex);
int primaryScroll = mOrientationHandler.getPrimaryScroll(this);
int focusedTaskScrollDiff = primaryScroll - focusedTaskScroll;
primaryTranslation += mIsRtl ? focusedTaskScrollDiff : -focusedTaskScrollDiff;
if (isSplitPlaceholderFirstInGrid) {
// Moves less if split placeholder is at the start.
primaryTranslation += mIsRtl ? -mSplitPlaceholderSize : mSplitPlaceholderSize;
}
}
anim.setFloat(taskView, taskView.getPrimaryDismissTranslationProperty(), mIsRtl ? primaryTranslation : -primaryTranslation, clampToProgress(LINEAR, animationStartProgress, dismissTranslationInterpolationEnd));
}
}
}
if (needsCurveUpdates) {
anim.addOnFrameCallback(this::updateCurveProperties);
}
// Add a tiny bit of translation Z, so that it draws on top of other views
if (animateTaskView) {
dismissedTaskView.setTranslationZ(0.1f);
}
mPendingAnimation = anim;
final TaskView finalNextFocusedTaskView = nextFocusedTaskView;
final boolean finalCloseGapBetweenClearAll = closeGapBetweenClearAll;
final boolean finalSnapToLastTask = snapToLastTask;
final boolean finalIsFocusedTaskDismissed = isFocusedTaskDismissed;
mPendingAnimation.addEndListener(new Consumer<Boolean>() {
@Override
public void accept(Boolean success) {
if (ENABLE_QUICKSTEP_LIVE_TILE.get() && mEnableDrawingLiveTile && dismissedTaskView.isRunningTask() && success) {
finishRecentsAnimation(true, /* toRecents */
false, /* shouldPip */
() -> onEnd(success));
} else {
onEnd(success);
}
}
@SuppressWarnings("WrongCall")
private void onEnd(boolean success) {
// Reset task translations as they may have updated via animations in
// createTaskDismissAnimation
resetTaskVisuals();
if (success) {
if (shouldRemoveTask) {
if (dismissedTaskView.getTask() != null) {
if (ENABLE_QUICKSTEP_LIVE_TILE.get() && dismissedTaskView.isRunningTask()) {
finishRecentsAnimation(true, /* toRecents */
false, /* shouldPip */
() -> removeTaskInternal(dismissedTaskViewId));
} else {
removeTaskInternal(dismissedTaskViewId);
}
mActivity.getStatsLogManager().logger().withItemInfo(dismissedTaskView.getItemInfo()).log(LAUNCHER_TASK_DISMISS_SWIPE_UP);
}
}
int pageToSnapTo = mCurrentPage;
mCurrentPageScrollDiff = 0;
int taskViewIdToSnapTo = -1;
if (showAsGrid) {
if (finalCloseGapBetweenClearAll) {
if (finalSnapToLastTask) {
// Last task will be determined after removing dismissed task.
pageToSnapTo = -1;
} else if (taskCount > 2) {
pageToSnapTo = indexOfChild(mClearAllButton);
} else if (isClearAllHidden) {
// Snap to focused task if clear all is hidden.
pageToSnapTo = 0;
}
} else {
// Get the id of the task view we will snap to based on the current
// page's relative position as the order of indices change over time due
// to dismissals.
TaskView snappedTaskView = getTaskViewAt(mCurrentPage);
boolean calculateScrollDiff = true;
if (snappedTaskView != null && !finalSnapToLastTask) {
if (snappedTaskView.getTaskViewId() == mFocusedTaskViewId) {
if (finalNextFocusedTaskView != null) {
taskViewIdToSnapTo = finalNextFocusedTaskView.getTaskViewId();
} else if (dismissedTaskViewId != mFocusedTaskViewId) {
taskViewIdToSnapTo = mFocusedTaskViewId;
} else {
// Won't focus next task in split select, so snap to the
// first task.
pageToSnapTo = 0;
calculateScrollDiff = false;
}
} else {
int snappedTaskViewId = snappedTaskView.getTaskViewId();
boolean isSnappedTaskInTopRow = mTopRowIdSet.contains(snappedTaskViewId);
IntArray taskViewIdArray = isSnappedTaskInTopRow ? getTopRowIdArray() : getBottomRowIdArray();
int snappedIndex = taskViewIdArray.indexOf(snappedTaskViewId);
taskViewIdArray.removeValue(dismissedTaskViewId);
if (finalNextFocusedTaskView != null) {
taskViewIdArray.removeValue(finalNextFocusedTaskView.getTaskViewId());
}
if (snappedIndex < taskViewIdArray.size()) {
taskViewIdToSnapTo = taskViewIdArray.get(snappedIndex);
} else if (snappedIndex == taskViewIdArray.size()) {
// If the snapped task is the last item from the
// dismissed row,
// snap to the same column in the other grid row
IntArray inverseRowTaskViewIdArray = isSnappedTaskInTopRow ? getBottomRowIdArray() : getTopRowIdArray();
if (snappedIndex < inverseRowTaskViewIdArray.size()) {
taskViewIdToSnapTo = inverseRowTaskViewIdArray.get(snappedIndex);
}
}
}
}
if (calculateScrollDiff) {
int primaryScroll = mOrientationHandler.getPrimaryScroll(RecentsView.this);
int currentPageScroll = getScrollForPage(mCurrentPage);
mCurrentPageScrollDiff = primaryScroll - currentPageScroll;
// Compensate for coordinate shift by split placeholder.
if (isSplitPlaceholderFirstInGrid && !finalSnapToLastTask) {
mCurrentPageScrollDiff += mIsRtl ? -mSplitPlaceholderSize : mSplitPlaceholderSize;
} else if (isSplitPlaceholderLastInGrid && finalSnapToLastTask) {
mCurrentPageScrollDiff += mIsRtl ? mSplitPlaceholderSize : -mSplitPlaceholderSize;
}
}
}
} else if (dismissedIndex < pageToSnapTo || pageToSnapTo == taskCount - 1) {
pageToSnapTo--;
}
boolean isHomeTaskDismissed = dismissedTaskView == getHomeTaskView();
removeViewInLayout(dismissedTaskView);
mTopRowIdSet.remove(dismissedTaskViewId);
if (taskCount == 1) {
removeViewInLayout(mClearAllButton);
if (isHomeTaskDismissed) {
updateEmptyMessage();
} else {
startHome();
}
} else {
// Update focus task and its size.
if (finalIsFocusedTaskDismissed && finalNextFocusedTaskView != null) {
mFocusedTaskViewId = finalNextFocusedTaskView.getTaskViewId();
mTopRowIdSet.remove(mFocusedTaskViewId);
finalNextFocusedTaskView.animateIconScaleAndDimIntoView();
}
updateTaskSize(/*isTaskDismissal=*/
true);
updateChildTaskOrientations();
// Update scroll and snap to page.
updateScrollSynchronously();
if (showAsGrid) {
// Rebalance tasks in the grid
int highestVisibleTaskIndex = getHighestVisibleTaskIndex();
if (highestVisibleTaskIndex < Integer.MAX_VALUE) {
TaskView taskView = requireTaskViewAt(highestVisibleTaskIndex);
boolean shouldRebalance;
int screenStart = mOrientationHandler.getPrimaryScroll(RecentsView.this);
int taskStart = mOrientationHandler.getChildStart(taskView) + (int) taskView.getOffsetAdjustment(/*fullscreenEnabled=*/
false, /*gridEnabled=*/
true);
// visible screen.
if (mIsRtl) {
shouldRebalance = taskStart <= screenStart + mPageSpacing;
} else {
int screenEnd = screenStart + mOrientationHandler.getMeasuredSize(RecentsView.this);
int taskSize = (int) (mOrientationHandler.getMeasuredSize(taskView) * taskView.getSizeAdjustment(/*fullscreenEnabled=*/
false));
int taskEnd = taskStart + taskSize;
shouldRebalance = taskEnd >= screenEnd - mPageSpacing;
}
if (shouldRebalance) {
updateGridProperties(/*isTaskDismissal=*/
true, highestVisibleTaskIndex);
updateScrollSynchronously();
}
}
IntArray topRowIdArray = getTopRowIdArray();
IntArray bottomRowIdArray = getBottomRowIdArray();
if (finalSnapToLastTask) {
// If snapping to last task, find the last task after dismissal.
pageToSnapTo = indexOfChild(getLastGridTaskView(topRowIdArray, bottomRowIdArray));
} else if (taskViewIdToSnapTo != -1) {
// If snapping to another page due to indices rearranging, find
// the new index after dismissal & rearrange using the task view id.
pageToSnapTo = indexOfChild(getTaskViewFromTaskViewId(taskViewIdToSnapTo));
if (!currentPageSnapsToEndOfGrid) {
// If it wasn't snapped to one of the last pages, but is now
// snapped to last pages, we'll need to compensate for the
// offset from the page's scroll to its visual position.
mCurrentPageScrollDiff += getOffsetFromScrollPosition(pageToSnapTo, topRowIdArray, bottomRowIdArray);
}
}
}
pageBeginTransition();
setCurrentPage(pageToSnapTo);
// Update various scroll-dependent UI.
dispatchScrollChanged();
updateActionsViewFocusedScroll();
if (isClearAllHidden()) {
mActionsView.updateDisabledFlags(OverviewActionsView.DISABLED_SCROLLING, false);
}
}
}
updateCurrentTaskActionsVisibility();
onDismissAnimationEnds();
mPendingAnimation = null;
}
});
return anim;
}
Aggregations