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
This commit is contained in:
Vinit Nayak 2021-11-17 19:51:22 -08:00
parent a21e47c930
commit 0d40e19c4a
6 changed files with 113 additions and 24 deletions

View File

@ -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;

View File

@ -818,7 +818,8 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
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<T extends StatefulActivity<S>,
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<T extends StatefulActivity<S>,
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<T extends StatefulActivity<S>,
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<T extends StatefulActivity<S>,
@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;

View File

@ -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;
}
}

View File

@ -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) {
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) {
t.setVisibility(leash, shown);
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();
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();
}
}
}

View File

@ -4172,8 +4172,10 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
mPendingAnimation.addEndListener(isSuccess -> {
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);

View File

@ -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) {