From 7faaffa56a61df629b341293e99e41d0c0a4d7ff Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Fri, 21 Jan 2022 23:51:08 +0000 Subject: [PATCH] Prevent lingering divider animators in AbsSwipeUpHandler - Refactor the util method to create the animator and track the existing animation in AbsSwipeUpHandler to be able to cancel it if another call to change the visbility comes in. Note that this doesn't address the case where the launch animation overlaps with swipe up (though that hopefully shouldn't happen in normal usage) Bug: 213403679 Test: Tap in the gesture space while split Change-Id: I078a7d0f22c2ef2ba847796ec79e740c789ce1ae Merged-In: I078a7d0f22c2ef2ba847796ec79e740c789ce1ae --- .../android/quickstep/AbsSwipeUpHandler.java | 31 ++++++---- .../com/android/quickstep/TaskViewUtils.java | 59 ++++++++----------- .../android/quickstep/views/RecentsView.java | 9 ++- 3 files changed, 51 insertions(+), 48 deletions(-) diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java index 9f1e47f15a..2f52c9d6c3 100644 --- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java @@ -249,6 +249,8 @@ public abstract class AbsSwipeUpHandler, private RunningWindowAnim[] mRunningWindowAnim; // Possible second animation running at the same time as mRunningWindowAnim private Animator mParallelRunningAnim; + // Current running divider animation + private ValueAnimator mDividerAnimator; private boolean mIsMotionPaused; private boolean mHasMotionEverBeenPaused; @@ -831,8 +833,8 @@ public abstract class AbsSwipeUpHandler, // Notify when the animation starts flushOnRecentsAnimationAndLauncherBound(); - TaskViewUtils.setSplitAuxiliarySurfacesShown(mRecentsAnimationTargets.nonApps, - false /*shown*/, true /*animate*/); + // Start hiding the divider + setDividerShown(false, false /* immediate */); // Only add the callback to enable the input consumer after we actually have the controller mStateCallback.runOnceAtState(STATE_APP_CONTROLLER_RECEIVED | STATE_GESTURE_STARTED, @@ -849,8 +851,7 @@ public abstract class AbsSwipeUpHandler, mStateCallback.setStateOnUiThread(STATE_GESTURE_CANCELLED | STATE_HANDLER_INVALIDATED); if (mRecentsAnimationTargets != null) { - TaskViewUtils.setSplitAuxiliarySurfacesShown(mRecentsAnimationTargets.nonApps, - true /*shown*/, true /*animate*/); + setDividerShown(true, false /* immediate */); } // Defer clearing the controller and the targets until after we've updated the state @@ -1000,8 +1001,7 @@ public abstract class AbsSwipeUpHandler, mStateCallback.setState(STATE_RESUME_LAST_TASK); } if (mRecentsAnimationTargets != null) { - TaskViewUtils.setSplitAuxiliarySurfacesShown(mRecentsAnimationTargets.nonApps, - true /*shown*/, false /*animate*/); + setDividerShown(true, true /* immediate */); } break; } @@ -1653,8 +1653,7 @@ public abstract class AbsSwipeUpHandler, mActivityInterface.onTransitionCancelled(wasVisible, mGestureState.getEndTarget()); if (mRecentsAnimationTargets != null) { - TaskViewUtils.setSplitAuxiliarySurfacesShown(mRecentsAnimationTargets.nonApps, - true /*shown*/, false /*animate*/); + setDividerShown(true, true /* immediate */); } // Leave the pending invisible flag, as it may be used by wallpaper open animation. @@ -1920,8 +1919,7 @@ public abstract class AbsSwipeUpHandler, @Override public void onRecentsAnimationFinished(RecentsAnimationController controller) { if (!controller.getFinishTargetIsLauncher()) { - TaskViewUtils.setSplitAuxiliarySurfacesShown(mRecentsAnimationTargets.nonApps, - true /*shown*/, true /*animate*/); + setDividerShown(true, false /* immediate */); } mRecentsAnimationController = null; mRecentsAnimationTargets = null; @@ -2026,6 +2024,19 @@ public abstract class AbsSwipeUpHandler, return scaleProgress; } + private void setDividerShown(boolean shown, boolean immediate) { + if (mDividerAnimator != null) { + mDividerAnimator.cancel(); + } + mDividerAnimator = TaskViewUtils.createSplitAuxiliarySurfacesAnimator( + mRecentsAnimationTargets.nonApps, shown, (dividerAnimator) -> { + dividerAnimator.start(); + if (immediate) { + dividerAnimator.end(); + } + }); + } + /** * Used for winscope tracing, see launcher_trace.proto * @see com.android.systemui.shared.tracing.ProtoTraceable#writeToProto diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java index 5d9a537165..30e225a932 100644 --- a/quickstep/src/com/android/quickstep/TaskViewUtils.java +++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java @@ -85,6 +85,7 @@ import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat. import java.util.ArrayList; import java.util.List; +import java.util.function.Consumer; /** * Utility class for helpful methods related to {@link TaskView} objects and their tasks. @@ -538,8 +539,16 @@ public final class TaskViewUtils { nonAppTargets, depthController, pa); if (launcherClosing) { // TODO(b/182592057): differentiate between "restore split" vs "launch fullscreen app" - TaskViewUtils.setSplitAuxiliarySurfacesShown(nonAppTargets, - true /*shown*/, true /*animate*/, pa); + TaskViewUtils.createSplitAuxiliarySurfacesAnimator(nonAppTargets, true /*shown*/, + (dividerAnimator) -> { + // If split apps are launching, we want to delay showing the divider bar + // until the very end once the apps are mostly in place. This is because we + // aren't moving the divider leash in the relative position with the + // launching apps. + dividerAnimator.setStartDelay(pa.getDuration() + - SPLIT_DIVIDER_ANIM_DURATION); + pa.add(dividerAnimator); + }); } Animator childStateAnimation = null; @@ -594,16 +603,17 @@ public final class TaskViewUtils { anim.addListener(windowAnimEndListener); } - public static void setSplitAuxiliarySurfacesShown(RemoteAnimationTargetCompat[] nonApps, - boolean shown, boolean animate) { - setSplitAuxiliarySurfacesShown(nonApps, shown, animate,null); - } - - private static void setSplitAuxiliarySurfacesShown( - @NonNull RemoteAnimationTargetCompat[] nonApps, boolean shown, boolean animate, - @Nullable PendingAnimation splitLaunchAnimation) { + /** + * Creates an animation to show/hide the auxiliary surfaces (aka. divider bar), only calling + * {@param animatorHandler} if there are valid surfaces to animate. + * + * @return the animator animating the surfaces + */ + public static ValueAnimator createSplitAuxiliarySurfacesAnimator( + RemoteAnimationTargetCompat[] nonApps, boolean shown, + Consumer animatorHandler) { if (nonApps == null || nonApps.length == 0) { - return; + return null; } SurfaceControl.Transaction t = new SurfaceControl.Transaction(); @@ -618,20 +628,7 @@ public final class TaskViewUtils { } } if (!hasSurfaceToAnimate) { - return; - } - - if (!animate) { - for (SurfaceControl leash : auxiliarySurfaces) { - t.setAlpha(leash, shown ? 1 : 0); - if (shown) { - t.show(leash); - } else { - t.hide(leash); - } - } - t.apply(); - return; + return null; } ValueAnimator dockFadeAnimator = ValueAnimator.ofFloat(0f, 1f); @@ -668,15 +665,7 @@ public final class TaskViewUtils { } }); dockFadeAnimator.setDuration(SPLIT_DIVIDER_ANIM_DURATION); - if (splitLaunchAnimation != null) { - // If split apps are launching, we want to delay showing the divider bar until the very - // end once the apps are mostly in place. This is because we aren't moving the divider - // leash in the relative position with the launching apps. - dockFadeAnimator.setStartDelay( - splitLaunchAnimation.getDuration() - SPLIT_DIVIDER_ANIM_DURATION); - splitLaunchAnimation.add(dockFadeAnimator); - } else { - dockFadeAnimator.start(); - } + animatorHandler.accept(dockFadeAnimator); + return dockFadeAnimator; } } diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index 02261af499..57c3b1d746 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -4235,9 +4235,12 @@ public abstract class RecentsView { + dividerAnimator.start(); + dividerAnimator.end(); + }); } if (ENABLE_QUICKSTEP_LIVE_TILE.get() && tv.isRunningTask()) { finishRecentsAnimation(false /* toRecents */, null);