use of com.android.launcher3.util.PendingAnimation in project android_packages_apps_Launcher3 by ArrowOS.
the class RecentsView method confirmSplitSelect.
public void confirmSplitSelect(TaskView taskView) {
mSplitToast.cancel();
if (!taskView.getTask().isDockable) {
// Task not split screen supported
mSplitUnsupportedToast.show();
return;
}
RectF secondTaskStartingBounds = new RectF();
Rect secondTaskEndingBounds = new Rect();
// TODO(194414938) starting bounds seem slightly off, investigate
Rect firstTaskStartingBounds = new Rect();
Rect firstTaskEndingBounds = mTempRect;
int duration = mActivity.getStateManager().getState().getTransitionDuration(getContext());
PendingAnimation pendingAnimation = new PendingAnimation(duration);
int halfDividerSize = getResources().getDimensionPixelSize(R.dimen.multi_window_task_divider_size) / 2;
mOrientationHandler.getFinalSplitPlaceholderBounds(halfDividerSize, mActivity.getDeviceProfile(), mSplitSelectStateController.getActiveSplitStagePosition(), firstTaskEndingBounds, secondTaskEndingBounds);
if (mFirstFloatingTaskView == null)
return;
mFirstFloatingTaskView.getBoundsOnScreen(firstTaskStartingBounds);
mFirstFloatingTaskView.addAnimation(pendingAnimation, new RectF(firstTaskStartingBounds), firstTaskEndingBounds, mFirstFloatingTaskView, false);
mSecondFloatingTaskView = FloatingTaskView.getFloatingTaskView(mActivity, taskView, secondTaskStartingBounds);
mSecondFloatingTaskView.setAlpha(1);
mSecondFloatingTaskView.addAnimation(pendingAnimation, secondTaskStartingBounds, secondTaskEndingBounds, taskView.getThumbnail(), true);
pendingAnimation.addEndListener(aBoolean -> mSplitSelectStateController.setSecondTaskId(taskView.getTask(), aBoolean1 -> RecentsView.this.resetFromSplitSelectionState()));
mSecondSplitHiddenTaskView = taskView;
taskView.setVisibility(INVISIBLE);
pendingAnimation.buildAnim().start();
}
use of com.android.launcher3.util.PendingAnimation 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.launcher3.util.PendingAnimation in project android_packages_apps_Launcher3 by ArrowOS.
the class TaskViewUtils method composeRecentsLaunchAnimator.
public static void composeRecentsLaunchAnimator(@NonNull AnimatorSet anim, @NonNull View v, @NonNull RemoteAnimationTargetCompat[] appTargets, @NonNull RemoteAnimationTargetCompat[] wallpaperTargets, @NonNull RemoteAnimationTargetCompat[] nonAppTargets, boolean launcherClosing, @NonNull StateManager stateManager, @NonNull RecentsView recentsView, @Nullable DepthController depthController) {
boolean skipLauncherChanges = !launcherClosing;
TaskView taskView = findTaskViewToLaunch(recentsView, v, appTargets);
PendingAnimation pa = new PendingAnimation(RECENTS_LAUNCH_DURATION);
createRecentsWindowAnimator(taskView, skipLauncherChanges, appTargets, wallpaperTargets, nonAppTargets, depthController, pa);
if (launcherClosing) {
// TODO(b/182592057): differentiate between "restore split" vs "launch fullscreen app"
TaskViewUtils.setSplitAuxiliarySurfacesShown(nonAppTargets, true, /*shown*/
true, /*animate*/
pa);
}
Animator childStateAnimation = null;
// Found a visible recents task that matches the opening app, lets launch the app from there
Animator launcherAnim;
final AnimatorListenerAdapter windowAnimEndListener;
if (launcherClosing) {
Context context = v.getContext();
DeviceProfile dp = BaseActivity.fromContext(context).getDeviceProfile();
launcherAnim = dp.overviewShowAsGrid ? ObjectAnimator.ofFloat(recentsView, RecentsView.CONTENT_ALPHA, 0) : recentsView.createAdjacentPageAnimForTaskLaunch(taskView);
launcherAnim.setInterpolator(Interpolators.TOUCH_RESPONSE_INTERPOLATOR);
launcherAnim.setDuration(RECENTS_LAUNCH_DURATION);
// Make sure recents gets fixed up by resetting task alphas and scales, etc.
windowAnimEndListener = new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
recentsView.finishRecentsAnimation(false, /* toRecents */
() -> {
recentsView.post(() -> {
stateManager.moveToRestState();
stateManager.reapplyState();
});
});
}
};
} else {
AnimatorPlaybackController controller = stateManager.createAnimationToNewWorkspace(NORMAL, RECENTS_LAUNCH_DURATION);
controller.dispatchOnStart();
childStateAnimation = controller.getTarget();
launcherAnim = controller.getAnimationPlayer().setDuration(RECENTS_LAUNCH_DURATION);
windowAnimEndListener = new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
recentsView.finishRecentsAnimation(false, /* toRecents */
() -> stateManager.goToState(NORMAL, false));
}
};
}
pa.add(launcherAnim);
if (ENABLE_QUICKSTEP_LIVE_TILE.get() && recentsView.getRunningTaskIndex() != -1) {
pa.addOnFrameCallback(recentsView::redrawLiveTile);
}
anim.play(pa.buildAnim());
// Set the current animation first, before adding windowAnimEndListener. Setting current
// animation adds some listeners which need to be called before windowAnimEndListener
// (the ordering of listeners matter in this case).
stateManager.setCurrentAnimation(anim, childStateAnimation);
anim.addListener(windowAnimEndListener);
}
use of com.android.launcher3.util.PendingAnimation in project android_packages_apps_Launcher3 by ArrowOS.
the class TaskViewUtils method createRecentsWindowAnimator.
public static void createRecentsWindowAnimator(@NonNull TaskView v, boolean skipViewChanges, @NonNull RemoteAnimationTargetCompat[] appTargets, @NonNull RemoteAnimationTargetCompat[] wallpaperTargets, @NonNull RemoteAnimationTargetCompat[] nonAppTargets, @Nullable DepthController depthController, PendingAnimation out) {
RecentsView recentsView = v.getRecentsView();
boolean isQuickSwitch = v.isEndQuickswitchCuj();
v.setEndQuickswitchCuj(false);
boolean inLiveTileMode = ENABLE_QUICKSTEP_LIVE_TILE.get() && v.getRecentsView().getRunningTaskIndex() != -1;
final RemoteAnimationTargets targets = new RemoteAnimationTargets(appTargets, wallpaperTargets, nonAppTargets, inLiveTileMode ? MODE_CLOSING : MODE_OPENING);
final RemoteAnimationTargetCompat navBarTarget = targets.getNavBarRemoteAnimationTarget();
SurfaceTransactionApplier applier = new SurfaceTransactionApplier(v);
targets.addReleaseCheck(applier);
RemoteTargetHandle[] remoteTargetHandles;
RemoteTargetHandle[] recentsViewHandles = recentsView.getRemoteTargetHandles();
if (v.isRunningTask() && recentsViewHandles != null) {
// Re-use existing handles
remoteTargetHandles = recentsViewHandles;
} else {
RemoteTargetGluer gluer = new RemoteTargetGluer(v.getContext(), recentsView.getSizeStrategy(), targets);
if (v.containsMultipleTasks()) {
remoteTargetHandles = gluer.assignTargetsForSplitScreen(targets, v.getTaskIds());
} else {
remoteTargetHandles = gluer.assignTargets(targets);
}
}
for (RemoteTargetHandle remoteTargetGluer : remoteTargetHandles) {
remoteTargetGluer.getTransformParams().setSyncTransactionApplier(applier);
}
int taskIndex = recentsView.indexOfChild(v);
Context context = v.getContext();
DeviceProfile dp = BaseActivity.fromContext(context).getDeviceProfile();
boolean showAsGrid = dp.overviewShowAsGrid;
boolean parallaxCenterAndAdjacentTask = taskIndex != recentsView.getCurrentPage() && !showAsGrid;
int taskRectTranslationPrimary = recentsView.getScrollOffset(taskIndex);
int taskRectTranslationSecondary = showAsGrid ? (int) v.getGridTranslationY() : 0;
RemoteTargetHandle[] topMostSimulators = null;
if (!v.isRunningTask()) {
// TVSs already initialized from the running task, no need to re-init
for (RemoteTargetHandle targetHandle : remoteTargetHandles) {
TaskViewSimulator tvsLocal = targetHandle.getTaskViewSimulator();
tvsLocal.setDp(dp);
// RecentsView never updates the display rotation until swipe-up so the value may
// be stale. Use the display value instead.
int displayRotation = DisplayController.INSTANCE.get(context).getInfo().rotation;
tvsLocal.getOrientationState().update(displayRotation, displayRotation);
tvsLocal.fullScreenProgress.value = 0;
tvsLocal.recentsViewScale.value = 1;
tvsLocal.setIsGridTask(v.isGridTask());
tvsLocal.getOrientationState().getOrientationHandler().set(tvsLocal, TaskViewSimulator::setTaskRectTranslation, taskRectTranslationPrimary, taskRectTranslationSecondary);
// Fade in the task during the initial 20% of the animation
out.addFloat(targetHandle.getTransformParams(), TransformParams.TARGET_ALPHA, 0, 1, clampToProgress(LINEAR, 0, 0.2f));
}
}
for (RemoteTargetHandle targetHandle : remoteTargetHandles) {
TaskViewSimulator tvsLocal = targetHandle.getTaskViewSimulator();
out.setFloat(tvsLocal.fullScreenProgress, AnimatedFloat.VALUE, 1, TOUCH_RESPONSE_INTERPOLATOR);
out.setFloat(tvsLocal.recentsViewScale, AnimatedFloat.VALUE, tvsLocal.getFullScreenScale(), TOUCH_RESPONSE_INTERPOLATOR);
out.setFloat(tvsLocal.recentsViewScroll, AnimatedFloat.VALUE, 0, TOUCH_RESPONSE_INTERPOLATOR);
out.addOnFrameCallback(() -> {
for (RemoteTargetHandle handle : remoteTargetHandles) {
handle.getTaskViewSimulator().apply(handle.getTransformParams());
}
});
if (navBarTarget != null) {
final Rect cropRect = new Rect();
out.addOnFrameListener(new MultiValueUpdateListener() {
FloatProp mNavFadeOut = new FloatProp(1f, 0f, 0, ANIMATION_NAV_FADE_OUT_DURATION, NAV_FADE_OUT_INTERPOLATOR);
FloatProp mNavFadeIn = new FloatProp(0f, 1f, ANIMATION_DELAY_NAV_FADE_IN, ANIMATION_NAV_FADE_IN_DURATION, NAV_FADE_IN_INTERPOLATOR);
@Override
public void onUpdate(float percent, boolean initOnly) {
final SurfaceParams.Builder navBuilder = new SurfaceParams.Builder(navBarTarget.leash);
// TODO Do we need to operate over multiple TVSs for the navbar leash?
for (RemoteTargetHandle handle : remoteTargetHandles) {
if (mNavFadeIn.value > mNavFadeIn.getStartValue()) {
TaskViewSimulator taskViewSimulator = handle.getTaskViewSimulator();
taskViewSimulator.getCurrentCropRect().round(cropRect);
navBuilder.withMatrix(taskViewSimulator.getCurrentMatrix()).withWindowCrop(cropRect).withAlpha(mNavFadeIn.value);
} else {
navBuilder.withAlpha(mNavFadeOut.value);
}
handle.getTransformParams().applySurfaceParams(navBuilder.build());
}
}
});
} else if (inLiveTileMode) {
// There is no transition animation for app launch from recent in live tile mode so
// we have to trigger the navigation bar animation from system here.
final RecentsAnimationController controller = recentsView.getRecentsAnimationController();
if (controller != null) {
controller.animateNavigationBarToApp(RECENTS_LAUNCH_DURATION);
}
}
topMostSimulators = remoteTargetHandles;
}
if (!skipViewChanges && parallaxCenterAndAdjacentTask && topMostSimulators.length > 0) {
out.addFloat(v, VIEW_ALPHA, 1, 0, clampToProgress(LINEAR, 0.2f, 0.4f));
RemoteTargetHandle[] simulatorCopies = topMostSimulators;
for (RemoteTargetHandle handle : simulatorCopies) {
handle.getTaskViewSimulator().apply(handle.getTransformParams());
}
// Mt represents the overall transformation on the thumbnailView relative to the
// Launcher's rootView
// K(t) represents transformation on the running window by the taskViewSimulator at
// any time t.
// at t = 0, we know that the simulator matches the thumbnailView. So if we apply K(0)`
// on the Launcher's rootView, the thumbnailView would match the full running task
// window. If we apply "K(0)` K(t)" thumbnailView will match the final transformed
// window at any time t. This gives the overall matrix on thumbnailView to be:
// Mt K(0)` K(t)
// During animation we apply transformation on the thumbnailView (and not the rootView)
// to follow the TaskViewSimulator. So the final matrix applied on the thumbnailView is:
// Mt K(0)` K(t) Mt`
TaskThumbnailView[] thumbnails = v.getThumbnails();
Matrix[] mt = new Matrix[simulatorCopies.length];
Matrix[] mti = new Matrix[simulatorCopies.length];
for (int i = 0; i < thumbnails.length; i++) {
TaskThumbnailView ttv = thumbnails[i];
RectF localBounds = new RectF(0, 0, ttv.getWidth(), ttv.getHeight());
float[] tvBoundsMapped = new float[] { 0, 0, ttv.getWidth(), ttv.getHeight() };
getDescendantCoordRelativeToAncestor(ttv, ttv.getRootView(), tvBoundsMapped, false);
RectF localBoundsInRoot = new RectF(tvBoundsMapped[0], tvBoundsMapped[1], tvBoundsMapped[2], tvBoundsMapped[3]);
Matrix localMt = new Matrix();
localMt.setRectToRect(localBounds, localBoundsInRoot, ScaleToFit.FILL);
mt[i] = localMt;
Matrix localMti = new Matrix();
localMt.invert(localMti);
mti[i] = localMti;
}
Matrix[] k0i = new Matrix[simulatorCopies.length];
for (int i = 0; i < simulatorCopies.length; i++) {
k0i[i] = new Matrix();
simulatorCopies[i].getTaskViewSimulator().getCurrentMatrix().invert(k0i[i]);
}
Matrix animationMatrix = new Matrix();
out.addOnFrameCallback(() -> {
for (int i = 0; i < simulatorCopies.length; i++) {
animationMatrix.set(mt[i]);
animationMatrix.postConcat(k0i[i]);
animationMatrix.postConcat(simulatorCopies[i].getTaskViewSimulator().getCurrentMatrix());
animationMatrix.postConcat(mti[i]);
thumbnails[i].setAnimationMatrix(animationMatrix);
}
});
out.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
for (TaskThumbnailView ttv : thumbnails) {
ttv.setAnimationMatrix(null);
}
}
});
}
out.addListener(new AnimationSuccessListener() {
@Override
public void onAnimationSuccess(Animator animator) {
if (isQuickSwitch) {
InteractionJankMonitorWrapper.end(InteractionJankMonitorWrapper.CUJ_QUICK_SWITCH);
}
}
@Override
public void onAnimationEnd(Animator animation) {
targets.release();
super.onAnimationEnd(animation);
}
});
if (depthController != null) {
out.setFloat(depthController, DEPTH, BACKGROUND_APP.getDepth(context), TOUCH_RESPONSE_INTERPOLATOR);
}
}
use of com.android.launcher3.util.PendingAnimation in project android_packages_apps_Launcher3 by ArrowOS.
the class RecentsView method createAllTasksDismissAnimation.
public PendingAnimation createAllTasksDismissAnimation(long duration) {
if (FeatureFlags.IS_STUDIO_BUILD && mPendingAnimation != null) {
throw new IllegalStateException("Another pending animation is still running");
}
PendingAnimation anim = new PendingAnimation(duration);
int count = getTaskViewCount();
for (int i = 0; i < count; i++) {
addDismissedTaskAnimations(requireTaskViewAt(i), duration, anim);
}
mPendingAnimation = anim;
mPendingAnimation.addEndListener(isSuccess -> {
if (isSuccess) {
// Remove all the task views now
finishRecentsAnimation(true, /* toRecents */
false, /* shouldPip */
() -> {
UI_HELPER_EXECUTOR.getHandler().postDelayed(ActivityManagerWrapper.getInstance()::removeAllRecentTasks, REMOVE_TASK_WAIT_FOR_APP_STOP_MS);
removeTasksViewsAndClearAllButton();
startHome();
});
}
mPendingAnimation = null;
});
return anim;
}
Aggregations