From 95a7ca485efb46e0132a32cb40281a20c9e645d5 Mon Sep 17 00:00:00 2001 From: Vinit Nayak Date: Tue, 2 Apr 2024 11:45:02 -0700 Subject: [PATCH] Launch AppPair live tile when not visible * End the recents animation and then relaunch as if from scratch * We explicitly ignore the anim for end of recents animation since that will cause the taskbar to quickly show and stash again, and we know in this case that we'll quickly be launching right back into an app Test: Tested w/ live tile + non live, fullscreen + app pairs Bug: 316485863 Change-Id: I6ae8cccc01401935bf96fba8a154216e6b1ad701 (cherry picked from commit 637274ebc9fce5f79637a76d35e9670286547f6a) Merged-In: I6ae8cccc01401935bf96fba8a154216e6b1ad701 --- .../taskbar/LauncherTaskbarUIController.java | 5 ++++ .../taskbar/TaskbarActivityContext.java | 20 +++++++++---- .../TaskbarLauncherStateController.java | 30 +++++++++++++++---- .../taskbar/TaskbarUIController.java | 8 +++++ .../android/quickstep/views/RecentsView.java | 25 +++++++++++----- 5 files changed, 70 insertions(+), 18 deletions(-) diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java index 1e861d2fb5..58c616fbb3 100644 --- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java @@ -312,6 +312,11 @@ public class LauncherTaskbarUIController extends TaskbarUIController { mControllers.taskbarEduTooltipController.maybeShowSwipeEdu(); } + /** Will make the next onRecentsAnimationFinished() animation a no-op. */ + public void setSkipNextRecentsAnimEnd() { + mTaskbarLauncherStateController.setSkipNextRecentsAnimEnd(); + } + /** * Returns {@code true} if a Taskbar education should be shown on application launch. */ diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java index 03133fd022..4d016417db 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java @@ -1231,13 +1231,13 @@ public class TaskbarActivityContext extends BaseTaskbarContext { return; } - boolean findExactPairMatch = itemInfos.size() == 2; + boolean isLaunchingAppPair = itemInfos.size() == 2; // Convert the list of ItemInfo instances to a list of ComponentKeys List componentKeys = itemInfos.stream().map(ItemInfo::getComponentKey).toList(); recents.getSplitSelectController().findLastActiveTasksAndRunCallback( componentKeys, - findExactPairMatch, + isLaunchingAppPair, foundTasks -> { @Nullable Task foundTask = foundTasks[0]; if (foundTask != null) { @@ -1251,10 +1251,18 @@ public class TaskbarActivityContext extends BaseTaskbarContext { } } - if (findExactPairMatch) { - // We did not find the app pair we were looking for, so launch one. - recents.getSplitSelectController().getAppPairsController().launchAppPair( - (AppPairIcon) launchingIconView, -1 /*cuj*/); + if (isLaunchingAppPair) { + // Finish recents animation if it's running before launching to ensure + // we get both leashes for the animation + mControllers.uiController.setSkipNextRecentsAnimEnd(); + recents.switchToScreenshot(() -> + recents.finishRecentsAnimation(true /*toRecents*/, + false /*shouldPip*/, + () -> recents + .getSplitSelectController() + .getAppPairsController() + .launchAppPair((AppPairIcon) launchingIconView, + -1 /*cuj*/))); } else { startItemInfoActivity(itemInfos.get(0)); } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java index 259af1d53a..fb9a9761e7 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java @@ -148,6 +148,7 @@ public class TaskbarLauncherStateController { private Integer mPrevState; private int mState; private LauncherState mLauncherState = LauncherState.NORMAL; + private boolean mSkipNextRecentsAnimEnd; // Time when FLAG_TASKBAR_HIDDEN was last cleared, SystemClock.elapsedRealtime (milliseconds). private long mLastUnlockTimeMs = 0; @@ -292,12 +293,12 @@ public class TaskbarLauncherStateController { if (mTaskBarRecentsAnimationListener != null) { mTaskBarRecentsAnimationListener.endGestureStateOverride( - !mLauncher.isInState(LauncherState.OVERVIEW)); + !mLauncher.isInState(LauncherState.OVERVIEW), false /*canceled*/); } mTaskBarRecentsAnimationListener = new TaskBarRecentsAnimationListener(callbacks); callbacks.addListener(mTaskBarRecentsAnimationListener); ((RecentsView) mLauncher.getOverviewPanel()).setTaskLaunchListener(() -> - mTaskBarRecentsAnimationListener.endGestureStateOverride(true)); + mTaskBarRecentsAnimationListener.endGestureStateOverride(true, false /*canceled*/)); ((RecentsView) mLauncher.getOverviewPanel()).setTaskLaunchCancelledRunnable(() -> { updateStateForUserFinishedToApp(false /* finishedToApp */); @@ -318,6 +319,11 @@ public class TaskbarLauncherStateController { mShouldDelayLauncherStateAnim = shouldDelayLauncherStateAnim; } + /** Will make the next onRecentsAnimationFinished() a no-op. */ + public void setSkipNextRecentsAnimEnd() { + mSkipNextRecentsAnimEnd = true; + } + /** SysUI flags updated, see QuickStepContract.SYSUI_STATE_* values. */ public void updateStateForSysuiFlags(int systemUiStateFlags) { updateStateForSysuiFlags(systemUiStateFlags, /* applyState */ true); @@ -770,19 +776,33 @@ public class TaskbarLauncherStateController { @Override public void onRecentsAnimationCanceled(HashMap thumbnailDatas) { boolean isInOverview = mLauncher.isInState(LauncherState.OVERVIEW); - endGestureStateOverride(!isInOverview); + endGestureStateOverride(!isInOverview, true /*canceled*/); } @Override public void onRecentsAnimationFinished(RecentsAnimationController controller) { - endGestureStateOverride(!controller.getFinishTargetIsLauncher()); + endGestureStateOverride(!controller.getFinishTargetIsLauncher(), false /*canceled*/); } - private void endGestureStateOverride(boolean finishedToApp) { + /** + * Handles whatever cleanup is needed after the recents animation is completed. + * NOTE: If {@link #mSkipNextRecentsAnimEnd} is set and we're coming from a non-cancelled + * path, this will not call {@link #updateStateForUserFinishedToApp(boolean)} + * + * @param finishedToApp {@code true} if the recents animation finished to showing an app and + * not workspace or overview + * @param canceled {@code true} if the recents animation was canceled instead of finishing + * to completion + */ + private void endGestureStateOverride(boolean finishedToApp, boolean canceled) { mCallbacks.removeListener(this); mTaskBarRecentsAnimationListener = null; ((RecentsView) mLauncher.getOverviewPanel()).setTaskLaunchListener(null); + if (mSkipNextRecentsAnimEnd && !canceled) { + mSkipNextRecentsAnimEnd = false; + return; + } updateStateForUserFinishedToApp(finishedToApp); } } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java index efe1e39f97..c74fd83c48 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java @@ -394,4 +394,12 @@ public class TaskbarUIController { mControllers.taskbarStashController.updateStateForFlag(FLAG_IN_APP, !isVisible); mControllers.taskbarStashController.applyState(); } + + /** + * Request for UI controller to ignore animations for the next callback for the end of recents + * animation + */ + public void setSkipNextRecentsAnimEnd() { + // Overridden + } } diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index c42bad3ddb..3caaea6b8b 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -1254,16 +1254,23 @@ public abstract class RecentsView { float percent = valueAnimator.getAnimatedFraction(); SurfaceTransaction transaction = new SurfaceTransaction(); - Matrix matrix = new Matrix(); - matrix.postScale(percent, percent); - matrix.postTranslate(mActivity.getDeviceProfile().widthPx * (1 - percent) / 2, - mActivity.getDeviceProfile().heightPx * (1 - percent) / 2); - transaction.forSurface(apps[apps.length - 1].leash) - .setAlpha(percent) - .setMatrix(matrix); + for (int i = apps.length - 1; i >= 0; --i) { + RemoteAnimationTarget app = apps[i]; + + float dx = mActivity.getDeviceProfile().widthPx * (1 - percent) / 2 + + app.screenSpaceBounds.left * percent; + float dy = mActivity.getDeviceProfile().heightPx * (1 - percent) / 2 + + app.screenSpaceBounds.top * percent; + matrix.setScale(percent, percent); + matrix.postTranslate(dx, dy); + transaction.forSurface(app.leash) + .setAlpha(percent) + .setMatrix(matrix); + } surfaceApplier.scheduleApply(transaction); }); appAnimator.addListener(new AnimatorListenerAdapter() { @@ -5418,6 +5425,10 @@ public abstract class RecentsView