From 0d40e19c4a027b4a988d8b22a46e2079db52e5e0 Mon Sep 17 00:00:00 2001 From: Vinit Nayak Date: Wed, 17 Nov 2021 19:51:22 -0800 Subject: [PATCH] Animate split divider * TODO currently it doesn't animate when dragging a split task back down because we need to sync that with the other task scaling animation playback controllers. * It also doesn't animate in when opening a split pair from overview because I think shell is setting it to be visible before the divider leash even makes it to launcher Bug: 202914644 Change-Id: I6c60cffdb63aa262d0b547f85acc604c0c8a3637 --- .../launcher3/QuickstepTransitionManager.java | 1 + .../android/quickstep/AbsSwipeUpHandler.java | 16 ++-- .../quickstep/TaskAnimationManager.java | 16 +++- .../com/android/quickstep/TaskViewUtils.java | 93 ++++++++++++++++--- .../android/quickstep/views/RecentsView.java | 4 +- .../com/android/quickstep/views/TaskView.java | 7 +- 6 files changed, 113 insertions(+), 24 deletions(-) diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java index 51d7914ee8..47df9aa513 100644 --- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java +++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java @@ -176,6 +176,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener private static final int LAUNCHER_RESUME_START_DELAY = 100; private static final int CLOSING_TRANSITION_DURATION_MS = 250; public static final int SPLIT_LAUNCH_DURATION = 370; + public static final int SPLIT_DIVIDER_ANIM_DURATION = 100; public static final int CONTENT_ALPHA_DURATION = 217; protected static final int CONTENT_SCALE_DURATION = 350; diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java index 1a901f1271..ec610eedfa 100644 --- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java @@ -818,7 +818,8 @@ public abstract class AbsSwipeUpHandler, mRecentsAnimationStartCallbacks.clear(); } - TaskViewUtils.setSplitAuxiliarySurfacesShown(mRecentsAnimationTargets.nonApps, false); + TaskViewUtils.setSplitAuxiliarySurfacesShown(mRecentsAnimationTargets.nonApps, + false /*shown*/, true /*animate*/); // Only add the callback to enable the input consumer after we actually have the controller mStateCallback.runOnceAtState(STATE_APP_CONTROLLER_RECEIVED | STATE_GESTURE_STARTED, @@ -835,7 +836,8 @@ public abstract class AbsSwipeUpHandler, mStateCallback.setStateOnUiThread(STATE_GESTURE_CANCELLED | STATE_HANDLER_INVALIDATED); if (mRecentsAnimationTargets != null) { - TaskViewUtils.setSplitAuxiliarySurfacesShown(mRecentsAnimationTargets.nonApps, true); + TaskViewUtils.setSplitAuxiliarySurfacesShown(mRecentsAnimationTargets.nonApps, + true /*shown*/, true /*animate*/); } // Defer clearing the controller and the targets until after we've updated the state @@ -985,8 +987,8 @@ public abstract class AbsSwipeUpHandler, mStateCallback.setState(STATE_RESUME_LAST_TASK); } if (mRecentsAnimationTargets != null) { - TaskViewUtils.setSplitAuxiliarySurfacesShown( - mRecentsAnimationTargets.nonApps, true); + TaskViewUtils.setSplitAuxiliarySurfacesShown(mRecentsAnimationTargets.nonApps, + true /*shown*/, true /*animate*/); } break; } @@ -1637,7 +1639,8 @@ public abstract class AbsSwipeUpHandler, mActivityInterface.onTransitionCancelled(wasVisible, mGestureState.getEndTarget()); if (mRecentsAnimationTargets != null) { - TaskViewUtils.setSplitAuxiliarySurfacesShown(mRecentsAnimationTargets.nonApps, true); + TaskViewUtils.setSplitAuxiliarySurfacesShown(mRecentsAnimationTargets.nonApps, + true /*shown*/, true /*animate*/); } // Leave the pending invisible flag, as it may be used by wallpaper open animation. @@ -1878,7 +1881,8 @@ public abstract class AbsSwipeUpHandler, @Override public void onRecentsAnimationFinished(RecentsAnimationController controller) { if (!controller.getFinishTargetIsLauncher()) { - TaskViewUtils.setSplitAuxiliarySurfacesShown(mRecentsAnimationTargets.nonApps, true); + TaskViewUtils.setSplitAuxiliarySurfacesShown(mRecentsAnimationTargets.nonApps, + true /*shown*/, true /*animate*/); } mRecentsAnimationController = null; mRecentsAnimationTargets = null; diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java index e69330ab22..d3b17f8324 100644 --- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java +++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java @@ -20,6 +20,7 @@ import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_INITIALIZED; import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_STARTED; +import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME; import android.app.ActivityManager; import android.content.Context; @@ -27,6 +28,7 @@ import android.content.Intent; import android.os.Bundle; import android.os.SystemProperties; import android.util.Log; +import android.view.RemoteAnimationTarget; import androidx.annotation.Nullable; import androidx.annotation.UiThread; @@ -42,6 +44,7 @@ import com.android.systemui.shared.system.RemoteTransitionCompat; import com.android.systemui.shared.system.TaskStackChangeListener; import com.android.systemui.shared.system.TaskStackChangeListeners; +import java.util.Arrays; import java.util.HashMap; public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAnimationListener { @@ -150,6 +153,17 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn public void onTasksAppeared(RemoteAnimationTargetCompat[] appearedTaskTargets) { RemoteAnimationTargetCompat appearedTaskTarget = appearedTaskTargets[0]; BaseActivityInterface activityInterface = mLastGestureState.getActivityInterface(); + // Convert appTargets to type RemoteAnimationTarget for all apps except Home app + RemoteAnimationTarget[] nonHomeApps = Arrays.stream(appearedTaskTargets) + .filter(remoteAnimationTarget -> + remoteAnimationTarget.activityType != ACTIVITY_TYPE_HOME) + .map(RemoteAnimationTargetCompat::unwrap) + .toArray(RemoteAnimationTarget[]::new); + + RemoteAnimationTarget[] nonAppTargets = + SystemUiProxy.INSTANCE.getNoCreate() + .onGoingToRecentsLegacy(false, nonHomeApps); + if (ENABLE_QUICKSTEP_LIVE_TILE.get() && activityInterface.isInLiveTileMode() && activityInterface.getCreatedActivity() != null) { RecentsView recentsView = @@ -158,7 +172,7 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn recentsView.launchSideTaskInLiveTileMode(appearedTaskTarget.taskId, appearedTaskTargets, new RemoteAnimationTargetCompat[0] /* wallpaper */, - new RemoteAnimationTargetCompat[0] /* nonApps */); + RemoteAnimationTargetCompat.wrap(nonAppTargets) /* nonApps */); return; } } diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java index 97fc6d7000..14f3ec453c 100644 --- a/quickstep/src/com/android/quickstep/TaskViewUtils.java +++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java @@ -28,6 +28,7 @@ import static com.android.launcher3.QuickstepTransitionManager.ANIMATION_NAV_FAD import static com.android.launcher3.QuickstepTransitionManager.NAV_FADE_IN_INTERPOLATOR; import static com.android.launcher3.QuickstepTransitionManager.NAV_FADE_OUT_INTERPOLATOR; import static com.android.launcher3.QuickstepTransitionManager.RECENTS_LAUNCH_DURATION; +import static com.android.launcher3.QuickstepTransitionManager.SPLIT_DIVIDER_ANIM_DURATION; import static com.android.launcher3.QuickstepTransitionManager.SPLIT_LAUNCH_DURATION; import static com.android.launcher3.Utilities.getDescendantCoordRelativeToAncestor; import static com.android.launcher3.anim.Interpolators.LINEAR; @@ -536,7 +537,8 @@ public final class TaskViewUtils { nonAppTargets, depthController, pa); if (launcherClosing) { // TODO(b/182592057): differentiate between "restore split" vs "launch fullscreen app" - TaskViewUtils.setSplitAuxiliarySurfacesShown(nonAppTargets, true); + TaskViewUtils.setSplitAuxiliarySurfacesShown(nonAppTargets, + true /*shown*/, true /*animate*/, pa); } Animator childStateAnimation = null; @@ -592,19 +594,88 @@ public final class TaskViewUtils { } public static void setSplitAuxiliarySurfacesShown(RemoteAnimationTargetCompat[] nonApps, - boolean shown) { - // TODO(b/182592057): make this part of the animations instead. - if (nonApps != null && nonApps.length > 0) { - SurfaceControl.Transaction t = new SurfaceControl.Transaction(); - for (int i = 0; i < nonApps.length; ++i) { - final RemoteAnimationTargetCompat targ = nonApps[i]; - final SurfaceControl leash = targ.leash.getSurfaceControl(); - if (targ.windowType == TYPE_DOCK_DIVIDER && leash != null) { - t.setVisibility(leash, shown); + boolean shown, boolean animate) { + setSplitAuxiliarySurfacesShown(nonApps, shown, animate,null); + } + + private static void setSplitAuxiliarySurfacesShown( + @NonNull RemoteAnimationTargetCompat[] nonApps, boolean shown, boolean animate, + @Nullable PendingAnimation splitLaunchAnimation) { + if (nonApps == null || nonApps.length == 0) { + return; + } + + SurfaceControl.Transaction t = new SurfaceControl.Transaction(); + SurfaceControl[] auxiliarySurfaces = new SurfaceControl[nonApps.length]; + boolean hasSurfaceToAnimate = false; + for (int i = 0; i < nonApps.length; ++i) { + final RemoteAnimationTargetCompat targ = nonApps[i]; + final SurfaceControl leash = targ.leash.getSurfaceControl(); + if (targ.windowType == TYPE_DOCK_DIVIDER && leash != null) { + auxiliarySurfaces[i] = leash; + hasSurfaceToAnimate = true; + } + } + 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(); - t.close(); + return; + } + + ValueAnimator dockFadeAnimator = ValueAnimator.ofFloat(0f, 1f); + dockFadeAnimator.addUpdateListener(valueAnimator -> { + float progress = valueAnimator.getAnimatedFraction(); + for (SurfaceControl leash : auxiliarySurfaces) { + t.setAlpha(leash, shown ? progress : 1 - progress); + } + t.apply(); + }); + dockFadeAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + super.onAnimationStart(animation); + if (shown) { + for (SurfaceControl leash : auxiliarySurfaces) { + t.setAlpha(leash, 0); + t.show(leash); + } + t.apply(); + } + } + + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + if (!shown) { + for (SurfaceControl leash : auxiliarySurfaces) { + t.hide(leash); + } + t.apply(); + } + t.close(); + } + }); + 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(); } } } diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index 2ad586d2f2..6d0f4c5df9 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -4172,8 +4172,10 @@ public abstract class RecentsView { if (isSuccess) { if (tv.getTaskIds()[1] != -1) { + // TODO(b/194414938): make this part of the animations instead. TaskViewUtils.setSplitAuxiliarySurfacesShown(mRemoteTargetHandles[0] - .getTransformParams().getTargetSet().nonApps, true); + .getTransformParams().getTargetSet().nonApps, + true /*shown*/, false /*animate*/); } if (ENABLE_QUICKSTEP_LIVE_TILE.get() && tv.isRunningTask()) { finishRecentsAnimation(false /* toRecents */, null); diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java index 8dee4e77cb..6801c5d6d2 100644 --- a/quickstep/src/com/android/quickstep/views/TaskView.java +++ b/quickstep/src/com/android/quickstep/views/TaskView.java @@ -628,11 +628,8 @@ public class TaskView extends FrameLayout implements Reusable { Arrays.stream(topLeftParams.getTargetSet().wallpapers), Arrays.stream(rightBottomParams.getTargetSet().wallpapers)) .toArray(RemoteAnimationTargetCompat[]::new); - RemoteAnimationTargetCompat[] nonApps = Stream.concat( - Arrays.stream(topLeftParams.getTargetSet().nonApps), - Arrays.stream(rightBottomParams.getTargetSet().nonApps)) - .toArray(RemoteAnimationTargetCompat[]::new); - targets = new RemoteAnimationTargets(apps, wallpapers, nonApps, + targets = new RemoteAnimationTargets(apps, wallpapers, + topLeftParams.getTargetSet().nonApps, topLeftParams.getTargetSet().targetMode); } if (targets == null) {