Use RectFSpringAnim for auto-enter-pip
Make SwipePipToHomeAnimator a subclass of RectFSpringAnim and use the
bounds calculated from latter for auto-enter-pip transition.
Note that the landscape to portrait case may not fully comply to
RectFSpringAnim as we calculate the position separately in
SwipePipToHomeAnimator.
Video: http://recall/-/aaaaaabFQoRHlzixHdtY/CWBPU2A6vB8CeTFRanQLx
Bug: 184789411
Test: manual, see video
Change-Id: I67dae09e682b7d8f1a1f08995eb3bcf76bdf7417
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 8f42993..57dcad6 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -45,8 +45,6 @@
import static com.android.quickstep.GestureState.STATE_RECENTS_SCROLLING_FINISHED;
import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
import static com.android.quickstep.util.NavigationModeFeatureFlag.LIVE_TILE;
-import static com.android.quickstep.util.SwipePipToHomeAnimator.FRACTION_END;
-import static com.android.quickstep.util.SwipePipToHomeAnimator.FRACTION_START;
import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME;
@@ -248,7 +246,6 @@
private final Runnable mOnDeferredActivityLaunch = this::onDeferredActivityLaunch;
- private static final long SWIPE_PIP_TO_HOME_DURATION = 425;
private SwipePipToHomeAnimator mSwipePipToHomeAnimator;
protected boolean mIsSwipingPipToHome;
@@ -1127,17 +1124,14 @@
createHomeAnimationFactory(cookies, duration, isTranslucent, appCanEnterPip,
runningTaskTarget);
mIsSwipingPipToHome = homeAnimFactory.supportSwipePipToHome() && appCanEnterPip;
+ final RectFSpringAnim windowAnim;
if (mIsSwipingPipToHome) {
- mSwipePipToHomeAnimator = getSwipePipToHomeAnimator(
+ mSwipePipToHomeAnimator = createWindowAnimationToPip(
homeAnimFactory, runningTaskTarget, start);
- mSwipePipToHomeAnimator.setDuration(SWIPE_PIP_TO_HOME_DURATION);
- mSwipePipToHomeAnimator.setInterpolator(interpolator);
- mSwipePipToHomeAnimator.setFloatValues(FRACTION_START, FRACTION_END);
- mSwipePipToHomeAnimator.start();
- mRunningWindowAnim = RunningWindowAnim.wrap(mSwipePipToHomeAnimator);
+ windowAnim = mSwipePipToHomeAnimator;
} else {
mSwipePipToHomeAnimator = null;
- RectFSpringAnim windowAnim = createWindowAnimationToHome(start, homeAnimFactory);
+ windowAnim = createWindowAnimationToHome(start, homeAnimFactory);
windowAnim.addAnimatorListener(new AnimationSuccessListener() {
@Override
public void onAnimationSuccess(Animator animator) {
@@ -1151,9 +1145,9 @@
mGestureState.setState(STATE_END_TARGET_ANIMATION_FINISHED);
}
});
- windowAnim.start(mContext, velocityPxPerMs);
- mRunningWindowAnim = RunningWindowAnim.wrap(windowAnim);
}
+ windowAnim.start(mContext, velocityPxPerMs);
+ mRunningWindowAnim = RunningWindowAnim.wrap(windowAnim);
homeAnimFactory.setSwipeVelocity(velocityPxPerMs.y);
homeAnimFactory.playAtomicAnimation(velocityPxPerMs.y);
mLauncherTransitionController = null;
@@ -1209,7 +1203,7 @@
}
}
- private SwipePipToHomeAnimator getSwipePipToHomeAnimator(HomeAnimationFactory homeAnimFactory,
+ private SwipePipToHomeAnimator createWindowAnimationToPip(HomeAnimationFactory homeAnimFactory,
RemoteAnimationTargetCompat runningTaskTarget, float startProgress) {
// Directly animate the app to PiP (picture-in-picture) mode
final ActivityManager.RunningTaskInfo taskInfo = mGestureState.getRunningTask();
@@ -1222,16 +1216,15 @@
runningTaskTarget.taskInfo.pictureInPictureParams,
homeRotation,
mDp.hotseatBarSizePx);
- final Rect startBounds = new Rect();
- updateProgressForStartRect(new Matrix(), startProgress).round(startBounds);
final SwipePipToHomeAnimator swipePipToHomeAnimator = new SwipePipToHomeAnimator(
+ mContext,
runningTaskTarget.taskId,
taskInfo.topActivity,
runningTaskTarget.leash.getSurfaceControl(),
TaskInfoCompat.getPipSourceRectHint(
runningTaskTarget.taskInfo.pictureInPictureParams),
TaskInfoCompat.getWindowConfigurationBounds(taskInfo),
- startBounds,
+ updateProgressForStartRect(new Matrix(), startProgress),
destinationBounds,
mRecentsView.getPipCornerRadius(),
mRecentsView);
@@ -1243,7 +1236,7 @@
}
AnimatorPlaybackController activityAnimationToHome =
homeAnimFactory.createActivityAnimationToHome();
- swipePipToHomeAnimator.addListener(new AnimatorListenerAdapter() {
+ swipePipToHomeAnimator.addAnimatorListener(new AnimatorListenerAdapter() {
private boolean mHasAnimationEnded;
@Override
public void onAnimationStart(Animator animation) {
diff --git a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
index 61a2eaf..67a635b 100644
--- a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
+++ b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
@@ -20,8 +20,8 @@
import android.animation.Animator;
import android.animation.RectEvaluator;
-import android.animation.ValueAnimator;
import android.content.ComponentName;
+import android.content.Context;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Rect;
@@ -44,30 +44,24 @@
import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
/**
- * An {@link Animator} that animates an Activity to PiP (picture-in-picture) window when
- * swiping up (in gesture navigation mode). Note that this class is derived from
- * {@link com.android.wm.shell.pip.PipAnimationController.PipTransitionAnimator}.
- *
- * TODO: consider sharing this class including the animator and leash operations between
- * Launcher and SysUI. Also, there should be one source of truth for the corner radius of the
- * PiP window, which would ideally be on SysUI side as well.
+ * Subclass of {@link RectFSpringAnim} that animates an Activity to PiP (picture-in-picture) window
+ * when swiping up (in gesture navigation mode).
*/
-public class SwipePipToHomeAnimator extends ValueAnimator {
+public class SwipePipToHomeAnimator extends RectFSpringAnim {
private static final String TAG = SwipePipToHomeAnimator.class.getSimpleName();
- public static final float FRACTION_START = 0f;
- public static final float FRACTION_END = 1f;
+ private static final float END_PROGRESS = 1.0f;
private final int mTaskId;
private final ComponentName mComponentName;
private final SurfaceControl mLeash;
private final Rect mAppBounds = new Rect();
private final Rect mStartBounds = new Rect();
+ private final Rect mCurrentBounds = new Rect();
private final Rect mDestinationBounds = new Rect();
private final PipSurfaceTransactionHelper mSurfaceTransactionHelper;
- /** for calculating the transform in {@link #onAnimationUpdate(ValueAnimator)} */
- private final RectEvaluator mRectEvaluator = new RectEvaluator(new Rect());
+ /** for calculating transform in {@link #onAnimationUpdate(AppCloseConfig, RectF, float)} */
private final RectEvaluator mInsetsEvaluator = new RectEvaluator(new Rect());
private final Rect mSourceHintRectInsets;
private final Rect mSourceInsets = new Rect();
@@ -90,6 +84,7 @@
private SurfaceControl mContentOverlay;
/**
+ * @param context {@link Context} provides Launcher resources
* @param taskId Task id associated with this animator, see also {@link #getTaskId()}
* @param componentName Component associated with this animator,
* see also {@link #getComponentName()}
@@ -102,20 +97,22 @@
* @param destinationBounds Bounds of the destination this animator ends to
* @param cornerRadius Corner radius in pixel value for PiP window
*/
- public SwipePipToHomeAnimator(int taskId,
+ public SwipePipToHomeAnimator(@NonNull Context context,
+ int taskId,
@NonNull ComponentName componentName,
@NonNull SurfaceControl leash,
@Nullable Rect sourceRectHint,
@NonNull Rect appBounds,
- @NonNull Rect startBounds,
+ @NonNull RectF startBounds,
@NonNull Rect destinationBounds,
int cornerRadius,
@NonNull View view) {
+ super(startBounds, new RectF(destinationBounds), context);
mTaskId = taskId;
mComponentName = componentName;
mLeash = leash;
mAppBounds.set(appBounds);
- mStartBounds.set(startBounds);
+ startBounds.round(mStartBounds);
mDestinationBounds.set(destinationBounds);
mDestinationBoundsTransformed.set(mDestinationBounds);
mDestinationBoundsAnimation.set(mDestinationBounds);
@@ -151,10 +148,10 @@
t.reparent(mContentOverlay, mLeash);
t.apply();
- addUpdateListener(valueAnimator -> {
- float alpha = valueAnimator.getAnimatedFraction() < 0.5f
+ addOnUpdateListener((values, currentRect, progress) -> {
+ float alpha = progress < 0.5f
? 0
- : Utilities.mapToRange(valueAnimator.getAnimatedFraction(), 0.5f, 1f,
+ : Utilities.mapToRange(Math.min(progress, 1f), 0.5f, 1f,
0f, 1f, Interpolators.FAST_OUT_SLOW_IN);
t.setAlpha(mContentOverlay, alpha);
t.apply();
@@ -166,7 +163,7 @@
appBounds.bottom - sourceRectHint.bottom);
}
- addListener(new AnimationSuccessListener() {
+ addAnimatorListener(new AnimationSuccessListener() {
@Override
public void onAnimationStart(Animator animation) {
InteractionJankMonitorWrapper.begin(view, CUJ_APP_CLOSE_TO_PIP);
@@ -191,7 +188,7 @@
mHasAnimationEnded = true;
}
});
- addUpdateListener(this::onAnimationUpdate);
+ addOnUpdateListener(this::onAnimationUpdate);
}
/** sets the from rotation if it's different from the target rotation. */
@@ -219,34 +216,34 @@
mAppBounds.top + mDestinationBounds.height());
}
- private void onAnimationUpdate(ValueAnimator animator) {
+ private void onAnimationUpdate(@Nullable AppCloseConfig values, RectF currentRect,
+ float progress) {
if (mHasAnimationEnded) return;
final SurfaceControl.Transaction tx =
PipSurfaceTransactionHelper.newSurfaceControlTransaction();
- onAnimationUpdate(tx, animator.getAnimatedFraction());
+ onAnimationUpdate(tx, currentRect, progress);
tx.apply();
}
private PictureInPictureSurfaceTransaction onAnimationUpdate(SurfaceControl.Transaction tx,
- float fraction) {
- final Rect bounds = mRectEvaluator.evaluate(fraction, mStartBounds,
- mDestinationBoundsAnimation);
+ RectF currentRect, float progress) {
+ currentRect.round(mCurrentBounds);
final PictureInPictureSurfaceTransaction op;
if (mSourceHintRectInsets == null) {
// no source rect hint been set, directly scale the window down
- op = onAnimationScale(fraction, tx, bounds);
+ op = onAnimationScale(progress, tx, mCurrentBounds);
} else {
// scale and crop according to the source rect hint
- op = onAnimationScaleAndCrop(fraction, tx, bounds);
+ op = onAnimationScaleAndCrop(progress, tx, mCurrentBounds);
}
return op;
}
/** scale the window directly with no source rect hint being set */
private PictureInPictureSurfaceTransaction onAnimationScale(
- float fraction, SurfaceControl.Transaction tx, Rect bounds) {
+ float progress, SurfaceControl.Transaction tx, Rect bounds) {
if (mFromRotation == Surface.ROTATION_90 || mFromRotation == Surface.ROTATION_270) {
- final RotatedPosition rotatedPosition = getRotatedPosition(fraction);
+ final RotatedPosition rotatedPosition = getRotatedPosition(progress);
return mSurfaceTransactionHelper.scale(tx, mLeash, mAppBounds, bounds,
rotatedPosition.degree, rotatedPosition.positionX, rotatedPosition.positionY);
} else {
@@ -256,12 +253,12 @@
/** scale and crop the window with source rect hint */
private PictureInPictureSurfaceTransaction onAnimationScaleAndCrop(
- float fraction, SurfaceControl.Transaction tx,
+ float progress, SurfaceControl.Transaction tx,
Rect bounds) {
- final Rect insets = mInsetsEvaluator.evaluate(fraction, mSourceInsets,
+ final Rect insets = mInsetsEvaluator.evaluate(progress, mSourceInsets,
mSourceHintRectInsets);
if (mFromRotation == Surface.ROTATION_90 || mFromRotation == Surface.ROTATION_270) {
- final RotatedPosition rotatedPosition = getRotatedPosition(fraction);
+ final RotatedPosition rotatedPosition = getRotatedPosition(progress);
return mSurfaceTransactionHelper.scaleAndRotate(tx, mLeash, mAppBounds, bounds, insets,
rotatedPosition.degree, rotatedPosition.positionX, rotatedPosition.positionY);
} else {
@@ -291,22 +288,22 @@
// get the final leash operations but do not apply to the leash.
final SurfaceControl.Transaction tx =
PipSurfaceTransactionHelper.newSurfaceControlTransaction();
- return onAnimationUpdate(tx, FRACTION_END);
+ return onAnimationUpdate(tx, new RectF(mDestinationBounds), END_PROGRESS);
}
- private RotatedPosition getRotatedPosition(float fraction) {
+ private RotatedPosition getRotatedPosition(float progress) {
final float degree, positionX, positionY;
if (mFromRotation == Surface.ROTATION_90) {
- degree = -90 * fraction;
- positionX = fraction * (mDestinationBoundsTransformed.left - mStartBounds.left)
+ degree = -90 * progress;
+ positionX = progress * (mDestinationBoundsTransformed.left - mStartBounds.left)
+ mStartBounds.left;
- positionY = fraction * (mDestinationBoundsTransformed.bottom - mStartBounds.top)
+ positionY = progress * (mDestinationBoundsTransformed.bottom - mStartBounds.top)
+ mStartBounds.top;
} else {
- degree = 90 * fraction;
- positionX = fraction * (mDestinationBoundsTransformed.right - mStartBounds.left)
+ degree = 90 * progress;
+ positionX = progress * (mDestinationBoundsTransformed.right - mStartBounds.left)
+ mStartBounds.left;
- positionY = fraction * (mDestinationBoundsTransformed.top - mStartBounds.top)
+ positionY = progress * (mDestinationBoundsTransformed.top - mStartBounds.top)
+ mStartBounds.top;
}
return new RotatedPosition(degree, positionX, positionY);